forked from Qortal/qortal
Merge branch 'master' into block-archive
This commit is contained in:
commit
ba06225b01
@ -1133,7 +1133,7 @@ public class Block {
|
||||
// Check transaction can even be processed
|
||||
validationResult = transaction.isProcessable();
|
||||
if (validationResult != Transaction.ValidationResult.OK) {
|
||||
LOGGER.debug(String.format("Error during transaction validation, tx %s: %s", Base58.encode(transactionData.getSignature()), validationResult.name()));
|
||||
LOGGER.info(String.format("Error during transaction validation, tx %s: %s", Base58.encode(transactionData.getSignature()), validationResult.name()));
|
||||
return ValidationResult.TRANSACTION_INVALID;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class RegisterNameTransactionData extends TransactionData {
|
||||
@Schema(description = "requested name", example = "my-name")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "simple name-related info in JSON format", example = "{ \"age\": 30 }")
|
||||
@Schema(description = "simple name-related info in JSON or text format", example = "Registered Name on the Qortal Chain")
|
||||
private String data;
|
||||
|
||||
// For internal use
|
||||
|
@ -26,7 +26,7 @@ public class UpdateNameTransactionData extends TransactionData {
|
||||
@Schema(description = "new name", example = "my-new-name")
|
||||
private String newName;
|
||||
|
||||
@Schema(description = "replacement simple name-related info in JSON format", example = "{ \"age\": 30 }")
|
||||
@Schema(description = "replacement simple name-related info in JSON or text format", example = "Registered Name on the Qortal Chain")
|
||||
private String newData;
|
||||
|
||||
// For internal use
|
||||
|
@ -2,11 +2,13 @@ package org.qortal.transaction;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.naming.NameData;
|
||||
import org.qortal.data.transaction.RegisterNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.naming.Name;
|
||||
@ -77,14 +79,32 @@ public class RegisterNameTransaction extends Transaction {
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check the name isn't already taken
|
||||
if (this.repository.getNameRepository().reducedNameExists(this.registerNameTransactionData.getReducedName()))
|
||||
if (this.repository.getNameRepository().reducedNameExists(this.registerNameTransactionData.getReducedName())) {
|
||||
// Name exists, but we'll allow the transaction if it has the same creator
|
||||
// This is necessary to workaround an issue due to inconsistent data in the Names table on some nodes.
|
||||
// Without this, the chain can get stuck for a subset of nodes when the name is registered
|
||||
// for the second time. It's simplest to just treat REGISTER_NAME as UPDATE_NAME if the creator
|
||||
// matches that of the original registration.
|
||||
|
||||
NameData nameData = this.repository.getNameRepository().fromReducedName(this.registerNameTransactionData.getReducedName());
|
||||
if (Objects.equals(this.getCreator().getAddress(), nameData.getOwner())) {
|
||||
// Transaction creator already owns the name, so it's safe to update it
|
||||
// Treat this as valid, which also requires skipping the "one name per account" check below.
|
||||
// Given that the name matches one already registered, we know that it won't exceed the limit.
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
// Name is already registered to someone else
|
||||
return ValidationResult.NAME_ALREADY_REGISTERED;
|
||||
}
|
||||
|
||||
// If accounts are only allowed one registered name then check for this
|
||||
if (BlockChain.getInstance().oneNamePerAccount()
|
||||
&& !this.repository.getNameRepository().getNamesByOwner(getRegistrant().getAddress()).isEmpty())
|
||||
return ValidationResult.MULTIPLE_NAMES_FORBIDDEN;
|
||||
|
||||
// FUTURE: when adding more validation, make sure to check the `return ValidationResult.OK` above
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ 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;
|
||||
@ -32,7 +33,7 @@ public class MiscTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "initial-name";
|
||||
String data = "initial-data";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -44,14 +45,14 @@ public class MiscTests extends Common {
|
||||
}
|
||||
}
|
||||
|
||||
// test trying to register same name twice
|
||||
// test trying to register same name twice (with same creator)
|
||||
@Test
|
||||
public void testDuplicateRegisterName() throws DataException {
|
||||
public void testDuplicateRegisterNameWithSameCreator() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
String data = "{}";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -63,7 +64,31 @@ public class MiscTests extends Common {
|
||||
transaction.sign(alice);
|
||||
|
||||
ValidationResult result = transaction.importAsUnconfirmed();
|
||||
assertTrue("Transaction should be invalid", ValidationResult.OK != result);
|
||||
assertTrue("Transaction should be valid because it has the same creator", ValidationResult.OK == result);
|
||||
}
|
||||
}
|
||||
|
||||
// test trying to register same name twice (with different creator)
|
||||
@Test
|
||||
public void testDuplicateRegisterNameWithDifferentCreator() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
String data = "{}";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
// duplicate (this time registered by Bob)
|
||||
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
|
||||
String duplicateName = "TEST-nÁme";
|
||||
transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(bob), duplicateName, data);
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(alice);
|
||||
|
||||
ValidationResult result = transaction.importAsUnconfirmed();
|
||||
assertTrue("Transaction should be invalid because it has a different creator", ValidationResult.OK != result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +99,7 @@ public class MiscTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
String data = "{}";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -103,7 +128,7 @@ public class MiscTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = alice.getAddress();
|
||||
String data = "{}";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
@ -121,7 +146,7 @@ public class MiscTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
String data = "{}";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -138,4 +163,61 @@ public class MiscTests extends Common {
|
||||
}
|
||||
}
|
||||
|
||||
// test registering and then orphaning
|
||||
@Test
|
||||
public void testRegisterNameAndOrphan() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
// Ensure the name doesn't exist
|
||||
assertNull(repository.getNameRepository().fromName(name));
|
||||
|
||||
// Register the name
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
// Ensure the name exists and the data is correct
|
||||
assertEquals(data, repository.getNameRepository().fromName(name).getData());
|
||||
|
||||
// Orphan the latest block
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
|
||||
// Ensure the name doesn't exist once again
|
||||
assertNull(repository.getNameRepository().fromName(name));
|
||||
}
|
||||
}
|
||||
|
||||
// test registering and then orphaning multiple times (to simulate several re-orgs)
|
||||
@Test
|
||||
public void testMultipleRegisterNameAndOrphan() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
String data = "{\"age\":30}";
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
||||
// Ensure the name doesn't exist
|
||||
assertNull(repository.getNameRepository().fromName(name));
|
||||
|
||||
// Register the name
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
// Ensure the name exists and the data is correct
|
||||
assertEquals(data, repository.getNameRepository().fromName(name).getData());
|
||||
|
||||
// Orphan the latest block
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
|
||||
// Ensure the name doesn't exist once again
|
||||
assertNull(repository.getNameRepository().fromName(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData initialTransactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, initialTransactionData, alice);
|
||||
@ -68,7 +68,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData initialTransactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, initialTransactionData, alice);
|
||||
@ -108,7 +108,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData initialTransactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, initialTransactionData, alice);
|
||||
@ -171,7 +171,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -217,7 +217,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -251,7 +251,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
@ -294,7 +294,7 @@ public class UpdateTests extends Common {
|
||||
// Register-name
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String initialName = "initial-name";
|
||||
String initialData = "initial-data";
|
||||
String initialData = "{\"age\":30}";
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), initialName, initialData);
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
Loading…
x
Reference in New Issue
Block a user