diff --git a/src/main/java/org/qortal/transaction/Transaction.java b/src/main/java/org/qortal/transaction/Transaction.java index 70f5517d..047b3cc6 100644 --- a/src/main/java/org/qortal/transaction/Transaction.java +++ b/src/main/java/org/qortal/transaction/Transaction.java @@ -486,9 +486,6 @@ public abstract class Transaction { /** * Returns whether transaction can be added to unconfirmed transactions. - *
- * NOTE: temporarily updates accounts' lastReference to check validity.
- * To do this, blockchain lock is obtained and pending repository changes are discarded.
*
* @return transaction validation result, e.g. OK
* @throws DataException
@@ -502,7 +499,7 @@ public abstract class Transaction {
if (now >= this.getDeadline())
return ValidationResult.TIMESTAMP_TOO_OLD;
- // Transactions with a timestamp prior to latest block's timestamp are too old
+ // Transactions with a expiry prior to latest block's timestamp are too old
BlockData latestBlock = repository.getBlockRepository().getLastBlock();
if (this.getDeadline() <= latestBlock.getTimestamp())
return ValidationResult.TIMESTAMP_TOO_OLD;
@@ -595,9 +592,6 @@ public abstract class Transaction {
/**
* Returns sorted, unconfirmed transactions, excluding invalid.
- *
- * NOTE: temporarily updates accounts' lastReference to check validity.
- * NOTE: temporarily updates accounts' lastReference to check validity.
- * NOTE: temporarily updates creator's lastReference to that from
- * unconfirmed transactions, and hence caller should use a repository
- * savepoint or invoke repository.discardChanges().
- *
- * Caller should also hold the blockchain lock as we're 'updating'
- * when we fake the transaction creator's last reference, even if
- * it discarded at rollback.
+ * This is like {@link #isValidUnconfirmed()} but only needs to perform
+ * a subset of those checks.
*
- * @return true if transaction can be added to unconfirmed transactions, false otherwise
+ * @return transaction validation result, e.g. OK
* @throws DataException
*/
- private static boolean isStillValidUnconfirmed(Repository repository, TransactionData transactionData, long blockTimestamp) throws DataException {
+ private ValidationResult isStillValidUnconfirmed(long blockTimestamp) throws DataException {
final Long now = NTP.getTime();
if (now == null)
- return false;
+ return ValidationResult.CLOCK_NOT_SYNCED;
- Transaction transaction = Transaction.fromData(repository, transactionData);
+ // Expired already?
+ if (now >= this.getDeadline())
+ return ValidationResult.TIMESTAMP_TOO_OLD;
- // Check transaction has not expired
- if (transaction.getDeadline() <= blockTimestamp || transaction.getDeadline() < now)
- return false;
+ // Transactions with a expiry prior to latest block's timestamp are too old
+ if (this.getDeadline() <= blockTimestamp)
+ return ValidationResult.TIMESTAMP_TOO_OLD;
- // Is transaction is past max approval period?
- if (transaction.needsGroupApproval()) {
- int txGroupId = transactionData.getTxGroupId();
- GroupData groupData = repository.getGroupRepository().fromGroupId(txGroupId);
+ // Transactions with a timestamp too far into future are too new
+ // Skipped because this test only applies at instant of submission
- int creationBlockHeight = repository.getBlockRepository().getHeightFromTimestamp(transactionData.getTimestamp());
- int currentBlockHeight = repository.getBlockRepository().getBlockchainHeight();
- if (currentBlockHeight > creationBlockHeight + groupData.getMaximumBlockDelay())
- return false;
- }
+ // Check fee is sufficient
+ // Skipped because this is checked upon submission and the result would be the same now
- // Check transaction is currently valid
- if (transaction.isValid() != Transaction.ValidationResult.OK)
- return false;
+ // Reject if unconfirmed pile already has X transactions from same creator
+ // Skipped because this test only applies at instant of submission
- // Good for adding to a block
- // Temporarily update sender's last reference so that subsequent transactions validations work
- // These updates should be discarded by some caller further up stack
- PublicKeyAccount creator = new PublicKeyAccount(repository, transactionData.getCreatorPublicKey());
- creator.setLastReference(transactionData.getSignature());
+ // Check transaction's txGroupId
+ // Skipped because this is checked upon submission and the result would be the same now
- return true;
+ // Check transaction references
+ if (!this.hasValidReference())
+ return ValidationResult.INVALID_REFERENCE;
+
+ // Check transaction is valid
+ ValidationResult result = this.isValid();
+ if (result != ValidationResult.OK)
+ return result;
+
+ // Check transaction is processable
+ result = this.isProcessable();
+
+ return result;
}
/**
- * To do this, blockchain lock is obtained and pending repository changes are discarded.
*
* @return sorted, unconfirmed transactions
* @throws DataException
@@ -609,35 +603,15 @@ public abstract class Transaction {
unconfirmedTransactions.sort(getDataComparator());
- /*
- * We have to grab the blockchain lock because we're updating
- * when we fake the creator's last reference,
- * even though we throw away the update when we rollback the
- * savepoint.
- */
- ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock();
- blockchainLock.lock();
- try {
- // Clear repository's "in transaction" state so we don't cause a repository deadlock
- repository.discardChanges();
+ Iterator
- * To do this, blockchain lock is obtained and pending repository changes are discarded.
*
* @return sorted, invalid, unconfirmed transactions
* @throws DataException
@@ -660,36 +631,16 @@ public abstract class Transaction {
unconfirmedTransactions.sort(getDataComparator());
- /*
- * We have to grab the blockchain lock because we're updating
- * when we fake the creator's last reference,
- * even though we throw away the update when we rollback the
- * savepoint.
- */
- ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock();
- blockchainLock.lock();
- try {
- // Clear repository's "in transaction" state so we don't cause a repository deadlock
- repository.discardChanges();
+ Iterator