forked from Qortal/qortal
Compare commits
1 Commits
master
...
optimize_a
Author | SHA1 | Date | |
---|---|---|---|
|
3be2abdf8d |
@ -1,5 +1,6 @@
|
||||
package org.qortal.at;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -10,6 +11,7 @@ import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.at.ATStateData;
|
||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.repository.ATRepository;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
@ -22,6 +24,8 @@ public class AT {
|
||||
private ATData atData;
|
||||
private ATStateData atStateData;
|
||||
|
||||
private List<TransactionData> parentBlockTransactions = new ArrayList<>();
|
||||
|
||||
// Constructors
|
||||
|
||||
public AT(Repository repository, ATData atData, ATStateData atStateData) {
|
||||
@ -72,6 +76,10 @@ public class AT {
|
||||
return this.atStateData;
|
||||
}
|
||||
|
||||
public void setParentBlockTransactions(List<TransactionData> transactions) {
|
||||
this.parentBlockTransactions = transactions;
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
public void deploy() throws DataException {
|
||||
@ -105,7 +113,7 @@ public class AT {
|
||||
QortalATAPI api = new QortalATAPI(repository, this.atData, blockTimestamp);
|
||||
QortalAtLoggerFactory loggerFactory = QortalAtLoggerFactory.getInstance();
|
||||
|
||||
if (!api.willExecute(blockHeight))
|
||||
if (!api.willExecute(blockHeight, this.parentBlockTransactions))
|
||||
// this.atStateData will be null
|
||||
return Collections.emptyList();
|
||||
|
||||
|
@ -3,6 +3,7 @@ package org.qortal.at;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -23,11 +24,7 @@ import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.data.block.BlockSummaryData;
|
||||
import org.qortal.data.transaction.ATTransactionData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.MessageTransactionData;
|
||||
import org.qortal.data.transaction.PaymentTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.*;
|
||||
import org.qortal.group.Group;
|
||||
import org.qortal.repository.ATRepository;
|
||||
import org.qortal.repository.DataException;
|
||||
@ -75,7 +72,7 @@ public class QortalATAPI extends API {
|
||||
return this.transactions;
|
||||
}
|
||||
|
||||
public boolean willExecute(int blockHeight) throws DataException {
|
||||
public boolean willExecute(int blockHeight, List<TransactionData> parentBlockTransactions) throws DataException {
|
||||
// Sleep-until-message/height checking
|
||||
Long sleepUntilMessageTimestamp = this.atData.getSleepUntilMessageTimestamp();
|
||||
|
||||
@ -87,13 +84,27 @@ public class QortalATAPI extends API {
|
||||
|
||||
boolean wakeDueToMessage = false;
|
||||
if (!wakeDueToHeight) {
|
||||
// No avoiding asking repository
|
||||
Timestamp previousTxTimestamp = new Timestamp(sleepUntilMessageTimestamp);
|
||||
NextTransactionInfo nextTransactionInfo = this.repository.getATRepository().findNextTransaction(this.atData.getATAddress(),
|
||||
previousTxTimestamp.blockHeight,
|
||||
previousTxTimestamp.transactionSequence);
|
||||
// Check parent block's transactions to see if any relate to this AT
|
||||
for (TransactionData transactionData : parentBlockTransactions) {
|
||||
if (this.wasTransactionSentToThisAT(transactionData)) {
|
||||
wakeDueToMessage = true;
|
||||
}
|
||||
}
|
||||
|
||||
wakeDueToMessage = nextTransactionInfo != null;
|
||||
if (wakeDueToMessage) {
|
||||
// Double check with repository that this AT should be executed, to filter out cases such as TRANSFER_ASSET
|
||||
Timestamp previousTxTimestamp = new Timestamp(sleepUntilMessageTimestamp);
|
||||
NextTransactionInfo nextTransactionInfo = this.repository.getATRepository().findNextTransaction(this.atData.getATAddress(),
|
||||
previousTxTimestamp.blockHeight,
|
||||
previousTxTimestamp.transactionSequence);
|
||||
|
||||
wakeDueToMessage = nextTransactionInfo != null;
|
||||
}
|
||||
else {
|
||||
// No relevant transactions in previous block, so there is no need to check the db
|
||||
// TODO: do we need to handle ATs that were previously frozen and have now recovered, or
|
||||
// would we always detect a transaction in the last block in these cases?
|
||||
}
|
||||
}
|
||||
|
||||
// Can we skip?
|
||||
@ -104,6 +115,32 @@ public class QortalATAPI extends API {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean wasTransactionSentToThisAT(TransactionData transactionData) {
|
||||
switch (transactionData.getType()) {
|
||||
case PAYMENT: {
|
||||
PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData;
|
||||
return Objects.equals(paymentTransactionData.getRecipient(), this.atData.getATAddress());
|
||||
}
|
||||
case TRANSFER_ASSET: {
|
||||
// ATs don't check for TRANSFER_ASSET, but an AT's balance could be topped up using TRANSFER_ASSET,
|
||||
// therefore unfreezing it.
|
||||
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) transactionData;
|
||||
return Objects.equals(transferAssetTransactionData.getRecipient(), this.atData.getATAddress());
|
||||
}
|
||||
case MESSAGE: {
|
||||
MessageTransactionData messageTransactionData = (MessageTransactionData) transactionData;
|
||||
return Objects.equals(messageTransactionData.getRecipient(), this.atData.getATAddress());
|
||||
}
|
||||
case AT: {
|
||||
ATTransactionData atTransactionData = (ATTransactionData) transactionData;
|
||||
return Objects.equals(atTransactionData.getRecipient(), this.atData.getATAddress());
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void preExecute(MachineState state) {
|
||||
// Sleep-until-message/height checking
|
||||
Long sleepUntilMessageTimestamp = this.atData.getSleepUntilMessageTimestamp();
|
||||
|
@ -1378,6 +1378,8 @@ public class Block {
|
||||
*
|
||||
*/
|
||||
private void executeATs() throws DataException {
|
||||
Long startTime = NTP.getTime();
|
||||
|
||||
// We're expecting a lack of AT state data at this point.
|
||||
if (this.ourAtStates != null)
|
||||
throw new IllegalStateException("Attempted to execute ATs when block's local AT state data already exists");
|
||||
@ -1391,9 +1393,13 @@ public class Block {
|
||||
// Find all executable ATs, ordered by earliest creation date first
|
||||
List<ATData> executableATs = this.repository.getATRepository().getAllExecutableATs();
|
||||
|
||||
// Get all transactions from the parent block. These are used to avoid unnecessary AT executions / db lookups.
|
||||
List<TransactionData> parentBlockTransactions = repository.getBlockRepository().getTransactionsFromSignature(this.blockData.getReference());
|
||||
|
||||
// Run each AT, appends AT-Transactions and corresponding AT states, to our lists
|
||||
for (ATData atData : executableATs) {
|
||||
AT at = new AT(this.repository, atData);
|
||||
at.setParentBlockTransactions(parentBlockTransactions);
|
||||
List<AtTransaction> atTransactions = at.run(this.blockData.getHeight(), this.blockData.getTimestamp());
|
||||
ATStateData atStateData = at.getATStateData();
|
||||
// Didn't execute? (e.g. sleeping)
|
||||
@ -1417,6 +1423,8 @@ public class Block {
|
||||
// AT Transactions do not affect block's transaction count
|
||||
|
||||
// AT Transactions do not affect block's transaction signature
|
||||
|
||||
LOGGER.info("Executing {} ATs in block {} took {} ms", executableATs.size(), this.blockData.getHeight(), (NTP.getTime()-startTime));
|
||||
}
|
||||
|
||||
/** Returns whether block's minter is actually allowed to mint this block. */
|
||||
|
Loading…
Reference in New Issue
Block a user