Merge branch 'master' into block-archive

This commit is contained in:
CalDescent 2021-09-12 10:17:11 +01:00
commit ba06225b01
6 changed files with 121 additions and 19 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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));
}
}
}
}

View File

@ -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);