From 0601629ee9640a8bbd49e40c771e2b3c2f29577b Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Tue, 26 Mar 2024 17:11:54 -0400 Subject: [PATCH 01/21] Implmentation of EthSwap mechanism --- .../co/rsk/core/bc/TransactionPoolImpl.java | 9 +- .../main/java/co/rsk/util/ContractUtil.java | 96 ++++++++ .../java/org/ethereum/config/Constants.java | 36 ++- .../ethereum/core/TransactionExecutor.java | 43 +++- .../java/co/rsk/util/ContractUtilTest.java | 83 +++++++ .../src/test/resources/dsl/etherswap.txt | 220 ++++++++++++++++++ 6 files changed, 470 insertions(+), 17 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/util/ContractUtil.java create mode 100644 rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java create mode 100644 rskj-core/src/test/resources/dsl/etherswap.txt 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 967b8d49fd3..62205b00ab8 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 @@ -26,6 +26,7 @@ import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.TxPendingValidator; import co.rsk.net.handler.quota.TxQuotaChecker; +import co.rsk.util.ContractUtil; import com.google.common.annotations.VisibleForTesting; import org.ethereum.core.*; import org.ethereum.db.BlockStore; @@ -477,7 +478,13 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos } Coin costWithNewTx = accumTxCost.add(getTxBaseCost(newTx)); - return costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0; + boolean senderCanPay = costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0; + + if(senderCanPay) { + return true; + } + + return ContractUtil.isClaimTxAndValid(newTx, currentRepository, costWithNewTx, config.getNetworkConstants(), signatureCache); } private Coin getTxBaseCost(Transaction tx) { diff --git a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java new file mode 100644 index 00000000000..efcdc9cf7e8 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java @@ -0,0 +1,96 @@ +package co.rsk.util; + +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.db.RepositorySnapshot; +import org.ethereum.config.Constants; +import org.ethereum.core.CallTransaction; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; +import org.ethereum.crypto.HashUtil; +import org.ethereum.solidity.SolidityType; +import org.ethereum.util.ByteUtil; +import org.ethereum.vm.DataWord; + +import java.math.BigInteger; +import java.util.Arrays; + +public class ContractUtil { + public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatureCache) { + CallTransaction.Invocation invocation = getTxInvocation(newTx); + + // Get arguments from the invocation object + byte[] preimage = (byte[]) invocation.args[0]; + // Encode preimage with sha256, this is to imitate the encoding done in teh claim function before calling hashValues + byte[] preimageHash = HashUtil.sha256(preimage); + BigInteger amount = (BigInteger) invocation.args[1]; + DataWord refundAddress = (DataWord) invocation.args[2]; + BigInteger timeLock = (BigInteger) invocation.args[3]; + + + // Remove the leading zeroes from the arguments bytes and merge them + byte[] argumentsBytes = encodePacked( + preimageHash, + amount, + newTx.getSender(signatureCache), + new RskAddress(ByteUtil.toHexString(refundAddress.getLast20Bytes())), + timeLock + ); + + return HashUtil.keccak256(argumentsBytes); + } + + public static byte[] encodePacked(Object...arguments) { + byte[] encodedArguments = new byte[]{}; + + for(Object arg: arguments) { + byte[] encodedArg = new byte[]{}; + if(arg instanceof byte[]) { + SolidityType bytes32Type = SolidityType.getType(SolidityType.BYTES32); + encodedArg = bytes32Type.encode(arg); + } else if(arg instanceof RskAddress) { + SolidityType addressType = SolidityType.getType(SolidityType.ADDRESS); + byte[] encodedAddress = addressType.encode(((RskAddress) arg).toHexString()); + encodedArg = org.bouncycastle.util.Arrays.copyOfRange(encodedAddress, 12, encodedAddress.length); + } else if(arg instanceof BigInteger) { + SolidityType uint256Type = SolidityType.getType(SolidityType.UINT); + encodedArg = uint256Type.encode(arg); + } + + encodedArguments = ByteUtil.merge(encodedArguments, encodedArg); + } + + return encodedArguments; + } + + public static CallTransaction.Invocation getTxInvocation(Transaction newTx) { + String abi = "[{\"constant\":false,\"inputs\":[{\"name\":\"preimage\",\"type\":\"bytes32\"}, {\"name\":\"amount\",\"type\":\"uint256\"}, {\"name\":\"address\",\"type\":\"address\"}, {\"name\":\"timelock\",\"type\":\"uint256\"}],\"name\":\"claim\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]"; + CallTransaction.Contract contract = new CallTransaction.Contract(abi); + return contract.parseInvocation(newTx.getData()); + } + + public static boolean isClaimTxAndValid(Transaction newTx, + RepositorySnapshot currentRepository, + Coin txCost, + Constants constants, + SignatureCache signatureCache) { + byte[] functionSelector = Arrays.copyOfRange(newTx.getData(), 0, 4); + if(newTx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) + && Arrays.equals(functionSelector, Constants.CLAIM_FUNCTION_SIGNATURE)) { + + byte[] swapHash = calculateSwapHash(newTx, signatureCache); + DataWord swapRecord = currentRepository.getStorageValue(newTx.getReceiveAddress(), DataWord.valueOf(swapHash)); + + if(swapRecord != null){ + CallTransaction.Invocation invocation = getTxInvocation(newTx); + BigInteger amount = (BigInteger) invocation.args[1]; + Coin balanceWithClaim = currentRepository.getBalance(newTx.getSender(signatureCache)) + .add(Coin.valueOf(amount.longValue())); + + return txCost.compareTo(balanceWithClaim) <= 0; + } + } + + return false; + } +} diff --git a/rskj-core/src/main/java/org/ethereum/config/Constants.java b/rskj-core/src/main/java/org/ethereum/config/Constants.java index 906c468e327..2a7b9a1049d 100644 --- a/rskj-core/src/main/java/org/ethereum/config/Constants.java +++ b/rskj-core/src/main/java/org/ethereum/config/Constants.java @@ -25,6 +25,7 @@ import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.CallTransaction; import java.math.BigDecimal; import java.math.BigInteger; @@ -45,6 +46,11 @@ public class Constants { private static final BigInteger SECP256K1N = new BigInteger("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16); private static final BigInteger TRANSACTION_GAS_CAP = BigDecimal.valueOf(Math.pow(2, 60)).toBigInteger(); private static final BigInteger RSKIP156_DIF_BOUND_DIVISOR = BigInteger.valueOf(400); + public static final byte[] CLAIM_FUNCTION_SIGNATURE = CallTransaction.Function.fromSignature( + "claim", + new String[]{"bytes32", "uint256", "address", "uint256"}, + new String[]{} + ).encodeSignature(); private static final long DEFAULT_MAX_TIMESTAMPS_DIFF_IN_SECS = 5L * 60; // 5 mins private static final long TESTNET_MAX_TIMESTAMPS_DIFF_IN_SECS = 120L * 60; // 120 mins @@ -59,6 +65,7 @@ public class Constants { private final int newBlockMaxSecondsInTheFuture; public final BridgeConstants bridgeConstants; private final ActivationConfig activationConfig; + private final String etherSwapContractAddress; public Constants( byte chainId, @@ -70,7 +77,8 @@ public Constants( int newBlockMaxSecondsInTheFuture, BridgeConstants bridgeConstants, ActivationConfig activationConfig, - BlockDifficulty minimumDifficultyForRskip290) { + BlockDifficulty minimumDifficultyForRskip290, + String etherSwapContractAddress) { this.chainId = chainId; this.seedCowAccounts = seedCowAccounts; this.durationLimit = durationLimit; @@ -81,6 +89,7 @@ public Constants( this.bridgeConstants = bridgeConstants; this.activationConfig = activationConfig; this.minimumDifficultyForRskip290 = minimumDifficultyForRskip290; + this.etherSwapContractAddress = etherSwapContractAddress; } public Constants( @@ -92,7 +101,8 @@ public Constants( BigInteger difficultyBoundDivisor, int newBlockMaxSecondsInTheFuture, BridgeConstants bridgeConstants, - BlockDifficulty minimumDifficultyForRskip290) { + BlockDifficulty minimumDifficultyForRskip290, + String etherSwapContractAddress) { this(chainId, seedCowAccounts, durationLimit, @@ -102,7 +112,8 @@ public Constants( newBlockMaxSecondsInTheFuture, bridgeConstants, null, - minimumDifficultyForRskip290 + minimumDifficultyForRskip290, + etherSwapContractAddress ); } @@ -225,6 +236,10 @@ public static int getMaxBitcoinMergedMiningMerkleProofLength() { return 960; } + public String getEtherSwapContractAddress() { + return etherSwapContractAddress; + } + public static Constants mainnet() { return new Constants( MAINNET_CHAIN_ID, @@ -235,7 +250,8 @@ public static Constants mainnet() { BigInteger.valueOf(50), 60, BridgeMainNetConstants.getInstance(), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + null ); } @@ -249,7 +265,8 @@ public static Constants devnetWithFederation(List federationPublicKeys BigInteger.valueOf(50), 540, new BridgeDevNetConstants(federationPublicKeys), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + null ); } @@ -264,7 +281,8 @@ public static Constants testnet(ActivationConfig activationConfig) { 540, BridgeTestNetConstants.getInstance(), activationConfig, - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + null ); } @@ -278,7 +296,8 @@ public static Constants regtest() { BigInteger.valueOf(2048), 0, new BridgeRegTestConstants(), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + "77045E71a7A2c50903d88e564cD72fab11e82051" ); } @@ -292,7 +311,8 @@ public static Constants regtestWithFederation(List genesisFederationPu BigInteger.valueOf(2048), 0, new BridgeRegTestConstants(genesisFederationPublicKeys), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + null ); } } diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index b0883a63821..bad58151dac 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -26,6 +26,7 @@ import co.rsk.metrics.profilers.ProfilerFactory; import co.rsk.panic.PanicProcessor; import co.rsk.rpc.modules.trace.ProgramSubtrace; +import co.rsk.util.ContractUtil; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; @@ -99,6 +100,7 @@ public class TransactionExecutor { private final SignatureCache signatureCache; private boolean localCall = false; + private boolean txWasPaid = false; public TransactionExecutor( Constants constants, ActivationConfig activationConfig, Transaction tx, int txindex, RskAddress coinbase, @@ -167,17 +169,11 @@ private boolean init() { } - Coin totalCost = tx.getValue(); - - if (basicTxCost > 0 ) { - // add gas cost only for priced transactions - Coin txGasCost = tx.getGasPrice().multiply(BigInteger.valueOf(txGasLimit)); - totalCost = totalCost.add(txGasCost); - } + Coin totalCost = getTxTotalCost(); Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); - if (!isCovers(senderBalance, totalCost)) { + if (!isCovers(senderBalance, totalCost) && !ContractUtil.isClaimTxAndValid(tx, track, totalCost,constants, signatureCache)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); @@ -271,6 +267,14 @@ private void execute() { track.increaseNonce(tx.getSender(signatureCache)); + Coin totalCost = getTxTotalCost(); + Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); + + if(isCovers(senderBalance, totalCost)) { + payTransaction(); + txWasPaid = true; + } + long txGasLimit = GasCost.toGas(tx.getGasLimit()); Coin txGasCost = tx.getGasPrice().multiply(BigInteger.valueOf(txGasLimit)); track.addBalance(tx.getSender(signatureCache), txGasCost.negate()); @@ -502,6 +506,9 @@ public TransactionReceipt getReceipt() { } private void finalization() { + if(!txWasPaid) { + payTransaction(); + } // RSK if local call gas balances must not be changed if (localCall) { // there's no need to save any change @@ -682,4 +689,24 @@ public long getGasUsed() { } public Coin getPaidFees() { return paidFees; } + + private void payTransaction() { + long txGasLimit = GasCost.toGas(tx.getGasLimit()); + Coin txGasCost = tx.getGasPrice().multiply(BigInteger.valueOf(txGasLimit)); + track.addBalance(tx.getSender(signatureCache), txGasCost.negate()); + + logger.trace("Paying: txGasCost: [{}], gasPrice: [{}], gasLimit: [{}]", txGasCost, tx.getGasPrice(), txGasLimit); + } + + private Coin getTxTotalCost() { + long txGasLimit = GasCost.toGas(tx.getGasLimit()); + Coin totalCost = tx.getValue(); + + if (basicTxCost > 0 ) { + Coin txGasCost = tx.getGasPrice().multiply(BigInteger.valueOf(txGasLimit)); + totalCost = totalCost.add(txGasCost); + } + + return totalCost; + } } diff --git a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java new file mode 100644 index 00000000000..462fd68014a --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java @@ -0,0 +1,83 @@ +package co.rsk.util; + +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.db.RepositorySnapshot; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.config.Constants; +import org.ethereum.core.CallTransaction; +import org.ethereum.core.ReceivedTxSignatureCache; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; +import org.ethereum.util.ByteUtil; +import org.ethereum.vm.DataWord; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import static org.junit.jupiter.api.Assertions.*; + +public class ContractUtilTest { + + private final CallTransaction.Function CLAIM_FUNCTION = CallTransaction.Function.fromSignature( + "claim", + new String[]{"bytes32", "uint256", "address", "uint256"}, + new String[]{} + ); + + private final Constants testConstans = Constants.regtest(); + + private final String EXPECTED_HASH = "0x3dc21e0a710489c951f29205f9961b2c311d48fdf5a35545469d7b43e88f7624"; + + @Test + public void testCalculateSwapHash() { + Transaction mockedTx = mockTx(); + + byte[] result = ContractUtil.calculateSwapHash(mockedTx, new ReceivedTxSignatureCache()); + + assertEquals(EXPECTED_HASH, HexUtils.toJsonHex(result)); + } + + @Test + public void testIsClaimTxAndValid() { + Transaction mockedTx = mockTx(); + Coin txCost = Coin.valueOf(5); + SignatureCache signatureCache = new ReceivedTxSignatureCache(); + RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + when(mockedRepository.getStorageValue(mockedTx.getReceiveAddress(), DataWord.valueOf(HexUtils.stringHexToByteArray(EXPECTED_HASH)))) + .thenReturn(DataWord.valueOf(1)); + when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); + + boolean result = ContractUtil.isClaimTxAndValid(mockedTx, mockedRepository, txCost, testConstans, signatureCache); + + assertTrue(result); + } + + private Transaction mockTx() { + byte[] senderBytes = Hex.decode("0000000000000000000000000000000001000001"); + RskAddress claimAddress = new RskAddress(senderBytes); + + byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); + byte[] callData = CLAIM_FUNCTION.encode(preimage, + 10, + "0000000000000000000000000000000001000002", + 1000000); + + Transaction mockedTx = mock(Transaction.class); + + when(mockedTx.getSender(any(SignatureCache.class))).thenReturn(claimAddress); + when(mockedTx.getNonce()).thenReturn(ByteUtil.cloneBytes(BigInteger.ZERO.toByteArray())); + when(mockedTx.getGasPrice()).thenReturn(Coin.valueOf(1)); + when(mockedTx.getGasLimit()).thenReturn(BigInteger.valueOf(1).toByteArray()); + when(mockedTx.getReceiveAddress()).thenReturn(new RskAddress(testConstans.getEtherSwapContractAddress())); + when(mockedTx.getData()).thenReturn(callData); + when(mockedTx.getValue()).thenReturn(Coin.ZERO); + + return mockedTx; + } +} diff --git a/rskj-core/src/test/resources/dsl/etherswap.txt b/rskj-core/src/test/resources/dsl/etherswap.txt new file mode 100644 index 00000000000..e826849670a --- /dev/null +++ b/rskj-core/src/test/resources/dsl/etherswap.txt @@ -0,0 +1,220 @@ +comment + +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import "./TransferHelper.sol"; + +contract EtherSwap { + uint8 constant public version = 3; + + bytes32 immutable public DOMAIN_SEPARATOR; + bytes32 immutable public TYPEHASH_REFUND; + + mapping (bytes32 => bool) public swaps; + + event Lockup( + bytes32 indexed preimageHash, + uint amount, + address claimAddress, + address indexed refundAddress, + uint timelock + ); + + event Claim(bytes32 indexed preimageHash, bytes32 preimage); + event Refund(bytes32 indexed preimageHash); + + constructor() { + DOMAIN_SEPARATOR = keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256("EtherSwap"), + keccak256("3"), + block.chainid, + address(this) + ) + ); + TYPEHASH_REFUND = keccak256( + "Refund(bytes32 preimageHash,uint256 amount,address claimAddress,uint256 timeout)" + ); + } + + function lock( + bytes32 preimageHash, + address claimAddress, + uint timelock + ) external payable { + lockEther(preimageHash, msg.value, claimAddress, timelock); + } + + function lockPrepayMinerfee( + bytes32 preimageHash, + address payable claimAddress, + uint timelock, + uint prepayAmount + ) external payable { + require(msg.value > prepayAmount, "EtherSwap: sent amount must be greater than the prepay amount"); + + lockEther(preimageHash, msg.value - prepayAmount, claimAddress, timelock); + + TransferHelper.transferEther(claimAddress, prepayAmount); + } + + function claim( + bytes32 preimage, + uint amount, + address refundAddress, + uint timelock + ) external { + claim(preimage, amount, msg.sender, refundAddress, timelock); + } + + function claim( + bytes32 preimage, + uint amount, + address claimAddress, + address refundAddress, + uint timelock + ) public { + bytes32 preimageHash = sha256(abi.encodePacked(preimage)); + + bytes32 hash = hashValues( + preimageHash, + amount, + claimAddress, + refundAddress, + timelock + ); + + checkSwapIsLocked(hash); + delete swaps[hash]; + + emit Claim(preimageHash, preimage); + + TransferHelper.transferEther(payable(claimAddress), amount); + } + + function refund( + bytes32 preimageHash, + uint amount, + address claimAddress, + uint timelock + ) external { + require(timelock <= block.number, "EtherSwap: swap has not timed out yet"); + refundInternal(preimageHash, amount, claimAddress, timelock); + } + + function refundCooperative( + bytes32 preimageHash, + uint amount, + address claimAddress, + uint timelock, + uint8 v, + bytes32 r, + bytes32 s + ) external { + address recoveredAddress = ecrecover( + keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR, + keccak256( + abi.encode( + TYPEHASH_REFUND, + preimageHash, + amount, + claimAddress, + timelock + ) + ) + ) + ), + v, + r, + s + ); + require(recoveredAddress != address(0) && recoveredAddress == claimAddress, "EtherSwap: invalid signature"); + + refundInternal(preimageHash, amount, claimAddress, timelock); + } + + function hashValues( + bytes32 preimageHash, + uint amount, + address claimAddress, + address refundAddress, + uint timelock + ) public pure returns (bytes32) { + return keccak256(abi.encodePacked( + preimageHash, + amount, + claimAddress, + refundAddress, + timelock + )); + } + + function lockEther(bytes32 preimageHash, uint amount, address claimAddress, uint timelock) private { + require(amount > 0, "EtherSwap: locked amount must not be zero"); + + bytes32 hash = hashValues( + preimageHash, + amount, + claimAddress, + msg.sender, + timelock + ); + + require(swaps[hash] == false, "EtherSwap: swap exists already"); + + swaps[hash] = true; + + emit Lockup(preimageHash, amount, claimAddress, msg.sender, timelock); + } + + function refundInternal(bytes32 preimageHash, uint amount, address claimAddress, uint timelock) private { + bytes32 hash = hashValues( + preimageHash, + amount, + claimAddress, + msg.sender, + timelock + ); + + checkSwapIsLocked(hash); + delete swaps[hash]; + + emit Refund(preimageHash); + + TransferHelper.transferEther(payable(msg.sender), amount); + } + + function checkSwapIsLocked(bytes32 hash) private view { + require(swaps[hash] == true, "EtherSwap: swap has no Ether locked in the contract"); + } +} + +end + +account_new acc1 20000000 + +# Deploy EtherSwap +transaction_build tx01 + sender acc1 + nonce 0 + receiverAddress 00 + value 0 + data 60c06040523480156200001157600080fd5b507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f0f435efbd794bc89b372127f0e96dcc927b729642a259c9b4dcbab48b107caec7f2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de46306040516020016200008d95949392919062000153565b60405160208183030381529060405280519060200120608081815250507f9e9b7110907661cf70aeef31f56954d657589e65e35455acf5737535f33a234160a08181525050620001b0565b6000819050919050565b620000ed81620000d8565b82525050565b6000819050919050565b6200010881620000f3565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200013b826200010e565b9050919050565b6200014d816200012e565b82525050565b600060a0820190506200016a6000830188620000e2565b620001796020830187620000e2565b620001886040830186620000e2565b620001976060830185620000fd565b620001a6608083018462000142565b9695505050505050565b60805160a051611591620001e4600039600081816103ae01526105240152600081816102e0015261050301526115916000f3fe60806040526004361061009c5760003560e01c80638b2f8f82116100645780638b2f8f8214610158578063a9ab4d5b14610195578063c3c37fbc146101c0578063cd413efa146101e9578063eb84e7f214610212578063fe237d451461024f5761009c565b80630899146b146100a157806335cd4ccb146100bd5780633644e515146100e657806354fd4d50146101115780636fa4ae601461013c575b600080fd5b6100bb60048036038101906100b69190610a45565b610278565b005b3480156100c957600080fd5b506100e460048036038101906100df9190610a98565b610289565b005b3480156100f257600080fd5b506100fb6102de565b6040516101089190610b0e565b60405180910390f35b34801561011d57600080fd5b50610126610302565b6040516101339190610b45565b60405180910390f35b61015660048036038101906101519190610b9e565b610307565b005b34801561016457600080fd5b5061017f600480360381019061017a9190610c05565b610370565b60405161018c9190610b0e565b60405180910390f35b3480156101a157600080fd5b506101aa6103ac565b6040516101b79190610b0e565b60405180910390f35b3480156101cc57600080fd5b506101e760048036038101906101e29190610a98565b6103d0565b005b3480156101f557600080fd5b50610210600480360381019061020b9190610c05565b6103e3565b005b34801561021e57600080fd5b5061023960048036038101906102349190610c80565b6104dd565b6040516102469190610cc8565b60405180910390f35b34801561025b57600080fd5b5061027660048036038101906102719190610d0f565b6104fd565b005b610284833484846106a3565b505050565b438111156102cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390610e34565b60405180910390fd5b6102d8848484846107e2565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600381565b803411610349576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034090610ec6565b60405180910390fd5b6103608482346103599190610f15565b85856106a3565b61036a838261085c565b50505050565b6000858585858560405160200161038b959493929190610fd3565b60405160208183030381529060405280519060200120905095945050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6103dd84843385856103e3565b50505050565b60006002866040516020016103f89190611032565b60405160208183030381529060405260405161041491906110be565b602060405180830381855afa158015610431573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061045491906110ea565b905060006104658287878787610370565b90506104708161090d565b60008082815260200190815260200160002060006101000a81549060ff0219169055817f5664142af3dcfc3dc3de45a43f75c746bd1d8c11170a5037fdf98bdb35775137886040516104c29190610b0e565b60405180910390a26104d4858761085c565b50505050505050565b60006020528060005260406000206000915054906101000a900460ff1681565b600060017f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a60405160200161055b959493929190611135565b604051602081830303815290604052805190602001206040516020016105829291906111df565b60405160208183030381529060405280519060200120858585604051600081526020016040526040516105b89493929190611216565b6020604051602081039080840390855afa1580156105da573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561064e57508573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b61068d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610684906112a7565b60405180910390fd5b610699888888886107e2565b5050505050505050565b600083116106e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106dd90611339565b60405180910390fd5b60006106f58585853386610370565b90506000151560008083815260200190815260200160002060009054906101000a900460ff1615151461075d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610754906113a5565b60405180910390fd5b600160008083815260200190815260200160002060006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff16857f15b4b8206809535e547317cd5cedc86cff6e7d203551f93701786ddaf14fd9f98686866040516107d3939291906113c5565b60405180910390a35050505050565b60006107f18585853386610370565b90506107fc8161090d565b60008082815260200190815260200160002060006101000a81549060ff0219169055847f3fbd469ec3a5ce074f975f76ce27e727ba21c99176917b97ae2e713695582a1260405160405180910390a2610855338561085c565b5050505050565b60008273ffffffffffffffffffffffffffffffffffffffff168260405161088290611422565b60006040518083038185875af1925050503d80600081146108bf576040519150601f19603f3d011682016040523d82523d6000602084013e6108c4565b606091505b5050905080610908576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ff906114a9565b60405180910390fd5b505050565b6001151560008083815260200190815260200160002060009054906101000a900460ff16151514610973576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096a9061153b565b60405180910390fd5b50565b600080fd5b6000819050919050565b61098e8161097b565b811461099957600080fd5b50565b6000813590506109ab81610985565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006109dc826109b1565b9050919050565b6109ec816109d1565b81146109f757600080fd5b50565b600081359050610a09816109e3565b92915050565b6000819050919050565b610a2281610a0f565b8114610a2d57600080fd5b50565b600081359050610a3f81610a19565b92915050565b600080600060608486031215610a5e57610a5d610976565b5b6000610a6c8682870161099c565b9350506020610a7d868287016109fa565b9250506040610a8e86828701610a30565b9150509250925092565b60008060008060808587031215610ab257610ab1610976565b5b6000610ac08782880161099c565b9450506020610ad187828801610a30565b9350506040610ae2878288016109fa565b9250506060610af387828801610a30565b91505092959194509250565b610b088161097b565b82525050565b6000602082019050610b236000830184610aff565b92915050565b600060ff82169050919050565b610b3f81610b29565b82525050565b6000602082019050610b5a6000830184610b36565b92915050565b6000610b6b826109b1565b9050919050565b610b7b81610b60565b8114610b8657600080fd5b50565b600081359050610b9881610b72565b92915050565b60008060008060808587031215610bb857610bb7610976565b5b6000610bc68782880161099c565b9450506020610bd787828801610b89565b9350506040610be887828801610a30565b9250506060610bf987828801610a30565b91505092959194509250565b600080600080600060a08688031215610c2157610c20610976565b5b6000610c2f8882890161099c565b9550506020610c4088828901610a30565b9450506040610c51888289016109fa565b9350506060610c62888289016109fa565b9250506080610c7388828901610a30565b9150509295509295909350565b600060208284031215610c9657610c95610976565b5b6000610ca48482850161099c565b91505092915050565b60008115159050919050565b610cc281610cad565b82525050565b6000602082019050610cdd6000830184610cb9565b92915050565b610cec81610b29565b8114610cf757600080fd5b50565b600081359050610d0981610ce3565b92915050565b600080600080600080600060e0888a031215610d2e57610d2d610976565b5b6000610d3c8a828b0161099c565b9750506020610d4d8a828b01610a30565b9650506040610d5e8a828b016109fa565b9550506060610d6f8a828b01610a30565b9450506080610d808a828b01610cfa565b93505060a0610d918a828b0161099c565b92505060c0610da28a828b0161099c565b91505092959891949750929550565b600082825260208201905092915050565b7f4574686572537761703a207377617020686173206e6f742074696d6564206f7560008201527f7420796574000000000000000000000000000000000000000000000000000000602082015250565b6000610e1e602583610db1565b9150610e2982610dc2565b604082019050919050565b60006020820190508181036000830152610e4d81610e11565b9050919050565b7f4574686572537761703a2073656e7420616d6f756e74206d757374206265206760008201527f726561746572207468616e207468652070726570617920616d6f756e74000000602082015250565b6000610eb0603d83610db1565b9150610ebb82610e54565b604082019050919050565b60006020820190508181036000830152610edf81610ea3565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610f2082610a0f565b9150610f2b83610a0f565b9250828203905081811115610f4357610f42610ee6565b5b92915050565b6000819050919050565b610f64610f5f8261097b565b610f49565b82525050565b6000819050919050565b610f85610f8082610a0f565b610f6a565b82525050565b60008160601b9050919050565b6000610fa382610f8b565b9050919050565b6000610fb582610f98565b9050919050565b610fcd610fc8826109d1565b610faa565b82525050565b6000610fdf8288610f53565b602082019150610fef8287610f74565b602082019150610fff8286610fbc565b60148201915061100f8285610fbc565b60148201915061101f8284610f74565b6020820191508190509695505050505050565b600061103e8284610f53565b60208201915081905092915050565b600081519050919050565b600081905092915050565b60005b83811015611081578082015181840152602081019050611066565b60008484015250505050565b60006110988261104d565b6110a28185611058565b93506110b2818560208601611063565b80840191505092915050565b60006110ca828461108d565b915081905092915050565b6000815190506110e481610985565b92915050565b600060208284031215611100576110ff610976565b5b600061110e848285016110d5565b91505092915050565b61112081610a0f565b82525050565b61112f816109d1565b82525050565b600060a08201905061114a6000830188610aff565b6111576020830187610aff565b6111646040830186611117565b6111716060830185611126565b61117e6080830184611117565b9695505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b60006111c9600283611188565b91506111d482611193565b600282019050919050565b60006111ea826111bc565b91506111f68285610f53565b6020820191506112068284610f53565b6020820191508190509392505050565b600060808201905061122b6000830187610aff565b6112386020830186610b36565b6112456040830185610aff565b6112526060830184610aff565b95945050505050565b7f4574686572537761703a20696e76616c6964207369676e617475726500000000600082015250565b6000611291601c83610db1565b915061129c8261125b565b602082019050919050565b600060208201905081810360008301526112c081611284565b9050919050565b7f4574686572537761703a206c6f636b656420616d6f756e74206d757374206e6f60008201527f74206265207a65726f0000000000000000000000000000000000000000000000602082015250565b6000611323602983610db1565b915061132e826112c7565b604082019050919050565b6000602082019050818103600083015261135281611316565b9050919050565b7f4574686572537761703a20737761702065786973747320616c72656164790000600082015250565b600061138f601e83610db1565b915061139a82611359565b602082019050919050565b600060208201905081810360008301526113be81611382565b9050919050565b60006060820190506113da6000830186611117565b6113e76020830185611126565b6113f46040830184611117565b949350505050565b50565b600061140c600083611058565b9150611417826113fc565b600082019050919050565b600061142d826113ff565b9150819050919050565b7f5472616e7366657248656c7065723a20636f756c64206e6f74207472616e736660008201527f6572204574686572000000000000000000000000000000000000000000000000602082015250565b6000611493602883610db1565b915061149e82611437565b604082019050919050565b600060208201905081810360008301526114c281611486565b9050919050565b7f4574686572537761703a207377617020686173206e6f204574686572206c6f6360008201527f6b656420696e2074686520636f6e747261637400000000000000000000000000602082015250565b6000611525603383610db1565b9150611530826114c9565b604082019050919050565b6000602082019050818103600083015261155481611518565b905091905056fea2646970667358221220521990c57fce8c6ba9b7c7cf550d50fb69f717ab41f4047528082b658e040ec464736f6c63430008180033 + gas 2000000 + build + +block_build b01 + parent g00 + transactions tx01 + build + +block_connect b01 + +# Assert best block +assert_best b01 \ No newline at end of file From 46a29e79bff867245a524dbb5a0e2a49776ef5c5 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Thu, 11 Apr 2024 13:52:58 -0400 Subject: [PATCH 02/21] Add integration test --- .../java/co/rsk/EtherSwapTest.java | 207 ++++++++++++++++++ .../src/main/java/co/rsk/RskContext.java | 7 +- .../rsk/core/TransactionExecutorFactory.java | 9 +- .../co/rsk/core/bc/TransactionPoolImpl.java | 21 +- .../rsk/net/handler/TxPendingValidator.java | 6 +- .../TxValidatorAccountBalanceValidator.java | 18 +- .../personal/PersonalModuleWalletEnabled.java | 2 +- .../main/java/co/rsk/util/ContractUtil.java | 40 +++- .../java/org/ethereum/config/Constants.java | 6 +- .../ethereum/core/TransactionExecutor.java | 14 +- .../src/main/resources/genesis/rsk-dev.json | 11 +- ...xValidatorAccountBalanceValidatorTest.java | 6 +- .../java/co/rsk/util/ContractUtilTest.java | 16 +- .../core/TransactionExecutorTest.java | 8 +- 14 files changed, 330 insertions(+), 41 deletions(-) create mode 100644 rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java diff --git a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java new file mode 100644 index 00000000000..10b1e473594 --- /dev/null +++ b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java @@ -0,0 +1,207 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * 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.util.ContractUtil; +import co.rsk.util.HexUtils; +import co.rsk.util.TestUtils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.squareup.okhttp.Response; +import org.ethereum.config.Constants; +import org.ethereum.core.CallTransaction; +import org.ethereum.crypto.HashUtil; +import org.ethereum.util.ByteUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +public class EtherSwapTest { + private static final int LOCAL_PORT = 4444; + + private static final CallTransaction.Function CALL_LOCK_FUNCTION = CallTransaction.Function.fromSignature( + "lock", + new String[]{"bytes32", "address", "uint256"}, + new String[]{} + ); + private static final CallTransaction.Function CALL_CLAIM_FUNCTION = CallTransaction.Function.fromSignature( + "claim", + new String[]{"bytes32", "uint256", "address", "uint256"}, + new String[]{} + ); + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private Response lockTxRequest(String refundAddress, byte[] lockData, BigInteger amount) throws IOException { + String lockTxRequestContent = "[{\n" + + " \"method\": \"eth_sendTransaction\",\n" + + " \"params\": [{\n" + + " \"from\": \"" + refundAddress + "\",\n" + + " \"to\": \"0x" + Constants.regtest().getEtherSwapContractAddress() + "\",\n" + + " \"data\": \"0x" + ByteUtil.toHexString(lockData) + "\",\n" + + " \"value\": \"" + HexUtils.toQuantityJsonHex(amount.longValue()) + "\",\n" + + " \"gas\": \"0xc350\",\n" + + " \"gasPrice\": \"0x1\"\n" + + " }],\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\"\n" + + "}]"; + + return TestUtils.sendJsonRpcMessage(lockTxRequestContent, LOCAL_PORT); + } + + private Response claimTxRequest(String claimAddress, byte[] claimData) throws IOException { + String claimTxRequestContent = "[{\n" + + " \"method\": \"eth_sendTransaction\",\n" + + " \"params\": [{\n" + + " \"from\": \"" + claimAddress + "\",\n" + + " \"to\": \"0x" + Constants.regtest().getEtherSwapContractAddress() + "\",\n" + + " \"data\": \"0x" + ByteUtil.toHexString(claimData) + "\",\n" + + " \"value\": \"0x0\",\n" + + " \"gas\": \"0xc350\",\n" + + " \"gasPrice\": \"0x1\"\n" + + " }],\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\"\n" + + "}]"; + + return TestUtils.sendJsonRpcMessage(claimTxRequestContent, LOCAL_PORT); + } + + private Response getBalanceRequest(String address) throws IOException { + String getBalanceRequestContent = "[{\n" + + " \"method\": \"eth_getBalance\",\n" + + " \"params\": [\n" + + " \"" + address + "\",\n" + + " \"latest\"\n" + + " ],\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\"\n" + + "}]"; + + return TestUtils.sendJsonRpcMessage(getBalanceRequestContent, LOCAL_PORT); + } + + private Response getTxReceiptRequest(String txHash) throws IOException { + String getReceiptRequestContent = "[{\n" + + " \"method\": \"eth_getTransactionReceipt\",\n" + + " \"params\": [\n" + + " \"" + txHash + "\"\n" + + " ],\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\"\n" + + "}]"; + + return TestUtils.sendJsonRpcMessage(getReceiptRequestContent, LOCAL_PORT); + } + + @Test + void whenClaimTxIsSend_shouldShouldFailDueToLowFundsInContract() throws Exception { + String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; + String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; + byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); + byte[] preimageHash = HashUtil.sha256(ContractUtil.encodePacked(preimage)); + BigInteger amount = BigInteger.valueOf(5000); + + byte[] lockData = CALL_LOCK_FUNCTION.encode( + preimageHash, + claimAddress, + 8000000); + + byte[] claimData = CALL_CLAIM_FUNCTION.encode( + preimage, + amount, + refundAddress, + 8000000); + + + Response getBalanceResponse = getBalanceRequest(claimAddress); + JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); + BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + + lockTxRequest(refundAddress, lockData, amount); + TimeUnit.SECONDS.sleep(5); + + claimTxRequest(claimAddress, claimData); + TimeUnit.SECONDS.sleep(5); + + getBalanceResponse = getBalanceRequest(claimAddress); + jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + currentBalance = jsonRpcResponse.get(0).get("result"); + balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + } + + + @Test + void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { + String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; + String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; + byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); + byte[] preimageHash = HashUtil.sha256(ContractUtil.encodePacked(preimage)); + BigInteger amount = BigInteger.valueOf(500000); + + byte[] lockData = CALL_LOCK_FUNCTION.encode( + preimageHash, + claimAddress, + 8000000); + + byte[] claimData = CALL_CLAIM_FUNCTION.encode( + preimage, + amount, + refundAddress, + 8000000); + + + Response getBalanceResponse = getBalanceRequest(claimAddress); + JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); + BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + + lockTxRequest(refundAddress, lockData, amount); + TimeUnit.SECONDS.sleep(5); + + Response claimResponse = claimTxRequest(claimAddress, claimData); + TimeUnit.SECONDS.sleep(5); + + jsonRpcResponse = objectMapper.readTree(claimResponse.body().string()); + JsonNode claimTxHash = jsonRpcResponse.get(0).get("result"); + + Response getTxReceiptResponse = getTxReceiptRequest(claimTxHash.asText()); + jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); + JsonNode gasUsed = jsonRpcResponse.get(0).get("result").get("gasUsed"); + BigInteger expectedBalance = amount.subtract(new BigInteger(HexUtils.removeHexPrefix(gasUsed.asText()), 16)); + + getBalanceResponse = getBalanceRequest(claimAddress); + jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + currentBalance = jsonRpcResponse.get(0).get("result"); + balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + + Assertions.assertEquals(0, balanceBigInt.compareTo(expectedBalance)); + } +} diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index cb9d175dac9..9b580104a62 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -1345,11 +1345,16 @@ protected synchronized Web3InformationRetriever getWeb3InformationRetriever() { checkIfNotClosed(); if (web3InformationRetriever == null) { + TransactionPoolImpl transactionPoolImpl = (TransactionPoolImpl) getTransactionPool(); + TransactionExecutorFactory transactionExecutorFactory = getTransactionExecutorFactory(); web3InformationRetriever = new Web3InformationRetriever( - getTransactionPool(), + transactionPoolImpl, getBlockchain(), getRepositoryLocator(), getExecutionBlockRetriever()); + + transactionPoolImpl.setWeb3InformationRetriever(web3InformationRetriever); + transactionExecutorFactory.setWeb3InformationRetriever(web3InformationRetriever); } return web3InformationRetriever; } diff --git a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java index fb500c9afcd..60532f98525 100644 --- a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java +++ b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java @@ -20,6 +20,7 @@ import co.rsk.config.RskSystemProperties; import co.rsk.config.VmConfig; +import co.rsk.rpc.Web3InformationRetriever; import org.ethereum.core.*; import org.ethereum.db.BlockStore; import org.ethereum.db.ReceiptStore; @@ -39,6 +40,7 @@ public class TransactionExecutorFactory { private final ProgramInvokeFactory programInvokeFactory; private final PrecompiledContracts precompiledContracts; private BlockTxSignatureCache blockTxSignatureCache; + private Web3InformationRetriever web3InformationRetriever; public TransactionExecutorFactory( RskSystemProperties config, @@ -109,7 +111,12 @@ public TransactionExecutor newInstance( config.isRemascEnabled(), precompiledContracts, deletedAccounts, - blockTxSignatureCache + blockTxSignatureCache, + web3InformationRetriever ); } + + public void setWeb3InformationRetriever(Web3InformationRetriever web3InformationRetriever) { + this.web3InformationRetriever = web3InformationRetriever; + } } 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 62205b00ab8..45c1bdbb936 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 @@ -26,6 +26,7 @@ import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.TxPendingValidator; import co.rsk.net.handler.quota.TxQuotaChecker; +import co.rsk.rpc.Web3InformationRetriever; import co.rsk.util.ContractUtil; import com.google.common.annotations.VisibleForTesting; import org.ethereum.core.*; @@ -75,12 +76,14 @@ public class TransactionPoolImpl implements TransactionPool { private Block bestBlock; - private final TxPendingValidator validator; + private TxPendingValidator validator; private final TxQuotaChecker quotaChecker; private final GasPriceTracker gasPriceTracker; + private Web3InformationRetriever web3InformationRetriever; + @java.lang.SuppressWarnings("squid:S107") public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator repositoryLocator, BlockStore blockStore, BlockFactory blockFactory, EthereumListener listener, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache, int outdatedThreshold, int outdatedTimeout, TxQuotaChecker txQuotaChecker, GasPriceTracker gasPriceTracker) { this.config = config; @@ -98,8 +101,6 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit 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")); } @@ -113,6 +114,13 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit public void start() { processBest(blockStore.getBestBlock()); + this.validator = new TxPendingValidator( + this.config.getNetworkConstants(), + this.config.getActivationConfig(), + this.config.getNumOfAccountSlots(), + signatureCache, + web3InformationRetriever); + if (this.outdatedTimeout > 0 && this.cleanerTimer != null) { this.cleanerFuture = this.cleanerTimer.scheduleAtFixedRate(this::cleanUp, this.outdatedTimeout, this.outdatedTimeout, TimeUnit.SECONDS); } @@ -435,6 +443,10 @@ public synchronized List getQueuedTransactions() { return ret; } + public void setWeb3InformationRetriever(Web3InformationRetriever web3InformationRetriever) { + this.web3InformationRetriever = web3InformationRetriever; + } + private void addQueuedTransaction(Transaction tx) { this.queuedTransactions.addTransaction(tx); } @@ -484,7 +496,7 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos return true; } - return ContractUtil.isClaimTxAndValid(newTx, currentRepository, costWithNewTx, config.getNetworkConstants(), signatureCache); + return ContractUtil.isClaimTxAndValid(newTx, costWithNewTx, config.getNetworkConstants(), signatureCache, web3InformationRetriever); } private Coin getTxBaseCost(Transaction tx) { @@ -500,5 +512,4 @@ private Coin getTxBaseCost(Transaction tx) { private long getTransactionCost(Transaction tx, long number) { return tx.transactionCost(config.getNetworkConstants(), config.getActivationConfig().forBlock(number), signatureCache); } - } 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 74ab6e38636..e15cdc9b932 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 @@ -20,6 +20,7 @@ import co.rsk.core.Coin; import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.txvalidator.*; +import co.rsk.rpc.Web3InformationRetriever; import org.bouncycastle.util.BigIntegers; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -52,7 +53,7 @@ public class TxPendingValidator { private final SignatureCache signatureCache; - public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache) { + public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache, Web3InformationRetriever web3InformationRetriever) { this.constants = constants; this.activationConfig = activationConfig; this.signatureCache = signatureCache; @@ -62,12 +63,13 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig validatorSteps.add(new TxValidatorGasLimitValidator()); validatorSteps.add(new TxValidatorAccountStateValidator()); validatorSteps.add(new TxValidatorNonceRangeValidator(accountSlots)); - validatorSteps.add(new TxValidatorAccountBalanceValidator()); + validatorSteps.add(new TxValidatorAccountBalanceValidator(constants, signatureCache, web3InformationRetriever)); validatorSteps.add(new TxValidatorMinimuGasPriceValidator()); validatorSteps.add(new TxValidatorIntrinsicGasLimitValidator(constants, activationConfig, signatureCache)); validatorSteps.add(new TxValidatorMaximumGasPriceValidator(activationConfig)); } + public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state) { BigInteger blockGasLimit = BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit()); Coin minimumGasPrice = executionBlock.getMinimumGasPrice(); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index f81e30ebceb..de0f322aaf6 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -19,8 +19,13 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; +import co.rsk.rpc.Web3InformationRetriever; +import co.rsk.util.ContractUtil; +import org.ethereum.config.Constants; import org.ethereum.core.AccountState; +import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; import javax.annotation.Nullable; @@ -31,6 +36,16 @@ */ public class TxValidatorAccountBalanceValidator implements TxValidatorStep { + private final Constants constants; + private final SignatureCache signatureCache; + private final Web3InformationRetriever web3InformationRetriever; + + public TxValidatorAccountBalanceValidator(Constants constants, SignatureCache signatureCache, Web3InformationRetriever web3InformationRetriever) { + this.constants = constants; + this.signatureCache = signatureCache; + this.web3InformationRetriever = web3InformationRetriever; + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (isFreeTx) { @@ -43,7 +58,8 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); - if (state.getBalance().compareTo(maximumPrice) >= 0) { + if (state.getBalance().compareTo(maximumPrice) >= 0 + || ContractUtil.isClaimTxAndValid(tx, maximumPrice, constants, signatureCache, web3InformationRetriever)) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java index eb294b1f43e..0aa9c1d240a 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java @@ -68,7 +68,7 @@ public void init() { if (config.getNetworkConstants().seedCowAccounts()) { newAccountWithSeed("cow"); - for (int k = 1; k <= 9; k++) { + for (int k = 1; k <= 10; k++) { newAccountWithSeed("cow" + k); } } diff --git a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java index efcdc9cf7e8..a8246f3ed24 100644 --- a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java @@ -1,8 +1,28 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ package co.rsk.util; import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.bc.AccountInformationProvider; import co.rsk.db.RepositorySnapshot; +import co.rsk.rpc.Web3InformationRetriever; import org.ethereum.config.Constants; import org.ethereum.core.CallTransaction; import org.ethereum.core.SignatureCache; @@ -16,13 +36,16 @@ import java.util.Arrays; public class ContractUtil { + private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; + + public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatureCache) { + CallTransaction.Invocation invocation = getTxInvocation(newTx); // Get arguments from the invocation object byte[] preimage = (byte[]) invocation.args[0]; - // Encode preimage with sha256, this is to imitate the encoding done in teh claim function before calling hashValues - byte[] preimageHash = HashUtil.sha256(preimage); + byte[] preimageHash = HashUtil.sha256(encodePacked(preimage)); BigInteger amount = (BigInteger) invocation.args[1]; DataWord refundAddress = (DataWord) invocation.args[2]; BigInteger timeLock = (BigInteger) invocation.args[3]; @@ -70,21 +93,24 @@ public static CallTransaction.Invocation getTxInvocation(Transaction newTx) { } public static boolean isClaimTxAndValid(Transaction newTx, - RepositorySnapshot currentRepository, Coin txCost, Constants constants, - SignatureCache signatureCache) { + SignatureCache signatureCache, + Web3InformationRetriever web3InformationRetriever) { byte[] functionSelector = Arrays.copyOfRange(newTx.getData(), 0, 4); if(newTx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) && Arrays.equals(functionSelector, Constants.CLAIM_FUNCTION_SIGNATURE)) { - byte[] swapHash = calculateSwapHash(newTx, signatureCache); - DataWord swapRecord = currentRepository.getStorageValue(newTx.getReceiveAddress(), DataWord.valueOf(swapHash)); + String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(newTx, signatureCache)); + byte[] key = HashUtil.keccak256(HexUtils.decode(HexUtils.stringToByteArray(swapHash + SWAPS_MAP_POSITION))); + + AccountInformationProvider accountInformationProvider = web3InformationRetriever.getInformationProvider("latest"); + DataWord swapRecord = accountInformationProvider.getStorageValue(newTx.getReceiveAddress(), DataWord.valueOf(key)); if(swapRecord != null){ CallTransaction.Invocation invocation = getTxInvocation(newTx); BigInteger amount = (BigInteger) invocation.args[1]; - Coin balanceWithClaim = currentRepository.getBalance(newTx.getSender(signatureCache)) + Coin balanceWithClaim = accountInformationProvider.getBalance(newTx.getSender(signatureCache)) .add(Coin.valueOf(amount.longValue())); return txCost.compareTo(balanceWithClaim) <= 0; diff --git a/rskj-core/src/main/java/org/ethereum/config/Constants.java b/rskj-core/src/main/java/org/ethereum/config/Constants.java index 2a7b9a1049d..8007a88682a 100644 --- a/rskj-core/src/main/java/org/ethereum/config/Constants.java +++ b/rskj-core/src/main/java/org/ethereum/config/Constants.java @@ -55,6 +55,8 @@ public class Constants { private static final long DEFAULT_MAX_TIMESTAMPS_DIFF_IN_SECS = 5L * 60; // 5 mins private static final long TESTNET_MAX_TIMESTAMPS_DIFF_IN_SECS = 120L * 60; // 120 mins + private static final String REGTEST_ETHERSWAP_CONTRACT_ADDRESS = "5fbdb2315678afecb367f032d93f642f64180aa3"; + private final byte chainId; private final boolean seedCowAccounts; private final int durationLimit; @@ -297,7 +299,7 @@ public static Constants regtest() { 0, new BridgeRegTestConstants(), new BlockDifficulty(new BigInteger("550000000")), - "77045E71a7A2c50903d88e564cD72fab11e82051" + REGTEST_ETHERSWAP_CONTRACT_ADDRESS ); } @@ -312,7 +314,7 @@ public static Constants regtestWithFederation(List genesisFederationPu 0, new BridgeRegTestConstants(genesisFederationPublicKeys), new BlockDifficulty(new BigInteger("550000000")), - null + REGTEST_ETHERSWAP_CONTRACT_ADDRESS ); } } diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index bad58151dac..9ef400642ec 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -25,6 +25,7 @@ import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; import co.rsk.panic.PanicProcessor; +import co.rsk.rpc.Web3InformationRetriever; import co.rsk.rpc.modules.trace.ProgramSubtrace; import co.rsk.util.ContractUtil; import org.ethereum.config.Constants; @@ -102,12 +103,14 @@ public class TransactionExecutor { private boolean localCall = false; private boolean txWasPaid = false; + private Web3InformationRetriever web3InformationRetriever; + public TransactionExecutor( Constants constants, ActivationConfig activationConfig, Transaction tx, int txindex, RskAddress coinbase, Repository track, BlockStore blockStore, ReceiptStore receiptStore, BlockFactory blockFactory, ProgramInvokeFactory programInvokeFactory, Block executionBlock, long gasUsedInTheBlock, VmConfig vmConfig, boolean remascEnabled, PrecompiledContracts precompiledContracts, Set deletedAccounts, - SignatureCache signatureCache) { + SignatureCache signatureCache, Web3InformationRetriever web3InformationRetriever) { this.constants = constants; this.signatureCache = signatureCache; this.activations = activationConfig.forBlock(executionBlock.getNumber()); @@ -126,6 +129,7 @@ public TransactionExecutor( this.precompiledContracts = precompiledContracts; this.enableRemasc = remascEnabled; this.deletedAccounts = new HashSet<>(deletedAccounts); + this.web3InformationRetriever = web3InformationRetriever; } /** @@ -173,7 +177,7 @@ private boolean init() { Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); - if (!isCovers(senderBalance, totalCost) && !ContractUtil.isClaimTxAndValid(tx, track, totalCost,constants, signatureCache)) { + if (!isCovers(senderBalance, totalCost) && !ContractUtil.isClaimTxAndValid(tx, totalCost,constants, signatureCache, web3InformationRetriever)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); @@ -274,12 +278,6 @@ private void execute() { payTransaction(); txWasPaid = true; } - - long txGasLimit = GasCost.toGas(tx.getGasLimit()); - Coin txGasCost = tx.getGasPrice().multiply(BigInteger.valueOf(txGasLimit)); - track.addBalance(tx.getSender(signatureCache), txGasCost.negate()); - - logger.trace("Paying: txGasCost: [{}], gasPrice: [{}], gasLimit: [{}]", txGasCost, tx.getGasPrice(), txGasLimit); } if (tx.isContractCreation()) { diff --git a/rskj-core/src/main/resources/genesis/rsk-dev.json b/rskj-core/src/main/resources/genesis/rsk-dev.json index 623531bd5ef..43faec36f85 100644 --- a/rskj-core/src/main/resources/genesis/rsk-dev.json +++ b/rskj-core/src/main/resources/genesis/rsk-dev.json @@ -33,8 +33,17 @@ }, "09a1eda29f664ac8f68106f6567276df0c65d859": { "balance": "1000000000000000000000000000000" + }, + "8486054b907b0d79569723c761b7113736d32c5a" : { + "balance" : "0" + }, + "5fbdb2315678afecb367f032d93f642f64180aa3" : { + "balance" : "0", + "contract" : { + "code" : "60806040526004361061009c5760003560e01c80638b2f8f82116100645780638b2f8f8214610158578063a9ab4d5b14610195578063c3c37fbc146101c0578063cd413efa146101e9578063eb84e7f214610212578063fe237d451461024f5761009c565b80630899146b146100a157806335cd4ccb146100bd5780633644e515146100e657806354fd4d50146101115780636fa4ae601461013c575b600080fd5b6100bb60048036038101906100b69190610aa1565b610278565b005b3480156100c957600080fd5b506100e460048036038101906100df9190610af4565b610289565b005b3480156100f257600080fd5b506100fb6102de565b6040516101089190610b6a565b60405180910390f35b34801561011d57600080fd5b50610126610302565b6040516101339190610ba1565b60405180910390f35b61015660048036038101906101519190610bfa565b610307565b005b34801561016457600080fd5b5061017f600480360381019061017a9190610c61565b610370565b60405161018c9190610b6a565b60405180910390f35b3480156101a157600080fd5b506101aa6103ac565b6040516101b79190610b6a565b60405180910390f35b3480156101cc57600080fd5b506101e760048036038101906101e29190610af4565b6103d0565b005b3480156101f557600080fd5b50610210600480360381019061020b9190610c61565b6103e3565b005b34801561021e57600080fd5b5061023960048036038101906102349190610cdc565b61050b565b6040516102469190610d24565b60405180910390f35b34801561025b57600080fd5b5061027660048036038101906102719190610d6b565b61052b565b005b610284833484846106d1565b505050565b438111156102cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390610e90565b60405180910390fd5b6102d88484848461083e565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600381565b803411610349576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034090610f22565b60405180910390fd5b6103608482346103599190610f71565b85856106d1565b61036a83826108b8565b50505050565b6000858585858560405160200161038b95949392919061102f565b60405160208183030381529060405280519060200120905095945050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6103dd84843385856103e3565b50505050565b60006002866040516020016103f8919061108e565b604051602081830303815290604052604051610414919061111a565b602060405180830381855afa158015610431573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906104549190611146565b905060006104658287878787610370565b905081817f224a3e56646f106035ca3d5ff0fe651d4f5a4ceff02ea5f9b9ac2976749f712860405160405180910390a361049e81610969565b60008082815260200190815260200160002060006101000a81549060ff0219169055817f5664142af3dcfc3dc3de45a43f75c746bd1d8c11170a5037fdf98bdb35775137886040516104f09190610b6a565b60405180910390a261050285876108b8565b50505050505050565b60006020528060005260406000206000915054906101000a900460ff1681565b600060017f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a604051602001610589959493929190611191565b604051602081830303815290604052805190602001206040516020016105b092919061123b565b60405160208183030381529060405280519060200120858585604051600081526020016040526040516105e69493929190611272565b6020604051602081039080840390855afa158015610608573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561067c57508573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6106bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b290611303565b60405180910390fd5b6106c78888888861083e565b5050505050505050565b60008311610714576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070b90611395565b60405180910390fd5b60006107238585853386610370565b905084817f224a3e56646f106035ca3d5ff0fe651d4f5a4ceff02ea5f9b9ac2976749f712860405160405180910390a36000151560008083815260200190815260200160002060009054906101000a900460ff161515146107b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b090611401565b60405180910390fd5b600160008083815260200190815260200160002060006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff16857f15b4b8206809535e547317cd5cedc86cff6e7d203551f93701786ddaf14fd9f986868660405161082f93929190611421565b60405180910390a35050505050565b600061084d8585853386610370565b905061085881610969565b60008082815260200190815260200160002060006101000a81549060ff0219169055847f3fbd469ec3a5ce074f975f76ce27e727ba21c99176917b97ae2e713695582a1260405160405180910390a26108b133856108b8565b5050505050565b60008273ffffffffffffffffffffffffffffffffffffffff16826040516108de9061147e565b60006040518083038185875af1925050503d806000811461091b576040519150601f19603f3d011682016040523d82523d6000602084013e610920565b606091505b5050905080610964576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095b90611505565b60405180910390fd5b505050565b6001151560008083815260200190815260200160002060009054906101000a900460ff161515146109cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c690611597565b60405180910390fd5b50565b600080fd5b6000819050919050565b6109ea816109d7565b81146109f557600080fd5b50565b600081359050610a07816109e1565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610a3882610a0d565b9050919050565b610a4881610a2d565b8114610a5357600080fd5b50565b600081359050610a6581610a3f565b92915050565b6000819050919050565b610a7e81610a6b565b8114610a8957600080fd5b50565b600081359050610a9b81610a75565b92915050565b600080600060608486031215610aba57610ab96109d2565b5b6000610ac8868287016109f8565b9350506020610ad986828701610a56565b9250506040610aea86828701610a8c565b9150509250925092565b60008060008060808587031215610b0e57610b0d6109d2565b5b6000610b1c878288016109f8565b9450506020610b2d87828801610a8c565b9350506040610b3e87828801610a56565b9250506060610b4f87828801610a8c565b91505092959194509250565b610b64816109d7565b82525050565b6000602082019050610b7f6000830184610b5b565b92915050565b600060ff82169050919050565b610b9b81610b85565b82525050565b6000602082019050610bb66000830184610b92565b92915050565b6000610bc782610a0d565b9050919050565b610bd781610bbc565b8114610be257600080fd5b50565b600081359050610bf481610bce565b92915050565b60008060008060808587031215610c1457610c136109d2565b5b6000610c22878288016109f8565b9450506020610c3387828801610be5565b9350506040610c4487828801610a8c565b9250506060610c5587828801610a8c565b91505092959194509250565b600080600080600060a08688031215610c7d57610c7c6109d2565b5b6000610c8b888289016109f8565b9550506020610c9c88828901610a8c565b9450506040610cad88828901610a56565b9350506060610cbe88828901610a56565b9250506080610ccf88828901610a8c565b9150509295509295909350565b600060208284031215610cf257610cf16109d2565b5b6000610d00848285016109f8565b91505092915050565b60008115159050919050565b610d1e81610d09565b82525050565b6000602082019050610d396000830184610d15565b92915050565b610d4881610b85565b8114610d5357600080fd5b50565b600081359050610d6581610d3f565b92915050565b600080600080600080600060e0888a031215610d8a57610d896109d2565b5b6000610d988a828b016109f8565b9750506020610da98a828b01610a8c565b9650506040610dba8a828b01610a56565b9550506060610dcb8a828b01610a8c565b9450506080610ddc8a828b01610d56565b93505060a0610ded8a828b016109f8565b92505060c0610dfe8a828b016109f8565b91505092959891949750929550565b600082825260208201905092915050565b7f4574686572537761703a207377617020686173206e6f742074696d6564206f7560008201527f7420796574000000000000000000000000000000000000000000000000000000602082015250565b6000610e7a602583610e0d565b9150610e8582610e1e565b604082019050919050565b60006020820190508181036000830152610ea981610e6d565b9050919050565b7f4574686572537761703a2073656e7420616d6f756e74206d757374206265206760008201527f726561746572207468616e207468652070726570617920616d6f756e74000000602082015250565b6000610f0c603d83610e0d565b9150610f1782610eb0565b604082019050919050565b60006020820190508181036000830152610f3b81610eff565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610f7c82610a6b565b9150610f8783610a6b565b9250828203905081811115610f9f57610f9e610f42565b5b92915050565b6000819050919050565b610fc0610fbb826109d7565b610fa5565b82525050565b6000819050919050565b610fe1610fdc82610a6b565b610fc6565b82525050565b60008160601b9050919050565b6000610fff82610fe7565b9050919050565b600061101182610ff4565b9050919050565b61102961102482610a2d565b611006565b82525050565b600061103b8288610faf565b60208201915061104b8287610fd0565b60208201915061105b8286611018565b60148201915061106b8285611018565b60148201915061107b8284610fd0565b6020820191508190509695505050505050565b600061109a8284610faf565b60208201915081905092915050565b600081519050919050565b600081905092915050565b60005b838110156110dd5780820151818401526020810190506110c2565b60008484015250505050565b60006110f4826110a9565b6110fe81856110b4565b935061110e8185602086016110bf565b80840191505092915050565b600061112682846110e9565b915081905092915050565b600081519050611140816109e1565b92915050565b60006020828403121561115c5761115b6109d2565b5b600061116a84828501611131565b91505092915050565b61117c81610a6b565b82525050565b61118b81610a2d565b82525050565b600060a0820190506111a66000830188610b5b565b6111b36020830187610b5b565b6111c06040830186611173565b6111cd6060830185611182565b6111da6080830184611173565b9695505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b60006112256002836111e4565b9150611230826111ef565b600282019050919050565b600061124682611218565b91506112528285610faf565b6020820191506112628284610faf565b6020820191508190509392505050565b60006080820190506112876000830187610b5b565b6112946020830186610b92565b6112a16040830185610b5b565b6112ae6060830184610b5b565b95945050505050565b7f4574686572537761703a20696e76616c6964207369676e617475726500000000600082015250565b60006112ed601c83610e0d565b91506112f8826112b7565b602082019050919050565b6000602082019050818103600083015261131c816112e0565b9050919050565b7f4574686572537761703a206c6f636b656420616d6f756e74206d757374206e6f60008201527f74206265207a65726f0000000000000000000000000000000000000000000000602082015250565b600061137f602983610e0d565b915061138a82611323565b604082019050919050565b600060208201905081810360008301526113ae81611372565b9050919050565b7f4574686572537761703a20737761702065786973747320616c72656164790000600082015250565b60006113eb601e83610e0d565b91506113f6826113b5565b602082019050919050565b6000602082019050818103600083015261141a816113de565b9050919050565b60006060820190506114366000830186611173565b6114436020830185611182565b6114506040830184611173565b949350505050565b50565b60006114686000836110b4565b915061147382611458565b600082019050919050565b60006114898261145b565b9150819050919050565b7f5472616e7366657248656c7065723a20636f756c64206e6f74207472616e736660008201527f6572204574686572000000000000000000000000000000000000000000000000602082015250565b60006114ef602883610e0d565b91506114fa82611493565b604082019050919050565b6000602082019050818103600083015261151e816114e2565b9050919050565b7f4574686572537761703a207377617020686173206e6f204574686572206c6f6360008201527f6b656420696e2074686520636f6e747261637400000000000000000000000000602082015250565b6000611581603383610e0d565b915061158c82611525565b604082019050919050565b600060208201905081810360008301526115b081611574565b905091905056fea2646970667358221220c964a51051fe526f23557ce8e89fa13f558967d1918ac14c29ae29425670de7e64736f6c63430008180033", + "data" : {} + } } - }, "nonce": "0xdeadbeefdeadbeef", diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java index 7b4be060cad..13a81d9c593 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java @@ -47,7 +47,7 @@ void validAccountBalance() { Mockito.when(tx3.getGasPrice()).thenReturn(Coin.valueOf(5000)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(10000)); - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(null, null, null); Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); @@ -66,7 +66,7 @@ void invalidAccountBalance() { Mockito.when(tx2.getGasPrice()).thenReturn(Coin.valueOf(10)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(19)); - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(null, null, null); Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); @@ -87,7 +87,7 @@ void balanceIsNotValidatedIfFreeTx() { tx.sign(new ECKey().getPrivKeyBytes()); - TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(); + TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(null, null, null); Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true).transactionIsValid()); } diff --git a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java index 462fd68014a..3b43caad28b 100644 --- a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java @@ -2,7 +2,9 @@ import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.bc.AccountInformationProvider; import co.rsk.db.RepositorySnapshot; +import co.rsk.rpc.Web3InformationRetriever; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; import org.ethereum.core.CallTransaction; @@ -45,15 +47,19 @@ public void testCalculateSwapHash() { @Test public void testIsClaimTxAndValid() { - Transaction mockedTx = mockTx(); Coin txCost = Coin.valueOf(5); SignatureCache signatureCache = new ReceivedTxSignatureCache(); - RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); - when(mockedRepository.getStorageValue(mockedTx.getReceiveAddress(), DataWord.valueOf(HexUtils.stringHexToByteArray(EXPECTED_HASH)))) + + Transaction mockedTx = mockTx(); + Web3InformationRetriever mockedWeb3InformationRetriever = mock(Web3InformationRetriever.class); + AccountInformationProvider mockedAccountInformationProvider = mock(AccountInformationProvider.class); + + when(mockedWeb3InformationRetriever.getInformationProvider("latest")).thenReturn(mockedAccountInformationProvider); + when(mockedAccountInformationProvider.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); + when(mockedAccountInformationProvider.getStorageValue(any(RskAddress.class), any(DataWord.class))) .thenReturn(DataWord.valueOf(1)); - when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); - boolean result = ContractUtil.isClaimTxAndValid(mockedTx, mockedRepository, txCost, testConstans, signatureCache); + boolean result = ContractUtil.isClaimTxAndValid(mockedTx, txCost, testConstans, signatureCache, mockedWeb3InformationRetriever); assertTrue(result); } diff --git a/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java b/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java index 200e646b886..3158e4d0b86 100644 --- a/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java @@ -96,7 +96,7 @@ void testInitHandlesFreeTransactionsOK() { repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache + blockTxSignatureCache, null ); @@ -233,7 +233,7 @@ void InvalidTxsIsInBlockAndShouldntBeInCache(){ repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache + blockTxSignatureCache, null ); assertEquals(0, transaction.transactionCost(constants, activationConfig.forBlock(executionBlock.getNumber()), new BlockTxSignatureCache(new ReceivedTxSignatureCache()))); @@ -266,7 +266,7 @@ void remascTxIsReceivedAndShouldntBeInCache(){ repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache + blockTxSignatureCache, null ); assertEquals(0, transaction.transactionCost(constants, activationConfig.forBlock(executionBlock.getNumber()), new BlockTxSignatureCache(new ReceivedTxSignatureCache()))); @@ -374,7 +374,7 @@ private boolean executeValidTransaction(Transaction transaction, BlockTxSignatur repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache + blockTxSignatureCache, null ); return txExecutor.executeTransaction(); From 2ac95f119686eb4de8cf15c39df5e74017e94c73 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Thu, 11 Apr 2024 18:23:41 -0400 Subject: [PATCH 03/21] Tests fixes --- .../src/main/java/co/rsk/PropertyGetter.java | 7 ++++ .../src/main/java/co/rsk/RskContext.java | 15 ++++--- .../rsk/core/TransactionExecutorFactory.java | 14 +++---- .../co/rsk/core/bc/TransactionPoolImpl.java | 27 ++++++------ .../rsk/net/handler/TxPendingValidator.java | 6 +-- .../TxValidatorAccountBalanceValidator.java | 11 +++-- .../main/java/co/rsk/util/ContractUtil.java | 7 ++-- .../ethereum/core/TransactionExecutor.java | 10 ++--- .../java/co/rsk/core/CallContractTest.java | 3 +- .../java/co/rsk/core/TransactionTest.java | 3 +- .../co/rsk/core/bc/BlockExecutorTest.java | 3 +- .../rsk/core/bc/TransactionPoolImplTest.java | 3 +- .../java/co/rsk/mine/MinerServerTest.java | 3 +- .../co/rsk/mine/TransactionModuleTest.java | 17 ++++---- .../java/co/rsk/net/SyncProcessorTest.java | 3 +- .../java/co/rsk/peg/RskForksBridgeTest.java | 3 +- .../remasc/RemascProcessMinerFeesTest.java | 3 +- .../rsk/remasc/RemascStorageProviderTest.java | 3 +- .../java/co/rsk/remasc/RemascTestRunner.java | 3 +- .../src/test/java/co/rsk/test/World.java | 3 +- .../co/rsk/test/builders/BlockBuilder.java | 3 +- .../rsk/test/builders/BlockChainBuilder.java | 5 ++- .../co/rsk/test/dsl/WorldDslProcessor.java | 3 +- .../java/co/rsk/util/ContractUtilTest.java | 5 ++- .../src/test/java/co/rsk/vm/MinerHelper.java | 2 +- .../org/ethereum/core/ImportLightTest.java | 5 ++- .../org/ethereum/core/TransactionTest.java | 6 ++- .../ethereum/jsontestsuite/TestRunner.java | 5 ++- .../runners/StateTestRunner.java | 42 ++++++++++--------- .../java/org/ethereum/rpc/Web3ImplTest.java | 13 +++--- .../org/ethereum/util/EthModuleTestUtils.java | 3 +- .../vm/program/NestedContractsTest.java | 1 + 32 files changed, 134 insertions(+), 106 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/PropertyGetter.java diff --git a/rskj-core/src/main/java/co/rsk/PropertyGetter.java b/rskj-core/src/main/java/co/rsk/PropertyGetter.java new file mode 100644 index 00000000000..2659b9e521a --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/PropertyGetter.java @@ -0,0 +1,7 @@ +package co.rsk; + +import co.rsk.rpc.Web3InformationRetriever; + +public interface PropertyGetter { + Web3InformationRetriever getWeb3InfoRetriever(); +} diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index 9b580104a62..2ffed355ac5 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -257,6 +257,8 @@ public class RskContext implements NodeContext, NodeBootstrapper { private volatile boolean closed; + private final PropertyGetter propertyGetter = this::getWeb3InformationRetriever; + /***** Constructors ***********************************************************************************************/ public RskContext(String[] args) { RskCli rskCli = new RskCli(); @@ -387,7 +389,8 @@ public synchronized TransactionPool getTransactionPool() { rskSystemProperties.txOutdatedThreshold(), rskSystemProperties.txOutdatedTimeout(), getTxQuotaChecker(), - getGasPriceTracker()); + getGasPriceTracker(), + propertyGetter); } return transactionPool; @@ -589,7 +592,8 @@ public synchronized TransactionExecutorFactory getTransactionExecutorFactory() { getBlockFactory(), getProgramInvokeFactory(), getPrecompiledContracts(), - getBlockTxSignatureCache() + getBlockTxSignatureCache(), + propertyGetter ); } @@ -1345,16 +1349,11 @@ protected synchronized Web3InformationRetriever getWeb3InformationRetriever() { checkIfNotClosed(); if (web3InformationRetriever == null) { - TransactionPoolImpl transactionPoolImpl = (TransactionPoolImpl) getTransactionPool(); - TransactionExecutorFactory transactionExecutorFactory = getTransactionExecutorFactory(); web3InformationRetriever = new Web3InformationRetriever( - transactionPoolImpl, + getTransactionPool(), getBlockchain(), getRepositoryLocator(), getExecutionBlockRetriever()); - - transactionPoolImpl.setWeb3InformationRetriever(web3InformationRetriever); - transactionExecutorFactory.setWeb3InformationRetriever(web3InformationRetriever); } return web3InformationRetriever; } diff --git a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java index 60532f98525..a0e896e6845 100644 --- a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java +++ b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java @@ -18,9 +18,9 @@ package co.rsk.core; +import co.rsk.PropertyGetter; import co.rsk.config.RskSystemProperties; import co.rsk.config.VmConfig; -import co.rsk.rpc.Web3InformationRetriever; import org.ethereum.core.*; import org.ethereum.db.BlockStore; import org.ethereum.db.ReceiptStore; @@ -40,7 +40,7 @@ public class TransactionExecutorFactory { private final ProgramInvokeFactory programInvokeFactory; private final PrecompiledContracts precompiledContracts; private BlockTxSignatureCache blockTxSignatureCache; - private Web3InformationRetriever web3InformationRetriever; + private PropertyGetter propertyGetter; public TransactionExecutorFactory( RskSystemProperties config, @@ -49,7 +49,8 @@ public TransactionExecutorFactory( BlockFactory blockFactory, ProgramInvokeFactory programInvokeFactory, PrecompiledContracts precompiledContracts, - BlockTxSignatureCache blockTxSignatureCache) { + BlockTxSignatureCache blockTxSignatureCache, + PropertyGetter propertyGetter) { this.config = config; this.blockStore = blockStore; this.receiptStore = receiptStore; @@ -57,6 +58,7 @@ public TransactionExecutorFactory( this.programInvokeFactory = programInvokeFactory; this.precompiledContracts = precompiledContracts; this.blockTxSignatureCache = blockTxSignatureCache; + this.propertyGetter = propertyGetter; } public TransactionExecutor newInstance( @@ -112,11 +114,7 @@ public TransactionExecutor newInstance( precompiledContracts, deletedAccounts, blockTxSignatureCache, - web3InformationRetriever + propertyGetter ); } - - public void setWeb3InformationRetriever(Web3InformationRetriever web3InformationRetriever) { - this.web3InformationRetriever = web3InformationRetriever; - } } 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 45c1bdbb936..d137a6bf7b2 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 @@ -17,6 +17,7 @@ */ package co.rsk.core.bc; +import co.rsk.PropertyGetter; import co.rsk.config.RskSystemProperties; import co.rsk.core.Coin; import co.rsk.core.TransactionExecutorFactory; @@ -26,7 +27,6 @@ import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.TxPendingValidator; import co.rsk.net.handler.quota.TxQuotaChecker; -import co.rsk.rpc.Web3InformationRetriever; import co.rsk.util.ContractUtil; import com.google.common.annotations.VisibleForTesting; import org.ethereum.core.*; @@ -82,10 +82,10 @@ public class TransactionPoolImpl implements TransactionPool { private final GasPriceTracker gasPriceTracker; - private Web3InformationRetriever web3InformationRetriever; + private PropertyGetter propertyGetter; @java.lang.SuppressWarnings("squid:S107") - public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator repositoryLocator, BlockStore blockStore, BlockFactory blockFactory, EthereumListener listener, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache, int outdatedThreshold, int outdatedTimeout, TxQuotaChecker txQuotaChecker, GasPriceTracker gasPriceTracker) { + public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator repositoryLocator, BlockStore blockStore, BlockFactory blockFactory, EthereumListener listener, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache, int outdatedThreshold, int outdatedTimeout, TxQuotaChecker txQuotaChecker, GasPriceTracker gasPriceTracker, PropertyGetter propertyGetter) { this.config = config; this.blockStore = blockStore; this.repositoryLocator = repositoryLocator; @@ -97,10 +97,18 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit this.outdatedTimeout = outdatedTimeout; this.quotaChecker = txQuotaChecker; this.gasPriceTracker = gasPriceTracker; + this.propertyGetter = propertyGetter; pendingTransactions = new TransactionSet(this.signatureCache); queuedTransactions = new TransactionSet(this.signatureCache); + this.validator = new TxPendingValidator( + this.config.getNetworkConstants(), + this.config.getActivationConfig(), + this.config.getNumOfAccountSlots(), + signatureCache, + this.propertyGetter); + if (this.outdatedTimeout > 0) { this.cleanerTimer = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "TransactionPoolCleanerTimer")); } @@ -114,13 +122,6 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit public void start() { processBest(blockStore.getBestBlock()); - this.validator = new TxPendingValidator( - this.config.getNetworkConstants(), - this.config.getActivationConfig(), - this.config.getNumOfAccountSlots(), - signatureCache, - web3InformationRetriever); - if (this.outdatedTimeout > 0 && this.cleanerTimer != null) { this.cleanerFuture = this.cleanerTimer.scheduleAtFixedRate(this::cleanUp, this.outdatedTimeout, this.outdatedTimeout, TimeUnit.SECONDS); } @@ -443,10 +444,6 @@ public synchronized List getQueuedTransactions() { return ret; } - public void setWeb3InformationRetriever(Web3InformationRetriever web3InformationRetriever) { - this.web3InformationRetriever = web3InformationRetriever; - } - private void addQueuedTransaction(Transaction tx) { this.queuedTransactions.addTransaction(tx); } @@ -496,7 +493,7 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos return true; } - return ContractUtil.isClaimTxAndValid(newTx, costWithNewTx, config.getNetworkConstants(), signatureCache, web3InformationRetriever); + return ContractUtil.isClaimTxAndValid(newTx, costWithNewTx, config.getNetworkConstants(), signatureCache, this.propertyGetter); } private Coin getTxBaseCost(Transaction tx) { 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 e15cdc9b932..16fa147c66d 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 @@ -17,10 +17,10 @@ */ package co.rsk.net.handler; +import co.rsk.PropertyGetter; import co.rsk.core.Coin; import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.txvalidator.*; -import co.rsk.rpc.Web3InformationRetriever; import org.bouncycastle.util.BigIntegers; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -53,7 +53,7 @@ public class TxPendingValidator { private final SignatureCache signatureCache; - public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache, Web3InformationRetriever web3InformationRetriever) { + public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache, PropertyGetter propertyGetter) { this.constants = constants; this.activationConfig = activationConfig; this.signatureCache = signatureCache; @@ -63,7 +63,7 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig validatorSteps.add(new TxValidatorGasLimitValidator()); validatorSteps.add(new TxValidatorAccountStateValidator()); validatorSteps.add(new TxValidatorNonceRangeValidator(accountSlots)); - validatorSteps.add(new TxValidatorAccountBalanceValidator(constants, signatureCache, web3InformationRetriever)); + validatorSteps.add(new TxValidatorAccountBalanceValidator(constants, signatureCache, propertyGetter)); validatorSteps.add(new TxValidatorMinimuGasPriceValidator()); validatorSteps.add(new TxValidatorIntrinsicGasLimitValidator(constants, activationConfig, signatureCache)); validatorSteps.add(new TxValidatorMaximumGasPriceValidator(activationConfig)); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index de0f322aaf6..7035545c2e5 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -18,10 +18,9 @@ package co.rsk.net.handler.txvalidator; +import co.rsk.PropertyGetter; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import co.rsk.rpc.Web3InformationRetriever; import co.rsk.util.ContractUtil; import org.ethereum.config.Constants; import org.ethereum.core.AccountState; @@ -38,12 +37,12 @@ public class TxValidatorAccountBalanceValidator implements TxValidatorStep { private final Constants constants; private final SignatureCache signatureCache; - private final Web3InformationRetriever web3InformationRetriever; + private final PropertyGetter propertyGetter; - public TxValidatorAccountBalanceValidator(Constants constants, SignatureCache signatureCache, Web3InformationRetriever web3InformationRetriever) { + public TxValidatorAccountBalanceValidator(Constants constants, SignatureCache signatureCache, PropertyGetter propertyGetter) { this.constants = constants; this.signatureCache = signatureCache; - this.web3InformationRetriever = web3InformationRetriever; + this.propertyGetter = propertyGetter; } @Override @@ -59,7 +58,7 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); if (state.getBalance().compareTo(maximumPrice) >= 0 - || ContractUtil.isClaimTxAndValid(tx, maximumPrice, constants, signatureCache, web3InformationRetriever)) { + || ContractUtil.isClaimTxAndValid(tx, maximumPrice, constants, signatureCache, propertyGetter)) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java index a8246f3ed24..f6256a0101e 100644 --- a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java @@ -18,11 +18,10 @@ */ package co.rsk.util; +import co.rsk.PropertyGetter; import co.rsk.core.Coin; import co.rsk.core.RskAddress; import co.rsk.core.bc.AccountInformationProvider; -import co.rsk.db.RepositorySnapshot; -import co.rsk.rpc.Web3InformationRetriever; import org.ethereum.config.Constants; import org.ethereum.core.CallTransaction; import org.ethereum.core.SignatureCache; @@ -96,7 +95,7 @@ public static boolean isClaimTxAndValid(Transaction newTx, Coin txCost, Constants constants, SignatureCache signatureCache, - Web3InformationRetriever web3InformationRetriever) { + PropertyGetter propertyGetter) { byte[] functionSelector = Arrays.copyOfRange(newTx.getData(), 0, 4); if(newTx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) && Arrays.equals(functionSelector, Constants.CLAIM_FUNCTION_SIGNATURE)) { @@ -104,7 +103,7 @@ public static boolean isClaimTxAndValid(Transaction newTx, String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(newTx, signatureCache)); byte[] key = HashUtil.keccak256(HexUtils.decode(HexUtils.stringToByteArray(swapHash + SWAPS_MAP_POSITION))); - AccountInformationProvider accountInformationProvider = web3InformationRetriever.getInformationProvider("latest"); + AccountInformationProvider accountInformationProvider = propertyGetter.getWeb3InfoRetriever().getInformationProvider("latest"); DataWord swapRecord = accountInformationProvider.getStorageValue(newTx.getReceiveAddress(), DataWord.valueOf(key)); if(swapRecord != null){ diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index 9ef400642ec..85077c7989b 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -18,6 +18,7 @@ */ package org.ethereum.core; +import co.rsk.PropertyGetter; import co.rsk.config.VmConfig; import co.rsk.core.Coin; import co.rsk.core.RskAddress; @@ -25,7 +26,6 @@ import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; import co.rsk.panic.PanicProcessor; -import co.rsk.rpc.Web3InformationRetriever; import co.rsk.rpc.modules.trace.ProgramSubtrace; import co.rsk.util.ContractUtil; import org.ethereum.config.Constants; @@ -103,14 +103,14 @@ public class TransactionExecutor { private boolean localCall = false; private boolean txWasPaid = false; - private Web3InformationRetriever web3InformationRetriever; + private PropertyGetter propertyGetter; public TransactionExecutor( Constants constants, ActivationConfig activationConfig, Transaction tx, int txindex, RskAddress coinbase, Repository track, BlockStore blockStore, ReceiptStore receiptStore, BlockFactory blockFactory, ProgramInvokeFactory programInvokeFactory, Block executionBlock, long gasUsedInTheBlock, VmConfig vmConfig, boolean remascEnabled, PrecompiledContracts precompiledContracts, Set deletedAccounts, - SignatureCache signatureCache, Web3InformationRetriever web3InformationRetriever) { + SignatureCache signatureCache, PropertyGetter propertyGetter) { this.constants = constants; this.signatureCache = signatureCache; this.activations = activationConfig.forBlock(executionBlock.getNumber()); @@ -129,7 +129,7 @@ public TransactionExecutor( this.precompiledContracts = precompiledContracts; this.enableRemasc = remascEnabled; this.deletedAccounts = new HashSet<>(deletedAccounts); - this.web3InformationRetriever = web3InformationRetriever; + this.propertyGetter = propertyGetter; } /** @@ -177,7 +177,7 @@ private boolean init() { Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); - if (!isCovers(senderBalance, totalCost) && !ContractUtil.isClaimTxAndValid(tx, totalCost,constants, signatureCache, web3InformationRetriever)) { + if (!isCovers(senderBalance, totalCost) && !ContractUtil.isClaimTxAndValid(tx, totalCost,constants, signatureCache, propertyGetter)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); diff --git a/rskj-core/src/test/java/co/rsk/core/CallContractTest.java b/rskj-core/src/test/java/co/rsk/core/CallContractTest.java index 7ac495685bf..5e6580afb67 100644 --- a/rskj-core/src/test/java/co/rsk/core/CallContractTest.java +++ b/rskj-core/src/test/java/co/rsk/core/CallContractTest.java @@ -82,7 +82,8 @@ private static ProgramResult callContract(World world, RskAddress receiveAddress blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, world.getBlockTxSignatureCache()), - world.getBlockTxSignatureCache() + world.getBlockTxSignatureCache(), + null ); org.ethereum.core.TransactionExecutor executor = transactionExecutorFactory diff --git a/rskj-core/src/test/java/co/rsk/core/TransactionTest.java b/rskj-core/src/test/java/co/rsk/core/TransactionTest.java index 1371ad6dba9..09d50cb43b6 100644 --- a/rskj-core/src/test/java/co/rsk/core/TransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/core/TransactionTest.java @@ -274,7 +274,8 @@ protected ProgramResult executeTransaction() { blockFactory, invokeFactory, precompiledContracts, - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null ); TransactionExecutor executor = transactionExecutorFactory .newInstance(txConst, 0, bestBlock.getCoinbase(), track, bestBlock, 0) diff --git a/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java b/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java index 726b7f329ac..f06042417a8 100644 --- a/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java @@ -867,7 +867,8 @@ private static BlockExecutor buildBlockExecutor(TrieStore store, RskSystemProper BLOCK_FACTORY, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - signatureCache + signatureCache, + null ) ); } diff --git a/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java b/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java index 3c797ca7e26..5e03d899115 100644 --- a/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java @@ -98,7 +98,8 @@ protected RepositoryLocator buildRepositoryLocator() { 10, 100, Mockito.mock(TxQuotaChecker.class), - Mockito.mock(GasPriceTracker.class)); + Mockito.mock(GasPriceTracker.class), + null); quotaChecker = mock(TxQuotaChecker.class); when(quotaChecker.acceptTx(any(), any(), any())).thenReturn(true); diff --git a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java index cdca5ceea1b..f7163d3bdf5 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java @@ -124,7 +124,8 @@ protected RepositoryLocator buildRepositoryLocator() { 10, 100, mock(TxQuotaChecker.class), - mock(GasPriceTracker.class)); + mock(GasPriceTracker.class), + null); transactionPool.processBest(standardBlockchain.getBestBlock()); diff --git a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java index 1d2f6641773..424fdcee066 100644 --- a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java @@ -102,7 +102,7 @@ void sendTransactionMustNotBeMined() { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, null, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); Web3Impl web3 = createEnvironment(blockchain, null, trieStore, transactionPool, blockStore, false, world.getBlockTxSignatureCache(), transactionGateway); @@ -129,7 +129,7 @@ void sendTransactionMustBeMined() { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, null, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); @@ -194,7 +194,7 @@ void sendRawTransactionWithAutoMining() throws Exception { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, receiptStore, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); Web3Impl web3 = createEnvironment(blockchain, receiptStore, trieStore, transactionPool, blockStore, true, world.getBlockTxSignatureCache(), transactionGateway); @@ -223,7 +223,7 @@ void sendRawTransactionWithoutAutoMining() { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, receiptStore, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); Web3Impl web3 = createEnvironment(blockchain, receiptStore, trieStore, transactionPool, blockStore, false, world.getBlockTxSignatureCache(), transactionGateway); @@ -261,7 +261,8 @@ void testGasEstimation() { 10, 100, Mockito.mock(TxQuotaChecker.class), - Mockito.mock(GasPriceTracker.class) + Mockito.mock(GasPriceTracker.class), + null ); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); @@ -698,7 +699,8 @@ private TransactionExecutorFactory buildTransactionExecutorFactory(BlockStore bl blockFactory, null, new PrecompiledContracts(config, bridgeSupportFactory(), signatureCache), - blockTxSignatureCache + blockTxSignatureCache, + null ); } @@ -710,7 +712,8 @@ private TransactionExecutorFactory buildTransactionExecutionFactoryWithProgramIn blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory(), signatureCache), - blockTxSignatureCache + blockTxSignatureCache, + null ); } diff --git a/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java b/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java index ecf2ecf37ed..21c67e4d9fc 100644 --- a/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java @@ -797,7 +797,8 @@ void processBodyResponseWithTransactionAddsToBlockchain() { blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null ) ); Assertions.assertEquals(1, block.getTransactionsList().size()); diff --git a/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java b/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java index 6966fceb7a0..625e3dab08b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java @@ -474,7 +474,8 @@ private BridgeState callGetStateForDebuggingTx() throws IOException { new BlockFactory(beforeBambooProperties.getActivationConfig()), new ProgramInvokeFactoryImpl(), new PrecompiledContracts(beforeBambooProperties, world.getBridgeSupportFactory(), world.getBlockTxSignatureCache()), - world.getBlockTxSignatureCache() + world.getBlockTxSignatureCache(), + null ); Repository track = repository.startTracking(); TransactionExecutor executor = transactionExecutorFactory diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java b/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java index d19c472efcc..a3143f0ea43 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java @@ -1038,7 +1038,8 @@ private BlockExecutor buildBlockExecutor(RepositoryLocator repositoryLocator, Bl blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null ) ); } diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java index d260406711a..f76d3bd13ad 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java @@ -493,7 +493,8 @@ void paysOnlyBlocksWithEnoughBalanceAccumulatedAfterRFS() { new BlockFactory(config.getActivationConfig()), new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null ) ); diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java b/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java index 635d3554edd..24ff7abf551 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java @@ -146,7 +146,8 @@ public void start() { blockFactory, programInvokeFactory, precompiledContracts, - blockTxSignatureCache + blockTxSignatureCache, + null ) ); Random random = new Random(RemascTestRunner.class.hashCode()); diff --git a/rskj-core/src/test/java/co/rsk/test/World.java b/rskj-core/src/test/java/co/rsk/test/World.java index ad909e61663..85f76c95fa8 100644 --- a/rskj-core/src/test/java/co/rsk/test/World.java +++ b/rskj-core/src/test/java/co/rsk/test/World.java @@ -183,7 +183,8 @@ public BlockExecutor getBlockExecutor() { new BlockFactory(config.getActivationConfig()), programInvokeFactory, new PrecompiledContracts(config, bridgeSupportFactory, blockTxSignatureCache), - blockTxSignatureCache + blockTxSignatureCache, + null ) ); } diff --git a/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java b/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java index c680bf60e3f..eea6631a15b 100644 --- a/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java +++ b/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java @@ -115,7 +115,8 @@ public Block build() { new BlockFactory(config.getActivationConfig()), new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, new BlockTxSignatureCache(new ReceivedTxSignatureCache())), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null ) ); executor.executeAndFill(block, parent.getHeader()); diff --git a/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java b/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java index 54c24e9d41f..afa659a3d6b 100644 --- a/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java +++ b/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java @@ -239,13 +239,14 @@ public BlockChainImpl build() { blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - blockTxSignatureCache + blockTxSignatureCache, + null ); repositoryLocator = new RepositoryLocator(trieStore, stateRootHandler); transactionPool = new TransactionPoolImpl( config, repositoryLocator, this.blockStore, blockFactory, new TestCompositeEthereumListener(), - transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); BlockExecutor blockExecutor = new BlockExecutor( config.getActivationConfig(), repositoryLocator, diff --git a/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java b/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java index 6536c1506a4..e1d072e8f76 100644 --- a/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java +++ b/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java @@ -323,7 +323,8 @@ private void processBlockChainCommand(DslCommand cmd) { new BlockFactory(config.getActivationConfig()), programInvokeFactory, null, - world.getBlockTxSignatureCache() + world.getBlockTxSignatureCache(), + null ) ); executor.executeAndFill(block, parent.getHeader()); diff --git a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java index 3b43caad28b..39030f8fb6b 100644 --- a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java @@ -1,5 +1,6 @@ package co.rsk.util; +import co.rsk.PropertyGetter; import co.rsk.core.Coin; import co.rsk.core.RskAddress; import co.rsk.core.bc.AccountInformationProvider; @@ -59,7 +60,9 @@ public void testIsClaimTxAndValid() { when(mockedAccountInformationProvider.getStorageValue(any(RskAddress.class), any(DataWord.class))) .thenReturn(DataWord.valueOf(1)); - boolean result = ContractUtil.isClaimTxAndValid(mockedTx, txCost, testConstans, signatureCache, mockedWeb3InformationRetriever); + PropertyGetter propertyGetter = () -> mockedWeb3InformationRetriever; + + boolean result = ContractUtil.isClaimTxAndValid(mockedTx, txCost, testConstans, signatureCache, propertyGetter); assertTrue(result); } diff --git a/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java b/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java index bc786fceae1..e70cd4108cd 100644 --- a/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java +++ b/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java @@ -103,7 +103,7 @@ public void processBlock( Block block, Block parent) { null, blockFactory, null, - new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), blockTxSignatureCache); + new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), blockTxSignatureCache, null); TransactionExecutor executor = transactionExecutorFactory .newInstance(tx, txindex++, block.getCoinbase(), track, block, totalGasUsed); diff --git a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java index f4119da5dec..645ad784b90 100644 --- a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -73,11 +73,12 @@ public static BlockChainImpl createBlockchain( blockFactory, new ProgramInvokeFactoryImpl(), null, - blockTxSignatureCache); + blockTxSignatureCache, + null); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); RepositoryLocator repositoryLocator = new RepositoryLocator(trieStore, stateRootHandler); - TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, receivedTxSignatureCache, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, receivedTxSignatureCache, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); BlockChainImpl blockchain = new BlockChainImpl( blockStore, diff --git a/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java b/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java index 7374a146754..4a6ea38a783 100644 --- a/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java @@ -495,7 +495,8 @@ protected ProgramResult executeTransaction() { blockFactory, invokeFactory, new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - signatureCache); + signatureCache, + null); TransactionExecutor executor = transactionExecutorFactory .newInstance(txConst, 0, bestBlock.getCoinbase(), track, bestBlock, 0) .setLocalCall(true); @@ -843,7 +844,8 @@ private TransactionExecutor executeTransaction( blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - blockTxSignatureCache); + blockTxSignatureCache, + null); TransactionExecutor executor = transactionExecutorFactory .newInstance(tx, 0, RskAddress.nullAddress(), repository, blockchain.getBestBlock(), 0); diff --git a/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java b/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java index 2f01f686168..ecfcee88fc8 100644 --- a/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java +++ b/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java @@ -150,11 +150,12 @@ public List runTestCase(BlockTestingCase testCase) { blockFactory, new ProgramInvokeFactoryImpl(), null, - blockTxSignatureCache); + blockTxSignatureCache, + null); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); RepositoryLocator repositoryLocator = new RepositoryLocator(trieStore, stateRootHandler); - TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); BlockChainImpl blockchain = new BlockChainImpl( blockStore, diff --git a/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java b/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java index dcd7877c3d6..2f624446e75 100644 --- a/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java +++ b/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java @@ -113,7 +113,8 @@ protected ProgramResult executeTransaction() { blockFactory, invokeFactory, precompiledContracts, - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null ); TransactionExecutor executor = transactionExecutorFactory.newInstance( transaction, @@ -147,25 +148,26 @@ public List runImpl() { BlockStore blockStore = new IndexedBlockStore(blockFactory, new HashMapDB(), new HashMapBlocksIndex()); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); blockchain = new BlockChainImpl( - blockStore, - null, - null, - null, - null, - new BlockExecutor( - config.getActivationConfig(), - new RepositoryLocator(trieStore, stateRootHandler), - new TransactionExecutorFactory( - config, - blockStore, - null, - blockFactory, - new ProgramInvokeFactoryImpl(), - precompiledContracts, - new BlockTxSignatureCache(new ReceivedTxSignatureCache()) - ) - ), - stateRootHandler + blockStore, + null, + null, + null, + null, + new BlockExecutor( + config.getActivationConfig(), + new RepositoryLocator(trieStore, stateRootHandler), + new TransactionExecutorFactory( + config, + blockStore, + null, + blockFactory, + new ProgramInvokeFactoryImpl(), + precompiledContracts, + new BlockTxSignatureCache(new ReceivedTxSignatureCache()), + null + ) + ), + stateRootHandler ); env = EnvBuilder.build(stateTestCase.getEnv()); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java index f23da51c182..05e01dc4d4f 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java @@ -908,7 +908,7 @@ void getPendingTransactionByHash() { BlockChainImpl blockChain = world.getBlockChain(); BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); - TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); transactionPool.processBest(blockChain.getBestBlock()); Web3Impl web3 = createWeb3(world, transactionPool, receiptStore); @@ -2518,7 +2518,7 @@ private void checkSendTransaction(Byte chainId) { BlockChainImpl blockChain = world.getBlockChain(); BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); - TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); Web3Impl web3 = createWeb3(world, transactionPool, receiptStore); // **** Initializes data ****************** @@ -2763,7 +2763,7 @@ private Web3Impl createWeb3(Ethereum eth, World world, ReceiptStore receiptStore BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, - blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); return createWeb3(eth, world, transactionPool, receiptStore); } @@ -2771,7 +2771,7 @@ private Web3Impl createWeb3CallNoReturn(Ethereum eth, World world, ReceiptStore BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, null); TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, - blockFactory, null, transactionExecutorFactory, null, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + blockFactory, null, transactionExecutorFactory, null, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); return createWeb3CallNoReturn(eth, world, transactionPool, receiptStore); } @@ -2796,7 +2796,7 @@ private Web3Impl createWeb3(World world, BlockProcessor blockProcessor, ReceiptS BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), - blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); + blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); RepositoryLocator repositoryLocator = new RepositoryLocator(world.getTrieStore(), world.getStateRootHandler()); return createWeb3( Web3Mocks.getMockEthereum(), blockChain, repositoryLocator, transactionPool, @@ -2947,7 +2947,8 @@ private TransactionExecutorFactory buildTransactionExecutorFactory( blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, null, signatureCache), - blockTxSignatureCache); + blockTxSignatureCache, + null); } private Block createChainWithOneBlock(World world) { diff --git a/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java b/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java index 1a80bcbff50..e672ba3fed7 100644 --- a/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java +++ b/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java @@ -97,7 +97,8 @@ public static TransactionExecutorFactory buildCustomExecutorFactory(World world, blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, world.getBridgeSupportFactory(), world.getBlockTxSignatureCache()), - blockTxSignatureCache + blockTxSignatureCache, + null ); } diff --git a/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java b/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java index dada3866b25..502f67d4163 100644 --- a/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java +++ b/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java @@ -205,6 +205,7 @@ private EthModule buildEthModule(World world) { null, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, world.getBridgeSupportFactory(), new BlockTxSignatureCache(new ReceivedTxSignatureCache())), + null, null ); From a0a4b6e08dfb6732e87d87abc4138e45bda75786 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Fri, 12 Apr 2024 08:34:51 -0400 Subject: [PATCH 04/21] Tests fixes --- rskj-core/src/main/java/co/rsk/util/ContractUtil.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java index f6256a0101e..88e7bc57c1c 100644 --- a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java @@ -96,9 +96,10 @@ public static boolean isClaimTxAndValid(Transaction newTx, Constants constants, SignatureCache signatureCache, PropertyGetter propertyGetter) { - byte[] functionSelector = Arrays.copyOfRange(newTx.getData(), 0, 4); - if(newTx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) - && Arrays.equals(functionSelector, Constants.CLAIM_FUNCTION_SIGNATURE)) { + if(newTx.getReceiveAddress() != null + && newTx.getData() != null + && newTx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) + && Arrays.equals(Arrays.copyOfRange(newTx.getData(), 0, 4), Constants.CLAIM_FUNCTION_SIGNATURE)) { String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(newTx, signatureCache)); byte[] key = HashUtil.keccak256(HexUtils.decode(HexUtils.stringToByteArray(swapHash + SWAPS_MAP_POSITION))); From 26b495da1eff78accee1ebec9370d1f94f478d13 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Thu, 18 Apr 2024 11:40:31 -0400 Subject: [PATCH 05/21] Automate tests and fix SonarCloud error --- .../java/co/rsk/EtherSwapTest.java | 160 ++++++++++++------ .../main/java/co/rsk/util/ContractUtil.java | 3 + 2 files changed, 111 insertions(+), 52 deletions(-) diff --git a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java index 10b1e473594..2e1108ee53c 100644 --- a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java +++ b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java @@ -19,9 +19,10 @@ package co.rsk; +import co.rsk.util.CommandLineFixture; import co.rsk.util.ContractUtil; import co.rsk.util.HexUtils; -import co.rsk.util.TestUtils; +import co.rsk.util.OkHttpClientTestFixture; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.squareup.okhttp.Response; @@ -30,12 +31,18 @@ import org.ethereum.crypto.HashUtil; import org.ethereum.util.ByteUtil; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.IOException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; public class EtherSwapTest { private static final int LOCAL_PORT = 4444; @@ -50,8 +57,35 @@ public class EtherSwapTest { new String[]{"bytes32", "uint256", "address", "uint256"}, new String[]{} ); - private final ObjectMapper objectMapper = new ObjectMapper(); + private String buildLibsPath; + private String jarName; + private String databaseDir; + @TempDir + private Path tempDir; + + private String[] baseArgs; + private String strBaseArgs; + private String baseJavaCmd; + + @BeforeEach + public void setup() throws IOException { + String projectPath = System.getProperty("user.dir"); + buildLibsPath = String.format("%s/build/libs", projectPath); + String integrationTestResourcesPath = String.format("%s/src/integrationTest/resources", projectPath); + String rskConfFile = String.format("%s/integration-test-rskj.conf", integrationTestResourcesPath); + Stream pathsStream = Files.list(Paths.get(buildLibsPath)); + jarName = pathsStream.filter(p -> !p.toFile().isDirectory()) + .map(p -> p.getFileName().toString()) + .filter(fn -> fn.endsWith("-all.jar")) + .findFirst() + .get(); + Path databaseDirPath = tempDir.resolve("database"); + databaseDir = databaseDirPath.toString(); + baseArgs = new String[]{"--regtest"}; + strBaseArgs = String.join(" ", baseArgs); + baseJavaCmd = String.format("java %s", String.format("-Drsk.conf.file=%s", rskConfFile)); + } private Response lockTxRequest(String refundAddress, byte[] lockData, BigInteger amount) throws IOException { String lockTxRequestContent = "[{\n" + @@ -68,7 +102,7 @@ private Response lockTxRequest(String refundAddress, byte[] lockData, BigInteger " \"jsonrpc\": \"2.0\"\n" + "}]"; - return TestUtils.sendJsonRpcMessage(lockTxRequestContent, LOCAL_PORT); + return OkHttpClientTestFixture.sendJsonRpcMessage(lockTxRequestContent, LOCAL_PORT); } private Response claimTxRequest(String claimAddress, byte[] claimData) throws IOException { @@ -86,7 +120,7 @@ private Response claimTxRequest(String claimAddress, byte[] claimData) throws IO " \"jsonrpc\": \"2.0\"\n" + "}]"; - return TestUtils.sendJsonRpcMessage(claimTxRequestContent, LOCAL_PORT); + return OkHttpClientTestFixture.sendJsonRpcMessage(claimTxRequestContent, LOCAL_PORT); } private Response getBalanceRequest(String address) throws IOException { @@ -100,7 +134,7 @@ private Response getBalanceRequest(String address) throws IOException { " \"jsonrpc\": \"2.0\"\n" + "}]"; - return TestUtils.sendJsonRpcMessage(getBalanceRequestContent, LOCAL_PORT); + return OkHttpClientTestFixture.sendJsonRpcMessage(getBalanceRequestContent, LOCAL_PORT); } private Response getTxReceiptRequest(String txHash) throws IOException { @@ -113,7 +147,7 @@ private Response getTxReceiptRequest(String txHash) throws IOException { " \"jsonrpc\": \"2.0\"\n" + "}]"; - return TestUtils.sendJsonRpcMessage(getReceiptRequestContent, LOCAL_PORT); + return OkHttpClientTestFixture.sendJsonRpcMessage(getReceiptRequestContent, LOCAL_PORT); } @Test @@ -135,25 +169,36 @@ void whenClaimTxIsSend_shouldShouldFailDueToLowFundsInContract() throws Exceptio refundAddress, 8000000); - - Response getBalanceResponse = getBalanceRequest(claimAddress); - JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); - JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); - BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); - Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); - - lockTxRequest(refundAddress, lockData, amount); - TimeUnit.SECONDS.sleep(5); - - claimTxRequest(claimAddress, claimData); - TimeUnit.SECONDS.sleep(5); - - getBalanceResponse = getBalanceRequest(claimAddress); - jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); - currentBalance = jsonRpcResponse.get(0).get("result"); - balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); - - Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + String cmd = String.format("%s -cp %s/%s co.rsk.Start --reset %s", baseJavaCmd, buildLibsPath, jarName, strBaseArgs); + CommandLineFixture.runCommand( + cmd, + 60, + TimeUnit.SECONDS, + proc -> { + try { + Response getBalanceResponse = getBalanceRequest(claimAddress); + JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); + BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + + lockTxRequest(refundAddress, lockData, amount); + TimeUnit.SECONDS.sleep(5); + + claimTxRequest(claimAddress, claimData); + TimeUnit.SECONDS.sleep(5); + + getBalanceResponse = getBalanceRequest(claimAddress); + jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + currentBalance = jsonRpcResponse.get(0).get("result"); + balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + } catch (IOException | InterruptedException e) { + Assertions.fail(e); + } + } + ); } @@ -176,32 +221,43 @@ void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { refundAddress, 8000000); - - Response getBalanceResponse = getBalanceRequest(claimAddress); - JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); - JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); - BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); - Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); - - lockTxRequest(refundAddress, lockData, amount); - TimeUnit.SECONDS.sleep(5); - - Response claimResponse = claimTxRequest(claimAddress, claimData); - TimeUnit.SECONDS.sleep(5); - - jsonRpcResponse = objectMapper.readTree(claimResponse.body().string()); - JsonNode claimTxHash = jsonRpcResponse.get(0).get("result"); - - Response getTxReceiptResponse = getTxReceiptRequest(claimTxHash.asText()); - jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); - JsonNode gasUsed = jsonRpcResponse.get(0).get("result").get("gasUsed"); - BigInteger expectedBalance = amount.subtract(new BigInteger(HexUtils.removeHexPrefix(gasUsed.asText()), 16)); - - getBalanceResponse = getBalanceRequest(claimAddress); - jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); - currentBalance = jsonRpcResponse.get(0).get("result"); - balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); - - Assertions.assertEquals(0, balanceBigInt.compareTo(expectedBalance)); + String cmd = String.format("%s -cp %s/%s co.rsk.Start --reset %s", baseJavaCmd, buildLibsPath, jarName, strBaseArgs); + CommandLineFixture.runCommand( + cmd, + 60, + TimeUnit.SECONDS, + proc -> { + try { + Response getBalanceResponse = getBalanceRequest(claimAddress); + JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); + BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + + Response lockResponse = lockTxRequest(refundAddress, lockData, amount); + TimeUnit.SECONDS.sleep(5); + + Response claimResponse = claimTxRequest(claimAddress, claimData); + TimeUnit.SECONDS.sleep(5); + + jsonRpcResponse = objectMapper.readTree(claimResponse.body().string()); + JsonNode claimTxHash = jsonRpcResponse.get(0).get("result"); + + Response getTxReceiptResponse = getTxReceiptRequest(claimTxHash.asText()); + jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); + JsonNode gasUsed = jsonRpcResponse.get(0).get("result").get("gasUsed"); + BigInteger expectedBalance = amount.subtract(new BigInteger(HexUtils.removeHexPrefix(gasUsed.asText()), 16)); + + getBalanceResponse = getBalanceRequest(claimAddress); + jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + currentBalance = jsonRpcResponse.get(0).get("result"); + balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + + Assertions.assertEquals(0, balanceBigInt.compareTo(expectedBalance)); + } catch (IOException | InterruptedException e) { + Assertions.fail(e); + } + } + ); } } diff --git a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java index 88e7bc57c1c..eec11a42864 100644 --- a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java @@ -37,6 +37,9 @@ public class ContractUtil { private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; + private ContractUtil() { + throw new IllegalStateException("Utility class"); + } public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatureCache) { From d9b20192537464becfec9979ad34236c690f7de6 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Mon, 13 May 2024 12:32:21 -0400 Subject: [PATCH 06/21] Adding ClaimTransactionInfoHolder class and covering edge cases --- .../java/co/rsk/EtherSwapTest.java | 145 +++++++++++- .../src/main/java/co/rsk/PropertyGetter.java | 7 - .../src/main/java/co/rsk/RskContext.java | 12 +- .../rsk/core/TransactionExecutorFactory.java | 9 +- .../java/co/rsk/core/bc/BlockExecutor.java | 19 +- .../core/bc/ClaimTransactionInfoHolder.java | 113 ++++++++++ .../co/rsk/core/bc/TransactionPoolImpl.java | 31 ++- .../src/main/java/co/rsk/mine/MinerUtils.java | 13 ++ .../rsk/net/handler/TxPendingValidator.java | 11 +- .../txvalidator/TxNotNullValidator.java | 7 + .../TxValidatorAccountBalanceValidator.java | 25 +-- .../TxValidatorAccountStateValidator.java | 6 + .../TxValidatorGasLimitValidator.java | 6 + ...TxValidatorIntrinsicGasLimitValidator.java | 6 + .../TxValidatorMaximumGasPriceValidator.java | 6 + .../TxValidatorMinimuGasPriceValidator.java | 6 + .../TxValidatorNonceRangeValidator.java | 6 + .../TxValidatorNotRemascTxValidator.java | 6 + .../handler/txvalidator/TxValidatorStep.java | 4 +- .../main/java/co/rsk/util/ContractUtil.java | 125 ----------- .../main/java/co/rsk/util/EthSwapUtil.java | 210 ++++++++++++++++++ .../ethereum/core/TransactionExecutor.java | 19 +- .../java/co/rsk/core/CallContractTest.java | 3 +- .../java/co/rsk/core/TransactionTest.java | 3 +- .../co/rsk/core/bc/BlockExecutorTest.java | 83 ++++++- .../rsk/core/bc/TransactionPoolImplTest.java | 3 +- .../java/co/rsk/mine/MinerServerTest.java | 3 +- .../co/rsk/mine/TransactionModuleTest.java | 21 +- .../java/co/rsk/net/SyncProcessorTest.java | 7 +- ...xValidatorAccountBalanceValidatorTest.java | 18 +- .../java/co/rsk/peg/RskForksBridgeTest.java | 3 +- .../remasc/RemascProcessMinerFeesTest.java | 7 +- .../rsk/remasc/RemascStorageProviderTest.java | 7 +- .../java/co/rsk/remasc/RemascTestRunner.java | 7 +- .../src/test/java/co/rsk/test/World.java | 7 +- .../co/rsk/test/builders/BlockBuilder.java | 8 +- .../rsk/test/builders/BlockChainBuilder.java | 9 +- .../co/rsk/test/dsl/WorldDslProcessor.java | 7 +- .../java/co/rsk/util/ContractUtilTest.java | 92 -------- .../java/co/rsk/util/EthSwapUtilTest.java | 169 ++++++++++++++ .../src/test/java/co/rsk/vm/MinerHelper.java | 2 +- .../org/ethereum/core/ImportLightTest.java | 9 +- .../core/TransactionExecutorTest.java | 8 +- .../org/ethereum/core/TransactionTest.java | 6 +- .../ethereum/jsontestsuite/TestRunner.java | 9 +- .../runners/StateTestRunner.java | 11 +- .../java/org/ethereum/rpc/Web3ImplTest.java | 13 +- .../org/ethereum/util/EthModuleTestUtils.java | 3 +- .../vm/program/NestedContractsTest.java | 1 - 49 files changed, 937 insertions(+), 374 deletions(-) delete mode 100644 rskj-core/src/main/java/co/rsk/PropertyGetter.java create mode 100644 rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java delete mode 100644 rskj-core/src/main/java/co/rsk/util/ContractUtil.java create mode 100644 rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java delete mode 100644 rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java create mode 100644 rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java diff --git a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java index 2e1108ee53c..0e9192df168 100644 --- a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java +++ b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java @@ -20,7 +20,7 @@ package co.rsk; import co.rsk.util.CommandLineFixture; -import co.rsk.util.ContractUtil; +import co.rsk.util.EthSwapUtil; import co.rsk.util.HexUtils; import co.rsk.util.OkHttpClientTestFixture; import com.fasterxml.jackson.databind.JsonNode; @@ -155,7 +155,7 @@ void whenClaimTxIsSend_shouldShouldFailDueToLowFundsInContract() throws Exceptio String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] preimageHash = HashUtil.sha256(ContractUtil.encodePacked(preimage)); + byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); BigInteger amount = BigInteger.valueOf(5000); byte[] lockData = CALL_LOCK_FUNCTION.encode( @@ -207,7 +207,7 @@ void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] preimageHash = HashUtil.sha256(ContractUtil.encodePacked(preimage)); + byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); BigInteger amount = BigInteger.valueOf(500000); byte[] lockData = CALL_LOCK_FUNCTION.encode( @@ -234,7 +234,7 @@ void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); - Response lockResponse = lockTxRequest(refundAddress, lockData, amount); + lockTxRequest(refundAddress, lockData, amount); TimeUnit.SECONDS.sleep(5); Response claimResponse = claimTxRequest(claimAddress, claimData); @@ -260,4 +260,141 @@ void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { } ); } + + @Test + void whenClaimTxIsSentTwice_secondClaimTxShoulNotBeIncludedInMempool() throws Exception { + String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; + String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; + byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); + byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); + BigInteger amount = BigInteger.valueOf(500000); + + byte[] lockData = CALL_LOCK_FUNCTION.encode( + preimageHash, + claimAddress, + 8000000); + + byte[] claimData = CALL_CLAIM_FUNCTION.encode( + preimage, + amount, + refundAddress, + 8000000); + + String cmd = String.format("%s -cp %s/%s co.rsk.Start --reset %s", baseJavaCmd, buildLibsPath, jarName, strBaseArgs); + CommandLineFixture.runCommand( + cmd, + 60, + TimeUnit.SECONDS, + proc -> { + try { + Response getBalanceResponse = getBalanceRequest(claimAddress); + JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); + BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + + lockTxRequest(refundAddress, lockData, amount); + TimeUnit.SECONDS.sleep(5); + + Response claimResponse = claimTxRequest(claimAddress, claimData); + Response duplicatedClaimResponse = claimTxRequest(claimAddress, claimData); + TimeUnit.SECONDS.sleep(5); + + jsonRpcResponse = objectMapper.readTree(claimResponse.body().string()); + JsonNode claimTxHash = jsonRpcResponse.get(0).get("result"); + + Assertions.assertNotNull(claimTxHash); + + jsonRpcResponse = objectMapper.readTree(duplicatedClaimResponse.body().string()); + JsonNode duplicatedClaimTxHash = jsonRpcResponse.get(0).get("result"); + + Assertions.assertNull(duplicatedClaimTxHash); + } catch (IOException | InterruptedException e) { + Assertions.fail(e); + } + } + ); + } + + @Test + void whenTwoClaimTxAreSent_shouldCombineBothLockedAmountsToPayBothTx() throws Exception { + String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; + String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; + byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); + byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); + BigInteger firstLockedAmount = BigInteger.valueOf(500000); + BigInteger secondLockedAmount = BigInteger.valueOf(5000); + + byte[] lockData = CALL_LOCK_FUNCTION.encode( + preimageHash, + claimAddress, + 8000000); + + byte[] firstClaimTxData = CALL_CLAIM_FUNCTION.encode( + preimage, + firstLockedAmount, + refundAddress, + 8000000); + + byte[] secondClaimTxData = CALL_CLAIM_FUNCTION.encode( + preimage, + secondLockedAmount, + refundAddress, + 8000000); + + String cmd = String.format("%s -cp %s/%s co.rsk.Start --reset %s", baseJavaCmd, buildLibsPath, jarName, strBaseArgs); + CommandLineFixture.runCommand( + cmd, + 60, + TimeUnit.SECONDS, + proc -> { + try { + Response getBalanceResponse = getBalanceRequest(claimAddress); + JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); + BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); + + lockTxRequest(refundAddress, lockData, firstLockedAmount); + lockTxRequest(refundAddress, lockData, secondLockedAmount); + TimeUnit.SECONDS.sleep(5); + + Response firstClaimTxResponse = claimTxRequest(claimAddress, firstClaimTxData); + Response secondClaimTxResponse = claimTxRequest(claimAddress, secondClaimTxData); + TimeUnit.SECONDS.sleep(5); + + // Get gas used by first claim tx + jsonRpcResponse = objectMapper.readTree(firstClaimTxResponse.body().string()); + JsonNode firstClaimTxHash = jsonRpcResponse.get(0).get("result"); + + Response getTxReceiptResponse = getTxReceiptRequest(firstClaimTxHash.asText()); + jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); + BigInteger firstClaimTxGasUsed = new BigInteger(HexUtils.removeHexPrefix(jsonRpcResponse.get(0).get("result").get("gasUsed").asText()), 16); + + // Get gas used by second claim tx + jsonRpcResponse = objectMapper.readTree(secondClaimTxResponse.body().string()); + JsonNode secondClaimTxHash = jsonRpcResponse.get(0).get("result"); + + getTxReceiptResponse = getTxReceiptRequest(secondClaimTxHash.asText()); + jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); + BigInteger secondClaimTxGasUsed = new BigInteger(HexUtils.removeHexPrefix(jsonRpcResponse.get(0).get("result").get("gasUsed").asText()), 16); + + // Add both locked amounts and subtract the total gas used to get the expected account balance + BigInteger totalGasUsed = firstClaimTxGasUsed.add(secondClaimTxGasUsed); + BigInteger expectedBalance = firstLockedAmount.add(secondLockedAmount).subtract(totalGasUsed); + + getBalanceResponse = getBalanceRequest(claimAddress); + jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); + currentBalance = jsonRpcResponse.get(0).get("result"); + balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); + + Assertions.assertEquals(0, balanceBigInt.compareTo(expectedBalance)); + + + } catch (IOException | InterruptedException e) { + Assertions.fail(e); + } + } + ); + } } diff --git a/rskj-core/src/main/java/co/rsk/PropertyGetter.java b/rskj-core/src/main/java/co/rsk/PropertyGetter.java deleted file mode 100644 index 2659b9e521a..00000000000 --- a/rskj-core/src/main/java/co/rsk/PropertyGetter.java +++ /dev/null @@ -1,7 +0,0 @@ -package co.rsk; - -import co.rsk.rpc.Web3InformationRetriever; - -public interface PropertyGetter { - Web3InformationRetriever getWeb3InfoRetriever(); -} diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index 2ffed355ac5..bfe493dddb5 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -257,8 +257,6 @@ public class RskContext implements NodeContext, NodeBootstrapper { private volatile boolean closed; - private final PropertyGetter propertyGetter = this::getWeb3InformationRetriever; - /***** Constructors ***********************************************************************************************/ public RskContext(String[] args) { RskCli rskCli = new RskCli(); @@ -389,8 +387,7 @@ public synchronized TransactionPool getTransactionPool() { rskSystemProperties.txOutdatedThreshold(), rskSystemProperties.txOutdatedTimeout(), getTxQuotaChecker(), - getGasPriceTracker(), - propertyGetter); + getGasPriceTracker()); } return transactionPool; @@ -482,7 +479,9 @@ public synchronized BlockExecutor getBlockExecutor() { blockExecutor = new BlockExecutor( getRskSystemProperties().getActivationConfig(), getRepositoryLocator(), - getTransactionExecutorFactory() + getTransactionExecutorFactory(), + getRskSystemProperties().getNetworkConstants(), + getBlockTxSignatureCache() ); } @@ -592,8 +591,7 @@ public synchronized TransactionExecutorFactory getTransactionExecutorFactory() { getBlockFactory(), getProgramInvokeFactory(), getPrecompiledContracts(), - getBlockTxSignatureCache(), - propertyGetter + getBlockTxSignatureCache() ); } diff --git a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java index a0e896e6845..fb500c9afcd 100644 --- a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java +++ b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java @@ -18,7 +18,6 @@ package co.rsk.core; -import co.rsk.PropertyGetter; import co.rsk.config.RskSystemProperties; import co.rsk.config.VmConfig; import org.ethereum.core.*; @@ -40,7 +39,6 @@ public class TransactionExecutorFactory { private final ProgramInvokeFactory programInvokeFactory; private final PrecompiledContracts precompiledContracts; private BlockTxSignatureCache blockTxSignatureCache; - private PropertyGetter propertyGetter; public TransactionExecutorFactory( RskSystemProperties config, @@ -49,8 +47,7 @@ public TransactionExecutorFactory( BlockFactory blockFactory, ProgramInvokeFactory programInvokeFactory, PrecompiledContracts precompiledContracts, - BlockTxSignatureCache blockTxSignatureCache, - PropertyGetter propertyGetter) { + BlockTxSignatureCache blockTxSignatureCache) { this.config = config; this.blockStore = blockStore; this.receiptStore = receiptStore; @@ -58,7 +55,6 @@ public TransactionExecutorFactory( this.programInvokeFactory = programInvokeFactory; this.precompiledContracts = precompiledContracts; this.blockTxSignatureCache = blockTxSignatureCache; - this.propertyGetter = propertyGetter; } public TransactionExecutor newInstance( @@ -113,8 +109,7 @@ public TransactionExecutor newInstance( config.isRemascEnabled(), precompiledContracts, deletedAccounts, - blockTxSignatureCache, - propertyGetter + blockTxSignatureCache ); } } diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java index 7f41ae18bd7..12c1f5b5393 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java @@ -26,7 +26,9 @@ import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; +import co.rsk.util.EthSwapUtil; import com.google.common.annotations.VisibleForTesting; +import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; @@ -62,13 +64,20 @@ public class BlockExecutor { private final Map transactionResults = new HashMap<>(); private boolean registerProgramResults; + private final Constants constants; + private final SignatureCache signatureCache; + public BlockExecutor( ActivationConfig activationConfig, RepositoryLocator repositoryLocator, - TransactionExecutorFactory transactionExecutorFactory) { + TransactionExecutorFactory transactionExecutorFactory, + Constants constants, + SignatureCache signatureCache) { this.repositoryLocator = repositoryLocator; this.transactionExecutorFactory = transactionExecutorFactory; this.activationConfig = activationConfig; + this.constants = constants; + this.signatureCache = signatureCache; } /** @@ -282,6 +291,14 @@ private BlockResult executeInternal( for (Transaction tx : block.getTransactionsList()) { logger.trace("apply block: [{}] tx: [{}] ", block.getNumber(), i); + if (EthSwapUtil.isClaimTx(tx, constants) + && !EthSwapUtil.hasLockedFunds(tx,signatureCache, track)) { + logger.warn("block: [{}] discarded claim tx: [{}], because the funds it tries to claim no longer exist in contract", + block.getNumber(), + tx.getHash()); + continue; + } + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance( tx, txindex++, diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java new file mode 100644 index 00000000000..4dfe2b29561 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java @@ -0,0 +1,113 @@ +package co.rsk.core.bc; + +import co.rsk.core.Coin; +import co.rsk.db.RepositorySnapshot; +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.core.AccountState; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigInteger; +import java.util.Objects; + +public class ClaimTransactionInfoHolder { + @Nonnull + private final Transaction tx; + + @Nonnull + private final RepositorySnapshot repositorySnapshot; + + @Nonnull + private final SignatureCache signatureCache; + + @Nonnull + private final Constants constants; + + @Nullable + private final AccountState accountState; + + @Nullable + private final ActivationConfig.ForBlock activation; + + private Coin txUserBalance; + + public ClaimTransactionInfoHolder(@Nonnull Transaction tx, + @Nonnull RepositorySnapshot repositorySnapshot, + @Nonnull SignatureCache signatureCache, + @Nonnull Constants constants, + @Nullable ActivationConfig.ForBlock activation) { + this.tx = Objects.requireNonNull(tx); + this.repositorySnapshot = Objects.requireNonNull(repositorySnapshot); + this.signatureCache = Objects.requireNonNull(signatureCache); + this.constants = Objects.requireNonNull(constants); + this.accountState = repositorySnapshot.getAccountState(signatureCache.getSender(tx)); + this.activation = activation; + } + + @Nonnull + private Coin getSenderBalance() { + return accountState == null ? Coin.ZERO : accountState.getBalance(); + } + + @Nonnull + private Coin getTxUserBalance() { + if (txUserBalance == null) { + txUserBalance = repositorySnapshot.getBalance(tx.getSender(signatureCache)); + } + return txUserBalance; + } + + public boolean accountExists() { + return accountState != null; + } + + @Nonnull + public BigInteger getAccountNonce() { + return accountState == null ? BigInteger.ZERO : accountState.getNonce(); + } + + public boolean canPayForTx() { + Coin txCost = tx.getGasPrice().multiply(tx.getGasLimitAsInteger()); + + Coin senderB = getSenderBalance(); + if (senderB.compareTo(txCost) >= 0) { + return true; + } + + Coin txUserB = getTxUserBalance(); + return txUserB.add(senderB).compareTo(txCost) >= 0; + } + + @Nonnull + public Transaction getTx() { + return tx; + } + + @Nonnull + public RepositorySnapshot getRepositorySnapshot() { + return repositorySnapshot; + } + + @Nonnull + public SignatureCache getSignatureCache() { + return signatureCache; + } + + @Nonnull + public Constants getConstants() { + return constants; + } + + @Nullable + public AccountState getAccountState() { + return accountState; + } + + @Nullable + public ActivationConfig.ForBlock getActivation() { + return activation; + } +} 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 d137a6bf7b2..ee1ff808090 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 @@ -17,7 +17,6 @@ */ package co.rsk.core.bc; -import co.rsk.PropertyGetter; import co.rsk.config.RskSystemProperties; import co.rsk.core.Coin; import co.rsk.core.TransactionExecutorFactory; @@ -27,7 +26,7 @@ import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.TxPendingValidator; import co.rsk.net.handler.quota.TxQuotaChecker; -import co.rsk.util.ContractUtil; +import co.rsk.util.EthSwapUtil; import com.google.common.annotations.VisibleForTesting; import org.ethereum.core.*; import org.ethereum.db.BlockStore; @@ -82,10 +81,8 @@ public class TransactionPoolImpl implements TransactionPool { private final GasPriceTracker gasPriceTracker; - private PropertyGetter propertyGetter; - @java.lang.SuppressWarnings("squid:S107") - public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator repositoryLocator, BlockStore blockStore, BlockFactory blockFactory, EthereumListener listener, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache, int outdatedThreshold, int outdatedTimeout, TxQuotaChecker txQuotaChecker, GasPriceTracker gasPriceTracker, PropertyGetter propertyGetter) { + public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator repositoryLocator, BlockStore blockStore, BlockFactory blockFactory, EthereumListener listener, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache, int outdatedThreshold, int outdatedTimeout, TxQuotaChecker txQuotaChecker, GasPriceTracker gasPriceTracker) { this.config = config; this.blockStore = blockStore; this.repositoryLocator = repositoryLocator; @@ -97,7 +94,6 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit this.outdatedTimeout = outdatedTimeout; this.quotaChecker = txQuotaChecker; this.gasPriceTracker = gasPriceTracker; - this.propertyGetter = propertyGetter; pendingTransactions = new TransactionSet(this.signatureCache); queuedTransactions = new TransactionSet(this.signatureCache); @@ -106,8 +102,7 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit this.config.getNetworkConstants(), this.config.getActivationConfig(), this.config.getNumOfAccountSlots(), - signatureCache, - this.propertyGetter); + signatureCache); if (this.outdatedTimeout > 0) { this.cleanerTimer = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "TransactionPoolCleanerTimer")); @@ -466,7 +461,15 @@ private Block createFakePendingBlock(Block best) { } private TransactionValidationResult shouldAcceptTx(Transaction tx, RepositorySnapshot currentRepository) { - return validator.isValid(tx, bestBlock, currentRepository.getAccountState(tx.getSender(signatureCache))); + ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( + tx, + currentRepository, + signatureCache, + config.getNetworkConstants(), + bestBlock == null ? null : config.getActivationConfig().forBlock(bestBlock.getNumber()) + ); + + return validator.isValid(tx, bestBlock, currentRepository.getAccountState(tx.getSender(signatureCache)), claimTransactionInfoHolder); } /** @@ -493,7 +496,15 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos return true; } - return ContractUtil.isClaimTxAndValid(newTx, costWithNewTx, config.getNetworkConstants(), signatureCache, this.propertyGetter); + ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( + newTx, + currentRepository, + signatureCache, + config.getNetworkConstants(), + bestBlock == null ? null : config.getActivationConfig().forBlock(bestBlock.getNumber()) + ); + + return EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(claimTransactionInfoHolder, transactions); } private Coin getTxBaseCost(Transaction tx) { 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 30f7fd0be8e..6045426564d 100644 --- a/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java +++ b/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java @@ -26,9 +26,11 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.RepositorySnapshot; import co.rsk.remasc.RemascTransaction; +import co.rsk.util.EthSwapUtil; import co.rsk.util.HexUtils; import co.rsk.validators.TxGasPriceCap; import org.bouncycastle.util.Arrays; +import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.SignatureCache; @@ -170,6 +172,10 @@ public List getAllTransactions(TransactionPool tr } public List filterTransactions(List txsToRemove, List txs, Map accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice, boolean isRskip252Enabled, SignatureCache signatureCache) { + return filterTransactions(txsToRemove, txs, accountNonces, originalRepo, minGasPrice, isRskip252Enabled, signatureCache, null); + } + + public List filterTransactions(List txsToRemove, List txs, Map accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice, boolean isRskip252Enabled, SignatureCache signatureCache, Constants constants) { List txsResult = new ArrayList<>(); for (org.ethereum.core.Transaction tx : txs) { try { @@ -187,6 +193,13 @@ public List filterTransactions(List expectedNonce = originalRepo.getNonce(txSender); } + if (EthSwapUtil.isClaimTx(tx, constants) + && !EthSwapUtil.hasLockedFunds(tx, signatureCache, originalRepo)) { + txsToRemove.add(tx); + logger.warn("Rejected tx={} because the funds is trying to claim no longer exist, removing tx from pending state.", hash); + continue; + } + if (isLowGasPriced(minGasPrice, tx)) { txsToRemove.add(tx); logger.warn("Rejected tx={} because of low gas account {}, removing tx from pending state.", hash, txSender); 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 16fa147c66d..cf6e1b81936 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 @@ -17,8 +17,8 @@ */ package co.rsk.net.handler; -import co.rsk.PropertyGetter; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.txvalidator.*; import org.bouncycastle.util.BigIntegers; @@ -53,7 +53,7 @@ public class TxPendingValidator { private final SignatureCache signatureCache; - public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache, PropertyGetter propertyGetter) { + public TxPendingValidator(Constants constants, ActivationConfig activationConfig, int accountSlots, SignatureCache signatureCache) { this.constants = constants; this.activationConfig = activationConfig; this.signatureCache = signatureCache; @@ -61,16 +61,15 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig validatorSteps.add(new TxNotNullValidator()); validatorSteps.add(new TxValidatorNotRemascTxValidator()); validatorSteps.add(new TxValidatorGasLimitValidator()); - validatorSteps.add(new TxValidatorAccountStateValidator()); validatorSteps.add(new TxValidatorNonceRangeValidator(accountSlots)); - validatorSteps.add(new TxValidatorAccountBalanceValidator(constants, signatureCache, propertyGetter)); + validatorSteps.add(new TxValidatorAccountBalanceValidator()); validatorSteps.add(new TxValidatorMinimuGasPriceValidator()); validatorSteps.add(new TxValidatorIntrinsicGasLimitValidator(constants, activationConfig, signatureCache)); validatorSteps.add(new TxValidatorMaximumGasPriceValidator(activationConfig)); } - public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state) { + public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state, ClaimTransactionInfoHolder claimTransactionInfoHolder) { BigInteger blockGasLimit = BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit()); Coin minimumGasPrice = executionBlock.getMinimumGasPrice(); long bestBlockNumber = executionBlock.getNumber(); @@ -88,7 +87,7 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock, } for (TxValidatorStep step : validatorSteps) { - TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0); + TransactionValidationResult validationResult = step.validate(tx, claimTransactionInfoHolder, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0); if (!validationResult.transactionIsValid()) { logger.info("[tx={}] validation failed with error: {}", tx.getHash(), validationResult.getErrorMessage()); return validationResult; diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java index e8ed9f558d3..878079cf5fe 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -33,6 +34,11 @@ */ public class TxNotNullValidator implements TxValidatorStep { + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return this.validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (tx != null) { @@ -42,4 +48,5 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta return TransactionValidationResult.withError("transaction is null"); } + } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index 7035545c2e5..641867f0a33 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -18,13 +18,11 @@ package co.rsk.net.handler.txvalidator; -import co.rsk.PropertyGetter; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; -import co.rsk.util.ContractUtil; -import org.ethereum.config.Constants; +import co.rsk.util.EthSwapUtil; import org.ethereum.core.AccountState; -import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; import javax.annotation.Nullable; @@ -34,19 +32,8 @@ * Checks if an account can pay the transaction execution cost */ public class TxValidatorAccountBalanceValidator implements TxValidatorStep { - - private final Constants constants; - private final SignatureCache signatureCache; - private final PropertyGetter propertyGetter; - - public TxValidatorAccountBalanceValidator(Constants constants, SignatureCache signatureCache, PropertyGetter propertyGetter) { - this.constants = constants; - this.signatureCache = signatureCache; - this.propertyGetter = propertyGetter; - } - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (isFreeTx) { return TransactionValidationResult.ok(); } @@ -58,11 +45,15 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); if (state.getBalance().compareTo(maximumPrice) >= 0 - || ContractUtil.isClaimTxAndValid(tx, maximumPrice, constants, signatureCache, propertyGetter)) { + || EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder, maximumPrice)) { return TransactionValidationResult.ok(); } return TransactionValidationResult.withError("insufficient funds"); } + @Override + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return TransactionValidationResult.ok(); + } } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java index 5d7b1cd37ed..16c3555b31a 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -31,6 +32,11 @@ */ public class TxValidatorAccountStateValidator implements TxValidatorStep { + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (isFreeTx) { diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java index 95e89038084..5c6bc6bb065 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; import org.ethereum.core.AccountState; @@ -33,6 +34,11 @@ * Also Checks that the transaction gas limit is not higher than the max allowed value */ public class TxValidatorGasLimitValidator implements TxValidatorStep { + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { BigInteger txGasLimit = tx.getGasLimitAsInteger(); 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 6ac70394496..33683222a36 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 @@ -18,6 +18,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -45,6 +46,11 @@ public TxValidatorIntrinsicGasLimitValidator( this.signatureCache = signatureCache; } + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @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), signatureCache)).compareTo(tx.getGasLimitAsInteger()) <= 0) { diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java index 71de3cd7bdf..27b0a6ddc13 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import co.rsk.validators.TxGasPriceCap; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -40,6 +41,11 @@ public TxValidatorMaximumGasPriceValidator(ActivationConfig activationConfig) { this.activationConfig = activationConfig; } + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { boolean isRskip252Enabled = activationConfig.isActive(ConsensusRule.RSKIP252, bestBlockNumber); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java index d0d068ea5ef..03ea5172b09 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -30,6 +31,11 @@ * Created by maty on 06/03/17. */ public class TxValidatorMinimuGasPriceValidator implements TxValidatorStep { + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { Coin gasPrice = tx.getGasPrice(); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java index ca1028f8cb7..0a9c898b695 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -41,6 +42,11 @@ public TxValidatorNonceRangeValidator(int accountSlots) { this.accountSlots = BigInteger.valueOf(accountSlots); } + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { BigInteger nonce = tx.getNonceAsInteger(); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java index a1231b6c490..ee647882a48 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import co.rsk.remasc.RemascTransaction; import org.ethereum.core.AccountState; @@ -33,6 +34,11 @@ * Transaction must not be null */ public class TxValidatorNotRemascTxValidator implements TxValidatorStep { + @Override + public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); + } + @Override public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (!(tx instanceof RemascTransaction)) { diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java index 992165e2def..cd5f320d185 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -32,6 +33,7 @@ */ public interface TxValidatorStep { - TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); + TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); + TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java b/rskj-core/src/main/java/co/rsk/util/ContractUtil.java deleted file mode 100644 index eec11a42864..00000000000 --- a/rskj-core/src/main/java/co/rsk/util/ContractUtil.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file is part of RskJ - * Copyright (C) 2024 RSK Labs Ltd. - * (derived from ethereumJ library, Copyright (c) 2016 ) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package co.rsk.util; - -import co.rsk.PropertyGetter; -import co.rsk.core.Coin; -import co.rsk.core.RskAddress; -import co.rsk.core.bc.AccountInformationProvider; -import org.ethereum.config.Constants; -import org.ethereum.core.CallTransaction; -import org.ethereum.core.SignatureCache; -import org.ethereum.core.Transaction; -import org.ethereum.crypto.HashUtil; -import org.ethereum.solidity.SolidityType; -import org.ethereum.util.ByteUtil; -import org.ethereum.vm.DataWord; - -import java.math.BigInteger; -import java.util.Arrays; - -public class ContractUtil { - private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; - - private ContractUtil() { - throw new IllegalStateException("Utility class"); - } - - public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatureCache) { - - CallTransaction.Invocation invocation = getTxInvocation(newTx); - - // Get arguments from the invocation object - byte[] preimage = (byte[]) invocation.args[0]; - byte[] preimageHash = HashUtil.sha256(encodePacked(preimage)); - BigInteger amount = (BigInteger) invocation.args[1]; - DataWord refundAddress = (DataWord) invocation.args[2]; - BigInteger timeLock = (BigInteger) invocation.args[3]; - - - // Remove the leading zeroes from the arguments bytes and merge them - byte[] argumentsBytes = encodePacked( - preimageHash, - amount, - newTx.getSender(signatureCache), - new RskAddress(ByteUtil.toHexString(refundAddress.getLast20Bytes())), - timeLock - ); - - return HashUtil.keccak256(argumentsBytes); - } - - public static byte[] encodePacked(Object...arguments) { - byte[] encodedArguments = new byte[]{}; - - for(Object arg: arguments) { - byte[] encodedArg = new byte[]{}; - if(arg instanceof byte[]) { - SolidityType bytes32Type = SolidityType.getType(SolidityType.BYTES32); - encodedArg = bytes32Type.encode(arg); - } else if(arg instanceof RskAddress) { - SolidityType addressType = SolidityType.getType(SolidityType.ADDRESS); - byte[] encodedAddress = addressType.encode(((RskAddress) arg).toHexString()); - encodedArg = org.bouncycastle.util.Arrays.copyOfRange(encodedAddress, 12, encodedAddress.length); - } else if(arg instanceof BigInteger) { - SolidityType uint256Type = SolidityType.getType(SolidityType.UINT); - encodedArg = uint256Type.encode(arg); - } - - encodedArguments = ByteUtil.merge(encodedArguments, encodedArg); - } - - return encodedArguments; - } - - public static CallTransaction.Invocation getTxInvocation(Transaction newTx) { - String abi = "[{\"constant\":false,\"inputs\":[{\"name\":\"preimage\",\"type\":\"bytes32\"}, {\"name\":\"amount\",\"type\":\"uint256\"}, {\"name\":\"address\",\"type\":\"address\"}, {\"name\":\"timelock\",\"type\":\"uint256\"}],\"name\":\"claim\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]"; - CallTransaction.Contract contract = new CallTransaction.Contract(abi); - return contract.parseInvocation(newTx.getData()); - } - - public static boolean isClaimTxAndValid(Transaction newTx, - Coin txCost, - Constants constants, - SignatureCache signatureCache, - PropertyGetter propertyGetter) { - if(newTx.getReceiveAddress() != null - && newTx.getData() != null - && newTx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) - && Arrays.equals(Arrays.copyOfRange(newTx.getData(), 0, 4), Constants.CLAIM_FUNCTION_SIGNATURE)) { - - String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(newTx, signatureCache)); - byte[] key = HashUtil.keccak256(HexUtils.decode(HexUtils.stringToByteArray(swapHash + SWAPS_MAP_POSITION))); - - AccountInformationProvider accountInformationProvider = propertyGetter.getWeb3InfoRetriever().getInformationProvider("latest"); - DataWord swapRecord = accountInformationProvider.getStorageValue(newTx.getReceiveAddress(), DataWord.valueOf(key)); - - if(swapRecord != null){ - CallTransaction.Invocation invocation = getTxInvocation(newTx); - BigInteger amount = (BigInteger) invocation.args[1]; - Coin balanceWithClaim = accountInformationProvider.getBalance(newTx.getSender(signatureCache)) - .add(Coin.valueOf(amount.longValue())); - - return txCost.compareTo(balanceWithClaim) <= 0; - } - } - - return false; - } -} diff --git a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java new file mode 100644 index 00000000000..9efbd26d81f --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java @@ -0,0 +1,210 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.util; + +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.core.CallTransaction; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; +import org.ethereum.crypto.HashUtil; +import org.ethereum.solidity.SolidityType; +import org.ethereum.util.ByteUtil; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.GasCost; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; + +public class EthSwapUtil { + private static final Logger logger = LoggerFactory.getLogger(EthSwapUtil.class); + + private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; + + private EthSwapUtil() { + throw new IllegalStateException("Utility class"); + } + + public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatureCache) { + + CallTransaction.Invocation invocation = getTxInvocation(newTx); + + // Get arguments from the invocation object + byte[] preimage = (byte[]) invocation.args[0]; + byte[] preimageHash = HashUtil.sha256(encodePacked(preimage)); + BigInteger amount = (BigInteger) invocation.args[1]; + DataWord refundAddress = (DataWord) invocation.args[2]; + BigInteger timeLock = (BigInteger) invocation.args[3]; + + + // Remove the leading zeroes from the arguments bytes and merge them + byte[] argumentsBytes = encodePacked( + preimageHash, + amount, + newTx.getSender(signatureCache), + new RskAddress(ByteUtil.toHexString(refundAddress.getLast20Bytes())), + timeLock + ); + + return HashUtil.keccak256(argumentsBytes); + } + + public static byte[] encodePacked(Object...arguments) { + byte[] encodedArguments = new byte[]{}; + + for(Object arg: arguments) { + byte[] encodedArg = new byte[]{}; + if(arg instanceof byte[]) { + SolidityType bytes32Type = SolidityType.getType(SolidityType.BYTES32); + encodedArg = bytes32Type.encode(arg); + } else if(arg instanceof RskAddress) { + SolidityType addressType = SolidityType.getType(SolidityType.ADDRESS); + byte[] encodedAddress = addressType.encode(((RskAddress) arg).toHexString()); + encodedArg = org.bouncycastle.util.Arrays.copyOfRange(encodedAddress, 12, encodedAddress.length); + } else if(arg instanceof BigInteger) { + SolidityType uint256Type = SolidityType.getType(SolidityType.UINT); + encodedArg = uint256Type.encode(arg); + } + + encodedArguments = ByteUtil.merge(encodedArguments, encodedArg); + } + + return encodedArguments; + } + + public static CallTransaction.Invocation getTxInvocation(Transaction newTx) { + String abi = "[{\"constant\":false,\"inputs\":[{\"name\":\"preimage\",\"type\":\"bytes32\"}, {\"name\":\"amount\",\"type\":\"uint256\"}, {\"name\":\"address\",\"type\":\"address\"}, {\"name\":\"timelock\",\"type\":\"uint256\"}],\"name\":\"claim\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]"; + CallTransaction.Contract contract = new CallTransaction.Contract(abi); + return contract.parseInvocation(newTx.getData()); + } + + public static boolean isClaimTx(Transaction tx, Constants constants) { + return tx.getReceiveAddress() != null + && tx.getData() != null + && tx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) + && Arrays.equals(Arrays.copyOfRange(tx.getData(), 0, 4), Constants.CLAIM_FUNCTION_SIGNATURE); + } + + public static boolean hasLockedFunds(Transaction tx, SignatureCache signatureCache, RepositorySnapshot repositorySnapshot) { + String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(tx, signatureCache)); + byte[] key = HashUtil.keccak256(HexUtils.decode(HexUtils.stringToByteArray(swapHash + SWAPS_MAP_POSITION))); + + DataWord swapRecord = repositorySnapshot.getStorageValue(tx.getReceiveAddress(), DataWord.valueOf(key)); + + return swapRecord != null; + } + + private static Coin getLockedAmount(Transaction tx) { + CallTransaction.Invocation invocation = getTxInvocation(tx); + BigInteger amount = (BigInteger) invocation.args[1]; + + return Coin.valueOf(amount.longValue()); + } + + private static Coin getTxCost(Transaction tx, + ActivationConfig.ForBlock activation, + Constants constants, + SignatureCache signatureCache) { + Coin txCost = tx.getValue(); + if (activation == null || tx.transactionCost(constants, activation, signatureCache) > 0) { + BigInteger gasLimit = BigInteger.valueOf(GasCost.toGas(tx.getGasLimit())); + txCost = txCost.add(tx.getGasPrice().multiply(gasLimit)); + } + + return txCost; + } + + public static boolean isClaimTxAndValid(ClaimTransactionInfoHolder claimTransactionInfoHolder, + Coin txCost) { + Transaction newTx = claimTransactionInfoHolder.getTx(); + Constants constants = claimTransactionInfoHolder.getConstants(); + SignatureCache signatureCache = claimTransactionInfoHolder.getSignatureCache(); + RepositorySnapshot repositorySnapshot = claimTransactionInfoHolder.getRepositorySnapshot(); + + if(!isClaimTx(newTx, constants)) { + return false; + } + + if(hasLockedFunds(newTx, signatureCache, repositorySnapshot)){ + Coin lockedAmount = getLockedAmount(newTx); + + Coin balanceWithClaim = repositorySnapshot.getBalance(newTx.getSender(signatureCache)) + .add(lockedAmount); + + return txCost.compareTo(balanceWithClaim) <= 0; + } + + return false; + } + + private static boolean isSameTx(Transaction pendingTx, Transaction newTx, SignatureCache signatureCache) { + return pendingTx.getSender(signatureCache).toHexString().equals(newTx.getSender(signatureCache).toHexString()) + && pendingTx.getReceiveAddress().toHexString().equals(newTx.getReceiveAddress().toHexString()) + && Arrays.equals(pendingTx.getData(), newTx.getData()); + } + + public static boolean isClaimTxAndSenderCanPayAlongPendingTx(ClaimTransactionInfoHolder claimTransactionInfoHolder, List pendingTransactions) { + Transaction newTx = claimTransactionInfoHolder.getTx(); + ActivationConfig.ForBlock activation = claimTransactionInfoHolder.getActivation(); + Constants constants = claimTransactionInfoHolder.getConstants(); + SignatureCache signatureCache = claimTransactionInfoHolder.getSignatureCache(); + RepositorySnapshot repositorySnapshot = claimTransactionInfoHolder.getRepositorySnapshot(); + + if(!isClaimTx(newTx, constants) + || !hasLockedFunds(newTx, signatureCache, repositorySnapshot)) { + return false; + } + + Coin totalLockedAmount = getLockedAmount(newTx); + Coin totalClaimTxCost = getTxCost(newTx, activation, constants, signatureCache); + Coin totalPendingTxCost = Coin.ZERO; + + for (Transaction tx : pendingTransactions) { + if(isSameTx(tx, newTx, signatureCache)) { + return false; + } + + boolean isReplacedTx = Arrays.equals(tx.getNonce(), newTx.getNonce()); + + if (isReplacedTx) { + continue; + } + + if(isClaimTx(tx, constants)) { + totalClaimTxCost = totalClaimTxCost.add(getTxCost(tx, activation, constants, signatureCache)); + totalLockedAmount = totalLockedAmount.add(getLockedAmount(tx)); + } else { + totalPendingTxCost = totalPendingTxCost.add(getTxCost(tx, activation, constants, signatureCache)); + } + } + + Coin senderBalance = repositorySnapshot.getBalance(newTx.getSender(signatureCache)); + Coin balanceAfterPendingTx = senderBalance.subtract(totalPendingTxCost); + + + return balanceAfterPendingTx.add(totalLockedAmount).compareTo(totalClaimTxCost) >= 0; + } +} diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index 85077c7989b..f1b63dcd911 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -18,16 +18,16 @@ */ package org.ethereum.core; -import co.rsk.PropertyGetter; import co.rsk.config.VmConfig; import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; import co.rsk.panic.PanicProcessor; import co.rsk.rpc.modules.trace.ProgramSubtrace; -import co.rsk.util.ContractUtil; +import co.rsk.util.EthSwapUtil; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; @@ -103,14 +103,12 @@ public class TransactionExecutor { private boolean localCall = false; private boolean txWasPaid = false; - private PropertyGetter propertyGetter; - public TransactionExecutor( Constants constants, ActivationConfig activationConfig, Transaction tx, int txindex, RskAddress coinbase, Repository track, BlockStore blockStore, ReceiptStore receiptStore, BlockFactory blockFactory, ProgramInvokeFactory programInvokeFactory, Block executionBlock, long gasUsedInTheBlock, VmConfig vmConfig, boolean remascEnabled, PrecompiledContracts precompiledContracts, Set deletedAccounts, - SignatureCache signatureCache, PropertyGetter propertyGetter) { + SignatureCache signatureCache) { this.constants = constants; this.signatureCache = signatureCache; this.activations = activationConfig.forBlock(executionBlock.getNumber()); @@ -129,7 +127,6 @@ public TransactionExecutor( this.precompiledContracts = precompiledContracts; this.enableRemasc = remascEnabled; this.deletedAccounts = new HashSet<>(deletedAccounts); - this.propertyGetter = propertyGetter; } /** @@ -177,7 +174,15 @@ private boolean init() { Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); - if (!isCovers(senderBalance, totalCost) && !ContractUtil.isClaimTxAndValid(tx, totalCost,constants, signatureCache, propertyGetter)) { + ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( + tx, + track, + signatureCache, + constants, + activations + ); + + if (!isCovers(senderBalance, totalCost) && !EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder, totalCost)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); diff --git a/rskj-core/src/test/java/co/rsk/core/CallContractTest.java b/rskj-core/src/test/java/co/rsk/core/CallContractTest.java index 5e6580afb67..7ac495685bf 100644 --- a/rskj-core/src/test/java/co/rsk/core/CallContractTest.java +++ b/rskj-core/src/test/java/co/rsk/core/CallContractTest.java @@ -82,8 +82,7 @@ private static ProgramResult callContract(World world, RskAddress receiveAddress blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, world.getBlockTxSignatureCache()), - world.getBlockTxSignatureCache(), - null + world.getBlockTxSignatureCache() ); org.ethereum.core.TransactionExecutor executor = transactionExecutorFactory diff --git a/rskj-core/src/test/java/co/rsk/core/TransactionTest.java b/rskj-core/src/test/java/co/rsk/core/TransactionTest.java index 09d50cb43b6..1371ad6dba9 100644 --- a/rskj-core/src/test/java/co/rsk/core/TransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/core/TransactionTest.java @@ -274,8 +274,7 @@ protected ProgramResult executeTransaction() { blockFactory, invokeFactory, precompiledContracts, - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ); TransactionExecutor executor = transactionExecutorFactory .newInstance(txConst, 0, bestBlock.getCoinbase(), track, bestBlock, 0) diff --git a/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java b/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java index f06042417a8..7ecb88c9911 100644 --- a/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java @@ -31,6 +31,7 @@ import co.rsk.trie.TrieStore; import co.rsk.trie.TrieStoreImpl; import org.bouncycastle.util.BigIntegers; +import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; @@ -50,11 +51,13 @@ import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.AssertionsKt; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.*; @@ -72,6 +75,12 @@ public class BlockExecutorTest { private static final TestSystemProperties CONFIG = new TestSystemProperties(); private static final BlockFactory BLOCK_FACTORY = new BlockFactory(CONFIG.getActivationConfig()); + private final CallTransaction.Function CLAIM_FUNCTION = CallTransaction.Function.fromSignature( + "claim", + new String[]{"bytes32", "uint256", "address", "uint256"}, + new String[]{} + ); + @TempDir public Path tempDir; @@ -537,6 +546,22 @@ void invalidBlockBadLogsBloom() { Assertions.assertFalse(executor.executeAndValidate(block, parent.getHeader())); } + @Test + void executeBlockButRejectClaimTransaction() { + Block block = getBlockWithOneTransactionsAndOneClaimTransaction(); + Block parent = blockchain.getBestBlock(); + + Transaction claimTx = block.getTransactionsList().get(1); + + BlockResult result = executor.execute(block, parent.getHeader(), false); + + Assertions.assertEquals(1, result.getExecutedTransactions().size()); + + Transaction resultTx = result.getExecutedTransactions().get(0); + + Assertions.assertNotEquals(claimTx.getHash(), resultTx.getHash()); + } + private static TestObjects generateBlockWithOneTransaction() { TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Repository repository = new MutableRepository(trieStore, new Trie(trieStore)); @@ -661,6 +686,57 @@ private Block getBlockWithTwoTransactions() { return new BlockGenerator().createChildBlock(bestBlock, txs, uncles, 1, null); } + private Block getBlockWithOneTransactionsAndOneClaimTransaction() { + Repository track = repository.startTracking(); + + Account account = createAccount("acctest1", track, Coin.valueOf(60000)); + Account account2 = createAccount("acctest2", track, Coin.valueOf(10L)); + + track.commit(); + + Assertions.assertFalse(Arrays.equals(EMPTY_TRIE_HASH, repository.getRoot())); + + Block bestBlock = blockchain.getBestBlock(); + bestBlock.setStateRoot(repository.getRoot()); + + byte[] callData = CLAIM_FUNCTION.encode( + "preimage".getBytes(StandardCharsets.UTF_8), + 10, + account2.getAddress().toString(), + 1000000); + + Transaction tx = Transaction + .builder() + .nonce(repository.getNonce(account.getAddress())) + .gasPrice(BigInteger.ONE) + .gasLimit(BigInteger.valueOf(21000)) + .destination(account2.getAddress()) + .chainId(CONFIG.getNetworkConstants().getChainId()) + .value(BigInteger.TEN) + .build(); + tx.sign(account.getEcKey().getPrivKeyBytes()); + + Transaction claimTx = Transaction + .builder() + .nonce(repository.getNonce(account.getAddress()).add(BigInteger.ONE)) + .gasPrice(BigInteger.ONE) + .gasLimit(BigInteger.valueOf(21000)) + .destination(new RskAddress(Constants.regtest().getEtherSwapContractAddress())) + .chainId(CONFIG.getNetworkConstants().getChainId()) + .value(BigInteger.ZERO) + .data(callData) + .build(); + claimTx.sign(account.getEcKey().getPrivKeyBytes()); + + List txs = Arrays.asList( + tx, + claimTx + ); + + List uncles = new ArrayList<>(); + return new BlockGenerator().createChildBlock(bestBlock, txs, uncles, 1, null); + } + public static Account createAccount(String seed, Repository repository, Coin balance) { Account account = createAccount(seed); repository.createAccount(account.getAddress()); @@ -867,9 +943,10 @@ private static BlockExecutor buildBlockExecutor(TrieStore store, RskSystemProper BLOCK_FACTORY, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - signatureCache, - null - ) + signatureCache + ), + config.getNetworkConstants(), + signatureCache ); } diff --git a/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java b/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java index 5e03d899115..3c797ca7e26 100644 --- a/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/TransactionPoolImplTest.java @@ -98,8 +98,7 @@ protected RepositoryLocator buildRepositoryLocator() { 10, 100, Mockito.mock(TxQuotaChecker.class), - Mockito.mock(GasPriceTracker.class), - null); + Mockito.mock(GasPriceTracker.class)); quotaChecker = mock(TxQuotaChecker.class); when(quotaChecker.acceptTx(any(), any(), any())).thenReturn(true); diff --git a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java index f7163d3bdf5..cdca5ceea1b 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MinerServerTest.java @@ -124,8 +124,7 @@ protected RepositoryLocator buildRepositoryLocator() { 10, 100, mock(TxQuotaChecker.class), - mock(GasPriceTracker.class), - null); + mock(GasPriceTracker.class)); transactionPool.processBest(standardBlockchain.getBestBlock()); diff --git a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java index 424fdcee066..b4a198ebecb 100644 --- a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java @@ -102,7 +102,7 @@ void sendTransactionMustNotBeMined() { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, null, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); Web3Impl web3 = createEnvironment(blockchain, null, trieStore, transactionPool, blockStore, false, world.getBlockTxSignatureCache(), transactionGateway); @@ -129,7 +129,7 @@ void sendTransactionMustBeMined() { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, null, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); @@ -194,7 +194,7 @@ void sendRawTransactionWithAutoMining() throws Exception { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, receiptStore, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); Web3Impl web3 = createEnvironment(blockchain, receiptStore, trieStore, transactionPool, blockStore, true, world.getBlockTxSignatureCache(), transactionGateway); @@ -223,7 +223,7 @@ void sendRawTransactionWithoutAutoMining() { BlockStore blockStore = world.getBlockStore(); TransactionPool transactionPool = new TransactionPoolImpl(config, repositoryLocator, blockStore, blockFactory, null, buildTransactionExecutorFactory(blockStore, receiptStore, world.getBlockTxSignatureCache()), - world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); Web3Impl web3 = createEnvironment(blockchain, receiptStore, trieStore, transactionPool, blockStore, false, world.getBlockTxSignatureCache(), transactionGateway); @@ -261,8 +261,7 @@ void testGasEstimation() { 10, 100, Mockito.mock(TxQuotaChecker.class), - Mockito.mock(GasPriceTracker.class), - null + Mockito.mock(GasPriceTracker.class) ); TransactionGateway transactionGateway = new TransactionGateway(new SimpleChannelManager(), transactionPool); @@ -591,7 +590,9 @@ private Web3Impl internalCreateEnvironment(Blockchain blockchain, config.getActivationConfig(), repositoryLocator, // stateRootHandler, - this.transactionExecutorFactory + this.transactionExecutorFactory, + config.getNetworkConstants(), + signatureCache ); MinerServer minerServer = new MinerServerImpl( @@ -699,8 +700,7 @@ private TransactionExecutorFactory buildTransactionExecutorFactory(BlockStore bl blockFactory, null, new PrecompiledContracts(config, bridgeSupportFactory(), signatureCache), - blockTxSignatureCache, - null + blockTxSignatureCache ); } @@ -712,8 +712,7 @@ private TransactionExecutorFactory buildTransactionExecutionFactoryWithProgramIn blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory(), signatureCache), - blockTxSignatureCache, - null + blockTxSignatureCache ); } diff --git a/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java b/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java index 21c67e4d9fc..ff675574b74 100644 --- a/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java @@ -797,9 +797,10 @@ void processBodyResponseWithTransactionAddsToBlockchain() { blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null - ) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + ), + config.getNetworkConstants(), + signatureCache ); Assertions.assertEquals(1, block.getTransactionsList().size()); blockExecutor.executeAndFillAll(block, genesis.getHeader()); diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java index 13a81d9c593..5ad9c69c7c2 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java @@ -47,11 +47,11 @@ void validAccountBalance() { Mockito.when(tx3.getGasPrice()).thenReturn(Coin.valueOf(5000)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(10000)); - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(null, null, null); + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); - Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx3, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx1, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx2, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx3, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); } @Test @@ -66,10 +66,10 @@ void invalidAccountBalance() { Mockito.when(tx2.getGasPrice()).thenReturn(Coin.valueOf(10)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(19)); - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(null, null, null); + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); - Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx1, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx2, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); } @Test @@ -87,9 +87,9 @@ void balanceIsNotValidatedIfFreeTx() { tx.sign(new ECKey().getPrivKeyBytes()); - TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(null, null, null); + TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(); - Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true).transactionIsValid()); + Assertions.assertTrue(tv.validate(tx, null, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true).transactionIsValid()); } } diff --git a/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java b/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java index 625e3dab08b..6966fceb7a0 100644 --- a/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java @@ -474,8 +474,7 @@ private BridgeState callGetStateForDebuggingTx() throws IOException { new BlockFactory(beforeBambooProperties.getActivationConfig()), new ProgramInvokeFactoryImpl(), new PrecompiledContracts(beforeBambooProperties, world.getBridgeSupportFactory(), world.getBlockTxSignatureCache()), - world.getBlockTxSignatureCache(), - null + world.getBlockTxSignatureCache() ); Repository track = repository.startTracking(); TransactionExecutor executor = transactionExecutorFactory diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java b/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java index a3143f0ea43..ef86d2d5370 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java @@ -1038,9 +1038,10 @@ private BlockExecutor buildBlockExecutor(RepositoryLocator repositoryLocator, Bl blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null - ) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + ), + config.getNetworkConstants(), + signatureCache ); } } diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java index f76d3bd13ad..9f907928000 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java @@ -493,9 +493,10 @@ void paysOnlyBlocksWithEnoughBalanceAccumulatedAfterRFS() { new BlockFactory(config.getActivationConfig()), new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null - ) + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + ), + config.getNetworkConstants(), + signatureCache ); for (Block b : blocks) { diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java b/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java index 24ff7abf551..0ce72ac091f 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java @@ -146,9 +146,10 @@ public void start() { blockFactory, programInvokeFactory, precompiledContracts, - blockTxSignatureCache, - null - ) + blockTxSignatureCache + ), + builder.getConfig().getNetworkConstants(), + blockTxSignatureCache ); Random random = new Random(RemascTestRunner.class.hashCode()); for(int i = 0; i <= this.initialHeight; i++) { diff --git a/rskj-core/src/test/java/co/rsk/test/World.java b/rskj-core/src/test/java/co/rsk/test/World.java index 85f76c95fa8..62d82fa081f 100644 --- a/rskj-core/src/test/java/co/rsk/test/World.java +++ b/rskj-core/src/test/java/co/rsk/test/World.java @@ -183,9 +183,10 @@ public BlockExecutor getBlockExecutor() { new BlockFactory(config.getActivationConfig()), programInvokeFactory, new PrecompiledContracts(config, bridgeSupportFactory, blockTxSignatureCache), - blockTxSignatureCache, - null - ) + blockTxSignatureCache + ), + config.getNetworkConstants(), + blockTxSignatureCache ); } diff --git a/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java b/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java index eea6631a15b..c6e7747a43e 100644 --- a/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java +++ b/rskj-core/src/test/java/co/rsk/test/builders/BlockBuilder.java @@ -105,6 +105,7 @@ public Block build() { if (blockChain != null) { final TestSystemProperties config = new TestSystemProperties(); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); + BlockTxSignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); BlockExecutor executor = new BlockExecutor( config.getActivationConfig(), new RepositoryLocator(trieStore, stateRootHandler), @@ -115,9 +116,10 @@ public Block build() { new BlockFactory(config.getActivationConfig()), new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, new BlockTxSignatureCache(new ReceivedTxSignatureCache())), - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null - ) + signatureCache + ), + config.getNetworkConstants(), + signatureCache ); executor.executeAndFill(block, parent.getHeader()); } diff --git a/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java b/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java index afa659a3d6b..a6b25269c67 100644 --- a/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java +++ b/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java @@ -239,18 +239,19 @@ public BlockChainImpl build() { blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - blockTxSignatureCache, - null + blockTxSignatureCache ); repositoryLocator = new RepositoryLocator(trieStore, stateRootHandler); transactionPool = new TransactionPoolImpl( config, repositoryLocator, this.blockStore, blockFactory, new TestCompositeEthereumListener(), - transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); BlockExecutor blockExecutor = new BlockExecutor( config.getActivationConfig(), repositoryLocator, - transactionExecutorFactory + transactionExecutorFactory, + config.getNetworkConstants(), + signatureCache ); BlockChainImpl blockChain = new BlockChainLoader( blockStore, diff --git a/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java b/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java index e1d072e8f76..965571d81bb 100644 --- a/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java +++ b/rskj-core/src/test/java/co/rsk/test/dsl/WorldDslProcessor.java @@ -323,9 +323,10 @@ private void processBlockChainCommand(DslCommand cmd) { new BlockFactory(config.getActivationConfig()), programInvokeFactory, null, - world.getBlockTxSignatureCache(), - null - ) + world.getBlockTxSignatureCache() + ), + config.getNetworkConstants(), + world.getBlockTxSignatureCache() ); executor.executeAndFill(block, parent.getHeader()); world.saveBlock(name, block); diff --git a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java b/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java deleted file mode 100644 index 39030f8fb6b..00000000000 --- a/rskj-core/src/test/java/co/rsk/util/ContractUtilTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package co.rsk.util; - -import co.rsk.PropertyGetter; -import co.rsk.core.Coin; -import co.rsk.core.RskAddress; -import co.rsk.core.bc.AccountInformationProvider; -import co.rsk.db.RepositorySnapshot; -import co.rsk.rpc.Web3InformationRetriever; -import org.bouncycastle.util.encoders.Hex; -import org.ethereum.config.Constants; -import org.ethereum.core.CallTransaction; -import org.ethereum.core.ReceivedTxSignatureCache; -import org.ethereum.core.SignatureCache; -import org.ethereum.core.Transaction; -import org.ethereum.util.ByteUtil; -import org.ethereum.vm.DataWord; -import org.junit.jupiter.api.Test; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import static org.junit.jupiter.api.Assertions.*; - -public class ContractUtilTest { - - private final CallTransaction.Function CLAIM_FUNCTION = CallTransaction.Function.fromSignature( - "claim", - new String[]{"bytes32", "uint256", "address", "uint256"}, - new String[]{} - ); - - private final Constants testConstans = Constants.regtest(); - - private final String EXPECTED_HASH = "0x3dc21e0a710489c951f29205f9961b2c311d48fdf5a35545469d7b43e88f7624"; - - @Test - public void testCalculateSwapHash() { - Transaction mockedTx = mockTx(); - - byte[] result = ContractUtil.calculateSwapHash(mockedTx, new ReceivedTxSignatureCache()); - - assertEquals(EXPECTED_HASH, HexUtils.toJsonHex(result)); - } - - @Test - public void testIsClaimTxAndValid() { - Coin txCost = Coin.valueOf(5); - SignatureCache signatureCache = new ReceivedTxSignatureCache(); - - Transaction mockedTx = mockTx(); - Web3InformationRetriever mockedWeb3InformationRetriever = mock(Web3InformationRetriever.class); - AccountInformationProvider mockedAccountInformationProvider = mock(AccountInformationProvider.class); - - when(mockedWeb3InformationRetriever.getInformationProvider("latest")).thenReturn(mockedAccountInformationProvider); - when(mockedAccountInformationProvider.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); - when(mockedAccountInformationProvider.getStorageValue(any(RskAddress.class), any(DataWord.class))) - .thenReturn(DataWord.valueOf(1)); - - PropertyGetter propertyGetter = () -> mockedWeb3InformationRetriever; - - boolean result = ContractUtil.isClaimTxAndValid(mockedTx, txCost, testConstans, signatureCache, propertyGetter); - - assertTrue(result); - } - - private Transaction mockTx() { - byte[] senderBytes = Hex.decode("0000000000000000000000000000000001000001"); - RskAddress claimAddress = new RskAddress(senderBytes); - - byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] callData = CLAIM_FUNCTION.encode(preimage, - 10, - "0000000000000000000000000000000001000002", - 1000000); - - Transaction mockedTx = mock(Transaction.class); - - when(mockedTx.getSender(any(SignatureCache.class))).thenReturn(claimAddress); - when(mockedTx.getNonce()).thenReturn(ByteUtil.cloneBytes(BigInteger.ZERO.toByteArray())); - when(mockedTx.getGasPrice()).thenReturn(Coin.valueOf(1)); - when(mockedTx.getGasLimit()).thenReturn(BigInteger.valueOf(1).toByteArray()); - when(mockedTx.getReceiveAddress()).thenReturn(new RskAddress(testConstans.getEtherSwapContractAddress())); - when(mockedTx.getData()).thenReturn(callData); - when(mockedTx.getValue()).thenReturn(Coin.ZERO); - - return mockedTx; - } -} diff --git a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java b/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java new file mode 100644 index 00000000000..b202c71a200 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java @@ -0,0 +1,169 @@ +package co.rsk.util; + +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.core.CallTransaction; +import org.ethereum.core.ReceivedTxSignatureCache; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; +import org.ethereum.vm.DataWord; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import static org.junit.jupiter.api.Assertions.*; + +public class EthSwapUtilTest { + + private final CallTransaction.Function CLAIM_FUNCTION = CallTransaction.Function.fromSignature( + "claim", + new String[]{"bytes32", "uint256", "address", "uint256"}, + new String[]{} + ); + + private final Constants testConstants = Constants.regtest(); + + private final String EXPECTED_HASH = "0x3dc21e0a710489c951f29205f9961b2c311d48fdf5a35545469d7b43e88f7624"; + + SignatureCache signatureCache; + RepositorySnapshot mockedRepository; + ActivationConfig.ForBlock activations; + + @BeforeEach + void setup() { + signatureCache = new ReceivedTxSignatureCache(); + mockedRepository = mock(RepositorySnapshot.class); + activations = mock(ActivationConfig.ForBlock.class); + + when(mockedRepository.getStorageValue( + eq(new RskAddress(testConstants.getEtherSwapContractAddress())), + any(DataWord.class))) + .thenReturn(DataWord.valueOf(1)); + when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); + } + + @Test + public void whenCalculateSwapHashIsCalled_shouldReturnExpectedHash() { + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); + + byte[] result = EthSwapUtil.calculateSwapHash(mockedClaimTx, new ReceivedTxSignatureCache()); + + assertEquals(EXPECTED_HASH, HexUtils.toJsonHex(result)); + } + + @Test + public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); + + Coin txCost = Coin.valueOf(5); + SignatureCache signatureCache = new ReceivedTxSignatureCache(); + RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + when(mockedRepository.getStorageValue(eq(mockedClaimTx.getReceiveAddress()), any(DataWord.class))) + .thenReturn(DataWord.valueOf(1)); + when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); + + ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( + mockedClaimTx, + mockedRepository, + signatureCache, + testConstants, + null + ); + + boolean result = EthSwapUtil.isClaimTxAndValid(testClaimTransactionInfoHolder, txCost); + + assertTrue(result); + } + + @Test + public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withIdenticalNewAndPendingTx_shouldReturnFalse() { + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); + + List pendingTransactions = new ArrayList<>(); + pendingTransactions.add(createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 1)); + + SignatureCache signatureCache = new ReceivedTxSignatureCache(); + RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + + when(mockedClaimTx.transactionCost(testConstants, activations, signatureCache)) + .thenReturn(5L); + + ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( + mockedClaimTx, + mockedRepository, + signatureCache, + testConstants, + activations + ); + + boolean result = EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(testClaimTransactionInfoHolder, pendingTransactions); + assertFalse(result); + } + + @Test + public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withMultipleClaimTx_shouldCombineLockedAmounts() { + Transaction mockedClaimTx = createClaimTx(3, "test".getBytes(StandardCharsets.UTF_8), 0); + Transaction mockedPendingClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 1); + + List pendingTransactions = new ArrayList<>(); + pendingTransactions.add(mockedPendingClaimTx); + + SignatureCache signatureCache = new ReceivedTxSignatureCache(); + RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + + when(mockedClaimTx.transactionCost(testConstants, activations, signatureCache)) + .thenReturn(5L); + when(mockedPendingClaimTx.transactionCost(testConstants, activations, signatureCache)) + .thenReturn(5L); + + ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( + mockedClaimTx, + mockedRepository, + signatureCache, + testConstants, + activations + ); + + boolean result = EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(testClaimTransactionInfoHolder, pendingTransactions); + assertTrue(result); + } + + private Transaction createClaimTx(int amount, byte[] preimage, long nonce) { + byte[] senderBytes = Hex.decode("0000000000000000000000000000000001000001"); + RskAddress claimAddress = new RskAddress(senderBytes); + + byte[] callData = CLAIM_FUNCTION.encode( + preimage, + amount, + "0000000000000000000000000000000001000002", + 1000000); + + Transaction claimTx = mock(Transaction.class); + + when(claimTx.getSender(any(SignatureCache.class))).thenReturn(claimAddress); + when(claimTx.getNonce()).thenReturn(BigInteger.valueOf(nonce).toByteArray()); + when(claimTx.getGasPrice()).thenReturn(Coin.valueOf(1)); + when(claimTx.getGasLimit()).thenReturn(BigInteger.valueOf(5).toByteArray()); + when(claimTx.getReceiveAddress()).thenReturn(new RskAddress(testConstants.getEtherSwapContractAddress())); + when(claimTx.getData()).thenReturn(callData); + when(claimTx.getValue()).thenReturn(Coin.ZERO); + + return claimTx; + } +} diff --git a/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java b/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java index e70cd4108cd..bc786fceae1 100644 --- a/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java +++ b/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java @@ -103,7 +103,7 @@ public void processBlock( Block block, Block parent) { null, blockFactory, null, - new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), blockTxSignatureCache, null); + new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), blockTxSignatureCache); TransactionExecutor executor = transactionExecutorFactory .newInstance(tx, txindex++, block.getCoinbase(), track, block, totalGasUsed); diff --git a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java index 645ad784b90..7037ea7d495 100644 --- a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -73,12 +73,11 @@ public static BlockChainImpl createBlockchain( blockFactory, new ProgramInvokeFactoryImpl(), null, - blockTxSignatureCache, - null); + blockTxSignatureCache); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); RepositoryLocator repositoryLocator = new RepositoryLocator(trieStore, stateRootHandler); - TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, receivedTxSignatureCache, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, receivedTxSignatureCache, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); BlockChainImpl blockchain = new BlockChainImpl( blockStore, @@ -89,7 +88,9 @@ public static BlockChainImpl createBlockchain( new BlockExecutor( config.getActivationConfig(), repositoryLocator, - transactionExecutorFactory + transactionExecutorFactory, + config.getNetworkConstants(), + blockTxSignatureCache ), stateRootHandler ); diff --git a/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java b/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java index 3158e4d0b86..200e646b886 100644 --- a/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java @@ -96,7 +96,7 @@ void testInitHandlesFreeTransactionsOK() { repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache, null + blockTxSignatureCache ); @@ -233,7 +233,7 @@ void InvalidTxsIsInBlockAndShouldntBeInCache(){ repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache, null + blockTxSignatureCache ); assertEquals(0, transaction.transactionCost(constants, activationConfig.forBlock(executionBlock.getNumber()), new BlockTxSignatureCache(new ReceivedTxSignatureCache()))); @@ -266,7 +266,7 @@ void remascTxIsReceivedAndShouldntBeInCache(){ repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache, null + blockTxSignatureCache ); assertEquals(0, transaction.transactionCost(constants, activationConfig.forBlock(executionBlock.getNumber()), new BlockTxSignatureCache(new ReceivedTxSignatureCache()))); @@ -374,7 +374,7 @@ private boolean executeValidTransaction(Transaction transaction, BlockTxSignatur repository, blockStore, receiptStore, blockFactory, programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, true, precompiledContracts, deletedAccounts, - blockTxSignatureCache, null + blockTxSignatureCache ); return txExecutor.executeTransaction(); diff --git a/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java b/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java index 4a6ea38a783..7374a146754 100644 --- a/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java @@ -495,8 +495,7 @@ protected ProgramResult executeTransaction() { blockFactory, invokeFactory, new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - signatureCache, - null); + signatureCache); TransactionExecutor executor = transactionExecutorFactory .newInstance(txConst, 0, bestBlock.getCoinbase(), track, bestBlock, 0) .setLocalCall(true); @@ -844,8 +843,7 @@ private TransactionExecutor executeTransaction( blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), - blockTxSignatureCache, - null); + blockTxSignatureCache); TransactionExecutor executor = transactionExecutorFactory .newInstance(tx, 0, RskAddress.nullAddress(), repository, blockchain.getBestBlock(), 0); diff --git a/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java b/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java index ecfcee88fc8..bdd61dcf5c2 100644 --- a/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java +++ b/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java @@ -150,12 +150,11 @@ public List runTestCase(BlockTestingCase testCase) { blockFactory, new ProgramInvokeFactoryImpl(), null, - blockTxSignatureCache, - null); + blockTxSignatureCache); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); RepositoryLocator repositoryLocator = new RepositoryLocator(trieStore, stateRootHandler); - TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + TransactionPoolImpl transactionPool = new TransactionPoolImpl(config, repositoryLocator, null, blockFactory, listener, transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); BlockChainImpl blockchain = new BlockChainImpl( blockStore, @@ -166,7 +165,9 @@ public List runTestCase(BlockTestingCase testCase) { new BlockExecutor( config.getActivationConfig(), new RepositoryLocator(trieStore, stateRootHandler), - transactionExecutorFactory + transactionExecutorFactory, + config.getNetworkConstants(), + blockTxSignatureCache ), stateRootHandler ); diff --git a/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java b/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java index 2f624446e75..0763e42f4f5 100644 --- a/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java +++ b/rskj-core/src/test/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java @@ -113,8 +113,7 @@ protected ProgramResult executeTransaction() { blockFactory, invokeFactory, precompiledContracts, - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ); TransactionExecutor executor = transactionExecutorFactory.newInstance( transaction, @@ -147,6 +146,7 @@ public List runImpl() { logger.info("transaction: {}", transaction); BlockStore blockStore = new IndexedBlockStore(blockFactory, new HashMapDB(), new HashMapBlocksIndex()); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); + BlockTxSignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); blockchain = new BlockChainImpl( blockStore, null, @@ -163,9 +163,10 @@ public List runImpl() { blockFactory, new ProgramInvokeFactoryImpl(), precompiledContracts, - new BlockTxSignatureCache(new ReceivedTxSignatureCache()), - null - ) + signatureCache + ), + config.getNetworkConstants(), + signatureCache ), stateRootHandler ); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java index 05e01dc4d4f..f23da51c182 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java @@ -908,7 +908,7 @@ void getPendingTransactionByHash() { BlockChainImpl blockChain = world.getBlockChain(); BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); - TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); transactionPool.processBest(blockChain.getBestBlock()); Web3Impl web3 = createWeb3(world, transactionPool, receiptStore); @@ -2518,7 +2518,7 @@ private void checkSendTransaction(Byte chainId) { BlockChainImpl blockChain = world.getBlockChain(); BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); - TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); Web3Impl web3 = createWeb3(world, transactionPool, receiptStore); // **** Initializes data ****************** @@ -2763,7 +2763,7 @@ private Web3Impl createWeb3(Ethereum eth, World world, ReceiptStore receiptStore BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, - blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); return createWeb3(eth, world, transactionPool, receiptStore); } @@ -2771,7 +2771,7 @@ private Web3Impl createWeb3CallNoReturn(Ethereum eth, World world, ReceiptStore BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, null); TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), blockStore, - blockFactory, null, transactionExecutorFactory, null, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + blockFactory, null, transactionExecutorFactory, null, 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); return createWeb3CallNoReturn(eth, world, transactionPool, receiptStore); } @@ -2796,7 +2796,7 @@ private Web3Impl createWeb3(World world, BlockProcessor blockProcessor, ReceiptS BlockStore blockStore = world.getBlockStore(); TransactionExecutorFactory transactionExecutorFactory = buildTransactionExecutorFactory(blockStore, world.getBlockTxSignatureCache()); TransactionPool transactionPool = new TransactionPoolImpl(config, world.getRepositoryLocator(), - blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class), null); + blockStore, blockFactory, null, transactionExecutorFactory, world.getReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); RepositoryLocator repositoryLocator = new RepositoryLocator(world.getTrieStore(), world.getStateRootHandler()); return createWeb3( Web3Mocks.getMockEthereum(), blockChain, repositoryLocator, transactionPool, @@ -2947,8 +2947,7 @@ private TransactionExecutorFactory buildTransactionExecutorFactory( blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, null, signatureCache), - blockTxSignatureCache, - null); + blockTxSignatureCache); } private Block createChainWithOneBlock(World world) { diff --git a/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java b/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java index e672ba3fed7..1a80bcbff50 100644 --- a/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java +++ b/rskj-core/src/test/java/org/ethereum/util/EthModuleTestUtils.java @@ -97,8 +97,7 @@ public static TransactionExecutorFactory buildCustomExecutorFactory(World world, blockFactory, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, world.getBridgeSupportFactory(), world.getBlockTxSignatureCache()), - blockTxSignatureCache, - null + blockTxSignatureCache ); } diff --git a/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java b/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java index 502f67d4163..dada3866b25 100644 --- a/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java +++ b/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java @@ -205,7 +205,6 @@ private EthModule buildEthModule(World world) { null, new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, world.getBridgeSupportFactory(), new BlockTxSignatureCache(new ReceivedTxSignatureCache())), - null, null ); From f4eed873483956990676a27a0d3ffc2c429ede60 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Mon, 13 May 2024 15:47:30 -0400 Subject: [PATCH 07/21] Test fixes --- .../java/co/rsk/EtherSwapTest.java | 82 ------------------- .../src/main/java/co/rsk/mine/MinerUtils.java | 13 --- .../rsk/net/handler/TxPendingValidator.java | 2 +- .../txvalidator/TxNotNullValidator.java | 2 +- .../TxValidatorAccountBalanceValidator.java | 2 +- .../TxValidatorAccountStateValidator.java | 2 +- .../TxValidatorGasLimitValidator.java | 2 +- ...TxValidatorIntrinsicGasLimitValidator.java | 2 +- .../TxValidatorMaximumGasPriceValidator.java | 2 +- .../TxValidatorMinimuGasPriceValidator.java | 2 +- .../TxValidatorNonceRangeValidator.java | 2 +- .../TxValidatorNotRemascTxValidator.java | 2 +- .../handler/txvalidator/TxValidatorStep.java | 2 +- .../main/java/co/rsk/util/EthSwapUtil.java | 1 + ...xValidatorAccountBalanceValidatorTest.java | 21 +++-- .../java/co/rsk/util/EthSwapUtilTest.java | 15 ++-- 16 files changed, 31 insertions(+), 123 deletions(-) diff --git a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java index 0e9192df168..720bcf2ca84 100644 --- a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java +++ b/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java @@ -315,86 +315,4 @@ void whenClaimTxIsSentTwice_secondClaimTxShoulNotBeIncludedInMempool() throws Ex } ); } - - @Test - void whenTwoClaimTxAreSent_shouldCombineBothLockedAmountsToPayBothTx() throws Exception { - String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; - String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; - byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); - BigInteger firstLockedAmount = BigInteger.valueOf(500000); - BigInteger secondLockedAmount = BigInteger.valueOf(5000); - - byte[] lockData = CALL_LOCK_FUNCTION.encode( - preimageHash, - claimAddress, - 8000000); - - byte[] firstClaimTxData = CALL_CLAIM_FUNCTION.encode( - preimage, - firstLockedAmount, - refundAddress, - 8000000); - - byte[] secondClaimTxData = CALL_CLAIM_FUNCTION.encode( - preimage, - secondLockedAmount, - refundAddress, - 8000000); - - String cmd = String.format("%s -cp %s/%s co.rsk.Start --reset %s", baseJavaCmd, buildLibsPath, jarName, strBaseArgs); - CommandLineFixture.runCommand( - cmd, - 60, - TimeUnit.SECONDS, - proc -> { - try { - Response getBalanceResponse = getBalanceRequest(claimAddress); - JsonNode jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); - JsonNode currentBalance = jsonRpcResponse.get(0).get("result"); - BigInteger balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); - Assertions.assertEquals(0, balanceBigInt.compareTo(BigInteger.ZERO)); - - lockTxRequest(refundAddress, lockData, firstLockedAmount); - lockTxRequest(refundAddress, lockData, secondLockedAmount); - TimeUnit.SECONDS.sleep(5); - - Response firstClaimTxResponse = claimTxRequest(claimAddress, firstClaimTxData); - Response secondClaimTxResponse = claimTxRequest(claimAddress, secondClaimTxData); - TimeUnit.SECONDS.sleep(5); - - // Get gas used by first claim tx - jsonRpcResponse = objectMapper.readTree(firstClaimTxResponse.body().string()); - JsonNode firstClaimTxHash = jsonRpcResponse.get(0).get("result"); - - Response getTxReceiptResponse = getTxReceiptRequest(firstClaimTxHash.asText()); - jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); - BigInteger firstClaimTxGasUsed = new BigInteger(HexUtils.removeHexPrefix(jsonRpcResponse.get(0).get("result").get("gasUsed").asText()), 16); - - // Get gas used by second claim tx - jsonRpcResponse = objectMapper.readTree(secondClaimTxResponse.body().string()); - JsonNode secondClaimTxHash = jsonRpcResponse.get(0).get("result"); - - getTxReceiptResponse = getTxReceiptRequest(secondClaimTxHash.asText()); - jsonRpcResponse = objectMapper.readTree(getTxReceiptResponse.body().string()); - BigInteger secondClaimTxGasUsed = new BigInteger(HexUtils.removeHexPrefix(jsonRpcResponse.get(0).get("result").get("gasUsed").asText()), 16); - - // Add both locked amounts and subtract the total gas used to get the expected account balance - BigInteger totalGasUsed = firstClaimTxGasUsed.add(secondClaimTxGasUsed); - BigInteger expectedBalance = firstLockedAmount.add(secondLockedAmount).subtract(totalGasUsed); - - getBalanceResponse = getBalanceRequest(claimAddress); - jsonRpcResponse = objectMapper.readTree(getBalanceResponse.body().string()); - currentBalance = jsonRpcResponse.get(0).get("result"); - balanceBigInt = new BigInteger(HexUtils.removeHexPrefix(currentBalance.asText()), 16); - - Assertions.assertEquals(0, balanceBigInt.compareTo(expectedBalance)); - - - } catch (IOException | InterruptedException e) { - Assertions.fail(e); - } - } - ); - } } 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 6045426564d..30f7fd0be8e 100644 --- a/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java +++ b/rskj-core/src/main/java/co/rsk/mine/MinerUtils.java @@ -26,11 +26,9 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.RepositorySnapshot; import co.rsk.remasc.RemascTransaction; -import co.rsk.util.EthSwapUtil; import co.rsk.util.HexUtils; import co.rsk.validators.TxGasPriceCap; import org.bouncycastle.util.Arrays; -import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.SignatureCache; @@ -172,10 +170,6 @@ public List getAllTransactions(TransactionPool tr } public List filterTransactions(List txsToRemove, List txs, Map accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice, boolean isRskip252Enabled, SignatureCache signatureCache) { - return filterTransactions(txsToRemove, txs, accountNonces, originalRepo, minGasPrice, isRskip252Enabled, signatureCache, null); - } - - public List filterTransactions(List txsToRemove, List txs, Map accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice, boolean isRskip252Enabled, SignatureCache signatureCache, Constants constants) { List txsResult = new ArrayList<>(); for (org.ethereum.core.Transaction tx : txs) { try { @@ -193,13 +187,6 @@ public List filterTransactions(List expectedNonce = originalRepo.getNonce(txSender); } - if (EthSwapUtil.isClaimTx(tx, constants) - && !EthSwapUtil.hasLockedFunds(tx, signatureCache, originalRepo)) { - txsToRemove.add(tx); - logger.warn("Rejected tx={} because the funds is trying to claim no longer exist, removing tx from pending state.", hash); - continue; - } - if (isLowGasPriced(minGasPrice, tx)) { txsToRemove.add(tx); logger.warn("Rejected tx={} because of low gas account {}, removing tx from pending state.", hash, txSender); 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 cf6e1b81936..f14c8c52321 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 @@ -87,7 +87,7 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock, } for (TxValidatorStep step : validatorSteps) { - TransactionValidationResult validationResult = step.validate(tx, claimTransactionInfoHolder, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0); + TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0, claimTransactionInfoHolder); if (!validationResult.transactionIsValid()) { logger.info("[tx={}] validation failed with error: {}", tx.getHash(), validationResult.getErrorMessage()); return validationResult; diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java index 878079cf5fe..472ff196693 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java @@ -35,7 +35,7 @@ public class TxNotNullValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return this.validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index 641867f0a33..1c2d5888c07 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -33,7 +33,7 @@ */ public class TxValidatorAccountBalanceValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { if (isFreeTx) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java index 16c3555b31a..0470b0fa248 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java @@ -33,7 +33,7 @@ public class TxValidatorAccountStateValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java index 5c6bc6bb065..7bdcdef49d0 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java @@ -35,7 +35,7 @@ */ public class TxValidatorGasLimitValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } 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 33683222a36..82643c5c91c 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 @@ -47,7 +47,7 @@ public TxValidatorIntrinsicGasLimitValidator( } @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java index 27b0a6ddc13..e55cab17bf9 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java @@ -42,7 +42,7 @@ public TxValidatorMaximumGasPriceValidator(ActivationConfig activationConfig) { } @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java index 03ea5172b09..d4e2e2ed6ed 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java @@ -32,7 +32,7 @@ */ public class TxValidatorMinimuGasPriceValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java index 0a9c898b695..3f65d979e27 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java @@ -43,7 +43,7 @@ public TxValidatorNonceRangeValidator(int accountSlots) { } @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java index ee647882a48..5f1aaea21c8 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java @@ -35,7 +35,7 @@ */ public class TxValidatorNotRemascTxValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java index cd5f320d185..e930b2db51e 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java @@ -33,7 +33,7 @@ */ public interface TxValidatorStep { - TransactionValidationResult validate(Transaction tx, ClaimTransactionInfoHolder claimTransactionInfoHolder, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); + TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder); TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java index 9efbd26d81f..e3361959135 100644 --- a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java @@ -103,6 +103,7 @@ public static CallTransaction.Invocation getTxInvocation(Transaction newTx) { public static boolean isClaimTx(Transaction tx, Constants constants) { return tx.getReceiveAddress() != null + && !tx.getReceiveAddress().toHexString().isEmpty() && tx.getData() != null && tx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) && Arrays.equals(Arrays.copyOfRange(tx.getData(), 0, 4), Constants.CLAIM_FUNCTION_SIGNATURE); diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java index 5ad9c69c7c2..351b15afa75 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; +import co.rsk.util.EthSwapUtil; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; import org.ethereum.core.AccountState; @@ -26,6 +27,7 @@ import org.ethereum.crypto.ECKey; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; import org.mockito.Mockito; import java.math.BigInteger; @@ -49,9 +51,9 @@ void validAccountBalance() { TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); - Assertions.assertTrue(tvabv.validate(tx1, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx2, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx3, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx3, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); } @Test @@ -66,10 +68,15 @@ void invalidAccountBalance() { Mockito.when(tx2.getGasPrice()).thenReturn(Coin.valueOf(10)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(19)); - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); + try (MockedStatic ethSwapUtilMocked = Mockito.mockStatic(EthSwapUtil.class)){ + ethSwapUtilMocked.when(() -> EthSwapUtil.isClaimTx(Mockito.any(Transaction.class), Mockito.any(Constants.class))) + .thenReturn(false); + + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); - Assertions.assertFalse(tvabv.validate(tx1, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertFalse(tvabv.validate(tx2, null, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); + } } @Test @@ -89,7 +96,7 @@ void balanceIsNotValidatedIfFreeTx() { TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(); - Assertions.assertTrue(tv.validate(tx, null, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true).transactionIsValid()); + Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true, null).transactionIsValid()); } } diff --git a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java b/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java index b202c71a200..63aea375fc1 100644 --- a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java +++ b/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java @@ -48,12 +48,6 @@ void setup() { signatureCache = new ReceivedTxSignatureCache(); mockedRepository = mock(RepositorySnapshot.class); activations = mock(ActivationConfig.ForBlock.class); - - when(mockedRepository.getStorageValue( - eq(new RskAddress(testConstants.getEtherSwapContractAddress())), - any(DataWord.class))) - .thenReturn(DataWord.valueOf(1)); - when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); } @Test @@ -123,14 +117,15 @@ public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withMultipleClaim List pendingTransactions = new ArrayList<>(); pendingTransactions.add(mockedPendingClaimTx); - SignatureCache signatureCache = new ReceivedTxSignatureCache(); - RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); - ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); - when(mockedClaimTx.transactionCost(testConstants, activations, signatureCache)) .thenReturn(5L); when(mockedPendingClaimTx.transactionCost(testConstants, activations, signatureCache)) .thenReturn(5L); + when(mockedRepository.getStorageValue( + eq(new RskAddress(testConstants.getEtherSwapContractAddress())), + any(DataWord.class))) + .thenReturn(DataWord.valueOf(1)); + when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( mockedClaimTx, From c5cd703fa7fea15dd13e4daa937e6cd2f5366097 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Mon, 13 May 2024 16:33:17 -0400 Subject: [PATCH 08/21] Fix SonarCloud error --- rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java index e3361959135..f2331436b5f 100644 --- a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java @@ -40,8 +40,6 @@ import java.util.List; public class EthSwapUtil { - private static final Logger logger = LoggerFactory.getLogger(EthSwapUtil.class); - private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; private EthSwapUtil() { From 425a31337cdf2d9d8ef05095d84713db6d0a5707 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Wed, 15 May 2024 08:57:35 -0400 Subject: [PATCH 09/21] Implementing some suggestions from review comments --- .../main/java/co/rsk/core/bc/TransactionPoolImpl.java | 10 +++------- .../java/co/rsk/net/handler/TxPendingValidator.java | 1 - rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java | 2 -- 3 files changed, 3 insertions(+), 10 deletions(-) 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 ee1ff808090..7972f6bdfe0 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 @@ -75,7 +75,7 @@ public class TransactionPoolImpl implements TransactionPool { private Block bestBlock; - private TxPendingValidator validator; + private final TxPendingValidator validator; private final TxQuotaChecker quotaChecker; @@ -490,11 +490,6 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos } Coin costWithNewTx = accumTxCost.add(getTxBaseCost(newTx)); - boolean senderCanPay = costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0; - - if(senderCanPay) { - return true; - } ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( newTx, @@ -504,7 +499,8 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos bestBlock == null ? null : config.getActivationConfig().forBlock(bestBlock.getNumber()) ); - return EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(claimTransactionInfoHolder, transactions); + return costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0 + || EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(claimTransactionInfoHolder, transactions); } private Coin getTxBaseCost(Transaction tx) { 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 f14c8c52321..4c7773add85 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 @@ -68,7 +68,6 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig validatorSteps.add(new TxValidatorMaximumGasPriceValidator(activationConfig)); } - public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state, ClaimTransactionInfoHolder claimTransactionInfoHolder) { BigInteger blockGasLimit = BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit()); Coin minimumGasPrice = executionBlock.getMinimumGasPrice(); diff --git a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java index f2331436b5f..ea1029da0f2 100644 --- a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java @@ -32,8 +32,6 @@ import org.ethereum.util.ByteUtil; import org.ethereum.vm.DataWord; import org.ethereum.vm.GasCost; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.util.Arrays; From 3a94c395f808f6de4a2e305b9cfb2721e4dca21f Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Wed, 15 May 2024 13:49:02 -0400 Subject: [PATCH 10/21] Remove unused imports --- rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java b/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java index 7ecb88c9911..a679e97d146 100644 --- a/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/BlockExecutorTest.java @@ -51,7 +51,6 @@ import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.AssertionsKt; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; From 96d6c113e8d0b09bf39e99b20187c39e875d7afd Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Thu, 16 May 2024 15:55:24 -0400 Subject: [PATCH 11/21] Refactor isClaimTxAndValid to remove txCost argument --- .../TxValidatorAccountBalanceValidator.java | 2 +- rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java | 6 ++++-- .../java/org/ethereum/core/TransactionExecutor.java | 2 +- .../src/test/java/co/rsk/util/EthSwapUtilTest.java | 12 +++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index 1c2d5888c07..5cbf9283c95 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -45,7 +45,7 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); if (state.getBalance().compareTo(maximumPrice) >= 0 - || EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder, maximumPrice)) { + || EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder)) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java index ea1029da0f2..16f418ea9ea 100644 --- a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java +++ b/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java @@ -134,9 +134,9 @@ private static Coin getTxCost(Transaction tx, return txCost; } - public static boolean isClaimTxAndValid(ClaimTransactionInfoHolder claimTransactionInfoHolder, - Coin txCost) { + public static boolean isClaimTxAndValid(ClaimTransactionInfoHolder claimTransactionInfoHolder) { Transaction newTx = claimTransactionInfoHolder.getTx(); + ActivationConfig.ForBlock activation = claimTransactionInfoHolder.getActivation(); Constants constants = claimTransactionInfoHolder.getConstants(); SignatureCache signatureCache = claimTransactionInfoHolder.getSignatureCache(); RepositorySnapshot repositorySnapshot = claimTransactionInfoHolder.getRepositorySnapshot(); @@ -151,6 +151,8 @@ public static boolean isClaimTxAndValid(ClaimTransactionInfoHolder claimTransact Coin balanceWithClaim = repositorySnapshot.getBalance(newTx.getSender(signatureCache)) .add(lockedAmount); + Coin txCost = getTxCost(newTx, activation, constants, signatureCache); + return txCost.compareTo(balanceWithClaim) <= 0; } diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index f1b63dcd911..97c721e1712 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -182,7 +182,7 @@ private boolean init() { activations ); - if (!isCovers(senderBalance, totalCost) && !EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder, totalCost)) { + if (!isCovers(senderBalance, totalCost) && !EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); diff --git a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java b/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java index 63aea375fc1..a87fd624da6 100644 --- a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java +++ b/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java @@ -61,11 +61,13 @@ public void whenCalculateSwapHashIsCalled_shouldReturnExpectedHash() { @Test public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { - Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); - - Coin txCost = Coin.valueOf(5); SignatureCache signatureCache = new ReceivedTxSignatureCache(); + + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + + when(mockedClaimTx.transactionCost(any(Constants.class), any(ActivationConfig.ForBlock.class), any(SignatureCache.class))) + .thenReturn(5L); when(mockedRepository.getStorageValue(eq(mockedClaimTx.getReceiveAddress()), any(DataWord.class))) .thenReturn(DataWord.valueOf(1)); when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); @@ -75,10 +77,10 @@ public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { mockedRepository, signatureCache, testConstants, - null + mock(ActivationConfig.ForBlock.class) ); - boolean result = EthSwapUtil.isClaimTxAndValid(testClaimTransactionInfoHolder, txCost); + boolean result = EthSwapUtil.isClaimTxAndValid(testClaimTransactionInfoHolder); assertTrue(result); } From 5b32bd0c29d4ee6fe5797d1a225c120078d46609 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Thu, 16 May 2024 16:59:17 -0400 Subject: [PATCH 12/21] Remove unused imports --- .../src/test/java/co/rsk/test/builders/BlockChainBuilder.java | 1 - rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java | 1 - 2 files changed, 2 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java b/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java index a6b25269c67..dcf6aaff2ca 100644 --- a/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java +++ b/rskj-core/src/test/java/co/rsk/test/builders/BlockChainBuilder.java @@ -51,7 +51,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Supplier; /** * Created by ajlopez on 8/6/2016. diff --git a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java index 7037ea7d495..7b348a914bb 100644 --- a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -43,7 +43,6 @@ import org.mockito.Mockito; import java.util.Map; -import java.util.function.Supplier; /** * Created by Anton Nashatyrev on 29.12.2015. From c1fe7d2f6c564b5f0a1c73a08722cb6e22e03d1d Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Tue, 21 May 2024 09:10:26 -0400 Subject: [PATCH 13/21] Refactor claim transaction validation class and implement some suggestions --- ...wapTest.java => ClaimTransactionTest.java} | 18 +- .../java/co/rsk/core/bc/BlockExecutor.java | 7 +- .../core/bc/ClaimTransactionInfoHolder.java | 113 ------------- .../bc/ClaimTransactionValidator.java} | 160 ++++++++---------- .../co/rsk/core/bc/TransactionPoolImpl.java | 25 +-- .../rsk/net/handler/TxPendingValidator.java | 8 +- .../txvalidator/TxNotNullValidator.java | 4 +- .../TxValidatorAccountBalanceValidator.java | 19 ++- .../TxValidatorAccountStateValidator.java | 4 +- .../TxValidatorGasLimitValidator.java | 4 +- ...TxValidatorIntrinsicGasLimitValidator.java | 4 +- .../TxValidatorMaximumGasPriceValidator.java | 4 +- .../TxValidatorMinimuGasPriceValidator.java | 4 +- .../TxValidatorNonceRangeValidator.java | 4 +- .../TxValidatorNotRemascTxValidator.java | 4 +- .../handler/txvalidator/TxValidatorStep.java | 4 +- .../ethereum/core/TransactionExecutor.java | 16 +- ...xValidatorAccountBalanceValidatorTest.java | 37 ++-- ...ava => ClaimTransactionValidatorTest.java} | 62 +++---- 19 files changed, 181 insertions(+), 320 deletions(-) rename rskj-core/src/integrationTest/java/co/rsk/{EtherSwapTest.java => ClaimTransactionTest.java} (94%) delete mode 100644 rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java rename rskj-core/src/main/java/co/rsk/{util/EthSwapUtil.java => core/bc/ClaimTransactionValidator.java} (50%) rename rskj-core/src/test/java/co/rsk/util/{EthSwapUtilTest.java => ClaimTransactionValidatorTest.java} (73%) diff --git a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java b/rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java similarity index 94% rename from rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java rename to rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java index 720bcf2ca84..592058216c1 100644 --- a/rskj-core/src/integrationTest/java/co/rsk/EtherSwapTest.java +++ b/rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java @@ -19,15 +19,17 @@ package co.rsk; +import co.rsk.core.bc.ClaimTransactionValidator; import co.rsk.util.CommandLineFixture; -import co.rsk.util.EthSwapUtil; import co.rsk.util.HexUtils; import co.rsk.util.OkHttpClientTestFixture; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.squareup.okhttp.Response; import org.ethereum.config.Constants; +import org.ethereum.core.BlockTxSignatureCache; import org.ethereum.core.CallTransaction; +import org.ethereum.core.ReceivedTxSignatureCache; import org.ethereum.crypto.HashUtil; import org.ethereum.util.ByteUtil; import org.junit.jupiter.api.Assertions; @@ -44,7 +46,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Stream; -public class EtherSwapTest { +public class ClaimTransactionTest { private static final int LOCAL_PORT = 4444; private static final CallTransaction.Function CALL_LOCK_FUNCTION = CallTransaction.Function.fromSignature( @@ -68,6 +70,8 @@ public class EtherSwapTest { private String strBaseArgs; private String baseJavaCmd; + private ClaimTransactionValidator claimTransactionValidator; + @BeforeEach public void setup() throws IOException { String projectPath = System.getProperty("user.dir"); @@ -85,6 +89,8 @@ public void setup() throws IOException { baseArgs = new String[]{"--regtest"}; strBaseArgs = String.join(" ", baseArgs); baseJavaCmd = String.format("java %s", String.format("-Drsk.conf.file=%s", rskConfFile)); + + claimTransactionValidator = new ClaimTransactionValidator( new BlockTxSignatureCache(new ReceivedTxSignatureCache()), Constants.regtest()); } private Response lockTxRequest(String refundAddress, byte[] lockData, BigInteger amount) throws IOException { @@ -155,7 +161,7 @@ void whenClaimTxIsSend_shouldShouldFailDueToLowFundsInContract() throws Exceptio String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); + byte[] preimageHash = HashUtil.sha256(claimTransactionValidator.encodePacked(preimage)); BigInteger amount = BigInteger.valueOf(5000); byte[] lockData = CALL_LOCK_FUNCTION.encode( @@ -207,7 +213,7 @@ void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); + byte[] preimageHash = HashUtil.sha256(claimTransactionValidator.encodePacked(preimage)); BigInteger amount = BigInteger.valueOf(500000); byte[] lockData = CALL_LOCK_FUNCTION.encode( @@ -262,11 +268,11 @@ void whenClaimTxIsSend_shouldExecuteEvenIfSenderHasNoFunds() throws Exception { } @Test - void whenClaimTxIsSentTwice_secondClaimTxShoulNotBeIncludedInMempool() throws Exception { + void whenClaimTxIsSentTwice_secondClaimTxShouldNotBeIncludedInMempool() throws Exception { String refundAddress = "0x7986b3df570230288501eea3d890bd66948c9b79"; String claimAddress = "0x8486054b907b0d79569723c761b7113736d32c5a"; byte[] preimage = "preimage".getBytes(StandardCharsets.UTF_8); - byte[] preimageHash = HashUtil.sha256(EthSwapUtil.encodePacked(preimage)); + byte[] preimageHash = HashUtil.sha256(claimTransactionValidator.encodePacked(preimage)); BigInteger amount = BigInteger.valueOf(500000); byte[] lockData = CALL_LOCK_FUNCTION.encode( diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java index 12c1f5b5393..4ec10f02d11 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java @@ -26,7 +26,6 @@ import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; -import co.rsk.util.EthSwapUtil; import com.google.common.annotations.VisibleForTesting; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -66,6 +65,7 @@ public class BlockExecutor { private final Constants constants; private final SignatureCache signatureCache; + private final ClaimTransactionValidator claimTransactionValidator; public BlockExecutor( ActivationConfig activationConfig, @@ -78,6 +78,7 @@ public BlockExecutor( this.activationConfig = activationConfig; this.constants = constants; this.signatureCache = signatureCache; + this.claimTransactionValidator = new ClaimTransactionValidator(signatureCache, constants); } /** @@ -291,8 +292,8 @@ private BlockResult executeInternal( for (Transaction tx : block.getTransactionsList()) { logger.trace("apply block: [{}] tx: [{}] ", block.getNumber(), i); - if (EthSwapUtil.isClaimTx(tx, constants) - && !EthSwapUtil.hasLockedFunds(tx,signatureCache, track)) { + if (claimTransactionValidator.isClaimTx(tx) + && !claimTransactionValidator.hasLockedFunds(tx, track)) { logger.warn("block: [{}] discarded claim tx: [{}], because the funds it tries to claim no longer exist in contract", block.getNumber(), tx.getHash()); diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java deleted file mode 100644 index 4dfe2b29561..00000000000 --- a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionInfoHolder.java +++ /dev/null @@ -1,113 +0,0 @@ -package co.rsk.core.bc; - -import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; -import org.ethereum.config.Constants; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; -import org.ethereum.core.SignatureCache; -import org.ethereum.core.Transaction; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.math.BigInteger; -import java.util.Objects; - -public class ClaimTransactionInfoHolder { - @Nonnull - private final Transaction tx; - - @Nonnull - private final RepositorySnapshot repositorySnapshot; - - @Nonnull - private final SignatureCache signatureCache; - - @Nonnull - private final Constants constants; - - @Nullable - private final AccountState accountState; - - @Nullable - private final ActivationConfig.ForBlock activation; - - private Coin txUserBalance; - - public ClaimTransactionInfoHolder(@Nonnull Transaction tx, - @Nonnull RepositorySnapshot repositorySnapshot, - @Nonnull SignatureCache signatureCache, - @Nonnull Constants constants, - @Nullable ActivationConfig.ForBlock activation) { - this.tx = Objects.requireNonNull(tx); - this.repositorySnapshot = Objects.requireNonNull(repositorySnapshot); - this.signatureCache = Objects.requireNonNull(signatureCache); - this.constants = Objects.requireNonNull(constants); - this.accountState = repositorySnapshot.getAccountState(signatureCache.getSender(tx)); - this.activation = activation; - } - - @Nonnull - private Coin getSenderBalance() { - return accountState == null ? Coin.ZERO : accountState.getBalance(); - } - - @Nonnull - private Coin getTxUserBalance() { - if (txUserBalance == null) { - txUserBalance = repositorySnapshot.getBalance(tx.getSender(signatureCache)); - } - return txUserBalance; - } - - public boolean accountExists() { - return accountState != null; - } - - @Nonnull - public BigInteger getAccountNonce() { - return accountState == null ? BigInteger.ZERO : accountState.getNonce(); - } - - public boolean canPayForTx() { - Coin txCost = tx.getGasPrice().multiply(tx.getGasLimitAsInteger()); - - Coin senderB = getSenderBalance(); - if (senderB.compareTo(txCost) >= 0) { - return true; - } - - Coin txUserB = getTxUserBalance(); - return txUserB.add(senderB).compareTo(txCost) >= 0; - } - - @Nonnull - public Transaction getTx() { - return tx; - } - - @Nonnull - public RepositorySnapshot getRepositorySnapshot() { - return repositorySnapshot; - } - - @Nonnull - public SignatureCache getSignatureCache() { - return signatureCache; - } - - @Nonnull - public Constants getConstants() { - return constants; - } - - @Nullable - public AccountState getAccountState() { - return accountState; - } - - @Nullable - public ActivationConfig.ForBlock getActivation() { - return activation; - } -} diff --git a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java similarity index 50% rename from rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java rename to rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java index 16f418ea9ea..77f7a7022ce 100644 --- a/rskj-core/src/main/java/co/rsk/util/EthSwapUtil.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java @@ -1,29 +1,10 @@ -/* - * This file is part of RskJ - * Copyright (C) 2024 RSK Labs Ltd. - * (derived from ethereumJ library, Copyright (c) 2016 ) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -package co.rsk.util; +package co.rsk.core.bc; import co.rsk.core.Coin; import co.rsk.core.RskAddress; -import co.rsk.core.bc.ClaimTransactionInfoHolder; import co.rsk.db.RepositorySnapshot; +import co.rsk.util.HexUtils; import org.ethereum.config.Constants; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.CallTransaction; import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; @@ -33,18 +14,31 @@ import org.ethereum.vm.DataWord; import org.ethereum.vm.GasCost; +import javax.annotation.Nonnull; import java.math.BigInteger; import java.util.Arrays; import java.util.List; +import java.util.Objects; -public class EthSwapUtil { +public class ClaimTransactionValidator { private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; + private static final String CLAIM_METHOD_ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"preimage\",\"type\":\"bytes32\"}, {\"name\":\"amount\",\"type\":\"uint256\"}, {\"name\":\"address\",\"type\":\"address\"}, {\"name\":\"timelock\",\"type\":\"uint256\"}],\"name\":\"claim\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]"; - private EthSwapUtil() { - throw new IllegalStateException("Utility class"); + @Nonnull + private final SignatureCache signatureCache; + + @Nonnull + private final Constants constants; + + private final CallTransaction.Contract contract = new CallTransaction.Contract(CLAIM_METHOD_ABI);; + + public ClaimTransactionValidator(@Nonnull SignatureCache signatureCache, + @Nonnull Constants constants) { + this.signatureCache = Objects.requireNonNull(signatureCache); + this.constants = Objects.requireNonNull(constants); } - public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatureCache) { + private byte[] calculateSwapHash(Transaction newTx) { CallTransaction.Invocation invocation = getTxInvocation(newTx); @@ -68,7 +62,30 @@ public static byte[] calculateSwapHash(Transaction newTx, SignatureCache signatu return HashUtil.keccak256(argumentsBytes); } - public static byte[] encodePacked(Object...arguments) { + private CallTransaction.Invocation getTxInvocation(Transaction newTx) { + return contract.parseInvocation(newTx.getData()); + } + + private Coin getLockedAmount(Transaction tx) { + CallTransaction.Invocation invocation = getTxInvocation(tx); + BigInteger amount = (BigInteger) invocation.args[1]; + + return Coin.valueOf(amount.longValue()); + } + + private Coin getTxCost(Transaction tx) { + BigInteger gasLimit = BigInteger.valueOf(GasCost.toGas(tx.getGasLimit())); + + return tx.getValue().add(tx.getGasPrice().multiply(gasLimit)); + } + + private boolean isSameTx(Transaction pendingTx, Transaction newTx) { + return pendingTx.getSender(signatureCache).toHexString().equals(newTx.getSender(signatureCache).toHexString()) + && pendingTx.getReceiveAddress().toHexString().equals(newTx.getReceiveAddress().toHexString()) + && Arrays.equals(pendingTx.getData(), newTx.getData()); + } + + public byte[] encodePacked(Object...arguments) { byte[] encodedArguments = new byte[]{}; for(Object arg: arguments) { @@ -91,22 +108,16 @@ public static byte[] encodePacked(Object...arguments) { return encodedArguments; } - public static CallTransaction.Invocation getTxInvocation(Transaction newTx) { - String abi = "[{\"constant\":false,\"inputs\":[{\"name\":\"preimage\",\"type\":\"bytes32\"}, {\"name\":\"amount\",\"type\":\"uint256\"}, {\"name\":\"address\",\"type\":\"address\"}, {\"name\":\"timelock\",\"type\":\"uint256\"}],\"name\":\"claim\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]"; - CallTransaction.Contract contract = new CallTransaction.Contract(abi); - return contract.parseInvocation(newTx.getData()); - } - - public static boolean isClaimTx(Transaction tx, Constants constants) { + public boolean isClaimTx(Transaction tx) { return tx.getReceiveAddress() != null - && !tx.getReceiveAddress().toHexString().isEmpty() && tx.getData() != null - && tx.getReceiveAddress().toHexString().equalsIgnoreCase(constants.getEtherSwapContractAddress()) + && constants.getEtherSwapContractAddress().equalsIgnoreCase(tx.getReceiveAddress().toHexString()) + && tx.getData().length > 4 && Arrays.equals(Arrays.copyOfRange(tx.getData(), 0, 4), Constants.CLAIM_FUNCTION_SIGNATURE); } - public static boolean hasLockedFunds(Transaction tx, SignatureCache signatureCache, RepositorySnapshot repositorySnapshot) { - String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(tx, signatureCache)); + public boolean hasLockedFunds(Transaction tx, RepositorySnapshot repositorySnapshot) { + String swapHash = HexUtils.toUnformattedJsonHex(calculateSwapHash(tx)); byte[] key = HashUtil.keccak256(HexUtils.decode(HexUtils.stringToByteArray(swapHash + SWAPS_MAP_POSITION))); DataWord swapRecord = repositorySnapshot.getStorageValue(tx.getReceiveAddress(), DataWord.valueOf(key)); @@ -114,44 +125,19 @@ public static boolean hasLockedFunds(Transaction tx, SignatureCache signatureCac return swapRecord != null; } - private static Coin getLockedAmount(Transaction tx) { - CallTransaction.Invocation invocation = getTxInvocation(tx); - BigInteger amount = (BigInteger) invocation.args[1]; - - return Coin.valueOf(amount.longValue()); - } - - private static Coin getTxCost(Transaction tx, - ActivationConfig.ForBlock activation, - Constants constants, - SignatureCache signatureCache) { - Coin txCost = tx.getValue(); - if (activation == null || tx.transactionCost(constants, activation, signatureCache) > 0) { - BigInteger gasLimit = BigInteger.valueOf(GasCost.toGas(tx.getGasLimit())); - txCost = txCost.add(tx.getGasPrice().multiply(gasLimit)); - } - - return txCost; - } - - public static boolean isClaimTxAndValid(ClaimTransactionInfoHolder claimTransactionInfoHolder) { - Transaction newTx = claimTransactionInfoHolder.getTx(); - ActivationConfig.ForBlock activation = claimTransactionInfoHolder.getActivation(); - Constants constants = claimTransactionInfoHolder.getConstants(); - SignatureCache signatureCache = claimTransactionInfoHolder.getSignatureCache(); - RepositorySnapshot repositorySnapshot = claimTransactionInfoHolder.getRepositorySnapshot(); + public boolean isClaimTxAndValid(Transaction tx, RepositorySnapshot repositorySnapshot) { - if(!isClaimTx(newTx, constants)) { + if(!isClaimTx(tx)) { return false; } - if(hasLockedFunds(newTx, signatureCache, repositorySnapshot)){ - Coin lockedAmount = getLockedAmount(newTx); + if(hasLockedFunds(tx, repositorySnapshot)){ + Coin lockedAmount = getLockedAmount(tx); - Coin balanceWithClaim = repositorySnapshot.getBalance(newTx.getSender(signatureCache)) + Coin balanceWithClaim = repositorySnapshot.getBalance(tx.getSender(signatureCache)) .add(lockedAmount); - Coin txCost = getTxCost(newTx, activation, constants, signatureCache); + Coin txCost = getTxCost(tx); return txCost.compareTo(balanceWithClaim) <= 0; } @@ -159,30 +145,18 @@ public static boolean isClaimTxAndValid(ClaimTransactionInfoHolder claimTransact return false; } - private static boolean isSameTx(Transaction pendingTx, Transaction newTx, SignatureCache signatureCache) { - return pendingTx.getSender(signatureCache).toHexString().equals(newTx.getSender(signatureCache).toHexString()) - && pendingTx.getReceiveAddress().toHexString().equals(newTx.getReceiveAddress().toHexString()) - && Arrays.equals(pendingTx.getData(), newTx.getData()); - } - - public static boolean isClaimTxAndSenderCanPayAlongPendingTx(ClaimTransactionInfoHolder claimTransactionInfoHolder, List pendingTransactions) { - Transaction newTx = claimTransactionInfoHolder.getTx(); - ActivationConfig.ForBlock activation = claimTransactionInfoHolder.getActivation(); - Constants constants = claimTransactionInfoHolder.getConstants(); - SignatureCache signatureCache = claimTransactionInfoHolder.getSignatureCache(); - RepositorySnapshot repositorySnapshot = claimTransactionInfoHolder.getRepositorySnapshot(); - - if(!isClaimTx(newTx, constants) - || !hasLockedFunds(newTx, signatureCache, repositorySnapshot)) { + public boolean canPayPendingAndNewClaimTx(Transaction newTx, RepositorySnapshot repositorySnapshot, List pendingTransactions) { + if(!isClaimTx(newTx) + || !hasLockedFunds(newTx, repositorySnapshot)) { return false; } Coin totalLockedAmount = getLockedAmount(newTx); - Coin totalClaimTxCost = getTxCost(newTx, activation, constants, signatureCache); + Coin totalClaimTxCost = getTxCost(newTx); Coin totalPendingTxCost = Coin.ZERO; for (Transaction tx : pendingTransactions) { - if(isSameTx(tx, newTx, signatureCache)) { + if(isSameTx(tx, newTx)) { return false; } @@ -192,11 +166,11 @@ public static boolean isClaimTxAndSenderCanPayAlongPendingTx(ClaimTransactionInf continue; } - if(isClaimTx(tx, constants)) { - totalClaimTxCost = totalClaimTxCost.add(getTxCost(tx, activation, constants, signatureCache)); + if(isClaimTx(tx)) { + totalClaimTxCost = totalClaimTxCost.add(getTxCost(tx)); totalLockedAmount = totalLockedAmount.add(getLockedAmount(tx)); } else { - totalPendingTxCost = totalPendingTxCost.add(getTxCost(tx, activation, constants, signatureCache)); + totalPendingTxCost = totalPendingTxCost.add(getTxCost(tx)); } } @@ -206,4 +180,14 @@ public static boolean isClaimTxAndSenderCanPayAlongPendingTx(ClaimTransactionInf return balanceAfterPendingTx.add(totalLockedAmount).compareTo(totalClaimTxCost) >= 0; } + + @Nonnull + public SignatureCache getSignatureCache() { + return signatureCache; + } + + @Nonnull + public Constants getConstants() { + return constants; + } } 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 7972f6bdfe0..64bdf567da5 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 @@ -26,7 +26,6 @@ import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.TxPendingValidator; import co.rsk.net.handler.quota.TxQuotaChecker; -import co.rsk.util.EthSwapUtil; import com.google.common.annotations.VisibleForTesting; import org.ethereum.core.*; import org.ethereum.db.BlockStore; @@ -81,6 +80,8 @@ public class TransactionPoolImpl implements TransactionPool { private final GasPriceTracker gasPriceTracker; + private final ClaimTransactionValidator claimTxValidator; + @java.lang.SuppressWarnings("squid:S107") public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator repositoryLocator, BlockStore blockStore, BlockFactory blockFactory, EthereumListener listener, TransactionExecutorFactory transactionExecutorFactory, SignatureCache signatureCache, int outdatedThreshold, int outdatedTimeout, TxQuotaChecker txQuotaChecker, GasPriceTracker gasPriceTracker) { this.config = config; @@ -111,6 +112,8 @@ public TransactionPoolImpl(RskSystemProperties config, RepositoryLocator reposit if (this.quotaChecker != null && this.config.isAccountTxRateLimitEnabled() && this.config.accountTxRateLimitCleanerPeriod() > 0) { this.accountTxRateLimitCleanerTimer = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "TxQuotaCleanerTimer")); } + + this.claimTxValidator = new ClaimTransactionValidator(this.signatureCache, this.config.getNetworkConstants()); } @Override @@ -461,15 +464,7 @@ private Block createFakePendingBlock(Block best) { } private TransactionValidationResult shouldAcceptTx(Transaction tx, RepositorySnapshot currentRepository) { - ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( - tx, - currentRepository, - signatureCache, - config.getNetworkConstants(), - bestBlock == null ? null : config.getActivationConfig().forBlock(bestBlock.getNumber()) - ); - - return validator.isValid(tx, bestBlock, currentRepository.getAccountState(tx.getSender(signatureCache)), claimTransactionInfoHolder); + return validator.isValid(tx, bestBlock, currentRepository.getAccountState(tx.getSender(signatureCache)), currentRepository); } /** @@ -491,16 +486,8 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos Coin costWithNewTx = accumTxCost.add(getTxBaseCost(newTx)); - ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( - newTx, - currentRepository, - signatureCache, - config.getNetworkConstants(), - bestBlock == null ? null : config.getActivationConfig().forBlock(bestBlock.getNumber()) - ); - return costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0 - || EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(claimTransactionInfoHolder, transactions); + || claimTxValidator.canPayPendingAndNewClaimTx(newTx, currentRepository, transactions); } private Coin getTxBaseCost(Transaction tx) { 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 4c7773add85..0f2f9e43b1f 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 @@ -18,7 +18,7 @@ package co.rsk.net.handler; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.txvalidator.*; import org.bouncycastle.util.BigIntegers; @@ -62,13 +62,13 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig validatorSteps.add(new TxValidatorNotRemascTxValidator()); validatorSteps.add(new TxValidatorGasLimitValidator()); validatorSteps.add(new TxValidatorNonceRangeValidator(accountSlots)); - validatorSteps.add(new TxValidatorAccountBalanceValidator()); + validatorSteps.add(new TxValidatorAccountBalanceValidator(constants, signatureCache)); validatorSteps.add(new TxValidatorMinimuGasPriceValidator()); validatorSteps.add(new TxValidatorIntrinsicGasLimitValidator(constants, activationConfig, signatureCache)); validatorSteps.add(new TxValidatorMaximumGasPriceValidator(activationConfig)); } - public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state, RepositorySnapshot repositorySnapshot) { BigInteger blockGasLimit = BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit()); Coin minimumGasPrice = executionBlock.getMinimumGasPrice(); long bestBlockNumber = executionBlock.getNumber(); @@ -86,7 +86,7 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock, } for (TxValidatorStep step : validatorSteps) { - TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0, claimTransactionInfoHolder); + TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0, repositorySnapshot); if (!validationResult.transactionIsValid()) { logger.info("[tx={}] validation failed with error: {}", tx.getHash(), validationResult.getErrorMessage()); return validationResult; diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java index 472ff196693..9328154c863 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -35,7 +35,7 @@ public class TxNotNullValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return this.validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index 5cbf9283c95..f596fc8381e 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -19,10 +19,12 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.core.bc.ClaimTransactionValidator; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import co.rsk.util.EthSwapUtil; +import org.ethereum.config.Constants; import org.ethereum.core.AccountState; +import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; import javax.annotation.Nullable; @@ -32,8 +34,17 @@ * Checks if an account can pay the transaction execution cost */ public class TxValidatorAccountBalanceValidator implements TxValidatorStep { + + private ClaimTransactionValidator claimTransactionValidator; + + public TxValidatorAccountBalanceValidator( + Constants constants, + SignatureCache signatureCache) { + this.claimTransactionValidator = new ClaimTransactionValidator(signatureCache, constants); + } + @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { if (isFreeTx) { return TransactionValidationResult.ok(); } @@ -45,7 +56,7 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); if (state.getBalance().compareTo(maximumPrice) >= 0 - || EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder)) { + || claimTransactionValidator.isClaimTxAndValid(tx, repositorySnapshot)) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java index 0470b0fa248..bbdec600b20 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -33,7 +33,7 @@ public class TxValidatorAccountStateValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java index 7bdcdef49d0..c0ba762b98d 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; import org.ethereum.core.AccountState; @@ -35,7 +35,7 @@ */ public class TxValidatorGasLimitValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } 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 82643c5c91c..4ba96db3d55 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 @@ -18,7 +18,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -47,7 +47,7 @@ public TxValidatorIntrinsicGasLimitValidator( } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java index e55cab17bf9..2fe89910982 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import co.rsk.validators.TxGasPriceCap; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -42,7 +42,7 @@ public TxValidatorMaximumGasPriceValidator(ActivationConfig activationConfig) { } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java index d4e2e2ed6ed..e93bed61e50 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -32,7 +32,7 @@ */ public class TxValidatorMinimuGasPriceValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java index 3f65d979e27..9a47081066e 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -43,7 +43,7 @@ public TxValidatorNonceRangeValidator(int accountSlots) { } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java index 5f1aaea21c8..360d51021da 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import co.rsk.remasc.RemascTransaction; import org.ethereum.core.AccountState; @@ -35,7 +35,7 @@ */ public class TxValidatorNotRemascTxValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java index e930b2db51e..16158e1dd75 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java @@ -19,7 +19,7 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -33,7 +33,7 @@ */ public interface TxValidatorStep { - TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, ClaimTransactionInfoHolder claimTransactionInfoHolder); + TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot); TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); } diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index 97c721e1712..697a2fc3acc 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -21,13 +21,12 @@ import co.rsk.config.VmConfig; import co.rsk.core.Coin; import co.rsk.core.RskAddress; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.core.bc.ClaimTransactionValidator; import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; import co.rsk.panic.PanicProcessor; import co.rsk.rpc.modules.trace.ProgramSubtrace; -import co.rsk.util.EthSwapUtil; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; @@ -103,6 +102,8 @@ public class TransactionExecutor { private boolean localCall = false; private boolean txWasPaid = false; + private final ClaimTransactionValidator claimTransactionValidator; + public TransactionExecutor( Constants constants, ActivationConfig activationConfig, Transaction tx, int txindex, RskAddress coinbase, Repository track, BlockStore blockStore, ReceiptStore receiptStore, BlockFactory blockFactory, @@ -127,6 +128,7 @@ public TransactionExecutor( this.precompiledContracts = precompiledContracts; this.enableRemasc = remascEnabled; this.deletedAccounts = new HashSet<>(deletedAccounts); + this.claimTransactionValidator = new ClaimTransactionValidator(signatureCache, constants); } /** @@ -174,15 +176,7 @@ private boolean init() { Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); - ClaimTransactionInfoHolder claimTransactionInfoHolder = new ClaimTransactionInfoHolder( - tx, - track, - signatureCache, - constants, - activations - ); - - if (!isCovers(senderBalance, totalCost) && !EthSwapUtil.isClaimTxAndValid(claimTransactionInfoHolder)) { + if (!isCovers(senderBalance, totalCost) && !claimTransactionValidator.isClaimTxAndValid(tx, track)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java index 351b15afa75..8f033050f3e 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java @@ -19,21 +19,35 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.util.EthSwapUtil; +import co.rsk.core.RskAddress; +import co.rsk.db.RepositorySnapshot; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; import org.ethereum.core.AccountState; +import org.ethereum.core.BlockTxSignatureCache; +import org.ethereum.core.ReceivedTxSignatureCache; +import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; import org.ethereum.crypto.ECKey; +import org.ethereum.vm.DataWord; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; import org.mockito.Mockito; import java.math.BigInteger; class TxValidatorAccountBalanceValidatorTest { + private Constants constants; + private SignatureCache signatureCache; + + @BeforeEach + void setUp() { + constants = Constants.regtest(); + signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + } + @Test void validAccountBalance() { Transaction tx1 = Mockito.mock(Transaction.class); @@ -49,7 +63,7 @@ void validAccountBalance() { Mockito.when(tx3.getGasPrice()).thenReturn(Coin.valueOf(5000)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(10000)); - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(constants, signatureCache); Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); @@ -61,22 +75,21 @@ void invalidAccountBalance() { Transaction tx1 = Mockito.mock(Transaction.class); Transaction tx2 = Mockito.mock(Transaction.class); AccountState as = Mockito.mock(AccountState.class); + RepositorySnapshot rs = Mockito.mock(RepositorySnapshot.class); + Mockito.when(tx1.getGasLimitAsInteger()).thenReturn(BigInteger.valueOf(1)); Mockito.when(tx2.getGasLimitAsInteger()).thenReturn(BigInteger.valueOf(2)); Mockito.when(tx1.getGasPrice()).thenReturn(Coin.valueOf(20)); Mockito.when(tx2.getGasPrice()).thenReturn(Coin.valueOf(10)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(19)); + Mockito.when(rs.getStorageValue(Mockito.any(RskAddress.class), Mockito.any(DataWord.class))).thenReturn(null); + Mockito.when(rs.getBalance(Mockito.any(RskAddress.class))).thenReturn(Coin.valueOf(19)); - try (MockedStatic ethSwapUtilMocked = Mockito.mockStatic(EthSwapUtil.class)){ - ethSwapUtilMocked.when(() -> EthSwapUtil.isClaimTx(Mockito.any(Transaction.class), Mockito.any(Constants.class))) - .thenReturn(false); - - TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(); + TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(constants, signatureCache); - Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); - Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); - } + Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, rs).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, rs).transactionIsValid()); } @Test @@ -94,7 +107,7 @@ void balanceIsNotValidatedIfFreeTx() { tx.sign(new ECKey().getPrivKeyBytes()); - TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(); + TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(constants, signatureCache); Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true, null).transactionIsValid()); } diff --git a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java similarity index 73% rename from rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java rename to rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java index a87fd624da6..559a323fcba 100644 --- a/rskj-core/src/test/java/co/rsk/util/EthSwapUtilTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java @@ -2,7 +2,7 @@ import co.rsk.core.Coin; import co.rsk.core.RskAddress; -import co.rsk.core.bc.ClaimTransactionInfoHolder; +import co.rsk.core.bc.ClaimTransactionValidator; import co.rsk.db.RepositorySnapshot; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; @@ -27,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class EthSwapUtilTest { +public class ClaimTransactionValidatorTest { private final CallTransaction.Function CLAIM_FUNCTION = CallTransaction.Function.fromSignature( "claim", @@ -37,27 +37,29 @@ public class EthSwapUtilTest { private final Constants testConstants = Constants.regtest(); - private final String EXPECTED_HASH = "0x3dc21e0a710489c951f29205f9961b2c311d48fdf5a35545469d7b43e88f7624"; - - SignatureCache signatureCache; - RepositorySnapshot mockedRepository; - ActivationConfig.ForBlock activations; + private SignatureCache signatureCache; + private RepositorySnapshot mockedRepository; + private ActivationConfig.ForBlock activations; + private ClaimTransactionValidator claimTransactionValidator; @BeforeEach void setup() { signatureCache = new ReceivedTxSignatureCache(); mockedRepository = mock(RepositorySnapshot.class); activations = mock(ActivationConfig.ForBlock.class); + claimTransactionValidator = new ClaimTransactionValidator(signatureCache, testConstants); } - @Test - public void whenCalculateSwapHashIsCalled_shouldReturnExpectedHash() { - Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); - - byte[] result = EthSwapUtil.calculateSwapHash(mockedClaimTx, new ReceivedTxSignatureCache()); - - assertEquals(EXPECTED_HASH, HexUtils.toJsonHex(result)); - } +// @Test +// public void whenCalculateSwapHashIsCalled_shouldReturnExpectedHash() { +// String expectedHash = "0x3dc21e0a710489c951f29205f9961b2c311d48fdf5a35545469d7b43e88f7624"; +// +// Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); +// +// byte[] result = claimTransactionValidator.calculateSwapHash(mockedClaimTx, new ReceivedTxSignatureCache()); +// +// assertEquals(expectedHash, HexUtils.toJsonHex(result)); +// } @Test public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { @@ -72,15 +74,7 @@ public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { .thenReturn(DataWord.valueOf(1)); when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); - ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( - mockedClaimTx, - mockedRepository, - signatureCache, - testConstants, - mock(ActivationConfig.ForBlock.class) - ); - - boolean result = EthSwapUtil.isClaimTxAndValid(testClaimTransactionInfoHolder); + boolean result = claimTransactionValidator.isClaimTxAndValid(mockedClaimTx, mockedRepository); assertTrue(result); } @@ -99,15 +93,7 @@ public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withIdenticalNewA when(mockedClaimTx.transactionCost(testConstants, activations, signatureCache)) .thenReturn(5L); - ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( - mockedClaimTx, - mockedRepository, - signatureCache, - testConstants, - activations - ); - - boolean result = EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(testClaimTransactionInfoHolder, pendingTransactions); + boolean result = claimTransactionValidator.canPayPendingAndNewClaimTx(mockedClaimTx, mockedRepository, pendingTransactions); assertFalse(result); } @@ -129,15 +115,7 @@ public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withMultipleClaim .thenReturn(DataWord.valueOf(1)); when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); - ClaimTransactionInfoHolder testClaimTransactionInfoHolder = new ClaimTransactionInfoHolder( - mockedClaimTx, - mockedRepository, - signatureCache, - testConstants, - activations - ); - - boolean result = EthSwapUtil.isClaimTxAndSenderCanPayAlongPendingTx(testClaimTransactionInfoHolder, pendingTransactions); + boolean result = claimTransactionValidator.canPayPendingAndNewClaimTx(mockedClaimTx, mockedRepository, pendingTransactions); assertTrue(result); } From 683001c014a4e4cb08afca4a98cbe808acab965d Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Wed, 22 May 2024 08:18:32 -0400 Subject: [PATCH 14/21] Test fixes and add placeholder hardfork --- .../java/co/rsk/core/bc/BlockExecutor.java | 14 ++++++++------ .../rsk/core/bc/ClaimTransactionValidator.java | 17 ++++++++++++----- .../co/rsk/core/bc/TransactionPoolImpl.java | 9 +++++++-- .../co/rsk/net/handler/TxPendingValidator.java | 2 +- .../txvalidator/TxNotNullValidator.java | 3 ++- .../TxValidatorAccountBalanceValidator.java | 7 ++++--- .../TxValidatorAccountStateValidator.java | 3 ++- .../TxValidatorGasLimitValidator.java | 3 ++- .../TxValidatorIntrinsicGasLimitValidator.java | 2 +- .../TxValidatorMaximumGasPriceValidator.java | 2 +- .../TxValidatorMinimuGasPriceValidator.java | 3 ++- .../TxValidatorNonceRangeValidator.java | 3 ++- .../TxValidatorNotRemascTxValidator.java | 3 ++- .../handler/txvalidator/TxValidatorStep.java | 3 ++- .../blockchain/upgrades/ConsensusRule.java | 3 ++- .../blockchain/upgrades/NetworkUpgrade.java | 3 ++- .../org/ethereum/core/TransactionExecutor.java | 2 +- .../src/main/resources/config/devnet.conf | 3 ++- rskj-core/src/main/resources/config/main.conf | 3 ++- .../src/main/resources/config/regtest.conf | 3 ++- .../src/main/resources/config/testnet.conf | 1 + rskj-core/src/main/resources/expected.conf | 2 ++ rskj-core/src/main/resources/reference.conf | 1 + .../java/co/rsk/mine/MainNetMinerTest.java | 3 ++- ...TxValidatorAccountBalanceValidatorTest.java | 18 ++++++++++++------ .../rsk/remasc/RemascStorageProviderTest.java | 5 +++++ .../util/ClaimTransactionValidatorTest.java | 8 +++++--- .../upgrades/ActivationConfigTest.java | 2 ++ .../upgrades/ActivationConfigsForTest.java | 1 - 29 files changed, 89 insertions(+), 43 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java index 4ec10f02d11..4a9c1b37582 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java @@ -292,12 +292,14 @@ private BlockResult executeInternal( for (Transaction tx : block.getTransactionsList()) { logger.trace("apply block: [{}] tx: [{}] ", block.getNumber(), i); - if (claimTransactionValidator.isClaimTx(tx) - && !claimTransactionValidator.hasLockedFunds(tx, track)) { - logger.warn("block: [{}] discarded claim tx: [{}], because the funds it tries to claim no longer exist in contract", - block.getNumber(), - tx.getHash()); - continue; + if (claimTransactionValidator.isFeatureActive(activationConfig.forBlock(block.getNumber()))) { + if(claimTransactionValidator.isClaimTx(tx) + && !claimTransactionValidator.hasLockedFunds(tx, track)) { + logger.warn("block: [{}] discarded claim tx: [{}], because the funds it tries to claim no longer exist in contract", + block.getNumber(), + tx.getHash()); + continue; + } } TransactionExecutor txExecutor = transactionExecutorFactory.newInstance( diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java index 77f7a7022ce..f024ccb7f76 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java @@ -5,6 +5,8 @@ import co.rsk.db.RepositorySnapshot; import co.rsk.util.HexUtils; import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.CallTransaction; import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; @@ -24,7 +26,6 @@ public class ClaimTransactionValidator { private static final String SWAPS_MAP_POSITION = "0000000000000000000000000000000000000000000000000000000000000000"; private static final String CLAIM_METHOD_ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"preimage\",\"type\":\"bytes32\"}, {\"name\":\"amount\",\"type\":\"uint256\"}, {\"name\":\"address\",\"type\":\"address\"}, {\"name\":\"timelock\",\"type\":\"uint256\"}],\"name\":\"claim\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]"; - @Nonnull private final SignatureCache signatureCache; @Nonnull @@ -32,9 +33,9 @@ public class ClaimTransactionValidator { private final CallTransaction.Contract contract = new CallTransaction.Contract(CLAIM_METHOD_ABI);; - public ClaimTransactionValidator(@Nonnull SignatureCache signatureCache, + public ClaimTransactionValidator(SignatureCache signatureCache, @Nonnull Constants constants) { - this.signatureCache = Objects.requireNonNull(signatureCache); + this.signatureCache = signatureCache; this.constants = Objects.requireNonNull(constants); } @@ -125,7 +126,14 @@ public boolean hasLockedFunds(Transaction tx, RepositorySnapshot repositorySnaps return swapRecord != null; } - public boolean isClaimTxAndValid(Transaction tx, RepositorySnapshot repositorySnapshot) { + public boolean isFeatureActive (ActivationConfig.ForBlock activationConfig) { + return activationConfig.isActive(ConsensusRule.RSKIP00); + } + + public boolean isClaimTxAndValid(Transaction tx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { + if(!isFeatureActive(activationConfig)) { + return false; + } if(!isClaimTx(tx)) { return false; @@ -181,7 +189,6 @@ public boolean canPayPendingAndNewClaimTx(Transaction newTx, RepositorySnapshot return balanceAfterPendingTx.add(totalLockedAmount).compareTo(totalClaimTxCost) >= 0; } - @Nonnull public SignatureCache getSignatureCache() { return signatureCache; } 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 64bdf567da5..bfbf75209c0 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 @@ -486,8 +486,13 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos Coin costWithNewTx = accumTxCost.add(getTxBaseCost(newTx)); - return costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0 - || claimTxValidator.canPayPendingAndNewClaimTx(newTx, currentRepository, transactions); + if(costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0) { + return true; + } if(claimTxValidator.isFeatureActive(config.getActivationConfig().forBlock(bestBlock.getNumber()))) { + return claimTxValidator.canPayPendingAndNewClaimTx(newTx, currentRepository, transactions); + } + + return false; } private Coin getTxBaseCost(Transaction tx) { 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 0f2f9e43b1f..1e337428dab 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 @@ -86,7 +86,7 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock, } for (TxValidatorStep step : validatorSteps) { - TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0, repositorySnapshot); + TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0, repositorySnapshot, activationConfig.forBlock(bestBlockNumber)); if (!validationResult.transactionIsValid()) { logger.info("[tx={}] validation failed with error: {}", tx.getHash(), validationResult.getErrorMessage()); return validationResult; diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java index 9328154c863..6e7d1e6bd19 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java @@ -21,6 +21,7 @@ import co.rsk.core.Coin; import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -35,7 +36,7 @@ public class TxNotNullValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return this.validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index f596fc8381e..6fceb9b981d 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -23,6 +23,7 @@ import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; @@ -35,7 +36,7 @@ */ public class TxValidatorAccountBalanceValidator implements TxValidatorStep { - private ClaimTransactionValidator claimTransactionValidator; + private final ClaimTransactionValidator claimTransactionValidator; public TxValidatorAccountBalanceValidator( Constants constants, @@ -44,7 +45,7 @@ public TxValidatorAccountBalanceValidator( } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { if (isFreeTx) { return TransactionValidationResult.ok(); } @@ -56,7 +57,7 @@ public TransactionValidationResult validate(Transaction tx, @Nullable AccountSta BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); if (state.getBalance().compareTo(maximumPrice) >= 0 - || claimTransactionValidator.isClaimTxAndValid(tx, repositorySnapshot)) { + || claimTransactionValidator.isClaimTxAndValid(tx, repositorySnapshot, activationConfig)) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java index bbdec600b20..925ea5a605d 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java @@ -21,6 +21,7 @@ import co.rsk.core.Coin; import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -33,7 +34,7 @@ public class TxValidatorAccountStateValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java index c0ba762b98d..a5088f2aca4 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java @@ -22,6 +22,7 @@ import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -35,7 +36,7 @@ */ public class TxValidatorGasLimitValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } 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 4ba96db3d55..9e73bf3b90c 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 @@ -47,7 +47,7 @@ public TxValidatorIntrinsicGasLimitValidator( } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java index 2fe89910982..d1b9b16078c 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java @@ -42,7 +42,7 @@ public TxValidatorMaximumGasPriceValidator(ActivationConfig activationConfig) { } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java index e93bed61e50..7345f1718e2 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java @@ -21,6 +21,7 @@ import co.rsk.core.Coin; import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -32,7 +33,7 @@ */ public class TxValidatorMinimuGasPriceValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java index 9a47081066e..cc8bd94e442 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java @@ -21,6 +21,7 @@ import co.rsk.core.Coin; import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -43,7 +44,7 @@ public TxValidatorNonceRangeValidator(int accountSlots) { } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java index 360d51021da..8246327a5ef 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java @@ -22,6 +22,7 @@ import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import co.rsk.remasc.RemascTransaction; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -35,7 +36,7 @@ */ public class TxValidatorNotRemascTxValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot) { + public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java index 16158e1dd75..51bb58fbf7c 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java @@ -21,6 +21,7 @@ import co.rsk.core.Coin; import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; @@ -33,7 +34,7 @@ */ public interface TxValidatorStep { - TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot); + TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig); TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); } diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java index 72b787537ea..f79a8120a4c 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java @@ -94,7 +94,8 @@ public enum ConsensusRule { RSKIP415("rskip415"), RSKIP417("rskip417"), RSKIP428("rskip428"), - RSKIP434("rskip434") + RSKIP434("rskip434"), + RSKIP00("rskip00") // Placeholder for EthSwap feature ; private String configKey; diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java index 36670f845e0..0136034e9bc 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java @@ -33,7 +33,8 @@ public enum NetworkUpgrade { FINGERROOT500("fingerroot500"), ARROWHEAD600("arrowhead600"), ARROWHEAD631("arrowhead631"), - LOVELL700("lovell700"); + LOVELL700("lovell700"), + TBD000("tbd000"); private String name; diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index 697a2fc3acc..04fe2f00e14 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -176,7 +176,7 @@ private boolean init() { Coin senderBalance = track.getBalance(tx.getSender(signatureCache)); - if (!isCovers(senderBalance, totalCost) && !claimTransactionValidator.isClaimTxAndValid(tx, track)) { + if (!isCovers(senderBalance, totalCost) && !claimTransactionValidator.isClaimTxAndValid(tx, track, activations)) { logger.warn("Not enough cash: Require: {}, Sender cash: {}, tx {}", totalCost, senderBalance, tx.getHash()); logger.warn("Transaction Data: {}", tx); diff --git a/rskj-core/src/main/resources/config/devnet.conf b/rskj-core/src/main/resources/config/devnet.conf index 43725ff44ba..0e20333b02a 100644 --- a/rskj-core/src/main/resources/config/devnet.conf +++ b/rskj-core/src/main/resources/config/devnet.conf @@ -13,7 +13,8 @@ blockchain.config { hop401 = 0, fingerroot500 = 0, arrowhead600 = 0, - lovell700 = 0 + lovell700 = 0, + tbd000 = 0, }, consensusRules = { rskip97 = -1 # disable orchid difficulty drop diff --git a/rskj-core/src/main/resources/config/main.conf b/rskj-core/src/main/resources/config/main.conf index da37b9165e1..b43f16d67be 100644 --- a/rskj-core/src/main/resources/config/main.conf +++ b/rskj-core/src/main/resources/config/main.conf @@ -14,7 +14,8 @@ blockchain.config { fingerroot500 = 5468000, arrowhead600 = 6223700, arrowhead631 = 6549300, - lovell700 = -1 + lovell700 = -1, + tbd000 = -1 } } diff --git a/rskj-core/src/main/resources/config/regtest.conf b/rskj-core/src/main/resources/config/regtest.conf index d19ce575c34..b3fb83b7b1f 100644 --- a/rskj-core/src/main/resources/config/regtest.conf +++ b/rskj-core/src/main/resources/config/regtest.conf @@ -14,7 +14,8 @@ blockchain.config { fingerroot500 = 0, arrowhead600 = 0, arrowhead631 = -1, - lovell700 = 0 + lovell700 = 0, + tbd000 = 0 }, consensusRules = { rskip97 = -1 # disable orchid difficulty drop diff --git a/rskj-core/src/main/resources/config/testnet.conf b/rskj-core/src/main/resources/config/testnet.conf index cfe42731cd8..94372538672 100644 --- a/rskj-core/src/main/resources/config/testnet.conf +++ b/rskj-core/src/main/resources/config/testnet.conf @@ -15,6 +15,7 @@ blockchain.config { arrowhead600 = 4927100, arrowhead631 = -1, lovell700 = -1 + tbd000 = -1, }, consensusRules = { rskip97 = -1, # disable orchid difficulty drop diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 5b440a1367e..1c74623aa67 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -18,6 +18,7 @@ blockchain = { arrowhead600 = arrowhead631 = lovell700 = + tbd000 = } consensusRules = { areBridgeTxsPaid = @@ -96,6 +97,7 @@ blockchain = { rskip417 = rskip428 = rskip434 = + rskip00 = } } gc = { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 8228aa620d1..63bd01d45eb 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -81,6 +81,7 @@ blockchain = { rskip417 = arrowhead600 rskip428 = lovell700 rskip434 = arrowhead631 + rskip00 = tbd000 } } gc = { diff --git a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java index 63a427680c5..c7be718bca5 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java @@ -36,6 +36,7 @@ import co.rsk.validators.ProofOfWorkRule; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; import org.ethereum.core.genesis.GenesisLoader; import org.ethereum.db.BlockStore; @@ -76,7 +77,7 @@ class MainNetMinerTest { void setup() { config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(Constants.mainnet()); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.all()); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); RskTestFactory factory = new RskTestFactory(tempDir, config) { @Override public GenesisLoader buildGenesisLoader() { diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java index 8f033050f3e..c13ca983e8a 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java @@ -23,6 +23,8 @@ import co.rsk.db.RepositorySnapshot; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.AccountState; import org.ethereum.core.BlockTxSignatureCache; import org.ethereum.core.ReceivedTxSignatureCache; @@ -41,11 +43,13 @@ class TxValidatorAccountBalanceValidatorTest { private Constants constants; private SignatureCache signatureCache; + private ActivationConfig.ForBlock activationConfig; @BeforeEach void setUp() { constants = Constants.regtest(); signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + activationConfig = Mockito.mock(ActivationConfig.ForBlock.class); } @Test @@ -62,12 +66,13 @@ void validAccountBalance() { Mockito.when(tx2.getGasPrice()).thenReturn(Coin.valueOf(10000)); Mockito.when(tx3.getGasPrice()).thenReturn(Coin.valueOf(5000)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(10000)); + Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP00)).thenReturn(false); TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(constants, signatureCache); - Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx3, as, null, null, Long.MAX_VALUE, false, null).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null, activationConfig).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null, activationConfig).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx3, as, null, null, Long.MAX_VALUE, false, null, activationConfig).transactionIsValid()); } @Test @@ -85,11 +90,12 @@ void invalidAccountBalance() { Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(19)); Mockito.when(rs.getStorageValue(Mockito.any(RskAddress.class), Mockito.any(DataWord.class))).thenReturn(null); Mockito.when(rs.getBalance(Mockito.any(RskAddress.class))).thenReturn(Coin.valueOf(19)); + Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP00)).thenReturn(true); TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(constants, signatureCache); - Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, rs).transactionIsValid()); - Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, rs).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, rs, activationConfig).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, rs, activationConfig).transactionIsValid()); } @Test @@ -109,7 +115,7 @@ void balanceIsNotValidatedIfFreeTx() { TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(constants, signatureCache); - Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true, null).transactionIsValid()); + Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true, null, null).transactionIsValid()); } } diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java index 9f907928000..87ec46b4770 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java @@ -326,6 +326,7 @@ void doesntPayFedBelowMinimumRewardAfterRFS() { when(constants.getFederatorMinimumPayableGas()).thenReturn(BigInteger.valueOf(10000L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); long minerFee = 21000; long txValue = 10000; long gasPrice = 1L; @@ -362,6 +363,7 @@ void doesntPayBelowMinimumRewardAfterRFS() { when(constants.getMinimumPayableGas()).thenReturn(BigInteger.valueOf(10000L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); long minerFee = 21000; long txValue = 10000; long gasPrice = 1L; @@ -386,6 +388,7 @@ void paysFedWhenHigherThanMinimumRewardAfterRFS() { when(constants.getFederatorMinimumPayableGas()).thenReturn(BigInteger.valueOf(10L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); long minerFee = 21000; long txValue = 10000; long gasPrice = 10L; @@ -425,6 +428,7 @@ void paysWhenHigherThanMinimumRewardAfterRFS() { when(constants.getFederatorMinimumPayableGas()).thenReturn(BigInteger.valueOf(10L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); long minerFee = 21000; long txValue = 10000; long gasPrice = 10L; @@ -449,6 +453,7 @@ void paysOnlyBlocksWithEnoughBalanceAccumulatedAfterRFS() { when(constants.getMinimumPayableGas()).thenReturn(BigInteger.valueOf(21000L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); long txValue = 10000; long gasLimit = 100000L; long gasPrice = 10L; diff --git a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java index 559a323fcba..3a3561dc4d2 100644 --- a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java @@ -7,6 +7,7 @@ import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.CallTransaction; import org.ethereum.core.ReceivedTxSignatureCache; import org.ethereum.core.SignatureCache; @@ -63,18 +64,19 @@ void setup() { @Test public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { - SignatureCache signatureCache = new ReceivedTxSignatureCache(); - Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + ActivationConfig.ForBlock mockedActivationConfig = mock(ActivationConfig.ForBlock.class); when(mockedClaimTx.transactionCost(any(Constants.class), any(ActivationConfig.ForBlock.class), any(SignatureCache.class))) .thenReturn(5L); when(mockedRepository.getStorageValue(eq(mockedClaimTx.getReceiveAddress()), any(DataWord.class))) .thenReturn(DataWord.valueOf(1)); when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); + when(mockedActivationConfig.isActive(ConsensusRule.RSKIP00)).thenReturn(true); + - boolean result = claimTransactionValidator.isClaimTxAndValid(mockedClaimTx, mockedRepository); + boolean result = claimTransactionValidator.isClaimTxAndValid(mockedClaimTx, mockedRepository, mockedActivationConfig); assertTrue(result); } diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java index 0593855f481..3b0744532ce 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java @@ -45,6 +45,7 @@ class ActivationConfigTest { " arrowhead600: 0", " arrowhead631: 0", " lovell700: 0", + " tbd000: 0", "},", "consensusRules: {", " areBridgeTxsPaid: afterBridgeSync,", @@ -123,6 +124,7 @@ class ActivationConfigTest { " rskip417: arrowhead600", " rskip434: arrowhead631", " rskip428: lovell700", + " rskip00: tbd000", "}" )); diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java index dc85d0e61ed..65891f8aa0d 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java @@ -397,7 +397,6 @@ public static ActivationConfig lovell700() { return lovell700(Collections.emptyList()); } - public static ActivationConfig regtest() { return REGTEST; } From 0e46f9b7a047a809f3aefb77febb87fbed73c3d8 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Wed, 22 May 2024 09:23:23 -0400 Subject: [PATCH 15/21] Fix sonarcloud issues --- rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java | 4 ---- .../src/main/java/co/rsk/core/bc/TransactionPoolImpl.java | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java index 4a9c1b37582..78f80caa8ed 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockExecutor.java @@ -63,8 +63,6 @@ public class BlockExecutor { private final Map transactionResults = new HashMap<>(); private boolean registerProgramResults; - private final Constants constants; - private final SignatureCache signatureCache; private final ClaimTransactionValidator claimTransactionValidator; public BlockExecutor( @@ -76,8 +74,6 @@ public BlockExecutor( this.repositoryLocator = repositoryLocator; this.transactionExecutorFactory = transactionExecutorFactory; this.activationConfig = activationConfig; - this.constants = constants; - this.signatureCache = signatureCache; this.claimTransactionValidator = new ClaimTransactionValidator(signatureCache, constants); } 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 bfbf75209c0..9ff36a7085d 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 @@ -488,7 +488,9 @@ private boolean senderCanPayPendingTransactionsAndNewTx(Transaction newTx, Repos if(costWithNewTx.compareTo(currentRepository.getBalance(newTx.getSender(signatureCache))) <= 0) { return true; - } if(claimTxValidator.isFeatureActive(config.getActivationConfig().forBlock(bestBlock.getNumber()))) { + } + + if(claimTxValidator.isFeatureActive(config.getActivationConfig().forBlock(bestBlock.getNumber()))) { return claimTxValidator.canPayPendingAndNewClaimTx(newTx, currentRepository, transactions); } From 7e801de2282fdb671ce3a67c991b0e76d2bc7d36 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Mon, 3 Jun 2024 15:17:43 -0400 Subject: [PATCH 16/21] Add RSKIP number and refactor validate method in TxValidatorStep --- .../core/bc/ClaimTransactionValidator.java | 2 +- .../rsk/net/handler/TxPendingValidator.java | 9 ++++- .../txvalidator/TxNotNullValidator.java | 13 +------ .../TxValidatorAccountBalanceValidator.java | 18 +++------ .../TxValidatorAccountStateValidator.java | 16 ++------ .../TxValidatorGasLimitValidator.java | 11 +----- ...TxValidatorIntrinsicGasLimitValidator.java | 9 +---- .../TxValidatorMaximumGasPriceValidator.java | 11 +----- .../TxValidatorMinimuGasPriceValidator.java | 11 +----- .../TxValidatorNonceRangeValidator.java | 14 ++----- .../TxValidatorNotRemascTxValidator.java | 11 +----- .../handler/txvalidator/TxValidatorStep.java | 9 +---- .../blockchain/upgrades/ConsensusRule.java | 4 ++ .../org/ethereum/core/ValidationArgs.java | 39 +++++++++++++++++++ .../src/main/resources/config/devnet.conf | 1 - .../src/main/resources/config/testnet.conf | 1 - rskj-core/src/main/resources/expected.conf | 2 +- rskj-core/src/main/resources/reference.conf | 1 + .../java/co/rsk/mine/MainNetMinerTest.java | 2 +- ...xValidatorAccountBalanceValidatorTest.java | 21 ++++++---- .../TxValidatorAccountStateValidatorTest.java | 7 +++- ...lidatorIntrinsicGasLimitValidatorTest.java | 26 +++++++------ .../TxValidatorNonceRangeValidatorTest.java | 13 +++++-- .../rsk/remasc/RemascStorageProviderTest.java | 10 ++--- .../util/ClaimTransactionValidatorTest.java | 2 +- .../upgrades/ActivationConfigTest.java | 2 - 26 files changed, 128 insertions(+), 137 deletions(-) create mode 100644 rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java index f024ccb7f76..30a6f04d43d 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java @@ -127,7 +127,7 @@ public boolean hasLockedFunds(Transaction tx, RepositorySnapshot repositorySnaps } public boolean isFeatureActive (ActivationConfig.ForBlock activationConfig) { - return activationConfig.isActive(ConsensusRule.RSKIP00); + return activationConfig.isActive(ConsensusRule.RSKIP432); } public boolean isClaimTxAndValid(Transaction tx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { 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 1e337428dab..30782d6163c 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 @@ -28,6 +28,7 @@ import org.ethereum.core.Block; import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,8 +86,14 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock, return TransactionValidationResult.withError(String.format("transaction's size is higher than defined maximum: %s > %s", tx.getSize(), TX_MAX_SIZE)); } + ValidationArgs validationArgs = new ValidationArgs( + state, + repositorySnapshot, + activationConfig.forBlock(bestBlockNumber) + ); + for (TxValidatorStep step : validatorSteps) { - TransactionValidationResult validationResult = step.validate(tx, state, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0, repositorySnapshot, activationConfig.forBlock(bestBlockNumber)); + TransactionValidationResult validationResult = step.validate(tx, validationArgs, blockGasLimit, minimumGasPrice, bestBlockNumber, basicTxCost == 0); if (!validationResult.transactionIsValid()) { logger.info("[tx={}] validation failed with error: {}", tx.getHash(), validationResult.getErrorMessage()); return validationResult; diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java index 6e7d1e6bd19..5d6486a2982 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxNotNullValidator.java @@ -19,13 +19,10 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -34,14 +31,8 @@ * Looks a little overhead, but simplifies a little bit the code in other places */ public class TxNotNullValidator implements TxValidatorStep { - - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return this.validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (tx != null) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java index 6fceb9b981d..a77234cff1c 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidator.java @@ -20,15 +20,12 @@ import co.rsk.core.Coin; import co.rsk.core.bc.ClaimTransactionValidator; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -45,27 +42,22 @@ public TxValidatorAccountBalanceValidator( } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (isFreeTx) { return TransactionValidationResult.ok(); } - if (state == null) { + if (validationArgs.getAccountState() == null) { return TransactionValidationResult.withError("the sender account doesn't exist"); } BigInteger txGasLimit = tx.getGasLimitAsInteger(); Coin maximumPrice = tx.getGasPrice().multiply(txGasLimit); - if (state.getBalance().compareTo(maximumPrice) >= 0 - || claimTransactionValidator.isClaimTxAndValid(tx, repositorySnapshot, activationConfig)) { + if (validationArgs.getAccountState().getBalance().compareTo(maximumPrice) >= 0 + || claimTransactionValidator.isClaimTxAndValid(tx, validationArgs.getRepositorySnapshot(), validationArgs.getActivationConfig())) { return TransactionValidationResult.ok(); } return TransactionValidationResult.withError("insufficient funds"); } - - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { - return TransactionValidationResult.ok(); - } } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java index 925ea5a605d..670a13bd543 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidator.java @@ -19,13 +19,10 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -34,21 +31,16 @@ public class TxValidatorAccountStateValidator implements TxValidatorStep { @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } - - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (isFreeTx) { return TransactionValidationResult.ok(); } - if (state == null) { + if (validationArgs.getAccountState() == null) { return TransactionValidationResult.withError("the sender account doesn't exist"); } - if (state.isDeleted()) { + if (validationArgs.getAccountState().isDeleted()) { return TransactionValidationResult.withError("the sender account is deleted"); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java index a5088f2aca4..5212b417522 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorGasLimitValidator.java @@ -19,14 +19,11 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -35,13 +32,9 @@ * Also Checks that the transaction gas limit is not higher than the max allowed value */ public class TxValidatorGasLimitValidator implements TxValidatorStep { - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { BigInteger txGasLimit = tx.getGasLimitAsInteger(); if (txGasLimit.compareTo(gasLimit) <= 0 && txGasLimit.compareTo(Constants.getTransactionGasCap()) <= 0) { 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 9e73bf3b90c..76471c368a7 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 @@ -18,13 +18,11 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.*; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -47,12 +45,7 @@ public TxValidatorIntrinsicGasLimitValidator( } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } - - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { 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/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java index d1b9b16078c..2451ed7a73c 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMaximumGasPriceValidator.java @@ -19,15 +19,13 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import co.rsk.validators.TxGasPriceCap; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -42,12 +40,7 @@ public TxValidatorMaximumGasPriceValidator(ActivationConfig activationConfig) { } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } - - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { boolean isRskip252Enabled = activationConfig.isActive(ConsensusRule.RSKIP252, bestBlockNumber); if (!isRskip252Enabled) { return TransactionValidationResult.ok(); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java index 7345f1718e2..f78d33eae8e 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorMinimuGasPriceValidator.java @@ -19,26 +19,19 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** * Created by maty on 06/03/17. */ public class TxValidatorMinimuGasPriceValidator implements TxValidatorStep { - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { Coin gasPrice = tx.getGasPrice(); if (gasPrice != null && gasPrice.compareTo(minimumGasPrice) >= 0) { return TransactionValidationResult.ok(); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java index cc8bd94e442..697e0aaee8d 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidator.java @@ -19,13 +19,10 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -44,14 +41,9 @@ public TxValidatorNonceRangeValidator(int accountSlots) { } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } - - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { BigInteger nonce = tx.getNonceAsInteger(); - BigInteger stateNonce = state == null ? BigInteger.ZERO : state.getNonce(); + BigInteger stateNonce = validationArgs.getAccountState() == null ? BigInteger.ZERO : validationArgs.getAccountState().getNonce(); if (stateNonce.compareTo(nonce) > 0) { return TransactionValidationResult.withError("transaction nonce too low"); diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java index 8246327a5ef..ccea9844e15 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorNotRemascTxValidator.java @@ -19,14 +19,11 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; import co.rsk.remasc.RemascTransaction; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -35,13 +32,9 @@ * Transaction must not be null */ public class TxValidatorNotRemascTxValidator implements TxValidatorStep { - @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig) { - return validate(tx, state, gasLimit, minimumGasPrice, bestBlockNumber, isFreeTx); - } @Override - public TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { + public TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx) { if (!(tx instanceof RemascTransaction)) { return TransactionValidationResult.ok(); } diff --git a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java index 51bb58fbf7c..4903be5fd74 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/txvalidator/TxValidatorStep.java @@ -19,13 +19,10 @@ package co.rsk.net.handler.txvalidator; import co.rsk.core.Coin; -import co.rsk.db.RepositorySnapshot; import co.rsk.net.TransactionValidationResult; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; -import javax.annotation.Nullable; import java.math.BigInteger; /** @@ -34,7 +31,5 @@ */ public interface TxValidatorStep { - TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx, RepositorySnapshot repositorySnapshot, ActivationConfig.ForBlock activationConfig); - - TransactionValidationResult validate(Transaction tx, @Nullable AccountState state, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); + TransactionValidationResult validate(Transaction tx, ValidationArgs validationArgs, BigInteger gasLimit, Coin minimumGasPrice, long bestBlockNumber, boolean isFreeTx); } diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java index f79a8120a4c..857e406bcf4 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java @@ -93,9 +93,13 @@ public enum ConsensusRule { RSKIP412("rskip412"), // From EIP-3198 BASEFEE opcode RSKIP415("rskip415"), RSKIP417("rskip417"), +<<<<<<< HEAD RSKIP428("rskip428"), RSKIP434("rskip434"), RSKIP00("rskip00") // Placeholder for EthSwap feature +======= + RSKIP432("rskip432"), // From RSKIP-432 RbtcSwap +>>>>>>> bd8b9a1a4 (Add RSKIP number and refactor validate method in TxValidatorStep) ; private String configKey; diff --git a/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java b/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java new file mode 100644 index 00000000000..f41c00860b0 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java @@ -0,0 +1,39 @@ +package org.ethereum.core; + +import co.rsk.db.RepositorySnapshot; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; + +import javax.annotation.Nullable; + +public class ValidationArgs { + + @Nullable + AccountState accountState; + + @Nullable + RepositorySnapshot repositorySnapshot; + + @Nullable + ActivationConfig.ForBlock activationConfig; + + public ValidationArgs(@Nullable AccountState accountState, @Nullable RepositorySnapshot repositorySnapshot, @Nullable ActivationConfig.ForBlock activationConfig) { + this.accountState = accountState; + this.repositorySnapshot = repositorySnapshot; + this.activationConfig = activationConfig; + } + + @Nullable + public AccountState getAccountState() { + return accountState; + } + + @Nullable + public RepositorySnapshot getRepositorySnapshot() { + return repositorySnapshot; + } + + @Nullable + public ActivationConfig.ForBlock getActivationConfig() { + return activationConfig; + } +} diff --git a/rskj-core/src/main/resources/config/devnet.conf b/rskj-core/src/main/resources/config/devnet.conf index 0e20333b02a..91756ee1fea 100644 --- a/rskj-core/src/main/resources/config/devnet.conf +++ b/rskj-core/src/main/resources/config/devnet.conf @@ -14,7 +14,6 @@ blockchain.config { fingerroot500 = 0, arrowhead600 = 0, lovell700 = 0, - tbd000 = 0, }, consensusRules = { rskip97 = -1 # disable orchid difficulty drop diff --git a/rskj-core/src/main/resources/config/testnet.conf b/rskj-core/src/main/resources/config/testnet.conf index 94372538672..cfe42731cd8 100644 --- a/rskj-core/src/main/resources/config/testnet.conf +++ b/rskj-core/src/main/resources/config/testnet.conf @@ -15,7 +15,6 @@ blockchain.config { arrowhead600 = 4927100, arrowhead631 = -1, lovell700 = -1 - tbd000 = -1, }, consensusRules = { rskip97 = -1, # disable orchid difficulty drop diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 1c74623aa67..855deaf1a2d 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -18,7 +18,6 @@ blockchain = { arrowhead600 = arrowhead631 = lovell700 = - tbd000 = } consensusRules = { areBridgeTxsPaid = @@ -98,6 +97,7 @@ blockchain = { rskip428 = rskip434 = rskip00 = + rskip432 = } } gc = { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 63bd01d45eb..c51b921ff61 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -82,6 +82,7 @@ blockchain = { rskip428 = lovell700 rskip434 = arrowhead631 rskip00 = tbd000 + rskip432 = lovell700 } } gc = { diff --git a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java index c7be718bca5..4b6ccda8dc8 100644 --- a/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/MainNetMinerTest.java @@ -77,7 +77,7 @@ class MainNetMinerTest { void setup() { config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(Constants.mainnet()); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP432)); RskTestFactory factory = new RskTestFactory(tempDir, config) { @Override public GenesisLoader buildGenesisLoader() { diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java index c13ca983e8a..e7b3ea4885d 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountBalanceValidatorTest.java @@ -30,6 +30,7 @@ import org.ethereum.core.ReceivedTxSignatureCache; import org.ethereum.core.SignatureCache; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; import org.ethereum.crypto.ECKey; import org.ethereum.vm.DataWord; import org.junit.jupiter.api.Assertions; @@ -66,13 +67,15 @@ void validAccountBalance() { Mockito.when(tx2.getGasPrice()).thenReturn(Coin.valueOf(10000)); Mockito.when(tx3.getGasPrice()).thenReturn(Coin.valueOf(5000)); Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(10000)); - Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP00)).thenReturn(false); + Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP432)).thenReturn(false); TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(constants, signatureCache); - Assertions.assertTrue(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, null, activationConfig).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, null, activationConfig).transactionIsValid()); - Assertions.assertTrue(tvabv.validate(tx3, as, null, null, Long.MAX_VALUE, false, null, activationConfig).transactionIsValid()); + ValidationArgs va = new ValidationArgs(as, null, activationConfig); + + Assertions.assertTrue(tvabv.validate(tx1, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx2, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvabv.validate(tx3, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); } @Test @@ -90,12 +93,13 @@ void invalidAccountBalance() { Mockito.when(as.getBalance()).thenReturn(Coin.valueOf(19)); Mockito.when(rs.getStorageValue(Mockito.any(RskAddress.class), Mockito.any(DataWord.class))).thenReturn(null); Mockito.when(rs.getBalance(Mockito.any(RskAddress.class))).thenReturn(Coin.valueOf(19)); - Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP00)).thenReturn(true); + Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP432)).thenReturn(true); TxValidatorAccountBalanceValidator tvabv = new TxValidatorAccountBalanceValidator(constants, signatureCache); + ValidationArgs va = new ValidationArgs(as, rs, activationConfig); - Assertions.assertFalse(tvabv.validate(tx1, as, null, null, Long.MAX_VALUE, false, rs, activationConfig).transactionIsValid()); - Assertions.assertFalse(tvabv.validate(tx2, as, null, null, Long.MAX_VALUE, false, rs, activationConfig).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx1, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvabv.validate(tx2, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); } @Test @@ -114,8 +118,9 @@ void balanceIsNotValidatedIfFreeTx() { tx.sign(new ECKey().getPrivKeyBytes()); TxValidatorAccountBalanceValidator tv = new TxValidatorAccountBalanceValidator(constants, signatureCache); + ValidationArgs va = new ValidationArgs(new AccountState(), null, null); - Assertions.assertTrue(tv.validate(tx, new AccountState(), BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true, null, null).transactionIsValid()); + Assertions.assertTrue(tv.validate(tx, va, BigInteger.ONE, Coin.valueOf(1L), Long.MAX_VALUE, true).transactionIsValid()); } } diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidatorTest.java index 93a9e98eaf4..52e8a883841 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorAccountStateValidatorTest.java @@ -19,6 +19,7 @@ package co.rsk.net.handler.txvalidator; import org.ethereum.core.AccountState; +import org.ethereum.core.ValidationArgs; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -31,7 +32,8 @@ void validAccountState() { Mockito.when(state.isDeleted()).thenReturn(false); TxValidatorAccountStateValidator tvasv = new TxValidatorAccountStateValidator(); - Assertions.assertTrue(tvasv.validate(null, state, null, null, Long.MAX_VALUE, false).transactionIsValid()); + ValidationArgs va = new ValidationArgs(state, null, null); + Assertions.assertTrue(tvasv.validate(null, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); } @Test @@ -40,6 +42,7 @@ void invalidAccountState() { Mockito.when(state.isDeleted()).thenReturn(true); TxValidatorAccountStateValidator tvasv = new TxValidatorAccountStateValidator(); - Assertions.assertFalse(tvasv.validate(null, state, null, null, Long.MAX_VALUE, false).transactionIsValid()); + ValidationArgs va = new ValidationArgs(state, null, null); + Assertions.assertFalse(tvasv.validate(null, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); } } diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidatorTest.java index 1fbd4b5623a..f799b44ea83 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorIntrinsicGasLimitValidatorTest.java @@ -17,9 +17,6 @@ */ package co.rsk.net.handler.txvalidator; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import co.rsk.bitcoinj.core.BtcECKey; import java.util.Arrays; import java.util.List; @@ -32,8 +29,10 @@ import org.ethereum.core.BlockTxSignatureCache; import org.ethereum.core.ReceivedTxSignatureCache; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; import org.ethereum.crypto.ECKey; import org.ethereum.vm.PrecompiledContracts; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -110,10 +109,13 @@ void validIntrinsicGasPrice() { new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ); - assertTrue(tvigpv.validate(tx1, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); - assertTrue(tvigpv.validate(tx2, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); - assertTrue(tvigpv.validate(tx3, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); - assertTrue(tvigpv.validate(tx4, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); + ValidationArgs va = new ValidationArgs(new AccountState(), null, null); + + Assertions.assertTrue(tvigpv.validate(tx1, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvigpv.validate(tx2, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvigpv.validate(tx3, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvigpv.validate(tx4, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + } @Test @@ -170,10 +172,12 @@ void invalidIntrinsicGasPrice() { new BlockTxSignatureCache(new ReceivedTxSignatureCache()) ); - assertFalse(tvigpv.validate(tx1, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); - assertFalse(tvigpv.validate(tx2, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); - assertFalse(tvigpv.validate(tx3, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); - assertFalse(tvigpv.validate(tx4, new AccountState(), null, null, Long.MAX_VALUE, false).transactionIsValid()); + ValidationArgs va = new ValidationArgs(new AccountState(), null, null); + + Assertions.assertFalse(tvigpv.validate(tx1, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvigpv.validate(tx2, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvigpv.validate(tx3, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvigpv.validate(tx4, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); } } diff --git a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidatorTest.java index 56cd2c92da3..008e92745b2 100644 --- a/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/handler/txvalidator/TxValidatorNonceRangeValidatorTest.java @@ -20,6 +20,7 @@ import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; +import org.ethereum.core.ValidationArgs; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -41,9 +42,11 @@ void oneSlotRange() { Mockito.when(as.getNonce()).thenReturn(BigInteger.valueOf(1)); TxValidatorNonceRangeValidator tvnrv = new TxValidatorNonceRangeValidator(1); - Assertions.assertFalse(tvnrv.validate(tx1, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertTrue(tvnrv.validate(tx2, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); - Assertions.assertFalse(tvnrv.validate(tx3, as, null, null, Long.MAX_VALUE, false).transactionIsValid()); + ValidationArgs va = new ValidationArgs(as, null, null); + + Assertions.assertFalse(tvnrv.validate(tx1, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertTrue(tvnrv.validate(tx2, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); + Assertions.assertFalse(tvnrv.validate(tx3, va, null, null, Long.MAX_VALUE, false).transactionIsValid()); } @Test @@ -62,7 +65,9 @@ void fiveSlotsRange() { for (int i = 0; i < 7; i++) { Transaction tx = txs[i]; long txNonce = tx.getNonceAsInteger().longValue(); - boolean isValid = tvnrv.validate(tx, as, null, null, Long.MAX_VALUE, false).transactionIsValid(); + ValidationArgs va = new ValidationArgs(as, null, null); + + boolean isValid = tvnrv.validate(tx, va, null, null, Long.MAX_VALUE, false).transactionIsValid(); Assertions.assertEquals(isValid, txNonce >= 1 && txNonce <= 5); // only valid if tx nonce is in the range [1; 5] } } diff --git a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java index 87ec46b4770..c6a84e86147 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java @@ -326,7 +326,7 @@ void doesntPayFedBelowMinimumRewardAfterRFS() { when(constants.getFederatorMinimumPayableGas()).thenReturn(BigInteger.valueOf(10000L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP432)); long minerFee = 21000; long txValue = 10000; long gasPrice = 1L; @@ -363,7 +363,7 @@ void doesntPayBelowMinimumRewardAfterRFS() { when(constants.getMinimumPayableGas()).thenReturn(BigInteger.valueOf(10000L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP432)); long minerFee = 21000; long txValue = 10000; long gasPrice = 1L; @@ -388,7 +388,7 @@ void paysFedWhenHigherThanMinimumRewardAfterRFS() { when(constants.getFederatorMinimumPayableGas()).thenReturn(BigInteger.valueOf(10L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP432)); long minerFee = 21000; long txValue = 10000; long gasPrice = 10L; @@ -428,7 +428,7 @@ void paysWhenHigherThanMinimumRewardAfterRFS() { when(constants.getFederatorMinimumPayableGas()).thenReturn(BigInteger.valueOf(10L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP432)); long minerFee = 21000; long txValue = 10000; long gasPrice = 10L; @@ -453,7 +453,7 @@ void paysOnlyBlocksWithEnoughBalanceAccumulatedAfterRFS() { when(constants.getMinimumPayableGas()).thenReturn(BigInteger.valueOf(21000L)); RskSystemProperties config = spy(new TestSystemProperties()); when(config.getNetworkConstants()).thenReturn(constants); - when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP00)); + when(config.getActivationConfig()).thenReturn(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP432)); long txValue = 10000; long gasLimit = 100000L; long gasPrice = 10L; diff --git a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java index 3a3561dc4d2..1d48497e6d7 100644 --- a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java @@ -73,7 +73,7 @@ public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { when(mockedRepository.getStorageValue(eq(mockedClaimTx.getReceiveAddress()), any(DataWord.class))) .thenReturn(DataWord.valueOf(1)); when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(3)); - when(mockedActivationConfig.isActive(ConsensusRule.RSKIP00)).thenReturn(true); + when(mockedActivationConfig.isActive(ConsensusRule.RSKIP432)).thenReturn(true); boolean result = claimTransactionValidator.isClaimTxAndValid(mockedClaimTx, mockedRepository, mockedActivationConfig); diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java index 3b0744532ce..0e5e0dcef8d 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java @@ -122,8 +122,6 @@ class ActivationConfigTest { " rskip412: arrowhead600", " rskip415: arrowhead600", " rskip417: arrowhead600", - " rskip434: arrowhead631", - " rskip428: lovell700", " rskip00: tbd000", "}" )); From e8393bfcba9b2c5c29d9f4d3ea950f221c3fe7ab Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Mon, 3 Jun 2024 15:51:20 -0400 Subject: [PATCH 17/21] Fix integration test --- .../src/integrationTest/java/co/rsk/ClaimTransactionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java b/rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java index 592058216c1..a81969130a6 100644 --- a/rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java +++ b/rskj-core/src/integrationTest/java/co/rsk/ClaimTransactionTest.java @@ -20,9 +20,9 @@ package co.rsk; import co.rsk.core.bc.ClaimTransactionValidator; -import co.rsk.util.CommandLineFixture; import co.rsk.util.HexUtils; import co.rsk.util.OkHttpClientTestFixture; +import co.rsk.util.cli.CommandLineFixture; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.squareup.okhttp.Response; From 57a4f7ff92dd284df230613b4323b5dcfa8d3e0b Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Mon, 3 Jun 2024 16:24:53 -0400 Subject: [PATCH 18/21] Fix sonarcloud issues --- .../src/main/java/org/ethereum/core/ValidationArgs.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java b/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java index f41c00860b0..bfe1fda6102 100644 --- a/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java +++ b/rskj-core/src/main/java/org/ethereum/core/ValidationArgs.java @@ -8,13 +8,13 @@ public class ValidationArgs { @Nullable - AccountState accountState; + private final AccountState accountState; @Nullable - RepositorySnapshot repositorySnapshot; + private final RepositorySnapshot repositorySnapshot; @Nullable - ActivationConfig.ForBlock activationConfig; + private final ActivationConfig.ForBlock activationConfig; public ValidationArgs(@Nullable AccountState accountState, @Nullable RepositorySnapshot repositorySnapshot, @Nullable ActivationConfig.ForBlock activationConfig) { this.accountState = accountState; From 97d1d99c19a1807f00892ff478958bcb939b6ec1 Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Thu, 6 Jun 2024 10:51:54 -0400 Subject: [PATCH 19/21] Removing unnecessary test --- .../co/rsk/util/ClaimTransactionValidatorTest.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java index 1d48497e6d7..76465339c43 100644 --- a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java @@ -51,17 +51,6 @@ void setup() { claimTransactionValidator = new ClaimTransactionValidator(signatureCache, testConstants); } -// @Test -// public void whenCalculateSwapHashIsCalled_shouldReturnExpectedHash() { -// String expectedHash = "0x3dc21e0a710489c951f29205f9961b2c311d48fdf5a35545469d7b43e88f7624"; -// -// Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); -// -// byte[] result = claimTransactionValidator.calculateSwapHash(mockedClaimTx, new ReceivedTxSignatureCache()); -// -// assertEquals(expectedHash, HexUtils.toJsonHex(result)); -// } - @Test public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); From 72272e07538a140abbc83e4207675354f8cf551e Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Fri, 9 Aug 2024 08:22:48 -0400 Subject: [PATCH 20/21] Addressing comments --- .../core/bc/ClaimTransactionValidator.java | 29 +++++++++-------- .../blockchain/upgrades/ConsensusRule.java | 4 --- .../util/ClaimTransactionValidatorTest.java | 32 +++++++++++++++---- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java index 30a6f04d43d..b0f97061e79 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/ClaimTransactionValidator.java @@ -90,25 +90,28 @@ public byte[] encodePacked(Object...arguments) { byte[] encodedArguments = new byte[]{}; for(Object arg: arguments) { - byte[] encodedArg = new byte[]{}; - if(arg instanceof byte[]) { - SolidityType bytes32Type = SolidityType.getType(SolidityType.BYTES32); - encodedArg = bytes32Type.encode(arg); - } else if(arg instanceof RskAddress) { - SolidityType addressType = SolidityType.getType(SolidityType.ADDRESS); - byte[] encodedAddress = addressType.encode(((RskAddress) arg).toHexString()); - encodedArg = org.bouncycastle.util.Arrays.copyOfRange(encodedAddress, 12, encodedAddress.length); - } else if(arg instanceof BigInteger) { - SolidityType uint256Type = SolidityType.getType(SolidityType.UINT); - encodedArg = uint256Type.encode(arg); - } - + byte[] encodedArg = encodeArgumentAccordingInstanceType(arg); encodedArguments = ByteUtil.merge(encodedArguments, encodedArg); } return encodedArguments; } + private static byte[] encodeArgumentAccordingInstanceType(Object arg) { + if (arg instanceof byte[]) { + SolidityType bytes32Type = SolidityType.getType(SolidityType.BYTES32); + return bytes32Type.encode(arg); + } else if (arg instanceof RskAddress) { + SolidityType addressType = SolidityType.getType(SolidityType.ADDRESS); + byte[] encodedAddress = addressType.encode(((RskAddress) arg).toHexString()); + return org.bouncycastle.util.Arrays.copyOfRange(encodedAddress, 12, encodedAddress.length); + } else if (arg instanceof BigInteger) { + SolidityType uint256Type = SolidityType.getType(SolidityType.UINT); + return uint256Type.encode(arg); + } + return new byte[]{}; + } + public boolean isClaimTx(Transaction tx) { return tx.getReceiveAddress() != null && tx.getData() != null diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java index 857e406bcf4..792e9da75e6 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java @@ -93,13 +93,9 @@ public enum ConsensusRule { RSKIP412("rskip412"), // From EIP-3198 BASEFEE opcode RSKIP415("rskip415"), RSKIP417("rskip417"), -<<<<<<< HEAD RSKIP428("rskip428"), RSKIP434("rskip434"), - RSKIP00("rskip00") // Placeholder for EthSwap feature -======= RSKIP432("rskip432"), // From RSKIP-432 RbtcSwap ->>>>>>> bd8b9a1a4 (Add RSKIP number and refactor validate method in TxValidatorStep) ; private String configKey; diff --git a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java index 76465339c43..d9d1699ccbb 100644 --- a/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java +++ b/rskj-core/src/test/java/co/rsk/util/ClaimTransactionValidatorTest.java @@ -53,7 +53,7 @@ void setup() { @Test public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { - Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0, 5); RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); ActivationConfig.ForBlock mockedActivationConfig = mock(ActivationConfig.ForBlock.class); @@ -70,12 +70,30 @@ public void whenIsClaimTxAndValidIsCalled_shouldReturnTrue() { assertTrue(result); } + @Test + public void whenIsClaimTxAndValidIsCalled_withInsufficientFunds_shouldReturnFalse() { + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0, 12); + RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); + ActivationConfig.ForBlock mockedActivationConfig = mock(ActivationConfig.ForBlock.class); + + when(mockedRepository.getBalance(any(RskAddress.class))).thenReturn(Coin.valueOf(1)); + + when(mockedRepository.getStorageValue(eq(mockedClaimTx.getReceiveAddress()), any(DataWord.class))) + .thenReturn(DataWord.valueOf(1)); + when(mockedActivationConfig.isActive(ConsensusRule.RSKIP432)).thenReturn(true); + + boolean result = claimTransactionValidator.isClaimTxAndValid(mockedClaimTx, mockedRepository, mockedActivationConfig); + + assertFalse(result); + } + + @Test public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withIdenticalNewAndPendingTx_shouldReturnFalse() { - Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0); + Transaction mockedClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 0, 5); List pendingTransactions = new ArrayList<>(); - pendingTransactions.add(createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 1)); + pendingTransactions.add(createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 1, 5)); SignatureCache signatureCache = new ReceivedTxSignatureCache(); RepositorySnapshot mockedRepository = mock(RepositorySnapshot.class); @@ -90,8 +108,8 @@ public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withIdenticalNewA @Test public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withMultipleClaimTx_shouldCombineLockedAmounts() { - Transaction mockedClaimTx = createClaimTx(3, "test".getBytes(StandardCharsets.UTF_8), 0); - Transaction mockedPendingClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 1); + Transaction mockedClaimTx = createClaimTx(3, "test".getBytes(StandardCharsets.UTF_8), 0, 5); + Transaction mockedPendingClaimTx = createClaimTx(10, "preimage".getBytes(StandardCharsets.UTF_8), 1, 5); List pendingTransactions = new ArrayList<>(); pendingTransactions.add(mockedPendingClaimTx); @@ -110,7 +128,7 @@ public void whenIsClaimTxAndSenderCanPayAlongPendingTxIsCalled_withMultipleClaim assertTrue(result); } - private Transaction createClaimTx(int amount, byte[] preimage, long nonce) { + private Transaction createClaimTx(int amount, byte[] preimage, long nonce, int gasLimit) { byte[] senderBytes = Hex.decode("0000000000000000000000000000000001000001"); RskAddress claimAddress = new RskAddress(senderBytes); @@ -125,7 +143,7 @@ private Transaction createClaimTx(int amount, byte[] preimage, long nonce) { when(claimTx.getSender(any(SignatureCache.class))).thenReturn(claimAddress); when(claimTx.getNonce()).thenReturn(BigInteger.valueOf(nonce).toByteArray()); when(claimTx.getGasPrice()).thenReturn(Coin.valueOf(1)); - when(claimTx.getGasLimit()).thenReturn(BigInteger.valueOf(5).toByteArray()); + when(claimTx.getGasLimit()).thenReturn(BigInteger.valueOf(gasLimit).toByteArray()); when(claimTx.getReceiveAddress()).thenReturn(new RskAddress(testConstants.getEtherSwapContractAddress())); when(claimTx.getData()).thenReturn(callData); when(claimTx.getValue()).thenReturn(Coin.ZERO); From 99712db08ee4fdbe68ca77cb62083cde42845e4e Mon Sep 17 00:00:00 2001 From: Reynold Morel Date: Fri, 9 Aug 2024 08:22:48 -0400 Subject: [PATCH 21/21] Addressing comments --- rskj-core/src/main/resources/config/main.conf | 3 +-- rskj-core/src/main/resources/config/regtest.conf | 3 +-- rskj-core/src/main/resources/expected.conf | 1 - rskj-core/src/main/resources/reference.conf | 1 - .../config/blockchain/upgrades/ActivationConfigTest.java | 5 +++-- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/rskj-core/src/main/resources/config/main.conf b/rskj-core/src/main/resources/config/main.conf index b43f16d67be..da37b9165e1 100644 --- a/rskj-core/src/main/resources/config/main.conf +++ b/rskj-core/src/main/resources/config/main.conf @@ -14,8 +14,7 @@ blockchain.config { fingerroot500 = 5468000, arrowhead600 = 6223700, arrowhead631 = 6549300, - lovell700 = -1, - tbd000 = -1 + lovell700 = -1 } } diff --git a/rskj-core/src/main/resources/config/regtest.conf b/rskj-core/src/main/resources/config/regtest.conf index b3fb83b7b1f..d19ce575c34 100644 --- a/rskj-core/src/main/resources/config/regtest.conf +++ b/rskj-core/src/main/resources/config/regtest.conf @@ -14,8 +14,7 @@ blockchain.config { fingerroot500 = 0, arrowhead600 = 0, arrowhead631 = -1, - lovell700 = 0, - tbd000 = 0 + lovell700 = 0 }, consensusRules = { rskip97 = -1 # disable orchid difficulty drop diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 855deaf1a2d..718dd008902 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -96,7 +96,6 @@ blockchain = { rskip417 = rskip428 = rskip434 = - rskip00 = rskip432 = } } diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index c51b921ff61..a10741524be 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -81,7 +81,6 @@ blockchain = { rskip417 = arrowhead600 rskip428 = lovell700 rskip434 = arrowhead631 - rskip00 = tbd000 rskip432 = lovell700 } } diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java index 0e5e0dcef8d..fc8fccf599b 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java @@ -45,7 +45,6 @@ class ActivationConfigTest { " arrowhead600: 0", " arrowhead631: 0", " lovell700: 0", - " tbd000: 0", "},", "consensusRules: {", " areBridgeTxsPaid: afterBridgeSync,", @@ -122,7 +121,9 @@ class ActivationConfigTest { " rskip412: arrowhead600", " rskip415: arrowhead600", " rskip417: arrowhead600", - " rskip00: tbd000", + " rskip432: lovell700", + " rskip434: arrowhead631", + " rskip428: lovell700", "}" ));