forked from Qortal/qortal
Added BuyNameTransaction support
Fixed IssueAssetTransactions not being constructed with signature. Fixed incorrect MessageTransactionData constructors. Refactored various transactions to remove duplicate code. e.g. in CancelOrderTransaction.process() use getCreator() instead of explicit repository call. Added name_reference to BuyNameTransactions HSQLDB table. Fixed incorrect SQL in HSQLDBMultiPaymentTransactionRepository. More unit tests! Fixed wrong data length in CancelOrderTransactionTransformer. Fixed wrong data length in CreateOrderTransactionTransformer. Fixed missing payment bytes in MultiPaymentTransactionTransformer.toBytes();
This commit is contained in:
parent
c8be77e7cc
commit
2bfb0227ae
68
src/data/transaction/BuyNameTransactionData.java
Normal file
68
src/data/transaction/BuyNameTransactionData.java
Normal file
@ -0,0 +1,68 @@
|
||||
package data.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import qora.transaction.Transaction.TransactionType;
|
||||
|
||||
public class BuyNameTransactionData extends TransactionData {
|
||||
|
||||
// Properties
|
||||
private byte[] buyerPublicKey;
|
||||
private String name;
|
||||
private BigDecimal amount;
|
||||
private String seller;
|
||||
private byte[] nameReference;
|
||||
|
||||
// Constructors
|
||||
|
||||
public BuyNameTransactionData(byte[] buyerPublicKey, String name, BigDecimal amount, String seller, byte[] nameReference, BigDecimal fee, long timestamp,
|
||||
byte[] reference, byte[] signature) {
|
||||
super(TransactionType.BUY_NAME, fee, buyerPublicKey, timestamp, reference, signature);
|
||||
|
||||
this.buyerPublicKey = buyerPublicKey;
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
this.seller = seller;
|
||||
}
|
||||
|
||||
public BuyNameTransactionData(byte[] buyerPublicKey, String name, BigDecimal amount, String seller, BigDecimal fee, long timestamp, byte[] reference,
|
||||
byte[] signature) {
|
||||
this(buyerPublicKey, name, amount, seller, null, fee, timestamp, reference, signature);
|
||||
}
|
||||
|
||||
public BuyNameTransactionData(byte[] buyerPublicKey, String name, BigDecimal amount, String seller, byte[] nameReference, BigDecimal fee, long timestamp,
|
||||
byte[] reference) {
|
||||
this(buyerPublicKey, name, amount, seller, nameReference, fee, timestamp, reference, null);
|
||||
}
|
||||
|
||||
public BuyNameTransactionData(byte[] buyerPublicKey, String name, BigDecimal amount, String seller, BigDecimal fee, long timestamp, byte[] reference) {
|
||||
this(buyerPublicKey, name, amount, seller, null, fee, timestamp, reference, null);
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
|
||||
public byte[] getBuyerPublicKey() {
|
||||
return this.buyerPublicKey;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public String getSeller() {
|
||||
return this.seller;
|
||||
}
|
||||
|
||||
public byte[] getNameReference() {
|
||||
return this.nameReference;
|
||||
}
|
||||
|
||||
public void setNameReference(byte[] nameReference) {
|
||||
this.nameReference = nameReference;
|
||||
}
|
||||
|
||||
}
|
@ -19,6 +19,10 @@ public class CancelOrderTransactionData extends TransactionData {
|
||||
this.orderId = orderId;
|
||||
}
|
||||
|
||||
public CancelOrderTransactionData(byte[] creatorPublicKey, byte[] orderId, BigDecimal fee, long timestamp, byte[] reference) {
|
||||
this(creatorPublicKey, orderId, fee, timestamp, reference, null);
|
||||
}
|
||||
|
||||
// Getters/Setters
|
||||
|
||||
public byte[] getCreatorPublicKey() {
|
||||
|
@ -20,7 +20,7 @@ public class IssueAssetTransactionData extends TransactionData {
|
||||
|
||||
public IssueAssetTransactionData(Long assetId, byte[] issuerPublicKey, String owner, String assetName, String description, long quantity,
|
||||
boolean isDivisible, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) {
|
||||
super(TransactionType.ISSUE_ASSET, fee, issuerPublicKey, timestamp, reference);
|
||||
super(TransactionType.ISSUE_ASSET, fee, issuerPublicKey, timestamp, reference, signature);
|
||||
|
||||
this.assetId = assetId;
|
||||
this.issuerPublicKey = issuerPublicKey;
|
||||
|
@ -18,8 +18,9 @@ public class MessageTransactionData extends TransactionData {
|
||||
protected boolean isEncrypted;
|
||||
|
||||
// Constructors
|
||||
public MessageTransactionData(int version, byte[] senderPublicKey, String recipient, Long assetId, BigDecimal amount, BigDecimal fee, byte[] data,
|
||||
boolean isText, boolean isEncrypted, long timestamp, byte[] reference, byte[] signature) {
|
||||
|
||||
public MessageTransactionData(int version, byte[] senderPublicKey, String recipient, Long assetId, BigDecimal amount, byte[] data, boolean isText,
|
||||
boolean isEncrypted, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) {
|
||||
super(TransactionType.MESSAGE, fee, senderPublicKey, timestamp, reference, signature);
|
||||
|
||||
this.version = version;
|
||||
@ -37,6 +38,11 @@ public class MessageTransactionData extends TransactionData {
|
||||
this.isEncrypted = isEncrypted;
|
||||
}
|
||||
|
||||
public MessageTransactionData(int version, byte[] senderPublicKey, String recipient, Long assetId, BigDecimal amount, byte[] data, boolean isText,
|
||||
boolean isEncrypted, BigDecimal fee, long timestamp, byte[] reference) {
|
||||
this(version, senderPublicKey, recipient, assetId, amount, data, isText, isEncrypted, fee, timestamp, reference, null);
|
||||
}
|
||||
|
||||
// Getters/Setters
|
||||
|
||||
public int getVersion() {
|
||||
|
@ -26,6 +26,11 @@ public class UpdateNameTransactionData extends TransactionData {
|
||||
this.nameReference = nameReference;
|
||||
}
|
||||
|
||||
public UpdateNameTransactionData(byte[] ownerPublicKey, String newOwner, String name, String newData, BigDecimal fee, long timestamp, byte[] reference,
|
||||
byte[] signature) {
|
||||
this(ownerPublicKey, newOwner, name, newData, null, fee, timestamp, reference, signature);
|
||||
}
|
||||
|
||||
public UpdateNameTransactionData(byte[] ownerPublicKey, String newOwner, String name, String newData, byte[] nameReference, BigDecimal fee, long timestamp,
|
||||
byte[] reference) {
|
||||
this(ownerPublicKey, newOwner, name, newData, nameReference, fee, timestamp, reference, null);
|
||||
|
@ -1,11 +1,14 @@
|
||||
package qora.naming;
|
||||
|
||||
import data.naming.NameData;
|
||||
import data.transaction.BuyNameTransactionData;
|
||||
import data.transaction.CancelSellNameTransactionData;
|
||||
import data.transaction.RegisterNameTransactionData;
|
||||
import data.transaction.SellNameTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import data.transaction.UpdateNameTransactionData;
|
||||
import qora.account.Account;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
|
||||
@ -56,6 +59,35 @@ public class Name {
|
||||
this.repository.getNameRepository().delete(this.nameData.getName());
|
||||
}
|
||||
|
||||
private void revert() throws DataException {
|
||||
TransactionData previousTransactionData = this.repository.getTransactionRepository().fromSignature(this.nameData.getReference());
|
||||
if (previousTransactionData == null)
|
||||
throw new DataException("Unable to revert name transaction as referenced transaction not found in repository");
|
||||
|
||||
switch (previousTransactionData.getType()) {
|
||||
case REGISTER_NAME:
|
||||
RegisterNameTransactionData previousRegisterNameTransactionData = (RegisterNameTransactionData) previousTransactionData;
|
||||
this.nameData.setOwner(previousRegisterNameTransactionData.getOwner());
|
||||
this.nameData.setData(previousRegisterNameTransactionData.getData());
|
||||
break;
|
||||
|
||||
case UPDATE_NAME:
|
||||
UpdateNameTransactionData previousUpdateNameTransactionData = (UpdateNameTransactionData) previousTransactionData;
|
||||
this.nameData.setData(previousUpdateNameTransactionData.getNewData());
|
||||
this.nameData.setOwner(previousUpdateNameTransactionData.getNewOwner());
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
public void update(UpdateNameTransactionData updateNameTransactionData) throws DataException {
|
||||
// Update reference in transaction data
|
||||
updateNameTransactionData.setNameReference(this.nameData.getReference());
|
||||
@ -76,26 +108,7 @@ public class Name {
|
||||
this.nameData.setReference(updateNameTransactionData.getNameReference());
|
||||
|
||||
// Previous Name's owner and/or data taken from referenced transaction
|
||||
TransactionData previousTransactionData = this.repository.getTransactionRepository().fromSignature(this.nameData.getReference());
|
||||
if (previousTransactionData == null)
|
||||
throw new DataException("Unable to un-update name as referenced transaction not found in repository");
|
||||
|
||||
switch (previousTransactionData.getType()) {
|
||||
case REGISTER_NAME:
|
||||
RegisterNameTransactionData previousRegisterNameTransactionData = (RegisterNameTransactionData) previousTransactionData;
|
||||
this.nameData.setOwner(previousRegisterNameTransactionData.getOwner());
|
||||
this.nameData.setData(previousRegisterNameTransactionData.getData());
|
||||
break;
|
||||
|
||||
case UPDATE_NAME:
|
||||
UpdateNameTransactionData previousUpdateNameTransactionData = (UpdateNameTransactionData) previousTransactionData;
|
||||
this.nameData.setData(previousUpdateNameTransactionData.getNewData());
|
||||
this.nameData.setOwner(previousUpdateNameTransactionData.getNewOwner());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unable to revert update name transaction due to unsupported referenced transaction");
|
||||
}
|
||||
this.revert();
|
||||
|
||||
// Save reverted name data
|
||||
this.repository.getNameRepository().save(this.nameData);
|
||||
@ -135,4 +148,36 @@ public class Name {
|
||||
this.repository.getNameRepository().save(this.nameData);
|
||||
}
|
||||
|
||||
public void buy(BuyNameTransactionData buyNameTransactionData) throws DataException {
|
||||
// Mark not for-sale but leave price in case we want to orphan
|
||||
this.nameData.setIsForSale(false);
|
||||
|
||||
// Set new owner
|
||||
Account buyer = new PublicKeyAccount(this.repository, buyNameTransactionData.getBuyerPublicKey());
|
||||
this.nameData.setOwner(buyer.getAddress());
|
||||
|
||||
// Update reference in transaction data
|
||||
buyNameTransactionData.setNameReference(this.nameData.getReference());
|
||||
|
||||
// New name reference is this transaction's signature
|
||||
this.nameData.setReference(buyNameTransactionData.getSignature());
|
||||
|
||||
// Save updated name data
|
||||
this.repository.getNameRepository().save(this.nameData);
|
||||
}
|
||||
|
||||
public void unbuy(BuyNameTransactionData buyNameTransactionData) throws DataException {
|
||||
// Mark as for-sale using existing price
|
||||
this.nameData.setIsForSale(true);
|
||||
|
||||
// Previous name reference is taken from this transaction's cached copy
|
||||
this.nameData.setReference(buyNameTransactionData.getNameReference());
|
||||
|
||||
// Previous Name's owner and/or data taken from referenced transaction
|
||||
this.revert();
|
||||
|
||||
// Save reverted name data
|
||||
this.repository.getNameRepository().save(this.nameData);
|
||||
}
|
||||
|
||||
}
|
||||
|
155
src/qora/transaction/BuyNameTransaction.java
Normal file
155
src/qora/transaction/BuyNameTransaction.java
Normal file
@ -0,0 +1,155 @@
|
||||
package qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Utf8;
|
||||
|
||||
import data.naming.NameData;
|
||||
import data.transaction.BuyNameTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.account.Account;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.assets.Asset;
|
||||
import qora.naming.Name;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
|
||||
public class BuyNameTransaction extends Transaction {
|
||||
|
||||
// Properties
|
||||
private BuyNameTransactionData buyNameTransactionData;
|
||||
|
||||
// Constructors
|
||||
|
||||
public BuyNameTransaction(Repository repository, TransactionData transactionData) {
|
||||
super(repository, transactionData);
|
||||
|
||||
this.buyNameTransactionData = (BuyNameTransactionData) this.transactionData;
|
||||
}
|
||||
|
||||
// More information
|
||||
|
||||
@Override
|
||||
public List<Account> getRecipientAccounts() throws DataException {
|
||||
return Collections.singletonList(new Account(this.repository, this.buyNameTransactionData.getSeller()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvolved(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
|
||||
if (address.equals(this.getBuyer().getAddress()))
|
||||
return true;
|
||||
|
||||
if (address.equals(this.buyNameTransactionData.getSeller()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getAmount(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
BigDecimal amount = BigDecimal.ZERO.setScale(8);
|
||||
|
||||
if (address.equals(this.getBuyer().getAddress()))
|
||||
amount = amount.subtract(this.transactionData.getFee());
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getBuyer() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, this.buyNameTransactionData.getBuyerPublicKey());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Check name size bounds
|
||||
int nameLength = Utf8.encodedLength(buyNameTransactionData.getName());
|
||||
if (nameLength < 1 || nameLength > Name.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check name is lowercase
|
||||
if (!buyNameTransactionData.getName().equals(buyNameTransactionData.getName().toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
|
||||
NameData nameData = this.repository.getNameRepository().fromName(buyNameTransactionData.getName());
|
||||
|
||||
// Check name exists
|
||||
if (nameData == null)
|
||||
return ValidationResult.NAME_DOES_NOT_EXIST;
|
||||
|
||||
// Check name is currently for sale
|
||||
if (!nameData.getIsForSale())
|
||||
return ValidationResult.NAME_NOT_FOR_SALE;
|
||||
|
||||
// Check buyer isn't trying to buy own name
|
||||
Account buyer = getBuyer();
|
||||
if (buyer.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.BUYER_ALREADY_OWNER;
|
||||
|
||||
// Check expected seller currently owns name
|
||||
if (!buyNameTransactionData.getSeller().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_SELLER;
|
||||
|
||||
// Check amounts agree
|
||||
if (buyNameTransactionData.getAmount().compareTo(nameData.getSalePrice()) != 0)
|
||||
return ValidationResult.INVALID_AMOUNT;
|
||||
|
||||
// Check fee is positive
|
||||
if (buyNameTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(buyer.getLastReference(), buyNameTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (buyer.getConfirmedBalance(Asset.QORA).compareTo(buyNameTransactionData.getFee()) == -1)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update Name
|
||||
Name name = new Name(this.repository, buyNameTransactionData.getName());
|
||||
name.buy(buyNameTransactionData);
|
||||
|
||||
// Save this transaction, now with updated "name reference" to previous transaction that updated name
|
||||
this.repository.getTransactionRepository().save(buyNameTransactionData);
|
||||
|
||||
// Update buyer's balance
|
||||
Account buyer = getBuyer();
|
||||
buyer.setConfirmedBalance(Asset.QORA, buyer.getConfirmedBalance(Asset.QORA).subtract(buyNameTransactionData.getFee()));
|
||||
|
||||
// Update buyer's reference
|
||||
buyer.setLastReference(buyNameTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Revert name
|
||||
Name name = new Name(this.repository, buyNameTransactionData.getName());
|
||||
name.unbuy(buyNameTransactionData);
|
||||
|
||||
// Delete this transaction itself
|
||||
this.repository.getTransactionRepository().delete(buyNameTransactionData);
|
||||
|
||||
// Update buyer's balance
|
||||
Account buyer = getBuyer();
|
||||
buyer.setConfirmedBalance(Asset.QORA, buyer.getConfirmedBalance(Asset.QORA).add(buyNameTransactionData.getFee()));
|
||||
|
||||
// Update buyer's reference
|
||||
buyer.setLastReference(buyNameTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
@ -49,6 +49,12 @@ public class CancelOrderTransaction extends Transaction {
|
||||
return amount;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getCreator() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, cancelOrderTransactionData.getCreatorPublicKey());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
@ -65,7 +71,7 @@ public class CancelOrderTransaction extends Transaction {
|
||||
if (orderData == null)
|
||||
return ValidationResult.ORDER_DOES_NOT_EXIST;
|
||||
|
||||
Account creator = new PublicKeyAccount(this.repository, cancelOrderTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
// Check creator's public key results in valid address
|
||||
if (!Crypto.isValidAddress(creator.getAddress()))
|
||||
@ -89,7 +95,7 @@ public class CancelOrderTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
Account creator = new PublicKeyAccount(this.repository, cancelOrderTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
// Save this transaction itself
|
||||
this.repository.getTransactionRepository().save(this.transactionData);
|
||||
@ -111,7 +117,7 @@ public class CancelOrderTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
Account creator = new PublicKeyAccount(this.repository, cancelOrderTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
// Save this transaction itself
|
||||
this.repository.getTransactionRepository().delete(this.transactionData);
|
||||
|
@ -88,7 +88,7 @@ public class CancelSellNameTransaction extends Transaction {
|
||||
return ValidationResult.NAME_NOT_FOR_SALE;
|
||||
|
||||
// Check transaction's public key matches name's current owner
|
||||
Account owner = new PublicKeyAccount(this.repository, cancelSellNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
if (!owner.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_NAME_OWNER;
|
||||
|
||||
@ -118,7 +118,7 @@ public class CancelSellNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().save(cancelSellNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = new PublicKeyAccount(this.repository, cancelSellNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(cancelSellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
@ -135,7 +135,7 @@ public class CancelSellNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().delete(cancelSellNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = new PublicKeyAccount(this.repository, cancelSellNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(cancelSellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
|
@ -52,6 +52,10 @@ public class CreateOrderTransaction extends Transaction {
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getCreator() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
|
||||
}
|
||||
|
||||
public Order getOrder() throws DataException {
|
||||
// orderId is the transaction signature
|
||||
OrderData orderData = this.repository.getAssetRepository().fromOrderId(this.createOrderTransactionData.getSignature());
|
||||
@ -92,7 +96,7 @@ public class CreateOrderTransaction extends Transaction {
|
||||
if (wantAssetData == null)
|
||||
return ValidationResult.ASSET_DOES_NOT_EXIST;
|
||||
|
||||
Account creator = new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(creator.getLastReference(), createOrderTransactionData.getReference()))
|
||||
@ -129,7 +133,7 @@ public class CreateOrderTransaction extends Transaction {
|
||||
}
|
||||
|
||||
public void process() throws DataException {
|
||||
Account creator = new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update creator's balance due to fee
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createOrderTransactionData.getFee()));
|
||||
@ -152,7 +156,7 @@ public class CreateOrderTransaction extends Transaction {
|
||||
}
|
||||
|
||||
public void orphan() throws DataException {
|
||||
Account creator = new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update creator's balance due to fee
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createOrderTransactionData.getFee()));
|
||||
|
@ -131,7 +131,7 @@ public class CreatePollTransaction extends Transaction {
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount creator = new PublicKeyAccount(this.repository, createPollTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
|
||||
if (!Arrays.equals(creator.getLastReference(), createPollTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
@ -153,7 +153,7 @@ public class CreatePollTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().save(createPollTransactionData);
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = new PublicKeyAccount(this.repository, createPollTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createPollTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
@ -170,7 +170,7 @@ public class CreatePollTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().delete(createPollTransactionData);
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = new PublicKeyAccount(this.repository, createPollTransactionData.getCreatorPublicKey());
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createPollTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
|
@ -106,7 +106,7 @@ public class IssueAssetTransaction extends Transaction {
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount issuer = new PublicKeyAccount(this.repository, issueAssetTransactionData.getIssuerPublicKey());
|
||||
Account issuer = getIssuer();
|
||||
|
||||
if (!Arrays.equals(issuer.getLastReference(), issueAssetTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
@ -134,20 +134,20 @@ public class IssueAssetTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().save(issueAssetTransactionData);
|
||||
|
||||
// Update issuer's balance
|
||||
Account issuer = new PublicKeyAccount(this.repository, issueAssetTransactionData.getIssuerPublicKey());
|
||||
Account issuer = getIssuer();
|
||||
issuer.setConfirmedBalance(Asset.QORA, issuer.getConfirmedBalance(Asset.QORA).subtract(issueAssetTransactionData.getFee()));
|
||||
|
||||
// Update issuer's reference
|
||||
issuer.setLastReference(issueAssetTransactionData.getSignature());
|
||||
|
||||
// Add asset to owner
|
||||
Account owner = new Account(this.repository, issueAssetTransactionData.getOwner());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(issueAssetTransactionData.getAssetId(), BigDecimal.valueOf(issueAssetTransactionData.getQuantity()).setScale(8));
|
||||
}
|
||||
|
||||
public void orphan() throws DataException {
|
||||
// Remove asset from owner
|
||||
Account owner = new Account(this.repository, issueAssetTransactionData.getOwner());
|
||||
Account owner = getOwner();
|
||||
owner.deleteBalance(issueAssetTransactionData.getAssetId());
|
||||
|
||||
// Issue asset
|
||||
@ -158,7 +158,7 @@ public class IssueAssetTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().delete(issueAssetTransactionData);
|
||||
|
||||
// Update issuer's balance
|
||||
Account issuer = new PublicKeyAccount(this.repository, issueAssetTransactionData.getIssuerPublicKey());
|
||||
Account issuer = getIssuer();
|
||||
issuer.setConfirmedBalance(Asset.QORA, issuer.getConfirmedBalance(Asset.QORA).add(issueAssetTransactionData.getFee()));
|
||||
|
||||
// Update issuer's reference
|
||||
|
@ -98,7 +98,7 @@ public class MessageTransaction extends Transaction {
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// Check reference is correct
|
||||
Account sender = new PublicKeyAccount(this.repository, messageTransactionData.getSenderPublicKey());
|
||||
Account sender = getSender();
|
||||
if (!Arrays.equals(sender.getLastReference(), messageTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
|
@ -98,7 +98,7 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
return ValidationResult.INVALID_PAYMENTS_COUNT;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount sender = new PublicKeyAccount(this.repository, multiPaymentTransactionData.getSenderPublicKey());
|
||||
Account sender = getSender();
|
||||
|
||||
if (!Arrays.equals(sender.getLastReference(), multiPaymentTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
@ -74,7 +74,7 @@ public class PaymentTransaction extends Transaction {
|
||||
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Check reference is correct
|
||||
Account sender = new PublicKeyAccount(repository, paymentTransactionData.getSenderPublicKey());
|
||||
Account sender = getSender();
|
||||
if (!Arrays.equals(sender.getLastReference(), paymentTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
|
@ -102,7 +102,7 @@ public class RegisterNameTransaction extends Transaction {
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount registrant = new PublicKeyAccount(this.repository, registerNameTransactionData.getRegistrantPublicKey());
|
||||
Account registrant = getRegistrant();
|
||||
|
||||
if (!Arrays.equals(registrant.getLastReference(), registerNameTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
@ -124,7 +124,7 @@ public class RegisterNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().save(registerNameTransactionData);
|
||||
|
||||
// Update registrant's balance
|
||||
Account registrant = new PublicKeyAccount(this.repository, registerNameTransactionData.getRegistrantPublicKey());
|
||||
Account registrant = getRegistrant();
|
||||
registrant.setConfirmedBalance(Asset.QORA, registrant.getConfirmedBalance(Asset.QORA).subtract(registerNameTransactionData.getFee()));
|
||||
|
||||
// Update registrant's reference
|
||||
@ -141,7 +141,7 @@ public class RegisterNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().delete(registerNameTransactionData);
|
||||
|
||||
// Update registrant's balance
|
||||
Account registrant = new PublicKeyAccount(this.repository, registerNameTransactionData.getRegistrantPublicKey());
|
||||
Account registrant = getRegistrant();
|
||||
registrant.setConfirmedBalance(Asset.QORA, registrant.getConfirmedBalance(Asset.QORA).add(registerNameTransactionData.getFee()));
|
||||
|
||||
// Update registrant's reference
|
||||
|
@ -89,7 +89,7 @@ public class SellNameTransaction extends Transaction {
|
||||
return ValidationResult.NAME_ALREADY_FOR_SALE;
|
||||
|
||||
// Check transaction's public key matches name's current owner
|
||||
Account owner = new PublicKeyAccount(this.repository, sellNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
if (!owner.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_NAME_OWNER;
|
||||
|
||||
@ -114,7 +114,6 @@ public class SellNameTransaction extends Transaction {
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -127,7 +126,7 @@ public class SellNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().save(sellNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = new PublicKeyAccount(this.repository, sellNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(sellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
@ -144,7 +143,7 @@ public class SellNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().delete(sellNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = new PublicKeyAccount(this.repository, sellNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(sellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
|
@ -44,12 +44,13 @@ public abstract class Transaction {
|
||||
// Validation results
|
||||
public enum ValidationResult {
|
||||
OK(1), INVALID_ADDRESS(2), NEGATIVE_AMOUNT(3), NEGATIVE_FEE(4), NO_BALANCE(5), INVALID_REFERENCE(6), INVALID_NAME_LENGTH(7), INVALID_VALUE_LENGTH(
|
||||
8), NAME_ALREADY_REGISTERED(9), NAME_DOES_NOT_EXIST(10), INVALID_NAME_OWNER(11), NAME_ALREADY_FOR_SALE(12), NAME_NOT_FOR_SALE(13), INVALID_AMOUNT(
|
||||
15), NAME_NOT_LOWER_CASE(17), INVALID_DESCRIPTION_LENGTH(18), INVALID_OPTIONS_COUNT(19), INVALID_OPTION_LENGTH(20), DUPLICATE_OPTION(
|
||||
21), POLL_ALREADY_EXISTS(22), POLL_DOES_NOT_EXIST(24), POLL_OPTION_DOES_NOT_EXIST(25), ALREADY_VOTED_FOR_THAT_OPTION(
|
||||
26), INVALID_DATA_LENGTH(27), INVALID_QUANTITY(28), ASSET_DOES_NOT_EXIST(29), INVALID_RETURN(30), HAVE_EQUALS_WANT(
|
||||
31), ORDER_DOES_NOT_EXIST(32), INVALID_ORDER_CREATOR(
|
||||
33), INVALID_PAYMENTS_COUNT(34), NEGATIVE_PRICE(35), ASSET_ALREADY_EXISTS(43), NOT_YET_RELEASED(1000);
|
||||
8), NAME_ALREADY_REGISTERED(9), NAME_DOES_NOT_EXIST(10), INVALID_NAME_OWNER(11), NAME_ALREADY_FOR_SALE(12), NAME_NOT_FOR_SALE(
|
||||
13), BUYER_ALREADY_OWNER(14), INVALID_AMOUNT(15), INVALID_SELLER(16), NAME_NOT_LOWER_CASE(17), INVALID_DESCRIPTION_LENGTH(
|
||||
18), INVALID_OPTIONS_COUNT(19), INVALID_OPTION_LENGTH(20), DUPLICATE_OPTION(21), POLL_ALREADY_EXISTS(22), POLL_DOES_NOT_EXIST(
|
||||
24), POLL_OPTION_DOES_NOT_EXIST(25), ALREADY_VOTED_FOR_THAT_OPTION(26), INVALID_DATA_LENGTH(27), INVALID_QUANTITY(
|
||||
28), ASSET_DOES_NOT_EXIST(29), INVALID_RETURN(30), HAVE_EQUALS_WANT(31), ORDER_DOES_NOT_EXIST(
|
||||
32), INVALID_ORDER_CREATOR(33), INVALID_PAYMENTS_COUNT(
|
||||
34), NEGATIVE_PRICE(35), ASSET_ALREADY_EXISTS(43), NOT_YET_RELEASED(1000);
|
||||
|
||||
public final int value;
|
||||
|
||||
@ -117,6 +118,9 @@ public abstract class Transaction {
|
||||
case CANCEL_SELL_NAME:
|
||||
return new CancelSellNameTransaction(repository, transactionData);
|
||||
|
||||
case BUY_NAME:
|
||||
return new BuyNameTransaction(repository, transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return new CreatePollTransaction(repository, transactionData);
|
||||
|
||||
|
@ -89,7 +89,7 @@ public class TransferAssetTransaction extends Transaction {
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount sender = new PublicKeyAccount(this.repository, transferAssetTransactionData.getSenderPublicKey());
|
||||
Account sender = getSender();
|
||||
|
||||
if (!Arrays.equals(sender.getLastReference(), transferAssetTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
@ -105,7 +105,7 @@ public class UpdateNameTransaction extends Transaction {
|
||||
return ValidationResult.NAME_ALREADY_FOR_SALE;
|
||||
|
||||
// Check transaction's public key matches name's current owner
|
||||
Account owner = new PublicKeyAccount(this.repository, updateNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
if (!owner.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_NAME_OWNER;
|
||||
|
||||
@ -134,7 +134,7 @@ public class UpdateNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().save(updateNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = new PublicKeyAccount(this.repository, updateNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(updateNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
@ -151,7 +151,7 @@ public class UpdateNameTransaction extends Transaction {
|
||||
this.repository.getTransactionRepository().delete(updateNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = new PublicKeyAccount(this.repository, updateNameTransactionData.getOwnerPublicKey());
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).add(updateNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
|
@ -56,6 +56,12 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
return amount;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getVoter() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, voteOnPollTransactionData.getVoterPublicKey());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
@ -98,13 +104,13 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount creator = new PublicKeyAccount(this.repository, voteOnPollTransactionData.getCreatorPublicKey());
|
||||
Account voter = getVoter();
|
||||
|
||||
if (!Arrays.equals(creator.getLastReference(), voteOnPollTransactionData.getReference()))
|
||||
if (!Arrays.equals(voter.getLastReference(), voteOnPollTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(voteOnPollTransactionData.getFee()) == -1)
|
||||
// Check voter has enough funds
|
||||
if (voter.getConfirmedBalance(Asset.QORA).compareTo(voteOnPollTransactionData.getFee()) == -1)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
@ -113,7 +119,7 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update voter's balance
|
||||
Account voter = new PublicKeyAccount(this.repository, voteOnPollTransactionData.getVoterPublicKey());
|
||||
Account voter = getVoter();
|
||||
voter.setConfirmedBalance(Asset.QORA, voter.getConfirmedBalance(Asset.QORA).subtract(voteOnPollTransactionData.getFee()));
|
||||
|
||||
// Update vote's reference
|
||||
@ -138,11 +144,11 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Update issuer's balance
|
||||
Account voter = new PublicKeyAccount(this.repository, voteOnPollTransactionData.getVoterPublicKey());
|
||||
// Update voter's balance
|
||||
Account voter = getVoter();
|
||||
voter.setConfirmedBalance(Asset.QORA, voter.getConfirmedBalance(Asset.QORA).add(voteOnPollTransactionData.getFee()));
|
||||
|
||||
// Update issuer's reference
|
||||
// Update voter's reference
|
||||
voter.setLastReference(voteOnPollTransactionData.getReference());
|
||||
|
||||
// Does this transaction have previous vote info?
|
||||
|
@ -190,7 +190,7 @@ public class HSQLDBDatabaseUpdates {
|
||||
case 9:
|
||||
// Buy Name Transactions
|
||||
stmt.execute("CREATE TABLE BuyNameTransactions (signature Signature, buyer QoraPublicKey NOT NULL, name RegisteredName NOT NULL, "
|
||||
+ "seller QoraAddress NOT NULL, amount QoraAmount NOT NULL, "
|
||||
+ "seller QoraAddress NOT NULL, amount QoraAmount NOT NULL, name_reference Signature NOT NULL, "
|
||||
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||
break;
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
package repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import data.transaction.BuyNameTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import repository.DataException;
|
||||
import repository.hsqldb.HSQLDBRepository;
|
||||
import repository.hsqldb.HSQLDBSaver;
|
||||
|
||||
public class HSQLDBBuyNameTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBBuyNameTransactionRepository(HSQLDBRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
TransactionData fromBase(byte[] signature, byte[] reference, byte[] buyerPublicKey, long timestamp, BigDecimal fee) throws DataException {
|
||||
try {
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT name, amount, seller, name_reference FROM BuyNameTransactions WHERE signature = ?",
|
||||
signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
String name = rs.getString(1);
|
||||
BigDecimal amount = rs.getBigDecimal(2);
|
||||
String seller = rs.getString(3);
|
||||
byte[] nameReference = rs.getBytes(4);
|
||||
|
||||
return new BuyNameTransactionData(buyerPublicKey, name, amount, seller, nameReference, fee, timestamp, reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch buy name transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("BuyNameTransactions");
|
||||
|
||||
saveHelper.bind("signature", buyNameTransactionData.getSignature()).bind("buyer", buyNameTransactionData.getBuyerPublicKey())
|
||||
.bind("name", buyNameTransactionData.getName()).bind("amount", buyNameTransactionData.getAmount())
|
||||
.bind("seller", buyNameTransactionData.getSeller()).bind("name_reference", buyNameTransactionData.getNameReference());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save buy name transaction into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ public class HSQLDBMessageTransactionRepository extends HSQLDBTransactionReposit
|
||||
Long assetId = rs.getLong(7);
|
||||
byte[] data = rs.getBytes(8);
|
||||
|
||||
return new MessageTransactionData(version, senderPublicKey, recipient, assetId, amount, fee, data, isText, isEncrypted, timestamp, reference,
|
||||
return new MessageTransactionData(version, senderPublicKey, recipient, assetId, amount, data, isText, isEncrypted, fee, timestamp, reference,
|
||||
signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch message transaction from repository", e);
|
||||
|
@ -20,7 +20,7 @@ public class HSQLDBMultiPaymentTransactionRepository extends HSQLDBTransactionRe
|
||||
|
||||
TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException {
|
||||
try {
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT sender MultiPaymentTransactions WHERE signature = ?", signature);
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT sender from MultiPaymentTransactions WHERE signature = ?", signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
|
@ -25,6 +25,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
private HSQLDBUpdateNameTransactionRepository updateNameTransactionRepository;
|
||||
private HSQLDBSellNameTransactionRepository sellNameTransactionRepository;
|
||||
private HSQLDBCancelSellNameTransactionRepository cancelSellNameTransactionRepository;
|
||||
private HSQLDBBuyNameTransactionRepository buyNameTransactionRepository;
|
||||
private HSQLDBCreatePollTransactionRepository createPollTransactionRepository;
|
||||
private HSQLDBVoteOnPollTransactionRepository voteOnPollTransactionRepository;
|
||||
private HSQLDBIssueAssetTransactionRepository issueAssetTransactionRepository;
|
||||
@ -42,6 +43,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.updateNameTransactionRepository = new HSQLDBUpdateNameTransactionRepository(repository);
|
||||
this.sellNameTransactionRepository = new HSQLDBSellNameTransactionRepository(repository);
|
||||
this.cancelSellNameTransactionRepository = new HSQLDBCancelSellNameTransactionRepository(repository);
|
||||
this.buyNameTransactionRepository = new HSQLDBBuyNameTransactionRepository(repository);
|
||||
this.createPollTransactionRepository = new HSQLDBCreatePollTransactionRepository(repository);
|
||||
this.voteOnPollTransactionRepository = new HSQLDBVoteOnPollTransactionRepository(repository);
|
||||
this.issueAssetTransactionRepository = new HSQLDBIssueAssetTransactionRepository(repository);
|
||||
@ -112,6 +114,9 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
case CANCEL_SELL_NAME:
|
||||
return this.cancelSellNameTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case BUY_NAME:
|
||||
return this.buyNameTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case CREATE_POLL:
|
||||
return this.createPollTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
@ -256,6 +261,10 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.cancelSellNameTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case BUY_NAME:
|
||||
this.buyNameTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case CREATE_POLL:
|
||||
this.createPollTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
@ -61,9 +61,9 @@ public class SerializationTests extends Common {
|
||||
|
||||
TransactionData parsedTransactionData = TransactionTransformer.fromBytes(bytes);
|
||||
|
||||
assertTrue(Arrays.equals(transactionData.getSignature(), parsedTransactionData.getSignature()));
|
||||
assertTrue("Transaction signature mismatch", Arrays.equals(transactionData.getSignature(), parsedTransactionData.getSignature()));
|
||||
|
||||
assertEquals(TransactionTransformer.getDataLength(transactionData), bytes.length);
|
||||
assertEquals("Data length mismatch", TransactionTransformer.getDataLength(transactionData), bytes.length);
|
||||
}
|
||||
|
||||
private void testSpecificBlockTransactions(int height, TransactionType type) throws DataException, TransformationException {
|
||||
@ -84,13 +84,11 @@ public class SerializationTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testPaymentSerialization() throws TransformationException, DataException {
|
||||
// Blocks 390 & 754 have only payment transactions
|
||||
testSpecificBlockTransactions(754, TransactionType.PAYMENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterNameSerialization() throws TransformationException, DataException {
|
||||
// Block 120 has only name registration transactions
|
||||
testSpecificBlockTransactions(120, TransactionType.REGISTER_NAME);
|
||||
}
|
||||
|
||||
@ -109,12 +107,46 @@ public class SerializationTests extends Common {
|
||||
testSpecificBlockTransactions(741, TransactionType.CANCEL_SELL_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuyNameSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(973, TransactionType.BUY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePollSerialization() throws TransformationException, DataException {
|
||||
// Block 10537 has only create poll transactions
|
||||
testSpecificBlockTransactions(10537, TransactionType.CREATE_POLL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteOnPollSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(10540, TransactionType.CREATE_POLL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssueAssetSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(33661, TransactionType.ISSUE_ASSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransferAssetSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(39039, TransactionType.TRANSFER_ASSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAssetOrderSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(35611, TransactionType.CREATE_ASSET_ORDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelAssetOrderSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(36176, TransactionType.CANCEL_ASSET_ORDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPaymentSerialization() throws TransformationException, DataException {
|
||||
testSpecificBlockTransactions(34500, TransactionType.MULTIPAYMENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageSerialization() throws TransformationException, DataException {
|
||||
// Message transactions went live block 99000
|
||||
|
@ -2,6 +2,7 @@ package test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -16,8 +17,10 @@ import data.account.AccountBalanceData;
|
||||
import data.account.AccountData;
|
||||
import data.block.BlockData;
|
||||
import data.naming.NameData;
|
||||
import data.transaction.BuyNameTransactionData;
|
||||
import data.transaction.CancelSellNameTransactionData;
|
||||
import data.transaction.CreatePollTransactionData;
|
||||
import data.transaction.MessageTransactionData;
|
||||
import data.transaction.PaymentTransactionData;
|
||||
import data.transaction.RegisterNameTransactionData;
|
||||
import data.transaction.SellNameTransactionData;
|
||||
@ -32,8 +35,10 @@ import qora.account.PublicKeyAccount;
|
||||
import qora.assets.Asset;
|
||||
import qora.block.Block;
|
||||
import qora.block.BlockChain;
|
||||
import qora.transaction.BuyNameTransaction;
|
||||
import qora.transaction.CancelSellNameTransaction;
|
||||
import qora.transaction.CreatePollTransaction;
|
||||
import qora.transaction.MessageTransaction;
|
||||
import qora.transaction.PaymentTransaction;
|
||||
import qora.transaction.RegisterNameTransaction;
|
||||
import qora.transaction.SellNameTransaction;
|
||||
@ -116,6 +121,19 @@ public class TransactionTests {
|
||||
RepositoryManager.closeRepositoryFactory();
|
||||
}
|
||||
|
||||
private Transaction createPayment(PrivateKeyAccount sender, String recipient) throws DataException {
|
||||
// Make a new payment transaction
|
||||
BigDecimal amount = BigDecimal.valueOf(1_000L);
|
||||
BigDecimal fee = BigDecimal.ONE;
|
||||
long timestamp = parentBlockData.getTimestamp() + 1_000;
|
||||
PaymentTransactionData paymentTransactionData = new PaymentTransactionData(sender.getPublicKey(), recipient, amount, fee, timestamp, reference);
|
||||
|
||||
Transaction paymentTransaction = new PaymentTransaction(repository, paymentTransactionData);
|
||||
paymentTransaction.calcSignature(sender);
|
||||
|
||||
return paymentTransaction;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPaymentTransaction() throws DataException {
|
||||
createTestAccounts(null);
|
||||
@ -360,6 +378,70 @@ public class TransactionTests {
|
||||
parentBlockData = block.getBlockData();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuyNameTransaction() throws DataException {
|
||||
// Register and sell name using another test
|
||||
testSellNameTransaction();
|
||||
|
||||
String name = "test name";
|
||||
NameData originalNameData = this.repository.getNameRepository().fromName(name);
|
||||
String seller = originalNameData.getOwner();
|
||||
|
||||
// Buyer
|
||||
PrivateKeyAccount buyer = new PrivateKeyAccount(repository, recipientSeed);
|
||||
byte[] nameReference = reference;
|
||||
|
||||
// Send buyer some funds so they have a reference
|
||||
Transaction somePaymentTransaction = createPayment(sender, buyer.getAddress());
|
||||
byte[] buyersReference = somePaymentTransaction.getTransactionData().getSignature();
|
||||
|
||||
// Forge new block with transaction
|
||||
Block block = new Block(repository, parentBlockData, generator, null, null);
|
||||
block.addTransaction(somePaymentTransaction.getTransactionData());
|
||||
block.sign();
|
||||
|
||||
block.process();
|
||||
repository.saveChanges();
|
||||
parentBlockData = block.getBlockData();
|
||||
|
||||
BigDecimal fee = BigDecimal.ONE;
|
||||
long timestamp = parentBlockData.getTimestamp() + 1_000;
|
||||
BuyNameTransactionData buyNameTransactionData = new BuyNameTransactionData(buyer.getPublicKey(), name, originalNameData.getSalePrice(), seller,
|
||||
nameReference, fee, timestamp, buyersReference);
|
||||
|
||||
Transaction buyNameTransaction = new BuyNameTransaction(repository, buyNameTransactionData);
|
||||
buyNameTransaction.calcSignature(buyer);
|
||||
assertTrue(buyNameTransaction.isSignatureValid());
|
||||
assertEquals(ValidationResult.OK, buyNameTransaction.isValid());
|
||||
|
||||
// Forge new block with transaction
|
||||
block = new Block(repository, parentBlockData, generator, null, null);
|
||||
block.addTransaction(buyNameTransactionData);
|
||||
block.sign();
|
||||
|
||||
assertTrue("Block signatures invalid", block.isSignatureValid());
|
||||
assertEquals("Block is invalid", Block.ValidationResult.OK, block.isValid());
|
||||
|
||||
block.process();
|
||||
repository.saveChanges();
|
||||
|
||||
// Check name was updated
|
||||
NameData actualNameData = this.repository.getNameRepository().fromName(name);
|
||||
assertFalse(actualNameData.getIsForSale());
|
||||
assertEquals(originalNameData.getSalePrice(), actualNameData.getSalePrice());
|
||||
assertEquals(buyer.getAddress(), actualNameData.getOwner());
|
||||
|
||||
// Now orphan block
|
||||
block.orphan();
|
||||
repository.saveChanges();
|
||||
|
||||
// Check name has been reverted correctly
|
||||
actualNameData = this.repository.getNameRepository().fromName(name);
|
||||
assertTrue(actualNameData.getIsForSale());
|
||||
assertEquals(originalNameData.getSalePrice(), actualNameData.getSalePrice());
|
||||
assertEquals(originalNameData.getOwner(), actualNameData.getOwner());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePollTransaction() throws DataException {
|
||||
// This test requires GenesisBlock's timestamp is set to something after BlockChain.VOTING_RELEASE_TIMESTAMP
|
||||
@ -491,4 +573,78 @@ public class TransactionTests {
|
||||
assertTrue("Wrong voter public key", Arrays.equals(sender.getPublicKey(), votes.get(0).getVoterPublicKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssueAssetTransaction() throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransferAssetTransaction() throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAssetOrderTransaction() throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelAssetOrderTransaction() throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPaymentTransaction() throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageTransaction() throws DataException, UnsupportedEncodingException {
|
||||
createTestAccounts(null);
|
||||
|
||||
// Make a new message transaction
|
||||
Account recipient = new PublicKeyAccount(repository, recipientSeed);
|
||||
BigDecimal amount = BigDecimal.valueOf(1_000L);
|
||||
BigDecimal fee = BigDecimal.ONE;
|
||||
long timestamp = parentBlockData.getTimestamp() + 1_000;
|
||||
int version = Transaction.getVersionByTimestamp(timestamp);
|
||||
byte[] data = "test".getBytes("UTF-8");
|
||||
boolean isText = true;
|
||||
boolean isEncrypted = false;
|
||||
|
||||
MessageTransactionData messageTransactionData = new MessageTransactionData(version, sender.getPublicKey(), recipient.getAddress(), Asset.QORA, amount,
|
||||
data, isText, isEncrypted, fee, timestamp, reference);
|
||||
|
||||
Transaction messageTransaction = new MessageTransaction(repository, messageTransactionData);
|
||||
messageTransaction.calcSignature(sender);
|
||||
assertTrue(messageTransaction.isSignatureValid());
|
||||
assertEquals(ValidationResult.OK, messageTransaction.isValid());
|
||||
|
||||
// Forge new block with message transaction
|
||||
Block block = new Block(repository, parentBlockData, generator, null, null);
|
||||
block.addTransaction(messageTransactionData);
|
||||
block.sign();
|
||||
|
||||
assertTrue("Block signatures invalid", block.isSignatureValid());
|
||||
assertEquals("Block is invalid", Block.ValidationResult.OK, block.isValid());
|
||||
|
||||
block.process();
|
||||
repository.saveChanges();
|
||||
|
||||
// Check sender's balance
|
||||
BigDecimal expectedBalance = senderBalance.subtract(amount).subtract(fee);
|
||||
BigDecimal actualBalance = accountRepository.getBalance(sender.getAddress(), Asset.QORA).getBalance();
|
||||
assertTrue("Sender's new balance incorrect", expectedBalance.compareTo(actualBalance) == 0);
|
||||
|
||||
// Fee should be in generator's balance
|
||||
expectedBalance = generatorBalance.add(fee);
|
||||
actualBalance = accountRepository.getBalance(generator.getAddress(), Asset.QORA).getBalance();
|
||||
assertTrue("Generator's new balance incorrect", expectedBalance.compareTo(actualBalance) == 0);
|
||||
|
||||
// Amount should be in recipient's balance
|
||||
expectedBalance = amount;
|
||||
actualBalance = accountRepository.getBalance(recipient.getAddress(), Asset.QORA).getBalance();
|
||||
assertTrue("Recipient's new balance incorrect", expectedBalance.compareTo(actualBalance) == 0);
|
||||
}
|
||||
|
||||
}
|
@ -11,7 +11,6 @@ import com.google.common.primitives.Longs;
|
||||
|
||||
import data.PaymentData;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class PaymentTransformer extends Transformer {
|
||||
@ -27,7 +26,7 @@ public class PaymentTransformer extends Transformer {
|
||||
if (byteBuffer.remaining() < TOTAL_LENGTH)
|
||||
throw new TransformationException("Byte data too short for payment information");
|
||||
|
||||
String recipient = Serialization.deserializeRecipient(byteBuffer);
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
long assetId = byteBuffer.getLong();
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
@ -42,7 +41,7 @@ public class PaymentTransformer extends Transformer {
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Base58.decode(paymentData.getRecipient()));
|
||||
Serialization.serializeAddress(bytes, paymentData.getRecipient());
|
||||
bytes.write(Longs.toByteArray(paymentData.getAssetId()));
|
||||
Serialization.serializeBigDecimal(bytes, paymentData.getAmount());
|
||||
|
||||
|
118
src/transform/transaction/BuyNameTransactionTransformer.java
Normal file
118
src/transform/transaction/BuyNameTransactionTransformer.java
Normal file
@ -0,0 +1,118 @@
|
||||
package transform.transaction;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.google.common.base.Utf8;
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
import data.transaction.BuyNameTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.naming.Name;
|
||||
import transform.TransformationException;
|
||||
import utils.Serialization;
|
||||
|
||||
public class BuyNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
// Property lengths
|
||||
private static final int BUYER_LENGTH = PUBLIC_KEY_LENGTH;
|
||||
private static final int NAME_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int AMOUNT_LENGTH = BIG_DECIMAL_LENGTH;
|
||||
private static final int SELLER_LENGTH = ADDRESS_LENGTH;
|
||||
|
||||
private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + BUYER_LENGTH + NAME_SIZE_LENGTH + AMOUNT_LENGTH + SELLER_LENGTH;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
if (byteBuffer.remaining() < TYPELESS_DATALESS_LENGTH)
|
||||
throw new TransformationException("Byte data too short for BuyNameTransaction");
|
||||
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] buyerPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String name = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE);
|
||||
|
||||
// Still need to make sure there are enough bytes left for remaining fields
|
||||
if (byteBuffer.remaining() < AMOUNT_LENGTH + SELLER_LENGTH + FEE_LENGTH + SIGNATURE_LENGTH)
|
||||
throw new TransformationException("Byte data too short for BuyNameTransaction");
|
||||
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
String seller = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||
byteBuffer.get(signature);
|
||||
|
||||
return new BuyNameTransactionData(buyerPublicKey, name, amount, seller, fee, timestamp, reference, signature);
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) transactionData;
|
||||
|
||||
int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(buyNameTransactionData.getName());
|
||||
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
try {
|
||||
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) transactionData;
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Ints.toByteArray(buyNameTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(buyNameTransactionData.getTimestamp()));
|
||||
bytes.write(buyNameTransactionData.getReference());
|
||||
|
||||
bytes.write(buyNameTransactionData.getBuyerPublicKey());
|
||||
Serialization.serializeSizedString(bytes, buyNameTransactionData.getName());
|
||||
Serialization.serializeBigDecimal(bytes, buyNameTransactionData.getAmount());
|
||||
Serialization.serializeAddress(bytes, buyNameTransactionData.getSeller());
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, buyNameTransactionData.getFee());
|
||||
|
||||
if (buyNameTransactionData.getSignature() != null)
|
||||
bytes.write(buyNameTransactionData.getSignature());
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException | ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JSONObject toJSON(TransactionData transactionData) throws TransformationException {
|
||||
JSONObject json = TransactionTransformer.getBaseJSON(transactionData);
|
||||
|
||||
try {
|
||||
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) transactionData;
|
||||
|
||||
byte[] buyerPublicKey = buyNameTransactionData.getBuyerPublicKey();
|
||||
|
||||
json.put("buyer", PublicKeyAccount.getAddress(buyerPublicKey));
|
||||
json.put("buyerPublicKey", HashCode.fromBytes(buyerPublicKey).toString());
|
||||
|
||||
json.put("name", buyNameTransactionData.getName());
|
||||
json.put("amount", buyNameTransactionData.getAmount().toPlainString());
|
||||
|
||||
json.put("seller", buyNameTransactionData.getSeller());
|
||||
} catch (ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -21,7 +21,7 @@ import utils.Serialization;
|
||||
public class CancelOrderTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
// Property lengths
|
||||
private static final int CREATOR_LENGTH = LONG_LENGTH;
|
||||
private static final int CREATOR_LENGTH = PUBLIC_KEY_LENGTH;
|
||||
private static final int ORDER_ID_LENGTH = SIGNATURE_LENGTH;
|
||||
|
||||
private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + CREATOR_LENGTH + ORDER_ID_LENGTH;
|
||||
|
@ -20,10 +20,11 @@ import utils.Serialization;
|
||||
public class CreateOrderTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
// Property lengths
|
||||
private static final int CREATOR_LENGTH = PUBLIC_KEY_LENGTH;
|
||||
private static final int ASSET_ID_LENGTH = LONG_LENGTH;
|
||||
private static final int AMOUNT_LENGTH = 12; // Not standard BIG_DECIMAL_LENGTH
|
||||
|
||||
private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + (ASSET_ID_LENGTH + AMOUNT_LENGTH) * 2;
|
||||
private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + CREATOR_LENGTH + (ASSET_ID_LENGTH + AMOUNT_LENGTH) * 2;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
if (byteBuffer.remaining() < TYPELESS_LENGTH)
|
||||
|
@ -21,7 +21,6 @@ import data.voting.PollOptionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.voting.Poll;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
@ -47,7 +46,7 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
byte[] creatorPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String owner = Serialization.deserializeRecipient(byteBuffer);
|
||||
String owner = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String pollName = Serialization.deserializeSizedString(byteBuffer, Poll.MAX_NAME_SIZE);
|
||||
String description = Serialization.deserializeSizedString(byteBuffer, Poll.MAX_DESCRIPTION_SIZE);
|
||||
@ -103,7 +102,7 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(createPollTransactionData.getReference());
|
||||
|
||||
bytes.write(createPollTransactionData.getCreatorPublicKey());
|
||||
bytes.write(Base58.decode(createPollTransactionData.getOwner()));
|
||||
Serialization.serializeAddress(bytes, createPollTransactionData.getOwner());
|
||||
Serialization.serializeSizedString(bytes, createPollTransactionData.getPollName());
|
||||
Serialization.serializeSizedString(bytes, createPollTransactionData.getDescription());
|
||||
|
||||
|
@ -13,7 +13,6 @@ import com.google.common.primitives.Longs;
|
||||
import data.transaction.TransactionData;
|
||||
import data.transaction.GenesisTransactionData;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
@ -30,7 +29,7 @@ public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
throw new TransformationException("Byte data too short for GenesisTransaction");
|
||||
|
||||
long timestamp = byteBuffer.getLong();
|
||||
String recipient = Serialization.deserializeRecipient(byteBuffer);
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
return new GenesisTransactionData(recipient, amount, timestamp);
|
||||
@ -49,7 +48,7 @@ public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(Ints.toByteArray(genesisTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(genesisTransactionData.getTimestamp()));
|
||||
|
||||
bytes.write(Base58.decode(genesisTransactionData.getRecipient()));
|
||||
Serialization.serializeAddress(bytes, genesisTransactionData.getRecipient());
|
||||
Serialization.serializeBigDecimal(bytes, genesisTransactionData.getAmount());
|
||||
|
||||
return bytes.toByteArray();
|
||||
|
@ -17,7 +17,6 @@ import qora.account.PublicKeyAccount;
|
||||
import qora.transaction.IssueAssetTransaction;
|
||||
import data.transaction.IssueAssetTransactionData;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
@ -43,7 +42,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] issuerPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
String owner = Serialization.deserializeRecipient(byteBuffer);
|
||||
String owner = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String assetName = Serialization.deserializeSizedString(byteBuffer, IssueAssetTransaction.MAX_NAME_SIZE);
|
||||
String description = Serialization.deserializeSizedString(byteBuffer, IssueAssetTransaction.MAX_DESCRIPTION_SIZE);
|
||||
@ -81,7 +80,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(issueAssetTransactionData.getReference());
|
||||
|
||||
bytes.write(issueAssetTransactionData.getIssuerPublicKey());
|
||||
bytes.write(Base58.decode(issueAssetTransactionData.getOwner()));
|
||||
Serialization.serializeAddress(bytes, issueAssetTransactionData.getOwner());
|
||||
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getAssetName());
|
||||
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getDescription());
|
||||
bytes.write(Longs.toByteArray(issueAssetTransactionData.getQuantity()));
|
||||
|
@ -18,7 +18,6 @@ import qora.assets.Asset;
|
||||
import qora.transaction.MessageTransaction;
|
||||
import data.transaction.MessageTransactionData;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
@ -54,7 +53,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] senderPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
String recipient = Serialization.deserializeRecipient(byteBuffer);
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
long assetId;
|
||||
if (version == 1)
|
||||
@ -84,7 +83,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||
byteBuffer.get(signature);
|
||||
|
||||
return new MessageTransactionData(version, senderPublicKey, recipient, assetId, amount, fee, data, isText, isEncrypted, timestamp, reference,
|
||||
return new MessageTransactionData(version, senderPublicKey, recipient, assetId, amount, data, isText, isEncrypted, fee, timestamp, reference,
|
||||
signature);
|
||||
}
|
||||
|
||||
@ -108,7 +107,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(messageTransactionData.getReference());
|
||||
|
||||
bytes.write(messageTransactionData.getSenderPublicKey());
|
||||
bytes.write(Base58.decode(messageTransactionData.getRecipient()));
|
||||
Serialization.serializeAddress(bytes, messageTransactionData.getRecipient());
|
||||
|
||||
if (messageTransactionData.getVersion() != 1)
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getAssetId()));
|
||||
|
@ -32,7 +32,7 @@ public class MultiPaymentTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
if (byteBuffer.remaining() < TYPELESS_LENGTH)
|
||||
throw new TransformationException("Byte data too short for PaymentTransaction");
|
||||
throw new TransformationException("Byte data too short for MultiPaymentTransaction");
|
||||
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
@ -45,7 +45,7 @@ public class MultiPaymentTransactionTransformer extends TransactionTransformer {
|
||||
// Check remaining buffer size
|
||||
int minRemaining = paymentsCount * PaymentTransformer.getDataLength() + FEE_LENGTH + SIGNATURE_LENGTH;
|
||||
if (byteBuffer.remaining() < minRemaining)
|
||||
throw new TransformationException("Byte data too short for PaymentTransaction");
|
||||
throw new TransformationException("Byte data too short for MultiPaymentTransaction");
|
||||
|
||||
List<PaymentData> payments = new ArrayList<PaymentData>();
|
||||
for (int i = 0; i < paymentsCount; ++i)
|
||||
@ -81,7 +81,7 @@ public class MultiPaymentTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(Ints.toByteArray(payments.size()));
|
||||
|
||||
for (PaymentData paymentData : payments)
|
||||
PaymentTransformer.toBytes(paymentData);
|
||||
bytes.write(PaymentTransformer.toBytes(paymentData));
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, multiPaymentTransactionData.getFee());
|
||||
|
||||
|
@ -15,7 +15,6 @@ import data.transaction.TransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import data.transaction.PaymentTransactionData;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class PaymentTransactionTransformer extends TransactionTransformer {
|
||||
@ -37,7 +36,7 @@ public class PaymentTransactionTransformer extends TransactionTransformer {
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] senderPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
String recipient = Serialization.deserializeRecipient(byteBuffer);
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
@ -63,7 +62,7 @@ public class PaymentTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(paymentTransactionData.getReference());
|
||||
|
||||
bytes.write(paymentTransactionData.getSenderPublicKey());
|
||||
bytes.write(Base58.decode(paymentTransactionData.getRecipient()));
|
||||
Serialization.serializeAddress(bytes, paymentTransactionData.getRecipient());
|
||||
Serialization.serializeBigDecimal(bytes, paymentTransactionData.getAmount());
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, paymentTransactionData.getFee());
|
||||
|
@ -17,7 +17,6 @@ import data.transaction.TransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.naming.Name;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
@ -41,7 +40,7 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
byte[] registrantPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String owner = Serialization.deserializeRecipient(byteBuffer);
|
||||
String owner = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String name = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE);
|
||||
String data = Serialization.deserializeSizedString(byteBuffer, Name.MAX_DATA_SIZE);
|
||||
@ -78,7 +77,7 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(registerNameTransactionData.getReference());
|
||||
|
||||
bytes.write(registerNameTransactionData.getRegistrantPublicKey());
|
||||
bytes.write(Base58.decode(registerNameTransactionData.getOwner()));
|
||||
Serialization.serializeAddress(bytes, registerNameTransactionData.getOwner());
|
||||
Serialization.serializeSizedString(bytes, registerNameTransactionData.getName());
|
||||
Serialization.serializeSizedString(bytes, registerNameTransactionData.getData());
|
||||
|
||||
|
@ -49,6 +49,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case CANCEL_SELL_NAME:
|
||||
return CancelSellNameTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case BUY_NAME:
|
||||
return BuyNameTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
@ -98,6 +101,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case CANCEL_SELL_NAME:
|
||||
return CancelSellNameTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case BUY_NAME:
|
||||
return BuyNameTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
@ -147,6 +153,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case CANCEL_SELL_NAME:
|
||||
return CancelSellNameTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case BUY_NAME:
|
||||
return BuyNameTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
@ -196,6 +205,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case CANCEL_SELL_NAME:
|
||||
return CancelSellNameTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case BUY_NAME:
|
||||
return BuyNameTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
|
@ -15,7 +15,6 @@ import data.transaction.TransactionData;
|
||||
import data.transaction.TransferAssetTransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class TransferAssetTransactionTransformer extends TransactionTransformer {
|
||||
@ -38,7 +37,7 @@ public class TransferAssetTransactionTransformer extends TransactionTransformer
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] senderPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
String recipient = Serialization.deserializeRecipient(byteBuffer);
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
long assetId = byteBuffer.getLong();
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer, AMOUNT_LENGTH);
|
||||
|
||||
@ -65,7 +64,7 @@ public class TransferAssetTransactionTransformer extends TransactionTransformer
|
||||
bytes.write(transferAssetTransactionData.getReference());
|
||||
|
||||
bytes.write(transferAssetTransactionData.getSenderPublicKey());
|
||||
bytes.write(Base58.decode(transferAssetTransactionData.getRecipient()));
|
||||
Serialization.serializeAddress(bytes, transferAssetTransactionData.getRecipient());
|
||||
bytes.write(Longs.toByteArray(transferAssetTransactionData.getAssetId()));
|
||||
Serialization.serializeBigDecimal(bytes, transferAssetTransactionData.getAmount(), AMOUNT_LENGTH);
|
||||
|
||||
|
@ -17,7 +17,6 @@ import data.transaction.TransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.naming.Name;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
@ -41,7 +40,7 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
byte[] ownerPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String newOwner = Serialization.deserializeRecipient(byteBuffer);
|
||||
String newOwner = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String name = Serialization.deserializeSizedString(byteBuffer, Name.MAX_NAME_SIZE);
|
||||
String newData = Serialization.deserializeSizedString(byteBuffer, Name.MAX_DATA_SIZE);
|
||||
@ -55,7 +54,7 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||
byteBuffer.get(signature);
|
||||
|
||||
return new UpdateNameTransactionData(ownerPublicKey, newOwner, name, newData, null, fee, timestamp, reference, signature);
|
||||
return new UpdateNameTransactionData(ownerPublicKey, newOwner, name, newData, fee, timestamp, reference, signature);
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
@ -78,7 +77,7 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(updateNameTransactionData.getReference());
|
||||
|
||||
bytes.write(updateNameTransactionData.getOwnerPublicKey());
|
||||
bytes.write(Base58.decode(updateNameTransactionData.getNewOwner()));
|
||||
Serialization.serializeAddress(bytes, updateNameTransactionData.getNewOwner());
|
||||
Serialization.serializeSizedString(bytes, updateNameTransactionData.getName());
|
||||
Serialization.serializeSizedString(bytes, updateNameTransactionData.getNewData());
|
||||
|
||||
|
@ -50,7 +50,11 @@ public class Serialization {
|
||||
return Serialization.deserializeBigDecimal(byteBuffer, 8);
|
||||
}
|
||||
|
||||
public static String deserializeRecipient(ByteBuffer byteBuffer) {
|
||||
public static void serializeAddress(ByteArrayOutputStream bytes, String address) throws IOException {
|
||||
bytes.write(Base58.decode(address));
|
||||
}
|
||||
|
||||
public static String deserializeAddress(ByteBuffer byteBuffer) {
|
||||
byte[] bytes = new byte[Transformer.ADDRESS_LENGTH];
|
||||
byteBuffer.get(bytes);
|
||||
return Base58.encode(bytes);
|
||||
|
Loading…
Reference in New Issue
Block a user