diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java
index dc4c49a1f7d..169304d22b7 100644
--- a/rskj-core/src/main/java/co/rsk/RskContext.java
+++ b/rskj-core/src/main/java/co/rsk/RskContext.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk;
import co.rsk.bitcoinj.core.NetworkParameters;
@@ -402,7 +401,7 @@ public TxQuotaChecker getTxQuotaChecker() {
checkIfNotClosed();
if (this.txQuotaChecker == null) {
- this.txQuotaChecker = new TxQuotaChecker(System::currentTimeMillis);
+ this.txQuotaChecker = new TxQuotaChecker(System::currentTimeMillis, getReceivedTxSignatureCache());
}
return txQuotaChecker;
}
@@ -417,6 +416,16 @@ public synchronized ReceivedTxSignatureCache getReceivedTxSignatureCache() {
return receivedTxSignatureCache;
}
+ public BlockTxSignatureCache getBlockTxSignatureCache() {
+ checkIfNotClosed();
+
+ if (blockTxSignatureCache == null) {
+ blockTxSignatureCache = new BlockTxSignatureCache(getReceivedTxSignatureCache());
+ }
+
+ return blockTxSignatureCache;
+ }
+
public synchronized RepositoryLocator getRepositoryLocator() {
checkIfNotClosed();
@@ -485,7 +494,10 @@ public synchronized PrecompiledContracts getPrecompiledContracts() {
checkIfNotClosed();
if (precompiledContracts == null) {
- precompiledContracts = new PrecompiledContracts(getRskSystemProperties(), getBridgeSupportFactory());
+ precompiledContracts = new PrecompiledContracts(
+ getRskSystemProperties(),
+ getBridgeSupportFactory(),
+ getBlockTxSignatureCache());
}
return precompiledContracts;
@@ -497,7 +509,7 @@ public synchronized BridgeSupportFactory getBridgeSupportFactory() {
if (bridgeSupportFactory == null) {
bridgeSupportFactory = new BridgeSupportFactory(getBtcBlockStoreFactory(),
getRskSystemProperties().getNetworkConstants().getBridgeConstants(),
- getRskSystemProperties().getActivationConfig());
+ getRskSystemProperties().getActivationConfig(), getBlockTxSignatureCache());
}
return bridgeSupportFactory;
@@ -815,7 +827,8 @@ public synchronized TraceModule getTraceModule() {
getBlockStore(),
getReceiptStore(),
getBlockExecutor(),
- getExecutionBlockRetriever()
+ getExecutionBlockRetriever(),
+ getBlockTxSignatureCache()
);
}
@@ -836,7 +849,7 @@ public synchronized TxPoolModule getTxPoolModule() {
checkIfNotClosed();
if (txPoolModule == null) {
- txPoolModule = new TxPoolModuleImpl(getTransactionPool());
+ txPoolModule = new TxPoolModuleImpl(getTransactionPool(), getReceivedTxSignatureCache());
}
return txPoolModule;
@@ -1101,7 +1114,7 @@ public synchronized BlockParentDependantValidationRule getBlockParentDependantVa
if (blockParentDependantValidationRule == null) {
Constants commonConstants = getRskSystemProperties().getNetworkConstants();
blockParentDependantValidationRule = new BlockParentCompositeRule(
- new BlockTxsFieldsValidationRule(),
+ new BlockTxsFieldsValidationRule(getBlockTxSignatureCache()),
new BlockTxsValidationRule(getRepositoryLocator(), getBlockTxSignatureCache()),
new PrevMinGasPriceRule(),
new BlockParentNumberRule(),
@@ -1288,7 +1301,8 @@ protected synchronized Web3 buildWeb3() {
getBuildInfo(),
getBlocksBloomStore(),
getWeb3InformationRetriever(),
- getSyncProcessor());
+ getSyncProcessor(),
+ getBlockTxSignatureCache());
}
protected synchronized Web3InformationRetriever getWeb3InformationRetriever() {
@@ -1442,14 +1456,6 @@ private void initializeNativeLibs() {
AbstractAltBN128.init();
}
- private BlockTxSignatureCache getBlockTxSignatureCache() {
- if (blockTxSignatureCache == null) {
- blockTxSignatureCache = new BlockTxSignatureCache(getReceivedTxSignatureCache());
- }
-
- return blockTxSignatureCache;
- }
-
private KeyValueDataSource getBlocksBloomDataSource() {
if (this.blocksBloomDataSource == null) {
this.blocksBloomDataSource = this.buildBlocksBloomDataSource();
@@ -1766,7 +1772,8 @@ private BlockToMineBuilder getBlockToMineBuilder() {
getBlockFactory(),
getBlockExecutor(),
new MinimumGasPriceCalculator(Coin.valueOf(getMiningConfig().getMinGasPriceTarget())),
- new MinerUtils()
+ new MinerUtils(),
+ getBlockTxSignatureCache()
);
}
diff --git a/rskj-core/src/main/java/co/rsk/core/bc/PendingState.java b/rskj-core/src/main/java/co/rsk/core/bc/PendingState.java
index 0c794416701..d4ff4529751 100644
--- a/rskj-core/src/main/java/co/rsk/core/bc/PendingState.java
+++ b/rskj-core/src/main/java/co/rsk/core/bc/PendingState.java
@@ -15,17 +15,13 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.core.bc;
import co.rsk.core.Coin;
import co.rsk.core.RskAddress;
import co.rsk.crypto.Keccak256;
import co.rsk.db.RepositorySnapshot;
-import org.ethereum.core.Repository;
-import org.ethereum.core.Transaction;
-import org.ethereum.core.TransactionExecutor;
-import org.ethereum.core.TransactionSet;
+import org.ethereum.core.*;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.slf4j.Logger;
@@ -46,12 +42,13 @@ public class PendingState implements AccountInformationProvider {
private final TransactionExecutorFactory transactionExecutorFactory;
private final TransactionSet pendingTransactions;
private boolean executed = false;
+ private final SignatureCache signatureCache;
-
- public PendingState(RepositorySnapshot repository, TransactionSet pendingTransactions, TransactionExecutorFactory transactionExecutorFactory) {
+ public PendingState(RepositorySnapshot repository, TransactionSet pendingTransactions, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache) {
this.pendingRepository = repository.startTracking();
this.pendingTransactions = pendingTransactions;
this.transactionExecutorFactory = transactionExecutorFactory;
+ this.signatureCache = signatureCache;
}
@Override
@@ -117,13 +114,13 @@ public BigInteger getNonce(RskAddress addr) {
// Note that this sort doesn't return the best solution, it is an approximation algorithm to find approximate
// solution. (No trivial solution)
- public static List sortByPriceTakingIntoAccountSenderAndNonce(List transactions) {
+ public static List sortByPriceTakingIntoAccountSenderAndNonce(List transactions, SignatureCache signatureCache) {
//Priority heap, and list of transactions are ordered by descending gas price.
Comparator gasPriceComparator = reverseOrder(Comparator.comparing(Transaction::getGasPrice));
//First create a map to separate txs by each sender.
- Map> senderTxs = transactions.stream().collect(Collectors.groupingBy(Transaction::getSender));
+ Map> senderTxs = transactions.stream().collect(Collectors.groupingBy(transaction -> transaction.getSender(signatureCache)));
//For each sender, order all txs by nonce and then by hash,
//finally we order by price in cases where nonce are equal, and then by hash to disambiguate
@@ -151,7 +148,7 @@ public static List sortByPriceTakingIntoAccountSenderAndNonce(List<
while (txsCount > 0) {
Transaction nextTxToAdd = candidateTxs.remove();
sortedTxs.add(nextTxToAdd);
- List txs = senderTxs.get(nextTxToAdd.getSender());
+ List txs = senderTxs.get(nextTxToAdd.getSender(signatureCache));
if (!txs.isEmpty()) {
Transaction tx = txs.remove(0);
candidateTxs.add(tx);
@@ -172,8 +169,7 @@ private T postExecutionReturn(PostExecutionAction action) {
}
private void executeTransactions(Repository currentRepository, List pendingTransactions) {
-
- PendingState.sortByPriceTakingIntoAccountSenderAndNonce(pendingTransactions)
+ PendingState.sortByPriceTakingIntoAccountSenderAndNonce(pendingTransactions, signatureCache)
.forEach(pendingTransaction -> executeTransaction(currentRepository, pendingTransaction));
}
diff --git a/rskj-core/src/main/java/co/rsk/core/bc/TransactionPoolImpl.java b/rskj-core/src/main/java/co/rsk/core/bc/TransactionPoolImpl.java
index d3e93159a52..1b784dd62fc 100644
--- a/rskj-core/src/main/java/co/rsk/core/bc/TransactionPoolImpl.java
+++ b/rskj-core/src/main/java/co/rsk/core/bc/TransactionPoolImpl.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.core.bc;
import co.rsk.config.RskSystemProperties;
@@ -52,8 +51,8 @@
public class TransactionPoolImpl implements TransactionPool {
private static final Logger logger = LoggerFactory.getLogger("txpool");
- private final TransactionSet pendingTransactions = new TransactionSet();
- private final TransactionSet queuedTransactions = new TransactionSet();
+ private final TransactionSet pendingTransactions;
+ private final TransactionSet queuedTransactions;
private final Map transactionBlocks = new HashMap<>();
private final Map transactionTimes = new HashMap<>();
@@ -95,7 +94,10 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit
this.quotaChecker = txQuotaChecker;
this.gasPriceTracker = gasPriceTracker;
- this.validator = new TxPendingValidator(config.getNetworkConstants(), config.getActivationConfig(), config.getNumOfAccountSlots());
+ pendingTransactions = new TransactionSet(this.signatureCache);
+ queuedTransactions = new TransactionSet(this.signatureCache);
+
+ this.validator = new TxPendingValidator(config.getNetworkConstants(), config.getActivationConfig(), config.getNumOfAccountSlots(), signatureCache);
if (this.outdatedTimeout > 0) {
this.cleanerTimer = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "TransactionPoolCleanerTimer"));
@@ -158,7 +160,7 @@ public PendingState getPendingState() {
private PendingState getPendingState(RepositorySnapshot currentRepository) {
removeObsoleteTransactions(this.outdatedThreshold, this.outdatedTimeout);
- return new PendingState(currentRepository, new TransactionSet(pendingTransactions), (repository, tx) -> transactionExecutorFactory.newInstance(tx, 0, bestBlock.getCoinbase(), repository, createFakePendingBlock(bestBlock), 0));
+ return new PendingState(currentRepository, new TransactionSet(pendingTransactions, signatureCache), (repository, tx) -> transactionExecutorFactory.newInstance(tx, 0, bestBlock.getCoinbase(), repository, createFakePendingBlock(bestBlock), 0), signatureCache);
}
private RepositorySnapshot getCurrentRepository() {
@@ -215,7 +217,7 @@ public synchronized List addTransactions(final List tx
private Optional getQueuedSuccessor(Transaction tx) {
BigInteger next = tx.getNonceAsInteger().add(BigInteger.ONE);
- List txsaccount = this.queuedTransactions.getTransactionsWithSender(tx.getSender());
+ List txsaccount = this.queuedTransactions.getTransactionsWithSender(tx.getSender(signatureCache));
if (txsaccount == null) {
return Optional.empty();
@@ -243,7 +245,7 @@ private TransactionPoolAddResult internalAddTransaction(final Transaction tx) {
Keccak256 hash = tx.getHash();
logger.trace("add transaction {} {}", toBI(tx.getNonce()), tx.getHash());
- Optional replacedTx = pendingTransactions.getTransactionsWithSender(tx.getSender()).stream().filter(t -> t.getNonceAsInteger().equals(tx.getNonceAsInteger())).findFirst();
+ Optional replacedTx = pendingTransactions.getTransactionsWithSender(tx.getSender(signatureCache)).stream().filter(t -> t.getNonceAsInteger().equals(tx.getNonceAsInteger())).findFirst();
if (replacedTx.isPresent() && !isBumpingGasPriceForSameNonceTx(tx, replacedTx.get())) {
return TransactionPoolAddResult.withError("gas price not enough to bump transaction");
}
@@ -253,7 +255,7 @@ private TransactionPoolAddResult internalAddTransaction(final Transaction tx) {
final long timestampSeconds = this.getCurrentTimeInSeconds();
transactionTimes.put(hash, timestampSeconds);
- BigInteger currentNonce = getPendingState(currentRepository).getNonce(tx.getSender());
+ BigInteger currentNonce = getPendingState(currentRepository).getNonce(tx.getSender(signatureCache));
BigInteger txNonce = tx.getNonceAsInteger();
if (txNonce.compareTo(currentNonce) > 0) {
this.addQueuedTransaction(tx);
@@ -454,8 +456,7 @@ private Block createFakePendingBlock(Block best) {
}
private TransactionValidationResult shouldAcceptTx(Transaction tx, RepositorySnapshot currentRepository) {
- AccountState state = currentRepository.getAccountState(tx.getSender(signatureCache));
- return validator.isValid(tx, bestBlock, state);
+ return validator.isValid(tx, bestBlock, currentRepository.getAccountState(tx.getSender(signatureCache)));
}
/**
@@ -464,7 +465,7 @@ private TransactionValidationResult shouldAcceptTx(Transaction tx, RepositorySna
* @return whether the sender balance is enough to pay for all pending transactions + newTx
*/
private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, RepositorySnapshot currentRepository) {
- List transactions = pendingTransactions.getTransactionsWithSender(newTx.getSender());
+ List transactions = pendingTransactions.getTransactionsWithSender(newTx.getSender(signatureCache));
Coin accumTxCost = Coin.ZERO;
for (Transaction t : transactions) {
@@ -472,7 +473,7 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos
}
Coin costWithNewTx = accumTxCost.add(getTxBaseCost(newTx));
- return costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender())) <= 0;
+ return costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0;
}
private Coin getTxBaseCost(Transaction tx) {
@@ -486,7 +487,7 @@ private Coin getTxBaseCost(Transaction tx) {
}
private long getTransactionCost(Transaction tx, long number) {
- return tx.transactionCost(config.getNetworkConstants(), config.getActivationConfig().forBlock(number));
+ return tx.transactionCost(config.getNetworkConstants(), config.getActivationConfig().forBlock(number), signatureCache);
}
}
diff --git a/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java b/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java
index d887562334a..42b895dd20c 100644
--- a/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java
+++ b/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java
@@ -71,6 +71,8 @@ public class BlockToMineBuilder {
private final ForkDetectionDataCalculator forkDetectionDataCalculator;
+ private final SignatureCache signatureCache;
+
public BlockToMineBuilder(
ActivationConfig activationConfig,
MiningConfig miningConfig,
@@ -85,7 +87,8 @@ public BlockToMineBuilder(
BlockFactory blockFactory,
BlockExecutor blockExecutor,
MinimumGasPriceCalculator minimumGasPriceCalculator,
- MinerUtils minerUtils) {
+ MinerUtils minerUtils,
+ SignatureCache signatureCache) {
this.activationConfig = Objects.requireNonNull(activationConfig);
this.miningConfig = Objects.requireNonNull(miningConfig);
this.repositoryLocator = Objects.requireNonNull(repositoryLocator);
@@ -100,6 +103,7 @@ public BlockToMineBuilder(
this.executor = blockExecutor;
this.minimumGasPriceCalculator = minimumGasPriceCalculator;
this.minerUtils = minerUtils;
+ this.signatureCache = signatureCache;
}
/**
@@ -157,7 +161,7 @@ private List getUnclesHeaders(BlockHeader newBlockParentHeader) {
private List getTransactions(List txsToRemove, BlockHeader parentHeader, Coin minGasPrice) {
logger.debug("getting transactions from pending state");
- List txs = minerUtils.getAllTransactions(transactionPool);
+ List txs = minerUtils.getAllTransactions(transactionPool, signatureCache);
logger.debug("{} transaction(s) collected from pending state", txs.size());
final long blockNumber = parentHeader.getNumber() + 1;
@@ -170,7 +174,7 @@ private List getTransactions(List txsToRemove, BlockHe
final boolean isRskip252Enabled = activationConfig.isActive(ConsensusRule.RSKIP252, blockNumber);
- return minerUtils.filterTransactions(txsToRemove, txs, accountNonces, originalRepo, minGasPrice, isRskip252Enabled);
+ return minerUtils.filterTransactions(txsToRemove, txs, accountNonces, originalRepo, minGasPrice, isRskip252Enabled, signatureCache);
}
private void removePendingTransactions(List transactions) {
diff --git a/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java b/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java
index ca2248f8b54..30f7fd0be8e 100644
--- a/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java
+++ b/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.mine;
import co.rsk.bitcoinj.core.BtcTransaction;
@@ -32,6 +31,7 @@
import org.bouncycastle.util.Arrays;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ConsensusRule;
+import org.ethereum.core.SignatureCache;
import org.ethereum.core.Transaction;
import org.ethereum.core.TransactionPool;
import org.slf4j.Logger;
@@ -48,7 +48,6 @@
import java.util.function.Function;
public class MinerUtils {
-
private static final Logger logger = LoggerFactory.getLogger("minerserver");
public static co.rsk.bitcoinj.core.BtcTransaction getBitcoinMergedMiningCoinbaseTransaction(co.rsk.bitcoinj.core.NetworkParameters params, MinerWork work) {
@@ -163,21 +162,21 @@ public static byte[] buildMerkleProof(
}
}
- public List getAllTransactions(TransactionPool transactionPool) {
+ public List getAllTransactions(TransactionPool transactionPool, SignatureCache signatureCache) {
List txs = transactionPool.getPendingTransactions();
- return PendingState.sortByPriceTakingIntoAccountSenderAndNonce(txs);
+ return PendingState.sortByPriceTakingIntoAccountSenderAndNonce(txs, signatureCache);
}
- public List filterTransactions(List txsToRemove, List txs, Map accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice, boolean isRskip252Enabled) {
+ public List filterTransactions(List txsToRemove, List txs, Map accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice, boolean isRskip252Enabled, SignatureCache signatureCache) {
List txsResult = new ArrayList<>();
for (org.ethereum.core.Transaction tx : txs) {
try {
Keccak256 hash = tx.getHash();
Coin txValue = tx.getValue();
BigInteger txNonce = new BigInteger(1, tx.getNonce());
- RskAddress txSender = tx.getSender();
+ RskAddress txSender = tx.getSender(signatureCache);
logger.debug("Examining tx={} sender: {} value: {} nonce: {}", hash, txSender, txValue, txNonce);
BigInteger expectedNonce;
diff --git a/rskj-core/src/main/java/co/rsk/net/handler/TxPendingValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/TxPendingValidator.java
index c01e9b8bb4f..74ab6e38636 100644
--- a/rskj-core/src/main/java/co/rsk/net/handler/TxPendingValidator.java
+++ b/rskj-core/src/main/java/co/rsk/net/handler/TxPendingValidator.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.net.handler;
import co.rsk.core.Coin;
@@ -26,6 +25,7 @@
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
+import org.ethereum.core.SignatureCache;
import org.ethereum.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,9 +50,12 @@ public class TxPendingValidator {
private final Constants constants;
private final ActivationConfig activationConfig;
- public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots) {
+ private final SignatureCache signatureCache;
+
+ public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache) {
this.constants = constants;
this.activationConfig = activationConfig;
+ this.signatureCache = signatureCache;
validatorSteps.add(new TxNotNullValidator());
validatorSteps.add(new TxValidatorNotRemascTxValidator());
@@ -61,7 +64,7 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig
validatorSteps.add(new TxValidatorNonceRangeValidator(accountSlots));
validatorSteps.add(new TxValidatorAccountBalanceValidator());
validatorSteps.add(new TxValidatorMinimuGasPriceValidator());
- validatorSteps.add(new TxValidatorIntrinsicGasLimitValidator(constants, activationConfig));
+ validatorSteps.add(new TxValidatorIntrinsicGasLimitValidator(constants, activationConfig, signatureCache));
validatorSteps.add(new TxValidatorMaximumGasPriceValidator(activationConfig));
}
@@ -69,10 +72,12 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock,
BigInteger blockGasLimit = BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit());
Coin minimumGasPrice = executionBlock.getMinimumGasPrice();
long bestBlockNumber = executionBlock.getNumber();
- long basicTxCost = tx.transactionCost(constants, activationConfig.forBlock(bestBlockNumber));
+ long basicTxCost = tx.transactionCost(constants, activationConfig.forBlock(bestBlockNumber), signatureCache);
if (state == null && basicTxCost != 0) {
- logger.trace("[tx={}, sender={}] account doesn't exist", tx.getHash(), tx.getSender());
+ if (logger.isTraceEnabled()) {
+ logger.trace("[tx={}, sender={}] account doesn't exist", tx.getHash(), tx.getSender(signatureCache));
+ }
return TransactionValidationResult.withError("the sender account doesn't exist");
}
diff --git a/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuotaChecker.java b/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuotaChecker.java
index 581c3791587..bff9690850d 100644
--- a/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuotaChecker.java
+++ b/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuotaChecker.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.net.handler.quota;
import co.rsk.core.RskAddress;
@@ -24,6 +23,7 @@
import co.rsk.util.MaxSizeHashMap;
import co.rsk.util.TimeProvider;
import org.ethereum.core.Block;
+import org.ethereum.core.SignatureCache;
import org.ethereum.core.Transaction;
import org.ethereum.listener.GasPriceTracker;
import org.slf4j.Logger;
@@ -55,10 +55,13 @@ public class TxQuotaChecker {
private final TimeProvider timeProvider;
- public TxQuotaChecker(TimeProvider timeProvider) {
+ private final SignatureCache signatureCache;
+
+ public TxQuotaChecker(TimeProvider timeProvider, SignatureCache signatureCache) {
this.accountQuotas = new MaxSizeHashMap<>(MAX_QUOTAS_SIZE, true);
this.timeProvider = timeProvider;
this.lastBlockGasLimit = UNKNOWN_LAST_BLOCK_GAS_LIMIT;
+ this.signatureCache = signatureCache;
}
/**
@@ -118,7 +121,7 @@ private void updateReceiverQuotaIfRequired(Transaction newTx, CurrentContext cur
}
private boolean isFirstTxFromSender(Transaction newTx, CurrentContext currentContext) {
- RskAddress senderAddress = newTx.getSender();
+ RskAddress senderAddress = newTx.getSender(signatureCache);
TxQuota quotaForSender = this.accountQuotas.get(senderAddress);
long accountNonce = currentContext.state.getNonce(senderAddress).longValue();
@@ -176,7 +179,7 @@ private TxQuota updateQuota(Transaction newTx, boolean isTxSource, CurrentContex
long maxGasPerSecond = getMaxGasPerSecond(blockGasLimit.longValue());
long maxQuota = getMaxQuota(maxGasPerSecond);
- RskAddress address = isTxSource ? newTx.getSender() : newTx.getReceiveAddress();
+ RskAddress address = isTxSource ? newTx.getSender(signatureCache) : newTx.getReceiveAddress();
TxQuota quotaForAddress = this.accountQuotas.get(address);
if (quotaForAddress == null) {
@@ -206,7 +209,7 @@ private long getMaxQuota(long maxGasPerSecond) {
}
private double calculateConsumedVirtualGas(Transaction newTx, @Nullable Transaction replacedTx, CurrentContext currentContext) {
- long accountNonce = currentContext.state.getNonce(newTx.getSender()).longValue();
+ long accountNonce = currentContext.state.getNonce(newTx.getSender(signatureCache)).longValue();
long blockGasLimit = currentContext.bestBlock.getGasLimitAsInteger().longValue();
long blockMinGasPrice = currentContext.bestBlock.getMinimumGasPrice().asBigInteger().longValue();
diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidator.java
index eab810cc340..6ac70394496 100644
--- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidator.java
+++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidator.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.net.handler.txvalidator;
import co.rsk.core.Coin;
@@ -35,15 +34,20 @@ public class TxValidatorIntrinsicGasLimitValidator implements TxValidatorStep {
private final Constants constants;
private final ActivationConfig activationConfig;
+ private final SignatureCache signatureCache;
- public TxValidatorIntrinsicGasLimitValidator(Constants constants, ActivationConfig activationConfig) {
+ public TxValidatorIntrinsicGasLimitValidator(
+ Constants constants,
+ ActivationConfig activationConfig,
+ SignatureCache signatureCache) {
this.constants = constants;
this.activationConfig = activationConfig;
+ this.signatureCache = signatureCache;
}
@Override
public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) {
- if (BigInteger.valueOf(tx.transactionCost(constants, activationConfig.forBlock(bestBlockNumber))).compareTo(tx.getGasLimitAsInteger()) <= 0) {
+ if (BigInteger.valueOf(tx.transactionCost(constants, activationConfig.forBlock(bestBlockNumber), signatureCache)).compareTo(tx.getGasLimitAsInteger()) <= 0) {
return TransactionValidationResult.ok();
}
diff --git a/rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java b/rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java
index 4d6e537c14e..3ef1101b0ce 100644
--- a/rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java
+++ b/rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java
@@ -15,10 +15,10 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.peg;
import co.rsk.core.RskAddress;
+import org.ethereum.core.SignatureCache;
import org.ethereum.core.Transaction;
import org.ethereum.crypto.ECKey;
@@ -48,8 +48,8 @@ public boolean isAuthorized(RskAddress sender) {
.anyMatch(address -> Arrays.equals(address, sender.getBytes()));
}
- public boolean isAuthorized(Transaction tx) {
- return isAuthorized(tx.getSender());
+ public boolean isAuthorized(Transaction tx, SignatureCache signatureCache) {
+ return isAuthorized(tx.getSender(signatureCache));
}
public int getNumberOfAuthorizedKeys() {
diff --git a/rskj-core/src/main/java/co/rsk/peg/Bridge.java b/rskj-core/src/main/java/co/rsk/peg/Bridge.java
index ba7cd5003fa..26cfa216238 100644
--- a/rskj-core/src/main/java/co/rsk/peg/Bridge.java
+++ b/rskj-core/src/main/java/co/rsk/peg/Bridge.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.peg;
import co.rsk.bitcoinj.core.*;
@@ -35,10 +34,7 @@
import org.ethereum.config.Constants;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ConsensusRule;
-import org.ethereum.core.Block;
-import org.ethereum.core.CallTransaction;
-import org.ethereum.core.Repository;
-import org.ethereum.core.Transaction;
+import org.ethereum.core.*;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ReceiptStore;
import org.ethereum.util.ByteUtil;
@@ -228,20 +224,23 @@ public class Bridge extends PrecompiledContracts.PrecompiledContract {
private final BiFunction, Integer, MerkleBranch> merkleBranchFactory;
+ private final SignatureCache signatureCache;
+
public Bridge(RskAddress contractAddress, Constants constants, ActivationConfig activationConfig,
- BridgeSupportFactory bridgeSupportFactory) {
- this(contractAddress, constants, activationConfig, bridgeSupportFactory, MerkleBranch::new);
+ BridgeSupportFactory bridgeSupportFactory, SignatureCache signatureCache) {
+ this(contractAddress, constants, activationConfig, bridgeSupportFactory, MerkleBranch::new, signatureCache);
}
@VisibleForTesting
Bridge(RskAddress contractAddress, Constants constants, ActivationConfig activationConfig,
- BridgeSupportFactory bridgeSupportFactory, BiFunction, Integer, MerkleBranch> merkleBranchFactory) {
+ BridgeSupportFactory bridgeSupportFactory, BiFunction, Integer, MerkleBranch> merkleBranchFactory, SignatureCache signatureCache) {
this.bridgeSupportFactory = bridgeSupportFactory;
this.contractAddress = contractAddress;
this.constants = constants;
this.bridgeConstants = constants.getBridgeConstants();
this.activationConfig = activationConfig;
this.merkleBranchFactory = merkleBranchFactory;
+ this.signatureCache = signatureCache;
}
@Override
@@ -251,7 +250,7 @@ public long getGasForData(byte[] data) {
throw new NullPointerException();
}
- if (BridgeUtils.isFreeBridgeTx(rskTx, constants, activations)) {
+ if (BridgeUtils.isFreeBridgeTx(rskTx, constants, activations, signatureCache)) {
return 0;
}
@@ -1235,8 +1234,8 @@ public static BridgeMethods.BridgeMethodExecutor activeAndRetiringFederationOnly
return (self, args) -> {
Federation retiringFederation = self.bridgeSupport.getRetiringFederation();
- if (!BridgeUtils.isFromFederateMember(self.rskTx, self.bridgeSupport.getActiveFederation())
- && (retiringFederation == null || !BridgeUtils.isFromFederateMember(self.rskTx, retiringFederation))) {
+ if (!BridgeUtils.isFromFederateMember(self.rskTx, self.bridgeSupport.getActiveFederation(), self.signatureCache)
+ && (retiringFederation == null || !BridgeUtils.isFromFederateMember(self.rskTx, retiringFederation, self.signatureCache))) {
String errorMessage = String.format("Sender is not part of the active or retiring federations, so he is not enabled to call the function '%s'",funcName);
logger.warn(errorMessage);
throw new VMException(errorMessage);
diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
index 71ef75c2e3d..f4b8e20aec2 100644
--- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
+++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-
package co.rsk.peg;
import co.rsk.bitcoinj.core.Address;
@@ -87,6 +86,7 @@
import org.ethereum.config.blockchain.upgrades.ConsensusRule;
import org.ethereum.core.Block;
import org.ethereum.core.Repository;
+import org.ethereum.core.SignatureCache;
import org.ethereum.core.Transaction;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
@@ -172,6 +172,8 @@ public class BridgeSupport {
private final org.ethereum.core.Block rskExecutionBlock;
private final ActivationConfig.ForBlock activations;
+ private final SignatureCache signatureCache;
+
protected enum TxType {
PEGIN,
PEGOUT,
@@ -190,7 +192,8 @@ public BridgeSupport(
Context btcContext,
FederationSupport federationSupport,
BtcBlockStoreWithCache.Factory btcBlockStoreFactory,
- ActivationConfig.ForBlock activations) {
+ ActivationConfig.ForBlock activations,
+ SignatureCache signatureCache) {
this.rskRepository = repository;
this.provider = provider;
this.rskExecutionBlock = executionBlock;
@@ -202,6 +205,7 @@ public BridgeSupport(
this.federationSupport = federationSupport;
this.btcBlockStoreFactory = btcBlockStoreFactory;
this.activations = activations;
+ this.signatureCache = signatureCache;
}
public List getSubtraces() {
@@ -774,7 +778,7 @@ private void saveNewUTXOs(BtcTransaction btcTx) throws IOException {
*/
public void releaseBtc(Transaction rskTx) throws IOException {
Coin value = rskTx.getValue().toBitcoin();
- final RskAddress senderAddress = rskTx.getSender();
+ final RskAddress senderAddress = rskTx.getSender(signatureCache);
//as we can't send btc from contracts we want to send them back to the senderAddressStr
if (BridgeUtils.isContractTx(rskTx)) {
logger.trace("Contract {} tried to release funds. Release is just allowed from standard accounts.", rskTx);
@@ -864,7 +868,7 @@ private void requestRelease(Address destinationAddress, Coin value, Transaction
if (activations.isActive(ConsensusRule.RSKIP185)) {
refundAndEmitRejectEvent(
value,
- rskTx.getSender(),
+ rskTx.getSender(signatureCache),
optionalRejectedPegoutReason.get()
);
}
@@ -876,7 +880,7 @@ private void requestRelease(Address destinationAddress, Coin value, Transaction
}
if (activations.isActive(ConsensusRule.RSKIP185)) {
- eventLogger.logReleaseBtcRequestReceived(rskTx.getSender().toHexString(), destinationAddress, value);
+ eventLogger.logReleaseBtcRequestReceived(rskTx.getSender(signatureCache).toHexString(), destinationAddress, value);
}
logger.info("releaseBtc successful to {}. Tx {}. Value {}.", destinationAddress, rskTx, value);
}
@@ -2104,7 +2108,7 @@ public Integer voteFederationChange(Transaction tx, ABICallSpec callSpec) throws
AddressBasedAuthorizer authorizer = bridgeConstants.getFederationChangeAuthorizer();
// Must be authorized to vote (checking for signature)
- if (!authorizer.isAuthorized(tx)) {
+ if (!authorizer.isAuthorized(tx, signatureCache)) {
return FEDERATION_CHANGE_GENERIC_ERROR_CODE;
}
@@ -2124,7 +2128,7 @@ public Integer voteFederationChange(Transaction tx, ABICallSpec callSpec) throws
ABICallElection election = provider.getFederationElection(authorizer);
// Register the vote. It is expected to succeed, since all previous checks succeeded
- if (!election.vote(callSpec, tx.getSender())) {
+ if (!election.vote(callSpec, tx.getSender(signatureCache))) {
logger.warn("Unexpected federation change vote failure");
return FEDERATION_CHANGE_GENERIC_ERROR_CODE;
}
@@ -2369,7 +2373,7 @@ private Integer addLockWhitelistAddress(Transaction tx, LockWhitelistEntry entry
private boolean isLockWhitelistChangeAuthorized(Transaction tx) {
AddressBasedAuthorizer authorizer = bridgeConstants.getLockWhitelistChangeAuthorizer();
- return authorizer.isAuthorized(tx);
+ return authorizer.isAuthorized(tx, signatureCache);
}
/**
@@ -2421,7 +2425,7 @@ public Coin getMinimumPeginTxValue() {
*/
public Integer voteFeePerKbChange(Transaction tx, Coin feePerKb) {
AddressBasedAuthorizer authorizer = bridgeConstants.getFeePerKbChangeAuthorizer();
- if (!authorizer.isAuthorized(tx)) {
+ if (!authorizer.isAuthorized(tx, signatureCache)) {
return FEE_PER_KB_GENERIC_ERROR_CODE;
}
@@ -2435,7 +2439,7 @@ public Integer voteFeePerKbChange(Transaction tx, Coin feePerKb) {
ABICallElection feePerKbElection = provider.getFeePerKbElection(authorizer);
ABICallSpec feeVote = new ABICallSpec("setFeePerKb", new byte[][]{BridgeSerializationUtils.serializeCoin(feePerKb)});
- boolean successfulVote = feePerKbElection.vote(feeVote, tx.getSender());
+ boolean successfulVote = feePerKbElection.vote(feeVote, tx.getSender(signatureCache));
if (!successfulVote) {
return -1;
}
@@ -2517,8 +2521,8 @@ public Optional