forked from Qortal/qortal
Registered names: changing 'owner' and allowing renaming.
REGISTER_NAME has an "owner" field which can be different from the actual registrant (transaction creator's public key, used for signing transaction). This allowed people to register names to be owned by someone else, thus breaking the whole "one name per account" aspect. So now "owner" is removed from REGISTER_NAME, and the actual owner address is derived from transaction creator's public key, as you would expect. Similarly, UPDATE_NAME has a corresponding "newOwner" field which has been removed. In addition, UPDATE_NAME now allows users to change their registered name using a new "newName" field. Various changes made to DB, Name class, etc. to accomodate above, along with some minor bug-fixes and comment improvements/corrections. Needs new unit tests to cover both new functionality and old!
This commit is contained in:
parent
f29ae656b9
commit
d9f784ed2b
@ -66,6 +66,10 @@ public class NameData {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ public class RegisterNameTransactionData extends TransactionData {
|
||||
// Properties
|
||||
@Schema(description = "registrant's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
|
||||
private byte[] registrantPublicKey;
|
||||
@Schema(description = "new owner's address", example = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v")
|
||||
private String owner;
|
||||
@Schema(description = "requested name", example = "my-name")
|
||||
private String name;
|
||||
@Schema(description = "simple name-related info in JSON format", example = "{ \"age\": 30 }")
|
||||
@ -38,11 +36,10 @@ public class RegisterNameTransactionData extends TransactionData {
|
||||
}
|
||||
|
||||
/** From repository */
|
||||
public RegisterNameTransactionData(BaseTransactionData baseTransactionData, String owner, String name, String data) {
|
||||
public RegisterNameTransactionData(BaseTransactionData baseTransactionData, String name, String data) {
|
||||
super(TransactionType.REGISTER_NAME, baseTransactionData);
|
||||
|
||||
this.registrantPublicKey = baseTransactionData.creatorPublicKey;
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
@ -53,10 +50,6 @@ public class RegisterNameTransactionData extends TransactionData {
|
||||
return this.registrantPublicKey;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ public class UpdateNameTransactionData extends TransactionData {
|
||||
// Properties
|
||||
@Schema(description = "owner's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
|
||||
private byte[] ownerPublicKey;
|
||||
@Schema(description = "new owner's address", example = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v")
|
||||
private String newOwner;
|
||||
@Schema(description = "which name to update", example = "my-name")
|
||||
private String name;
|
||||
@Schema(description = "new name", example = "my-new-name")
|
||||
private String newName;
|
||||
@Schema(description = "replacement simple name-related info in JSON format", example = "{ \"age\": 30 }")
|
||||
private String newData;
|
||||
// For internal use when orphaning
|
||||
@ -40,19 +40,19 @@ public class UpdateNameTransactionData extends TransactionData {
|
||||
}
|
||||
|
||||
/** From repository */
|
||||
public UpdateNameTransactionData(BaseTransactionData baseTransactionData, String newOwner, String name, String newData, byte[] nameReference) {
|
||||
public UpdateNameTransactionData(BaseTransactionData baseTransactionData, String name, String newName, String newData, byte[] nameReference) {
|
||||
super(TransactionType.UPDATE_NAME, baseTransactionData);
|
||||
|
||||
this.ownerPublicKey = baseTransactionData.creatorPublicKey;
|
||||
this.newOwner = newOwner;
|
||||
this.name = name;
|
||||
this.newName = newName;
|
||||
this.newData = newData;
|
||||
this.nameReference = nameReference;
|
||||
}
|
||||
|
||||
/** From network/API */
|
||||
public UpdateNameTransactionData(BaseTransactionData baseTransactionData, String newOwner, String name, String newData) {
|
||||
this(baseTransactionData, newOwner, name, newData, null);
|
||||
public UpdateNameTransactionData(BaseTransactionData baseTransactionData, String name, String newName, String newData) {
|
||||
this(baseTransactionData, name, newName, newData, null);
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
@ -61,14 +61,14 @@ public class UpdateNameTransactionData extends TransactionData {
|
||||
return this.ownerPublicKey;
|
||||
}
|
||||
|
||||
public String getNewOwner() {
|
||||
return this.newOwner;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getNewName() {
|
||||
return this.newName;
|
||||
}
|
||||
|
||||
public String getNewData() {
|
||||
return this.newData;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.qortal.naming;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.naming.NameData;
|
||||
import org.qortal.data.transaction.BuyNameTransactionData;
|
||||
import org.qortal.data.transaction.CancelSellNameTransactionData;
|
||||
@ -20,6 +21,7 @@ public class Name {
|
||||
private NameData nameData;
|
||||
|
||||
// Useful constants
|
||||
public static final int MIN_NAME_SIZE = 3;
|
||||
public static final int MAX_NAME_SIZE = 400;
|
||||
public static final int MAX_DATA_SIZE = 4000;
|
||||
|
||||
@ -33,7 +35,10 @@ public class Name {
|
||||
*/
|
||||
public Name(Repository repository, RegisterNameTransactionData registerNameTransactionData) {
|
||||
this.repository = repository;
|
||||
this.nameData = new NameData(registerNameTransactionData.getOwner(),
|
||||
|
||||
String owner = Crypto.toAddress(registerNameTransactionData.getRegistrantPublicKey());
|
||||
|
||||
this.nameData = new NameData(owner,
|
||||
registerNameTransactionData.getName(), registerNameTransactionData.getData(), registerNameTransactionData.getTimestamp(),
|
||||
registerNameTransactionData.getSignature(), registerNameTransactionData.getTxGroupId());
|
||||
}
|
||||
@ -66,23 +71,31 @@ public class Name {
|
||||
throw new DataException("Unable to revert name transaction as referenced transaction not found in repository");
|
||||
|
||||
switch (previousTransactionData.getType()) {
|
||||
case REGISTER_NAME:
|
||||
case REGISTER_NAME: {
|
||||
RegisterNameTransactionData previousRegisterNameTransactionData = (RegisterNameTransactionData) previousTransactionData;
|
||||
this.nameData.setOwner(previousRegisterNameTransactionData.getOwner());
|
||||
this.nameData.setName(previousRegisterNameTransactionData.getName());
|
||||
this.nameData.setData(previousRegisterNameTransactionData.getData());
|
||||
break;
|
||||
}
|
||||
|
||||
case UPDATE_NAME:
|
||||
case UPDATE_NAME: {
|
||||
UpdateNameTransactionData previousUpdateNameTransactionData = (UpdateNameTransactionData) previousTransactionData;
|
||||
this.nameData.setData(previousUpdateNameTransactionData.getNewData());
|
||||
this.nameData.setOwner(previousUpdateNameTransactionData.getNewOwner());
|
||||
break;
|
||||
|
||||
case BUY_NAME:
|
||||
if (!previousUpdateNameTransactionData.getNewName().isBlank())
|
||||
this.nameData.setName(previousUpdateNameTransactionData.getNewName());
|
||||
|
||||
if (!previousUpdateNameTransactionData.getNewData().isEmpty())
|
||||
this.nameData.setData(previousUpdateNameTransactionData.getNewData());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
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");
|
||||
@ -96,9 +109,12 @@ public class Name {
|
||||
// New name reference is this transaction's signature
|
||||
this.nameData.setReference(updateNameTransactionData.getSignature());
|
||||
|
||||
// Update Name's owner and data
|
||||
this.nameData.setOwner(updateNameTransactionData.getNewOwner());
|
||||
this.nameData.setData(updateNameTransactionData.getNewData());
|
||||
// Update name and data where appropriate
|
||||
if (!updateNameTransactionData.getNewName().isEmpty())
|
||||
this.nameData.setOwner(updateNameTransactionData.getNewName());
|
||||
|
||||
if (!updateNameTransactionData.getNewData().isEmpty())
|
||||
this.nameData.setData(updateNameTransactionData.getNewData());
|
||||
|
||||
// Save updated name data
|
||||
this.repository.getNameRepository().save(this.nameData);
|
||||
|
@ -294,11 +294,11 @@ public class HSQLDBDatabaseUpdates {
|
||||
|
||||
// Register Name Transactions
|
||||
stmt.execute("CREATE TABLE RegisterNameTransactions (signature Signature, registrant QortalPublicKey NOT NULL, name RegisteredName NOT NULL, "
|
||||
+ "owner QortalAddress NOT NULL, data NameData NOT NULL, " + TRANSACTION_KEYS + ")");
|
||||
+ "data NameData NOT NULL, " + TRANSACTION_KEYS + ")");
|
||||
|
||||
// Update Name Transactions
|
||||
stmt.execute("CREATE TABLE UpdateNameTransactions (signature Signature, owner QortalPublicKey NOT NULL, name RegisteredName NOT NULL, "
|
||||
+ "new_owner QortalAddress NOT NULL, new_data NameData NOT NULL, name_reference Signature, " + TRANSACTION_KEYS + ")");
|
||||
+ "new_name RegisteredName NOT NULL, new_data NameData NOT NULL, name_reference Signature, " + TRANSACTION_KEYS + ")");
|
||||
|
||||
// Sell Name Transactions
|
||||
stmt.execute("CREATE TABLE SellNameTransactions (signature Signature, owner QortalPublicKey NOT NULL, name RegisteredName NOT NULL, "
|
||||
|
@ -17,17 +17,16 @@ public class HSQLDBRegisterNameTransactionRepository extends HSQLDBTransactionRe
|
||||
}
|
||||
|
||||
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
||||
String sql = "SELECT owner, name, data FROM RegisterNameTransactions WHERE signature = ?";
|
||||
String sql = "SELECT name, data FROM RegisterNameTransactions WHERE signature = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
String owner = resultSet.getString(1);
|
||||
String name = resultSet.getString(2);
|
||||
String data = resultSet.getString(3);
|
||||
String name = resultSet.getString(1);
|
||||
String data = resultSet.getString(2);
|
||||
|
||||
return new RegisterNameTransactionData(baseTransactionData, owner, name, data);
|
||||
return new RegisterNameTransactionData(baseTransactionData, name, data);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch register name transaction from repository", e);
|
||||
}
|
||||
@ -40,8 +39,7 @@ public class HSQLDBRegisterNameTransactionRepository extends HSQLDBTransactionRe
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("RegisterNameTransactions");
|
||||
|
||||
saveHelper.bind("signature", registerNameTransactionData.getSignature()).bind("registrant", registerNameTransactionData.getRegistrantPublicKey())
|
||||
.bind("owner", registerNameTransactionData.getOwner()).bind("name", registerNameTransactionData.getName())
|
||||
.bind("data", registerNameTransactionData.getData());
|
||||
.bind("name", registerNameTransactionData.getName()).bind("data", registerNameTransactionData.getData());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
|
@ -17,18 +17,18 @@ public class HSQLDBUpdateNameTransactionRepository extends HSQLDBTransactionRepo
|
||||
}
|
||||
|
||||
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
||||
String sql = "SELECT new_owner, name, new_data, name_reference FROM UpdateNameTransactions WHERE signature = ?";
|
||||
String sql = "SELECT name, new_name, new_data, name_reference FROM UpdateNameTransactions WHERE signature = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
String newOwner = resultSet.getString(1);
|
||||
String name = resultSet.getString(2);
|
||||
String name = resultSet.getString(1);
|
||||
String newName = resultSet.getString(2);
|
||||
String newData = resultSet.getString(3);
|
||||
byte[] nameReference = resultSet.getBytes(4);
|
||||
|
||||
return new UpdateNameTransactionData(baseTransactionData, newOwner, name, newData, nameReference);
|
||||
return new UpdateNameTransactionData(baseTransactionData, name, newName, newData, nameReference);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch update name transaction from repository", e);
|
||||
}
|
||||
@ -41,7 +41,7 @@ public class HSQLDBUpdateNameTransactionRepository extends HSQLDBTransactionRepo
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("UpdateNameTransactions");
|
||||
|
||||
saveHelper.bind("signature", updateNameTransactionData.getSignature()).bind("owner", updateNameTransactionData.getOwnerPublicKey())
|
||||
.bind("new_owner", updateNameTransactionData.getNewOwner()).bind("name", updateNameTransactionData.getName())
|
||||
.bind("name", updateNameTransactionData.getName()).bind("new_name", updateNameTransactionData.getNewName())
|
||||
.bind("new_data", updateNameTransactionData.getNewData()).bind("name_reference", updateNameTransactionData.getNameReference());
|
||||
|
||||
try {
|
||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
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.BuyNameTransactionData;
|
||||
@ -54,7 +55,7 @@ public class BuyNameTransaction extends Transaction {
|
||||
|
||||
// Check name size bounds
|
||||
int nameLength = Utf8.encodedLength(name);
|
||||
if (nameLength < 1 || nameLength > Name.MAX_NAME_SIZE)
|
||||
if (nameLength < Name.MIN_NAME_SIZE || nameLength > Name.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check name is lowercase
|
||||
@ -76,6 +77,11 @@ public class BuyNameTransaction extends Transaction {
|
||||
if (buyer.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.BUYER_ALREADY_OWNER;
|
||||
|
||||
// If accounts are only allowed one registered name then check for this
|
||||
if (BlockChain.getInstance().oneNamePerAccount()
|
||||
&& !this.repository.getNameRepository().getNamesByOwner(buyer.getAddress()).isEmpty())
|
||||
return ValidationResult.MULTIPLE_NAMES_FORBIDDEN;
|
||||
|
||||
// Check expected seller currently owns name
|
||||
if (!this.buyNameTransactionData.getSeller().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_SELLER;
|
||||
@ -84,7 +90,7 @@ public class BuyNameTransaction extends Transaction {
|
||||
if (this.buyNameTransactionData.getAmount() != nameData.getSalePrice())
|
||||
return ValidationResult.INVALID_AMOUNT;
|
||||
|
||||
// Check issuer has enough funds
|
||||
// Check buyer has enough funds
|
||||
if (buyer.getConfirmedBalance(Asset.QORT) < this.buyNameTransactionData.getFee())
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
@ -93,21 +99,21 @@ public class BuyNameTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update Name
|
||||
// Buy Name
|
||||
Name name = new Name(this.repository, this.buyNameTransactionData.getName());
|
||||
name.buy(this.buyNameTransactionData);
|
||||
|
||||
// Save transaction with updated "name reference" pointing to previous transaction that updated name
|
||||
// Save transaction with updated "name reference" pointing to previous transaction that changed name
|
||||
this.repository.getTransactionRepository().save(this.buyNameTransactionData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Revert name
|
||||
// Un-buy name
|
||||
Name name = new Name(this.repository, this.buyNameTransactionData.getName());
|
||||
name.unbuy(this.buyNameTransactionData);
|
||||
|
||||
// Save this transaction, with removed "name reference"
|
||||
// Save this transaction, with previous "name reference"
|
||||
this.repository.getTransactionRepository().save(this.buyNameTransactionData);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.transaction.RegisterNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.naming.Name;
|
||||
@ -32,7 +31,7 @@ public class RegisterNameTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public List<String> getRecipientAddresses() throws DataException {
|
||||
return Collections.singletonList(this.registerNameTransactionData.getOwner());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Navigation
|
||||
@ -46,23 +45,20 @@ public class RegisterNameTransaction extends Transaction {
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
Account registrant = getRegistrant();
|
||||
|
||||
// Check owner address is valid
|
||||
if (!Crypto.isValidAddress(this.registerNameTransactionData.getOwner()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
String name = this.registerNameTransactionData.getName();
|
||||
|
||||
// Check name size bounds
|
||||
int nameLength = Utf8.encodedLength(this.registerNameTransactionData.getName());
|
||||
if (nameLength < 1 || nameLength > Name.MAX_NAME_SIZE)
|
||||
int nameLength = Utf8.encodedLength(name);
|
||||
if (nameLength < Name.MIN_NAME_SIZE || nameLength > Name.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check data size bounds
|
||||
int dataLength = Utf8.encodedLength(this.registerNameTransactionData.getData());
|
||||
if (dataLength < 1 || dataLength > Name.MAX_DATA_SIZE)
|
||||
if (dataLength > Name.MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// Check name is lowercase
|
||||
if (!this.registerNameTransactionData.getName().equals(this.registerNameTransactionData.getName().toLowerCase()))
|
||||
if (!name.equals(name.toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
|
||||
// Check registrant has enough funds
|
||||
@ -78,10 +74,9 @@ public class RegisterNameTransaction extends Transaction {
|
||||
if (this.repository.getNameRepository().nameExists(this.registerNameTransactionData.getName()))
|
||||
return ValidationResult.NAME_ALREADY_REGISTERED;
|
||||
|
||||
Account registrant = getRegistrant();
|
||||
|
||||
// If accounts are only allowed one registered name then check for this
|
||||
if (BlockChain.getInstance().oneNamePerAccount() && !this.repository.getNameRepository().getNamesByOwner(registrant.getAddress()).isEmpty())
|
||||
if (BlockChain.getInstance().oneNamePerAccount()
|
||||
&& !this.repository.getNameRepository().getNamesByOwner(getRegistrant().getAddress()).isEmpty())
|
||||
return ValidationResult.MULTIPLE_NAMES_FORBIDDEN;
|
||||
|
||||
return ValidationResult.OK;
|
||||
|
@ -5,7 +5,6 @@ import java.util.List;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.naming.NameData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.UpdateNameTransactionData;
|
||||
@ -32,7 +31,7 @@ public class UpdateNameTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public List<String> getRecipientAddresses() throws DataException {
|
||||
return Collections.singletonList(this.updateNameTransactionData.getNewOwner());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Navigation
|
||||
@ -41,30 +40,17 @@ public class UpdateNameTransaction extends Transaction {
|
||||
return this.getCreator();
|
||||
}
|
||||
|
||||
public Account getNewOwner() {
|
||||
return new Account(this.repository, this.updateNameTransactionData.getNewOwner());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
String name = this.updateNameTransactionData.getName();
|
||||
|
||||
// Check new owner address is valid
|
||||
if (!Crypto.isValidAddress(this.updateNameTransactionData.getNewOwner()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
|
||||
// Check name size bounds
|
||||
int nameLength = Utf8.encodedLength(name);
|
||||
if (nameLength < 1 || nameLength > Name.MAX_NAME_SIZE)
|
||||
if (nameLength < Name.MIN_NAME_SIZE || nameLength > Name.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check new data size bounds
|
||||
int newDataLength = Utf8.encodedLength(this.updateNameTransactionData.getNewData());
|
||||
if (newDataLength < 1 || newDataLength > Name.MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// Check name is lowercase
|
||||
if (!name.equals(name.toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
@ -79,6 +65,24 @@ public class UpdateNameTransaction extends Transaction {
|
||||
if (nameData.getCreationGroupId() != this.updateNameTransactionData.getTxGroupId())
|
||||
return ValidationResult.TX_GROUP_ID_MISMATCH;
|
||||
|
||||
// Check new name (0 length means don't update name)
|
||||
String newName = this.updateNameTransactionData.getNewName();
|
||||
int newNameLength = Utf8.encodedLength(newName);
|
||||
if (newNameLength != 0) {
|
||||
// Check new name size bounds
|
||||
if (newNameLength < Name.MIN_NAME_SIZE || newNameLength > Name.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check new name is lowercase
|
||||
if (!newName.equals(newName.toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
}
|
||||
|
||||
// Check new data size bounds (0 length means don't update data)
|
||||
int newDataLength = Utf8.encodedLength(this.updateNameTransactionData.getNewData());
|
||||
if (newDataLength > Name.MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
Account owner = getOwner();
|
||||
|
||||
// Check owner has enough funds
|
||||
@ -92,6 +96,10 @@ public class UpdateNameTransaction extends Transaction {
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
NameData nameData = this.repository.getNameRepository().fromName(this.updateNameTransactionData.getName());
|
||||
|
||||
// Check name still exists
|
||||
if (nameData == null)
|
||||
return ValidationResult.NAME_DOES_NOT_EXIST;
|
||||
|
||||
// Check name isn't currently for sale
|
||||
if (nameData.getIsForSale())
|
||||
return ValidationResult.NAME_ALREADY_FOR_SALE;
|
||||
@ -102,6 +110,10 @@ public class UpdateNameTransaction extends Transaction {
|
||||
if (!owner.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_NAME_OWNER;
|
||||
|
||||
// Check new name isn't already taken
|
||||
if (this.repository.getNameRepository().nameExists(this.updateNameTransactionData.getNewName()))
|
||||
return ValidationResult.NAME_ALREADY_REGISTERED;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@ -111,7 +123,7 @@ public class UpdateNameTransaction extends Transaction {
|
||||
Name name = new Name(this.repository, this.updateNameTransactionData.getName());
|
||||
name.update(this.updateNameTransactionData);
|
||||
|
||||
// Save this transaction, now with updated "name reference" to previous transaction that updated name
|
||||
// Save this transaction, now with updated "name reference" to previous transaction that changed name
|
||||
this.repository.getTransactionRepository().save(this.updateNameTransactionData);
|
||||
}
|
||||
|
||||
@ -121,7 +133,7 @@ public class UpdateNameTransaction extends Transaction {
|
||||
Name name = new Name(this.repository, this.updateNameTransactionData.getName());
|
||||
name.revert(this.updateNameTransactionData);
|
||||
|
||||
// Save this transaction, now with removed "name reference"
|
||||
// Save this transaction, with previous "name reference"
|
||||
this.repository.getTransactionRepository().save(this.updateNameTransactionData);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
layout.add("transaction's groupID", TransformationType.INT);
|
||||
layout.add("reference", TransformationType.SIGNATURE);
|
||||
layout.add("name registrant's public key", TransformationType.PUBLIC_KEY);
|
||||
layout.add("name owner", TransformationType.ADDRESS);
|
||||
layout.add("name length", TransformationType.INT);
|
||||
layout.add("name", TransformationType.STRING);
|
||||
layout.add("data length", TransformationType.INT);
|
||||
@ -52,8 +51,6 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
byte[] registrantPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String owner = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String name = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE);
|
||||
|
||||
String data = Serialization.deserializeSizedString(byteBuffer, Name.MAX_DATA_SIZE);
|
||||
@ -65,7 +62,7 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, registrantPublicKey, fee, signature);
|
||||
|
||||
return new RegisterNameTransactionData(baseTransactionData, owner, name, data);
|
||||
return new RegisterNameTransactionData(baseTransactionData, name, data);
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
@ -83,8 +80,6 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
transformCommonBytes(transactionData, bytes);
|
||||
|
||||
Serialization.serializeAddress(bytes, registerNameTransactionData.getOwner());
|
||||
|
||||
Serialization.serializeSizedString(bytes, registerNameTransactionData.getName());
|
||||
|
||||
Serialization.serializeSizedString(bytes, registerNameTransactionData.getData());
|
||||
|
@ -18,11 +18,11 @@ import com.google.common.primitives.Longs;
|
||||
public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
// Property lengths
|
||||
private static final int OWNER_LENGTH = ADDRESS_LENGTH;
|
||||
private static final int NAME_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int DATA_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int NEW_NAME_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int NEW_DATA_SIZE_LENGTH = INT_LENGTH;
|
||||
|
||||
private static final int EXTRAS_LENGTH = OWNER_LENGTH + NAME_SIZE_LENGTH + DATA_SIZE_LENGTH;
|
||||
private static final int EXTRAS_LENGTH = NAME_SIZE_LENGTH + NEW_NAME_SIZE_LENGTH + NEW_DATA_SIZE_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
@ -33,10 +33,11 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
layout.add("transaction's groupID", TransformationType.INT);
|
||||
layout.add("reference", TransformationType.SIGNATURE);
|
||||
layout.add("name owner's public key", TransformationType.PUBLIC_KEY);
|
||||
layout.add("name's new owner", TransformationType.ADDRESS);
|
||||
layout.add("name length", TransformationType.INT);
|
||||
layout.add("name", TransformationType.STRING);
|
||||
layout.add("new data length", TransformationType.INT);
|
||||
layout.add("new name's length (0 for no change)", TransformationType.INT);
|
||||
layout.add("new name", TransformationType.STRING);
|
||||
layout.add("new data length (0 for no change)", TransformationType.INT);
|
||||
layout.add("new data", TransformationType.STRING);
|
||||
layout.add("fee", TransformationType.AMOUNT);
|
||||
layout.add("signature", TransformationType.SIGNATURE);
|
||||
@ -52,10 +53,10 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
byte[] ownerPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String newOwner = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String name = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE);
|
||||
|
||||
String newName = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE);
|
||||
|
||||
String newData = Serialization.deserializeSizedString(byteBuffer, Name.MAX_DATA_SIZE);
|
||||
|
||||
long fee = byteBuffer.getLong();
|
||||
@ -65,13 +66,14 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, ownerPublicKey, fee, signature);
|
||||
|
||||
return new UpdateNameTransactionData(baseTransactionData, newOwner, name, newData);
|
||||
return new UpdateNameTransactionData(baseTransactionData, name, newName, newData);
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
UpdateNameTransactionData updateNameTransactionData = (UpdateNameTransactionData) transactionData;
|
||||
|
||||
return getBaseLength(transactionData) + EXTRAS_LENGTH + Utf8.encodedLength(updateNameTransactionData.getName())
|
||||
+ Utf8.encodedLength(updateNameTransactionData.getNewName())
|
||||
+ Utf8.encodedLength(updateNameTransactionData.getNewData());
|
||||
}
|
||||
|
||||
@ -83,10 +85,10 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
transformCommonBytes(transactionData, bytes);
|
||||
|
||||
Serialization.serializeAddress(bytes, updateNameTransactionData.getNewOwner());
|
||||
|
||||
Serialization.serializeSizedString(bytes, updateNameTransactionData.getName());
|
||||
|
||||
Serialization.serializeSizedString(bytes, updateNameTransactionData.getNewName());
|
||||
|
||||
Serialization.serializeSizedString(bytes, updateNameTransactionData.getNewData());
|
||||
|
||||
bytes.write(Longs.toByteArray(updateNameTransactionData.getFee()));
|
||||
|
@ -46,7 +46,7 @@ public class NamesApiTests extends ApiCommon {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), alice.getAddress(), name, "{}");
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}");
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
assertNotNull(this.namesResource.getNamesByAddress(alice.getAddress(), null, null, null));
|
||||
@ -61,7 +61,7 @@ public class NamesApiTests extends ApiCommon {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), alice.getAddress(), name, "{}");
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}");
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
assertNotNull(this.namesResource.getName(name));
|
||||
@ -76,7 +76,7 @@ public class NamesApiTests extends ApiCommon {
|
||||
String name = "test-name";
|
||||
long price = 1_23456789L;
|
||||
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), alice.getAddress(), name, "{}");
|
||||
TransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}");
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
// Sell-name
|
||||
|
@ -9,14 +9,13 @@ import org.qortal.repository.Repository;
|
||||
public class RegisterNameTestTransaction extends TestTransaction {
|
||||
|
||||
public static TransactionData randomTransaction(Repository repository, PrivateKeyAccount account, boolean wantValid) throws DataException {
|
||||
String owner = account.getAddress();
|
||||
String name = "test name";
|
||||
if (!wantValid)
|
||||
name += " " + random.nextInt(1_000_000);
|
||||
|
||||
String data = "{ \"key\": \"value\" }";
|
||||
|
||||
return new RegisterNameTransactionData(generateBase(account), owner, name, data);
|
||||
return new RegisterNameTransactionData(generateBase(account), name, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class BuySellTests extends Common {
|
||||
@Test
|
||||
public void testRegisterName() throws DataException {
|
||||
// Register-name
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), alice.getAddress(), name, "{}");
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}");
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
String name = transactionData.getName();
|
||||
|
@ -29,7 +29,7 @@ public class MiscTests extends Common {
|
||||
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||
String name = "test-name";
|
||||
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), alice.getAddress(), name, "{}");
|
||||
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "{}");
|
||||
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||
|
||||
List<String> recentNames = repository.getNameRepository().getRecentNames(0L);
|
||||
|
Loading…
Reference in New Issue
Block a user