diff --git a/src/main/java/org/qortal/naming/Name.java b/src/main/java/org/qortal/naming/Name.java index 17d1aae2..75f620b7 100644 --- a/src/main/java/org/qortal/naming/Name.java +++ b/src/main/java/org/qortal/naming/Name.java @@ -70,11 +70,15 @@ public class Name { if (previousTransactionData == null) throw new DataException("Unable to revert name transaction as referenced transaction not found in repository"); + String previousName = this.nameData.getName(); + switch (previousTransactionData.getType()) { case REGISTER_NAME: { RegisterNameTransactionData previousRegisterNameTransactionData = (RegisterNameTransactionData) previousTransactionData; + this.nameData.setName(previousRegisterNameTransactionData.getName()); this.nameData.setData(previousRegisterNameTransactionData.getData()); + break; } @@ -92,14 +96,22 @@ public class Name { case BUY_NAME: { BuyNameTransactionData previousBuyNameTransactionData = (BuyNameTransactionData) previousTransactionData; + Account buyer = new PublicKeyAccount(this.repository, previousBuyNameTransactionData.getBuyerPublicKey()); this.nameData.setOwner(buyer.getAddress()); + break; } default: throw new IllegalStateException("Unable to revert name transaction due to unsupported referenced transaction"); } + + this.repository.getNameRepository().save(this.nameData); + + if (!this.nameData.getName().equals(previousName)) + // Name has changed, delete old entry + this.repository.getNameRepository().delete(previousName); } public void update(UpdateNameTransactionData updateNameTransactionData) throws DataException { @@ -110,8 +122,12 @@ public class Name { this.nameData.setReference(updateNameTransactionData.getSignature()); // Update name and data where appropriate - if (!updateNameTransactionData.getNewName().isEmpty()) - this.nameData.setOwner(updateNameTransactionData.getNewName()); + if (!updateNameTransactionData.getNewName().isEmpty()) { + // If we're changing the name, we need to delete old entry + this.repository.getNameRepository().delete(nameData.getName()); + + this.nameData.setName(updateNameTransactionData.getNewName()); + } if (!updateNameTransactionData.getNewData().isEmpty()) this.nameData.setData(updateNameTransactionData.getNewData()); @@ -127,9 +143,6 @@ public class Name { // Previous Name's owner and/or data taken from referenced transaction this.revert(); - // Save reverted name data - this.repository.getNameRepository().save(this.nameData); - // Remove reference to previous name-changing transaction updateNameTransactionData.setNameReference(null); } @@ -213,9 +226,6 @@ public class Name { // Revert seller's balance Account seller = new Account(this.repository, this.nameData.getOwner()); seller.modifyAssetBalance(Asset.QORT, - buyNameTransactionData.getAmount()); - - // Save reverted name data - this.repository.getNameRepository().save(this.nameData); } } diff --git a/src/main/java/org/qortal/transaction/UpdateNameTransaction.java b/src/main/java/org/qortal/transaction/UpdateNameTransaction.java index 8ecc7472..379b4e08 100644 --- a/src/main/java/org/qortal/transaction/UpdateNameTransaction.java +++ b/src/main/java/org/qortal/transaction/UpdateNameTransaction.java @@ -130,7 +130,12 @@ public class UpdateNameTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert name - Name name = new Name(this.repository, this.updateNameTransactionData.getName()); + + String nameToRevert = this.updateNameTransactionData.getNewName(); + if (nameToRevert.isEmpty()) + nameToRevert = this.updateNameTransactionData.getName(); + + Name name = new Name(this.repository, nameToRevert); name.revert(this.updateNameTransactionData); // Save this transaction, with previous "name reference" diff --git a/src/test/java/org/qortal/test/naming/MiscTests.java b/src/test/java/org/qortal/test/naming/MiscTests.java index d183ed82..f124b2dc 100644 --- a/src/test/java/org/qortal/test/naming/MiscTests.java +++ b/src/test/java/org/qortal/test/naming/MiscTests.java @@ -8,12 +8,17 @@ import org.junit.Before; import org.junit.Test; import org.qortal.account.PrivateKeyAccount; import org.qortal.data.transaction.RegisterNameTransactionData; +import org.qortal.data.transaction.TransactionData; +import org.qortal.data.transaction.UpdateNameTransactionData; import org.qortal.repository.DataException; import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; +import org.qortal.test.common.BlockUtils; import org.qortal.test.common.Common; import org.qortal.test.common.TransactionUtils; import org.qortal.test.common.transaction.TestTransaction; +import org.qortal.transaction.Transaction; +import org.qortal.transaction.Transaction.ValidationResult; public class MiscTests extends Common { @@ -39,4 +44,169 @@ public class MiscTests extends Common { } } + @Test + public void testUpdateName() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + // Register-name + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String name = "test-name"; + + TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}"); + TransactionUtils.signAndMint(repository, transactionData, alice); + + String newName = "new-name"; + String newData = ""; + transactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), name, newName, newData); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // Check old name no longer exists + assertFalse(repository.getNameRepository().nameExists(name)); + + // Check new name exists + assertTrue(repository.getNameRepository().nameExists(newName)); + + // orphan and recheck + BlockUtils.orphanLastBlock(repository); + + // Check new name no longer exists + assertFalse(repository.getNameRepository().nameExists(newName)); + + // Check old name exists again + assertTrue(repository.getNameRepository().nameExists(name)); + } + } + + // Test that reverting using previous UPDATE_NAME works as expected + @Test + public void testDoubleUpdateName() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + // Register-name + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String name = "test-name"; + + TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}"); + TransactionUtils.signAndMint(repository, transactionData, alice); + + String newName = "new-name"; + String newData = ""; + transactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), name, newName, newData); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // Check old name no longer exists + assertFalse(repository.getNameRepository().nameExists(name)); + + // Check new name exists + assertTrue(repository.getNameRepository().nameExists(newName)); + + String newestName = "newest-name"; + String newestData = "abc"; + transactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), newName, newestName, newestData); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // Check previous name no longer exists + assertFalse(repository.getNameRepository().nameExists(newName)); + + // Check newest name exists + assertTrue(repository.getNameRepository().nameExists(newestName)); + + // orphan and recheck + BlockUtils.orphanLastBlock(repository); + + // Check newest name no longer exists + assertFalse(repository.getNameRepository().nameExists(newestName)); + + // Check previous name exists again + assertTrue(repository.getNameRepository().nameExists(newName)); + + // orphan and recheck + BlockUtils.orphanLastBlock(repository); + + // Check new name no longer exists + assertFalse(repository.getNameRepository().nameExists(newName)); + + // Check original name exists again + assertTrue(repository.getNameRepository().nameExists(name)); + } + } + + @Test + public void testUpdateData() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + // Register-name + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String name = "test-name"; + String data = "{}"; + + TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data); + TransactionUtils.signAndMint(repository, transactionData, alice); + + String newName = ""; + String newData = "new-data"; + transactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), name, newName, newData); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // Check name still exists + assertTrue(repository.getNameRepository().nameExists(name)); + + // Check data is correct + assertEquals(newData, repository.getNameRepository().fromName(name).getData()); + + // orphan and recheck + BlockUtils.orphanLastBlock(repository); + + // Check name still exists + assertTrue(repository.getNameRepository().nameExists(name)); + + // Check old data restored + assertEquals(data, repository.getNameRepository().fromName(name).getData()); + } + } + + // test trying to register same name twice + @Test + public void testDuplicateRegisterName() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + // Register-name + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String name = "test-name"; + + RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}"); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // duplicate + transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}"); + Transaction transaction = Transaction.fromData(repository, transactionData); + transaction.sign(alice); + + ValidationResult result = transaction.importAsUnconfirmed(); + assertTrue("Transaction should be invalid", ValidationResult.OK != result); + } + } + + // test register then trying to update another name to existing name + @Test + public void testUpdateToExistingName() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + // Register-name + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String name = "test-name"; + + TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}"); + TransactionUtils.signAndMint(repository, transactionData, alice); + + String newName = "new-name"; + String newData = ""; + transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), newName, newData); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // we shouldn't be able to update name to existing name + transactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), newName, name, newData); + Transaction transaction = Transaction.fromData(repository, transactionData); + transaction.sign(alice); + + ValidationResult result = transaction.importAsUnconfirmed(); + assertTrue("Transaction should be invalid", ValidationResult.OK != result); + } + } + }