forked from Qortal/qortal
Interim commit of *Transaction refactoring
Transaction subclass isValid methods have last reference checks removed. (Now handled by Transaction.hasValidReference) Some checks in subclass' isValid moved to isProcessable, typically for transaction types that require group-approval. Removed fee extraction and last-reference update code from subclass' process() method to Transaction.processReferencesAndFees. Other changes to transaction/block processing.
This commit is contained in:
parent
c9968b3dd2
commit
9bb673ba82
@ -32,7 +32,6 @@ import org.qora.repository.BlockRepository;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
import org.qora.transaction.AtTransaction;
|
||||
import org.qora.transaction.GenesisTransaction;
|
||||
import org.qora.transaction.Transaction;
|
||||
import org.qora.transaction.Transaction.ApprovalStatus;
|
||||
import org.qora.transaction.Transaction.TransactionType;
|
||||
@ -896,33 +895,55 @@ public class Block {
|
||||
repository.setSavepoint();
|
||||
|
||||
for (Transaction transaction : this.getTransactions()) {
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
|
||||
// GenesisTransactions are not allowed (GenesisBlock overrides isValid() to allow them)
|
||||
if (transaction instanceof GenesisTransaction)
|
||||
if (transactionData.getType() == TransactionType.GENESIS || transactionData.getType() == TransactionType.ACCOUNT_FLAGS)
|
||||
return ValidationResult.GENESIS_TRANSACTIONS_INVALID;
|
||||
|
||||
// Check timestamp and deadline
|
||||
if (transaction.getTransactionData().getTimestamp() > this.blockData.getTimestamp()
|
||||
if (transactionData.getTimestamp() > this.blockData.getTimestamp()
|
||||
|| transaction.getDeadline() <= this.blockData.getTimestamp())
|
||||
return ValidationResult.TRANSACTION_TIMESTAMP_INVALID;
|
||||
|
||||
// Check transaction isn't already included in a block
|
||||
if (this.repository.getTransactionRepository().isConfirmed(transaction.getTransactionData().getSignature()))
|
||||
if (this.repository.getTransactionRepository().isConfirmed(transactionData.getSignature()))
|
||||
return ValidationResult.TRANSACTION_ALREADY_PROCESSED;
|
||||
|
||||
// Check transaction has correct reference, etc.
|
||||
if (!transaction.hasValidReference()) {
|
||||
LOGGER.debug("Error during transaction validation, tx " + Base58.encode(transactionData.getSignature()) + ": INVALID_REFERENCE");
|
||||
return ValidationResult.TRANSACTION_INVALID;
|
||||
}
|
||||
|
||||
// Check transaction is even valid
|
||||
// NOTE: in Gen1 there was an extra block height passed to DeployATTransaction.isValid
|
||||
Transaction.ValidationResult validationResult = transaction.isValid();
|
||||
if (validationResult != Transaction.ValidationResult.OK) {
|
||||
LOGGER.debug("Error during transaction validation, tx " + Base58.encode(transaction.getTransactionData().getSignature()) + ": "
|
||||
LOGGER.debug("Error during transaction validation, tx " + Base58.encode(transactionData.getSignature()) + ": "
|
||||
+ validationResult.name());
|
||||
return ValidationResult.TRANSACTION_INVALID;
|
||||
}
|
||||
|
||||
// Check transaction can even be processed
|
||||
validationResult = transaction.isProcessable();
|
||||
if (validationResult != Transaction.ValidationResult.OK) {
|
||||
LOGGER.debug("Error during transaction validation, tx " + Base58.encode(transactionData.getSignature()) + ": "
|
||||
+ validationResult.name());
|
||||
return ValidationResult.TRANSACTION_INVALID;
|
||||
}
|
||||
|
||||
// Process transaction to make sure other transactions validate properly
|
||||
try {
|
||||
transaction.process();
|
||||
// Only process transactions that don't require group-approval.
|
||||
// Group-approval transactions are dealt with later.
|
||||
if (transactionData.getApprovalStatus() == ApprovalStatus.NOT_REQUIRED)
|
||||
transaction.process();
|
||||
|
||||
// Regardless of group-approval, update relevant info for creator (e.g. lastReference)
|
||||
transaction.processReferencesAndFees();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Exception during transaction validation, tx " + Base58.encode(transaction.getTransactionData().getSignature()), e);
|
||||
LOGGER.error("Exception during transaction validation, tx " + Base58.encode(transactionData.getSignature()), e);
|
||||
e.printStackTrace();
|
||||
return ValidationResult.TRANSACTION_PROCESSING_FAILED;
|
||||
}
|
||||
@ -1056,7 +1077,7 @@ public class Block {
|
||||
transaction.process();
|
||||
|
||||
// Regardless of group-approval, update relevant info for creator (e.g. lastReference)
|
||||
transaction.processCreatorUpdates();
|
||||
transaction.processReferencesAndFees();
|
||||
}
|
||||
|
||||
// Group-approval transactions
|
||||
@ -1133,15 +1154,15 @@ public class Block {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Approved, but check transaction is still valid
|
||||
if (transaction.isValid() != Transaction.ValidationResult.OK) {
|
||||
// Approved, but check transaction can still be processed
|
||||
if (transaction.isProcessable() != Transaction.ValidationResult.OK) {
|
||||
transactionData.setApprovalStatus(ApprovalStatus.INVALID);
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
continue;
|
||||
}
|
||||
|
||||
// APPROVED, in which case do transaction.process();
|
||||
transactionData.setApprovalStatus(ApprovalStatus.INVALID);
|
||||
transactionData.setApprovalStatus(ApprovalStatus.APPROVED);
|
||||
this.repository.getTransactionRepository().save(transactionData);
|
||||
|
||||
transaction.process();
|
||||
|
@ -242,15 +242,15 @@ public class BlockGenerator extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
// Sign to create block's signature, needed by Block.isValid()
|
||||
newBlock.sign();
|
||||
|
||||
// Attempt to add transactions until block is full, or we run out
|
||||
// If a transaction makes the block invalid then skip it and it'll either expire or be in next block.
|
||||
for (TransactionData transactionData : unconfirmedTransactions) {
|
||||
if (!newBlock.addTransaction(transactionData))
|
||||
break;
|
||||
|
||||
// Sign to create block's signature
|
||||
newBlock.sign();
|
||||
|
||||
// If newBlock is no longer valid then we can't use transaction
|
||||
ValidationResult validationResult = newBlock.isValid();
|
||||
if (validationResult != ValidationResult.OK) {
|
||||
|
@ -26,6 +26,7 @@ import org.qora.group.Group;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
import org.qora.transaction.Transaction;
|
||||
import org.qora.transaction.Transaction.ApprovalStatus;
|
||||
import org.qora.transaction.Transaction.TransactionType;
|
||||
import org.qora.transform.TransformationException;
|
||||
import org.qora.transform.transaction.TransactionTransformer;
|
||||
@ -300,8 +301,11 @@ public class GenesisBlock extends Block {
|
||||
TransactionData transactionData = transaction.getTransactionData();
|
||||
Account creator = new PublicKeyAccount(this.repository, transactionData.getCreatorPublicKey());
|
||||
|
||||
// Missing reference?
|
||||
if (transactionData.getReference() == null)
|
||||
transactionData.setReference(creator.getLastReference());
|
||||
|
||||
// Missing signature?
|
||||
if (transactionData.getSignature() == null) {
|
||||
byte[] digest = Crypto.digest(TransactionTransformer.toBytesForSigning(transactionData));
|
||||
byte[] signature = Bytes.concat(digest, digest);
|
||||
@ -309,7 +313,12 @@ public class GenesisBlock extends Block {
|
||||
transactionData.setSignature(signature);
|
||||
}
|
||||
|
||||
transaction.process();
|
||||
// Missing approval status (not used in V1)
|
||||
transactionData.setApprovalStatus(ApprovalStatus.NOT_REQUIRED);
|
||||
|
||||
// Ask transaction to update references, etc.
|
||||
transaction.processReferencesAndFees();
|
||||
|
||||
creator.setLastReference(transactionData.getSignature());
|
||||
}
|
||||
} catch (TransformationException e) {
|
||||
|
@ -33,7 +33,7 @@ public class Payment {
|
||||
|
||||
// Processing
|
||||
|
||||
// Validate multiple payments
|
||||
/** Are payments valid? */
|
||||
public ValidationResult isValid(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, boolean isZeroAmountValid) throws DataException {
|
||||
AssetRepository assetRepository = this.repository.getAssetRepository();
|
||||
|
||||
@ -100,20 +100,70 @@ public class Payment {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
/** Are payments valid? */
|
||||
public ValidationResult isValid(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee) throws DataException {
|
||||
return isValid(senderPublicKey, payments, fee, false);
|
||||
}
|
||||
|
||||
// Single payment forms
|
||||
/** Is single payment valid? */
|
||||
public ValidationResult isValid(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, boolean isZeroAmountValid) throws DataException {
|
||||
return isValid(senderPublicKey, Collections.singletonList(paymentData), fee, isZeroAmountValid);
|
||||
}
|
||||
|
||||
/** Is single payment valid? */
|
||||
public ValidationResult isValid(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee) throws DataException {
|
||||
return isValid(senderPublicKey, paymentData, fee, false);
|
||||
}
|
||||
|
||||
public void process(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, boolean alwaysInitializeRecipientReference)
|
||||
/** Are multiple payments processable? */
|
||||
public ValidationResult isProcessable(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, boolean isZeroAmountValid) throws DataException {
|
||||
// Essentially the same as isValid...
|
||||
return isValid(senderPublicKey, payments, fee, isZeroAmountValid);
|
||||
}
|
||||
|
||||
/** Are multiple payments processable? */
|
||||
public ValidationResult isProcessable(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee) throws DataException {
|
||||
return isProcessable(senderPublicKey, payments, fee, false);
|
||||
}
|
||||
|
||||
/** Is single payment processable? */
|
||||
public ValidationResult isProcessable(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, boolean isZeroAmountValid) throws DataException {
|
||||
return isProcessable(senderPublicKey, Collections.singletonList(paymentData), fee, isZeroAmountValid);
|
||||
}
|
||||
|
||||
/** Is single payment processable? */
|
||||
public ValidationResult isProcessable(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee) throws DataException {
|
||||
return isProcessable(senderPublicKey, paymentData, fee, false);
|
||||
}
|
||||
|
||||
/** Multiple payment processing */
|
||||
public void process(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature)
|
||||
throws DataException {
|
||||
Account sender = new PublicKeyAccount(this.repository, senderPublicKey);
|
||||
|
||||
// Process all payments
|
||||
for (PaymentData paymentData : payments) {
|
||||
Account recipient = new Account(this.repository, paymentData.getRecipient());
|
||||
|
||||
long assetId = paymentData.getAssetId();
|
||||
BigDecimal amount = paymentData.getAmount();
|
||||
|
||||
// Update sender's balance due to amount
|
||||
sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).subtract(amount));
|
||||
|
||||
// Update recipient's balance
|
||||
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(amount));
|
||||
}
|
||||
}
|
||||
|
||||
/** Single payment processing */
|
||||
public void process(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature)
|
||||
throws DataException {
|
||||
process(senderPublicKey, Collections.singletonList(paymentData), fee, signature);
|
||||
}
|
||||
|
||||
/** Multiple payment reference processing */
|
||||
public void processReferencesAndFees(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, boolean alwaysInitializeRecipientReference)
|
||||
throws DataException {
|
||||
Account sender = new PublicKeyAccount(this.repository, senderPublicKey);
|
||||
|
||||
@ -128,13 +178,6 @@ public class Payment {
|
||||
Account recipient = new Account(this.repository, paymentData.getRecipient());
|
||||
|
||||
long assetId = paymentData.getAssetId();
|
||||
BigDecimal amount = paymentData.getAmount();
|
||||
|
||||
// Update sender's balance due to amount
|
||||
sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).subtract(amount));
|
||||
|
||||
// Update recipient's balance
|
||||
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(amount));
|
||||
|
||||
// For QORA amounts only: if recipient has no reference yet, then this is their starting reference
|
||||
if ((alwaysInitializeRecipientReference || assetId == Asset.QORA) && recipient.getLastReference() == null)
|
||||
@ -142,9 +185,10 @@ public class Payment {
|
||||
}
|
||||
}
|
||||
|
||||
public void process(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature, boolean alwaysInitializeRecipientReference)
|
||||
/** Multiple payment reference processing */
|
||||
public void processReferencesAndFees(byte[] senderPublicKey, PaymentData payment, BigDecimal fee, byte[] signature, boolean alwaysInitializeRecipientReference)
|
||||
throws DataException {
|
||||
process(senderPublicKey, Collections.singletonList(paymentData), fee, signature, alwaysInitializeRecipientReference);
|
||||
processReferencesAndFees(senderPublicKey, Collections.singletonList(payment), fee, signature, alwaysInitializeRecipientReference);
|
||||
}
|
||||
|
||||
public void orphan(byte[] senderPublicKey, List<PaymentData> payments, BigDecimal fee, byte[] signature, byte[] reference,
|
||||
|
@ -12,6 +12,9 @@ public interface ATRepository {
|
||||
/** Returns ATData using AT's address or null if none found */
|
||||
public ATData fromATAddress(String atAddress) throws DataException;
|
||||
|
||||
/** Returns where AT with passed address exists in repository */
|
||||
public boolean exists(String atAddress) throws DataException;
|
||||
|
||||
/** Returns list of executable ATs, empty if none found */
|
||||
public List<ATData> getAllExecutableATs() throws DataException;
|
||||
|
||||
|
@ -45,6 +45,10 @@ public interface GroupRepository {
|
||||
|
||||
public void delete(String groupName) throws DataException;
|
||||
|
||||
// Group Owner
|
||||
|
||||
public String getOwner(int groupId) throws DataException;
|
||||
|
||||
// Group Admins
|
||||
|
||||
public GroupAdminData getAdmin(int groupId, String address) throws DataException;
|
||||
|
@ -57,6 +57,15 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String atAddress) throws DataException {
|
||||
try {
|
||||
return this.repository.exists("ATs", "AT_address = ?", atAddress);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to check for AT in repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ATData> getAllExecutableATs() throws DataException {
|
||||
List<ATData> executableATs = new ArrayList<ATData>();
|
||||
|
@ -289,6 +289,22 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// Group Owner
|
||||
|
||||
@Override
|
||||
public String getOwner(int groupId) throws DataException {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT owner FROM Groups WHERE group_id = ?", groupId)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
String owner = resultSet.getString(1);
|
||||
|
||||
return owner;
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch group owner from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Group Admins
|
||||
|
||||
@Override
|
||||
|
@ -657,7 +657,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
|
||||
List<TransactionData> transactions = new ArrayList<TransactionData>();
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, ApprovalStatus.PENDING, blockHeight)) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, ApprovalStatus.PENDING.value, blockHeight)) {
|
||||
if (resultSet == null)
|
||||
return transactions;
|
||||
|
||||
@ -688,7 +688,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
|
||||
List<TransactionData> transactions = new ArrayList<TransactionData>();
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, ApprovalStatus.PENDING, blockHeight)) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, ApprovalStatus.PENDING.value, blockHeight)) {
|
||||
if (resultSet == null)
|
||||
return transactions;
|
||||
|
||||
@ -861,7 +861,8 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
saver.bind("signature", transactionData.getSignature()).bind("reference", transactionData.getReference())
|
||||
.bind("type", transactionData.getType().value)
|
||||
.bind("creator", transactionData.getCreatorPublicKey()).bind("creation", new Timestamp(transactionData.getTimestamp()))
|
||||
.bind("fee", transactionData.getFee()).bind("milestone_block", null).bind("tx_group_id", transactionData.getTxGroupId());
|
||||
.bind("fee", transactionData.getFee()).bind("milestone_block", null).bind("tx_group_id", transactionData.getTxGroupId())
|
||||
.bind("approval_status", transactionData.getApprovalStatus().value);
|
||||
|
||||
try {
|
||||
saver.execute(this.repository);
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -77,10 +76,6 @@ public class AccountFlagsTransaction extends Transaction {
|
||||
if (accountFlagsTransactionData.getFee().compareTo(BigDecimal.ZERO) < 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(creator.getLastReference(), accountFlagsTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(accountFlagsTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -107,13 +102,6 @@ public class AccountFlagsTransaction extends Transaction {
|
||||
| accountFlagsTransactionData.getOrMask() ^ accountFlagsTransactionData.getXorMask();
|
||||
|
||||
target.setFlags(newFlags);
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(accountFlagsTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(accountFlagsTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -10,7 +9,6 @@ import org.qora.account.PublicKeyAccount;
|
||||
import org.qora.asset.Asset;
|
||||
import org.qora.crypto.Crypto;
|
||||
import org.qora.data.transaction.AddGroupAdminTransactionData;
|
||||
import org.qora.data.group.GroupData;
|
||||
import org.qora.data.transaction.TransactionData;
|
||||
import org.qora.group.Group;
|
||||
import org.qora.repository.DataException;
|
||||
@ -78,16 +76,19 @@ public class AddGroupAdminTransaction extends Transaction {
|
||||
if (!Crypto.isValidAddress(addGroupAdminTransactionData.getMember()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
|
||||
GroupData groupData = this.repository.getGroupRepository().fromGroupId(addGroupAdminTransactionData.getGroupId());
|
||||
|
||||
// Check group exists
|
||||
if (groupData == null)
|
||||
if (!this.repository.getGroupRepository().groupExists(addGroupAdminTransactionData.getGroupId()))
|
||||
return ValidationResult.GROUP_DOES_NOT_EXIST;
|
||||
|
||||
// Check fee is positive
|
||||
if (addGroupAdminTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
Account owner = getOwner();
|
||||
String groupOwner = this.repository.getGroupRepository().getOwner(addGroupAdminTransactionData.getGroupId());
|
||||
|
||||
// Check transaction's public key matches group's current owner
|
||||
if (!owner.getAddress().equals(groupData.getOwner()))
|
||||
if (!owner.getAddress().equals(groupOwner))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
|
||||
Account member = getMember();
|
||||
@ -100,15 +101,7 @@ public class AddGroupAdminTransaction extends Transaction {
|
||||
if (this.repository.getGroupRepository().adminExists(addGroupAdminTransactionData.getGroupId(), member.getAddress()))
|
||||
return ValidationResult.ALREADY_GROUP_ADMIN;
|
||||
|
||||
// Check fee is positive
|
||||
if (addGroupAdminTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(owner.getLastReference(), addGroupAdminTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
// Check group owner has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(addGroupAdminTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
@ -122,13 +115,6 @@ public class AddGroupAdminTransaction extends Transaction {
|
||||
group.promoteToAdmin(addGroupAdminTransactionData);
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(addGroupAdminTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(addGroupAdminTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
@ -103,22 +102,31 @@ public class ArbitraryTransaction extends Transaction {
|
||||
if (arbitraryTransactionData.getData().length < 1 || arbitraryTransactionData.getData().length > MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// Check reference is correct
|
||||
Account sender = getSender();
|
||||
if (!Arrays.equals(sender.getLastReference(), arbitraryTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Wrap and delegate final payment checks to Payment class
|
||||
// Wrap and delegate final payment validity checks to Payment class
|
||||
return new Payment(this.repository).isValid(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Wrap and delegate final payment processable checks to Payment class
|
||||
return new Payment(this.repository).isProcessable(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class. Always update recipients' last references regardless of asset.
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate reference and fee processing to Payment class. Always update recipients' last references regardless of asset.
|
||||
new Payment(this.repository).processReferencesAndFees(arbitraryTransactionData.getSenderPublicKey(), arbitraryTransactionData.getPayments(),
|
||||
arbitraryTransactionData.getFee(), arbitraryTransactionData.getSignature(), true);
|
||||
}
|
||||
|
||||
|
@ -108,12 +108,14 @@ public class AtTransaction extends Transaction {
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
public boolean hasValidReference() throws DataException {
|
||||
// Check reference is correct
|
||||
Account atAccount = getATAccount();
|
||||
if (!Arrays.equals(atAccount.getLastReference(), atTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
return Arrays.equals(atAccount.getLastReference(), atTransactionData.getReference());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
if (this.atTransactionData.getMessage().length > MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
@ -173,6 +175,14 @@ public class AtTransaction extends Transaction {
|
||||
|
||||
// Update recipient's balance
|
||||
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(amount));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
if (this.atTransactionData.getAmount() != null) {
|
||||
Account recipient = getRecipient();
|
||||
long assetId = this.atTransactionData.getAssetId();
|
||||
|
||||
// For QORA amounts only: if recipient has no reference yet, then this is their starting reference
|
||||
if (assetId == Asset.QORA && recipient.getLastReference() == null)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -110,10 +109,6 @@ public class BuyNameTransaction extends Transaction {
|
||||
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()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -129,13 +124,6 @@ public class BuyNameTransaction extends Transaction {
|
||||
|
||||
// Save transaction with updated "name reference" pointing 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
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
@ -90,25 +89,13 @@ public class CancelAssetOrderTransaction extends Transaction {
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(cancelOrderTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(creator.getLastReference(), cancelOrderTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update creator's balance regarding fee
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(cancelOrderTransactionData.getFee()));
|
||||
|
||||
// Update creator's last reference
|
||||
creator.setLastReference(cancelOrderTransactionData.getSignature());
|
||||
|
||||
// Mark Order as completed so no more trades can happen
|
||||
OrderData orderData = this.repository.getAssetRepository().fromOrderId(cancelOrderTransactionData.getOrderId());
|
||||
Order order = new Order(this.repository, orderData);
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -100,10 +99,6 @@ public class CancelGroupBanTransaction extends Transaction {
|
||||
if (groupUnbanTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(admin.getLastReference(), groupUnbanTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupUnbanTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -119,13 +114,6 @@ public class CancelGroupBanTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupUnbanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupUnbanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupUnbanTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -100,10 +99,6 @@ public class CancelGroupInviteTransaction extends Transaction {
|
||||
if (cancelGroupInviteTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(admin.getLastReference(), cancelGroupInviteTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(cancelGroupInviteTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -119,13 +114,6 @@ public class CancelGroupInviteTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(cancelGroupInviteTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(cancelGroupInviteTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(cancelGroupInviteTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
@ -96,10 +95,6 @@ public class CancelSellNameTransaction extends Transaction {
|
||||
if (cancelSellNameTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(owner.getLastReference(), cancelSellNameTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(cancelSellNameTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -116,13 +111,6 @@ public class CancelSellNameTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, with updated "name reference" to previous transaction that updated name
|
||||
this.repository.getTransactionRepository().save(cancelSellNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(cancelSellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(cancelSellNameTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -92,20 +91,12 @@ public class CreateGroupTransaction extends Transaction {
|
||||
if (!createGroupTransactionData.getGroupName().equals(createGroupTransactionData.getGroupName().toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
|
||||
// Check the group name isn't already taken
|
||||
if (this.repository.getGroupRepository().groupExists(createGroupTransactionData.getGroupName()))
|
||||
return ValidationResult.GROUP_ALREADY_EXISTS;
|
||||
|
||||
// Check fee is positive
|
||||
if (createGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
Account creator = getCreator();
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(creator.getLastReference(), createGroupTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(createGroupTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -113,6 +104,15 @@ public class CreateGroupTransaction extends Transaction {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check the group name isn't already taken
|
||||
if (this.repository.getGroupRepository().groupExists(createGroupTransactionData.getGroupName()))
|
||||
return ValidationResult.GROUP_ALREADY_EXISTS;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Create Group
|
||||
@ -124,13 +124,6 @@ public class CreateGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction
|
||||
this.repository.getTransactionRepository().save(createGroupTransactionData);
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createGroupTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(createGroupTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -102,10 +101,6 @@ public class CreatePollTransaction extends Transaction {
|
||||
if (!createPollTransactionData.getPollName().equals(createPollTransactionData.getPollName().toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
|
||||
// Check the poll name isn't already taken
|
||||
if (this.repository.getVotingRepository().pollExists(createPollTransactionData.getPollName()))
|
||||
return ValidationResult.POLL_ALREADY_EXISTS;
|
||||
|
||||
// In gen1 we tested for presence of existing votes but how could there be any if poll doesn't exist?
|
||||
|
||||
// Check number of options
|
||||
@ -137,9 +132,6 @@ public class CreatePollTransaction extends Transaction {
|
||||
// Check reference is correct
|
||||
Account creator = getCreator();
|
||||
|
||||
if (!Arrays.equals(creator.getLastReference(), createPollTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(createPollTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -147,6 +139,15 @@ public class CreatePollTransaction extends Transaction {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check the poll name isn't already taken
|
||||
if (this.repository.getVotingRepository().pollExists(createPollTransactionData.getPollName()))
|
||||
return ValidationResult.POLL_ALREADY_EXISTS;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Publish poll to allow voting
|
||||
@ -154,13 +155,6 @@ public class CreatePollTransaction extends Transaction {
|
||||
poll.publish();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createPollTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(createPollTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,7 +5,6 @@ import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.ciyam.at.MachineState;
|
||||
@ -171,12 +170,8 @@ public class DeployAtTransaction extends Transaction {
|
||||
if (deployATTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
Account creator = getCreator();
|
||||
|
||||
if (!Arrays.equals(creator.getLastReference(), deployATTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (assetId == Asset.QORA) {
|
||||
// Simple case: amount and fee both in Qora
|
||||
@ -208,6 +203,33 @@ public class DeployAtTransaction extends Transaction {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
Account creator = getCreator();
|
||||
long assetId = deployATTransactionData.getAssetId();
|
||||
|
||||
// Check creator has enough funds
|
||||
if (assetId == Asset.QORA) {
|
||||
// Simple case: amount and fee both in Qora
|
||||
BigDecimal minimumBalance = deployATTransactionData.getFee().add(deployATTransactionData.getAmount());
|
||||
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(minimumBalance) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
} else {
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(deployATTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
if (creator.getConfirmedBalance(assetId).compareTo(deployATTransactionData.getAmount()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
}
|
||||
|
||||
// Check AT doesn't already exist
|
||||
if (this.repository.getATRepository().exists(deployATTransactionData.getAtAddress()))
|
||||
return ValidationResult.AT_ALREADY_EXISTS;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
ensureATAddress();
|
||||
@ -220,13 +242,9 @@ public class DeployAtTransaction extends Transaction {
|
||||
|
||||
long assetId = deployATTransactionData.getAssetId();
|
||||
|
||||
// Update creator's balance
|
||||
// Update creator's balance regarding initial payment to AT
|
||||
Account creator = getCreator();
|
||||
creator.setConfirmedBalance(assetId, creator.getConfirmedBalance(assetId).subtract(deployATTransactionData.getAmount()));
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(deployATTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(deployATTransactionData.getSignature());
|
||||
|
||||
// Update AT's reference, which also creates AT account
|
||||
Account atAccount = this.getATAccount();
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -121,10 +120,6 @@ public class EnableForgingTransaction extends Transaction {
|
||||
if (enableForgingTransactionData.getFee().compareTo(BigDecimal.ZERO) < 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(creator.getLastReference(), enableForgingTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(enableForgingTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -153,12 +148,6 @@ public class EnableForgingTransaction extends Transaction {
|
||||
target.setForgingEnabler(creator.getAddress());
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update creator's balance
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(enableForgingTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(enableForgingTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,13 +140,20 @@ public class GenesisTransaction extends Transaction {
|
||||
|
||||
Account recipient = new Account(repository, genesisTransactionData.getRecipient());
|
||||
|
||||
// Set recipient's starting reference (also creates account)
|
||||
recipient.setLastReference(genesisTransactionData.getSignature());
|
||||
|
||||
// Update recipient's balance
|
||||
recipient.setConfirmedBalance(Asset.QORA, genesisTransactionData.getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// Do not attempt to update non-existent genesis account's reference!
|
||||
|
||||
Account recipient = new Account(repository, genesisTransactionData.getRecipient());
|
||||
|
||||
// Set recipient's starting reference (also creates account)
|
||||
recipient.setLastReference(genesisTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -83,10 +82,6 @@ public class GroupApprovalTransaction extends Transaction {
|
||||
if (groupApprovalTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(admin.getLastReference(), groupApprovalTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupApprovalTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -104,13 +99,6 @@ public class GroupApprovalTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated prior reference to transaction that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupApprovalTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupApprovalTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupApprovalTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -101,10 +100,6 @@ public class GroupBanTransaction extends Transaction {
|
||||
if (groupBanTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(admin.getLastReference(), groupBanTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check admin has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupBanTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -120,13 +115,6 @@ public class GroupBanTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupBanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupBanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupBanTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -107,10 +106,6 @@ public class GroupInviteTransaction extends Transaction {
|
||||
if (groupInviteTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(admin.getLastReference(), groupInviteTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupInviteTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -126,13 +121,6 @@ public class GroupInviteTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupInviteTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupInviteTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupInviteTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -107,10 +106,6 @@ public class GroupKickTransaction extends Transaction {
|
||||
if (groupKickTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(admin.getLastReference(), groupKickTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupKickTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -126,13 +121,6 @@ public class GroupKickTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupKickTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupKickTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupKickTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -118,16 +117,17 @@ public class IssueAssetTransaction extends Transaction {
|
||||
if (issueAssetTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
Account issuer = getIssuer();
|
||||
|
||||
if (!Arrays.equals(issuer.getLastReference(), issueAssetTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (issuer.getConfirmedBalance(Asset.QORA).compareTo(issueAssetTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check the asset name isn't already taken. This check is not present in gen1.
|
||||
if (issueAssetTransactionData.getTimestamp() >= BlockChain.getInstance().getQoraV2Timestamp())
|
||||
if (this.repository.getAssetRepository().assetExists(issueAssetTransactionData.getAssetName()))
|
||||
@ -148,13 +148,6 @@ public class IssueAssetTransaction extends Transaction {
|
||||
// Save this transaction, now with corresponding assetId
|
||||
this.repository.getTransactionRepository().save(issueAssetTransactionData);
|
||||
|
||||
// Update issuer's balance
|
||||
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 = getOwner();
|
||||
owner.setConfirmedBalance(issueAssetTransactionData.getAssetId(), BigDecimal.valueOf(issueAssetTransactionData.getQuantity()).setScale(8));
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -87,10 +86,6 @@ public class JoinGroupTransaction extends Transaction {
|
||||
// Check fee is positive
|
||||
if (joinGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
if (!Arrays.equals(joiner.getLastReference(), joinGroupTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (joiner.getConfirmedBalance(Asset.QORA).compareTo(joinGroupTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -106,14 +101,6 @@ public class JoinGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with cached references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(joinGroupTransactionData);
|
||||
|
||||
// Update joiner's balance
|
||||
Account joiner = getJoiner();
|
||||
joiner.setConfirmedBalance(Asset.QORA, joiner.getConfirmedBalance(Asset.QORA).subtract(joinGroupTransactionData.getFee()));
|
||||
|
||||
// Update joiner's reference
|
||||
joiner.setLastReference(joinGroupTransactionData.getSignature());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -86,10 +85,6 @@ public class LeaveGroupTransaction extends Transaction {
|
||||
if (leaveGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(leaver.getLastReference(), leaveGroupTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (leaver.getConfirmedBalance(Asset.QORA).compareTo(leaveGroupTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -105,13 +100,6 @@ public class LeaveGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(leaveGroupTransactionData);
|
||||
|
||||
// Update leaver's balance
|
||||
Account leaver = getLeaver();
|
||||
leaver.setConfirmedBalance(Asset.QORA, leaver.getConfirmedBalance(Asset.QORA).subtract(leaveGroupTransactionData.getFee()));
|
||||
|
||||
// Update leaver's reference
|
||||
leaver.setLastReference(leaveGroupTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -101,11 +100,6 @@ public class MessageTransaction extends Transaction {
|
||||
if (messageTransactionData.getData().length < 1 || messageTransactionData.getData().length > MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// Check reference is correct
|
||||
Account sender = getSender();
|
||||
if (!Arrays.equals(sender.getLastReference(), messageTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Zero-amount payments (i.e. message-only) only valid for versions later than 1
|
||||
boolean isZeroAmountValid = messageTransactionData.getVersion() > 1;
|
||||
|
||||
@ -114,12 +108,29 @@ public class MessageTransaction extends Transaction {
|
||||
isZeroAmountValid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Zero-amount payments (i.e. message-only) only valid for versions later than 1
|
||||
boolean isZeroAmountValid = messageTransactionData.getVersion() > 1;
|
||||
|
||||
// Wrap and delegate final processable checks to Payment class
|
||||
return new Payment(this.repository).isProcessable(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(),
|
||||
isZeroAmountValid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class. Only update recipient's last reference if transferring QORA.
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(),
|
||||
messageTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate references processing to Payment class. Only update recipient's last reference if transferring QORA.
|
||||
new Payment(this.repository).processReferencesAndFees(messageTransactionData.getSenderPublicKey(), getPaymentData(), messageTransactionData.getFee(),
|
||||
messageTransactionData.getSignature(), false);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
@ -102,9 +101,6 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
// Check reference is correct
|
||||
Account sender = getSender();
|
||||
|
||||
if (!Arrays.equals(sender.getLastReference(), multiPaymentTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check sender has enough funds for fee
|
||||
// NOTE: in Gen1 pre-POWFIX-RELEASE transactions didn't have this check
|
||||
if (multiPaymentTransactionData.getTimestamp() >= BlockChain.getInstance().getPowFixReleaseTimestamp()
|
||||
@ -114,12 +110,28 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
return new Payment(this.repository).isValid(multiPaymentTransactionData.getSenderPublicKey(), payments, multiPaymentTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
List<PaymentData> payments = multiPaymentTransactionData.getPayments();
|
||||
|
||||
return new Payment(this.repository).isProcessable(multiPaymentTransactionData.getSenderPublicKey(), payments, multiPaymentTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class. Always update recipients' last references regardless of asset.
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(),
|
||||
multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate reference processing to Payment class. Always update recipients' last references regardless of asset.
|
||||
new Payment(this.repository).processReferencesAndFees(multiPaymentTransactionData.getSenderPublicKey(), multiPaymentTransactionData.getPayments(),
|
||||
multiPaymentTransactionData.getFee(), multiPaymentTransactionData.getSignature(), true);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -77,21 +76,29 @@ public class PaymentTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Check reference is correct
|
||||
Account sender = getSender();
|
||||
if (!Arrays.equals(sender.getLastReference(), paymentTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Wrap and delegate final payment checks to Payment class
|
||||
return new Payment(this.repository).isValid(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Wrap and delegate final processable checks to Payment class
|
||||
return new Payment(this.repository).isProcessable(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap and delegate payment processing to Payment class. Only update recipient's last reference if transferring QORA.
|
||||
// Wrap and delegate payment processing to Payment class.
|
||||
new Payment(this.repository).process(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee(),
|
||||
paymentTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// Wrap and delegate references processing to Payment class. Only update recipient's last reference if transferring QORA.
|
||||
new Payment(this.repository).processReferencesAndFees(paymentTransactionData.getSenderPublicKey(), getPaymentData(), paymentTransactionData.getFee(),
|
||||
paymentTransactionData.getSignature(), false);
|
||||
}
|
||||
|
||||
|
@ -106,10 +106,6 @@ public class ProxyForgingTransaction extends Transaction {
|
||||
if (proxyForgingTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(creator.getLastReference(), proxyForgingTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(proxyForgingTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -134,12 +130,11 @@ public class ProxyForgingTransaction extends Transaction {
|
||||
// Save proxy forging info
|
||||
proxyForgerData = new ProxyForgerData(forger.getPublicKey(), proxyForgingTransactionData.getRecipient(), proxyForgingTransactionData.getProxyPublicKey(), proxyForgingTransactionData.getShare());
|
||||
this.repository.getAccountRepository().save(proxyForgerData);
|
||||
}
|
||||
|
||||
// Update forger's balance
|
||||
forger.setConfirmedBalance(Asset.QORA, forger.getConfirmedBalance(Asset.QORA).subtract(proxyForgingTransactionData.getFee()));
|
||||
|
||||
// Update forger's reference
|
||||
forger.setLastReference(proxyForgingTransactionData.getSignature());
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
super.processReferencesAndFees();
|
||||
|
||||
// If proxy recipient has no last-reference then use this transaction's signature as last-reference so they can spend their block rewards
|
||||
Account recipient = new Account(this.repository, proxyForgingTransactionData.getRecipient());
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -78,10 +77,6 @@ public class RegisterNameTransaction extends Transaction {
|
||||
public ValidationResult isValid() throws DataException {
|
||||
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())
|
||||
return ValidationResult.MULTIPLE_NAMES_FORBIDDEN;
|
||||
|
||||
// Check owner address is valid
|
||||
if (!Crypto.isValidAddress(registerNameTransactionData.getOwner()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
@ -100,18 +95,10 @@ public class RegisterNameTransaction extends Transaction {
|
||||
if (!registerNameTransactionData.getName().equals(registerNameTransactionData.getName().toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
|
||||
// Check the name isn't already taken
|
||||
if (this.repository.getNameRepository().nameExists(registerNameTransactionData.getName()))
|
||||
return ValidationResult.NAME_ALREADY_REGISTERED;
|
||||
|
||||
// Check fee is positive
|
||||
if (registerNameTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(registrant.getLastReference(), registerNameTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (registrant.getConfirmedBalance(Asset.QORA).compareTo(registerNameTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -119,6 +106,21 @@ public class RegisterNameTransaction extends Transaction {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check the name isn't already taken
|
||||
if (this.repository.getNameRepository().nameExists(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())
|
||||
return ValidationResult.MULTIPLE_NAMES_FORBIDDEN;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Register Name
|
||||
@ -126,13 +128,6 @@ public class RegisterNameTransaction extends Transaction {
|
||||
name.register();
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update registrant's balance
|
||||
Account registrant = getRegistrant();
|
||||
registrant.setConfirmedBalance(Asset.QORA, registrant.getConfirmedBalance(Asset.QORA).subtract(registerNameTransactionData.getFee()));
|
||||
|
||||
// Update registrant's reference
|
||||
registrant.setLastReference(registerNameTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -100,10 +99,6 @@ public class RemoveGroupAdminTransaction extends Transaction {
|
||||
if (removeGroupAdminTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(owner.getLastReference(), removeGroupAdminTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(removeGroupAdminTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -119,13 +114,6 @@ public class RemoveGroupAdminTransaction extends Transaction {
|
||||
|
||||
// Save this transaction with cached references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(removeGroupAdminTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(removeGroupAdminTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(removeGroupAdminTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
@ -105,10 +104,6 @@ public class SellNameTransaction extends Transaction {
|
||||
if (sellNameTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(owner.getLastReference(), sellNameTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(sellNameTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -123,13 +118,6 @@ public class SellNameTransaction extends Transaction {
|
||||
name.sell(sellNameTransactionData);
|
||||
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(sellNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(sellNameTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -74,10 +73,6 @@ public class SetGroupTransaction extends Transaction {
|
||||
if (setGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference
|
||||
if (!Arrays.equals(creator.getLastReference(), setGroupTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(setGroupTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -100,12 +95,6 @@ public class SetGroupTransaction extends Transaction {
|
||||
|
||||
// Set account's new default groupID
|
||||
creator.setDefaultGroupId(setGroupTransactionData.getDefaultGroupId());
|
||||
|
||||
// Update creator's balance
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(setGroupTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
creator.setLastReference(setGroupTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -229,6 +229,7 @@ public abstract class Transaction {
|
||||
PUBLIC_KEY_UNKNOWN(78),
|
||||
INVALID_PUBLIC_KEY(79),
|
||||
AT_UNKNOWN(80),
|
||||
AT_ALREADY_EXISTS(81),
|
||||
NOT_YET_RELEASED(1000);
|
||||
|
||||
public final int value;
|
||||
@ -831,6 +832,33 @@ public abstract class Transaction {
|
||||
*/
|
||||
public abstract ValidationResult isValid() throws DataException;
|
||||
|
||||
/**
|
||||
* Returns whether transaction's reference is valid.
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public boolean hasValidReference() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
return Arrays.equals(transactionData.getReference(), creator.getLastReference());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether transaction can be processed.
|
||||
* <p>
|
||||
* With group-approval, even if a transaction had valid values
|
||||
* when submitted, by the time it is approved dependency might
|
||||
* have changed.
|
||||
* <p>
|
||||
* For example, with UPDATE_ASSET, the asset owner might have
|
||||
* changed between submission and approval.
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
return ValidationResult.OK;
|
||||
};
|
||||
|
||||
/**
|
||||
* Actually process a transaction, updating the blockchain.
|
||||
* <p>
|
||||
@ -841,13 +869,14 @@ public abstract class Transaction {
|
||||
public abstract void process() throws DataException;
|
||||
|
||||
/**
|
||||
* Update creator's last reference, subtract transaction fee, etc.
|
||||
* Update last references, subtract transaction fees, etc.
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public void processCreatorUpdates() throws DataException {
|
||||
// Update transaction creator's balance
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
Account creator = getCreator();
|
||||
|
||||
// Update transaction creator's balance
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(transactionData.getFee()));
|
||||
|
||||
// Update transaction creator's reference
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -89,22 +88,29 @@ public class TransferAssetTransaction extends Transaction {
|
||||
if (this.transferAssetTransactionData.getTimestamp() < BlockChain.getInstance().getAssetsReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check reference is correct
|
||||
Account sender = getSender();
|
||||
|
||||
if (!Arrays.equals(sender.getLastReference(), transferAssetTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Wrap asset transfer as a payment and delegate final payment checks to Payment class
|
||||
return new Payment(this.repository).isValid(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Wrap asset transfer as a payment and delegate final processable checks to Payment class
|
||||
return new Payment(this.repository).isProcessable(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// We would save updated transaction at this point, but it hasn't been modified
|
||||
|
||||
// Wrap asset transfer as a payment and delegate processing to Payment class. Only update recipient's last reference if transferring QORA.
|
||||
new Payment(this.repository).process(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee(),
|
||||
transferAssetTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReferencesAndFees() throws DataException {
|
||||
// Wrap asset transfer as a payment and delegate processing to Payment class. Only update recipient's last reference if transferring QORA.
|
||||
new Payment(this.repository).processReferencesAndFees(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee(),
|
||||
transferAssetTransactionData.getSignature(), false);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -85,11 +84,6 @@ public class UpdateAssetTransaction extends Transaction {
|
||||
if (assetData == null)
|
||||
return ValidationResult.ASSET_DOES_NOT_EXIST;
|
||||
|
||||
// Check transaction's public key matches asset's current owner
|
||||
PublicKeyAccount currentOwner = getOwner();
|
||||
if (!assetData.getOwner().equals(currentOwner.getAddress()))
|
||||
return ValidationResult.INVALID_ASSET_OWNER;
|
||||
|
||||
// Check new owner address is valid
|
||||
if (!Crypto.isValidAddress(updateAssetTransactionData.getNewOwner()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
@ -113,9 +107,7 @@ public class UpdateAssetTransaction extends Transaction {
|
||||
if (updateAssetTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(currentOwner.getLastReference(), updateAssetTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
Account currentOwner = getOwner();
|
||||
|
||||
// Check current owner has enough funds
|
||||
if (currentOwner.getConfirmedBalance(Asset.QORA).compareTo(updateAssetTransactionData.getFee()) < 0)
|
||||
@ -124,6 +116,18 @@ public class UpdateAssetTransaction extends Transaction {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check transaction's public key matches asset's current owner
|
||||
Account currentOwner = getOwner();
|
||||
AssetData assetData = this.repository.getAssetRepository().fromAssetId(updateAssetTransactionData.getAssetId());
|
||||
|
||||
if (!assetData.getOwner().equals(currentOwner.getAddress()))
|
||||
return ValidationResult.INVALID_ASSET_OWNER;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update Asset
|
||||
@ -132,14 +136,6 @@ public class UpdateAssetTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, with updated "name reference" to previous transaction that updated name
|
||||
this.repository.getTransactionRepository().save(updateAssetTransactionData);
|
||||
|
||||
// Update old owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA,
|
||||
owner.getConfirmedBalance(Asset.QORA).subtract(updateAssetTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(updateAssetTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -101,6 +100,22 @@ public class UpdateGroupTransaction extends Transaction {
|
||||
|
||||
Account owner = getOwner();
|
||||
|
||||
// Check fee is positive
|
||||
if (updateGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(updateGroupTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
GroupData groupData = this.repository.getGroupRepository().fromGroupId(updateGroupTransactionData.getGroupId());
|
||||
Account owner = getOwner();
|
||||
|
||||
// Check transaction's public key matches group's current owner
|
||||
if (!owner.getAddress().equals(groupData.getOwner()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
@ -111,17 +126,6 @@ public class UpdateGroupTransaction extends Transaction {
|
||||
if (this.repository.getGroupRepository().banExists(updateGroupTransactionData.getGroupId(), newOwner.getAddress()))
|
||||
return ValidationResult.BANNED_FROM_GROUP;
|
||||
|
||||
// Check fee is positive
|
||||
if (updateGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(owner.getLastReference(), updateGroupTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(updateGroupTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
@ -134,13 +138,6 @@ public class UpdateGroupTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, now with updated "group reference" to previous transaction that updated group
|
||||
this.repository.getTransactionRepository().save(updateGroupTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(updateGroupTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(updateGroupTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -104,23 +103,12 @@ public class UpdateNameTransaction extends Transaction {
|
||||
if (nameData.getCreationGroupId() != updateNameTransactionData.getTxGroupId())
|
||||
return ValidationResult.TX_GROUP_ID_MISMATCH;
|
||||
|
||||
// Check name isn't currently for sale
|
||||
if (nameData.getIsForSale())
|
||||
return ValidationResult.NAME_ALREADY_FOR_SALE;
|
||||
|
||||
// Check transaction's public key matches name's current owner
|
||||
Account owner = getOwner();
|
||||
if (!owner.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_NAME_OWNER;
|
||||
|
||||
// Check fee is positive
|
||||
if (updateNameTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
if (!Arrays.equals(owner.getLastReference(), updateNameTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (owner.getConfirmedBalance(Asset.QORA).compareTo(updateNameTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -128,6 +116,23 @@ public class UpdateNameTransaction extends Transaction {
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
NameData nameData = this.repository.getNameRepository().fromName(updateNameTransactionData.getName());
|
||||
|
||||
// Check name isn't currently for sale
|
||||
if (nameData.getIsForSale())
|
||||
return ValidationResult.NAME_ALREADY_FOR_SALE;
|
||||
|
||||
Account owner = getOwner();
|
||||
|
||||
// Check transaction's public key matches name's current owner
|
||||
if (!owner.getAddress().equals(nameData.getOwner()))
|
||||
return ValidationResult.INVALID_NAME_OWNER;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update Name
|
||||
@ -136,13 +141,6 @@ public class UpdateNameTransaction extends Transaction {
|
||||
|
||||
// Save this transaction, now with updated "name reference" to previous transaction that updated name
|
||||
this.repository.getTransactionRepository().save(updateNameTransactionData);
|
||||
|
||||
// Update owner's balance
|
||||
Account owner = getOwner();
|
||||
owner.setConfirmedBalance(Asset.QORA, owner.getConfirmedBalance(Asset.QORA).subtract(updateNameTransactionData.getFee()));
|
||||
|
||||
// Update owner's reference
|
||||
owner.setLastReference(updateNameTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,6 @@ package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -110,9 +109,6 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
// Check reference is correct
|
||||
Account voter = getVoter();
|
||||
|
||||
if (!Arrays.equals(voter.getLastReference(), voteOnPollTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check voter has enough funds
|
||||
if (voter.getConfirmedBalance(Asset.QORA).compareTo(voteOnPollTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
@ -122,12 +118,7 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update voter's balance
|
||||
Account voter = getVoter();
|
||||
voter.setConfirmedBalance(Asset.QORA, voter.getConfirmedBalance(Asset.QORA).subtract(voteOnPollTransactionData.getFee()));
|
||||
|
||||
// Update vote's reference
|
||||
voter.setLastReference(voteOnPollTransactionData.getSignature());
|
||||
|
||||
VotingRepository votingRepository = this.repository.getVotingRepository();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user