diff --git a/src/main/java/org/qortal/controller/repository/NamesDatabaseIntegrityCheck.java b/src/main/java/org/qortal/controller/repository/NamesDatabaseIntegrityCheck.java index 4214eccf..0e65e746 100644 --- a/src/main/java/org/qortal/controller/repository/NamesDatabaseIntegrityCheck.java +++ b/src/main/java/org/qortal/controller/repository/NamesDatabaseIntegrityCheck.java @@ -320,46 +320,7 @@ public class NamesDatabaseIntegrityCheck { } public List fetchAllTransactionsInvolvingName(String name, Repository repository) throws DataException { - List transactions = new ArrayList<>(); - String reducedName = Unicode.sanitize(name); - - // Fetch all the confirmed name-modification transactions - if (this.nameTransactions.isEmpty()) { - this.fetchAllNameTransactions(repository); - } - - for (TransactionData transactionData : this.nameTransactions) { - - if ((transactionData instanceof RegisterNameTransactionData)) { - RegisterNameTransactionData registerNameTransactionData = (RegisterNameTransactionData) transactionData; - if (Objects.equals(registerNameTransactionData.getName(), name) || - Objects.equals(registerNameTransactionData.getReducedName(), reducedName)) { - transactions.add(transactionData); - } - } - if ((transactionData instanceof UpdateNameTransactionData)) { - UpdateNameTransactionData updateNameTransactionData = (UpdateNameTransactionData) transactionData; - boolean hasReducedNewName = updateNameTransactionData.getReducedNewName() == null && !updateNameTransactionData.getReducedNewName().isEmpty(); - if (Objects.equals(updateNameTransactionData.getName(), name) || - (hasReducedNewName && Objects.equals(updateNameTransactionData.getReducedNewName(), reducedName)) || - Objects.equals(updateNameTransactionData.getNewName(), name)) { - transactions.add(transactionData); - } - } - if ((transactionData instanceof BuyNameTransactionData)) { - BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) transactionData; - if (Objects.equals(buyNameTransactionData.getName(), name)) { - transactions.add(transactionData); - } - } - if ((transactionData instanceof SellNameTransactionData)) { - SellNameTransactionData sellNameTransactionData = (SellNameTransactionData) transactionData; - if (Objects.equals(sellNameTransactionData.getName(), name)) { - transactions.add(transactionData); - } - } - } - return transactions; + return repository.getTransactionRepository().getTransactionsInvolvingName(name, ConfirmationStatus.CONFIRMED); } private TransactionData fetchLatestModificationTransactionInvolvingName(String registeredName, Repository repository) throws DataException { diff --git a/src/main/java/org/qortal/repository/TransactionRepository.java b/src/main/java/org/qortal/repository/TransactionRepository.java index b0e3a864..643de60a 100644 --- a/src/main/java/org/qortal/repository/TransactionRepository.java +++ b/src/main/java/org/qortal/repository/TransactionRepository.java @@ -125,6 +125,17 @@ public interface TransactionRepository { */ public byte[] getLatestAutoUpdateTransaction(TransactionType txType, int txGroupId, Integer service) throws DataException; + /** + * Returns signatures for all name-registration related transactions relating to supplied name. + * Note: this does not currently include ARBITRARY data relating to the name. + * + * @param name + * @param confirmationStatus + * @return + * @throws DataException + */ + public List getTransactionsInvolvingName(String name, ConfirmationStatus confirmationStatus) throws DataException; + /** * Returns list of transactions relating to specific asset ID. * diff --git a/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index e326b498..141d5c1f 100644 --- a/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -30,6 +30,7 @@ import org.qortal.repository.hsqldb.HSQLDBSaver; import org.qortal.transaction.Transaction.ApprovalStatus; import org.qortal.transaction.Transaction.TransactionType; import org.qortal.utils.Base58; +import org.qortal.utils.Unicode; public class HSQLDBTransactionRepository implements TransactionRepository { @@ -700,6 +701,88 @@ public class HSQLDBTransactionRepository implements TransactionRepository { } } + @Override + public List getTransactionsInvolvingName(String name, ConfirmationStatus confirmationStatus) throws DataException { + TransactionType[] transactionTypes = new TransactionType[] { + REGISTER_NAME, UPDATE_NAME, BUY_NAME, SELL_NAME + }; // TODO: CancelSellNameTransaction? + + String reducedName = Unicode.sanitize(name); + + StringBuilder sql = new StringBuilder(1024); + List bindParams = new ArrayList<>(); + sql.append("SELECT Transactions.signature FROM Transactions"); + + for (int ti = 0; ti < transactionTypes.length; ++ti) { + sql.append(" LEFT OUTER JOIN "); + sql.append(transactionTypes[ti].className); + sql.append("Transactions USING (signature)"); + } + + sql.append(" WHERE Transactions.type IN ("); + for (int ti = 0; ti < transactionTypes.length; ++ti) { + if (ti != 0) + sql.append(", "); + + sql.append(transactionTypes[ti].value); + } + sql.append(")"); + + // Confirmation status + switch (confirmationStatus) { + case BOTH: + break; + + case CONFIRMED: + sql.append(" AND Transactions.block_height IS NOT NULL"); + break; + + case UNCONFIRMED: + sql.append(" AND Transactions.block_height IS NULL"); + break; + } + + sql.append(" AND (RegisterNameTransactions.name = ?"); + bindParams.add(name); + sql.append(" OR RegisterNameTransactions.reduced_name = ?"); + bindParams.add(reducedName); + sql.append(" OR UpdateNameTransactions.name = ?"); + bindParams.add(name); + sql.append(" OR (UpdateNameTransactions.reduced_new_name != '' AND UpdateNameTransactions.reduced_new_name = ?)"); + bindParams.add(reducedName); + sql.append(" OR UpdateNameTransactions.new_name = ?"); + bindParams.add(name); + sql.append(" OR SellNameTransactions.name = ?"); + bindParams.add(name); + sql.append(" OR BuyNameTransactions.name = ?"); + bindParams.add(name); + + sql.append(") GROUP BY Transactions.signature, Transactions.created_when ORDER BY Transactions.created_when"); + + List transactions = new ArrayList<>(); + + try (ResultSet resultSet = this.repository.checkedExecute(sql.toString(), bindParams.toArray())) { + if (resultSet == null) + return transactions; + + do { + byte[] signature = resultSet.getBytes(1); + + TransactionData transactionData = this.fromSignature(signature); + + if (transactionData == null) + // Something inconsistent with the repository + throw new DataException("Unable to fetch name-related transaction from repository?"); + + transactions.add(transactionData); + } while (resultSet.next()); + + return transactions; + } catch (SQLException | DataException e) { + throw new DataException("Unable to fetch name-related transactions from repository", e); + } + } + @Override public List getAssetTransactions(long assetId, ConfirmationStatus confirmationStatus, Integer limit, Integer offset, Boolean reverse) throws DataException { diff --git a/src/test/java/org/qortal/test/naming/IntegrityTests.java b/src/test/java/org/qortal/test/naming/IntegrityTests.java index 1a8af3ad..7531bea6 100644 --- a/src/test/java/org/qortal/test/naming/IntegrityTests.java +++ b/src/test/java/org/qortal/test/naming/IntegrityTests.java @@ -125,7 +125,6 @@ public class IntegrityTests extends Common { TransactionUtils.signAndMint(repository, updateTransactionData, alice); // Register emoji name - PrivateKeyAccount bob = Common.getTestAccount(repository, "bob"); String emojiName = "\uD83E\uDD73"; // Translates to a reducedName of "" // Ensure that the initial_name isn't associated with the emoji name