diff --git a/src/main/java/org/qortal/transaction/BuyNameTransaction.java b/src/main/java/org/qortal/transaction/BuyNameTransaction.java index 6c390085..370e770a 100644 --- a/src/main/java/org/qortal/transaction/BuyNameTransaction.java +++ b/src/main/java/org/qortal/transaction/BuyNameTransaction.java @@ -49,6 +49,15 @@ public class BuyNameTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { + Optional buyerPrimaryName = this.getBuyer().getPrimaryName(); + if( buyerPrimaryName.isPresent() ) { + + NameData nameData = repository.getNameRepository().fromName(buyerPrimaryName.get()); + if (nameData.isForSale()) { + return ValidationResult.NOT_SUPPORTED; + } + } + String name = this.buyNameTransactionData.getName(); // Check seller address is valid diff --git a/src/main/java/org/qortal/transaction/SellNameTransaction.java b/src/main/java/org/qortal/transaction/SellNameTransaction.java index 3b6bf5df..8dcf9bd2 100644 --- a/src/main/java/org/qortal/transaction/SellNameTransaction.java +++ b/src/main/java/org/qortal/transaction/SellNameTransaction.java @@ -45,6 +45,12 @@ public class SellNameTransaction extends Transaction { public ValidationResult isValid() throws DataException { String name = this.sellNameTransactionData.getName(); + // if the account has more than one name, then they cannot sell their primary name + if( this.repository.getNameRepository().getNamesByOwner(this.getOwner().getAddress()).size() > 1 && + this.getOwner().getPrimaryName().get().equals(name) ) { + return ValidationResult.NOT_SUPPORTED; + } + // Check name size bounds int nameLength = Utf8.encodedLength(name); if (nameLength < 1 || nameLength > Name.MAX_NAME_SIZE) diff --git a/src/test/java/org/qortal/test/naming/BuySellTests.java b/src/test/java/org/qortal/test/naming/BuySellTests.java index 9788bd7c..6f807265 100644 --- a/src/test/java/org/qortal/test/naming/BuySellTests.java +++ b/src/test/java/org/qortal/test/naming/BuySellTests.java @@ -133,6 +133,11 @@ public class BuySellTests extends Common { // check that the order is correct assertEquals(name1, namesByOwner.get(0).getName()); + SellNameTransactionData sellPrimaryNameData = new SellNameTransactionData(TestTransaction.generateBase(alice), name, price); + Transaction.ValidationResult sellPrimaryNameResult = TransactionUtils.signAndImport(repository, sellPrimaryNameData, alice); + + // check that selling primary name is not supported while owning multiple addresses + assertTrue(Transaction.ValidationResult.NOT_SUPPORTED.equals(sellPrimaryNameResult)); } @Test @@ -438,4 +443,60 @@ public class BuySellTests extends Common { assertEquals(bob.getPrimaryName(), bob.determinePrimaryName(TransactionsResource.ConfirmationStatus.CONFIRMED)); } + @Test + public void testBuyInvalidationDuringPrimaryNameSale() throws DataException { + // mint passed the feature trigger block + BlockUtils.mintBlocks(repository, BlockChain.getInstance().getMultipleNamesPerAccountHeight()); + + // Register-name + testRegisterName(); + + // assert primary name for alice + Optional alicePrimaryName1 = alice.getPrimaryName(); + assertTrue(alicePrimaryName1.isPresent()); + assertTrue(alicePrimaryName1.get().equals(name)); + + // Sell-name + SellNameTransactionData transactionData = new SellNameTransactionData(TestTransaction.generateBase(alice), name, price); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // assert primary name for alice + Optional alicePrimaryName2 = alice.getPrimaryName(); + assertTrue(alicePrimaryName2.isPresent()); + assertTrue(alicePrimaryName2.get().equals(name)); + + NameData nameData; + + // Check name is for sale + nameData = repository.getNameRepository().fromName(name); + assertTrue(nameData.isForSale()); + assertEquals("price incorrect", price, nameData.getSalePrice()); + + // assert alice cannot register another name while primary name is for sale + final String name2 = "another name"; + RegisterNameTransactionData registerSecondNameData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name2, "{}"); + Transaction.ValidationResult registrationResult = TransactionUtils.signAndImport(repository, registerSecondNameData, alice); + + // check that registering is not supported while primary name is for sale + assertTrue(Transaction.ValidationResult.NOT_SUPPORTED.equals(registrationResult)); + + String bobName = "bob"; + RegisterNameTransactionData bobRegisterData = new RegisterNameTransactionData(TestTransaction.generateBase(bob), bobName, "{}"); + transactionData.setFee(new RegisterNameTransaction(null, null).getUnitFee(bobRegisterData.getTimestamp())); + TransactionUtils.signAndMint(repository, bobRegisterData, bob); + + Optional bobPrimaryName = bob.getPrimaryName(); + + assertTrue(bobPrimaryName.isPresent()); + assertEquals(bobName, bobPrimaryName.get()); + + SellNameTransactionData bobSellData = new SellNameTransactionData(TestTransaction.generateBase(bob), bobName, price); + TransactionUtils.signAndMint(repository, bobSellData, bob); + + BuyNameTransactionData aliceBuyData = new BuyNameTransactionData(TestTransaction.generateBase(alice), bobName, price, bob.getAddress()); + Transaction.ValidationResult aliceBuyResult = TransactionUtils.signAndImport(repository, aliceBuyData, alice); + + // check that buying is not supported while primary name is for sale + assertTrue(Transaction.ValidationResult.NOT_SUPPORTED.equals(aliceBuyResult)); + } }