diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index dbfec017604..1167b72a40d 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -105,7 +105,7 @@ jobs: GH_REF: ${{ github.ref }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | - if [ "$GH_EVENT" = pull_request ]; then + if [ "$GH_EVENT" = pull_request ] && [ "${{ github.event.pull_request.head.repo.fork }}" != "true" ]; then ./gradlew -Dorg.gradle.jvmargs=-Xmx5g sonarqube --no-daemon -x build -x test \ -Dsonar.pullrequest.base="$GH_PR_BASE_REF" \ -Dsonar.pullrequest.branch="$GH_PR_HEAD_REF" \ diff --git a/.github/workflows/rit.yml b/.github/workflows/rit.yml index 9fac1b2cf9d..b5d76120548 100644 --- a/.github/workflows/rit.yml +++ b/.github/workflows/rit.yml @@ -36,6 +36,8 @@ jobs: github_event_pull_request_number: ${{ github.event.pull_request.number }} github_head_ref: ${{ github.head_ref }} github_ref_name: ${{ github.ref_name }} + github_event_pull_request_head_repo_owner_login: ${{ github.event.pull_request.head.repo.owner.login }} + github_repository_owner: ${{ github.repository_owner }} run: | PR_DESCRIPTION=pr-description.txt @@ -96,6 +98,11 @@ jobs: exit 1 fi + # Set the Repo Owner + REPO_OWNER="${github_event_pull_request_head_repo_owner_login:-$github_repository_owner}" + + + echo "REPO_OWNER=$REPO_OWNER" >> $GITHUB_ENV echo "RSKJ_BRANCH=$RSKJ_BRANCH" >> $GITHUB_ENV echo "RIT_BRANCH=$RIT_BRANCH" >> $GITHUB_ENV echo "POWPEG_BRANCH=$POWPEG_BRANCH" >> $GITHUB_ENV @@ -116,11 +123,12 @@ jobs: echo "SAFE_BRANCH_NAME=$SAFE_BRANCH_NAME" >> $GITHUB_ENV - name: Run Rootstock Integration Tests - uses: rsksmart/rootstock-integration-tests@497172fd38dcfaf48c77f9bb1eeb6617eef5eed6 #v1 + uses: rsksmart/rootstock-integration-tests@e86332474179a63f027d0fe969687d3d24f34c29 #v1 with: rskj-branch: ${{ env.RSKJ_BRANCH }} powpeg-node-branch: ${{ env.POWPEG_BRANCH }} rit-branch: ${{ env.RIT_BRANCH }} + repo-owner: ${{ env.REPO_OWNER }} - name: Send Slack Notification on Success if: success() && github.event.pull_request.head.repo.owner.login == 'rsksmart' diff --git a/rskj-core/src/integrationTest/java/co/rsk/util/OkHttpClientTestFixture.java b/rskj-core/src/integrationTest/java/co/rsk/util/OkHttpClientTestFixture.java index e3e1fabe913..66bf51c8f3d 100644 --- a/rskj-core/src/integrationTest/java/co/rsk/util/OkHttpClientTestFixture.java +++ b/rskj-core/src/integrationTest/java/co/rsk/util/OkHttpClientTestFixture.java @@ -40,6 +40,31 @@ public class OkHttpClientTestFixture { " \"jsonrpc\": \"2.0\"\n" + "}]"; + public static final String ETH_GET_BLOCK_BY_NUMBER = + "{\n" + + " \"method\": \"eth_getBlockByNumber\",\n" + + " \"params\": [\n" + + " \"\",\n" + + " true\n" + + " ],\n" + + " \"id\": 1,\n" + + " \"jsonrpc\": \"2.0\"\n" + + "}"; + + public static final String ETH_SEND_TRANSACTION = + "{\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"method\": \"eth_sendTransaction\",\n" + + " \"id\": 1,\n" + + " \"params\": [{\n" + + " \"from\": \"\",\n" + + " \"to\": \"\",\n" + + " \"gas\": \"\",\n" + + " \"gasPrice\": \"\",\n" + + " \"value\": \"\"\n" + + " }]\n" + + "}"; + private OkHttpClientTestFixture() { } @@ -101,4 +126,9 @@ public static JsonNode getJsonResponseForGetBestBlockMessage(int port) throws IO Response response = sendJsonRpcGetBestBlockMessage(port); return new ObjectMapper().readTree(response.body().string()); } + + public static String getEnvelopedMethodCalls(String... methodCall) { + return "[\n" + String.join(",\n", methodCall) + "]"; + } + } diff --git a/rskj-core/src/integrationTest/java/pte/PteIntegrationTest.java b/rskj-core/src/integrationTest/java/pte/PteIntegrationTest.java new file mode 100644 index 00000000000..fefc75b6d83 --- /dev/null +++ b/rskj-core/src/integrationTest/java/pte/PteIntegrationTest.java @@ -0,0 +1,244 @@ +/* + * 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 pte; + +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; +import org.apache.commons.lang3.StringUtils; +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.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.*; +import java.util.stream.Stream; + +import static co.rsk.util.OkHttpClientTestFixture.*; + +public class PteIntegrationTest { + + /* + When running this test locally, don't forget to build the .jar for the code you're trying to + test ('./gradlew clean' and './gradlew assemble' should be sufficient for most cases). + */ + + private static final int RPC_PORT = 9999; + private static final int MAX_BLOCKS_TO_GET = 20; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private String buildLibsPath; + private String jarName; + private String strBaseArgs; + private String baseJavaCmd; + + @TempDir + private Path tempDir; + + @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 logbackXmlFile = String.format("%s/logback.xml", integrationTestResourcesPath); + String rskConfFile = String.format("%s/pte-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() + .orElse(""); + + Path databaseDirPath = tempDir.resolve("database"); + String databaseDir = databaseDirPath.toString(); + String[] baseArgs = new String[]{ + String.format("-Xdatabase.dir=%s", databaseDir), + "--regtest", + String.format("-Xrpc.providers.web.http.port=%s", RPC_PORT) + }; + strBaseArgs = String.join(" ", baseArgs); + baseJavaCmd = String.format("java %s %s", String.format("-Dlogback.configurationFile=%s", logbackXmlFile), String.format("-Drsk.conf.file=%s", rskConfFile)); + } + + @Test + void whenParallelizableTransactionsAreSent_someAreExecutedInParallel() throws Exception { + + // Given + + // Pre-funded Test Accounts on Regtest + List accounts = Arrays.asList( + "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "0x7986b3df570230288501eea3d890bd66948c9b79", + "0x0a3aa774752ec2042c46548456c094a76c7f3a79", + "0xcf7cdbbb5f7ba79d3ffe74a0bba13fc0295f6036", + "0x39b12c05e8503356e3a7df0b7b33efa4c054c409", + "0xc354d97642faa06781b76ffb6786f72cd7746c97", + "0xdebe71e1de41fc77c44df4b6db940026e31b0e71", + "0x7857288e171c6159c5576d1bd9ac40c0c48a771c", + "0xa4dea4d5c954f5fd9e87f0e9752911e83a3d18b3", + "0x09a1eda29f664ac8f68106f6567276df0c65d859", + "0xec4ddeb4380ad69b3e509baad9f158cdf4e4681d" + ); + + Map txResponseMap = new HashMap<>(); + Map> blocksResponseMap = new HashMap<>(); + + String cmd = String.format( + "%s -cp %s/%s co.rsk.Start --reset %s", + baseJavaCmd, + buildLibsPath, + jarName, + strBaseArgs); + + // When + + CommandLineFixture.runCommand( + cmd, + 1, + TimeUnit.MINUTES, + proc -> { + try { + + // Send bulk transactions + + Response txResponse = sendBulkTransactions( + accounts.get(0), accounts.get(1), accounts.get(2), accounts.get(3), + accounts.get(4), accounts.get(5), accounts.get(6), accounts.get(7)); + + txResponseMap.put("bulkTransactionsResponse", txResponse); + + // Await for n blocks to be mined and return them + + Future> future = getBlocksAsync(); + + try { + + blocksResponseMap.put("asyncBlocksResult", future.get()); + + } catch (ExecutionException | InterruptedException e) { + Assertions.fail(e); + } + + } catch (IOException e) { + Assertions.fail(e); + } + } + ); + + // Then + + Assertions.assertEquals(200, txResponseMap.get("bulkTransactionsResponse").code()); + + Map blocksResult = blocksResponseMap.get("asyncBlocksResult"); + Assertions.assertEquals(MAX_BLOCKS_TO_GET, blocksResult.size()); + + boolean pteFound = false; + int i = blocksResult.size(); // Start from the last element (optimization) + while (!pteFound && i >= 0) { + i -= 1; + + JsonNode blockResponse = objectMapper.readTree(blocksResult.get(i)); + JsonNode result = blockResponse.get(0).get("result"); + + if (!result.isNull()) { + JsonNode pteEdges = result.get("rskPteEdges"); + if (pteEdges.isArray() && pteEdges.size() > 0) { + Assertions.assertTrue(result.get("transactions").isArray()); + Assertions.assertTrue(result.get("transactions").size() > 1); + pteFound = true; + } + } + } + + Assertions.assertTrue(pteFound); + + } + + private Response getBlockByNumber(String number) throws IOException { + String content = getEnvelopedMethodCalls( + ETH_GET_BLOCK_BY_NUMBER.replace( + "", + number) + ); + + System.out.println(content); + + return OkHttpClientTestFixture.sendJsonRpcMessage(content, RPC_PORT); + } + + private Response sendBulkTransactions( + String addressFrom1, String addressTo1, + String addressFrom2, String addressTo2, + String addressFrom3, String addressTo3, + String addressFrom4, String addressTo4) throws IOException { + + String gas = "0x9C40"; + String gasPrice = "0x10"; + String value = "0x500"; + + String[] placeholders = new String[]{ + "", "", "", + "", "" + }; + + String content = getEnvelopedMethodCalls( + StringUtils.replaceEach(ETH_SEND_TRANSACTION, placeholders, + new String[]{addressFrom1, addressTo1, gas, gasPrice, value}), + StringUtils.replaceEach(ETH_SEND_TRANSACTION, placeholders, + new String[]{addressFrom2, addressTo2, gas, gasPrice, value}), + StringUtils.replaceEach(ETH_SEND_TRANSACTION, placeholders, + new String[]{addressFrom3, addressTo3, gas, gasPrice, value}), + StringUtils.replaceEach(ETH_SEND_TRANSACTION, placeholders, + new String[]{addressFrom4, addressTo4, gas, gasPrice, value}) + ); + + System.out.println(content); + + return OkHttpClientTestFixture.sendJsonRpcMessage(content, RPC_PORT); + } + + private Future> getBlocksAsync() { + CompletableFuture> completableFuture = new CompletableFuture<>(); + + Executors.newCachedThreadPool().submit(() -> { + Map results = new HashMap<>(); + + for (int i = 0; i < MAX_BLOCKS_TO_GET; i++) { + String response = getBlockByNumber("0x" + String.format("%02x", i)).body().string(); + + results.put(i, response); + Thread.sleep(500); + } + + completableFuture.complete(results); + return null; + }); + + return completableFuture; + } + +} \ No newline at end of file diff --git a/rskj-core/src/integrationTest/resources/pte-integration-test-rskj.conf b/rskj-core/src/integrationTest/resources/pte-integration-test-rskj.conf new file mode 100644 index 00000000000..3e6f988dfb3 --- /dev/null +++ b/rskj-core/src/integrationTest/resources/pte-integration-test-rskj.conf @@ -0,0 +1,34 @@ +miner { + + server { + enabled = true + updateWorkOnNewTransaction = true + } + + client { + enabled = true + automine = false + delayBetweenBlocks = 5 seconds + delayBetweenRefreshes = 1 second + } + +} + +peer { + + discovery = { + + # if peer discovery is off + # the peer window will show + # only what retrieved by active + # peer [true/false] + enabled = false + + # List of the peers to start + # the search of the online peers + # values: [ip:port] + ip.list = [] + + } + +} \ No newline at end of file diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index aaf85ce6f3b..3ca9a4ac69e 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -481,9 +481,9 @@ public synchronized BlockExecutor getBlockExecutor() { if (blockExecutor == null) { blockExecutor = new BlockExecutor( - getRskSystemProperties().getActivationConfig(), getRepositoryLocator(), - getTransactionExecutorFactory() + getTransactionExecutorFactory(), + getRskSystemProperties() ); } @@ -1093,7 +1093,7 @@ public synchronized BlockValidationRule getBlockValidationRule() { rskSystemProperties.getActivationConfig(), rskSystemProperties.getNetworkConstants() ); - blockValidationRule = new BlockValidatorRule( + blockValidationRule = new BlockCompositeRule( new TxsMinGasPriceRule(), new BlockTxsMaxGasPriceRule(rskSystemProperties.getActivationConfig()), new BlockUnclesValidationRule( @@ -1120,7 +1120,8 @@ public synchronized BlockValidationRule getBlockValidationRule() { blockTimeStampValidationRule, new GasLimitRule(commonConstants.getMinGasLimit()), new ExtraDataRule(commonConstants.getMaximumExtraDataSize()), - getForkDetectionDataRule() + getForkDetectionDataRule(), + new ValidTxExecutionSublistsEdgesRule(getRskSystemProperties().getActivationConfig()) ); } diff --git a/rskj-core/src/main/java/co/rsk/cli/tools/ExecuteBlocks.java b/rskj-core/src/main/java/co/rsk/cli/tools/ExecuteBlocks.java index 2f80fafbed7..61ca94672e4 100644 --- a/rskj-core/src/main/java/co/rsk/cli/tools/ExecuteBlocks.java +++ b/rskj-core/src/main/java/co/rsk/cli/tools/ExecuteBlocks.java @@ -70,7 +70,7 @@ private void executeBlocks(BlockExecutor blockExecutor, BlockStore blockStore, T Block block = blockStore.getChainBlockByNumber(n); Block parent = blockStore.getBlockByHash(block.getParentHash().getBytes()); - BlockResult blockResult = blockExecutor.execute(block, parent.getHeader(), false, false, true); + BlockResult blockResult = blockExecutor.execute(null, 0, block, parent.getHeader(), false, false, true); Keccak256 stateRootHash = stateRootHandler.translate(block.getHeader()); if (!Arrays.equals(blockResult.getFinalState().getHash().getBytes(), stateRootHash.getBytes())) { diff --git a/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java b/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java index b2df37f1357..4b513e206f6 100644 --- a/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java +++ b/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java @@ -21,6 +21,7 @@ import co.rsk.core.RskAddress; import co.rsk.net.discovery.table.KademliaOptions; import co.rsk.rpc.ModuleDescription; +import com.google.common.annotations.VisibleForTesting; import com.typesafe.config.Config; import com.typesafe.config.ConfigObject; import com.typesafe.config.ConfigValue; @@ -31,7 +32,9 @@ import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.ethereum.listener.GasPriceCalculator; +import org.ethereum.vm.PrecompiledContracts; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -72,6 +75,10 @@ public class RskSystemProperties extends SystemProperties { //TODO: REMOVE THIS WHEN THE LocalBLockTests starts working with REMASC private boolean remascEnabled = true; + private Set concurrentContractsDisallowed = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + PrecompiledContracts.REMASC_ADDR, PrecompiledContracts.BRIDGE_ADDR + ))); + private List moduleDescriptions; public RskSystemProperties(ConfigLoader loader) { @@ -246,6 +253,15 @@ public boolean isRemascEnabled() { return remascEnabled; } + public Set concurrentContractsDisallowed() { + return concurrentContractsDisallowed; + } + + @VisibleForTesting + public void setConcurrentContractsDisallowed(@Nonnull Set disallowed) { + this.concurrentContractsDisallowed = Collections.unmodifiableSet(new HashSet<>(disallowed)); + } + //TODO: REMOVE THIS WHEN THE LocalBLockTests starts working with REMASC public void setRemascEnabled(boolean remascEnabled) { this.remascEnabled = remascEnabled; @@ -258,7 +274,7 @@ public boolean skipRemasc() { public boolean usePeersFromLastSession() { return getBoolean(USE_PEERS_FROM_LAST_SESSION, false); } - + public long peerDiscoveryMessageTimeOut() { return getLong("peer.discovery.msg.timeout", PD_DEFAULT_TIMEOUT_MESSAGE); } 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..c8b951f5e43 100644 --- a/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java +++ b/rskj-core/src/main/java/co/rsk/core/TransactionExecutorFactory.java @@ -24,6 +24,7 @@ import org.ethereum.db.BlockStore; import org.ethereum.db.ReceiptStore; import org.ethereum.vm.DataWord; +import org.ethereum.vm.GasCost; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.invoke.ProgramInvokeFactory; @@ -66,6 +67,7 @@ public TransactionExecutor newInstance( long totalGasUsed) { return newInstance(tx, txindex, coinbase, track, block, totalGasUsed, false, 0, new HashSet<>()); } + // TODO(JULI): newInstance calls a second newInstance hardcoding Postpone payment fees and sublist gas limit as block.gasLimit() public TransactionExecutor newInstance( Transaction tx, @@ -76,7 +78,9 @@ public TransactionExecutor newInstance( long totalGasUsed, boolean vmTrace, int vmTraceOptions, - Set deletedAccounts) { + Set deletedAccounts, + boolean postponeFeePayment, + long sublistGasLimit) { // Tracing configuration is scattered across different files (VM, DetailedProgramTrace, etc.) and // TransactionExecutor#extractTrace doesn't work when called independently. // It would be great to decouple from VmConfig#vmTrace, but sadly that's a major refactor we can't do now. @@ -109,7 +113,23 @@ public TransactionExecutor newInstance( config.isRemascEnabled(), precompiledContracts, deletedAccounts, - blockTxSignatureCache + blockTxSignatureCache, + postponeFeePayment, + sublistGasLimit ); } + + public TransactionExecutor newInstance( + Transaction tx, + int txindex, + RskAddress coinbase, + Repository track, + Block block, + long totalGasUsed, + boolean vmTrace, + int vmTraceOptions, + Set deletedAccounts) { + return newInstance(tx, txindex, coinbase, track, block, totalGasUsed, vmTrace, vmTraceOptions, deletedAccounts, false, GasCost.toGas(block.getGasLimit())); + } + // TODO(JULI): set the sublist gas limit as the whole block is wrong. However, this method is just used either when RSKIP144 is deactivated or for testing. } diff --git a/rskj-core/src/main/java/co/rsk/core/TransactionListExecutor.java b/rskj-core/src/main/java/co/rsk/core/TransactionListExecutor.java new file mode 100644 index 00000000000..208da85832d --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/TransactionListExecutor.java @@ -0,0 +1,250 @@ +package co.rsk.core; + +import co.rsk.crypto.Keccak256; +import org.ethereum.core.*; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.PrecompiledContracts; +import org.ethereum.vm.program.ProgramResult; +import org.ethereum.vm.trace.ProgramTraceProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.concurrent.Callable; + +public class TransactionListExecutor implements Callable { + + private static final Logger logger = LoggerFactory.getLogger("transactionlistexecutor"); + + private final TransactionExecutorFactory transactionExecutorFactory; + private final List transactions; + private final Block block; + private final Repository track; + private final boolean vmTrace; + private final int vmTraceOptions; + private final Set deletedAccounts; + private final boolean discardInvalidTxs; + private final boolean acceptInvalidTransactions; + private final Map executedTransactions; + private final Map receipts; + private final Map transactionResults; + private final ProgramTraceProcessor programTraceProcessor; + private long sublistGasLimit; + private final boolean remascEnabled; + private long totalGas; + private int i; + private final boolean registerProgramResults; + private final Set concurrentContractsDisallowed; + private Coin totalPaidFees; + + private volatile boolean stopped; + + public TransactionListExecutor( + List transactions, + Block block, + TransactionExecutorFactory transactionExecutorFactory, + Repository track, + boolean vmTrace, + int vmTraceOptions, + Set deletedAccounts, + boolean discardInvalidTxs, + boolean acceptInvalidTransactions, + Map receipts, + Map executedTransactions, + Map transactionResults, + boolean registerProgramResults, + @Nullable ProgramTraceProcessor programTraceProcessor, + int firstTxIndex, + Coin totalPaidFees, + boolean remascEnabled, + Set concurrentContractsDisallowed, + long sublistGasLimit) { + this.block = block; + this.transactionExecutorFactory = transactionExecutorFactory; + this.track = track; + this.vmTrace = vmTrace; + this.vmTraceOptions = vmTraceOptions; + this.transactions = new ArrayList<>(transactions); + this.deletedAccounts = deletedAccounts; + this.discardInvalidTxs = discardInvalidTxs; + this.acceptInvalidTransactions = acceptInvalidTransactions; + this.executedTransactions = executedTransactions; + this.receipts = receipts; + this.registerProgramResults = registerProgramResults; + this.transactionResults = transactionResults; + this.programTraceProcessor = programTraceProcessor; + this.totalGas = 0L; + this.i = firstTxIndex; + this.totalPaidFees = totalPaidFees; + this.remascEnabled = remascEnabled; + this.concurrentContractsDisallowed = Collections.unmodifiableSet(new HashSet<>(concurrentContractsDisallowed)); + this.sublistGasLimit = sublistGasLimit; + } + + @Override + public Boolean call() { + if (stopped) { + return false; + } + + long totalGasUsed = 0; + for (Transaction tx : transactions) { + + int numberOfTransactions = block.getTransactionsList().size(); + boolean isRemascTransaction = tx.isRemascTransaction(this.i, numberOfTransactions); + + addFeesToRemascIfEnabled(isRemascTransaction); + + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance( + tx, + i, + block.getCoinbase(), + track, + block, + totalGasUsed, + vmTrace, + vmTraceOptions, + deletedAccounts, + true, + sublistGasLimit); + boolean transactionSucceeded = txExecutor.executeTransaction(); + if (stopped) { + return false; + } + + if (!this.concurrentContractsDisallowed.isEmpty() && txExecutor.precompiledContractsCalled().stream().anyMatch(this.concurrentContractsDisallowed::contains)) { + transactionSucceeded = false; + } + + if (!acceptInvalidTransactions && !transactionSucceeded) { + if (discardIfInvalid(tx, numberOfTransactions, isRemascTransaction)) { + return false; + } + continue; + } + + executedTransactions.put(i, tx); + + if (this.registerProgramResults) { + this.transactionResults.put(tx.getHash(), txExecutor.getResult()); + } + + if (vmTrace) { + txExecutor.extractTrace(programTraceProcessor); + } + + logger.trace("tx[{}] executed", i + 1); + logger.trace("track commit"); + + long txGasUsed = txExecutor.getGasConsumed(); + totalGasUsed += txGasUsed; + + addPaidFeesToToal(txExecutor); + + // It's used just for testing, the last tx should be always the REMASC. + payToRemascWhenThereIsNoRemascTx(numberOfTransactions, isRemascTransaction); + + deletedAccounts.addAll(txExecutor.getResult().getDeleteAccounts()); + + TransactionReceipt receipt = createTransactionReceipt(totalGasUsed, tx, txExecutor, txGasUsed); + + logger.trace("block: [{}] executed tx: [{}]", block.getNumber(), tx.getHash()); + + i++; + + logger.trace("tx[{}].receipt", i); + + receipts.put(i, receipt); + + logger.trace("tx[{}] done", i); + } + totalGas += totalGasUsed; + return true; + } + + private boolean discardIfInvalid(Transaction tx, int numberOfTransactions, boolean isRemascTransaction) { + // It's used just for testing, the last tx should be always the REMASC. + payToRemascWhenThereIsNoRemascTx(numberOfTransactions, isRemascTransaction); + if (!discardInvalidTxs) { + logger.warn("block: [{}] execution interrupted because of invalid tx: [{}]", + block.getNumber(), tx.getHash() + ); + return true; + } + + logger.warn("block: [{}] discarded tx: [{}]", block.getNumber(), tx.getHash()); + return false; + } + + private TransactionReceipt createTransactionReceipt(long totalGasUsed, Transaction tx, TransactionExecutor txExecutor, long txGasUsed) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setGasUsed(txGasUsed); + receipt.setCumulativeGas(totalGasUsed); + + receipt.setTxStatus(txExecutor.getReceipt().isSuccessful()); + receipt.setTransaction(tx); + receipt.setLogInfoList(txExecutor.getVMLogs()); + receipt.setStatus(txExecutor.getReceipt().getStatus()); + return receipt; + } + + private void addPaidFeesToToal(TransactionExecutor txExecutor) { + Coin txPaidFees = txExecutor.getPaidFees(); + if (txPaidFees != null) { + totalPaidFees = totalPaidFees.add(txPaidFees); + } + } + + private void addFeesToRemascIfEnabled(boolean isRemascTransaction) { + if (this.remascEnabled && isRemascTransaction) { + addFeesToRemasc(); + } + } + + private void payToRemascWhenThereIsNoRemascTx(int numberOfTransactions, boolean isRemascTransaction) { + boolean isLastTx = this.i == numberOfTransactions - 1; + if (this.remascEnabled && isLastTx && !isRemascTransaction) { + addFeesToRemasc(); + } + } + + private void addFeesToRemasc() { + if (this.totalPaidFees.compareTo(Coin.ZERO) > 0) { + logger.trace("Adding fee to remasc contract account"); + track.addBalance(PrecompiledContracts.REMASC_ADDR, this.totalPaidFees); + } + } + + public Repository getRepository() { + return this.track; + } + + public Set getDeletedAccounts() { + return new HashSet<>(this.deletedAccounts); + } + + public Map getReceipts() { + return this.receipts; + } + + public Map getExecutedTransactions() { + return this.executedTransactions; + } + + public Map getTransactionResults() { + return this.transactionResults; + } + + public Coin getTotalFees() { + return this.totalPaidFees; + } + + public long getTotalGas() { + return this.totalGas; + } + + public void stop() { + this.stopped = true; + } +} diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockChainImpl.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockChainImpl.java index 2a369dd61ce..6bed3f10649 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockChainImpl.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockChainImpl.java @@ -249,7 +249,7 @@ private ImportResult internalTryToConnect(Block block) { long saveTime = System.nanoTime(); logger.trace("execute start"); - result = blockExecutor.execute(block, parent.getHeader(), false, noValidation, true); + result = blockExecutor.execute(null, 0, block, parent.getHeader(), false, noValidation, true); logger.trace("execute done"); 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..afff40d822b 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 @@ -18,18 +18,22 @@ package co.rsk.core.bc; +import co.rsk.config.RskSystemProperties; import co.rsk.core.Coin; import co.rsk.core.RskAddress; import co.rsk.core.TransactionExecutorFactory; +import co.rsk.core.TransactionListExecutor; import co.rsk.crypto.Keccak256; import co.rsk.db.RepositoryLocator; import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; 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.*; +import org.ethereum.util.ByteUtil; import org.ethereum.vm.DataWord; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.ProgramResult; @@ -37,8 +41,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP126; import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP85; @@ -48,7 +55,7 @@ * There are two main use cases: * - execute and validate the block final state * - execute and complete the block final state - * + *

* Note that this class IS NOT guaranteed to be thread safe because its dependencies might hold state. */ public class BlockExecutor { @@ -58,40 +65,96 @@ public class BlockExecutor { private final RepositoryLocator repositoryLocator; private final TransactionExecutorFactory transactionExecutorFactory; private final ActivationConfig activationConfig; + private final boolean remascEnabled; + private final Set concurrentContractsDisallowed; - private final Map transactionResults = new HashMap<>(); + private final Map transactionResults = new ConcurrentHashMap<>(); private boolean registerProgramResults; + private long minSequentialSetGasLimit; + + /** + * An array of ExecutorService's of size `Constants.getTransactionExecutionThreads()`. Each parallel list uses an executor + * at specific index of this array, so that threads chosen by thread pools cannot be "reused" for executing parallel + * lists from same block. Otherwise, that could lead to non-determinism, when trie keys collision may not be detected + * on some circumstances. + */ + private final ExecutorService[] execServices; public BlockExecutor( - ActivationConfig activationConfig, RepositoryLocator repositoryLocator, - TransactionExecutorFactory transactionExecutorFactory) { + TransactionExecutorFactory transactionExecutorFactory, + RskSystemProperties systemProperties) { this.repositoryLocator = repositoryLocator; this.transactionExecutorFactory = transactionExecutorFactory; - this.activationConfig = activationConfig; + this.activationConfig = systemProperties.getActivationConfig(); + this.remascEnabled = systemProperties.isRemascEnabled(); + this.concurrentContractsDisallowed = Collections.unmodifiableSet(new HashSet<>(systemProperties.concurrentContractsDisallowed())); + this.minSequentialSetGasLimit = systemProperties.getNetworkConstants().getMinSequentialSetGasLimit(); + + int numOfParallelList = Constants.getTransactionExecutionThreads(); + this.execServices = new ExecutorService[numOfParallelList]; + for (int i = 0; i < numOfParallelList; i++) { + execServices[i] = new ThreadPoolExecutorImpl(i); + } + } + + /** + * Precompiled contracts storage is setup like any other contract for consistency. Here, we apply this logic on the + * exact activation block. + * This method is called automatically for every block except for the Genesis (which makes an explicit call). + */ + public static void maintainPrecompiledContractStorageRoots(Repository track, ActivationConfig.ForBlock activations) { + if (activations.isActivating(RSKIP126)) { + for (RskAddress addr : PrecompiledContracts.GENESIS_ADDRESSES) { + if (!track.isExist(addr)) { + track.createAccount(addr); + } + track.setupContract(addr); + } + } + + for (Map.Entry e : PrecompiledContracts.CONSENSUS_ENABLED_ADDRESSES.entrySet()) { + ConsensusRule contractActivationRule = e.getValue(); + if (activations.isActivating(contractActivationRule)) { + RskAddress addr = e.getKey(); + track.createAccount(addr); + track.setupContract(addr); + } + } + } + + @VisibleForTesting + public static byte[] calculateLogsBloom(List receipts) { + Bloom logBloom = new Bloom(); + + for (TransactionReceipt receipt : receipts) { + logBloom.or(receipt.getBloomFilter()); + } + + return logBloom.getData(); } /** * Execute and complete a block. * - * @param block A block to execute and complete - * @param parent The parent of the block. + * @param block A block to execute and complete + * @param parent The parent of the block. */ public BlockResult executeAndFill(Block block, BlockHeader parent) { - BlockResult result = execute(block, parent, true, false, false); + BlockResult result = executeForMining(block, parent, true, false, false); fill(block, result); return result; } @VisibleForTesting public void executeAndFillAll(Block block, BlockHeader parent) { - BlockResult result = execute(block, parent, false, true, false); + BlockResult result = executeForMining(block, parent, false, true, false); fill(block, result); } @VisibleForTesting public void executeAndFillReal(Block block, BlockHeader parent) { - BlockResult result = execute(block, parent, false, false, false); + BlockResult result = executeForMining(block, parent, false, false, false); if (result != BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT) { fill(block, result); } @@ -108,6 +171,7 @@ private void fill(Block block, BlockResult result) { header.setGasUsed(result.getGasUsed()); header.setPaidFees(result.getPaidFees()); header.setLogsBloom(calculateLogsBloom(result.getTransactionReceipts())); + header.setTxExecutionSublistsEdges(result.getTxEdges()); block.flushRLP(); profiler.stop(metric); @@ -116,13 +180,13 @@ private void fill(Block block, BlockResult result) { /** * Execute and validate the final state of a block. * - * @param block A block to execute and complete - * @param parent The parent of the block. + * @param block A block to execute and complete + * @param parent The parent of the block. * @return true if the block final state is equalBytes to the calculated final state. */ @VisibleForTesting public boolean executeAndValidate(Block block, BlockHeader parent) { - BlockResult result = execute(block, parent, false, false, false); + BlockResult result = execute(null, 0, block, parent, false, false, false); return this.validate(block, result); } @@ -130,8 +194,8 @@ public boolean executeAndValidate(Block block, BlockHeader parent) { /** * Validate the final state of a block. * - * @param block A block to validate - * @param result A block result (state root, receipts root, etc...) + * @param block A block to validate + * @param result A block result (state root, receipts root, etc...) * @return true if the block final state is equalBytes to the calculated final state. */ public boolean validate(Block block, BlockResult result) { @@ -172,7 +236,7 @@ public boolean validate(Block block, BlockResult result) { Coin paidFees = result.getPaidFees(); Coin feesPaidToMiner = block.getFeesPaidToMiner(); - if (!paidFees.equals(feesPaidToMiner)) { + if (!paidFees.equals(feesPaidToMiner)) { logger.error("Block {} [{}] given paidFees doesn't match: {} != {}", block.getNumber(), block.getPrintableHash(), feesPaidToMiner, paidFees); profiler.stop(metric); return false; @@ -181,7 +245,7 @@ public boolean validate(Block block, BlockResult result) { List executedTransactions = result.getExecutedTransactions(); List transactionsList = block.getTransactionsList(); - if (!executedTransactions.equals(transactionsList)) { + if (!executedTransactions.equals(transactionsList)) { logger.error("Block {} [{}] given txs doesn't match: {} != {}", block.getNumber(), block.getPrintableHash(), transactionsList, executedTransactions); profiler.stop(metric); return false; @@ -217,30 +281,45 @@ private boolean validateLogsBloom(BlockHeader header, BlockResult result) { return Arrays.equals(calculateLogsBloom(result.getTransactionReceipts()), header.getLogsBloom()); } - @VisibleForTesting - BlockResult execute(Block block, BlockHeader parent, boolean discardInvalidTxs) { - return execute(block, parent, discardInvalidTxs, false, true); - } - - public BlockResult execute(Block block, BlockHeader parent, boolean discardInvalidTxs, boolean ignoreReadyToExecute, boolean saveState) { - return executeInternal(null, 0, block, parent, discardInvalidTxs, ignoreReadyToExecute, saveState); + public BlockResult executeForMining(Block block, BlockHeader parent, boolean discardInvalidTxs, boolean ignoreReadyToExecute, boolean saveState) { + if (activationConfig.isActive(ConsensusRule.RSKIP144, block.getHeader().getNumber())) { + return executeForMiningAfterRSKIP144(block, parent, discardInvalidTxs, ignoreReadyToExecute, saveState); + } else { + return executeInternal(null, 0, block, parent, discardInvalidTxs, ignoreReadyToExecute, saveState); + } } /** * Execute a block while saving the execution trace in the trace processor */ - public void traceBlock( - ProgramTraceProcessor programTraceProcessor, - int vmTraceOptions, - Block block, - BlockHeader parent, - boolean discardInvalidTxs, - boolean ignoreReadyToExecute) { - executeInternal( - Objects.requireNonNull(programTraceProcessor), vmTraceOptions, block, parent, discardInvalidTxs, ignoreReadyToExecute, false - ); + public void traceBlock(ProgramTraceProcessor programTraceProcessor, + int vmTraceOptions, + Block block, + BlockHeader parent, + boolean discardInvalidTxs, + boolean ignoreReadyToExecute) { + execute(Objects.requireNonNull(programTraceProcessor), vmTraceOptions, block, parent, discardInvalidTxs, + ignoreReadyToExecute, false); } + public BlockResult execute(@Nullable ProgramTraceProcessor programTraceProcessor, + int vmTraceOptions, + Block block, + BlockHeader parent, + boolean discardInvalidTxs, + boolean acceptInvalidTransactions, + boolean saveState) { + if (activationConfig.isActive(ConsensusRule.RSKIP144, block.getHeader().getNumber())) { + return executeParallel(programTraceProcessor, vmTraceOptions, block, parent, discardInvalidTxs, acceptInvalidTransactions, saveState); + } else { + return executeInternal(programTraceProcessor, vmTraceOptions, block, parent, discardInvalidTxs, acceptInvalidTransactions, saveState); + } + } + + // executes the block before RSKIP 144 + // when RSKIP 144 is active the block is in executed parallel + // miners use executeForMiningAfterRSKIP144 to create the parallel schedule + // new blocks are executed with executeParallel private BlockResult executeInternal( @Nullable ProgramTraceProcessor programTraceProcessor, int vmTraceOptions, @@ -250,8 +329,8 @@ private BlockResult executeInternal( boolean acceptInvalidTransactions, boolean saveState) { boolean vmTrace = programTraceProcessor != null; - logger.trace("Start executeInternal."); - logger.trace("applyBlock: block: [{}] tx.list: [{}]", block.getNumber(), block.getTransactionsList().size()); + logger.trace("Start execute pre RSKIP144."); + loggingApplyBlock(block); // Forks the repo, does not change "repository". It will have a completely different // image of the repo, where the middle caches are immediately ignored. @@ -261,7 +340,7 @@ private BlockResult executeInternal( // in the next block processed. // Note that creating a snapshot is important when the block is executed twice // (e.g. once while building the block in tests/mining, and the other when trying - // to conect the block). This is because the first execution will change the state + // to connect the block). This is because the first execution will change the state // of the repository to the state post execution, so it's necessary to get it to // the state prior execution again. Metric metric = profiler.start(Profiler.PROFILING_TYPE.BLOCK_EXECUTE); @@ -280,7 +359,7 @@ private BlockResult executeInternal( int txindex = 0; for (Transaction tx : block.getTransactionsList()) { - logger.trace("apply block: [{}] tx: [{}] ", block.getNumber(), i); + loggingApplyBlockToTx(block, i); TransactionExecutor txExecutor = transactionExecutorFactory.newInstance( tx, @@ -295,121 +374,465 @@ private BlockResult executeInternal( boolean transactionExecuted = txExecutor.executeTransaction(); if (!acceptInvalidTransactions && !transactionExecuted) { - if (discardInvalidTxs) { - logger.warn("block: [{}] discarded tx: [{}]", block.getNumber(), tx.getHash()); - continue; - } else { - logger.warn("block: [{}] execution interrupted because of invalid tx: [{}]", - block.getNumber(), tx.getHash()); - profiler.stop(metric); - return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; + if (!discardInvalidTxs) { + return getBlockResultAndLogExecutionInterrupted(block, metric, tx); } + loggingDiscardedBlock(block, tx); + continue; } - executedTransactions.add(tx); + registerExecutedTx(programTraceProcessor, vmTrace, executedTransactions, tx, txExecutor); + + long gasUsed = txExecutor.getGasConsumed(); + totalGasUsed += gasUsed; + + totalPaidFees = addTotalPaidFees(totalPaidFees, txExecutor); + + deletedAccounts.addAll(txExecutor.getResult().getDeleteAccounts()); + + TransactionReceipt receipt = buildTransactionReceipt(tx, txExecutor, gasUsed, totalGasUsed); + + loggingExecuteTxAndReceipt(block, i, tx); + + i++; + + receipts.add(receipt); + + loggingTxDone(); + } + + + saveOrCommitTrackState(saveState, track); + + BlockResult result = new BlockResult( + block, + executedTransactions, + receipts, + null, + totalGasUsed, + totalPaidFees, + vmTrace ? null : track.getTrie() + + ); + profiler.stop(metric); + logger.trace("End execute pre RSKIP144."); + return result; + } + + private BlockResult executeParallel( + @Nullable ProgramTraceProcessor programTraceProcessor, + int vmTraceOptions, + Block block, + BlockHeader parent, + boolean discardInvalidTxs, + boolean acceptInvalidTransactions, + boolean saveState) { + boolean vmTrace = programTraceProcessor != null; + logger.trace("Start executeParallel."); + loggingApplyBlock(block); + + // Forks the repo, does not change "repository". It will have a completely different + // image of the repo, where the middle caches are immediately ignored. + // In fact, while cloning everything, it asserts that no cache elements remains. + // (see assertNoCache()) + // Which means that you must commit changes and save them to be able to recover + // in the next block processed. + // Note that creating a snapshot is important when the block is executed twice + // (e.g. once while building the block in tests/mining, and the other when trying + // to conect the block). This is because the first execution will change the state + // of the repository to the state post execution, so it's necessary to get it to + // the state prior execution again. + Metric metric = profiler.start(Profiler.PROFILING_TYPE.BLOCK_EXECUTE); + + ReadWrittenKeysTracker readWrittenKeysTracker = new ReadWrittenKeysTracker(); + Repository track = repositoryLocator.startTrackingAt(parent, readWrittenKeysTracker); + + maintainPrecompiledContractStorageRoots(track, activationConfig.forBlock(block.getNumber())); + readWrittenKeysTracker.clear(); + + short[] txExecutionEdges = block.getHeader().getTxExecutionSublistsEdges(); + + // if the number of parallel lists is less than 2, then there's no need to execute in another thread. The work can + // be done in the same thread (in-line) without any threads switching. + ExecutorCompletionService completionService = new ExecutorCompletionService<>(txExecutionEdges.length > 1 ? new Executor() { + private final AtomicInteger parallelListIndex = new AtomicInteger(0); // 'parallelListIndex' should not exceed Constants.getTransactionExecutionThreads() - if (this.registerProgramResults) { - this.transactionResults.put(tx.getHash(), txExecutor.getResult()); + @Override + public void execute(@Nonnull Runnable command) { + execServices[parallelListIndex.getAndIncrement()].execute(command); } + } : Runnable::run); + List transactionListExecutors = new ArrayList<>(); - if (vmTrace) { - txExecutor.extractTrace(programTraceProcessor); + short start = 0; + + for (short end : txExecutionEdges) { + List sublist = block.getTransactionsList().subList(start, end); + TransactionListExecutor txListExecutor = new TransactionListExecutor( + sublist, + block, + transactionExecutorFactory, + track.startTracking(), + vmTrace, + vmTraceOptions, + new HashSet<>(), + discardInvalidTxs, + acceptInvalidTransactions, + new HashMap<>(), + new HashMap<>(), + new HashMap<>(), + registerProgramResults, + programTraceProcessor, + start, + Coin.ZERO, + remascEnabled, + concurrentContractsDisallowed, + BlockUtils.getSublistGasLimit(block, false, minSequentialSetGasLimit) + ); + completionService.submit(txListExecutor); + transactionListExecutors.add(txListExecutor); + start = end; + } + + for (int i = 0; i < transactionListExecutors.size(); i++) { + try { + Future success = completionService.take(); + if (!Boolean.TRUE.equals(success.get())) { + transactionListExecutors.forEach(TransactionListExecutor::stop); + profiler.stop(metric); + return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; + } + } catch (InterruptedException e) { + logger.warn("block: [{}]/[{}] execution was interrupted", block.getNumber(), block.getHash()); + logger.trace("", e); + Thread.currentThread().interrupt(); + profiler.stop(metric); + return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; + } catch (ExecutionException e) { + logger.warn("block: [{}]/[{}] execution failed", block.getNumber(), block.getHash()); + logger.trace("", e); + profiler.stop(metric); + return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; } + } - logger.trace("tx executed"); + // Review collision + if (readWrittenKeysTracker.detectCollision()) { + logger.warn("block: [{}]/[{}] execution failed. Block data: [{}]", block.getNumber(), block.getHash(), ByteUtil.toHexString(block.getEncoded())); + profiler.stop(metric); + return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; + } - // No need to commit the changes here. track.commit(); + // Merge maps. + Map executedTransactions = new HashMap<>(); + Set deletedAccounts = new HashSet<>(); + Map receipts = new HashMap<>(); + Map mergedTransactionResults = new HashMap<>(); + Coin totalPaidFees = Coin.ZERO; + long totalGasUsed = 0; - logger.trace("track commit"); + for (TransactionListExecutor tle : transactionListExecutors) { + tle.getRepository().commit(); + deletedAccounts.addAll(tle.getDeletedAccounts()); + executedTransactions.putAll(tle.getExecutedTransactions()); + receipts.putAll(tle.getReceipts()); + mergedTransactionResults.putAll(tle.getTransactionResults()); + totalPaidFees = totalPaidFees.add(tle.getTotalFees()); + totalGasUsed += tle.getTotalGas(); + } - long gasUsed = txExecutor.getGasUsed(); - totalGasUsed += gasUsed; - Coin paidFees = txExecutor.getPaidFees(); - if (paidFees != null) { - totalPaidFees = totalPaidFees.add(paidFees); + // execute remaining transactions after the parallel subsets + List sublist = block.getTransactionsList().subList(start, block.getTransactionsList().size()); + TransactionListExecutor txListExecutor = new TransactionListExecutor( + sublist, + block, + transactionExecutorFactory, + track, + vmTrace, + vmTraceOptions, + deletedAccounts, + discardInvalidTxs, + acceptInvalidTransactions, + receipts, + executedTransactions, + mergedTransactionResults, + registerProgramResults, + programTraceProcessor, + start, + totalPaidFees, + remascEnabled, + Collections.emptySet(), // precompiled contracts are always allowed in a sequential list, as there's no concurrency in it + BlockUtils.getSublistGasLimit(block, true, minSequentialSetGasLimit) + ); + Boolean success = txListExecutor.call(); + if (!Boolean.TRUE.equals(success)) { + return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; + } + + Coin totalBlockPaidFees = txListExecutor.getTotalFees(); + totalGasUsed += txListExecutor.getTotalGas(); + + saveOrCommitTrackState(saveState, track); + + BlockResult result = new BlockResult( + block, + new LinkedList<>(executedTransactions.values()), + new LinkedList<>(receipts.values()), + txExecutionEdges, + totalGasUsed, + totalBlockPaidFees, + vmTrace ? null : track.getTrie() + ); + profiler.stop(metric); + logger.trace("End executeParallel."); + return result; + } + + private BlockResult executeForMiningAfterRSKIP144( + Block block, + BlockHeader parent, + boolean discardInvalidTxs, + boolean acceptInvalidTransactions, + boolean saveState) { + logger.trace("Start executeForMining."); + List transactionsList = block.getTransactionsList(); + loggingApplyBlock(block); + + // Forks the repo, does not change "repository". It will have a completely different + // image of the repo, where the middle caches are immediately ignored. + // In fact, while cloning everything, it asserts that no cache elements remains. + // (see assertNoCache()) + // Which means that you must commit changes and save them to be able to recover + // in the next block processed. + // Note that creating a snapshot is important when the block is executed twice + // (e.g. once while building the block in tests/mining, and the other when trying + // to conect the block). This is because the first execution will change the state + // of the repository to the state post execution, so it's necessary to get it to + // the state prior execution again. + Metric metric = profiler.start(Profiler.PROFILING_TYPE.BLOCK_EXECUTE); + + IReadWrittenKeysTracker readWrittenKeysTracker = new ReadWrittenKeysTracker(); + Repository track = repositoryLocator.startTrackingAt(parent, readWrittenKeysTracker); + + maintainPrecompiledContractStorageRoots(track, activationConfig.forBlock(block.getNumber())); + readWrittenKeysTracker.clear(); + + int i = 1; + long totalGasUsed = 0; + Coin totalPaidFees = Coin.ZERO; + Map receiptsByTx = new HashMap<>(); + Set deletedAccounts = new HashSet<>(); + + int txindex = 0; + + int transactionExecutionThreads = Constants.getTransactionExecutionThreads(); + ParallelizeTransactionHandler parallelizeTransactionHandler = new ParallelizeTransactionHandler((short) transactionExecutionThreads, block, minSequentialSetGasLimit); + + for (Transaction tx : transactionsList) { + loggingApplyBlockToTx(block, i); + + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance( + tx, + txindex, + block.getCoinbase(), + track, + block, + parallelizeTransactionHandler.getGasUsedInSequential(), + false, + 0, + deletedAccounts, + true, + Math.max(BlockUtils.getSublistGasLimit(block, true, minSequentialSetGasLimit), BlockUtils.getSublistGasLimit(block, false, minSequentialSetGasLimit)) + ); + boolean transactionExecuted = txExecutor.executeTransaction(); + + if (!acceptInvalidTransactions && !transactionExecuted) { + if (!discardInvalidTxs) { + return getBlockResultAndLogExecutionInterrupted(block, metric, tx); + } + + loggingDiscardedBlock(block, tx); + txindex++; + continue; } - deletedAccounts.addAll(txExecutor.getResult().getDeleteAccounts()); + Optional sublistGasAccumulated = addTxToSublistAndGetAccumulatedGas( + readWrittenKeysTracker, + parallelizeTransactionHandler, + tx, + tx.isRemascTransaction(txindex, transactionsList.size()), + txExecutor.getGasConsumed(), + txExecutor.precompiledContractsCalled().stream().anyMatch(this.concurrentContractsDisallowed::contains)); + + if (!acceptInvalidTransactions && !sublistGasAccumulated.isPresent()) { + if (!discardInvalidTxs) { + return getBlockResultAndLogExecutionInterrupted(block, metric, tx); + } - TransactionReceipt receipt = new TransactionReceipt(); - receipt.setGasUsed(gasUsed); - receipt.setCumulativeGas(totalGasUsed); + loggingDiscardedBlock(block, tx); + txindex++; + continue; + } + + registerTxExecutedForMiningAfterRSKIP144(readWrittenKeysTracker, tx, txExecutor); - receipt.setTxStatus(txExecutor.getReceipt().isSuccessful()); - receipt.setTransaction(tx); - receipt.setLogInfoList(txExecutor.getVMLogs()); - receipt.setStatus(txExecutor.getReceipt().getStatus()); + long gasUsed = txExecutor.getGasConsumed(); + totalGasUsed += gasUsed; + totalPaidFees = addTotalPaidFees(totalPaidFees, txExecutor); + + deletedAccounts.addAll(txExecutor.getResult().getDeleteAccounts()); - logger.trace("block: [{}] executed tx: [{}]", block.getNumber(), tx.getHash()); + //orElseGet is used for testing only when acceptInvalidTransactions is set. + long cumulativeGas = sublistGasAccumulated + .orElseGet(() -> parallelizeTransactionHandler.getGasUsedIn((short) Constants.getTransactionExecutionThreads())); + TransactionReceipt receipt = buildTransactionReceipt(tx, txExecutor, gasUsed, cumulativeGas); - logger.trace("tx[{}].receipt", i); + loggingExecuteTxAndReceipt(block, i, tx); i++; + txindex++; - receipts.add(receipt); + receiptsByTx.put(tx, receipt); - logger.trace("tx done"); + loggingTxDone(); } - logger.trace("End txs executions."); - if (saveState) { - logger.trace("Saving track."); - track.save(); - logger.trace("End saving track."); - } else { - logger.trace("Committing track."); - track.commit(); - logger.trace("End committing track."); + if (totalPaidFees.compareTo(Coin.ZERO) > 0) { + if (remascEnabled) { + track.addBalance(PrecompiledContracts.REMASC_ADDR, totalPaidFees); + } else { + track.addBalance(block.getCoinbase(), totalPaidFees); + } } - logger.trace("Building execution results."); + saveOrCommitTrackState(saveState, track); + + List executedTransactions = parallelizeTransactionHandler.getTransactionsInOrder(); + short[] sublistOrder = parallelizeTransactionHandler.getTransactionsPerSublistInOrder(); + List receipts = getTransactionReceipts(receiptsByTx, executedTransactions); + BlockResult result = new BlockResult( block, executedTransactions, receipts, + sublistOrder, totalGasUsed, totalPaidFees, - vmTrace ? null : track.getTrie() + track.getTrie() ); profiler.stop(metric); - logger.trace("End executeInternal."); + logger.trace("End executeForMining."); return result; } - /** - * Precompiled contracts storage is setup like any other contract for consistency. Here, we apply this logic on the - * exact activation block. - * This method is called automatically for every block except for the Genesis (which makes an explicit call). - */ - public static void maintainPrecompiledContractStorageRoots(Repository track, ActivationConfig.ForBlock activations) { - if (activations.isActivating(RSKIP126)) { - for (RskAddress addr : PrecompiledContracts.GENESIS_ADDRESSES) { - if (!track.isExist(addr)) { - track.createAccount(addr); - } - track.setupContract(addr); - } + private void registerExecutedTx(ProgramTraceProcessor programTraceProcessor, boolean vmTrace, List executedTransactions, Transaction tx, TransactionExecutor txExecutor) { + executedTransactions.add(tx); + + if (this.registerProgramResults) { + this.transactionResults.put(tx.getHash(), txExecutor.getResult()); } - for (Map.Entry e : PrecompiledContracts.CONSENSUS_ENABLED_ADDRESSES.entrySet()) { - ConsensusRule contractActivationRule = e.getValue(); - if (activations.isActivating(contractActivationRule)) { - RskAddress addr = e.getKey(); - track.createAccount(addr); - track.setupContract(addr); - } + if (vmTrace) { + txExecutor.extractTrace(programTraceProcessor); } + + loggingTxExecuted(); } - @VisibleForTesting - public static byte[] calculateLogsBloom(List receipts) { - Bloom logBloom = new Bloom(); + private Coin addTotalPaidFees(Coin totalPaidFees, TransactionExecutor txExecutor) { + Coin paidFees = txExecutor.getPaidFees(); + if (paidFees != null) { + totalPaidFees = totalPaidFees.add(paidFees); + } + return totalPaidFees; + } - for (TransactionReceipt receipt : receipts) { - logBloom.or(receipt.getBloomFilter()); + private void registerTxExecutedForMiningAfterRSKIP144(IReadWrittenKeysTracker readWrittenKeysTracker, Transaction tx, TransactionExecutor txExecutor) { + readWrittenKeysTracker.clear(); + + if (this.registerProgramResults) { + this.transactionResults.put(tx.getHash(), txExecutor.getResult()); } - return logBloom.getData(); + loggingTxExecuted(); + } + + private List getTransactionReceipts(Map receiptsByTx, List executedTransactions) { + List receipts = new ArrayList<>(); + + for (Transaction tx : executedTransactions) { + receipts.add(receiptsByTx.get(tx)); + } + return receipts; + } + + private Optional addTxToSublistAndGetAccumulatedGas(IReadWrittenKeysTracker readWrittenKeysTracker, ParallelizeTransactionHandler parallelizeTransactionHandler, Transaction tx, boolean isRemascTransaction, long gasUsed, boolean isSequentialSublistRequired) { + Optional sublistGasAccumulated; + + if (isRemascTransaction) { + sublistGasAccumulated = parallelizeTransactionHandler.addRemascTransaction(tx, gasUsed); + } else if (isSequentialSublistRequired) { + sublistGasAccumulated = parallelizeTransactionHandler.addTxToSequentialSublist(tx, gasUsed); + } else { + sublistGasAccumulated = parallelizeTransactionHandler.addTransaction(tx, readWrittenKeysTracker.getThisThreadReadKeys(), readWrittenKeysTracker.getThisThreadWrittenKeys(), gasUsed); + } + return sublistGasAccumulated; + } + + private void saveOrCommitTrackState(boolean saveState, Repository track) { + logger.trace("End txs executions."); + if (saveState) { + logger.trace("Saving track."); + track.save(); + logger.trace("End saving track."); + } else { + logger.trace("Committing track."); + track.commit(); + logger.trace("End committing track."); + } + } + + private TransactionReceipt buildTransactionReceipt(Transaction tx, TransactionExecutor txExecutor, long gasUsed, long cumulativeGas) { + TransactionReceipt receipt = new TransactionReceipt(); + receipt.setGasUsed(gasUsed); + receipt.setTxStatus(txExecutor.getReceipt().isSuccessful()); + receipt.setTransaction(tx); + receipt.setLogInfoList(txExecutor.getVMLogs()); + receipt.setStatus(txExecutor.getReceipt().getStatus()); + receipt.setCumulativeGas(cumulativeGas); + return receipt; + } + + private BlockResult getBlockResultAndLogExecutionInterrupted(Block block, Metric metric, Transaction tx) { + logger.warn("block: [{}]/[{}] execution interrupted because of invalid tx: [{}]", + block.getNumber(), block.getHash(), tx.getHash()); + profiler.stop(metric); + return BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT; + } + + private void loggingTxExecuted() { + logger.trace("tx executed"); + } + + private void loggingTxDone() { + logger.trace("tx done"); + } + + private void loggingDiscardedBlock(Block block, Transaction tx) { + logger.warn("block: [{}] discarded tx: [{}]", block.getNumber(), tx.getHash()); + } + + private void loggingApplyBlock(Block block) { + logger.trace("applyBlock: block: [{}] tx.list: [{}]", block.getNumber(), block.getTransactionsList().size()); + } + + private void loggingApplyBlockToTx(Block block, int i) { + logger.trace("apply block: [{}] tx: [{}] ", block.getNumber(), i); + } + + private void loggingExecuteTxAndReceipt(Block block, int i, Transaction tx) { + logger.trace("block: [{}] executed tx: [{}]", block.getNumber(), tx.getHash()); + logger.trace("tx[{}].receipt", i); } public ProgramResult getProgramResult(Keccak256 txhash) { @@ -420,4 +843,53 @@ public void setRegisterProgramResults(boolean value) { this.registerProgramResults = value; this.transactionResults.clear(); } + + /** + * This implementation mimics a thread pool returned by {@link Executors#newCachedThreadPool()}, meaning that + * its core pool size is zero and maximum pool size is unbounded, while each thead created has keep-alive time - 15 mins. + */ + private static final class ThreadPoolExecutorImpl extends ThreadPoolExecutor { + private static final long KEEP_ALIVE_TIME_IN_SECS = 15*60L; /* 15 minutes */ + + public ThreadPoolExecutorImpl(int parallelListIndex) { + super(0, Integer.MAX_VALUE, + KEEP_ALIVE_TIME_IN_SECS, TimeUnit.SECONDS, + new SynchronousQueue<>(), new ThreadFactoryImpl(parallelListIndex)); + } + + @Override + protected void beforeExecute(Thread t, Runnable r) { + logger.debug("[{}]: before execution", t); + super.beforeExecute(t, r); + } + + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + if (t == null) { + logger.debug("[{}]: after execution", Thread.currentThread()); + } else { + logger.warn("[{}]: failed execution", Thread.currentThread(), t); + } + } + } + + /** + * A utility class that helps to specify a proper thread name in the form of `BlockExecutorWorker--`. + */ + private static final class ThreadFactoryImpl implements ThreadFactory { + private final AtomicInteger cnt = new AtomicInteger(0); + private final int parallelListIndex; + + ThreadFactoryImpl(int parallelListIndex) { + this.parallelListIndex = parallelListIndex; + } + + @Override + public Thread newThread(@Nonnull Runnable r) { + String threadName = "BlockExecutorWorker-" + parallelListIndex + "-" + cnt.getAndIncrement(); + logger.info("New block execution thread [{}] for parallel list [{}] has been created", threadName, parallelListIndex); + return new Thread(r, threadName); + } + } } diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockResult.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockResult.java index bb52ec2e364..b8f3468b9d3 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockResult.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockResult.java @@ -24,6 +24,7 @@ import org.ethereum.core.Transaction; import org.ethereum.core.TransactionReceipt; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -35,7 +36,7 @@ public class BlockResult { null, Collections.emptyList(), Collections.emptyList(), - 0, + new short[0], 0, Coin.ZERO, null ); @@ -49,11 +50,13 @@ public class BlockResult { // It is for optimizing switching between states. Instead of using the "stateRoot" field, // which requires regenerating the trie, using the finalState field does not. private final Trie finalState; + private final short[] txEdges; public BlockResult( Block block, List executedTransactions, List transactionReceipts, + short[] txEdges, long gasUsed, Coin paidFees, Trie finalState) { @@ -63,12 +66,14 @@ public BlockResult( this.gasUsed = gasUsed; this.paidFees = paidFees; this.finalState = finalState; + this.txEdges = txEdges != null? Arrays.copyOf(txEdges, txEdges.length) : null; } - public Block getBlock() { return block; } + public short[] getTxEdges() { return this.txEdges != null ? Arrays.copyOf(txEdges, txEdges.length) : null; } + public List getExecutedTransactions() { return executedTransactions; } public List getTransactionReceipts() { diff --git a/rskj-core/src/main/java/co/rsk/core/bc/BlockUtils.java b/rskj-core/src/main/java/co/rsk/core/bc/BlockUtils.java index afe66fd0a4e..f8a305799f2 100644 --- a/rskj-core/src/main/java/co/rsk/core/bc/BlockUtils.java +++ b/rskj-core/src/main/java/co/rsk/core/bc/BlockUtils.java @@ -20,10 +20,12 @@ import co.rsk.crypto.Keccak256; import co.rsk.net.NetBlockStore; +import org.ethereum.config.Constants; import org.ethereum.core.Block; import org.ethereum.core.BlockHeader; import org.ethereum.core.Blockchain; import org.ethereum.db.BlockInformation; +import org.ethereum.vm.GasCost; import java.util.*; import java.util.stream.Collectors; @@ -116,4 +118,77 @@ public static List sortBlocksByNumber(List blocks) { .collect(Collectors.toList()); } + /** + * Calculate the gas limit of a sublist, depending on the sublist type (sequential and parallel), from the block + * gas limit. The distribution can be performed one of two ways: + * + * 1. The block gas limit is divided equally among all sublists. If the division was not even (results in a decimal + * number) then the extra gas limit gets added to the sequential sublist. + * + * 2. The sequential sublist gets assigned a fixed value, determined by minSequentialSetGasLimit and additional + * gas limit is calculated by subtracting minSequentialSetGasLimit form block gas limit, the result is then divided + * by the amount of transaction execution threads. If the division for the parallel sublists was not even (results + * in a decimal number) then the extra gas limit gets added to the sequential sublist. + * + * + * @param block the block to get the gas limit from + * @param forSequentialTxSet a boolean the indicates if the gas limit beign calculated is for a sequential + * sublist or a paralle one. + * @param minSequentialSetGasLimit The minimum gas limit value the sequential sublist can have, configured by + * network in {@link Constants}. + * + * @return set of ancestors block hashes + */ + public static long getSublistGasLimit(Block block, boolean forSequentialTxSet, long minSequentialSetGasLimit) { + long blockGasLimit = GasCost.toGas(block.getGasLimit()); + int transactionExecutionThreadCount = Constants.getTransactionExecutionThreads(); + + /* + This if determines which distribution approach will be performed. If the result of multiplying the minSequentialSetGasLimit + by transactionExecutionThreadCount + 1 (where transactionExecutionThreadCount is the parallel sublist count and + the + 1 represents the sequential sublist) is less than the block gas limit then the equal division approach is performed, + otherwise the second approach, where the parallel sublists get less gas limit than the sequential sublist, is executed. + */ + if((transactionExecutionThreadCount + 1) * minSequentialSetGasLimit <= blockGasLimit) { + long parallelTxSetGasLimit = blockGasLimit / (transactionExecutionThreadCount + 1); + + if (forSequentialTxSet) { + /* + Subtract the total parallel sublist gas limit (parallelTxSetGasLimit) from the block gas limit to get + the sequential sublist gas limit + the possible extra gas limit and return it. + */ + return blockGasLimit - (transactionExecutionThreadCount * parallelTxSetGasLimit); + } + + return parallelTxSetGasLimit; + } else { + // Check if the block gas limit is less than the sequential gas limit. + if (blockGasLimit <= minSequentialSetGasLimit) { + /* + If this method execution is for a sequential sublist then return the total block gas limit. This will + skip the parallel sublist gas limit calculation since there will not be any gas limit left. + */ + if (forSequentialTxSet) { + return blockGasLimit; + } + + // If this method execution is NOT for a sequential sublist then return 0. + return 0; + } + + long additionalGasLimit = (blockGasLimit - minSequentialSetGasLimit); + long parallelTxSetGasLimit = additionalGasLimit / (transactionExecutionThreadCount); + + /* + If this method execution is for a sequential sublist then calculate the possible extra gas limit by subtracting + the total parallel sublist gas limit (parallelTxSetGasLimit) from additionalGasLimit and add the result to + minSequentialSetGasLimit + */ + if (forSequentialTxSet) { + long extraGasLimit = additionalGasLimit - (parallelTxSetGasLimit * transactionExecutionThreadCount); + return minSequentialSetGasLimit + extraGasLimit; + } + return parallelTxSetGasLimit; + } + } } diff --git a/rskj-core/src/main/java/co/rsk/core/bc/IReadWrittenKeysTracker.java b/rskj-core/src/main/java/co/rsk/core/bc/IReadWrittenKeysTracker.java new file mode 100644 index 00000000000..fdc29fef320 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/bc/IReadWrittenKeysTracker.java @@ -0,0 +1,42 @@ +/* + * This file is part of RskJ + * Copyright (C) 2019 RSK Labs Ltd. + * + * 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.core.bc; + +import org.ethereum.db.ByteArrayWrapper; + +import java.util.Map; +import java.util.Set; + +public interface IReadWrittenKeysTracker { + Set getThisThreadReadKeys(); + + Set getThisThreadWrittenKeys(); + + Map> getReadKeysByThread(); + + Map> getWrittenKeysByThread(); + + void addNewReadKey(ByteArrayWrapper key); + + void addNewWrittenKey(ByteArrayWrapper key); + + boolean detectCollision(); + + void clear(); +} diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ParallelizeTransactionHandler.java b/rskj-core/src/main/java/co/rsk/core/bc/ParallelizeTransactionHandler.java new file mode 100644 index 00000000000..814554f3e33 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/bc/ParallelizeTransactionHandler.java @@ -0,0 +1,290 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * 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.core.bc; + +import co.rsk.core.RskAddress; +import org.ethereum.core.Block; +import org.ethereum.core.Transaction; +import org.ethereum.db.ByteArrayWrapper; +import org.ethereum.vm.GasCost; + +import java.util.*; + +public class ParallelizeTransactionHandler { + private final HashMap sublistsHavingWrittenToKey; + private final HashMap> sublistsHavingReadFromKey; + private final Map sublistOfSender; + private final ArrayList sublists; + + public ParallelizeTransactionHandler(short numberOfSublists, Block block, long minSequentialSetGasLimit) { + this.sublistOfSender = new HashMap<>(); + this.sublistsHavingWrittenToKey = new HashMap<>(); + this.sublistsHavingReadFromKey = new HashMap<>(); + this.sublists = new ArrayList<>(); + for (short i = 0; i < numberOfSublists; i++){ + this.sublists.add(new TransactionSublist(BlockUtils.getSublistGasLimit(block, false, minSequentialSetGasLimit), false)); + } + this.sublists.add(new TransactionSublist(BlockUtils.getSublistGasLimit(block, true, minSequentialSetGasLimit), true)); + } + + public Optional addTransaction(Transaction tx, Set newReadKeys, Set newWrittenKeys, long gasUsedByTx) { + TransactionSublist sublistCandidate = getSublistCandidates(tx, newReadKeys, newWrittenKeys); + + if (sublistDoesNotHaveEnoughGas(tx, sublistCandidate)) { + if (sublistCandidate.isSequential()) { + return Optional.empty(); + } + sublistCandidate = getSequentialSublist(); + + if (sublistDoesNotHaveEnoughGas(tx, sublistCandidate)) { + return Optional.empty(); + } + } + + sublistCandidate.addTransaction(tx, gasUsedByTx); + addNewKeysToMaps(tx.getSender(), sublistCandidate, newReadKeys, newWrittenKeys); + return Optional.of(sublistCandidate.getGasUsed()); + } + + private boolean sublistDoesNotHaveEnoughGas(Transaction tx, TransactionSublist sublistCandidate) { + return !sublistCandidate.hasGasAvailable(GasCost.toGas(tx.getGasLimit())); + } + + public Optional addRemascTransaction(Transaction tx, long gasUsedByTx) { + TransactionSublist sequentialSublist = getSequentialSublist(); + sequentialSublist.addTransaction(tx, gasUsedByTx); + return Optional.of(sequentialSublist.getGasUsed()); + } + + // Unlike the smart contracts execution, Precompiled contracts persist the changes in the repository when they + // complete the execution. So, there is no way for the ParallelTransactionHandler to track the keys if the execution + // fails since the Precompiled contract rolls back the repository. + // Therefore, the tx is added to the sequential sublist to avoid possible race conditions. + public Optional addTxToSequentialSublist(Transaction tx, long gasUsedByTx) { + TransactionSublist sequentialSublist = getSequentialSublist(); + + if (sublistDoesNotHaveEnoughGas(tx, sequentialSublist)) { + return Optional.empty(); + } + + sequentialSublist.addTransaction(tx, gasUsedByTx); + addNewKeysToMaps(tx.getSender(), sequentialSublist, new HashSet<>(), new HashSet<>()); + + return Optional.of(sequentialSublist.getGasUsed()); + } + + public long getGasUsedIn(Short sublistId) { + + if (sublistId < 0 || sublistId >= sublists.size()) { + throw new NoSuchElementException(); + } + + return this.sublists.get(sublistId).getGasUsed(); + } + + public List getTransactionsInOrder() { + List txs = new ArrayList<>(); + for (TransactionSublist sublist: this.sublists) { + txs.addAll(sublist.getTransactions()); + } + return txs; + } + + public short[] getTransactionsPerSublistInOrder() { + List sublistSizes = new ArrayList<>(); + short sublistEdges = 0; + + for (TransactionSublist sublist: this.sublists) { + if (sublist.getTransactions().isEmpty() || sublist.isSequential()) { + continue; + } + sublistEdges += (short) sublist.getTransactions().size(); + sublistSizes.add(sublistEdges); + } + + short[] sublistOrder = new short[sublistSizes.size()]; + int i = 0; + for (Short size: sublistSizes) { + sublistOrder[i] = size; + i++; + } + + return sublistOrder; + } + + public long getGasUsedInSequential() { + return getSequentialSublist().getGasUsed(); + } + + private void addNewKeysToMaps(RskAddress sender, TransactionSublist sublist, Set newReadKeys, Set newWrittenKeys) { + for (ByteArrayWrapper key : newReadKeys) { + Set sublistsAlreadyRead = sublistsHavingReadFromKey.getOrDefault(key, new HashSet<>()); + sublistsAlreadyRead.add(sublist); + sublistsHavingReadFromKey.put(key, sublistsAlreadyRead); + } + + if (sublist.isSequential()) { + sublistOfSender.put(sender, sublist); + } else { + sublistOfSender.putIfAbsent(sender, sublist); + } + + for (ByteArrayWrapper key: newWrittenKeys) { + sublistsHavingWrittenToKey.put(key, sublist); + } + } + + private Optional getSublistBySender(Transaction tx) { + return Optional.ofNullable(sublistOfSender.get(tx.getSender())); + } + + private Optional getAvailableSublistWithLessUsedGas(long txGasLimit) { + long gasUsed = Long.MAX_VALUE; + Optional sublistCandidate = Optional.empty(); + + for (TransactionSublist sublist : sublists) { + if (!sublist.isSequential() && sublist.hasGasAvailable(txGasLimit) && sublist.getGasUsed() < gasUsed) { + sublistCandidate = Optional.of(sublist); + gasUsed = sublist.getGasUsed(); + } + } + + return sublistCandidate; + } + + private TransactionSublist getSublistCandidates(Transaction tx, Set newReadKeys, Set newWrittenKeys) { + Optional sublistCandidate = getSublistBySender(tx); + + if (sublistCandidate.isPresent() && sublistCandidate.get().isSequential()) { + // there is a tx with the same sender in the sequential sublist + return sublistCandidate.get(); + } + + // analyze reads + for (ByteArrayWrapper newReadKey : newReadKeys) { + // read - written + if (sublistsHavingWrittenToKey.containsKey(newReadKey)) { + TransactionSublist sublist = sublistsHavingWrittenToKey.get(newReadKey); + + if (sublist.isSequential()) { + // there is a tx with read-written collision in sequential sublist + return sublist; + } + if (!sublistCandidate.isPresent()) { + // this is the new candidate + sublistCandidate = Optional.of(sublist); + } else if (!sublistCandidate.get().equals(sublist)) { + // use the sequential sublist (greedy decision) + return getSequentialSublist(); + } + } + } + + // analyze writes + for (ByteArrayWrapper newWrittenKey : newWrittenKeys) { + // write - written + if (sublistsHavingWrittenToKey.containsKey(newWrittenKey)) { + TransactionSublist sublist = sublistsHavingWrittenToKey.get(newWrittenKey); + + if (sublist.isSequential()) { + // there is a tx with write-written collision in sequential sublist + return sublist; + } + if (!sublistCandidate.isPresent()) { + // this is the new candidate + sublistCandidate = Optional.of(sublist); + } else if (!sublistCandidate.get().equals(sublist)) { + // use the sequential sublist (greedy decision) + return getSequentialSublist(); + } + } + + // write - read + if (sublistsHavingReadFromKey.containsKey(newWrittenKey)) { + Set setOfsublists = sublistsHavingReadFromKey.get(newWrittenKey); + if (setOfsublists.size() > 1) { + // there is a write-read collision with multiple sublists + return getSequentialSublist(); + } + + // there is only one colluded sublist + TransactionSublist sublist = getNextSublist(setOfsublists); + if (!sublistCandidate.isPresent()) { + // if there is no candidate, take the colluded sublist + sublistCandidate = Optional.of(sublist); + } else if (!sublistCandidate.get().equals(sublist)) { + // otherwise, check if the sublist is different from the candidate and return the sequential + return getSequentialSublist(); + } + } + } + + // if there is no candidate use the sublist with more gas available + // if the is no more gas available in any parallel sublist use the sequential + return sublistCandidate + .orElseGet(() -> getAvailableSublistWithLessUsedGas(GasCost.toGas(tx.getGasLimit())) + .orElseGet(this::getSequentialSublist)); + } + + private TransactionSublist getNextSublist(Set sublist) { + return sublist.iterator().next(); + } + + private TransactionSublist getSequentialSublist() { + return this.sublists.get(this.sublists.size()-1); + } + + private static class TransactionSublist { + + private final long gasLimit; + private final boolean isSequential; + private final List transactions; + private long gasUsedInSublist; + + public TransactionSublist(long sublistGasLimit, boolean isSequential) { + this.gasLimit = sublistGasLimit; + this.isSequential = isSequential; + this.transactions = new ArrayList<>(); + this.gasUsedInSublist = 0; + } + + private void addTransaction(Transaction tx, long gasUsedByTx) { + transactions.add(tx); + gasUsedInSublist = gasUsedInSublist + gasUsedByTx; + } + + private boolean hasGasAvailable(long txGasLimit) { + //TODO(JULI): Re-check a thousand of times this line. + long cumulativeGas = GasCost.add(gasUsedInSublist, txGasLimit); + return cumulativeGas <= gasLimit; + } + + public long getGasUsed() { + return gasUsedInSublist; + } + + public List getTransactions() { + return new ArrayList<>(this.transactions); + } + + public boolean isSequential() { + return isSequential; + } + } +} diff --git a/rskj-core/src/main/java/co/rsk/core/bc/ReadWrittenKeysTracker.java b/rskj-core/src/main/java/co/rsk/core/bc/ReadWrittenKeysTracker.java new file mode 100644 index 00000000000..968465ba20d --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/bc/ReadWrittenKeysTracker.java @@ -0,0 +1,135 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * 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.core.bc; + +import org.ethereum.db.ByteArrayWrapper; + +import java.util.*; + +public class ReadWrittenKeysTracker implements IReadWrittenKeysTracker { + + private Map> readKeysByThread; + + private Map> writtenKeysByThread; + + + public ReadWrittenKeysTracker() { + this.readKeysByThread = new HashMap<>(); + this.writtenKeysByThread = new HashMap<>(); + } + + @Override + public Set getThisThreadReadKeys(){ + long threadId = Thread.currentThread().getId(); + if (this.readKeysByThread.containsKey(threadId)) { + return new HashSet<>(this.readKeysByThread.get(threadId)); + } else { + return new HashSet<>(); + } + } + + @Override + public Set getThisThreadWrittenKeys(){ + long threadId = Thread.currentThread().getId(); + if (this.writtenKeysByThread.containsKey(threadId)) { + return new HashSet<>(this.writtenKeysByThread.get(threadId)); + } else { + return new HashSet<>(); + } + } + + @Override + public Map> getReadKeysByThread() { + return new HashMap<>(this.readKeysByThread); + } + + @Override + public Map> getWrittenKeysByThread() { + return new HashMap<>(this.writtenKeysByThread); + } + + @Override + public synchronized void addNewReadKey(ByteArrayWrapper key) { + long threadId = Thread.currentThread().getId(); + addNewReadKeyToThread(threadId,key); + } + + public synchronized void addNewReadKeyToThread(long threadId,ByteArrayWrapper key) { + Set readKeys = readKeysByThread.containsKey(threadId)? readKeysByThread.get(threadId) : new HashSet<>(); + readKeys.add(key); + readKeysByThread.put(threadId, readKeys); + } + public synchronized void removeReadKeyToThread(long threadId,ByteArrayWrapper key) { + Set readKeys = readKeysByThread.containsKey(threadId)? readKeysByThread.get(threadId) : new HashSet<>(); + readKeys.remove(key); + readKeysByThread.put(threadId, readKeys); + } + + @Override + public synchronized void addNewWrittenKey(ByteArrayWrapper key) { + long threadId = Thread.currentThread().getId(); + addNewWrittenKeyToThread(threadId,key); + + } + public synchronized void removeWrittenKeyToThread(long threadId,ByteArrayWrapper key) { + Set writtenKeys = writtenKeysByThread.containsKey(threadId)? writtenKeysByThread.get(threadId) : new HashSet<>(); + writtenKeys.remove(key); + writtenKeysByThread.put(threadId, writtenKeys); + } + + public synchronized void addNewWrittenKeyToThread(long threadId,ByteArrayWrapper key) { + Set writtenKeys = writtenKeysByThread.containsKey(threadId)? writtenKeysByThread.get(threadId) : new HashSet<>(); + writtenKeys.add(key); + writtenKeysByThread.put(threadId, writtenKeys); + } + + @Override + public synchronized void clear() { + this.readKeysByThread = new HashMap<>(); + this.writtenKeysByThread = new HashMap<>(); + } + + public boolean detectCollision() { + Set threads = new HashSet<>(); + threads.addAll(readKeysByThread.keySet()); + threads.addAll(writtenKeysByThread.keySet()); + + for (Long threadId : threads) { + Set baseReadKeys = readKeysByThread.getOrDefault(threadId, new HashSet<>()); + Set baseWrittenKeys = writtenKeysByThread.getOrDefault(threadId, new HashSet<>()); + + for (Long threadId2 : threads) { + if (threadId >= threadId2) { + continue; + } + + Set temporalReadKeys = readKeysByThread.getOrDefault(threadId2, new HashSet<>()); + Set temporalWrittenKeys = writtenKeysByThread.getOrDefault(threadId2, new HashSet<>()); + + boolean isDisjoint = Collections.disjoint(baseWrittenKeys, temporalWrittenKeys) && Collections.disjoint(baseWrittenKeys, temporalReadKeys) + && Collections.disjoint(baseReadKeys, temporalWrittenKeys); + + if (!isDisjoint) { + return true; + } + } + } + return false; + } +} diff --git a/rskj-core/src/main/java/co/rsk/db/MutableTrieCache.java b/rskj-core/src/main/java/co/rsk/db/MutableTrieCache.java index 997b07defd2..64f8bc729e9 100644 --- a/rskj-core/src/main/java/co/rsk/db/MutableTrieCache.java +++ b/rskj-core/src/main/java/co/rsk/db/MutableTrieCache.java @@ -31,6 +31,7 @@ import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; public class MutableTrieCache implements MutableTrie { @@ -40,14 +41,14 @@ public class MutableTrieCache implements MutableTrie { private MutableTrie trie; // We use a single cache to mark both changed elements and removed elements. // null value means the element has been removed. - private final Map> cache; + private final Map>> cache; // this logs recursive delete operations to be performed at commit time private final Set deleteRecursiveLog; public MutableTrieCache(MutableTrie parentTrie) { trie = parentTrie; - cache = new HashMap<>(); + cache = new ConcurrentHashMap<>(); deleteRecursiveLog = new HashSet<>(); } @@ -75,7 +76,7 @@ private Optional internalGet( ByteArrayWrapper wrapper = new ByteArrayWrapper(key); ByteArrayWrapper accountWrapper = getAccountWrapper(wrapper); - Map accountItems = cache.get(accountWrapper); + Map> accountItems = cache.get(accountWrapper); boolean isDeletedAccount = deleteRecursiveLog.contains(accountWrapper); if (accountItems == null || !accountItems.containsKey(wrapper)) { if (isDeletedAccount) { @@ -85,14 +86,14 @@ private Optional internalGet( return Optional.ofNullable(trieRetriever.apply(key)); } - byte[] cacheItem = accountItems.get(wrapper); - if (cacheItem == null) { + Optional cacheItem = accountItems.get(wrapper); + if (!cacheItem.isPresent()) { // deleted account key return Optional.empty(); } // cached account key - return Optional.ofNullable(cacheTransformer.apply(cacheItem)); + return Optional.ofNullable(cacheTransformer.apply(cacheItem.get())); } public Iterator getStorageKeys(RskAddress addr) { @@ -100,7 +101,7 @@ public Iterator getStorageKeys(RskAddress addr) { ByteArrayWrapper accountWrapper = getAccountWrapper(new ByteArrayWrapper(accountStoragePrefixKey)); boolean isDeletedAccount = deleteRecursiveLog.contains(accountWrapper); - Map accountItems = cache.get(accountWrapper); + Map> accountItems = cache.get(accountWrapper); if (accountItems == null && isDeletedAccount) { return Collections.emptyIterator(); } @@ -139,8 +140,8 @@ public void put(ByteArrayWrapper wrapper, byte[] value) { // in cache with null or in deleteCache. Here we have the choice to // to add it to cache with null value or to deleteCache. ByteArrayWrapper accountWrapper = getAccountWrapper(wrapper); - Map accountMap = cache.computeIfAbsent(accountWrapper, k -> new HashMap<>()); - accountMap.put(wrapper, value); + Map> accountMap = cache.computeIfAbsent(accountWrapper, k -> new ConcurrentHashMap<>()); + accountMap.put(wrapper, Optional.ofNullable(value)); } @Override @@ -179,7 +180,7 @@ public void commit() { cache.forEach((accountKey, accountData) -> { if (accountData != null) { // cached account - accountData.forEach((realKey, value) -> this.trie.put(realKey, value)); + accountData.forEach((realKey, value) -> this.trie.put(realKey, value.orElse(null))); } }); @@ -242,7 +243,7 @@ public Optional getValueHash(byte[] key) { private static class StorageKeysIterator implements Iterator { private final Iterator keysIterator; - private final Map accountItems; + private final Map> accountItems; private final RskAddress address; private final int storageKeyOffset = ( TrieKeyMapper.domainPrefix().length + @@ -252,11 +253,11 @@ private static class StorageKeysIterator implements Iterator { * Byte.SIZE; private final TrieKeyMapper trieKeyMapper; private DataWord currentStorageKey; - private Iterator> accountIterator; + private Iterator>> accountIterator; StorageKeysIterator( Iterator keysIterator, - Map accountItems, + Map> accountItems, RskAddress addr, TrieKeyMapper trieKeyMapper) { this.keysIterator = keysIterator; @@ -275,8 +276,8 @@ public boolean hasNext() { DataWord item = keysIterator.next(); ByteArrayWrapper fullKey = getCompleteKey(item); if (accountItems.containsKey(fullKey)) { - byte[] value = accountItems.remove(fullKey); - if (value == null){ + Optional value = accountItems.remove(fullKey); + if (!value.isPresent()){ continue; } } @@ -289,9 +290,9 @@ public boolean hasNext() { } while (accountIterator.hasNext()) { - Map.Entry entry = accountIterator.next(); + Map.Entry> entry = accountIterator.next(); byte[] key = entry.getKey().getData(); - if (entry.getValue() != null && key.length * Byte.SIZE > storageKeyOffset) { + if (entry.getValue().isPresent() && key.length * Byte.SIZE > storageKeyOffset) { // cached account key currentStorageKey = getPartialKey(key); return true; diff --git a/rskj-core/src/main/java/co/rsk/db/RepositoryLocator.java b/rskj-core/src/main/java/co/rsk/db/RepositoryLocator.java index 3a3eef66fec..7d328039bc5 100644 --- a/rskj-core/src/main/java/co/rsk/db/RepositoryLocator.java +++ b/rskj-core/src/main/java/co/rsk/db/RepositoryLocator.java @@ -18,6 +18,7 @@ package co.rsk.db; +import co.rsk.core.bc.IReadWrittenKeysTracker; import co.rsk.crypto.Keccak256; import co.rsk.trie.MutableTrie; import co.rsk.trie.Trie; @@ -77,6 +78,13 @@ public Repository startTrackingAt(BlockHeader header) { .orElseThrow(() -> trieNotFoundException(header)); } + public Repository startTrackingAt(BlockHeader header, IReadWrittenKeysTracker tracker) { + return mutableTrieSnapshotAt(header) + .map(MutableTrieCache::new) + .map(mutableTrieCache -> new MutableRepository(mutableTrieCache, tracker)) + .orElseThrow(() -> trieNotFoundException(header)); + } + private IllegalArgumentException trieNotFoundException(BlockHeader header) { return new IllegalArgumentException(String.format( "The trie with root %s is missing in this store", header.getHash() diff --git a/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java b/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java index 42b895dd20c..dfa07fed3a0 100644 --- a/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java +++ b/rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java @@ -249,6 +249,7 @@ private BlockHeader createHeader( .setMinimumGasPrice(minimumGasPrice) .setUncleCount(uncles.size()) .setUmmRoot(ummRoot) + .setCreateParallelCompliantHeader(activationConfig.isActive(ConsensusRule.RSKIP144, blockNumber)) .build(); newHeader.setDifficulty(difficultyCalculator.calcDifficulty(newHeader, newBlockParentHeader)); diff --git a/rskj-core/src/main/java/co/rsk/net/NodeBlockProcessor.java b/rskj-core/src/main/java/co/rsk/net/NodeBlockProcessor.java index 2e2a303dc6c..1a3a7b52afc 100644 --- a/rskj-core/src/main/java/co/rsk/net/NodeBlockProcessor.java +++ b/rskj-core/src/main/java/co/rsk/net/NodeBlockProcessor.java @@ -227,7 +227,7 @@ public void processBodyRequest(@Nonnull final Peer sender, long requestId, @Nonn return; } - Message responseMessage = new BodyResponseMessage(requestId, block.getTransactionsList(), block.getUncleList()); + Message responseMessage = new BodyResponseMessage(requestId, block.getTransactionsList(), block.getUncleList(), block.getHeader().getExtension()); sender.sendMessage(responseMessage); } 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 24416ac005f..54b81c17b5a 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,11 +18,13 @@ package co.rsk.net.handler; import co.rsk.core.Coin; +import co.rsk.core.bc.BlockUtils; import co.rsk.net.TransactionValidationResult; import co.rsk.net.handler.txvalidator.*; 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.AccountState; import org.ethereum.core.Block; import org.ethereum.core.SignatureCache; @@ -69,10 +71,14 @@ public TxPendingValidator(Constants constants, ActivationConfig activationConfig } public TransactionValidationResult isValid(Transaction tx, Block executionBlock, @Nullable AccountState state) { - BigInteger blockGasLimit = BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit()); + long executionBlockNumber = executionBlock.getNumber(); + ActivationConfig.ForBlock activations = activationConfig.forBlock(executionBlockNumber); + BigInteger gasLimit = activations.isActive(ConsensusRule.RSKIP144) + ? BigInteger.valueOf(Math.max(BlockUtils.getSublistGasLimit(executionBlock, true, constants.getMinSequentialSetGasLimit()), BlockUtils.getSublistGasLimit(executionBlock, false, constants.getMinSequentialSetGasLimit()))) + : BigIntegers.fromUnsignedByteArray(executionBlock.getGasLimit()); Coin minimumGasPrice = executionBlock.getMinimumGasPrice(); long bestBlockNumber = executionBlock.getNumber(); - long basicTxCost = tx.transactionCost(constants, activationConfig.forBlock(bestBlockNumber), signatureCache); + long basicTxCost = tx.transactionCost(constants, activations, signatureCache); if (state == null && basicTxCost != 0) { if (logger.isTraceEnabled()) { @@ -81,7 +87,7 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock, return TransactionValidationResult.withError("the sender account doesn't exist"); } - if(tx.isInitCodeSizeInvalidForTx(activationConfig.forBlock(bestBlockNumber))) { + if (tx.isInitCodeSizeInvalidForTx(activationConfig.forBlock(bestBlockNumber))) { return TransactionValidationResult.withError("transaction's init code size is invalid"); } @@ -90,7 +96,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, state, gasLimit, minimumGasPrice, executionBlockNumber, 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/messages/BlockHeadersResponseMessage.java b/rskj-core/src/main/java/co/rsk/net/messages/BlockHeadersResponseMessage.java index ada7749f442..d38324cb303 100644 --- a/rskj-core/src/main/java/co/rsk/net/messages/BlockHeadersResponseMessage.java +++ b/rskj-core/src/main/java/co/rsk/net/messages/BlockHeadersResponseMessage.java @@ -32,7 +32,7 @@ public BlockHeadersResponseMessage(long id, List headers) { @Override protected byte[] getEncodedMessageWithoutId() { byte[][] rlpHeaders = this.blockHeaders.stream() - .map(BlockHeader::getFullEncoded) + .map(BlockHeader::getEncodedCompressed) .toArray(byte[][]::new); return RLP.encodeList(RLP.encodeList(rlpHeaders)); diff --git a/rskj-core/src/main/java/co/rsk/net/messages/BodyResponseMessage.java b/rskj-core/src/main/java/co/rsk/net/messages/BodyResponseMessage.java index 41c73c76de7..b857f262fc9 100644 --- a/rskj-core/src/main/java/co/rsk/net/messages/BodyResponseMessage.java +++ b/rskj-core/src/main/java/co/rsk/net/messages/BodyResponseMessage.java @@ -1,6 +1,8 @@ package co.rsk.net.messages; +import com.google.common.collect.Lists; import org.ethereum.core.BlockHeader; +import org.ethereum.core.BlockHeaderExtension; import org.ethereum.core.Transaction; import org.ethereum.util.RLP; @@ -10,14 +12,16 @@ * Created by ajlopez on 25/08/2017. */ public class BodyResponseMessage extends MessageWithId { - private long id; - private List transactions; - private List uncles; + private final long id; + private final List transactions; + private final List uncles; + private final BlockHeaderExtension blockHeaderExtension; - public BodyResponseMessage(long id, List transactions, List uncles) { + public BodyResponseMessage(long id, List transactions, List uncles, BlockHeaderExtension blockHeaderExtension) { this.id = id; this.transactions = transactions; this.uncles = uncles; + this.blockHeaderExtension = blockHeaderExtension; } @Override @@ -26,6 +30,7 @@ public BodyResponseMessage(long id, List transactions, List getTransactions() { return this.transactions; } public List getUncles() { return this.uncles; } + public BlockHeaderExtension getBlockHeaderExtension() { return this.blockHeaderExtension; } @Override protected byte[] getEncodedMessageWithoutId() { @@ -40,7 +45,13 @@ protected byte[] getEncodedMessageWithoutId() { rlpUncles[k] = this.uncles.get(k).getFullEncoded(); } - return RLP.encodeList(RLP.encodeList(rlpTransactions), RLP.encodeList(rlpUncles)); + List elements = Lists.newArrayList(RLP.encodeList(rlpTransactions), RLP.encodeList(rlpUncles)); + + if (this.blockHeaderExtension != null) { + elements.add(BlockHeaderExtension.toEncoded(blockHeaderExtension)); + } + + return RLP.encodeList(elements.toArray(new byte[][]{})); } @Override diff --git a/rskj-core/src/main/java/co/rsk/net/messages/MessageType.java b/rskj-core/src/main/java/co/rsk/net/messages/MessageType.java index a7e9ad21fb5..27db4c7e83e 100644 --- a/rskj-core/src/main/java/co/rsk/net/messages/MessageType.java +++ b/rskj-core/src/main/java/co/rsk/net/messages/MessageType.java @@ -143,7 +143,7 @@ public Message createMessage(BlockFactory blockFactory, RLPList list) { for (int k = 0; k < rlpHeaders.size(); k++) { RLPElement element = rlpHeaders.get(k); - BlockHeader header = blockFactory.decodeHeader(element.getRLPData()); + BlockHeader header = blockFactory.decodeHeader(element.getRLPData(), true); headers.add(header); } @@ -229,10 +229,14 @@ public Message createMessage(BlockFactory blockFactory, RLPList list) { for (int j = 0; j < rlpUncles.size(); j++) { RLPElement element = rlpUncles.get(j); - uncles.add(blockFactory.decodeHeader(element.getRLPData())); + uncles.add(blockFactory.decodeHeader(element.getRLPData(), false)); } - return new BodyResponseMessage(id, transactions, uncles); + BlockHeaderExtension blockHeaderExtension = message.size() == 3 + ? BlockHeaderExtension.fromEncoded(message.get(2).getRLPData()) + : null; + + return new BodyResponseMessage(id, transactions, uncles, blockHeaderExtension); } }, SKELETON_REQUEST_MESSAGE(16) { diff --git a/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncState.java b/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncState.java index e3a663c4939..e59da6fcaac 100644 --- a/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncState.java +++ b/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncState.java @@ -94,6 +94,7 @@ public void newBody(BodyResponseMessage body, Peer peer) { return; } + requestedHeader.setExtension(body.getBlockHeaderExtension()); Block block = blockFactory.newBlock(requestedHeader, body.getTransactions(), body.getUncles()); block.seal(); diff --git a/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBodiesSyncState.java b/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBodiesSyncState.java index dc1eedf0dd4..1eb1d3e1255 100644 --- a/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBodiesSyncState.java +++ b/rskj-core/src/main/java/co/rsk/net/sync/DownloadingBodiesSyncState.java @@ -116,6 +116,7 @@ public void newBody(BodyResponseMessage message, Peer peer) { // we already checked that this message was expected BlockHeader header = pendingBodyResponses.remove(requestId).header; + header.setExtension(message.getBlockHeaderExtension()); Block block; try { block = blockFactory.newBlock(header, message.getTransactions(), message.getUncles()); diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeMethods.java b/rskj-core/src/main/java/co/rsk/peg/BridgeMethods.java index 2fbdb688a55..80458a14139 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeMethods.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeMethods.java @@ -19,6 +19,7 @@ import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*; +import java.math.BigInteger; import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -31,7 +32,11 @@ import org.ethereum.vm.MessageCall.MsgType; /** - * This enum holds the basic information of the Bridge contract methods: the ABI, the cost and the implementation. + * Represents the methods of the Bridge contract, encapsulating details such as + * the Application Binary Interface (ABI), execution costs, and method implementations. + * + * Each enum constant corresponds to a specific method of the Bridge contract, + * defining its signature and providing the necessary information for execution. */ public enum BridgeMethods { ADD_FEDERATOR_PUBLIC_KEY( @@ -41,7 +46,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(13000L), - (BridgeMethodExecutorTyped) Bridge::addFederatorPublicKey, + (BridgeMethodExecutorTyped) Bridge::addFederatorPublicKey, activations -> !activations.isActive(RSKIP123), fixedPermission(false) ), @@ -52,7 +57,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(13000L), - (BridgeMethodExecutorTyped) Bridge::addFederatorPublicKeyMultikey, + (BridgeMethodExecutorTyped) Bridge::addFederatorPublicKeyMultikey, activations -> activations.isActive(RSKIP123), fixedPermission(false) ), @@ -63,7 +68,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(25000L), - (BridgeMethodExecutorTyped) Bridge::addOneOffLockWhitelistAddress, + (BridgeMethodExecutorTyped) Bridge::addOneOffLockWhitelistAddress, activations -> !activations.isActive(RSKIP87), fixedPermission(false) ), @@ -74,7 +79,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(25000L), // using same gas estimation as ADD_LOCK_WHITELIST_ADDRESS - (BridgeMethodExecutorTyped) Bridge::addOneOffLockWhitelistAddress, + (BridgeMethodExecutorTyped) Bridge::addOneOffLockWhitelistAddress, activations -> activations.isActive(RSKIP87), fixedPermission(false) ), @@ -85,7 +90,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(25000L), // using same gas estimation as ADD_LOCK_WHITELIST_ADDRESS - (BridgeMethodExecutorTyped) Bridge::addUnlimitedLockWhitelistAddress, + (BridgeMethodExecutorTyped) Bridge::addUnlimitedLockWhitelistAddress, activations -> activations.isActive(RSKIP87), fixedPermission(false) ), @@ -106,7 +111,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(38000L), - (BridgeMethodExecutorTyped) Bridge::commitFederation, + (BridgeMethodExecutorTyped) Bridge::commitFederation, fixedPermission(false) ), CREATE_FEDERATION( @@ -116,7 +121,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(11000L), - (BridgeMethodExecutorTyped) Bridge::createFederation, + (BridgeMethodExecutorTyped) Bridge::createFederation, fixedPermission(false) ), GET_BTC_BLOCKCHAIN_BEST_CHAIN_HEIGHT( @@ -126,7 +131,7 @@ public enum BridgeMethods { new String[]{"int"} ), fixedCost(19000L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBestChainHeight, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBestChainHeight, fromMethod(Bridge::getBtcBlockchainBestChainHeightOnlyAllowsLocalCalls), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -137,7 +142,7 @@ public enum BridgeMethods { new String[]{"int"} ), fixedCost(20000L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainInitialBlockHeight, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainInitialBlockHeight, activations -> activations.isActive(RSKIP89), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -149,7 +154,7 @@ public enum BridgeMethods { new String[]{"string[]"} ), fixedCost(76000L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockLocator, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockLocator, activations -> !activations.isActive(RSKIP89), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -161,7 +166,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(20000L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockHashAtDepth, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockHashAtDepth, activations -> activations.isActive(RSKIP89), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -173,7 +178,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fromMethod(Bridge::getBtcTransactionConfirmationsGetCost), - (BridgeMethodExecutorTyped) Bridge::getBtcTransactionConfirmations, + (BridgeMethodExecutorTyped) Bridge::getBtcTransactionConfirmations, activations -> activations.isActive(RSKIP122), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -185,7 +190,7 @@ public enum BridgeMethods { new String[]{"int64"} ), fixedCost(22000L), - (BridgeMethodExecutorTyped) Bridge::getBtcTxHashProcessedHeight, + (BridgeMethodExecutorTyped) Bridge::getBtcTxHashProcessedHeight, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -196,7 +201,7 @@ public enum BridgeMethods { new String[]{"string"} ), fixedCost(11000L), - (BridgeMethodExecutorTyped) Bridge::getFederationAddress, + (BridgeMethodExecutorTyped) Bridge::getFederationAddress, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -207,7 +212,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(10000L), - (BridgeMethodExecutorTyped) Bridge::getFederationCreationBlockNumber, + (BridgeMethodExecutorTyped) Bridge::getFederationCreationBlockNumber, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -218,7 +223,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(10000L), - (BridgeMethodExecutorTyped) Bridge::getFederationCreationTime, + (BridgeMethodExecutorTyped) Bridge::getFederationCreationTime, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -229,7 +234,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(10000L), - (BridgeMethodExecutorTyped) Bridge::getFederationSize, + (BridgeMethodExecutorTyped) Bridge::getFederationSize, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -240,7 +245,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(11000L), - (BridgeMethodExecutorTyped) Bridge::getFederationThreshold, + (BridgeMethodExecutorTyped) Bridge::getFederationThreshold, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -251,7 +256,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(10000L), - (BridgeMethodExecutorTyped) Bridge::getFederatorPublicKey, + (BridgeMethodExecutorTyped) Bridge::getFederatorPublicKey, activations -> !activations.isActive(RSKIP123), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -263,7 +268,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(10000L), - (BridgeMethodExecutorTyped) Bridge::getFederatorPublicKeyOfType, + (BridgeMethodExecutorTyped) Bridge::getFederatorPublicKeyOfType, activations -> activations.isActive(RSKIP123), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -275,7 +280,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(2000L), - (BridgeMethodExecutorTyped) Bridge::getFeePerKb, + (BridgeMethodExecutorTyped) Bridge::getFeePerKb, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -286,7 +291,7 @@ public enum BridgeMethods { new String[]{"string"} ), fixedCost(16000L), - (BridgeMethodExecutorTyped) Bridge::getLockWhitelistAddress, + (BridgeMethodExecutorTyped) Bridge::getLockWhitelistAddress, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -297,7 +302,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(16000L), - (BridgeMethodExecutorTyped) Bridge::getLockWhitelistEntryByAddress, + (BridgeMethodExecutorTyped) Bridge::getLockWhitelistEntryByAddress, activations -> activations.isActive(RSKIP87), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -309,7 +314,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(16000L), - (BridgeMethodExecutorTyped) Bridge::getLockWhitelistSize, + (BridgeMethodExecutorTyped) Bridge::getLockWhitelistSize, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -320,7 +325,7 @@ public enum BridgeMethods { new String[]{"int"} ), fixedCost(2000L), - (BridgeMethodExecutorTyped) Bridge::getMinimumLockTxValue, + (BridgeMethodExecutorTyped) Bridge::getMinimumLockTxValue, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -331,7 +336,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getPendingFederationHashSerialized, + (BridgeMethodExecutorTyped) Bridge::getPendingFederationHashSerialized, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -342,7 +347,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getPendingFederationSize, + (BridgeMethodExecutorTyped) Bridge::getPendingFederationSize, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -353,7 +358,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getPendingFederatorPublicKey, + (BridgeMethodExecutorTyped) Bridge::getPendingFederatorPublicKey, activations -> !activations.isActive(RSKIP123), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -365,7 +370,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getPendingFederatorPublicKeyOfType, + (BridgeMethodExecutorTyped) Bridge::getPendingFederatorPublicKeyOfType, activations -> activations.isActive(RSKIP123), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -377,7 +382,7 @@ public enum BridgeMethods { new String[]{"string"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederationAddress, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederationAddress, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -388,7 +393,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederationCreationBlockNumber, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederationCreationBlockNumber, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -399,7 +404,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederationCreationTime, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederationCreationTime, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -410,7 +415,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederationSize, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederationSize, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -421,7 +426,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederationThreshold, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederationThreshold, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -432,7 +437,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederatorPublicKey, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederatorPublicKey, activations -> !activations.isActive(RSKIP123), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -444,7 +449,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3000L), - (BridgeMethodExecutorTyped) Bridge::getRetiringFederatorPublicKeyOfType, + (BridgeMethodExecutorTyped) Bridge::getRetiringFederatorPublicKeyOfType, activations -> activations.isActive(RSKIP123), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -456,7 +461,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(4000L), - (BridgeMethodExecutorTyped) Bridge::getStateForBtcReleaseClient, + (BridgeMethodExecutorTyped) Bridge::getStateForBtcReleaseClient, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -467,7 +472,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3_000_000L), - (BridgeMethodExecutorTyped) Bridge::getStateForDebugging, + (BridgeMethodExecutorTyped) Bridge::getStateForDebugging, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -478,7 +483,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(3_000L), - (BridgeMethodExecutorTyped) Bridge::getLockingCap, + (BridgeMethodExecutorTyped) Bridge::getLockingCap, activations -> activations.isActive(RSKIP134), fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL @@ -490,7 +495,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(30_000L), - (BridgeMethodExecutorTyped) Bridge::getActivePowpegRedeemScript, + (BridgeMethodExecutorTyped) Bridge::getActivePowpegRedeemScript, activations -> activations.isActive(RSKIP293), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -502,7 +507,7 @@ public enum BridgeMethods { new String[]{"uint256"} ), fixedCost(3_000L), - (BridgeMethodExecutorTyped) Bridge::getActiveFederationCreationBlockHeight, + (BridgeMethodExecutorTyped) Bridge::getActiveFederationCreationBlockHeight, activations -> activations.isActive(RSKIP186), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -514,7 +519,7 @@ public enum BridgeMethods { new String[]{"bool"} ), fixedCost(8_000L), - (BridgeMethodExecutorTyped) Bridge::increaseLockingCap, + (BridgeMethodExecutorTyped) Bridge::increaseLockingCap, activations -> activations.isActive(RSKIP134), fixedPermission(false) ), @@ -525,7 +530,7 @@ public enum BridgeMethods { new String[]{"bool"} ), fixedCost(23000L), - (BridgeMethodExecutorTyped) Bridge::isBtcTxHashAlreadyProcessed, + (BridgeMethodExecutorTyped) Bridge::isBtcTxHashAlreadyProcessed, fixedPermission(true), CallTypeHelper.ALLOW_STATIC_CALL ), @@ -550,7 +555,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(10_600L), - (BridgeMethodExecutorTyped) Bridge::receiveHeader, + (BridgeMethodExecutorTyped) Bridge::receiveHeader, activations -> activations.isActive(RSKIP200), fixedPermission(false) ), @@ -585,7 +590,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(24000L), - (BridgeMethodExecutorTyped) Bridge::removeLockWhitelistAddress, + (BridgeMethodExecutorTyped) Bridge::removeLockWhitelistAddress, fixedPermission(false) ), ROLLBACK_FEDERATION( @@ -595,7 +600,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(12000L), - (BridgeMethodExecutorTyped) Bridge::rollbackFederation, + (BridgeMethodExecutorTyped) Bridge::rollbackFederation, fixedPermission(false) ), SET_LOCK_WHITELIST_DISABLE_BLOCK_DELAY( @@ -605,7 +610,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(24000L), - (BridgeMethodExecutorTyped) Bridge::setLockWhitelistDisableBlockDelay, + (BridgeMethodExecutorTyped) Bridge::setLockWhitelistDisableBlockDelay, fixedPermission(false) ), UPDATE_COLLECTIONS( @@ -625,7 +630,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(10000L), - (BridgeMethodExecutorTyped) Bridge::voteFeePerKbChange, + (BridgeMethodExecutorTyped) Bridge::voteFeePerKbChange, fixedPermission(false) ), REGISTER_BTC_COINBASE_TRANSACTION( @@ -646,7 +651,7 @@ public enum BridgeMethods { new String[]{"bool"} ), fixedCost(5000L), - (BridgeMethodExecutorTyped) Bridge::hasBtcBlockCoinbaseTransactionInformation, + (BridgeMethodExecutorTyped) Bridge::hasBtcBlockCoinbaseTransactionInformation, activations -> activations.isActive(RSKIP143), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -658,7 +663,7 @@ public enum BridgeMethods { new String[]{"int256"} ), fixedCost(25_000L), - (BridgeMethodExecutorTyped) Bridge::registerFlyoverBtcTransaction, + (BridgeMethodExecutorTyped) Bridge::registerFlyoverBtcTransaction, activations -> activations.isActive(RSKIP176), fixedPermission(false) ), @@ -669,7 +674,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(3_800L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBestBlockHeader, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBestBlockHeader, activations -> activations.isActive(RSKIP220), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -681,7 +686,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(4_600L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockHeaderByHash, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockHeaderByHash, activations -> activations.isActive(RSKIP220), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -693,7 +698,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(5_000L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockHeaderByHeight, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainBlockHeaderByHeight, activations -> activations.isActive(RSKIP220), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -705,7 +710,7 @@ public enum BridgeMethods { new String[]{"bytes"} ), fixedCost(4_900L), - (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainParentBlockHeaderByHash, + (BridgeMethodExecutorTyped) Bridge::getBtcBlockchainParentBlockHeaderByHash, activations -> activations.isActive(RSKIP220), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -717,7 +722,7 @@ public enum BridgeMethods { new String[]{"uint256"} ), fixedCost(3_000L), - (BridgeMethodExecutorTyped) Bridge::getNextPegoutCreationBlockNumber, + (BridgeMethodExecutorTyped) Bridge::getNextPegoutCreationBlockNumber, activations -> activations.isActive(RSKIP271), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -729,7 +734,7 @@ public enum BridgeMethods { new String[]{"uint256"} ), fixedCost(3_000L), - (BridgeMethodExecutorTyped) Bridge::getQueuedPegoutsCount, + (BridgeMethodExecutorTyped) Bridge::getQueuedPegoutsCount, activations -> activations.isActive(RSKIP271), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -741,7 +746,7 @@ public enum BridgeMethods { new String[]{"uint256"} ), fixedCost(10_000L), - (BridgeMethodExecutorTyped) Bridge::getEstimatedFeesForNextPegOutEvent, + (BridgeMethodExecutorTyped) Bridge::getEstimatedFeesForNextPegOutEvent, activations -> activations.isActive(RSKIP271), fixedPermission(false), CallTypeHelper.ALLOW_STATIC_CALL @@ -858,10 +863,33 @@ public interface BridgeCondition { boolean isTrue(Bridge bridge); } + /** + * Interface for executing methods in the Bridge context. + * + *

+ * This interface defines a single method, {@code execute}, which takes a + * {@link Bridge} instance and an array of arguments, returning an + * {@code Optional} result. Implementations of this interface should handle + * the execution logic and manage potential exceptions. + *

+ */ public interface BridgeMethodExecutor { Optional execute(Bridge self, Object[] args) throws Exception; } + /** + * A typed variant of {@link BridgeMethodExecutor} that allows for specific + * return types. + * + *

+ * This interface extends {@code BridgeMethodExecutor} and provides a default + * implementation of the {@code execute} method, delegating the call to a typed + * execution method {@code executeTyped}. Implementations must define this + * method to specify the expected return type. + *

+ * + * @param the return type of the executed method + */ private interface BridgeMethodExecutorTyped extends BridgeMethodExecutor { @Override default Optional execute(Bridge self, Object[] args) throws Exception { @@ -871,6 +899,16 @@ default Optional execute(Bridge self, Object[] args) throws Exception { T executeTyped(Bridge self, Object[] args) throws Exception; } + /** + * A variant of {@link BridgeMethodExecutor} for void methods. + * + *

+ * This interface overrides the {@code execute} method to perform an action + * without returning a result. Implementations should define the + * {@code executeVoid} method, which executes the intended action using the + * provided {@link Bridge} instance and arguments. + *

+ */ private interface BridgeMethodExecutorVoid extends BridgeMethodExecutor { @Override default Optional execute(Bridge self, Object[] args) throws Exception { diff --git a/rskj-core/src/main/java/co/rsk/rpc/Web3InformationRetriever.java b/rskj-core/src/main/java/co/rsk/rpc/Web3InformationRetriever.java index 40af9360099..0f8dc1f69cb 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/Web3InformationRetriever.java +++ b/rskj-core/src/main/java/co/rsk/rpc/Web3InformationRetriever.java @@ -21,19 +21,22 @@ import co.rsk.core.bc.AccountInformationProvider; import co.rsk.db.RepositoryLocator; import co.rsk.util.HexUtils; +import co.rsk.util.StringUtils; import org.bouncycastle.util.encoders.DecoderException; import org.ethereum.core.Block; import org.ethereum.core.Blockchain; import org.ethereum.core.Transaction; import org.ethereum.core.TransactionPool; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.HashParam32; +import org.ethereum.rpc.parameters.HexNumberParam; import java.util.List; import java.util.Optional; -import static co.rsk.crypto.Keccak256.HASH_LEN; import static org.ethereum.rpc.exception.RskJsonRpcRequestException.blockNotFound; import static org.ethereum.rpc.exception.RskJsonRpcRequestException.invalidParamError; +import static org.ethereum.rpc.parameters.HashParam32.HASH_BYTE_LENGTH; /** * Retrieves information requested by web3 based on the block identifier: @@ -84,10 +87,18 @@ public Optional getBlock(String identifier) { block = blockchain.getBlockByNumber(0); break; default: - byte[] hash = getBlockHash(identifier); - block = hash.length == HASH_LEN ? - blockchain.getBlockByHash(hash) - : blockchain.getBlockByNumber(getBlockNumber(identifier)); + if (HashParam32.isHash32HexLengthValid(identifier) + && HexUtils.isHex(identifier, HexUtils.hasHexPrefix(identifier) ? 2 : 0)) { + byte[] hash = getBlockHash(identifier); + if (hash.length != HASH_BYTE_LENGTH) { + throw invalidParamError(String.format("invalid block hash %s", identifier)); + } + block = blockchain.getBlockByHash(hash); + } else if (HexNumberParam.isHexNumberLengthValid(identifier)) { + block = blockchain.getBlockByNumber(getBlockNumber(identifier)); + } else { + throw invalidParamError(String.format("invalid block identifier %s", StringUtils.trim(identifier))); + } } return Optional.ofNullable(block); diff --git a/rskj-core/src/main/java/co/rsk/util/HexUtils.java b/rskj-core/src/main/java/co/rsk/util/HexUtils.java index f04aae64aef..55bcef88128 100644 --- a/rskj-core/src/main/java/co/rsk/util/HexUtils.java +++ b/rskj-core/src/main/java/co/rsk/util/HexUtils.java @@ -361,15 +361,4 @@ public static int jsonHexToInt(final String param) { return Integer.parseInt(preResult, 16); } - - public static int jsonHexToIntOptionalPrefix(final String param) { - if (!hasHexPrefix(param) && !HexUtils.isHex(param)) { - throw invalidParamError(INCORRECT_HEX_SYNTAX); - } - - String preResult = removeHexPrefix(param); - - return Integer.parseInt(preResult, 16); - } - } diff --git a/rskj-core/src/main/java/co/rsk/util/StringUtils.java b/rskj-core/src/main/java/co/rsk/util/StringUtils.java index 02ef4106555..73ff8c56c65 100644 --- a/rskj-core/src/main/java/co/rsk/util/StringUtils.java +++ b/rskj-core/src/main/java/co/rsk/util/StringUtils.java @@ -22,7 +22,7 @@ public class StringUtils { - private static final int DEFAULT_MAX_LEN = 64; + private static final int DEFAULT_MAX_LEN = 66; // 0x + 32 bytes, where each byte is represented by 2 hex characters private StringUtils() { /* hidden */ } diff --git a/rskj-core/src/main/java/co/rsk/validators/ValidTxExecutionSublistsEdgesRule.java b/rskj-core/src/main/java/co/rsk/validators/ValidTxExecutionSublistsEdgesRule.java new file mode 100644 index 00000000000..63e6cbb3e43 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/validators/ValidTxExecutionSublistsEdgesRule.java @@ -0,0 +1,64 @@ +package co.rsk.validators; + +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.Block; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + Validates that: + - There are no more defined transaction subsets than the max number of execution threads + - All the edges are within the range of the list of transactions + - The edges do not define any empty subset + - The edges are in ascending order + */ +public class ValidTxExecutionSublistsEdgesRule implements BlockValidationRule { + + private static final Logger logger = LoggerFactory.getLogger("blockvalidator"); + private final ActivationConfig activationConfig; + + public ValidTxExecutionSublistsEdgesRule(ActivationConfig activationConfig) { + this.activationConfig = activationConfig; + } + + + @Override + public boolean isValid(Block block) { + if (!activationConfig.isActive(ConsensusRule.RSKIP144, block.getHeader().getNumber())) { + return true; + } + + short[] edges = block.getHeader().getTxExecutionSublistsEdges(); + + if (edges.length == 0) { + return true; + } + + if (edges.length > Constants.getTransactionExecutionThreads()) { + logger.warn("Invalid block: number of execution lists edges is greater than number of execution threads ({} vs {})", + edges.length, Constants.getTransactionExecutionThreads()); + return false; + } + + if (edges[0] <= 0) { + logger.warn("Invalid block: execution list edge is out of bounds"); + return false; + } + + for (int i = 0; i < edges.length - 1; i++) { + if (edges[i] >= edges[i + 1]) { + logger.warn("Invalid block: execution lists edges are not in ascending order"); + return false; + } + } + + if (edges[edges.length-1] > block.getTransactionsList().size() - 1) { + logger.warn("Invalid block: execution list edge is out of bounds"); + return false; + } + + return true; + } +} 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 433bad156fa..92dea9f5171 100644 --- a/rskj-core/src/main/java/org/ethereum/config/Constants.java +++ b/rskj-core/src/main/java/org/ethereum/config/Constants.java @@ -50,6 +50,7 @@ public class Constants { private static final long TESTNET_MAX_TIMESTAMPS_DIFF_IN_SECS = 120L * 60; // 120 mins private static final long MAX_CONTRACT_SIZE = 0x6000; private static final long MAX_INITCODE_SIZE = 2 * MAX_CONTRACT_SIZE; + public static final int TX_EXECUTION_THREADS = 2; private final byte chainId; private final boolean seedCowAccounts; @@ -61,6 +62,7 @@ public class Constants { private final int newBlockMaxSecondsInTheFuture; public final BridgeConstants bridgeConstants; private final ActivationConfig activationConfig; + private final long minSequentialSetGasLimit; public Constants( byte chainId, @@ -72,7 +74,8 @@ public Constants( int newBlockMaxSecondsInTheFuture, BridgeConstants bridgeConstants, ActivationConfig activationConfig, - BlockDifficulty minimumDifficultyForRskip290) { + BlockDifficulty minimumDifficultyForRskip290, + long minSequentialSetGasLimit) { this.chainId = chainId; this.seedCowAccounts = seedCowAccounts; this.durationLimit = durationLimit; @@ -83,6 +86,7 @@ public Constants( this.bridgeConstants = bridgeConstants; this.activationConfig = activationConfig; this.minimumDifficultyForRskip290 = minimumDifficultyForRskip290; + this.minSequentialSetGasLimit = minSequentialSetGasLimit; } public Constants( @@ -94,7 +98,8 @@ public Constants( BigInteger difficultyBoundDivisor, int newBlockMaxSecondsInTheFuture, BridgeConstants bridgeConstants, - BlockDifficulty minimumDifficultyForRskip290) { + BlockDifficulty minimumDifficultyForRskip290, + long minSequentialSetGasLimit) { this(chainId, seedCowAccounts, durationLimit, @@ -104,7 +109,8 @@ public Constants( newBlockMaxSecondsInTheFuture, bridgeConstants, null, - minimumDifficultyForRskip290 + minimumDifficultyForRskip290, + minSequentialSetGasLimit ); } @@ -231,6 +237,12 @@ public static int getMaxBitcoinMergedMiningMerkleProofLength() { return 960; } + public static int getTransactionExecutionThreads() { return TX_EXECUTION_THREADS; } + + public long getMinSequentialSetGasLimit() { + return minSequentialSetGasLimit; + } + public static Constants mainnet() { return new Constants( MAINNET_CHAIN_ID, @@ -241,7 +253,8 @@ public static Constants mainnet() { BigInteger.valueOf(50), 60, BridgeMainNetConstants.getInstance(), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + 6_800_000L ); } @@ -255,7 +268,8 @@ public static Constants devnetWithFederation() { BigInteger.valueOf(50), 540, new BridgeDevNetConstants(), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + 6_800_000L ); } @@ -270,7 +284,8 @@ public static Constants testnet(ActivationConfig activationConfig) { 540, BridgeTestNetConstants.getInstance(), activationConfig, - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + 6_800_000L ); } @@ -284,7 +299,8 @@ public static Constants regtest() { BigInteger.valueOf(2048), 0, new BridgeRegTestConstants(), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + 1_000_000L ); } @@ -298,7 +314,8 @@ public static Constants regtestWithFederation(List genesisFederationPu BigInteger.valueOf(2048), 0, new BridgeRegTestConstants(genesisFederationPublicKeys), - new BlockDifficulty(new BigInteger("550000000")) + new BlockDifficulty(new BigInteger("550000000")), + 1_000_000L ); } } diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ActivationConfig.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ActivationConfig.java index a0641854f13..429c1b0a90c 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ActivationConfig.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ActivationConfig.java @@ -44,6 +44,14 @@ public ActivationConfig(Map activationHeights) { this.activationHeights = activationHeights; } + public byte getHeaderVersion(long blockNumber) { + if (this.isActive(ConsensusRule.RSKIP351, blockNumber)) { + return 0x1; + } + + return 0x0; + } + public boolean isActive(ConsensusRule consensusRule, long blockNumber) { long activationHeight = activationHeights.get(consensusRule); return 0 <= activationHeight && activationHeight <= blockNumber; 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 d9f306d0951..7a6b4d3a663 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 @@ -78,6 +78,8 @@ public enum ConsensusRule { RSKIP293("rskip293"), // Flyover improvements RSKIP294("rskip294"), RSKIP297("rskip297"), // Increase max timestamp difference between btc and rsk blocks for Testnet + RSKIP351("rskip351"), // block header extension v1 + RSKIP144("rskip144"), // Parallel tx execution RSKIP326("rskip326"), // release_request_received event update to use base58 for btcDestinationAddress RSKIP353("rskip353"), RSKIP357("rskip357"), diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockFactory.java b/rskj-core/src/main/java/org/ethereum/core/BlockFactory.java index f6e6ae3eb5e..cd58a3d7f28 100644 --- a/rskj-core/src/main/java/org/ethereum/core/BlockFactory.java +++ b/rskj-core/src/main/java/org/ethereum/core/BlockFactory.java @@ -26,6 +26,7 @@ import org.bouncycastle.util.BigIntegers; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; import org.ethereum.util.RLPElement; import org.ethereum.util.RLPList; @@ -38,8 +39,8 @@ import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; public class BlockFactory { - private static final int RLP_HEADER_SIZE = 17; - private static final int RLP_HEADER_SIZE_WITH_MERGED_MINING = 20; + private static final int RLP_HEADER_SIZE = 19; + private static final int RLP_HEADER_SIZE_WITH_MERGED_MINING = 22; private final ActivationConfig activationConfig; @@ -66,7 +67,7 @@ private Block decodeBlock(byte[] rawData, boolean sealed) { } RLPList rlpHeader = (RLPList) block.get(0); - BlockHeader header = decodeHeader(rlpHeader, sealed); + BlockHeader header = decodeHeader(rlpHeader, false, sealed); List transactionList = parseTxs((RLPList) block.get(1)); @@ -76,7 +77,7 @@ private Block decodeBlock(byte[] rawData, boolean sealed) { for (int k = 0; k < uncleHeadersRlp.size(); k++) { RLPElement element = uncleHeadersRlp.get(k); - BlockHeader uncleHeader = decodeHeader((RLPList)element, sealed); + BlockHeader uncleHeader = decodeHeader((RLPList)element, false, sealed); uncleList.add(uncleHeader); } @@ -92,11 +93,11 @@ public Block newBlock(BlockHeader header, List transactionList, Lis return new Block(header, transactionList, uncleList, isRskip126Enabled, sealed); } - public BlockHeader decodeHeader(byte[] encoded) { - return decodeHeader(RLP.decodeList(encoded), true); + public BlockHeader decodeHeader(byte[] encoded, boolean compressed) { + return decodeHeader(RLP.decodeList(encoded), compressed, true); } - private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) { + private BlockHeader decodeHeader(RLPList rlpHeader, boolean compressed, boolean sealed) { byte[] parentHash = rlpHeader.get(0).getRLPData(); byte[] unclesHash = rlpHeader.get(1).getRLPData(); byte[] coinBaseBytes = rlpHeader.get(2).getRLPData(); @@ -116,7 +117,7 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) { receiptTrieRoot = EMPTY_TRIE_HASH; } - byte[] logsBloom = rlpHeader.get(6).getRLPData(); + byte[] extensionData = rlpHeader.get(6).getRLPData(); // rskip351: logs bloom when decoding extended, list(version, hash(extension)) when compressed byte[] difficultyBytes = rlpHeader.get(7).getRLPData(); BlockDifficulty difficulty = RLP.parseBlockDifficulty(difficultyBytes); @@ -136,30 +137,36 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) { byte[] minimumGasPriceBytes = rlpHeader.get(14).getRLPData(); Coin minimumGasPrice = RLP.parseSignedCoinNonNullZero(minimumGasPriceBytes); - if (!canBeDecoded(rlpHeader, blockNumber)) { + if (!canBeDecoded(rlpHeader, blockNumber, compressed)) { throw new IllegalArgumentException(String.format( - "A block header must have 16/17 elements or 19/20 including merged-mining fields but it had %d", + "Invalid block header size: %d", rlpHeader.size() )); } int r = 15; - boolean isUmm = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber); + byte[] ucBytes = rlpHeader.get(r++).getRLPData(); + int uncleCount = parseBigInteger(ucBytes).intValueExact(); - boolean includeUncleCount = isUmm || - // sizes prior to UMM activation - rlpHeader.size() == (RLP_HEADER_SIZE-1) || rlpHeader.size() == (RLP_HEADER_SIZE_WITH_MERGED_MINING-1); + byte[] ummRoot = null; + if (activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber)) { + ummRoot = rlpHeader.get(r++).getRLPRawData(); + } - int uncleCount = 0; - if (includeUncleCount) { - byte[] ucBytes = rlpHeader.get(r++).getRLPData(); - uncleCount = parseBigInteger(ucBytes).intValueExact(); + byte version = 0x0; + + if (activationConfig.isActive(ConsensusRule.RSKIP351, blockNumber)) { + version = compressed + ? RLP.decodeList(extensionData).get(0).getRLPData()[0] + : rlpHeader.get(r++).getRLPData()[0]; } - byte[] ummRoot = null; - if (isUmm) { - ummRoot = rlpHeader.get(r++).getRLPRawData(); + short[] txExecutionSublistsEdges = null; + + if ((!activationConfig.isActive(ConsensusRule.RSKIP351, blockNumber) || !compressed) && + (rlpHeader.size() > r && activationConfig.isActive(ConsensusRule.RSKIP144, blockNumber))) { + txExecutionSublistsEdges = ByteUtil.rlpToShorts(rlpHeader.get(r++).getRLPRawData()); } byte[] bitcoinMergedMiningHeader = null; @@ -175,11 +182,25 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) { boolean includeForkDetectionData = activationConfig.isActive(ConsensusRule.RSKIP110, blockNumber) && blockNumber >= MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION; + return createBlockHeader(compressed, sealed, parentHash, unclesHash, + coinBaseBytes, coinbase, stateRoot, txTrieRoot, receiptTrieRoot, extensionData, + difficultyBytes, difficulty, glBytes, blockNumber, gasUsed, timestamp, extraData, + paidFees, minimumGasPriceBytes, minimumGasPrice, uncleCount, ummRoot, version, txExecutionSublistsEdges, + bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, bitcoinMergedMiningCoinbaseTransaction, + useRskip92Encoding, includeForkDetectionData); + } + + private BlockHeader createBlockHeader(boolean compressed, boolean sealed, byte[] parentHash, byte[] unclesHash, + byte[] coinBaseBytes, RskAddress coinbase, byte[] stateRoot, byte[] txTrieRoot, byte[] receiptTrieRoot, byte[] extensionData, + byte[] difficultyBytes, BlockDifficulty difficulty, byte[] glBytes, long blockNumber, long gasUsed, long timestamp, byte[] extraData, + Coin paidFees, byte[] minimumGasPriceBytes, Coin minimumGasPrice, int uncleCount, byte[] ummRoot, byte version, short[] txExecutionSublistsEdges, + byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, byte[] bitcoinMergedMiningCoinbaseTransaction, + boolean useRskip92Encoding, boolean includeForkDetectionData) { if (blockNumber == Genesis.NUMBER) { return new GenesisHeader( parentHash, unclesHash, - logsBloom, + extensionData, difficultyBytes, blockNumber, glBytes, @@ -195,22 +216,50 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) { stateRoot); } - return new BlockHeader( + if (version == 1) { + return new BlockHeaderV1( + parentHash, unclesHash, coinbase, stateRoot, + txTrieRoot, receiptTrieRoot, extensionData, difficulty, + blockNumber, glBytes, gasUsed, timestamp, extraData, + paidFees, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, + bitcoinMergedMiningCoinbaseTransaction, new byte[0], + minimumGasPrice, uncleCount, sealed, useRskip92Encoding, includeForkDetectionData, + ummRoot, txExecutionSublistsEdges, compressed + ); + } + + return new BlockHeaderV0( parentHash, unclesHash, coinbase, stateRoot, - txTrieRoot, receiptTrieRoot, logsBloom, difficulty, + txTrieRoot, receiptTrieRoot, extensionData, difficulty, blockNumber, glBytes, gasUsed, timestamp, extraData, paidFees, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, bitcoinMergedMiningCoinbaseTransaction, new byte[0], minimumGasPrice, uncleCount, sealed, useRskip92Encoding, includeForkDetectionData, - ummRoot + ummRoot, txExecutionSublistsEdges ); } - private boolean canBeDecoded(RLPList rlpHeader, long blockNumber) { + private boolean canBeDecoded(RLPList rlpHeader, long blockNumber, boolean compressed) { int preUmmHeaderSizeAdjustment = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber) ? 0 : 1; + int preParallelSizeAdjustment = activationConfig.isActive(ConsensusRule.RSKIP144, blockNumber) ? 0 : 1; + int preRSKIP351SizeAdjustment = getRSKIP351SizeAdjustment(blockNumber, compressed, preParallelSizeAdjustment); + + int expectedSize = RLP_HEADER_SIZE - preUmmHeaderSizeAdjustment - preParallelSizeAdjustment - preRSKIP351SizeAdjustment; + int expectedSizeMM = RLP_HEADER_SIZE_WITH_MERGED_MINING - preUmmHeaderSizeAdjustment - preParallelSizeAdjustment - preRSKIP351SizeAdjustment; + + return rlpHeader.size() == expectedSize || rlpHeader.size() == expectedSizeMM; + } + + private int getRSKIP351SizeAdjustment(long blockNumber, boolean compressed, int preParallelSizeAdjustment) { + if (!activationConfig.isActive(ConsensusRule.RSKIP351, blockNumber)) { + return 1; // remove version + } + + if (compressed) { + return 2 - preParallelSizeAdjustment; // remove version and edges if existent + } - return rlpHeader.size() == (RLP_HEADER_SIZE - preUmmHeaderSizeAdjustment) || - rlpHeader.size() == (RLP_HEADER_SIZE_WITH_MERGED_MINING - preUmmHeaderSizeAdjustment); + return 0; } private static BigInteger parseBigInteger(byte[] bytes) { diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockHeader.java b/rskj-core/src/main/java/org/ethereum/core/BlockHeader.java index 7bbf0c7434a..dd3b4c69361 100644 --- a/rskj-core/src/main/java/org/ethereum/core/BlockHeader.java +++ b/rskj-core/src/main/java/org/ethereum/core/BlockHeader.java @@ -27,6 +27,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import org.ethereum.crypto.HashUtil; +import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; import org.ethereum.util.Utils; @@ -43,7 +44,19 @@ * Block header is a value object containing * the basic information of a block */ -public class BlockHeader { +public abstract class BlockHeader { + /* RSKIP 351 */ + public abstract byte getVersion(); + public abstract BlockHeaderExtension getExtension(); + + // fields from block header extension + public abstract byte[] getLogsBloom(); + public abstract void setLogsBloom(byte[] logsBloom); + public abstract short[] getTxExecutionSublistsEdges(); // Edges of the transaction execution lists + public abstract void setTxExecutionSublistsEdges(short[] edges); + + // called after encoding the header, used to add elements at the end + public abstract void addExtraFieldsToEncodedHeader(boolean usingCompressedEncoding, List fieldsToEncode); private static final int HASH_FOR_MERGED_MINING_PREFIX_LENGTH = 20; private static final int FORK_DETECTION_DATA_LENGTH = 12; @@ -69,8 +82,6 @@ public class BlockHeader { * list portion, the trie is populate by [key, val] --> [rlp(index), rlp(tx_recipe)] * of the block */ private byte[] receiptTrieRoot; - /* The bloom filter for the logs of the block */ - private byte[] logsBloom; /** * A scalar value corresponding to the difficulty level of this block. * This can be calculated from the previous block’s difficulty level @@ -105,6 +116,8 @@ public class BlockHeader { private final byte[] ummRoot; + protected byte[] extensionData; + /** * The mgp for a tx to be included in the block. */ @@ -112,10 +125,10 @@ public class BlockHeader { private final int uncleCount; /* Indicates if this block header cannot be changed */ - private volatile boolean sealed; + protected volatile boolean sealed; /* Holds calculated block hash */ - private Keccak256 hash; + protected Keccak256 hash; /* Indicates if the block was mined according to RSKIP-92 rules */ private final boolean useRskip92Encoding; @@ -123,8 +136,8 @@ public class BlockHeader { /* Indicates if Block hash for merged mining should have the format described in RSKIP-110 */ private final boolean includeForkDetectionData; - public BlockHeader(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, byte[] stateRoot, - byte[] txTrieRoot, byte[] receiptTrieRoot, byte[] logsBloom, BlockDifficulty difficulty, + protected BlockHeader(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, byte[] stateRoot, + byte[] txTrieRoot, byte[] receiptTrieRoot, byte[] extensionData, BlockDifficulty difficulty, long number, byte[] gasLimit, long gasUsed, long timestamp, byte[] extraData, Coin paidFees, byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] mergedMiningForkDetectionData, @@ -135,8 +148,8 @@ public BlockHeader(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, by this.coinbase = coinbase; this.stateRoot = stateRoot; this.txTrieRoot = txTrieRoot; + this.extensionData = extensionData; this.receiptTrieRoot = receiptTrieRoot; - this.logsBloom = logsBloom; this.difficulty = difficulty; this.number = number; this.gasLimit = gasLimit; @@ -157,6 +170,11 @@ public BlockHeader(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, by this.ummRoot = ummRoot != null ? Arrays.copyOf(ummRoot, ummRoot.length) : null; } + public abstract void setExtension(BlockHeaderExtension extension); + + // contains the logs bloom or the hash of the extension depending on version + public byte[] getExtensionData() { return this.extensionData; } + @VisibleForTesting public boolean isSealed() { return this.sealed; @@ -228,11 +246,6 @@ public void setTransactionsRoot(byte[] stateRoot) { this.txTrieRoot = stateRoot; } - - public byte[] getLogsBloom() { - return logsBloom; - } - public BlockDifficulty getDifficulty() { // some blocks have zero encoded as null, but if we altered the internal field then re-encoding the value would // give a different value than the original. @@ -297,41 +310,36 @@ public byte[] getExtraData() { return extraData; } - public void setLogsBloom(byte[] logsBloom) { - /* A sealed block header is immutable, cannot be changed */ - if (this.sealed) { - throw new SealedBlockHeaderException("trying to alter logs bloom"); - } - this.hash = null; - - this.logsBloom = logsBloom; - } - public Keccak256 getHash() { if (this.hash == null) { - this.hash = new Keccak256(HashUtil.keccak256(getEncoded())); + this.hash = new Keccak256(HashUtil.keccak256(getEncodedForHash())); } return this.hash; } - public byte[] getFullEncoded() { - // the encoded block header must include all fields, even the bitcoin PMT and coinbase which are not used for - // calculating RSKIP92 block hashes - return this.getEncoded(true, true); - } - public byte[] getEncoded() { - // the encoded block header used for calculating block hashes including RSKIP92 - return this.getEncoded(true, !useRskip92Encoding); - } + // the encoded block header must include all fields, even the bitcoin PMT and coinbase which are not used for + // calculating RSKIP92 block hashes + public byte[] getFullEncoded() { return this.getEncoded(true, true); } + // the encoded block header used for calculating block hashes including RSKIP92 + public byte[] getEncoded() { return this.getEncoded(true, !useRskip92Encoding); } + public byte[] getEncodedCompressed() { return this.getEncoded(true, true, true); } + public byte[] getEncodedForHash() { return this.getEncoded(true, !useRskip92Encoding, true); } @Nullable public Coin getMinimumGasPrice() { return this.minimumGasPrice; } + /** + * note: being also used by powpeg + */ public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProofAndCoinbase) { + return this.getEncoded(withMergedMiningFields, withMerkleProofAndCoinbase, false); + } + + public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProofAndCoinbase, boolean compressed) { byte[] parentHash = RLP.encodeElement(this.parentHash); byte[] unclesHash = RLP.encodeElement(this.unclesHash); @@ -351,7 +359,7 @@ public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProof byte[] receiptTrieRoot = RLP.encodeElement(this.receiptTrieRoot); - byte[] logsBloom = RLP.encodeElement(this.logsBloom); + byte[] logsBloomField = RLP.encodeElement(compressed ? this.getExtensionData() : this.getLogsBloom()); byte[] difficulty = encodeBlockDifficulty(this.difficulty); byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number)); byte[] gasLimit = RLP.encodeElement(this.gasLimit); @@ -361,7 +369,7 @@ public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProof byte[] paidFees = RLP.encodeCoin(this.paidFees); byte[] mgp = RLP.encodeSignedCoinNonNullZero(this.minimumGasPrice); List fieldToEncodeList = Lists.newArrayList(parentHash, unclesHash, coinbase, - stateRoot, txTrieRoot, receiptTrieRoot, logsBloom, difficulty, number, + stateRoot, txTrieRoot, receiptTrieRoot, logsBloomField, difficulty, number, gasLimit, gasUsed, timestamp, extraData, paidFees, mgp); byte[] uncleCount = RLP.encodeBigInteger(BigInteger.valueOf(this.uncleCount)); @@ -371,6 +379,8 @@ public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProof fieldToEncodeList.add(RLP.encodeElement(this.ummRoot)); } + this.addExtraFieldsToEncodedHeader(compressed, fieldToEncodeList); + if (withMergedMiningFields && hasMiningFields()) { byte[] bitcoinMergedMiningHeader = RLP.encodeElement(this.bitcoinMergedMiningHeader); fieldToEncodeList.add(bitcoinMergedMiningHeader); @@ -381,10 +391,16 @@ public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProof fieldToEncodeList.add(bitcoinMergedMiningCoinbaseTransaction); } } - return RLP.encodeList(fieldToEncodeList.toArray(new byte[][]{})); } + public void addTxExecutionSublistsEdgesIfAny(List fieldsToEncode) { + short[] txExecutionSublistsEdges = this.getTxExecutionSublistsEdges(); + if (txExecutionSublistsEdges != null) { + fieldsToEncode.add(ByteUtil.shortsToRLP(txExecutionSublistsEdges)); + } + } + /** * This is here to override specific non-minimal instances such as the mainnet Genesis */ @@ -448,6 +464,7 @@ private String toStringWithSuffix(final String suffix) { toStringBuff.append(" timestamp=").append(timestamp).append(" (").append(Utils.longToDateTime(timestamp)).append(")").append(suffix); toStringBuff.append(" extraData=").append(toHexStringOrEmpty(extraData)).append(suffix); toStringBuff.append(" minGasPrice=").append(minimumGasPrice).append(suffix); + toStringBuff.append(" txExecutionSublistsEdges=").append(Arrays.toString(this.getTxExecutionSublistsEdges())).append(suffix); return toStringBuff.toString(); } @@ -594,7 +611,7 @@ public byte[] getMiningForkDetectionData() { * @return The computed hash for merged mining */ private byte[] getBaseHashForMergedMining() { - byte[] encodedBlock = getEncoded(false, false); + byte[] encodedBlock = getEncoded(false, false, true); byte[] hashForMergedMining = HashUtil.keccak256(encodedBlock); if (isUMMBlock()) { diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockHeaderBuilder.java b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderBuilder.java index ac62a6a600f..61aeb871d05 100644 --- a/rskj-core/src/main/java/org/ethereum/core/BlockHeaderBuilder.java +++ b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderBuilder.java @@ -57,6 +57,7 @@ public class BlockHeaderBuilder { private byte[] bitcoinMergedMiningCoinbaseTransaction; private byte[] mergedMiningForkDetectionData; private byte[] ummRoot; + private short[] txExecutionSublistsEdges; private Coin minimumGasPrice; private int uncleCount; @@ -68,11 +69,13 @@ public class BlockHeaderBuilder { private boolean createConsensusCompliantHeader; private boolean createUmmCompliantHeader; + private boolean createParallelCompliantHeader; public BlockHeaderBuilder(ActivationConfig activationConfig) { this.activationConfig = activationConfig; createConsensusCompliantHeader = true; createUmmCompliantHeader = true; + createParallelCompliantHeader = true; } public BlockHeaderBuilder setCreateConsensusCompliantHeader(boolean createConsensusCompliantHeader) { @@ -85,6 +88,15 @@ public BlockHeaderBuilder setCreateUmmCompliantHeader(boolean createUmmCompliant return this; } + public BlockHeaderBuilder setCreateParallelCompliantHeader(boolean createParallelCompliantHeader) { + this.createParallelCompliantHeader = createParallelCompliantHeader; + + if (!createParallelCompliantHeader) { + this.txExecutionSublistsEdges = null; + } + return this; + } + public BlockHeaderBuilder setStateRoot(byte[] stateRoot) { this.stateRoot = copy(stateRoot); return this; @@ -252,6 +264,18 @@ public BlockHeaderBuilder setUmmRoot(byte[] ummRoot) { return this; } + public BlockHeaderBuilder setTxExecutionSublistsEdges(short[] edges) { + if (edges != null) { + this.txExecutionSublistsEdges = new short[edges.length]; + System.arraycopy(edges, 0, this.txExecutionSublistsEdges, 0, edges.length); + this.createParallelCompliantHeader = true; + } else { + this.txExecutionSublistsEdges = null; + this.createParallelCompliantHeader = false; + } + return this; + } + private void initializeWithDefaultValues() { extraData = normalizeValue(extraData, new byte[0]); bitcoinMergedMiningHeader = normalizeValue(bitcoinMergedMiningHeader, new byte[0]); @@ -309,7 +333,27 @@ public BlockHeader build() { } } - return new BlockHeader( + if (activationConfig.isActive(ConsensusRule.RSKIP144, number) && createParallelCompliantHeader && txExecutionSublistsEdges == null) { + txExecutionSublistsEdges = new short[0]; + } + + if (activationConfig.getHeaderVersion(number) == 0x1) { + return new BlockHeaderV1( + parentHash, unclesHash, coinbase, + stateRoot, txTrieRoot, receiptTrieRoot, + logsBloom, difficulty, number, + gasLimit, gasUsed, timestamp, extraData, paidFees, + bitcoinMergedMiningHeader, + bitcoinMergedMiningMerkleProof, + bitcoinMergedMiningCoinbaseTransaction, + mergedMiningForkDetectionData, + minimumGasPrice, uncleCount, + false, useRskip92Encoding, + includeForkDetectionData, ummRoot, txExecutionSublistsEdges, false + ); + } + + return new BlockHeaderV0( parentHash, unclesHash, coinbase, stateRoot, txTrieRoot, receiptTrieRoot, logsBloom, difficulty, number, @@ -320,7 +364,7 @@ public BlockHeader build() { mergedMiningForkDetectionData, minimumGasPrice, uncleCount, false, useRskip92Encoding, - includeForkDetectionData, ummRoot + includeForkDetectionData, ummRoot, txExecutionSublistsEdges ); } } \ No newline at end of file diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockHeaderExtension.java b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderExtension.java new file mode 100644 index 00000000000..b087e4f4afb --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderExtension.java @@ -0,0 +1,31 @@ +package org.ethereum.core; + +import org.ethereum.util.RLP; +import org.ethereum.util.RLPList; + +import java.util.Objects; + +public interface BlockHeaderExtension { + byte[] getEncoded(); + byte[] getHash(); + + static byte[] toEncoded(BlockHeaderExtension extension) { + if (!(Objects.requireNonNull(extension) instanceof BlockHeaderExtensionV1)) { + throw new IllegalArgumentException("Unknown extension"); + } + return RLP.encodeList( + RLP.encodeByte((byte) 0x1), + RLP.encodeElement(extension.getEncoded()) + ); + } + + static BlockHeaderExtension fromEncoded(byte[] encoded) { + RLPList rlpList = RLP.decodeList(encoded); + byte[] versionData = rlpList.get(0).getRLPData(); + byte version = versionData == null || versionData.length == 0 ? 0 : versionData[0]; + if (version == 0x1) { + return BlockHeaderExtensionV1.fromEncoded(rlpList.get(1).getRLPData()); + } + throw new IllegalArgumentException("Unknown extension with version: " + version); + } +} diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockHeaderExtensionV1.java b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderExtensionV1.java new file mode 100644 index 00000000000..6f0a0ce2ad2 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderExtensionV1.java @@ -0,0 +1,58 @@ +package org.ethereum.core; + +import com.google.common.collect.Lists; +import org.ethereum.crypto.HashUtil; +import org.ethereum.util.ByteUtil; +import org.ethereum.util.RLP; +import org.ethereum.util.RLPList; + +import java.util.Arrays; +import java.util.List; + +public class BlockHeaderExtensionV1 implements BlockHeaderExtension { + private byte[] logsBloom; + private short[] txExecutionSublistsEdges; + + public BlockHeaderExtensionV1(byte[] logsBloom, short[] edges) { + this.logsBloom = logsBloom; + this.txExecutionSublistsEdges = edges != null ? Arrays.copyOf(edges, edges.length) : null; + } + + @Override + public byte[] getHash() { + return HashUtil.keccak256(this.getEncodedForHash()); + } + + @Override + public byte[] getEncoded() { + List fieldToEncodeList = Lists.newArrayList(RLP.encodeElement(this.getLogsBloom())); + this.addEdgesEncoded(fieldToEncodeList); + return RLP.encodeList(fieldToEncodeList.toArray(new byte[][]{})); + } + public byte[] getLogsBloom() { return this.logsBloom; } + public void setLogsBloom(byte[] logsBloom) { this.logsBloom = logsBloom; } + + public short[] getTxExecutionSublistsEdges() { return this.txExecutionSublistsEdges != null ? Arrays.copyOf(this.txExecutionSublistsEdges, this.txExecutionSublistsEdges.length) : null; } + public void setTxExecutionSublistsEdges(short[] edges) { this.txExecutionSublistsEdges = edges != null? Arrays.copyOf(edges, edges.length) : null; } + + public static BlockHeaderExtensionV1 fromEncoded(byte[] encoded) { + RLPList rlpExtension = RLP.decodeList(encoded); + return new BlockHeaderExtensionV1( + rlpExtension.get(0).getRLPData(), + rlpExtension.size() == 2 ? ByteUtil.rlpToShorts(rlpExtension.get(1).getRLPRawData()): null + ); + } + + private void addEdgesEncoded(List fieldToEncodeList) { + short[] internalExecutionSublistsEdges = this.getTxExecutionSublistsEdges(); + if (internalExecutionSublistsEdges != null) { + fieldToEncodeList.add(ByteUtil.shortsToRLP(internalExecutionSublistsEdges)); + } + } + + private byte[] getEncodedForHash() { + List fieldToEncodeList = Lists.newArrayList(RLP.encodeElement(HashUtil.keccak256(this.getLogsBloom()))); + this.addEdgesEncoded(fieldToEncodeList); + return RLP.encodeList(fieldToEncodeList.toArray(new byte[][]{})); + } +} diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockHeaderV0.java b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderV0.java new file mode 100644 index 00000000000..ea80deb6ee1 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderV0.java @@ -0,0 +1,88 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 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 org.ethereum.core; + +import co.rsk.core.BlockDifficulty; +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; + +import java.util.Arrays; +import java.util.List; + +public class BlockHeaderV0 extends BlockHeader { + // block header for blocks before rskip351 + @Override + public byte getVersion() { return 0x0; } + @Override + public BlockHeaderExtension getExtension() { return null; } // block header v0 has no extension + @Override + public void setExtension(BlockHeaderExtension extension) { + // block header v0 has no extension + } + + private short[] txExecutionSublistsEdges; + + public BlockHeaderV0(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, byte[] stateRoot, + byte[] txTrieRoot, byte[] receiptTrieRoot, byte[] logsBloom, BlockDifficulty difficulty, + long number, byte[] gasLimit, long gasUsed, long timestamp, byte[] extraData, + Coin paidFees, byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, + byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] mergedMiningForkDetectionData, + Coin minimumGasPrice, int uncleCount, boolean sealed, + boolean useRskip92Encoding, boolean includeForkDetectionData, byte[] ummRoot, short[] txExecutionSublistsEdges) { + super(parentHash,unclesHash, coinbase, stateRoot, + txTrieRoot, receiptTrieRoot, logsBloom, difficulty, + number, gasLimit, gasUsed, timestamp, extraData, + paidFees, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, + bitcoinMergedMiningCoinbaseTransaction, mergedMiningForkDetectionData, + minimumGasPrice, uncleCount, sealed, + useRskip92Encoding, includeForkDetectionData, ummRoot); + this.txExecutionSublistsEdges = txExecutionSublistsEdges != null ? Arrays.copyOf(txExecutionSublistsEdges, txExecutionSublistsEdges.length) : null; + } + + // logs bloom is stored in the extension data + @Override + public byte[] getLogsBloom() { return extensionData; } + @Override + public void setLogsBloom(byte[] logsBloom) { + if (this.sealed) { + throw new SealedBlockHeaderException("trying to alter logs bloom"); + } + this.hash = null; + + this.extensionData = logsBloom; + } + + @Override + public short[] getTxExecutionSublistsEdges() { return this.txExecutionSublistsEdges != null ? Arrays.copyOf(this.txExecutionSublistsEdges, this.txExecutionSublistsEdges.length) : null; } + + @Override + public void setTxExecutionSublistsEdges(short[] edges) { + this.txExecutionSublistsEdges = edges != null? Arrays.copyOf(edges, edges.length) : null; + } + + @Override + public void addExtraFieldsToEncodedHeader(boolean usingCompressedEncoding, List fieldsToEncode) { + // adding edges to + // 1. keep RSKIP 351 and RSKIP 144 independent + // either can be activated at any height independently + // 2. keep compressed encoding the same as uncompressed + // since this difference should not exist on v0 + this.addTxExecutionSublistsEdgesIfAny(fieldsToEncode); + } +} diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockHeaderV1.java b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderV1.java new file mode 100644 index 00000000000..5ad22d5435d --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/core/BlockHeaderV1.java @@ -0,0 +1,92 @@ +package org.ethereum.core; + +import co.rsk.core.BlockDifficulty; +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import com.google.common.annotations.VisibleForTesting; +import org.ethereum.util.RLP; + +import java.util.Arrays; +import java.util.List; + +public class BlockHeaderV1 extends BlockHeader { + private BlockHeaderExtensionV1 extension; + + public BlockHeaderV1(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, byte[] stateRoot, + byte[] txTrieRoot, byte[] receiptTrieRoot, byte[] extensionData, BlockDifficulty difficulty, + long number, byte[] gasLimit, long gasUsed, long timestamp, byte[] extraData, + Coin paidFees, byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, + byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] mergedMiningForkDetectionData, + Coin minimumGasPrice, int uncleCount, boolean sealed, + boolean useRskip92Encoding, boolean includeForkDetectionData, byte[] ummRoot, short[] txExecutionSublistsEdges, boolean compressed) { + super(parentHash,unclesHash, coinbase, stateRoot, + txTrieRoot, receiptTrieRoot, compressed ? extensionData : null, difficulty, + number, gasLimit, gasUsed, timestamp, extraData, + paidFees, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, + bitcoinMergedMiningCoinbaseTransaction, mergedMiningForkDetectionData, + minimumGasPrice, uncleCount, sealed, + useRskip92Encoding, includeForkDetectionData, ummRoot); + this.extension = compressed + ? new BlockHeaderExtensionV1(null, null) + : new BlockHeaderExtensionV1(extensionData, txExecutionSublistsEdges); + if(!compressed) { + this.updateExtensionData(); // update after calculating + } + + } + @Override + public byte getVersion() { return 0x1; } + + @Override + public BlockHeaderExtensionV1 getExtension() { return this.extension; } + @Override + public void setExtension(BlockHeaderExtension extension) { this.extension = (BlockHeaderExtensionV1) extension; } + + @VisibleForTesting + public static byte[] createExtensionData(byte[] extensionHash) { + return RLP.encodeList( + RLP.encodeByte((byte) 0x1), + RLP.encodeElement(extensionHash) + ); + } + + private void updateExtensionData() { + this.extensionData = BlockHeaderV1.createExtensionData(this.extension.getHash()); + } + + @Override + public byte[] getLogsBloom() { return this.extension.getLogsBloom(); } + + @Override + public void setLogsBloom(byte[] logsBloom) { + if (this.sealed) { + throw new SealedBlockHeaderException("trying to alter logs bloom"); + } + this.hash = null; + + this.extension.setLogsBloom(logsBloom); + this.updateExtensionData(); + } + + @Override + public short[] getTxExecutionSublistsEdges() { return this.extension.getTxExecutionSublistsEdges(); } + + @Override + public void setTxExecutionSublistsEdges(short[] edges) { + if (this.sealed) { + throw new SealedBlockHeaderException("trying to alter edges"); + } + this.hash = null; + + this.extension.setTxExecutionSublistsEdges(edges != null ? Arrays.copyOf(edges, edges.length) : null); + this.updateExtensionData(); + } + + @Override + public void addExtraFieldsToEncodedHeader(boolean usingCompressedEncoding, List fieldsToEncode) { + if (!usingCompressedEncoding) { + fieldsToEncode.add(RLP.encodeByte(this.getVersion())); + this.addTxExecutionSublistsEdgesIfAny(fieldsToEncode); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/core/GenesisHeader.java b/rskj-core/src/main/java/org/ethereum/core/GenesisHeader.java index 1419ff2c978..2c280e5080b 100644 --- a/rskj-core/src/main/java/org/ethereum/core/GenesisHeader.java +++ b/rskj-core/src/main/java/org/ethereum/core/GenesisHeader.java @@ -8,7 +8,7 @@ import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; -public class GenesisHeader extends BlockHeader { +public class GenesisHeader extends BlockHeaderV0 { private final byte[] difficulty; @@ -52,6 +52,7 @@ public GenesisHeader(byte[] parentHash, false, useRskip92Encoding, false, + null, null); this.difficulty = ByteUtils.clone(difficulty); } @@ -95,6 +96,7 @@ public GenesisHeader(byte[] parentHash, false, useRskip92Encoding, false, + null, null); this.difficulty = ByteUtils.clone(difficulty); } diff --git a/rskj-core/src/main/java/org/ethereum/core/Transaction.java b/rskj-core/src/main/java/org/ethereum/core/Transaction.java index edca4aa7d23..97901355fbd 100644 --- a/rskj-core/src/main/java/org/ethereum/core/Transaction.java +++ b/rskj-core/src/main/java/org/ethereum/core/Transaction.java @@ -577,7 +577,9 @@ private boolean checkRemascAddress() { } private boolean checkRemascTxZeroValues() { - if (null != getData() || null != getSignature()) { + byte[] currentData = getData(); + + if ((null != currentData && currentData.length != 0) || null != getSignature()) { return false; } 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 451cebaf1da..79f89cfff83 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -44,11 +44,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import java.math.BigInteger; import java.util.*; import static co.rsk.util.ListArrayUtil.getLength; import static co.rsk.util.ListArrayUtil.isEmpty; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP144; import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP174; import static org.ethereum.util.BIUtil.*; import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; @@ -76,7 +78,7 @@ public class TransactionExecutor { private final PrecompiledContracts precompiledContracts; private final boolean enableRemasc; private String executionError = ""; - private final long gasUsedInTheBlock; + private final long gasConsumed; private Coin paidFees; private final ProgramInvokeFactory programInvokeFactory; @@ -97,15 +99,20 @@ public class TransactionExecutor { private List logs = null; private final Set deletedAccounts; private final SignatureCache signatureCache; + private final long sublistGasLimit; private boolean localCall = false; + private final Set precompiledContractsCalled = new HashSet<>(); + + private final boolean postponeFeePayment; + 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, + ProgramInvokeFactory programInvokeFactory, Block executionBlock, long gasConsumed, VmConfig vmConfig, boolean remascEnabled, PrecompiledContracts precompiledContracts, Set deletedAccounts, - SignatureCache signatureCache) { + SignatureCache signatureCache, boolean postponeFeePayment, long sublistGasLimit) { this.constants = constants; this.signatureCache = signatureCache; this.activations = activationConfig.forBlock(executionBlock.getNumber()); @@ -119,11 +126,13 @@ public TransactionExecutor( this.blockFactory = blockFactory; this.programInvokeFactory = programInvokeFactory; this.executionBlock = executionBlock; - this.gasUsedInTheBlock = gasUsedInTheBlock; + this.gasConsumed = gasConsumed; this.vmConfig = vmConfig; this.precompiledContracts = precompiledContracts; this.enableRemasc = remascEnabled; this.deletedAccounts = new HashSet<>(deletedAccounts); + this.postponeFeePayment = postponeFeePayment; + this.sublistGasLimit = sublistGasLimit; } /** @@ -167,9 +176,9 @@ private boolean init() { } long txGasLimit = GasCost.toGas(tx.getGasLimit()); - long curBlockGasLimit = GasCost.toGas(executionBlock.getGasLimit()); + long gasLimit = activations.isActive(RSKIP144)? sublistGasLimit : GasCost.toGas(executionBlock.getGasLimit()); - if (!gasIsValid(txGasLimit, curBlockGasLimit)) { + if (!gasIsValid(txGasLimit, gasLimit)) { return false; } @@ -251,18 +260,18 @@ private boolean nonceIsValid() { return true; } - private boolean gasIsValid(long txGasLimit, long curBlockGasLimit) { - // if we've passed the curBlockGas limit we must stop exec + private boolean gasIsValid(long txGasLimit, long curContainerGasLimit) { + // if we've passed the curContainerGasLimit limit we must stop exec // cumulativeGas being equal to GasCost.MAX_GAS is a border condition // which is used on some stress tests, but its far from being practical // as the current gas limit on blocks is 6.8M... several orders of magnitude // less than the theoretical max gas on blocks. - long cumulativeGas = GasCost.add(txGasLimit, gasUsedInTheBlock); + long cumulativeGas = GasCost.add(txGasLimit, gasConsumed); - boolean cumulativeGasReached = cumulativeGas > curBlockGasLimit || cumulativeGas == GasCost.MAX_GAS; + boolean cumulativeGasReached = cumulativeGas > curContainerGasLimit || cumulativeGas == GasCost.MAX_GAS; if (cumulativeGasReached) { - execError(String.format("Too much gas used in this block: available in block: %s tx sent: %s", - curBlockGasLimit - txGasLimit, + execError(String.format("Too much gas used in this block or sublist(RSKIP144): available in sublist: %s tx sent: %s", + curContainerGasLimit - txGasLimit, txGasLimit)); return false; } @@ -317,6 +326,7 @@ private void call() { this.subtraces = new ArrayList<>(); if (precompiledContract != null) { + this.precompiledContractsCalled.add(targetAddress); Metric metric = profiler.start(Profiler.PROFILING_TYPE.PRECOMPILED_CONTRACT_INIT); PrecompiledContractArgs args = PrecompiledContractArgsBuilder.builder() .transaction(tx) @@ -444,6 +454,11 @@ private void go() { vm.play(program); + // This line checks whether the invoked smart contract calls a Precompiled contract. + // This flag is then taken by the Parallel transaction handler, if the tx calls a precompiled contract, + // it should be executed sequentially. + this.precompiledContractsCalled.addAll(program.precompiledContractsCalled()); + result = program.getResult(); gasLeftover = GasCost.subtract(GasCost.toGas(tx.getGasLimit()), program.getResult().getGasUsed()); @@ -504,11 +519,11 @@ private void configureRuntimeExceptionOnProgram(RuntimeException e) { public TransactionReceipt getReceipt() { if (receipt == null) { receipt = new TransactionReceipt(); - long totalGasUsed = GasCost.add(gasUsedInTheBlock, getGasUsed()); + long totalGasUsed = GasCost.add(gasConsumed, getGasConsumed()); receipt.setCumulativeGas(totalGasUsed); receipt.setTransaction(tx); receipt.setLogInfoList(getVMLogs()); - receipt.setGasUsed(getGasUsed()); + receipt.setGasUsed(getGasConsumed()); receipt.setStatus(executionError.isEmpty() ? TransactionReceipt.SUCCESS_STATUS : TransactionReceipt.FAILED_STATUS); } return receipt; @@ -550,11 +565,13 @@ private void finalization() { Coin summaryFee = summary.getFee(); //TODO: REMOVE THIS WHEN THE LocalBLockTests starts working with REMASC - if (enableRemasc) { - logger.trace("Adding fee to remasc contract account"); - track.addBalance(PrecompiledContracts.REMASC_ADDR, summaryFee); - } else { - track.addBalance(coinbase, summaryFee); + if (!postponeFeePayment) { + if (enableRemasc) { + logger.trace("Adding fee to remasc contract account"); + track.addBalance(PrecompiledContracts.REMASC_ADDR, summaryFee); + } else { + track.addBalance(coinbase, summaryFee); + } } this.paidFees = summaryFee; @@ -595,7 +612,7 @@ private void localCallFinalization() { long gasRefund = refundGas(); - result.setGasUsed(getGasUsed()); + result.setGasUsed(getGasConsumed()); TransactionExecutionSummary summary = buildTransactionExecutionSummary(summaryBuilder, gasRefund); @@ -687,7 +704,7 @@ public ProgramResult getResult() { return result; } - public long getGasUsed() { + public long getGasConsumed() { if (activations.isActive(ConsensusRule.RSKIP136)) { return GasCost.subtract(GasCost.toGas(tx.getGasLimit()), gasLeftover); } @@ -695,4 +712,9 @@ public long getGasUsed() { } public Coin getPaidFees() { return paidFees; } + + @Nonnull + public Set precompiledContractsCalled() { + return this.precompiledContractsCalled.isEmpty() ? Collections.emptySet() : new HashSet<>(this.precompiledContractsCalled); + } } diff --git a/rskj-core/src/main/java/org/ethereum/db/DummyReadWrittenKeysTracker.java b/rskj-core/src/main/java/org/ethereum/db/DummyReadWrittenKeysTracker.java new file mode 100644 index 00000000000..d26f0e9494b --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/db/DummyReadWrittenKeysTracker.java @@ -0,0 +1,59 @@ +package org.ethereum.db; + +import co.rsk.core.bc.IReadWrittenKeysTracker; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class DummyReadWrittenKeysTracker implements IReadWrittenKeysTracker { + + private final Map> readKeysByThread; + private final Map> writtenKeysByThread; + + public DummyReadWrittenKeysTracker() { + this.readKeysByThread = new HashMap<>(); + this.writtenKeysByThread = new HashMap<>(); + } + + @Override + public Set getThisThreadReadKeys() { + return new HashSet<>(); + } + + @Override + public Set getThisThreadWrittenKeys() { + return new HashSet<>(); + } + + @Override + public Map> getReadKeysByThread() { + return readKeysByThread; + } + + @Override + public Map> getWrittenKeysByThread() { + return writtenKeysByThread; + } + + @Override + public void addNewReadKey(ByteArrayWrapper key) { + //Dummy tracker does not store added keys + } + + @Override + public void addNewWrittenKey(ByteArrayWrapper key) { + //Dummy tracker does not store added keys + } + + @Override + public boolean detectCollision(){ + return false; + } + + @Override + public void clear() { + //Dummy tracker does not store added keys + } +} diff --git a/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java b/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java index e56c0df82c7..42dd7336b25 100644 --- a/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java +++ b/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java @@ -20,6 +20,7 @@ import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.bc.IReadWrittenKeysTracker; import co.rsk.core.types.ints.Uint24; import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; @@ -46,6 +47,7 @@ public class MutableRepository implements Repository { private final TrieKeyMapper trieKeyMapper; private final MutableTrie mutableTrie; + private final IReadWrittenKeysTracker tracker; public MutableRepository(TrieStore trieStore, Trie trie) { this(new MutableTrieImpl(trieStore, trie)); @@ -54,6 +56,13 @@ public MutableRepository(TrieStore trieStore, Trie trie) { public MutableRepository(MutableTrie mutableTrie) { this.trieKeyMapper = new TrieKeyMapper(); this.mutableTrie = mutableTrie; + this.tracker = new DummyReadWrittenKeysTracker(); + } + + public MutableRepository(MutableTrie mutableTrie, IReadWrittenKeysTracker tracker) { + this.trieKeyMapper = new TrieKeyMapper(); + this.mutableTrie = mutableTrie; + this.tracker = tracker; } @Override @@ -71,13 +80,14 @@ public synchronized AccountState createAccount(RskAddress addr) { @Override public synchronized void setupContract(RskAddress addr) { byte[] prefix = trieKeyMapper.getAccountStoragePrefixKey(addr); - mutableTrie.put(prefix, ONE_BYTE_ARRAY); + internalPut(prefix, ONE_BYTE_ARRAY); } @Override public synchronized boolean isExist(RskAddress addr) { // Here we assume size != 0 means the account exists - return mutableTrie.getValueLength(trieKeyMapper.getAccountKey(addr)).compareTo(Uint24.ZERO) > 0; + byte[] accountKey = trieKeyMapper.getAccountKey(addr); + return internalGetValueLength(accountKey).compareTo(Uint24.ZERO) > 0; } @Override @@ -94,7 +104,9 @@ public synchronized AccountState getAccountState(RskAddress addr) { @Override public synchronized void delete(RskAddress addr) { - mutableTrie.deleteRecursive(trieKeyMapper.getAccountKey(addr)); + byte[] accountKey = trieKeyMapper.getAccountKey(addr); + tracker.addNewWrittenKey(new ByteArrayWrapper(accountKey)); + mutableTrie.deleteRecursive(accountKey); } @Override @@ -137,7 +149,7 @@ public synchronized BigInteger getNonce(RskAddress addr) { @Override public synchronized void saveCode(RskAddress addr, byte[] code) { byte[] key = trieKeyMapper.getCodeKey(addr); - mutableTrie.put(key, code); + internalPut(key, code); if (code != null && code.length != 0 && !isExist(addr)) { createAccount(addr); @@ -152,7 +164,7 @@ public synchronized int getCodeLength(RskAddress addr) { } byte[] key = trieKeyMapper.getCodeKey(addr); - return mutableTrie.getValueLength(key).intValue(); + return internalGetValueLength(key).intValue(); } @Override @@ -167,7 +179,7 @@ public synchronized Keccak256 getCodeHashNonStandard(RskAddress addr) { } byte[] key = trieKeyMapper.getCodeKey(addr); - Optional valueHash = mutableTrie.getValueHash(key); + Optional valueHash = internalGetValueHash(key); //Returning ZERO_HASH is the non standard implementation we had pre RSKIP169 implementation //and thus me must honor it. @@ -187,7 +199,7 @@ public synchronized Keccak256 getCodeHashStandard(RskAddress addr) { byte[] key = trieKeyMapper.getCodeKey(addr); - return mutableTrie.getValueHash(key).orElse(KECCAK_256_OF_EMPTY_ARRAY); + return internalGetValueHash(key).orElse(KECCAK_256_OF_EMPTY_ARRAY); } @Override @@ -202,13 +214,13 @@ public synchronized byte[] getCode(RskAddress addr) { } byte[] key = trieKeyMapper.getCodeKey(addr); - return mutableTrie.get(key); + return internalGet(key); } @Override public boolean isContract(RskAddress addr) { byte[] prefix = trieKeyMapper.getAccountStoragePrefixKey(addr); - return mutableTrie.get(prefix) != null; + return internalGet(prefix) != null; } @Override @@ -233,16 +245,16 @@ public synchronized void addStorageBytes(RskAddress addr, DataWord key, byte[] v // conversion here only applies if this is called directly. If suppose this only occurs in tests, but it can // also occur in precompiled contracts that store data directly using this method. if (value == null || value.length == 0) { - mutableTrie.put(triekey, null); + internalPut(triekey, null); } else { - mutableTrie.put(triekey, value); + internalPut(triekey, value); } } @Override public synchronized DataWord getStorageValue(RskAddress addr, DataWord key) { byte[] triekey = trieKeyMapper.getAccountStorageKey(addr, key); - byte[] value = mutableTrie.get(triekey); + byte[] value = internalGet(triekey); if (value == null) { return null; } @@ -253,7 +265,7 @@ public synchronized DataWord getStorageValue(RskAddress addr, DataWord key) { @Override public synchronized byte[] getStorageBytes(RskAddress addr, DataWord key) { byte[] triekey = trieKeyMapper.getAccountStorageKey(addr, key); - return mutableTrie.get(triekey); + return internalGet(triekey); } @Override @@ -284,6 +296,10 @@ public synchronized Coin getBalance(RskAddress addr) { public synchronized Coin addBalance(RskAddress addr, Coin value) { AccountState account = getAccountStateOrCreateNew(addr); + if (value.equals(Coin.ZERO)) { + return account.getBalance(); + } + Coin result = account.addToBalance(value); updateAccountState(addr, account); @@ -311,7 +327,7 @@ public synchronized Set getAccountsKeys() { // To start tracking, a new repository is created, with a MutableTrieCache in the middle @Override public synchronized Repository startTracking() { - return new MutableRepository(new MutableTrieCache(mutableTrie)); + return new MutableRepository(new MutableTrieCache(mutableTrie), tracker); } @Override @@ -341,7 +357,7 @@ public synchronized byte[] getRoot() { @Override public synchronized void updateAccountState(RskAddress addr, final AccountState accountState) { byte[] accountKey = trieKeyMapper.getAccountKey(addr); - mutableTrie.put(accountKey, accountState.getEncoded()); + internalPut(accountKey, accountState.getEncoded()); } @VisibleForTesting @@ -367,6 +383,27 @@ private synchronized AccountState getAccountStateOrCreateNew(RskAddress addr) { } private byte[] getAccountData(RskAddress addr) { - return mutableTrie.get(trieKeyMapper.getAccountKey(addr)); + byte[] accountKey = trieKeyMapper.getAccountKey(addr); + return internalGet(accountKey); + } + + private void internalPut(byte[] key, byte[] value) { + tracker.addNewWrittenKey(new ByteArrayWrapper(key)); + mutableTrie.put(key, value); + } + + private byte[] internalGet(byte[] key) { + tracker.addNewReadKey(new ByteArrayWrapper(key)); + return mutableTrie.get(key); + } + + private Uint24 internalGetValueLength(byte[] key) { + tracker.addNewReadKey(new ByteArrayWrapper(key)); + return mutableTrie.getValueLength(key); + } + + private Optional internalGetValueHash(byte[] key) { + tracker.addNewReadKey(new ByteArrayWrapper(key)); + return mutableTrie.getValueHash(key); } } diff --git a/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java b/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java index 1acf8aaad7f..d529bee160c 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java @@ -64,6 +64,7 @@ public class BlockResultDTO { private final String hashForMergedMining; private final String paidFees; private final String cumulativeDifficulty; + private final short[] rskPteEdges; private BlockResultDTO( Long number, @@ -90,7 +91,8 @@ private BlockResultDTO( byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] bitcoinMergedMiningMerkleProof, byte[] hashForMergedMining, - Coin paidFees) { + Coin paidFees, + short[] rskPteEdges) { this.number = number != null ? HexUtils.toQuantityJsonHex(number) : null; this.hash = hash != null ? hash.toJsonString() : null; this.parentHash = parentHash.toJsonString(); @@ -120,6 +122,8 @@ private BlockResultDTO( this.bitcoinMergedMiningMerkleProof = HexUtils.toUnformattedJsonHex(bitcoinMergedMiningMerkleProof); this.hashForMergedMining = HexUtils.toUnformattedJsonHex(hashForMergedMining); this.paidFees = paidFees != null ? HexUtils.toQuantityJsonHex(paidFees.getBytes()) : null; + + this.rskPteEdges = rskPteEdges; } public static BlockResultDTO fromBlock(Block b, boolean fullTx, BlockStore blockStore, boolean skipRemasc, boolean zeroSignatureIfRemasc, SignatureCache signatureCache) { @@ -177,7 +181,8 @@ public static BlockResultDTO fromBlock(Block b, boolean fullTx, BlockStore block b.getBitcoinMergedMiningCoinbaseTransaction(), b.getBitcoinMergedMiningMerkleProof(), b.getHashForMergedMining(), - b.getFeesPaidToMiner() + b.getFeesPaidToMiner(), + b.getHeader().getTxExecutionSublistsEdges() ); } @@ -290,4 +295,8 @@ public String getHashForMergedMining() { public String getPaidFees() { return paidFees; } + + public short[] getRskPteEdges() { + return rskPteEdges; + } } \ No newline at end of file diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java index 4ff85034314..2de92a57e7e 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java @@ -24,12 +24,15 @@ import static co.rsk.util.HexUtils.stringHexToByteArray; public abstract class HashParam32 { - private static final int HASH_BYTE_LENGTH = 32; + public static final int HASH_BYTE_LENGTH = Keccak256.HASH_LEN; + public static final int MIN_HASH_HEX_LEN = 2 * HASH_BYTE_LENGTH; // 2 hex characters per byte + public static final int MAX_HASH_HEX_LEN = MIN_HASH_HEX_LEN + 2; // 2 bytes for 0x prefix + private final Keccak256 hash; HashParam32(String hashType, String hash) { - if (hash == null || hash.isEmpty()) { - throw RskJsonRpcRequestException.invalidParamError("Invalid " + hashType + ": empty or null."); + if (!isHash32HexLengthValid(hash)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid " + hashType + ": incorrect length."); } byte[] hashBytes; @@ -50,4 +53,8 @@ public abstract class HashParam32 { public Keccak256 getHash() { return hash; } + + public static boolean isHash32HexLengthValid(String hex) { + return hex != null && hex.length() >= MIN_HASH_HEX_LEN && hex.length() <= MAX_HASH_HEX_LEN; + } } diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java index 863a682018c..338755defa9 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java @@ -31,11 +31,15 @@ public class HexAddressParam implements Serializable { private static final long serialVersionUID = 1L; + public static final int HEX_ADDR_BYTE_LENGTH = RskAddress.LENGTH_IN_BYTES; + public static final int MIN_HEX_ADDR_LEN = 2 * HEX_ADDR_BYTE_LENGTH; // 2 hex characters per byte + public static final int MAX_HEX_ADDR_LEN = MIN_HEX_ADDR_LEN + 2; // 2 bytes for 0x prefix + private transient final RskAddress address; public HexAddressParam(String hexAddress) { - if (hexAddress == null || hexAddress.isEmpty()) { - throw RskJsonRpcRequestException.invalidParamError("Invalid address: empty or null."); + if (!isHexAddressLengthValid(hexAddress)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid address: null, empty or invalid hex value."); } try { @@ -53,6 +57,10 @@ public RskAddress getAddress() { public String toString() { return address.toString(); } + + public static boolean isHexAddressLengthValid(String hex) { + return hex != null && hex.length() >= MIN_HEX_ADDR_LEN && hex.length() <= MAX_HEX_ADDR_LEN; + } public static class Deserializer extends StdDeserializer { private static final long serialVersionUID = 1L; diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java index bbb3539fdd7..14f206cb038 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java @@ -18,6 +18,7 @@ package org.ethereum.rpc.parameters; import co.rsk.util.HexUtils; +import co.rsk.util.StringUtils; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -32,9 +33,16 @@ public class HexNumberParam implements Serializable { private static final long serialVersionUID = 1L; + public static final int HEX_NUM_BYTE_LENGTH = 32; + public static final int MAX_HEX_NUM_LEN = 2 + 2 * HEX_NUM_BYTE_LENGTH; // 2 bytes for 0x prefix; 2 hex characters per byte + private final String hexNumber; public HexNumberParam(String hexNumber) { + if (!isHexNumberLengthValid(hexNumber)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid param: " + StringUtils.trim(hexNumber)); + } + boolean hasPrefix = HexUtils.hasHexPrefix(hexNumber); if (!HexUtils.isHex(hexNumber.toLowerCase(), hasPrefix ? 2 : 0)) { try { @@ -56,6 +64,10 @@ public String toString() { return this.hexNumber; } + public static boolean isHexNumberLengthValid(String hex) { + return hex != null && hex.length() <= MAX_HEX_NUM_LEN; + } + public static class Deserializer extends StdDeserializer { private static final long serialVersionUID = 1L; diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java index c36d838ed86..55b70177f19 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java @@ -18,14 +18,21 @@ package org.ethereum.rpc.parameters; import co.rsk.util.HexUtils; +import co.rsk.util.StringUtils; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import static org.ethereum.rpc.parameters.HexNumberParam.isHexNumberLengthValid; + public abstract class HexStringParam { HexStringParam(String hexString) { - if(hexString.isEmpty()) { + if (hexString.isEmpty()) { return; } + if (!isHexNumberLengthValid(hexString)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid argument: " + StringUtils.trim(hexString)); + } + if (!HexUtils.hasHexPrefix(hexString) || !HexUtils.isHex(hexString,2)) { throw RskJsonRpcRequestException.invalidParamError(String.format("Invalid argument \"%s\": param should be a hex value string.", hexString)); } diff --git a/rskj-core/src/main/java/org/ethereum/util/ByteUtil.java b/rskj-core/src/main/java/org/ethereum/util/ByteUtil.java index 12c22f62f9b..ed4f2448868 100644 --- a/rskj-core/src/main/java/org/ethereum/util/ByteUtil.java +++ b/rskj-core/src/main/java/org/ethereum/util/ByteUtil.java @@ -26,6 +26,7 @@ import javax.annotation.Nullable; import java.math.BigInteger; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; @@ -674,4 +675,20 @@ public static boolean fastEquals(byte[] left, byte[] right) { left, 0, left.length, right, 0, right.length) == 0; } + + public static byte[] shortsToRLP(short[] shorts) { + byte[] edgesBytes = new byte[shorts.length * 2]; + ByteBuffer.wrap(edgesBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(shorts); + return RLP.encodeElement(edgesBytes); + } + + public static short[] rlpToShorts(byte[] rlpData) { + if(rlpData.length == 0) return new short[]{}; + short[] shorts = new short[rlpData.length / 2]; + ByteBuffer.wrap(rlpData) + .order(ByteOrder.LITTLE_ENDIAN) + .asShortBuffer() + .get(shorts); + return shorts; + } } \ No newline at end of file diff --git a/rskj-core/src/main/java/org/ethereum/vm/VM.java b/rskj-core/src/main/java/org/ethereum/vm/VM.java index e3297ebfff7..6c5adc79246 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1547,7 +1547,6 @@ protected void doCALL(){ PrecompiledContracts.PrecompiledContract precompiledContract = precompiledContracts.getContractForAddress(activations, codeAddress); if (precompiledContract != null) { - program.callToPrecompiledAddress(msg, precompiledContract); } else { program.callToAddress(msg); diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java index 680c651438e..2029b0c6f3b 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java @@ -141,6 +141,7 @@ public class Program { private final Set deletedAccountsInBlock; private final SignatureCache signatureCache; + private final Set precompiledContractsCalled = new HashSet<>(); public Program( VmConfig config, @@ -179,7 +180,6 @@ public Program( this.storage = setupProgramListener(new Storage(programInvoke)); this.deletedAccountsInBlock = new HashSet<>(deletedAccounts); this.signatureCache = signatureCache; - precompile(); traceListener = new ProgramTraceListener(config); } @@ -873,6 +873,7 @@ private boolean executeCode( getTrace().merge(program.getTrace()); getResult().merge(childResult); + this.precompiledContractsCalled.addAll(program.precompiledContractsCalled()); boolean childCallSuccessful = true; @@ -1388,7 +1389,7 @@ public int verifyJumpDest(DataWord nextPC) { } public void callToPrecompiledAddress(MessageCall msg, PrecompiledContract contract) { - + this.precompiledContractsCalled.add(new RskAddress(msg.getCodeAddress())); if (getCallDeep() == getMaxDepth()) { stackPushZero(); this.refundGas(msg.getGas().longValue(), " call deep limit reach"); @@ -1553,6 +1554,11 @@ private boolean byTestingSuite() { return invoke.byTestingSuite(); } + @Nonnull + public Set precompiledContractsCalled() { + return precompiledContractsCalled.isEmpty() ? Collections.emptySet() : new HashSet<>(this.precompiledContractsCalled); + } + public interface ProgramOutListener { void output(String out); } diff --git a/rskj-core/src/main/java/org/ethereum/vm/trace/ProgramTraceProcessor.java b/rskj-core/src/main/java/org/ethereum/vm/trace/ProgramTraceProcessor.java index 747b820de90..a5c9e5fb866 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/trace/ProgramTraceProcessor.java +++ b/rskj-core/src/main/java/org/ethereum/vm/trace/ProgramTraceProcessor.java @@ -27,15 +27,17 @@ import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** * Provides tracing and exporting to JSON */ public class ProgramTraceProcessor { - - private final Map traces = new HashMap<>(); + private final Map traces = new ConcurrentHashMap<>(); private final TraceOptions traceOptions; diff --git a/rskj-core/src/main/resources/config/regtest.conf b/rskj-core/src/main/resources/config/regtest.conf index d19ce575c34..5e351fb7dab 100644 --- a/rskj-core/src/main/resources/config/regtest.conf +++ b/rskj-core/src/main/resources/config/regtest.conf @@ -19,6 +19,8 @@ blockchain.config { consensusRules = { rskip97 = -1 # disable orchid difficulty drop rskipUMM = 1 + rskip144 = 1 + rskip351 = 1 } } diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 74091ce8ab0..b9a4f65a9da 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -79,6 +79,8 @@ blockchain = { rskip293 = rskip294 = rskip297 = + rskip351 = + rskip144 = rskip326 = rskip353 = rskip357 = diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 9cd09885d95..5987c3e3e0b 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -64,6 +64,8 @@ blockchain = { rskip293 = hop400 rskip294 = hop400 rskip297 = hop400 + rskip351 = -1 + rskip144 = -1 rskip326 = fingerroot500 rskip353 = hop401 rskip357 = hop401 diff --git a/rskj-core/src/main/resources/version.properties b/rskj-core/src/main/resources/version.properties index f6a49d73be6..8a6347af516 100644 --- a/rskj-core/src/main/resources/version.properties +++ b/rskj-core/src/main/resources/version.properties @@ -1,2 +1,2 @@ -versionNumber='6.4.0' +versionNumber='6.5.0' modifier="SNAPSHOT" diff --git a/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java b/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java index 038ee120217..a7538302397 100644 --- a/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java +++ b/rskj-core/src/test/java/co/rsk/blockchain/utils/BlockGenerator.java @@ -33,8 +33,8 @@ 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.config.blockchain.upgrades.ActivationConfigsForTest; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; import org.ethereum.crypto.HashUtil; import org.ethereum.util.ByteUtil; @@ -171,6 +171,7 @@ public Block createChildBlock(Block parent, long fees, List uncles, .setEmptyMergedMiningForkDetectionData() .setUncleCount(uncles.size()) .setUmmRoot(ummRoot) + .setCreateParallelCompliantHeader(activationConfig.isActive(ConsensusRule.RSKIP144, blockNumber)) .build(); return blockFactory.newBlock( @@ -207,6 +208,7 @@ public Block createChildBlock(Block parent, List txs, byte[] stateR .setTimestamp(parent.getTimestamp() + ++count) .setEmptyMergedMiningForkDetectionData() .setUmmRoot(ummRoot) + .setCreateParallelCompliantHeader(activationConfig.isActive(ConsensusRule.RSKIP144, blockNumber)) .build(); return blockFactory.newBlock( @@ -242,9 +244,15 @@ public Block createChildBlock(Block parent, List txs, List txs, List uncles, + long difficulty, BigInteger minGasPrice, byte[] gasLimit, RskAddress coinbase) { + short[] edges = activationConfig.isActive(ConsensusRule.RSKIP144, parent.getNumber() + 1) ? new short[0] : null; + return createChildBlock(parent, txs, uncles, difficulty, minGasPrice, gasLimit, coinbase, edges); + } public Block createChildBlock(Block parent, List txs, List uncles, - long difficulty, BigInteger minGasPrice, byte[] gasLimit, RskAddress coinbase) { + long difficulty, BigInteger minGasPrice, byte[] gasLimit, RskAddress coinbase, short[] edges) { if (txs == null) { txs = new ArrayList<>(); } @@ -278,6 +286,8 @@ public Block createChildBlock(Block parent, List txs, List + rawConfig.withValue("blockchain.config.consensusRules.rskip351", ConfigValueFactory.fromAnyRef(-1)) + ); + Assertions.assertFalse(config.getActivationConfig().isActive(ConsensusRule.RSKIP351, 3)); + World world = new World(receiptStore, config); + testImportBlocks(world); + } + + @Test + void importBlocksWithRskip351InMiddle() throws IOException, DslProcessorException { + ReceiptStore receiptStore = new ReceiptStoreImpl(new HashMapDB()); + TestSystemProperties config = new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.consensusRules.rskip351", ConfigValueFactory.fromAnyRef(2)) + ); + Assertions.assertFalse(config.getActivationConfig().isActive(ConsensusRule.RSKIP351, 1)); + Assertions.assertTrue(config.getActivationConfig().isActive(ConsensusRule.RSKIP351, 2)); + World world = new World(receiptStore, config); + testImportBlocks(world); + } + + @Test + void importBlocks() throws IOException, DslProcessorException { + ReceiptStore receiptStore = new ReceiptStoreImpl(new HashMapDB()); + World world = new World(receiptStore); + testImportBlocks(world); + } + @Test void importState() throws IOException { byte[] value = TestUtils.generateBytes(CliToolsTest.class, "value", 42); diff --git a/rskj-core/src/test/java/co/rsk/core/BlockFactoryTest.java b/rskj-core/src/test/java/co/rsk/core/BlockFactoryTest.java index 3136b0814ea..ca0000fe990 100644 --- a/rskj-core/src/test/java/co/rsk/core/BlockFactoryTest.java +++ b/rskj-core/src/test/java/co/rsk/core/BlockFactoryTest.java @@ -26,10 +26,11 @@ import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.BlockFactory; import org.ethereum.core.BlockHeader; +import org.ethereum.core.BlockHeaderV1; +import org.ethereum.core.Bloom; import org.ethereum.crypto.HashUtil; import org.ethereum.util.RLP; import org.ethereum.util.RLPList; -import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,8 +39,10 @@ import java.util.Arrays; import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.mockito.AdditionalMatchers.geq; +import static org.mockito.AdditionalMatchers.lt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -58,7 +61,7 @@ void setUp() { @Test void decodeGenesisBlock() { enableRulesAt(0L, RSKIP92); - MatcherAssert.assertThat(factory.decodeBlock(genesisRaw()).getHash().getBytes(), is(genesisRawHash())); + assertThat(factory.decodeBlock(genesisRaw()).getHash().getBytes(), is(genesisRawHash())); } @Test @@ -66,12 +69,12 @@ void newHeaderWithNoForkDetectionDataAndRskip110On() { long number = 20L; enableRulesAt(number, RSKIP92, RSKIP110); - BlockHeader header = createBlockHeader(number, new byte[0], new byte[0]); + BlockHeader header = createBlockHeader(number, new byte[0], new byte[0], null); Keccak256 hash = header.getHash(); byte[] hashForMergedMining = header.getHashForMergedMining(); - MatcherAssert.assertThat(hash.getBytes(), is(hashForMergedMining)); + assertThat(hash.getBytes(), is(hashForMergedMining)); } @Test @@ -79,15 +82,15 @@ void decodeBlockPriorToHeight449AndRskip110On() { long number = 20L; enableRulesAt(number, RSKIP92, RSKIP110); - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null, null); byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(19)); + assertThat(headerRLP.size(), is(19)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); } @Test @@ -95,15 +98,15 @@ void decodeBlockPriorToHeight449AndRskip110Off() { long number = 20L; enableRulesAt(number, RSKIP92); - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null, null); byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(19)); + assertThat(headerRLP.size(), is(19)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); } @Test @@ -111,15 +114,15 @@ void decodeBlockAfterHeight449AndRskip110OFF() { long number = 457L; enableRulesAt(number, RSKIP92); - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null, null); byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(19)); + assertThat(headerRLP.size(), is(19)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); } @Test @@ -128,9 +131,10 @@ void decodeBlockAfterHeight449AndRskip110On() { enableRulesAt(number, RSKIP92, RSKIP110); byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, forkDetectionData, null); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, forkDetectionData, null, null); - byte[] encodedBlock = header.getEncoded(false, false); + boolean compressed = false; + byte[] encodedBlock = header.getEncoded(false, false, compressed); byte[] hashForMergedMining = Arrays.copyOfRange(HashUtil.keccak256(encodedBlock), 0, 20); byte[] coinbase = org.bouncycastle.util.Arrays.concatenate(hashForMergedMining, forkDetectionData); coinbase = org.bouncycastle.util.Arrays.concatenate(RskMiningConstants.RSK_TAG, coinbase); @@ -139,11 +143,11 @@ void decodeBlockAfterHeight449AndRskip110On() { byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(19)); + assertThat(headerRLP.size(), is(19)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, compressed); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getMiningForkDetectionData(), is(decodedHeader.getMiningForkDetectionData())); } /** @@ -155,14 +159,15 @@ void decodeWithNoMergedMiningDataAndRskip110OffAndNoForkDetectionData() { long number = 20L; enableRulesAt(number, RSKIP92); - BlockHeader header = createBlockHeader(number, new byte[0], null); + BlockHeader header = createBlockHeader(number, new byte[0], null, null); - byte[] encodedHeader = header.getEncoded(false, false); + boolean compressed = false; + byte[] encodedHeader = header.getEncoded(false, false, compressed); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(16)); + assertThat(headerRLP.size(), is(16)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, compressed); + assertThat(header.getHash(), is(decodedHeader.getHash())); } /** @@ -176,14 +181,15 @@ void decodeWithNoMergedMiningDataAndRskip110OffAndForkDetectionData() { enableRulesAt(number, RSKIP92); byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); - BlockHeader header = createBlockHeader(number, forkDetectionData, null); + BlockHeader header = createBlockHeader(number, forkDetectionData, null, null); - byte[] encodedHeader = header.getEncoded(false, false); + boolean compressed = false; + byte[] encodedHeader = header.getEncoded(false, false, compressed); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(16)); + assertThat(headerRLP.size(), is(16)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, compressed); + assertThat(header.getHash(), is(decodedHeader.getHash())); } @Test @@ -192,16 +198,16 @@ void decodeBlockRskip110OffRskipUMMOnAndNoMergedMiningFieldsValidUMMRoot() { enableRulesAt(number, RSKIP92, RSKIPUMM); byte[] ummRoot = TestUtils.generateBytes("ummRoot",20); - BlockHeader header = createBlockHeader(number, new byte[0], ummRoot); + BlockHeader header = createBlockHeader(number, new byte[0], ummRoot, null); byte[] encodedHeader = header.getEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(17)); + assertThat(headerRLP.size(), is(17)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); } @Test @@ -209,16 +215,16 @@ void decodeBlockRskip110OffRskipUMMOnAndNoMergedMiningFieldsEmptyUMMRoot() { long number = 500L; enableRulesAt(number, RSKIP92, RSKIPUMM); - BlockHeader header = createBlockHeader(number, new byte[0], new byte[0]); + BlockHeader header = createBlockHeader(number, new byte[0], new byte[0], null); byte[] encodedHeader = header.getEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(17)); + assertThat(headerRLP.size(), is(17)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); } @Test @@ -228,13 +234,13 @@ void decodeBlockRskip110OffRskipUMMOnAndNoMergedMiningFieldsNullUMMRoot() { // this should not be possible after the activation of UMM // blocks are expected to have an empty byte array - BlockHeader header = createBlockHeader(number, new byte[0], null); + BlockHeader header = createBlockHeader(number, new byte[0], null, null); byte[] encodedHeader = header.getEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(16)); + assertThat(headerRLP.size(), is(16)); - Assertions.assertThrows(IllegalArgumentException.class, () -> factory.decodeHeader(encodedHeader)); + Assertions.assertThrows(IllegalArgumentException.class, () -> factory.decodeHeader(encodedHeader, false)); } @Test @@ -243,16 +249,16 @@ void decodeBlockRskip110OffRskipUMMOnAndMergedMiningFieldsValidUMMRoot() { enableRulesAt(number, RSKIP92, RSKIPUMM); byte[] ummRoot = TestUtils.generateBytes("ummRoot",20); - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], ummRoot); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], ummRoot, null); byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(20)); + assertThat(headerRLP.size(), is(20)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); } @Test @@ -260,16 +266,16 @@ void decodeBlockRskip110OffRskipUMMOnAndMergedMiningFieldsEmptyUmmRoot() { long number = 500L; enableRulesAt(number, RSKIP92, RSKIPUMM); - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], new byte[0], null); byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(20)); + assertThat(headerRLP.size(), is(20)); - BlockHeader decodedHeader = factory.decodeHeader(encodedHeader); + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); - MatcherAssert.assertThat(header.getHash(), is(decodedHeader.getHash())); - MatcherAssert.assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); } @Test @@ -279,13 +285,359 @@ void decodeBlockRskip110OffRskipUMMOnAndMergedMiningFieldsNullUmmRoot() { // this should not be possible after the activation of UMM // blocks are expected to have an empty byte array - BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null); + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null, null); byte[] encodedHeader = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(encodedHeader); - MatcherAssert.assertThat(headerRLP.size(), is(19)); + assertThat(headerRLP.size(), is(19)); - Assertions.assertThrows(IllegalArgumentException.class, () -> factory.decodeHeader(encodedHeader)); + Assertions.assertThrows(IllegalArgumentException.class, () -> factory.decodeHeader(encodedHeader, false)); + } + + @Test + void genesisHasVersion0() { + Assertions.assertEquals((byte) 0x0, factory.decodeBlock(genesisRaw()).getHeader().getVersion()); + } + + @Test + void headerIsVersion0Before351Activation () { + long number = 20L; + enableRskip351At(number); + BlockHeader header = factory.getBlockHeaderBuilder().setNumber(number - 1).build(); + Assertions.assertEquals(0, header.getVersion()); + } + + @Test + void headerIsVersion1After351Activation () { + long number = 20L; + enableRskip351At(number); + BlockHeader header = factory.getBlockHeaderBuilder().setNumber(number).build(); + Assertions.assertEquals(1, header.getVersion()); + } + + private BlockHeader testRSKIP351FullHeaderEncoding(byte[] encoded, byte expectedVersion, byte[] expectedLogsBloom, short[] expectedEdges) { + return testRSKIP351CompressedHeaderEncoding(encoded, expectedVersion, expectedLogsBloom, expectedEdges, false); + } + + private BlockHeader testRSKIP351CompressedHeaderEncoding(byte[] encoded, byte expectedVersion, byte[] expectedLogsBloom, short[] expectedEdges) { + return testRSKIP351CompressedHeaderEncoding(encoded, expectedVersion, expectedLogsBloom, expectedEdges, true); + } + + private BlockHeader testRSKIP351CompressedHeaderEncoding(byte[] encoded, byte expectedVersion, byte[] expectedLogsBloom, short[] expectedEdges, boolean compressed) { + BlockHeader decodedHeader = factory.decodeHeader(encoded, compressed); + + Assertions.assertEquals(expectedVersion, decodedHeader.getVersion()); + Assertions.assertArrayEquals(expectedLogsBloom, decodedHeader.getLogsBloom()); + Assertions.assertArrayEquals(expectedEdges, decodedHeader.getTxExecutionSublistsEdges()); + + return decodedHeader; + } + + @Test + void decodeCompressedBefore351() { + long number = 20L; + enableRulesAt(number, RSKIP144); + enableRskip351At(number); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setNumber(number - 1) + .build(); + + byte[] encoded = header.getEncodedCompressed(); + + BlockHeader decodedHeader = testRSKIP351CompressedHeaderEncoding(encoded, (byte) 0, logsBloom, null); + Assertions.assertArrayEquals(logsBloom, decodedHeader.getExtensionData()); + } + + @Test + void decodeCompressedBefore351WithEdges() { + long number = 20L; + long blockNumber = number - 1; + enableRulesAt(blockNumber, RSKIP144); + enableRskip351At(number); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + short[] edges = { 1, 2, 3, 4 }; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setTxExecutionSublistsEdges(edges) + .setNumber(blockNumber) + .build(); + + byte[] encoded = header.getEncodedCompressed(); + + BlockHeader decodedHeader = testRSKIP351CompressedHeaderEncoding(encoded, (byte) 0, logsBloom, edges); + Assertions.assertArrayEquals(logsBloom, decodedHeader.getExtensionData()); + } + + @Test + void decodeCompressedWithNoEdgesAndMergedMiningFields() { + long blockNumber = 20L; + enableRulesAt(blockNumber, RSKIP144, RSKIP92, RSKIPUMM); + enableRskip351At(blockNumber); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + BlockHeader header = createBlockHeaderWithMergedMiningFields(blockNumber, new byte[0], new byte[0], null, logsBloom); + + byte[] encoded = header.getEncodedCompressed(); + + BlockHeader decodedHeader = testRSKIP351CompressedHeaderEncoding(encoded, (byte) 1, null, null); + + Assertions.assertArrayEquals(header.getExtensionData(), decodedHeader.getExtensionData()); + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getUmmRoot(), is(decodedHeader.getUmmRoot())); + } + /** + * note on decodeCompressedOfExtendedBefore351 & + * decodeCompressedOfExtendedBefore351WithEdges: + * while nodes activate hf, the new nodes will decode + * blocks headers v0 with compressed=true when old nodes send + * block headers encoded in the old fashion. in consequence, + * decode(compressed=true) needs to handle encoded(compress=false) + * for blocks v0 + */ + + @Test + void decodeCompressedOfExtendedBefore351() { + long number = 20L; + enableRulesAt(number, RSKIP144); + enableRskip351At(number); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setNumber(number - 1) + .build(); + + byte[] encoded = header.getFullEncoded(); // used before hf + + BlockHeader decodedHeader = testRSKIP351CompressedHeaderEncoding(encoded, (byte) 0, logsBloom, null); + Assertions.assertArrayEquals(logsBloom, decodedHeader.getExtensionData()); + } + + @Test + void decodeCompressedOfExtendedBefore351WithEdges() { + long number = 20L; + long blockNumber = number - 1; + enableRulesAt(blockNumber, RSKIP144); + enableRskip351At(number); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + short[] edges = { 1, 2, 3, 4 }; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setTxExecutionSublistsEdges(edges) + .setNumber(blockNumber) + .build(); + + byte[] encoded = header.getFullEncoded(); // used before hf + + BlockHeader decodedHeader = testRSKIP351CompressedHeaderEncoding(encoded, (byte) 0, logsBloom, edges); + Assertions.assertArrayEquals(logsBloom, decodedHeader.getExtensionData()); + } + + @Test + void decodeCompressedAfter351WithEdges() { + long blockNumber = 20L; + enableRulesAt(blockNumber, RSKIP144); + enableRskip351At(blockNumber); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + short[] edges = { 1, 2, 3, 4 }; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setTxExecutionSublistsEdges(edges) + .setNumber(blockNumber) + .build(); + + byte[] encoded = header.getEncodedCompressed(); + + BlockHeader decodedHeader = testRSKIP351CompressedHeaderEncoding(encoded, (byte) 1, null, null); + Assertions.assertArrayEquals(BlockHeaderV1.createExtensionData(header.getExtension().getHash()), decodedHeader.getExtensionData()); + } + + @Test + void decodeFullBefore351And144() { + long number = 20L; + long blockNumber = number - 1; + enableRulesAt(number, RSKIP144); + enableRskip351At(number); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setNumber(blockNumber) + .build(); + + byte[] encoded = header.getFullEncoded(); + + BlockHeader decodedHeader = testRSKIP351FullHeaderEncoding(encoded, (byte) 0, logsBloom, null); + Assertions.assertArrayEquals(header.getLogsBloom(), decodedHeader.getExtensionData()); + } + + @Test + void decodeFullBefore351WithEdges() { + long number = 20L; + long blockNumber = number - 1; + enableRulesAt(blockNumber, RSKIP144); + enableRskip351At(number); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + short[] edges = { 1, 2, 3, 4 }; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setTxExecutionSublistsEdges(edges) + .setNumber(blockNumber) + .build(); + + byte[] encoded = header.getFullEncoded(); + + BlockHeader decodedHeader = testRSKIP351FullHeaderEncoding(encoded, (byte) 0, logsBloom, edges); + Assertions.assertArrayEquals(header.getLogsBloom(), decodedHeader.getExtensionData()); + } + + @Test + void decodeFullAfter351WithEdges() { + long blockNumber = 20L; + enableRulesAt(blockNumber, RSKIP144); + enableRskip351At(blockNumber); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 1; + logsBloom[1] = 1; + logsBloom[2] = 1; + logsBloom[3] = 1; + + short[] edges = { 1, 2, 3, 4 }; + + BlockHeader header = factory.getBlockHeaderBuilder() + .setLogsBloom(logsBloom) + .setTxExecutionSublistsEdges(edges) + .setNumber(blockNumber) + .build(); + + byte[] encoded = header.getFullEncoded(); + + BlockHeader decodedHeader = testRSKIP351FullHeaderEncoding(encoded, (byte) 1, logsBloom, edges); + Assertions.assertArrayEquals(BlockHeaderV1.createExtensionData(header.getExtension().getHash()), decodedHeader.getExtensionData()); + } + + @Test + void decodeBlockRskip144OnRskipUMMOnAndMergedMiningFields() { + long number = 500L; + enableRulesAt(number, RSKIPUMM, RSKIP144); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], new byte[0], edges); + + byte[] encodedHeader = header.getEncoded(); + RLPList headerRLP = RLP.decodeList(encodedHeader); + assertThat(headerRLP.size(), is(21)); + + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getTxExecutionSublistsEdges(), is(edges)); + } + + @Test + void decodeBlockRskip144OnRskipUMMOnAndNoMergedMiningFields() { + long number = 500L; + enableRulesAt(number, RSKIPUMM, RSKIP144); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = createBlockHeader(number, new byte[0], new byte[0], edges); + + byte[] encodedHeader = header.getEncoded(); + RLPList headerRLP = RLP.decodeList(encodedHeader); + assertThat(headerRLP.size(), is(18)); + + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getTxExecutionSublistsEdges(), is(edges)); + } + + @Test + void decodeBlockRskip144OnRskipUMMOffAndMergedMiningFields() { + long number = 500L; + enableRulesAt(number, RSKIP144); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = createBlockHeaderWithMergedMiningFields(number, new byte[0], null, edges); + + byte[] encodedHeader = header.getEncoded(); + RLPList headerRLP = RLP.decodeList(encodedHeader); + assertThat(headerRLP.size(), is(20)); + + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getTxExecutionSublistsEdges(), is(edges)); + } + + @Test + void decodeBlockRskip144OnRskipUMMOffAndNoMergedMiningFields() { + long number = 500L; + enableRulesAt(number, RSKIP144); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = createBlockHeader(number, new byte[0], null, edges); + + byte[] encodedHeader = header.getEncoded(); + RLPList headerRLP = RLP.decodeList(encodedHeader); + assertThat(headerRLP.size(), is(17)); + + BlockHeader decodedHeader = factory.decodeHeader(encodedHeader, false); + + assertThat(header.getHash(), is(decodedHeader.getHash())); + assertThat(header.getTxExecutionSublistsEdges(), is(edges)); } private void enableRulesAt(long number, ConsensusRule... consensusRules) { @@ -294,10 +646,26 @@ private void enableRulesAt(long number, ConsensusRule... consensusRules) { } } + private void enableRskip351At(long number) { + when(activationConfig.getHeaderVersion(lt(number))).thenReturn((byte) 0x0); + when(activationConfig.getHeaderVersion(geq(number))).thenReturn((byte) 0x1); + when(activationConfig.isActive(eq(RSKIP351), geq(number))).thenReturn(true); + } + + private BlockHeader createBlockHeaderWithMergedMiningFields( + long number, + byte[] forkDetectionData, + byte[] ummRoot, + short[] edges) { + return createBlockHeaderWithMergedMiningFields(number, forkDetectionData, ummRoot, edges, null); + } + private BlockHeader createBlockHeaderWithMergedMiningFields( long number, byte[] forkDetectionData, - byte[] ummRoot) { + byte[] ummRoot, + short[] edges, + byte[] logsBloom) { byte[] difficulty = BigInteger.ONE.toByteArray(); byte[] gasLimit = BigInteger.valueOf(6800000).toByteArray(); long timestamp = 7731067; // Friday, 10 May 2019 6:04:05 @@ -324,13 +692,16 @@ private BlockHeader createBlockHeaderWithMergedMiningFields( .setUncleCount(0) .setCreateUmmCompliantHeader(ummRoot != null) .setUmmRoot(ummRoot) + .setTxExecutionSublistsEdges(edges) + .setLogsBloom(logsBloom) .build(); } private BlockHeader createBlockHeader( long number, byte[] forkDetectionData, - byte[] ummRoot) { + byte[] ummRoot, + short[] edges) { byte[] difficulty = BigInteger.ONE.toByteArray(); byte[] gasLimit = BigInteger.valueOf(6800000).toByteArray(); long timestamp = 7731067; // Friday, 10 May 2019 6:04:05 @@ -354,10 +725,10 @@ private BlockHeader createBlockHeader( .setUncleCount(0) .setCreateUmmCompliantHeader(ummRoot != null) .setUmmRoot(ummRoot) + .setTxExecutionSublistsEdges(edges) .build(); } - private static byte[] genesisRawHash() { return Hex.decode("cabb7fbe88cd6d922042a32ffc08ce8b1fbb37d650b9d4e7dbfe2a7469adfa42"); } diff --git a/rskj-core/src/test/java/co/rsk/core/BlockHeaderExtensionTest.java b/rskj-core/src/test/java/co/rsk/core/BlockHeaderExtensionTest.java new file mode 100644 index 00000000000..be0d6f5158e --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/BlockHeaderExtensionTest.java @@ -0,0 +1,47 @@ +package co.rsk.core; + +import org.ethereum.core.BlockHeaderExtension; +import org.ethereum.core.BlockHeaderExtensionV1; +import org.ethereum.core.Bloom; +import org.ethereum.util.ByteUtil; +import org.ethereum.util.RLP; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class BlockHeaderExtensionTest { + @Test + public void decodeV1() { + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 0x00; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x04; + + short[] edges = { 1, 2, 3, 4 }; + + BlockHeaderExtensionV1 extension = new BlockHeaderExtensionV1(logsBloom, edges); + + BlockHeaderExtension decoded = BlockHeaderExtension.fromEncoded( + BlockHeaderExtension.toEncoded(extension) + ); + + Assertions.assertArrayEquals(extension.getHash(), decoded.getHash()); + } + + @Test + void invalidDecode() { + byte version = 0; + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + short[] edges = { 1, 2, 3, 4 }; + + Assertions.assertThrows(IllegalArgumentException.class, () -> BlockHeaderExtension.fromEncoded( + RLP.encodeList( + RLP.encodeByte(version), + RLP.encodeList( + RLP.encodeElement(logsBloom), + ByteUtil.shortsToRLP(edges) + ) + ) + ), "Unknown extension with version: " + version); + } +} diff --git a/rskj-core/src/test/java/co/rsk/core/BlockHeaderExtensionV1Test.java b/rskj-core/src/test/java/co/rsk/core/BlockHeaderExtensionV1Test.java new file mode 100644 index 00000000000..541de169b31 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/BlockHeaderExtensionV1Test.java @@ -0,0 +1,110 @@ +package co.rsk.core; + +import org.ethereum.core.BlockHeaderExtensionV1; +import org.ethereum.core.Bloom; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +class BlockHeaderExtensionV1Test { + private static final short[] EDGES = new short[] { 1, 2, 3, 4 }; + private static final short[] NO_EDGES = new short[0]; + + @Test + void createWithLogsBloomAndEdges() { + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 0x01; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x04; + + BlockHeaderExtensionV1 extension = new BlockHeaderExtensionV1(logsBloom, EDGES); + + Assertions.assertArrayEquals(logsBloom, extension.getLogsBloom()); + Assertions.assertArrayEquals(EDGES, extension.getTxExecutionSublistsEdges()); + } + + @Test + void setLogsBloom() { + BlockHeaderExtensionV1 extension = new BlockHeaderExtensionV1(new byte[32], EDGES); + + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 0x01; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x04; + + extension.setLogsBloom(logsBloom); + + Assertions.assertArrayEquals(logsBloom, extension.getLogsBloom()); + } + + + @Test + void setEdges() { + BlockHeaderExtensionV1 extension = new BlockHeaderExtensionV1(new byte[32], EDGES); + + short[] edges = new short[] { 5, 6, 7, 8}; + + extension.setTxExecutionSublistsEdges(edges); + + Assertions.assertArrayEquals(edges, extension.getTxExecutionSublistsEdges()); + } + + @Test + void hashIncludesLogsBloom() { + byte[] logsBloom1 = new byte[Bloom.BLOOM_BYTES]; + logsBloom1[0] = 0x01; + logsBloom1[1] = 0x02; + logsBloom1[2] = 0x03; + logsBloom1[3] = 0x04; + BlockHeaderExtensionV1 extension1 = new BlockHeaderExtensionV1(logsBloom1, EDGES); + + byte[] logsBloom2 = new byte[Bloom.BLOOM_BYTES]; + logsBloom2[0] = 0x01; + logsBloom2[1] = 0x02; + logsBloom2[2] = 0x03; + logsBloom2[3] = 0x05; + BlockHeaderExtensionV1 extension2 = new BlockHeaderExtensionV1(logsBloom2, EDGES); + + Assertions.assertFalse(Arrays.equals(extension1.getHash(), extension2.getHash())); + } + + @Test + void hashIncludesEdges() { + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 0x01; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x04; + BlockHeaderExtensionV1 extension1 = new BlockHeaderExtensionV1(logsBloom, EDGES); + + short[] edges2 = new short[] { 5, 6, 7, 8 }; + BlockHeaderExtensionV1 extension2 = new BlockHeaderExtensionV1(logsBloom, edges2); + + Assertions.assertFalse(Arrays.equals(extension1.getHash(), extension2.getHash())); + } + + @Test + void encodeDecode() { + byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 0x01; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x04; + + BlockHeaderExtensionV1 extension = BlockHeaderExtensionV1.fromEncoded( + new BlockHeaderExtensionV1(logsBloom, EDGES).getEncoded() + ); + + Assertions.assertArrayEquals(logsBloom, extension.getLogsBloom()); + Assertions.assertArrayEquals(EDGES, extension.getTxExecutionSublistsEdges()); + + extension = BlockHeaderExtensionV1.fromEncoded( + new BlockHeaderExtensionV1(logsBloom, NO_EDGES).getEncoded() + ); + + Assertions.assertArrayEquals(NO_EDGES, extension.getTxExecutionSublistsEdges()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/core/BlockHeaderTest.java b/rskj-core/src/test/java/co/rsk/core/BlockHeaderTest.java index a91c6bf6763..05c7d41ca3c 100644 --- a/rskj-core/src/test/java/co/rsk/core/BlockHeaderTest.java +++ b/rskj-core/src/test/java/co/rsk/core/BlockHeaderTest.java @@ -23,13 +23,13 @@ import co.rsk.peg.PegTestUtils; import com.google.common.primitives.Bytes; import org.ethereum.TestUtils; -import org.ethereum.core.BlockHeader; -import org.ethereum.core.Bloom; +import org.ethereum.core.*; import org.ethereum.crypto.HashUtil; import org.ethereum.util.RLP; import org.ethereum.util.RLPList; import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatchers; @@ -44,6 +44,7 @@ import static java.lang.System.arraycopy; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mockStatic; @ExtendWith(MockitoExtension.class) @@ -51,9 +52,9 @@ class BlockHeaderTest { @Test void getHashForMergedMiningWithForkDetectionDataAndIncludedOnAndMergedMiningFields() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], true, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], true, new byte[0], new short[0]); - byte[] encodedBlock = header.getEncoded(false, false); + byte[] encodedBlock = header.getEncoded(false, false, false); byte[] hashForMergedMiningPrefix = Arrays.copyOfRange(HashUtil.keccak256(encodedBlock), 0, 20); byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); byte[] hashForMergedMining = concatenate(hashForMergedMiningPrefix, forkDetectionData); @@ -68,7 +69,7 @@ void getHashForMergedMiningWithForkDetectionDataAndIncludedOnAndMergedMiningFiel @Test void getHashForMergedMiningWithNoForkDetectionDataAndIncludedOffAndMergedMiningFields() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0], new short[0]); Keccak256 hash = header.getHash(); byte[] hashForMergedMining = header.getHashForMergedMining(); @@ -79,7 +80,7 @@ void getHashForMergedMiningWithNoForkDetectionDataAndIncludedOffAndMergedMiningF @Test void getHashForMergedMiningWithForkDetectionDataAndIncludedOn() { byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); - BlockHeader header = createBlockHeaderWithNoMergedMiningFields(forkDetectionData, true, new byte[0]); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(forkDetectionData, true, new byte[0], new short[0]); byte[] hash = header.getHash().getBytes(); byte[] hashFirst20Elements = Arrays.copyOfRange(hash, 0, 20); @@ -93,7 +94,7 @@ void getHashForMergedMiningWithForkDetectionDataAndIncludedOn() { @Test void getHashForMergedMiningWithForkDetectionDataAndIncludedOff() { byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); - BlockHeader header = createBlockHeaderWithNoMergedMiningFields(forkDetectionData, false, new byte[0]); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(forkDetectionData, false, new byte[0], new short[0]); byte[] hash = header.getHash().getBytes(); byte[] hashForMergedMining = header.getHashForMergedMining(); @@ -105,58 +106,100 @@ void getHashForMergedMiningWithForkDetectionDataAndIncludedOff() { @Test void getEncodedWithUmmRootWithMergedMiningFields() { byte[] ummRoot = TestUtils.generateBytes("ummRoot",20); - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, ummRoot); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, ummRoot, new short[0]); byte[] headerEncoded = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(headerEncoded); - MatcherAssert.assertThat(headerRLP.size(), is(20)); + MatcherAssert.assertThat(headerRLP.size(), is(21)); } @Test void getEncodedWithUmmRootWithoutMergedMiningFields() { byte[] ummRoot = TestUtils.generateBytes("ummRoot",20); - BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, ummRoot); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, ummRoot, new short[0]); byte[] headerEncoded = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(headerEncoded); - MatcherAssert.assertThat(headerRLP.size(), is(17)); + MatcherAssert.assertThat(headerRLP.size(), is(18)); } @Test void getEncodedNullUmmRootWithMergedMiningFields() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, null); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, null, new short[0]); byte[] headerEncoded = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(headerEncoded); - MatcherAssert.assertThat(headerRLP.size(), is(19)); + MatcherAssert.assertThat(headerRLP.size(), is(20)); } @Test void getEncodedNullUmmRootWithoutMergedMiningFields() { - BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, null); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, null, new short[0]); byte[] headerEncoded = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(headerEncoded); - MatcherAssert.assertThat(headerRLP.size(), is(16)); + MatcherAssert.assertThat(headerRLP.size(), is(17)); } @Test void getEncodedEmptyUmmRootWithMergedMiningFields() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0], new short[0]); byte[] headerEncoded = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(headerEncoded); - MatcherAssert.assertThat(headerRLP.size(), is(20)); + MatcherAssert.assertThat(headerRLP.size(), is(21)); } @Test void getEncodedEmptyUmmRootWithoutMergedMiningFields() { - BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, new byte[0]); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, new byte[0], new short[0]); + + byte[] headerEncoded = header.getFullEncoded(); + RLPList headerRLP = RLP.decodeList(headerEncoded); + + MatcherAssert.assertThat(headerRLP.size(), is(18)); + } + + @Test + void getEncodedWithEdgesWithMergedMiningFields() { + short[] edges = TestUtils.randomShortArray("edges", 4); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0], edges); + + byte[] headerEncoded = header.getFullEncoded(); + RLPList headerRLP = RLP.decodeList(headerEncoded); + + MatcherAssert.assertThat(headerRLP.size(), is(21)); + } + + @Test + void getEncodedWithEdgesWithoutMergedMiningFields() { + short[] edges = TestUtils.randomShortArray("edges", 4); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, new byte[0], edges); + + byte[] headerEncoded = header.getFullEncoded(); + RLPList headerRLP = RLP.decodeList(headerEncoded); + + MatcherAssert.assertThat(headerRLP.size(), is(18)); + } + + @Test + void getEncodedNullEdgesWithMergedMiningFields() { + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0], null); + + byte[] headerEncoded = header.getFullEncoded(); + RLPList headerRLP = RLP.decodeList(headerEncoded); + + MatcherAssert.assertThat(headerRLP.size(), is(20)); + } + + @Test + void getEncodedNullEdgesWithoutMergedMiningFields() { + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, new byte[0], null); byte[] headerEncoded = header.getFullEncoded(); RLPList headerRLP = RLP.decodeList(headerEncoded); @@ -164,11 +207,36 @@ void getEncodedEmptyUmmRootWithoutMergedMiningFields() { MatcherAssert.assertThat(headerRLP.size(), is(17)); } + @Test + void getEncodedWithEdgesAndUmmRootWithMergedMiningFields() { + byte[] ummRoot = TestUtils.generateBytes("umm", 20); + short[] edges = TestUtils.randomShortArray("edges", 4); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, ummRoot, edges); + + byte[] headerEncoded = header.getFullEncoded(); + RLPList headerRLP = RLP.decodeList(headerEncoded); + + MatcherAssert.assertThat(headerRLP.size(), is(21)); + } + + @Test + void getEncodedWithEdgesAndUmmRootWithoutMergedMiningFields() { + byte[] ummRoot = TestUtils.generateBytes("umm", 20); + short[] edges = TestUtils.randomShortArray("edges", 4); + BlockHeader header = createBlockHeaderWithNoMergedMiningFields(new byte[0], false, ummRoot, edges); + + byte[] headerEncoded = header.getFullEncoded(); + RLPList headerRLP = RLP.decodeList(headerEncoded); + + MatcherAssert.assertThat(headerRLP.size(), is(18)); + } + + @Test void getMiningForkDetectionData() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], true, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], true, new byte[0], new short[0]); - byte[] encodedBlock = header.getEncoded(false, false); + byte[] encodedBlock = header.getEncoded(false, false, false); byte[] hashForMergedMining = Arrays.copyOfRange(HashUtil.keccak256(encodedBlock), 0, 20); byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); byte[] coinbase = concatenate(hashForMergedMining, forkDetectionData); @@ -217,7 +285,7 @@ void getHashForMergedMiningWhenUmmRoot() { byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); BlockHeader header = createBlockHeaderWithUmmRoot(ummRoot, forkDetectionData); - byte[] encodedBlock = header.getEncoded(false, false); + byte[] encodedBlock = header.getEncoded(false, false, false); byte[] oldHashForMergedMining = HashUtil.keccak256(encodedBlock); byte[] leftHash = Arrays.copyOf(oldHashForMergedMining, 20); byte[] hashRoot = HashUtil.keccak256(concatenate(leftHash, ummRoot)); @@ -235,7 +303,7 @@ void getHashForMergedMiningWhenEmptyUmmRoot() { BlockHeader header = createBlockHeaderWithUmmRoot(ummRoot); - byte[] encodedBlock = header.getEncoded(false, false); + byte[] encodedBlock = header.getEncoded(false, false, false); byte[] hashForMergedMining = HashUtil.keccak256(encodedBlock); MatcherAssert.assertThat(header.getHashForMergedMining(), is(hashForMergedMining)); @@ -262,7 +330,7 @@ void getHashForMergedMiningWhenUmmRootWithLengthOver20() { */ @Test void getMiningForkDetectionDataNoDataCanBeFound() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], true, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], true, new byte[0], new short[0]); byte[] forkDetectionData = TestUtils.generateBytes("forkDetectionData",12); byte[] coinbase = concatenate(RskMiningConstants.RSK_TAG, forkDetectionData); @@ -274,14 +342,14 @@ void getMiningForkDetectionDataNoDataCanBeFound() { @Test void getMiningForkDetectionDataNoDataMustBeIncluded() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0], new short[0]); MatcherAssert.assertThat(new byte[0], is(header.getMiningForkDetectionData())); } @Test void getHashShouldReuseCalculatedValue() { - BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0]); + BlockHeader header = createBlockHeaderWithMergedMiningFields(new byte[0], false, new byte[0], new short[0]); byte[] headerEncoded = header.getEncoded(); try (MockedStatic hashUtilMocked = mockStatic(HashUtil.class)) { @@ -298,9 +366,9 @@ void getHashShouldReuseCalculatedValue() { @Test void verifyRecalculatedHashForAmendedBlocks() { BlockHeader header = createBlockHeader(new byte[80], new byte[32], new byte[128], new byte[0], - false, new byte[0], false, false); + false, new byte[0], new short[0], false, false); - assertArrayEquals(HashUtil.keccak256(header.getEncoded()), header.getHash().getBytes()); + assertArrayEquals(HashUtil.keccak256(header.getEncodedForHash()), header.getHash().getBytes()); List> stateModifiers = Arrays.asList( h -> h.setBitcoinMergedMiningCoinbaseTransaction(HashUtil.keccak256("BitcoinMergedMiningCoinbaseTransaction".getBytes())), @@ -318,53 +386,244 @@ void verifyRecalculatedHashForAmendedBlocks() { stateModifiers.forEach(sm -> { sm.accept(header); - assertArrayEquals(HashUtil.keccak256(header.getEncoded()), + assertArrayEquals(HashUtil.keccak256(header.getEncodedForHash()), header.getHash().getBytes(), "Block header returned invalid hash after modification"); }); } + private void testHeaderVersion(byte version) { + BlockHeader header = createBlockHeaderWithVersion(version); + assertEquals(version, header.getVersion()); + } + + @Test + void getVersion0() { this.testHeaderVersion((byte) 0x0); } + + @Test + void getVersion1() { + this.testHeaderVersion((byte) 0x1); + } + + private static byte[] logsBloom = new byte[Bloom.BLOOM_BYTES]; + private static short[] edges = new short[]{ 1, 2, 3, 4 }; + + @BeforeAll + static void setupLogsBloom() { + logsBloom[0] = 0x01; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x04; + } + + @Test + void encodeForLogsBloomField() { + BlockHeaderV1 header = (BlockHeaderV1) createBlockHeaderWithVersion((byte) 0x1); + header.setLogsBloom(logsBloom); + header.setTxExecutionSublistsEdges(edges); + + RLPList extensionDataRLP = RLP.decodeList(header.getExtensionData()); + byte version = extensionDataRLP.get(0).getRLPData()[0]; + byte[] extensionHash = extensionDataRLP.get(1).getRLPData(); + + Assertions.assertEquals((byte) 0x1, version); + Assertions.assertArrayEquals(header.getExtension().getHash(), extensionHash); + } + + @Test + void encodeForLogsBloomFieldIsNotLogsBloomSize() { + // this test is added to assert the blockchain is still serializable + // it is still possible to serialize wether logs bloom field is the + // actual logs bloom or the extension data by reading its length != 256 + BlockHeaderV1 header = (BlockHeaderV1) createBlockHeaderWithVersion((byte) 0x1); + header.setLogsBloom(logsBloom); + header.setTxExecutionSublistsEdges(edges); + + byte[] extensionData = header.getExtensionData(); + + Assertions.assertNotEquals(Bloom.BLOOM_BYTES, extensionData.length); + } + + private BlockHeaderV1 createV1FromV0(BlockHeaderV0 headerV0) { + return new BlockHeaderV1( + headerV0.getParentHash().getBytes(), headerV0.getUnclesHash(), headerV0.getCoinbase(), headerV0.getStateRoot(), + headerV0.getTxTrieRoot(), headerV0.getReceiptsRoot(), headerV0.getLogsBloom(), headerV0.getDifficulty(), + headerV0.getNumber(), headerV0.getGasLimit(), headerV0.getGasUsed(), headerV0.getTimestamp(), headerV0.getExtraData(), + headerV0.getPaidFees(), headerV0.getBitcoinMergedMiningHeader(), headerV0.getBitcoinMergedMiningMerkleProof(), + headerV0.getBitcoinMergedMiningCoinbaseTransaction(), headerV0.getMiningForkDetectionData(), + headerV0.getMinimumGasPrice(), headerV0.getUncleCount(), headerV0.isSealed(), + false, false, headerV0.getUmmRoot(), headerV0.getTxExecutionSublistsEdges(), false + ); + } + + private void testEncodingButVersion(BlockHeaderV0 headerV0, BlockHeaderV1 headerV1) { + RLPList rlpHeaderV0 = RLP.decodeList(headerV0.getEncoded()); + RLPList rlpHeaderV1 = RLP.decodeList(headerV1.getEncoded()); + + for (int i = 0; i < rlpHeaderV0.size(); i++) { + // jump version field + Assertions.assertArrayEquals(rlpHeaderV0.get(i).getRLPData(), rlpHeaderV1.get(i > 15 ? i + 1 : i).getRLPData()); + } + } + + @Test + void encodedV0IsTheSameForV0andV1 () { + BlockHeaderV0 headerV0 = (BlockHeaderV0) createBlockHeaderWithVersion((byte) 0x0); + headerV0.setLogsBloom(logsBloom); + + BlockHeaderV1 headerV1 = createV1FromV0(headerV0); + + testEncodingButVersion(headerV0, headerV1); + } + + @Test + void fullEncodedV0IsTheSameForV0andV1 () { + BlockHeaderV0 headerV0 = (BlockHeaderV0) createBlockHeaderWithVersion((byte) 0x0); + headerV0.setLogsBloom(logsBloom); + + BlockHeaderV1 headerV1 = createV1FromV0(headerV0); + + testEncodingButVersion(headerV0, headerV1); + } + + @Test + void fullEncodedV0IsTheSameAsEncodedForHeaderMessage () { + BlockHeaderV0 headerV0 = (BlockHeaderV0) createBlockHeaderWithVersion((byte) 0x0); + headerV0.setLogsBloom(logsBloom); + + Assertions.assertArrayEquals(headerV0.getFullEncoded(), headerV0.getEncodedCompressed()); + } + + @Test + void fullEncodedV1IsTheSameAsCompressedButLogsBloomEdgesAndVersion () { + // this test is added to assert that there were no changes in the rest of the elements + BlockHeaderV1 headerV1 = (BlockHeaderV1) createBlockHeaderWithVersion((byte) 0x1); + headerV1.setLogsBloom(logsBloom); + + RLPList fullEncoded = RLP.decodeList(headerV1.getFullEncoded()); + RLPList encodedCompressed = RLP.decodeList(headerV1.getEncodedCompressed()); + + // extension data takes the element of logs bloom + // version element is not existent, is inside the rlp list od the extension data + // edges is not existent + int sizeDifference = 2; + Assertions.assertEquals(fullEncoded.size() - sizeDifference, encodedCompressed.size()); + + for (int i = 0; i < encodedCompressed.size(); i++) { + int j = i < 16 ? i : i + sizeDifference; // keep comparing elements jumping version and edges + if (i != 6) { + // logs bloom field + Assertions.assertArrayEquals(fullEncoded.get(j).getRLPData(), encodedCompressed.get(i).getRLPData()); + } + } + } + + @Test + void compressedEncodingV1HasSameRLPSizeAsFullEncodedV0WithoutEdges () { + // this test is added to assert that the rlp header size does not change + // in the hard fork, assuming both RSKIP 351 and RSKIP 144 are activated + // together + BlockHeaderV0 headerV0 = (BlockHeaderV0) createBlockHeaderWithVersion((byte) 0x0); + headerV0.setLogsBloom(logsBloom); + headerV0.setTxExecutionSublistsEdges(null); + + BlockHeaderV1 headerV1 = (BlockHeaderV1) createBlockHeaderWithVersion((byte) 0x1); + headerV1.setLogsBloom(logsBloom); + headerV1.setTxExecutionSublistsEdges(null); + + RLPList compressedEncodingV1 = RLP.decodeList(headerV1.getEncodedCompressed()); + RLPList fullEncodedV0 = RLP.decodeList(headerV0.getFullEncoded()); + + Assertions.assertEquals(fullEncodedV0.size(), compressedEncodingV1.size()); + } + + @Test + void hashOfV1IncludesLogsBloom() { + BlockHeaderV1 headerV1 = (BlockHeaderV1) createBlockHeaderWithVersion((byte) 0x1); + + headerV1.setLogsBloom(logsBloom); + byte[] hash = headerV1.getHash().getBytes(); + + byte[] otherLogsBloom = new byte[Bloom.BLOOM_BYTES]; + logsBloom[0] = 0x01; + logsBloom[1] = 0x02; + logsBloom[2] = 0x03; + logsBloom[3] = 0x05; + headerV1.setLogsBloom(otherLogsBloom); + + Assertions.assertFalse(Arrays.equals(hash, headerV1.getHash().getBytes())); + } + + @Test + void hashOfV1IncludesEdges() { + BlockHeaderV1 headerV1 = (BlockHeaderV1) createBlockHeaderWithVersion((byte) 0x1); + + headerV1.setTxExecutionSublistsEdges(edges); + byte[] hash = headerV1.getHash().getBytes(); + + + short[] otherEdges = new short[]{ 1, 2, 3, 5}; + headerV1.setTxExecutionSublistsEdges(otherEdges); + + Assertions.assertFalse(Arrays.equals(hash, headerV1.getHash().getBytes())); + } + private BlockHeader createBlockHeaderWithMergedMiningFields( byte[] forkDetectionData, - boolean includeForkDetectionData, byte[] ummRoot) { + boolean includeForkDetectionData, byte[] ummRoot, short[] edges){ return createBlockHeader(new byte[80], new byte[32], new byte[128], - forkDetectionData, includeForkDetectionData, ummRoot, false); + forkDetectionData, includeForkDetectionData, ummRoot, edges, false); } private BlockHeader createBlockHeaderWithNoMergedMiningFields( byte[] forkDetectionData, - boolean includeForkDetectionData, byte[] ummRoot) { + boolean includeForkDetectionData, byte[] ummRoot, short[] edges) { return createBlockHeader(null, null, null, - forkDetectionData, includeForkDetectionData, ummRoot, true); + forkDetectionData, includeForkDetectionData, ummRoot, edges, true); } private BlockHeader createBlockHeaderWithUmmRoot(byte[] ummRoot) { return createBlockHeader(null, null, null, - new byte[0], false, ummRoot, true); + new byte[0], false, ummRoot, new short[0], true); } private BlockHeader createBlockHeaderWithUmmRoot(byte[] ummRoot, byte[] forkDetectionData) { return createBlockHeader(null, null, null, - forkDetectionData, true, ummRoot, true); + forkDetectionData, true, ummRoot, new short[0], true); } private BlockHeader createBlockHeader(byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] forkDetectionData, - boolean includeForkDetectionData, byte[] ummRoot, boolean sealed) { + boolean includeForkDetectionData, byte[] ummRoot, short[] edges, boolean sealed) { return createBlockHeader(bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, bitcoinMergedMiningCoinbaseTransaction, - forkDetectionData, includeForkDetectionData, ummRoot, true, sealed); + forkDetectionData, includeForkDetectionData, ummRoot, edges, true, sealed); } private BlockHeader createBlockHeader(byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] forkDetectionData, - boolean includeForkDetectionData, byte[] ummRoot, boolean useRskip92Encoding, + boolean includeForkDetectionData, byte[] ummRoot, short[] edges, + boolean useRskip92Encoding, + boolean sealed) { + return createBlockHeader((byte) 0x0, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof, bitcoinMergedMiningCoinbaseTransaction, + forkDetectionData, includeForkDetectionData, ummRoot, edges, useRskip92Encoding, sealed); + } + + private BlockHeader createBlockHeaderWithVersion(byte version) { + return createBlockHeader(version, new byte[80], new byte[32], new byte[128], + new byte[0], false, null, new short[0], false, false); + } + + private BlockHeader createBlockHeader(byte version, + byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof, + byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] forkDetectionData, + boolean includeForkDetectionData, byte[] ummRoot, short[] edges, boolean useRskip92Encoding, boolean sealed) { BlockDifficulty difficulty = new BlockDifficulty(BigInteger.ONE); long number = 1; BigInteger gasLimit = BigInteger.valueOf(6800000); long timestamp = 7731067; // Friday, 10 May 2019 6:04:05 - return new BlockHeader( + if (version == 0x1) return new BlockHeaderV1( PegTestUtils.createHash3().getBytes(), HashUtil.keccak256(RLP.encodeList()), TestUtils.generateAddress("address"), @@ -388,7 +647,36 @@ private BlockHeader createBlockHeader(byte[] bitcoinMergedMiningHeader, byte[] b sealed, useRskip92Encoding, includeForkDetectionData, - ummRoot); + ummRoot, + edges, + false); + + return new BlockHeaderV0( + PegTestUtils.createHash3().getBytes(), + HashUtil.keccak256(RLP.encodeList()), + new RskAddress(TestUtils.generateAddress("coinbase").getBytes()), + HashUtil.EMPTY_TRIE_HASH, + "tx_trie_root".getBytes(), + HashUtil.EMPTY_TRIE_HASH, + new Bloom().getData(), + difficulty, + number, + gasLimit.toByteArray(), + 3000000, + timestamp, + new byte[0], + Coin.ZERO, + bitcoinMergedMiningHeader, + bitcoinMergedMiningMerkleProof, + bitcoinMergedMiningCoinbaseTransaction, + forkDetectionData, + Coin.valueOf(10L), + 0, + sealed, + useRskip92Encoding, + includeForkDetectionData, + ummRoot, + edges); } private byte[] concatenate(byte[] left, byte[] right) { diff --git a/rskj-core/src/test/java/co/rsk/core/BlockHeaderV0Test.java b/rskj-core/src/test/java/co/rsk/core/BlockHeaderV0Test.java new file mode 100644 index 00000000000..7b60ee5199e --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/BlockHeaderV0Test.java @@ -0,0 +1,71 @@ +package co.rsk.core; + +import co.rsk.peg.PegTestUtils; +import org.ethereum.TestUtils; +import org.ethereum.core.BlockHeaderExtensionV1; +import org.ethereum.core.BlockHeaderV0; +import org.ethereum.crypto.HashUtil; +import org.ethereum.util.RLP; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.util.Arrays; + +class BlockHeaderV0Test { + private BlockHeaderV0 createBlockHeader(byte[] logsBloom, short[] edges) { + return new BlockHeaderV0( + PegTestUtils.createHash3().getBytes(), + HashUtil.keccak256(RLP.encodeList()), + new RskAddress(TestUtils.generateAddress("coinbase").getBytes()), + HashUtil.EMPTY_TRIE_HASH, + "tx_trie_root".getBytes(), + HashUtil.EMPTY_TRIE_HASH, + logsBloom, + new BlockDifficulty(BigInteger.ONE), + 1, + BigInteger.valueOf(6800000).toByteArray(), + 3000000, + 7731067, + new byte[0], + Coin.ZERO, + new byte[80], + new byte[32], + new byte[128], + new byte[0], + Coin.valueOf(10L), + 0, + false, + false, + false, + null, + edges + ); + } + + @Test + void hasNullExtension() { + short[] edges = new short[]{ 1, 2, 3, 4 }; + BlockHeaderV0 header = createBlockHeader(TestUtils.generateBytes("bloom", 256), edges); + Assertions.assertEquals(null, header.getExtension()); + } + + @Test + void setsExtensionIsVoid() { + short[] edges = new short[]{ 1, 2, 3, 4 }; + BlockHeaderV0 header = createBlockHeader(TestUtils.generateBytes("bloom", 256), edges); + byte[] bloom = Arrays.copyOf(header.getLogsBloom(), header.getLogsBloom().length); + header.setExtension(new BlockHeaderExtensionV1(TestUtils.generateBytes("bloom", 256), edges)); + Assertions.assertEquals(null, header.getExtension()); + Assertions.assertArrayEquals(bloom, header.getLogsBloom()); + } + + @Test + void logsBloomFieldEncoded() { + byte[] bloom = TestUtils.generateBytes("bloom", 256); + short[] edges = new short[]{ 1, 2, 3, 4 }; + BlockHeaderV0 header = createBlockHeader(bloom, edges); + byte[] field = header.getExtensionData(); + Assertions.assertArrayEquals(bloom, field); + } +} diff --git a/rskj-core/src/test/java/co/rsk/core/BlockHeaderV1Test.java b/rskj-core/src/test/java/co/rsk/core/BlockHeaderV1Test.java new file mode 100644 index 00000000000..c9b47f3c9fc --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/BlockHeaderV1Test.java @@ -0,0 +1,103 @@ +package co.rsk.core; + +import co.rsk.peg.PegTestUtils; +import org.ethereum.TestUtils; +import org.ethereum.core.BlockHeaderExtensionV1; +import org.ethereum.core.BlockHeaderV1; +import org.ethereum.crypto.HashUtil; +import org.ethereum.util.RLP; +import org.ethereum.util.RLPList; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.math.BigInteger; +import java.util.Arrays; + +class BlockHeaderV1Test { + private BlockHeaderV1 createBlockHeader(byte[] logsBloom) { + return new BlockHeaderV1( + PegTestUtils.createHash3().getBytes(), + HashUtil.keccak256(RLP.encodeList()), + new RskAddress(TestUtils.generateAddress("coinbase").getBytes()), + HashUtil.EMPTY_TRIE_HASH, + "tx_trie_root".getBytes(), + HashUtil.EMPTY_TRIE_HASH, + logsBloom, + new BlockDifficulty(BigInteger.ONE), + 1, + BigInteger.valueOf(6800000).toByteArray(), + 3000000, + 7731067, + new byte[0], + Coin.ZERO, + new byte[80], + new byte[32], + new byte[128], + new byte[0], + Coin.valueOf(10L), + 0, + false, + false, + false, + null, + new short[0], + false + ); + } + + @Test + void createsAnExtensionWithGivenData() { + byte[] bloom = TestUtils.generateBytes("bloom", 256); + BlockHeaderV1 header = createBlockHeader(bloom); + Assertions.assertArrayEquals(bloom, header.getExtension().getLogsBloom()); + } + + @Test + void setsExtension() { + byte[] bloom = TestUtils.generateBytes("bloom", 256); + short[] edges = new short[]{ 1, 2, 3, 4 }; + BlockHeaderV1 header = createBlockHeader(bloom); + BlockHeaderExtensionV1 extension = new BlockHeaderExtensionV1(bloom, edges); + header.setExtension(extension); + Assertions.assertArrayEquals(extension.getEncoded(), header.getExtension().getEncoded()); + } + + @Test + void setsLogsBloomToExtension() { + byte[] bloom = TestUtils.generateBytes("bloom", 256); + BlockHeaderV1 header = createBlockHeader(new byte[]{}); + header.setLogsBloom(bloom); + Assertions.assertArrayEquals(bloom, header.getExtension().getLogsBloom()); + } + + @Test + void logsBloomFieldEncoded() { + byte[] bloom = TestUtils.generateBytes("bloom", 256); + BlockHeaderV1 header = createBlockHeader(bloom); + RLPList extensionDataRLP = RLP.decodeList(header.getExtensionData()); + + byte version = extensionDataRLP.get(0).getRLPData()[0]; + byte[] extensionHash = extensionDataRLP.get(1).getRLPData(); + + Assertions.assertEquals((byte) 0x1, version); + Assertions.assertArrayEquals(header.getExtension().getHash(), extensionHash); + } + + @Test + void logsBloomFieldEncodedIncludesExtensionHash() { + BlockHeaderV1 header = createBlockHeader(TestUtils.generateBytes("bloom", 256)); + BlockHeaderExtensionV1 extension = Mockito.mock(BlockHeaderExtensionV1.class); + byte[] hash = TestUtils.generateHash("hash").getBytes(); + Mockito.when(extension.getHash()).thenReturn(hash); + header.setExtension(extension); + + BlockHeaderV1 otherHeader = createBlockHeader(TestUtils.generateBytes("otherBloom", 256)); + BlockHeaderExtensionV1 otherExtension = Mockito.mock(BlockHeaderExtensionV1.class); + byte[] otherHash = TestUtils.generateHash("otherHash").getBytes(); + Mockito.when(otherExtension.getHash()).thenReturn(otherHash); + otherHeader.setExtension(otherExtension); + + Assertions.assertFalse(Arrays.equals(header.getExtensionData(), otherHeader.getExtensionData())); + } +} diff --git a/rskj-core/src/test/java/co/rsk/core/TransactionIsRemascTest.java b/rskj-core/src/test/java/co/rsk/core/TransactionIsRemascTest.java new file mode 100644 index 00000000000..ef1da7d733d --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/TransactionIsRemascTest.java @@ -0,0 +1,154 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * 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.core; + +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.core.*; +import org.ethereum.crypto.ECKey; +import org.ethereum.crypto.HashUtil; +import org.ethereum.util.ByteUtil; +import org.ethereum.util.RLP; +import org.ethereum.vm.PrecompiledContracts; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TransactionIsRemascTest { + int txPosition = 6; + int txsSize = 7; + RskAddress destination = PrecompiledContracts.REMASC_ADDR; + byte[] data = null; + Coin value = Coin.ZERO; + byte[] gasPrice = Hex.decode("00"); + byte[] gasLimit = Hex.decode("00"); + + private Transaction buildTx( + RskAddress destination, + byte[] data, + Coin value, + byte[] gasPrice, + byte[] gasLimit + ) { + return Transaction.builder() + .destination(destination) + .data(data) + .value(value) + .gasPrice(gasPrice) + .gasLimit(gasLimit) + .build(); + } + + private void assertIsRemascTransaction( + RskAddress destination, + byte[] data, + Coin value, + byte[] gasPrice, + byte[] gasLimit, + int txPosition, + int txsSize + ) { + Transaction tx = buildTx(destination, data, value, gasPrice, gasLimit); + + Assertions.assertTrue(tx.isRemascTransaction(txPosition, txsSize)); + } + + private void assertIsNotRemascTransaction( + Transaction tx, + int txPosition, + int txsSize + ) { + Assertions.assertFalse(tx.isRemascTransaction(txPosition, txsSize)); + } + + private void assertIsNotRemascTransaction( + RskAddress destination, + byte[] data, + Coin value, + byte[] gasPrice, + byte[] gasLimit, + int txPosition, + int txsSize + ) { + Transaction tx = buildTx(destination, data, value, gasPrice, gasLimit); + + assertIsNotRemascTransaction(tx, txPosition, txsSize); + } + + @Test + void validRemascTransactionNullData() { + assertIsRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + @Test + void validRemascTransactionEmptyData() { + byte[] data = {}; + assertIsRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + @Test + void notRemascTransactionNotLastTx() { + int txPosition = 3; + assertIsNotRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + @Test + void notRemascTransactionNotEmptyData() { + byte[] data = { 1, 2, 3, 4 }; + assertIsNotRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + @Test + void notRemascTransactionNotNullSig() { + byte[] senderPrivateKey = HashUtil.keccak256("cow".getBytes()); + Transaction tx = buildTx(destination, data, value, gasPrice, gasLimit); + tx.sign(senderPrivateKey); + + assertIsNotRemascTransaction(tx, txPosition, txsSize); + } + + @Test + void notRemascTransactionReceiverIsNotRemasc() { + byte[] privateKey = HashUtil.keccak256("cat".getBytes()); + ECKey ecKey = ECKey.fromPrivate(privateKey); + RskAddress destination = RLP.parseRskAddress(ByteUtil.cloneBytes(ecKey.getAddress())); + + assertIsNotRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + + @Test + void notRemascTransactionValueIsNotZero() { + Coin value = Coin.valueOf(10); + assertIsNotRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + + @Test + void notRemascTransactionGasPriceIsNotZero() { + byte[] gasPrice = { 10 }; + assertIsNotRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } + + + @Test + void notRemascTransactionGasLimitIsNotZero() { + byte[] gasLimit = { 10 }; + assertIsNotRemascTransaction(destination, data, value, gasPrice, gasLimit, txPosition, txsSize); + } +} + 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..16ae34501ea 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 @@ -15,6 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ + package co.rsk.core.bc; import co.rsk.blockchain.utils.BlockGenerator; @@ -27,10 +28,12 @@ import co.rsk.peg.BridgeSupportFactory; import co.rsk.peg.BtcBlockStoreWithCache.Factory; import co.rsk.peg.RepositoryBtcBlockStoreWithCache; +import co.rsk.remasc.RemascTransaction; import co.rsk.trie.Trie; 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.*; @@ -47,11 +50,13 @@ import org.ethereum.net.server.Channel; import org.ethereum.util.RLP; import org.ethereum.util.RskTestFactory; +import org.ethereum.vm.GasCost; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.api.io.TempDir; import java.math.BigInteger; @@ -59,6 +64,7 @@ import java.util.*; import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP126; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP144; import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -69,33 +75,40 @@ */ public class BlockExecutorTest { private static final byte[] EMPTY_TRIE_HASH = sha3(RLP.encodeElement(EMPTY_BYTE_ARRAY)); - private static final TestSystemProperties CONFIG = new TestSystemProperties(); - private static final BlockFactory BLOCK_FACTORY = new BlockFactory(CONFIG.getActivationConfig()); + private static final boolean RSKIP_126_IS_ACTIVE = true; + private static final long MIN_SEQUENTIAL_SET_GAS_LIMIT = Constants.regtest().getMinSequentialSetGasLimit(); + + private final TestSystemProperties config = new TestSystemProperties(); + private final ActivationConfig activationConfig = spy(config.getActivationConfig()); + private final BlockFactory BLOCK_FACTORY = new BlockFactory(activationConfig); @TempDir public Path tempDir; private Blockchain blockchain; - private BlockExecutor executor; private TrieStore trieStore; private RepositorySnapshot repository; @BeforeEach - void setUp() { - RskTestFactory objects = new RskTestFactory(tempDir, CONFIG); + public void setUp() { + RskTestFactory objects = new RskTestFactory(tempDir, config); blockchain = objects.getBlockchain(); - executor = objects.getBlockExecutor(); trieStore = objects.getTrieStore(); repository = objects.getRepositoryLocator().snapshotAt(blockchain.getBestBlock().getHeader()); } - @Test - void executeBlockWithoutTransaction() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlockWithoutTransaction(Boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); Block parent = blockchain.getBestBlock(); - Block block = new BlockGenerator().createChildBlock(parent); + Block block = new BlockGenerator(Constants.regtest(), activationConfig).createChildBlock(parent); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + BlockResult result = executor.executeForMining(block, parent.getHeader(), false, false, true); - BlockResult result = executor.execute(block, parent.getHeader(), false); + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getTransactionReceipts()); Assertions.assertTrue(result.getTransactionReceipts().isEmpty()); @@ -103,17 +116,22 @@ void executeBlockWithoutTransaction() { Assertions.assertArrayEquals(repository.getRoot(), result.getFinalState().getHash().getBytes()); } - @Test - void executeBlockWithOneTransaction() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlockWithOneTransaction(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); executor.setRegisterProgramResults(false); Block block = getBlockWithOneTransaction(); // this changes the best block Block parent = blockchain.getBestBlock(); Transaction tx = block.getTransactionsList().get(0); RskAddress account = tx.getSender(); + BlockResult result = executor.executeForMining(block, parent.getHeader(), false, false, true); - BlockResult result = executor.execute(block, parent.getHeader(), false); + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getTransactionReceipts()); Assertions.assertFalse(result.getTransactionReceipts().isEmpty()); @@ -150,17 +168,22 @@ void executeBlockWithOneTransaction() { Assertions.assertEquals(BigInteger.valueOf(30000 - 21000 - 10), accountState.getBalance().asBigInteger()); } - @Test - void executeBlockWithOneTransactionAndCollectingProgramResults() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlockWithOneTransactionAndCollectingProgramResults(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); executor.setRegisterProgramResults(true); Block block = getBlockWithOneTransaction(); // this changes the best block Block parent = blockchain.getBestBlock(); Transaction tx = block.getTransactionsList().get(0); RskAddress account = tx.getSender(); + BlockResult result = executor.executeForMining(block, parent.getHeader(), false, false, true); - BlockResult result = executor.execute(block, parent.getHeader(), false); + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getTransactionReceipts()); Assertions.assertFalse(result.getTransactionReceipts().isEmpty()); @@ -198,17 +221,22 @@ void executeBlockWithOneTransactionAndCollectingProgramResults() { Assertions.assertEquals(BigInteger.valueOf(30000 - 21000 - 10), accountState.getBalance().asBigInteger()); } - @Test - void executeBlockWithTwoTransactions() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlockWithTwoTransactions(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); Block block = getBlockWithTwoTransactions(); // this changes the best block Block parent = blockchain.getBestBlock(); Transaction tx1 = block.getTransactionsList().get(0); Transaction tx2 = block.getTransactionsList().get(1); RskAddress account = tx1.getSender(); + BlockResult result = executor.executeForMining(block, parent.getHeader(), false, false, true); - BlockResult result = executor.execute(block, parent.getHeader(), false); + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getTransactionReceipts()); @@ -256,43 +284,50 @@ void executeBlockWithTwoTransactions() { Assertions.assertEquals(BigInteger.valueOf(60000 - 42000 - 20), accountState.getBalance().asBigInteger()); } - @Test - void executeAndFillBlockWithNoSavingToStore() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeAndFillBlockWithNoSavingToStore(boolean activeRskip144) { + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); TrieStore trieStore = objects.getTrieStore(); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); executor.executeAndFill(block, parent.getHeader()); Assertions.assertEquals(Optional.empty(), trieStore.retrieve(block.getStateRoot())); } - @Test - void executeBlockWithSavingToStore() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlockWithSavingToStore(boolean activeRskip144) { + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); TrieStore trieStore = objects.getTrieStore(); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); - BlockResult result = executor.execute(block, parent.getHeader(), false, false, true); + BlockResult result = executor.execute(null, 0, block, parent.getHeader(), false, false, true); Assertions.assertEquals(trieStore.retrieve(block.getStateRoot()), Optional.of(result.getFinalState())); } - @Test - void executeAndFillBlockWithOneTransaction() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeAndFillBlockWithOneTransaction(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); - BlockResult result = executor.execute(block, parent.getHeader(), false); + BlockResult result = executor.executeForMining(block, parent.getHeader(), false, false, true); executor.executeAndFill(block, parent.getHeader()); byte[] calculatedReceiptsRoot = BlockHashesHelper.calculateReceiptsTrieRoot(result.getTransactionReceipts(), true); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertArrayEquals(calculatedReceiptsRoot, block.getReceiptsRoot()); Assertions.assertArrayEquals(result.getFinalState().getHash().getBytes(), block.getStateRoot()); Assertions.assertEquals(result.getGasUsed(), block.getGasUsed()); @@ -302,8 +337,8 @@ void executeAndFillBlockWithOneTransaction() { Assertions.assertEquals(3000000, new BigInteger(1, block.getGasLimit()).longValue()); } - @Test - void executeAndFillBlockWithTxToExcludeBecauseSenderHasNoBalance() { + + private Block createBlockWithExcludedTransaction(boolean withRemasc, boolean activeRskip144) { TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Repository repository = new MutableRepository(new MutableTrieImpl(trieStore, new Trie(trieStore))); @@ -317,7 +352,7 @@ void executeAndFillBlockWithTxToExcludeBecauseSenderHasNoBalance() { Assertions.assertFalse(Arrays.equals(EMPTY_TRIE_HASH, repository.getRoot())); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); Transaction tx3 = Transaction .builder() @@ -325,7 +360,7 @@ void executeAndFillBlockWithTxToExcludeBecauseSenderHasNoBalance() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx3.sign(account.getEcKey().getPrivKeyBytes()); @@ -336,7 +371,7 @@ void executeAndFillBlockWithTxToExcludeBecauseSenderHasNoBalance() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx1.sign(account3.getEcKey().getPrivKeyBytes()); @@ -345,28 +380,54 @@ void executeAndFillBlockWithTxToExcludeBecauseSenderHasNoBalance() { txs.add(tx); txs.add(tx2); + + List expectedTxList = new ArrayList(); + expectedTxList.add(tx); + + if (withRemasc) { + Transaction remascTx = new RemascTransaction(1L); + txs.add(remascTx); + expectedTxList.add(remascTx); + } + List uncles = new ArrayList<>(); - BlockGenerator blockGenerator = new BlockGenerator(); + BlockGenerator blockGenerator = new BlockGenerator(Constants.regtest(), activationConfig); Block genesis = blockGenerator.getGenesisBlock(); genesis.setStateRoot(repository.getRoot()); Block block = blockGenerator.createChildBlock(genesis, txs, uncles, 1, null); executor.executeAndFill(block, genesis.getHeader()); - // Check tx2 was excluded - Assertions.assertEquals(1, block.getTransactionsList().size()); Assertions.assertEquals(tx, block.getTransactionsList().get(0)); Assertions.assertArrayEquals( - calculateTxTrieRoot(Collections.singletonList(tx), block.getNumber()), + calculateTxTrieRoot(expectedTxList, block.getNumber()), block.getTxTrieRoot() ); + return block; + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeAndFillBlockWithTxToExcludeBecauseSenderHasNoBalance(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + Block block = createBlockWithExcludedTransaction(false, activeRskip144); + + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); + // Check tx2 was excluded + + Assertions.assertEquals(1, block.getTransactionsList().size()); + Assertions.assertEquals(3141592, new BigInteger(1, block.getGasLimit()).longValue()); } - @Test - void executeBlockWithTxThatMakesBlockInvalidSenderHasNoBalance() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlockWithTxThatMakesBlockInvalidSenderHasNoBalance(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Repository repository = new MutableRepository(new MutableTrieImpl(trieStore, new Trie(trieStore))); @@ -380,7 +441,7 @@ void executeBlockWithTxThatMakesBlockInvalidSenderHasNoBalance() { Assertions.assertFalse(Arrays.equals(EMPTY_TRIE_HASH, repository.getRoot())); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); Transaction tx3 = Transaction .builder() @@ -388,7 +449,7 @@ void executeBlockWithTxThatMakesBlockInvalidSenderHasNoBalance() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx3.sign(account.getEcKey().getPrivKeyBytes()); @@ -399,7 +460,7 @@ void executeBlockWithTxThatMakesBlockInvalidSenderHasNoBalance() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx1.sign(account3.getEcKey().getPrivKeyBytes()); @@ -410,134 +471,544 @@ void executeBlockWithTxThatMakesBlockInvalidSenderHasNoBalance() { List uncles = new ArrayList<>(); - BlockGenerator blockGenerator = new BlockGenerator(); + BlockGenerator blockGenerator = new BlockGenerator(Constants.regtest(), activationConfig); Block genesis = blockGenerator.getGenesisBlock(); genesis.setStateRoot(repository.getRoot()); Block block = blockGenerator.createChildBlock(genesis, txs, uncles, 1, null); - BlockResult result = executor.execute(block, genesis.getHeader(), false); + BlockResult result = executor.executeForMining(block, genesis.getHeader(), false, false, true); + + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertSame(BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT, result); } - @Test - void validateStateRootWithRskip126DisabledAndValidStateRoot() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeSequentiallyATransactionAndGasShouldBeSubtractedCorrectly(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + long expectedAccumulatedGas = 21000L; + + Block block = getBlockWithNIndependentTransactions(1, BigInteger.valueOf(expectedAccumulatedGas), false); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + + Assertions.assertEquals(block.getTransactionsList(), blockResult.getExecutedTransactions()); + Assertions.assertEquals(expectedAccumulatedGas, blockResult.getGasUsed()); + Assertions.assertArrayEquals(new short[]{1}, blockResult.getTxEdges()); + + List transactionReceipts = blockResult.getTransactionReceipts(); + for (TransactionReceipt receipt: transactionReceipts) { + Assertions.assertEquals(expectedAccumulatedGas, GasCost.toGas(receipt.getCumulativeGas())); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeSequentiallyTenIndependentTxsAndThemShouldGoInBothSublists(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + long txGasLimit = 21000L; + short[] expectedEdges = new short[]{6, 12}; + Block parent = blockchain.getBestBlock(); + int numberOfTxs = 12; + + Block block = getBlockWithNIndependentTransactions(numberOfTxs, BigInteger.valueOf(txGasLimit), false); + List txs = block.getTransactionsList(); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + + Assertions.assertEquals(txs.size(), blockResult.getExecutedTransactions().size()); + Assertions.assertTrue(txs.containsAll(blockResult.getExecutedTransactions())); + Assertions.assertArrayEquals(expectedEdges, blockResult.getTxEdges()); + Assertions.assertEquals(txGasLimit * numberOfTxs, blockResult.getGasUsed()); + + List transactionReceipts = blockResult.getTransactionReceipts(); + long accumulatedGasUsed = 0L; + short i = 0; + short edgeIndex = 0; + for (TransactionReceipt receipt: transactionReceipts) { + boolean isFromADifferentSublist = (edgeIndex < expectedEdges.length) && (i == expectedEdges[edgeIndex]); + if (isFromADifferentSublist) { + edgeIndex++; + accumulatedGasUsed = 0L; + } + + accumulatedGasUsed += txGasLimit; + Assertions.assertEquals(accumulatedGasUsed, GasCost.toGas(receipt.getCumulativeGas())); + i++; + } + + Assertions.assertEquals(i, transactionReceipts.size()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void gasUsedShouldNeverSurprassBlockGasLimit(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + int gasLimit = 21000; + int transactionNumberToFillSequentialSublist = (int) (BlockUtils.getSublistGasLimit(parent, true, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int transactionNumberToFillParallelSublist = (int) (BlockUtils.getSublistGasLimit(parent, false, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int totalNumberOfParallelSublists = Constants.getTransactionExecutionThreads(); + int totalTxs = (transactionNumberToFillParallelSublist * totalNumberOfParallelSublists) + transactionNumberToFillSequentialSublist + 1; + Block block = getBlockWithNIndependentTransactions(totalTxs, BigInteger.valueOf(gasLimit), false); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + Assertions.assertFalse(block.getGasUsed() > GasCost.toGas(block.getGasLimit())); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void whenParallelSublistsAreFullTheLastTxShouldGoToSequential(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + int gasLimit = 21000; + int numberOfTransactions = (int) (BlockUtils.getSublistGasLimit(parent, false, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + short[] expectedEdges = new short[]{(short) numberOfTransactions, (short) (numberOfTransactions*2)}; + int transactionsInSequential = 1; + Block block = getBlockWithNIndependentTransactions(numberOfTransactions * Constants.getTransactionExecutionThreads() + transactionsInSequential, BigInteger.valueOf(gasLimit), false); + List transactionsList = block.getTransactionsList(); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + + Assertions.assertArrayEquals(expectedEdges, blockResult.getTxEdges()); + Assertions.assertEquals(transactionsList.size(), blockResult.getExecutedTransactions().size()); + Assertions.assertTrue(transactionsList.containsAll(blockResult.getExecutedTransactions())); + + List transactionReceipts = blockResult.getTransactionReceipts(); + long accumulatedGasUsed = 0L; + short i = 0; + short edgeIndex = 0; + for (TransactionReceipt receipt: transactionReceipts) { + accumulatedGasUsed += gasLimit; + + if ((edgeIndex < expectedEdges.length) && (i == expectedEdges[edgeIndex])) { + edgeIndex++; + accumulatedGasUsed = gasLimit; + } + Assertions.assertEquals(accumulatedGasUsed, GasCost.toGas(receipt.getCumulativeGas())); + i++; + } + + Assertions.assertEquals(i, transactionReceipts.size()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeATxInSequentialAndBlockResultShouldTrackTheGasUsedInTheBlock(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + int gasLimit = 21000; + int transactionNumberToFillParallelSublist = (int) (BlockUtils.getSublistGasLimit(parent, false, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int transactionsInSequential = 1; + int totalTxsNumber = transactionNumberToFillParallelSublist * Constants.getTransactionExecutionThreads() + transactionsInSequential; + Block block = getBlockWithNIndependentTransactions(totalTxsNumber, BigInteger.valueOf(gasLimit), false); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + + Assertions.assertEquals(gasLimit * totalTxsNumber, blockResult.getGasUsed()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void withTheSublistsFullTheLastTransactionShouldNotFit(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + int gasLimit = 21000; + int transactionNumberToFillSequentialSublist = (int) (BlockUtils.getSublistGasLimit(parent, true, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int transactionNumberToFillParallelSublist = (int) (BlockUtils.getSublistGasLimit(parent, false, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int totalNumberOfSublists = Constants.getTransactionExecutionThreads(); + int totalTxs = (transactionNumberToFillParallelSublist * totalNumberOfSublists) + transactionNumberToFillSequentialSublist + 1; + Block block = getBlockWithNIndependentTransactions(totalTxs, BigInteger.valueOf(gasLimit), false); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + Assertions.assertEquals(totalTxs - 1, blockResult.getExecutedTransactions().size()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void withSequentialSublistFullRemascTxShouldFit(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + int gasLimit = 21000; + int transactionNumberToFillSequentialSublist = (int) (BlockUtils.getSublistGasLimit(parent, true, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int transactionNumberToFillParallelSublist = (int) (BlockUtils.getSublistGasLimit(parent, false, MIN_SEQUENTIAL_SET_GAS_LIMIT) / gasLimit); + int totalNumberOfParallelSublists = Constants.getTransactionExecutionThreads(); + int expectedNumberOfTx = (transactionNumberToFillParallelSublist * totalNumberOfParallelSublists) + transactionNumberToFillSequentialSublist + 1; + + Block block = getBlockWithNIndependentTransactions(expectedNumberOfTx, BigInteger.valueOf(gasLimit), true); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + Assertions.assertEquals(expectedNumberOfTx, blockResult.getExecutedTransactions().size()); + } + + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeParallelBlocksWithDifferentSubsets(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + + doReturn(true).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + Block block1 = getBlockWithTenTransactions(new short[]{4, 8}); + BlockResult result1 = executor.execute(null, 0, block1, parent.getHeader(), true, false, true); + + + Block block2 = getBlockWithTenTransactions(new short[]{5}); + BlockResult result2 = executor.execute(null, 0, block2, parent.getHeader(), true, false, true); + + Assertions.assertArrayEquals(result2.getFinalState().getHash().getBytes(), result1.getFinalState().getHash().getBytes()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeParallelBlockAgainstSequentialBlock(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + + doReturn(true).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + Block pBlock = getBlockWithTenTransactions(new short[]{4, 8}); + BlockResult parallelResult = executor.execute(null, 0, pBlock, parent.getHeader(), true, false, true); + + + Block sBlock = getBlockWithTenTransactions(null); + BlockResult seqResult = executor.executeForMining(sBlock, parent.getHeader(), true, false, true); + + Assertions.assertEquals(pBlock.getTransactionsList().size(), parallelResult.getExecutedTransactions().size()); + Assertions.assertArrayEquals(seqResult.getFinalState().getHash().getBytes(), parallelResult.getFinalState().getHash().getBytes()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeInvalidParallelBlockDueToCollision(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + Block pBlock = getBlockWithTwoDependentTransactions(new short[]{1, 2}); + BlockResult result = executor.execute(null, 0, pBlock, parent.getHeader(), true, false, true); + Assertions.assertEquals(BlockResult.INTERRUPTED_EXECUTION_BLOCK_RESULT, result); + } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void whenExecuteATxWithGasLimitExceedingSublistGasLimitShouldNotBeInlcuded(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + + + Repository track = repository.startTracking(); + Account sender = createAccount("sender", track, Coin.valueOf(6000000)); + Account receiver = createAccount("receiver", track, Coin.valueOf(6000000)); + + track.commit(); + parent.setStateRoot(repository.getRoot()); + + List txs = new LinkedList<>(); + Transaction tx = Transaction.builder() + .nonce(BigInteger.ZERO) + .gasPrice(BigInteger.ONE) + .gasLimit(parent.getGasLimit()) + .destination(receiver.getAddress()) + .chainId(config.getNetworkConstants().getChainId()) + .value(BigInteger.TEN) + .build(); + tx.sign(sender.getEcKey().getPrivKeyBytes()); + txs.add(tx); + List uncles = new ArrayList<>(); + + Block block = new BlockGenerator(Constants.regtest(), activationConfig) + .createChildBlock( + parent, + txs, + uncles, + 1, + null, + parent.getGasLimit(), + parent.getCoinbase(), + new short[]{1} + ); + + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + Assertions.assertEquals(0, blockResult.getExecutedTransactions().size()); + + BlockResult result = executor.execute(null, 0, block, parent.getHeader(), true, false, true); + Assertions.assertEquals(0, result.getExecutedTransactions().size()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void ifThereIsACollisionBetweenParallelAndSequentialSublistsTxShouldNotBeConsidered(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + Block pBlock = getBlockWithTwoDependentTransactions(new short[]{1}); + BlockResult result = executor.execute(null, 0, pBlock, parent.getHeader(), true, false, true); + Assertions.assertTrue(pBlock.getTransactionsList().containsAll(result.getExecutedTransactions())); + Assertions.assertEquals(pBlock.getTransactionsList().size(), result.getExecutedTransactions().size()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeParallelBlockTwice(boolean activeRskip144) { + if (!activeRskip144) { + return; + } + + doReturn(true).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + Block parent = blockchain.getBestBlock(); + Block block1 = getBlockWithTenTransactions(new short[]{4, 8}); + BlockResult result1 = executor.execute(null, 0, block1, parent.getHeader(), true, false, true); + + + Block block2 = getBlockWithTenTransactions(new short[]{4, 8}); + BlockResult result2 = executor.execute(null, 0, block2, parent.getHeader(), true, false, true); + + Assertions.assertArrayEquals(result2.getFinalState().getHash().getBytes(), result1.getFinalState().getHash().getBytes()); + Assertions.assertArrayEquals(block1.getHash().getBytes(), block2.getHash().getBytes()); + } + + private void testBlockWithTxTxEdgesMatchAndRemascTxIsAtLastPosition (int txAmount, short [] expectedSublistsEdges, Boolean activeRskip144) { + Block block = getBlockWithNIndependentTransactions(txAmount, BigInteger.valueOf(21000), true); + + assertBlockResultHasTxEdgesAndRemascAtLastPosition(block, txAmount, expectedSublistsEdges, activeRskip144); + } + + private void assertBlockResultHasTxEdgesAndRemascAtLastPosition (Block block, int txAmount, short [] expectedSublistsEdges, Boolean activeRskip144) { + Block parent = blockchain.getBestBlock(); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); + BlockResult blockResult = executor.executeAndFill(block, parent.getHeader()); + + int expectedTxSize = txAmount + 1; + + Assertions.assertArrayEquals(expectedSublistsEdges, blockResult.getTxEdges()); + Assertions.assertEquals(expectedTxSize, blockResult.getExecutedTransactions().size()); + Assertions.assertTrue(blockResult.getExecutedTransactions().get(txAmount).isRemascTransaction(txAmount, expectedTxSize)); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void blockWithOnlyRemascShouldGoToSequentialSublist (boolean activeRskip144) { + if (!activeRskip144) return; + testBlockWithTxTxEdgesMatchAndRemascTxIsAtLastPosition(0, new short[]{}, activeRskip144); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void blockWithOneTxRemascShouldGoToSequentialSublist (boolean activeRskip144) { + if (!activeRskip144) return; + testBlockWithTxTxEdgesMatchAndRemascTxIsAtLastPosition(1, new short[]{ 1 }, activeRskip144); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void blockWithManyTxsRemascShouldGoToSequentialSublist (boolean activeRskip144) { + if (!activeRskip144) return; + testBlockWithTxTxEdgesMatchAndRemascTxIsAtLastPosition(2, new short[]{ 1, 2 }, activeRskip144); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void blockWithMoreThanThreadsTxsRemascShouldGoToSequentialSublist (boolean activeRskip144) { + if (!activeRskip144) return; + testBlockWithTxTxEdgesMatchAndRemascTxIsAtLastPosition(3, new short[]{ 2, 3 }, activeRskip144); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void blockWithExcludedTransactionHasRemascInSequentialSublist (boolean activeRskip144) { + if (!activeRskip144) return; + Block block = createBlockWithExcludedTransaction(true, activeRskip144); + assertBlockResultHasTxEdgesAndRemascAtLastPosition(block, 0, new short[]{}, activeRskip144); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void validateStateRootWithRskip126DisabledAndValidStateRoot(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Trie trie = new Trie(trieStore); - Block block = new BlockGenerator().getBlock(1); + Block block = new BlockGenerator(Constants.regtest(), activationConfig).getBlock(1); block.setStateRoot(trie.getHash().getBytes()); - BlockResult blockResult = new BlockResult(block, Collections.emptyList(), Collections.emptyList(), 0, + BlockResult blockResult = new BlockResult(block, Collections.emptyList(), Collections.emptyList(), new short[0], 0, Coin.ZERO, trie); - RskSystemProperties cfg = spy(CONFIG); - - ActivationConfig activationConfig = spy(cfg.getActivationConfig()); - doReturn(false).when(activationConfig).isActive(eq(RSKIP126), anyLong()); - doReturn(activationConfig).when(cfg).getActivationConfig(); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, false); - BlockExecutor executor = buildBlockExecutor(trieStore, cfg); + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertTrue(executor.validateStateRoot(block.getHeader(), blockResult)); } - @Test - void validateStateRootWithRskip126DisabledAndInvalidStateRoot() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void validateStateRootWithRskip126DisabledAndInvalidStateRoot(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Trie trie = new Trie(trieStore); - Block block = new BlockGenerator().getBlock(1); + Block block = new BlockGenerator(Constants.regtest(), activationConfig).getBlock(1); block.setStateRoot(new byte[] { 1, 2, 3, 4 }); - BlockResult blockResult = new BlockResult(block, Collections.emptyList(), Collections.emptyList(), 0, + BlockResult blockResult = new BlockResult(block, Collections.emptyList(), Collections.emptyList(), new short[0], 0, Coin.ZERO, trie); - RskSystemProperties cfg = spy(CONFIG); +// RskSystemProperties cfg = spy(CONFIG); - ActivationConfig activationConfig = spy(cfg.getActivationConfig()); - doReturn(false).when(activationConfig).isActive(eq(RSKIP126), anyLong()); - doReturn(activationConfig).when(cfg).getActivationConfig(); +// ActivationConfig activationConfig = spy(cfg.getActivationConfig()); + boolean rskip126IsActive = false; +// doReturn(activationConfig).when(cfg).getActivationConfig(); + + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, rskip126IsActive); - BlockExecutor executor = buildBlockExecutor(trieStore, cfg); + short[] expectedEdges = activeRskip144 ? new short[0] : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertTrue(executor.validateStateRoot(block.getHeader(), blockResult)); } - @Test - void validateBlock() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void validateBlock(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertTrue(executor.executeAndValidate(block, parent.getHeader())); } - @Test - void invalidBlockBadStateRoot() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void invalidBlockBadStateRoot(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); byte[] stateRoot = block.getStateRoot(); stateRoot[0] = (byte) ((stateRoot[0] + 1) % 256); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertFalse(executor.executeAndValidate(block, parent.getHeader())); } - @Test - void invalidBlockBadReceiptsRoot() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void invalidBlockBadReceiptsRoot(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); byte[] receiptsRoot = block.getReceiptsRoot(); receiptsRoot[0] = (byte) ((receiptsRoot[0] + 1) % 256); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertFalse(executor.executeAndValidate(block, parent.getHeader())); } - @Test - void invalidBlockBadGasUsed() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void invalidBlockBadGasUsed(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); block.getHeader().setGasUsed(0); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertFalse(executor.executeAndValidate(block, parent.getHeader())); } - @Test - void invalidBlockBadPaidFees() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void invalidBlockBadPaidFees(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); block.getHeader().setPaidFees(Coin.ZERO); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertFalse(executor.executeAndValidate(block, parent.getHeader())); } - @Test - void invalidBlockBadLogsBloom() { - TestObjects objects = generateBlockWithOneTransaction(); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void invalidBlockBadLogsBloom(boolean activeRskip144) { + doReturn(activeRskip144).when(activationConfig).isActive(eq(ConsensusRule.RSKIP144), anyLong()); + TestObjects objects = generateBlockWithOneTransaction(activeRskip144, RSKIP_126_IS_ACTIVE); Block parent = objects.getParent(); Block block = objects.getBlock(); - BlockExecutor executor = buildBlockExecutor(objects.getTrieStore()); + BlockExecutor executor = buildBlockExecutor(objects.getTrieStore(), activeRskip144, RSKIP_126_IS_ACTIVE); byte[] logBloom = block.getLogBloom(); logBloom[0] = (byte) ((logBloom[0] + 1) % 256); + short[] expectedEdges = activeRskip144 ? new short[]{(short) block.getTransactionsList().size()} : null; + Assertions.assertArrayEquals(expectedEdges, block.getHeader().getTxExecutionSublistsEdges()); Assertions.assertFalse(executor.executeAndValidate(block, parent.getHeader())); } - private static TestObjects generateBlockWithOneTransaction() { + private TestObjects generateBlockWithOneTransaction(Boolean activeRskip144, boolean rskip126IsActive) { TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Repository repository = new MutableRepository(trieStore, new Trie(trieStore)); @@ -550,7 +1021,7 @@ private static TestObjects generateBlockWithOneTransaction() { Assertions.assertFalse(Arrays.equals(EMPTY_TRIE_HASH, repository.getRoot())); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, rskip126IsActive); Transaction tx1 = Transaction .builder() @@ -558,7 +1029,7 @@ private static TestObjects generateBlockWithOneTransaction() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx1.sign(account.getEcKey().getPrivKeyBytes()); @@ -578,7 +1049,7 @@ private static TestObjects generateBlockWithOneTransaction() { // in genesis. byte[] rootPriorExecution = repository.getRoot(); - Block block = new BlockGenerator().createChildBlock(genesis, txs, uncles, 1, null); + Block block = new BlockGenerator(Constants.regtest(), activationConfig).createChildBlock(genesis, txs, uncles, 1, null); executor.executeAndFill(block, genesis.getHeader()); repository.save(); @@ -605,7 +1076,7 @@ private Block getBlockWithOneTransaction() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx.sign(account.getEcKey().getPrivKeyBytes()); @@ -614,7 +1085,7 @@ private Block getBlockWithOneTransaction() { ); List uncles = new ArrayList<>(); - return new BlockGenerator().createChildBlock(bestBlock, txs, uncles, 1, null); + return new BlockGenerator(Constants.regtest(), activationConfig).createChildBlock(bestBlock, txs, uncles, 1, null); } private Block getBlockWithTwoTransactions() { @@ -638,7 +1109,7 @@ private Block getBlockWithTwoTransactions() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx.sign(account.getEcKey().getPrivKeyBytes()); @@ -648,7 +1119,7 @@ private Block getBlockWithTwoTransactions() { .gasPrice(BigInteger.ONE) .gasLimit(BigInteger.valueOf(21000)) .destination(account2.getAddress()) - .chainId(CONFIG.getNetworkConstants().getChainId()) + .chainId(config.getNetworkConstants().getChainId()) .value(BigInteger.TEN) .build(); tx1.sign(account.getEcKey().getPrivKeyBytes()); @@ -658,7 +1129,137 @@ private Block getBlockWithTwoTransactions() { ); List uncles = new ArrayList<>(); - return new BlockGenerator().createChildBlock(bestBlock, txs, uncles, 1, null); + return new BlockGenerator(Constants.regtest(), activationConfig).createChildBlock(bestBlock, txs, uncles, 1, null); + } + + private Block getBlockWithTwoDependentTransactions(short[] edges) { + int nTxs = 2; + + Repository track = repository.startTracking(); + List accounts = new LinkedList<>(); + + for (int i = 0; i < nTxs; i++) { + accounts.add(createAccount("accounttest" + i, track, Coin.valueOf(60000))); + } + track.commit(); + Block bestBlock = blockchain.getBestBlock(); + bestBlock.setStateRoot(repository.getRoot()); + + List txs = new LinkedList<>(); + + for (int i = 0; i < nTxs; i++) { + Transaction tx = Transaction.builder() + .nonce(BigInteger.ZERO) + .gasPrice(BigInteger.ONE) + .gasLimit(BigInteger.valueOf(21000)) + .destination(accounts.get((i + 1) % 2).getAddress()) + .chainId(config.getNetworkConstants().getChainId()) + .value(BigInteger.TEN) + .build(); + tx.sign(accounts.get(i).getEcKey().getPrivKeyBytes()); + txs.add(tx); + } + List uncles = new ArrayList<>(); + + return new BlockGenerator(Constants.regtest(), activationConfig) + .createChildBlock( + bestBlock, + txs, + uncles, + 1, + null, + bestBlock.getGasLimit(), + bestBlock.getCoinbase(), + edges + ); + } + + private Block getBlockWithTenTransactions(short[] edges) { + int nTxs = 10; + int nAccounts = nTxs * 2; + Repository track = repository.startTracking(); + List accounts = new LinkedList<>(); + + for (int i = 0; i < nAccounts; i++) { + accounts.add(createAccount("accounttest" + i, track, Coin.valueOf(60000))); + } + track.commit(); + Block bestBlock = blockchain.getBestBlock(); + bestBlock.setStateRoot(repository.getRoot()); + + List txs = new LinkedList<>(); + + for (int i = 0; i < nTxs; i++) { + Transaction tx = Transaction.builder() + .nonce(BigInteger.ZERO) + .gasPrice(BigInteger.ONE) + .gasLimit(BigInteger.valueOf(21000)) + .destination(accounts.get(i + nTxs).getAddress()) + .chainId(config.getNetworkConstants().getChainId()) + .value(BigInteger.TEN) + .build(); + tx.sign(accounts.get(i).getEcKey().getPrivKeyBytes()); + txs.add(tx); + } + List uncles = new ArrayList<>(); + + return new BlockGenerator(Constants.regtest(), activationConfig) + .createChildBlock( + bestBlock, + txs, + uncles, + 1, + null, + bestBlock.getGasLimit(), + bestBlock.getCoinbase(), + edges + ); + } + + private Block getBlockWithNIndependentTransactions(int numberOfTxs, BigInteger txGasLimit, boolean withRemasc) { + int nAccounts = numberOfTxs * 2; + Repository track = repository.startTracking(); + List accounts = new LinkedList<>(); + + for (int i = 0; i < nAccounts; i++) { + accounts.add(createAccount("accounttest" + i, track, Coin.valueOf(600000))); + } + track.commit(); + Block bestBlock = blockchain.getBestBlock(); + bestBlock.setStateRoot(repository.getRoot()); + + List txs = new LinkedList<>(); + + for (int i = 0; i < numberOfTxs; i++) { + Transaction tx = Transaction.builder() + .nonce(BigInteger.ZERO) + .gasPrice(BigInteger.ONE) + .gasLimit(txGasLimit) + .destination(accounts.get(i + numberOfTxs).getAddress()) + .chainId(config.getNetworkConstants().getChainId()) + .value(BigInteger.TEN) + .build(); + tx.sign(accounts.get(i).getEcKey().getPrivKeyBytes()); + txs.add(tx); + } + + if (withRemasc) { + txs.add(new RemascTransaction(1L)); + } + + List uncles = new ArrayList<>(); + + return new BlockGenerator(Constants.regtest(), activationConfig) + .createChildBlock( + bestBlock, + txs, + uncles, + 1, + null, + bestBlock.getGasLimit(), + bestBlock.getCoinbase(), + null + ); } public static Account createAccount(String seed, Repository repository, Coin balance) { @@ -678,32 +1279,36 @@ public static Account createAccount(String seed) { ////////////////////////////////////////////// // Testing strange Txs ///////////////////////////////////////////// - @Test - void executeBlocksWithOneStrangeTransactions1() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlocksWithOneStrangeTransactions1(Boolean activeRskip144) { // will fail to create an address that is not 20 bytes long - Assertions.assertThrows(RuntimeException.class, () -> generateBlockWithOneStrangeTransaction(0)); + Assertions.assertThrows(RuntimeException.class, () -> generateBlockWithOneStrangeTransaction(0, activeRskip144)); } - @Test - void executeBlocksWithOneStrangeTransactions2() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlocksWithOneStrangeTransactions2(Boolean activeRskip144) { // will fail to create an address that is not 20 bytes long - Assertions.assertThrows(RuntimeException.class, () -> generateBlockWithOneStrangeTransaction(1)); + Assertions.assertThrows(RuntimeException.class, () -> generateBlockWithOneStrangeTransaction(1, activeRskip144)); } - @Test - void executeBlocksWithOneStrangeTransactions3() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void executeBlocksWithOneStrangeTransactions3(Boolean activeRskip144) { // the wrongly-encoded value parameter will be re-encoded with the correct serialization and won't fail - executeBlockWithOneStrangeTransaction(false, false, generateBlockWithOneStrangeTransaction(2)); + executeBlockWithOneStrangeTransaction(false, false, generateBlockWithOneStrangeTransaction(2, activeRskip144), activeRskip144); } private void executeBlockWithOneStrangeTransaction( boolean mustFailValidation, boolean mustFailExecution, - TestObjects objects) { + TestObjects objects, + Boolean activeRskip144) { Block parent = objects.getParent(); Block block = objects.getBlock(); TrieStore trieStore = objects.getTrieStore(); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); Repository repository = new MutableRepository(trieStore, trieStore.retrieve(objects.getParent().getStateRoot()).get()); Transaction tx = objects.getTransaction(); @@ -721,7 +1326,7 @@ private void executeBlockWithOneStrangeTransaction( return; } - BlockResult result = executor.execute(block, parent.getHeader(), false); + BlockResult result = executor.executeForMining(block, parent.getHeader(), false, false, true); Assertions.assertNotNull(result); if (mustFailExecution) { @@ -761,7 +1366,7 @@ private void executeBlockWithOneStrangeTransaction( Assertions.assertEquals(BigInteger.valueOf(30000 - 21000 - 10), accountState.getBalance().asBigInteger()); } - public TestObjects generateBlockWithOneStrangeTransaction(int strangeTransactionType) { + public TestObjects generateBlockWithOneStrangeTransaction(int strangeTransactionType, Boolean activeRskip144) { TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); Repository repository = new MutableRepository(trieStore, new Trie(trieStore)); Repository track = repository.startTracking(); @@ -773,7 +1378,7 @@ public TestObjects generateBlockWithOneStrangeTransaction(int strangeTransaction Assertions.assertFalse(Arrays.equals(EMPTY_TRIE_HASH, repository.getRoot())); - BlockExecutor executor = buildBlockExecutor(trieStore); + BlockExecutor executor = buildBlockExecutor(trieStore, activeRskip144, RSKIP_126_IS_ACTIVE); List txs = new ArrayList<>(); Transaction tx = createStrangeTransaction( @@ -789,7 +1394,7 @@ public TestObjects generateBlockWithOneStrangeTransaction(int strangeTransaction Block genesis = BlockChainImplTest.getGenesisBlock(trieStore); genesis.setStateRoot(repository.getRoot()); - Block block = new BlockGenerator().createChildBlock(genesis, txs, uncles, 1, null); + Block block = new BlockGenerator(Constants.regtest(), activationConfig).createChildBlock(genesis, txs, uncles, 1, null); executor.executeAndFillReal(block, genesis.getHeader()); // Forces all transactions included repository.save(); @@ -800,7 +1405,7 @@ public TestObjects generateBlockWithOneStrangeTransaction(int strangeTransaction private byte[] calculateTxTrieRoot(List transactions, long blockNumber) { return BlockHashesHelper.getTxTrieRoot( transactions, - CONFIG.getActivationConfig().isActive(ConsensusRule.RSKIP126, blockNumber) + config.getActivationConfig().isActive(ConsensusRule.RSKIP126, blockNumber) ); } @@ -842,34 +1447,39 @@ private static byte[] sha3(byte[] input) { return digest.digest(); } - private static BlockExecutor buildBlockExecutor(TrieStore store) { - return buildBlockExecutor(store, CONFIG); + private BlockExecutor buildBlockExecutor(TrieStore store, Boolean activeRskip144, boolean rskip126IsActive) { + return buildBlockExecutor(store, config, activeRskip144, rskip126IsActive); } - private static BlockExecutor buildBlockExecutor(TrieStore store, RskSystemProperties config) { - StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); + private BlockExecutor buildBlockExecutor(TrieStore store, RskSystemProperties config, Boolean activeRskip144, Boolean activeRskip126) { + RskSystemProperties cfg = spy(config); + doReturn(activationConfig).when(cfg).getActivationConfig(); + doReturn(activeRskip144).when(activationConfig).isActive(eq(RSKIP144), anyLong()); + doReturn(activeRskip126).when(activationConfig).isActive(eq(RSKIP126), anyLong()); + + + StateRootHandler stateRootHandler = new StateRootHandler(cfg.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory( - config.getNetworkConstants().getBridgeConstants().getBtcParams()); + cfg.getNetworkConstants().getBridgeConstants().getBtcParams()); BridgeSupportFactory bridgeSupportFactory = new BridgeSupportFactory( - btcBlockStoreFactory, config.getNetworkConstants().getBridgeConstants(), config.getActivationConfig(), new BlockTxSignatureCache(new ReceivedTxSignatureCache())); + btcBlockStoreFactory, cfg.getNetworkConstants().getBridgeConstants(), cfg.getActivationConfig(), new BlockTxSignatureCache(new ReceivedTxSignatureCache())); BlockTxSignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); return new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(store, stateRootHandler), new TransactionExecutorFactory( - config, + cfg, null, null, BLOCK_FACTORY, new ProgramInvokeFactoryImpl(), - new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), + new PrecompiledContracts(cfg, bridgeSupportFactory, signatureCache), signatureCache - ) - ); + ), + cfg); } public static class TestObjects { diff --git a/rskj-core/src/test/java/co/rsk/core/bc/BlockUtilsTest.java b/rskj-core/src/test/java/co/rsk/core/bc/BlockUtilsTest.java index fef07ce4437..3235c99bc97 100644 --- a/rskj-core/src/test/java/co/rsk/core/bc/BlockUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/BlockUtilsTest.java @@ -23,8 +23,8 @@ import co.rsk.net.NetBlockStore; import co.rsk.test.builders.BlockBuilder; import co.rsk.test.builders.BlockChainBuilder; +import org.ethereum.config.Constants; import org.ethereum.core.*; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.math.BigInteger; @@ -32,6 +32,10 @@ import java.util.List; import java.util.Set; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + /** * Created by ajlopez on 19/08/2016. */ @@ -53,11 +57,11 @@ void blockInSomeBlockChain() { blockChain.tryToConnect(block1); blockChain.tryToConnect(block1b); - Assertions.assertTrue(BlockUtils.blockInSomeBlockChain(genesis, blockChain)); - Assertions.assertTrue(BlockUtils.blockInSomeBlockChain(block1, blockChain)); - Assertions.assertTrue(BlockUtils.blockInSomeBlockChain(block1b, blockChain)); - Assertions.assertFalse(BlockUtils.blockInSomeBlockChain(block2, blockChain)); - Assertions.assertTrue(BlockUtils.blockInSomeBlockChain(block3, blockChain)); + assertTrue(BlockUtils.blockInSomeBlockChain(genesis, blockChain)); + assertTrue(BlockUtils.blockInSomeBlockChain(block1, blockChain)); + assertTrue(BlockUtils.blockInSomeBlockChain(block1b, blockChain)); + assertFalse(BlockUtils.blockInSomeBlockChain(block2, blockChain)); + assertTrue(BlockUtils.blockInSomeBlockChain(block3, blockChain)); } @Test @@ -74,37 +78,37 @@ void unknowAncestorsHashes() { store.saveBlock(block3); - Assertions.assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); - Assertions.assertEquals(ImportResult.IMPORTED_NOT_BEST, blockChain.tryToConnect(block1b)); + assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); + assertEquals(ImportResult.IMPORTED_NOT_BEST, blockChain.tryToConnect(block1b)); Set hashes = BlockUtils.unknownAncestorsHashes(genesis.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertTrue(hashes.isEmpty()); + assertNotNull(hashes); + assertTrue(hashes.isEmpty()); hashes = BlockUtils.unknownAncestorsHashes(block1.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertTrue(hashes.isEmpty()); + assertNotNull(hashes); + assertTrue(hashes.isEmpty()); hashes = BlockUtils.unknownAncestorsHashes(block1b.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertTrue(hashes.isEmpty()); + assertNotNull(hashes); + assertTrue(hashes.isEmpty()); hashes = BlockUtils.unknownAncestorsHashes(block2.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertFalse(hashes.isEmpty()); - Assertions.assertEquals(1, hashes.size()); - Assertions.assertTrue(hashes.contains(block2.getHash())); + assertNotNull(hashes); + assertFalse(hashes.isEmpty()); + assertEquals(1, hashes.size()); + assertTrue(hashes.contains(block2.getHash())); hashes = BlockUtils.unknownAncestorsHashes(block3.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertFalse(hashes.isEmpty()); - Assertions.assertEquals(1, hashes.size()); - Assertions.assertTrue(hashes.contains(block2.getHash())); + assertNotNull(hashes); + assertFalse(hashes.isEmpty()); + assertEquals(1, hashes.size()); + assertTrue(hashes.contains(block2.getHash())); } @Test @@ -136,46 +140,85 @@ void unknowAncestorsHashesUsingUncles() { Set hashes = BlockUtils.unknownAncestorsHashes(genesis.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertTrue(hashes.isEmpty()); + assertNotNull(hashes); + assertTrue(hashes.isEmpty()); hashes = BlockUtils.unknownAncestorsHashes(block1.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertTrue(hashes.isEmpty()); + assertNotNull(hashes); + assertTrue(hashes.isEmpty()); hashes = BlockUtils.unknownAncestorsHashes(block1b.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); + assertNotNull(hashes); - Assertions.assertTrue(hashes.isEmpty()); + assertTrue(hashes.isEmpty()); hashes = BlockUtils.unknownAncestorsHashes(block2.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertFalse(hashes.isEmpty()); - Assertions.assertEquals(1, hashes.size()); - Assertions.assertTrue(hashes.contains(block2.getHash())); + assertNotNull(hashes); + assertFalse(hashes.isEmpty()); + assertEquals(1, hashes.size()); + assertTrue(hashes.contains(block2.getHash())); hashes = BlockUtils.unknownAncestorsHashes(block3.getHash(), blockChain, store); - Assertions.assertNotNull(hashes); - Assertions.assertFalse(hashes.isEmpty()); - Assertions.assertEquals(3, hashes.size()); - Assertions.assertTrue(hashes.contains(block2.getHash())); - Assertions.assertTrue(hashes.contains(uncle1.getHash())); - Assertions.assertTrue(hashes.contains(uncle2.getHash())); + assertNotNull(hashes); + assertFalse(hashes.isEmpty()); + assertEquals(3, hashes.size()); + assertTrue(hashes.contains(block2.getHash())); + assertTrue(hashes.contains(uncle1.getHash())); + assertTrue(hashes.contains(uncle2.getHash())); } @Test void tooMuchProcessTime() { - Assertions.assertFalse(BlockUtils.tooMuchProcessTime(0)); - Assertions.assertFalse(BlockUtils.tooMuchProcessTime(1000)); - Assertions.assertFalse(BlockUtils.tooMuchProcessTime(1_000_000L)); - Assertions.assertFalse(BlockUtils.tooMuchProcessTime(1_000_000_000L)); - Assertions.assertFalse(BlockUtils.tooMuchProcessTime(60_000_000_000L)); - - Assertions.assertTrue(BlockUtils.tooMuchProcessTime(60_000_000_001L)); - Assertions.assertTrue(BlockUtils.tooMuchProcessTime(1_000_000_000_000L)); + assertFalse(BlockUtils.tooMuchProcessTime(0)); + assertFalse(BlockUtils.tooMuchProcessTime(1000)); + assertFalse(BlockUtils.tooMuchProcessTime(1_000_000L)); + assertFalse(BlockUtils.tooMuchProcessTime(1_000_000_000L)); + assertFalse(BlockUtils.tooMuchProcessTime(60_000_000_000L)); + + assertTrue(BlockUtils.tooMuchProcessTime(60_000_000_001L)); + assertTrue(BlockUtils.tooMuchProcessTime(1_000_000_000_000L)); + } + + @Test + void sublistGasLimit_ShouldDivideGasLimitEquallyAmongAllSets() { + long minSequentialSetGasLimit = Constants.regtest().getMinSequentialSetGasLimit(); + long mockedBlockGasLimit = 9_000_000L; + Block block = mock(Block.class); + when(block.getGasLimit()).thenReturn(BigInteger.valueOf(mockedBlockGasLimit).toByteArray()); + + long expectedLimit = mockedBlockGasLimit / (Constants.getTransactionExecutionThreads() + 1); + assertEquals(expectedLimit, BlockUtils.getSublistGasLimit(block, false, minSequentialSetGasLimit)); + assertEquals(expectedLimit, BlockUtils.getSublistGasLimit(block, true, minSequentialSetGasLimit)); + } + + @Test + void sublistGasLimit_ShouldAssignLessGasLimitToParallelSets() { + long minSequentialSetGasLimit = 6_800_000L; + long mockedBlockGasLimit = 10_000_000L; + Block block = mock(Block.class); + when(block.getGasLimit()).thenReturn(BigInteger.valueOf(mockedBlockGasLimit).toByteArray()); + + assertEquals(minSequentialSetGasLimit, BlockUtils.getSublistGasLimit(block, true, minSequentialSetGasLimit)); + + long expectedParallelLimit = (mockedBlockGasLimit - minSequentialSetGasLimit) / (Constants.getTransactionExecutionThreads()); + assertEquals(expectedParallelLimit, BlockUtils.getSublistGasLimit(block, false, minSequentialSetGasLimit)); + } + + @Test + void sublistGasLimit_ShouldAssignExtraGasLimitToSequentialSet() { + long minSequentialSetGasLimit = Constants.regtest().getMinSequentialSetGasLimit(); + long mockedBlockGasLimit = 10_000_010L; + Block block = mock(Block.class); + when(block.getGasLimit()).thenReturn(BigInteger.valueOf(mockedBlockGasLimit).toByteArray()); + + long expectedSequentialLimit = 3_333_338L; + assertEquals(expectedSequentialLimit, BlockUtils.getSublistGasLimit(block, true, minSequentialSetGasLimit)); + + long expectedParallelLimit = 3_333_336L; + assertEquals(expectedParallelLimit, BlockUtils.getSublistGasLimit(block, false, minSequentialSetGasLimit)); } } diff --git a/rskj-core/src/test/java/co/rsk/core/bc/ParallelizeTransactionHandlerTest.java b/rskj-core/src/test/java/co/rsk/core/bc/ParallelizeTransactionHandlerTest.java new file mode 100644 index 00000000000..ff324b676b0 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/bc/ParallelizeTransactionHandlerTest.java @@ -0,0 +1,926 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * 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.core.bc; + +import co.rsk.test.builders.AccountBuilder; +import co.rsk.test.builders.TransactionBuilder; +import org.ethereum.config.Constants; +import org.ethereum.core.Account; +import org.ethereum.core.Block; +import org.ethereum.core.Transaction; +import org.ethereum.db.ByteArrayWrapper; +import org.ethereum.vm.GasCost; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.util.*; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +class ParallelizeTransactionHandlerTest { + + private short sublists; + private ParallelizeTransactionHandler handler; + private Transaction tx; + private Transaction tx2; + private Transaction tx3; + private ByteArrayWrapper aWrappedKey; + private ByteArrayWrapper aDifferentWrappedKey; + private Transaction bigTx; + private Transaction bigTx2; + private Transaction bigSequentialTx; + private short sequentialSublistNumber; + private long minSequentialSetGasLimit; + + @BeforeEach + public void setup() { + long blockGasLimit = 8_160_000L; + Block executionBlock = mock(Block.class); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(blockGasLimit).toByteArray()); + Account sender = new AccountBuilder().name("sender").build(); + Account sender2 = new AccountBuilder().name("sender2").build(); + Account sender3 = new AccountBuilder().name("sender3").build(); + Account sender4 = new AccountBuilder().name("sender4").build(); + Account sender5 = new AccountBuilder().name("sender5").build(); + Account sender6 = new AccountBuilder().name("sender6").build(); + byte[] aKey = {1, 2, 3}; + byte[] aDifferentKey = {1, 2, 3, 4}; + long gasUsedByTx = 16000; + minSequentialSetGasLimit = Constants.regtest().getMinSequentialSetGasLimit(); + long biggestGasLimitPossibleInParallelSublists = BlockUtils.getSublistGasLimit(executionBlock, false, minSequentialSetGasLimit) - 1; + long biggestGasLimitPossibleInSequentialSublist = BlockUtils.getSublistGasLimit(executionBlock, true, minSequentialSetGasLimit) - 1; + + aWrappedKey = new ByteArrayWrapper(aKey); + sublists = 2; + sequentialSublistNumber = sublists; + handler = new ParallelizeTransactionHandler(sublists, executionBlock, minSequentialSetGasLimit); + tx = new TransactionBuilder().nonce(1).sender(sender).value(BigInteger.valueOf(1)).gasLimit(BigInteger.valueOf(gasUsedByTx)).build(); + tx2 = new TransactionBuilder().nonce(1).sender(sender2).value(BigInteger.valueOf(1)).gasLimit(BigInteger.valueOf(gasUsedByTx)).build(); + tx3 = new TransactionBuilder().nonce(1).sender(sender3).value(BigInteger.valueOf(1)).gasLimit(BigInteger.valueOf(gasUsedByTx)).build(); + bigTx = new TransactionBuilder().nonce(1).sender(sender4).gasLimit(BigInteger.valueOf(biggestGasLimitPossibleInParallelSublists)).value(BigInteger.valueOf(1)).build(); + bigTx2 = new TransactionBuilder().nonce(1).sender(sender5).gasLimit(BigInteger.valueOf(biggestGasLimitPossibleInParallelSublists)).value(BigInteger.valueOf(1)).build(); + bigSequentialTx = new TransactionBuilder().nonce(1).sender(sender6).gasLimit(BigInteger.valueOf(biggestGasLimitPossibleInSequentialSublist)).value(BigInteger.valueOf(1)).build(); + aDifferentWrappedKey = new ByteArrayWrapper(aDifferentKey); + } + + @Test + void createAHandlerShouldReturnAnEmptyTransactionList() { + int expectedNumberOfTxs = 0; + int expectedNumberOfTxsInSublists = 0; + Assertions.assertEquals(expectedNumberOfTxs, handler.getTransactionsInOrder().size()); + Assertions.assertEquals(expectedNumberOfTxsInSublists, handler.getTransactionsPerSublistInOrder().length); + } + + @Test + void createAHandlerAndGasUsedInBucketShouldBeZero() { + int expectedGasUsed = 0; + for (short i = 0; i < sublists; i++) { + Assertions.assertEquals(expectedGasUsed, handler.getGasUsedIn(i)); + } + } + + @Test + void addTransactionIntoTheHandlerAndShouldBeAddedInTheFirstParallelSublist() { + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), 0); + short[] expectedTransactionEdgeList = new short[]{1}; + long expectedGasUsed = 0; + + Assertions.assertTrue(sublistGasUsed.isPresent()); + Assertions.assertEquals(expectedGasUsed, (long) sublistGasUsed.get()); + + List expectedListOfTxs = new ArrayList<>(); + expectedListOfTxs.add(tx); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void addTransactionIntoTheHandlerAndShouldBeSubtractedGasUsedInTheSublist() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + Assertions.assertTrue(sublistGasUsed.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + } + + @Test + void addTwoTransactionsWithTheSameReadKeyAndShouldBeAddedInADifferentSublist() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1, 2}; + + Set readKeys = createASetAndAddKeys(aWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, readKeys, new HashSet<>(), gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithDifferentReadKeysShouldBeAddedInADifferentSublist() { + short[] expectedTransactionEdgeList = new short[]{1, 2}; + + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys2 = createASetAndAddKeys(aDifferentWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, readKeys2, new HashSet<>(), gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithSameWrittenKeysShouldBeAddedInTheSameSublist() { + short[] expectedTransactionEdgeList = new short[]{2}; + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys, gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx+gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithDifferentWrittenKeysShouldBeAddedInDifferentBuckets() { + short[] expectedTransactionEdgeList = new short[]{1, 2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet writtenKeys2 = createASetAndAddKeys(aDifferentWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys2, gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithTheSameWrittenReadKeyShouldBeAddedInTheSameSublist() { + short[] expectedTransactionEdgeList = new short[]{2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, readKeys, new HashSet<>(), gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx+gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithTheSameReadWrittenKeyShouldBeAddedInTheSameSublist() { + short[] expectedTransactionEdgeList = new short[]{2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys, gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx+gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithDifferentReadWrittenKeysShouldBeAddedInDifferentSublists() { + short[] expectedTransactionEdgeList = new short[]{1,2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys = createASetAndAddKeys(aDifferentWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys, gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionWithDifferentWrittenReadKeyShouldBeAddedInDifferentSublists() { + short[] expectedTransactionEdgeList = new short[]{1, 2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys = createASetAndAddKeys(aDifferentWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, writtenKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, readKeys, new HashSet<>(), gasUsedByTx2); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx2, expectedTransactionEdgeList); + } + + @Test + void addTwoIndependentTxsAndAThirdOneCollidingWithBothAndShouldBeAddedInTheSequential() { + short[] expectedTransactionEdgeList = new short[]{1, 2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet differentWrittenKeys = createASetAndAddKeys(aDifferentWrappedKey); + + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + long gasUsedByTx3 = GasCost.toGas(tx3.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), differentWrittenKeys, gasUsedByTx2); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx3, differentWrittenKeys, writtenKeys, gasUsedByTx3); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent() && sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByTx3, (long) sublistGasUsed3.get()); + Assertions.assertEquals(gasUsedByTx3, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(tx, tx2, tx3); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void addTwoDependentTxsWithTheSecondInSequentialAndAThirdOneCollidingWithBothAndShouldBeAddedInTheSequential() { + short[] expectedTransactionEdgeList = new short[]{1}; + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + long gasUsedByTx3 = GasCost.toGas(tx3.getGasLimit()); + long totalGasInSequential = gasUsedByTx2 + gasUsedByTx3; + + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), writtenKeys, gasUsedByBigTx); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys, gasUsedByTx2); + Optional sublistGasUsed3 = handler.addTransaction(tx3, new HashSet<>(), writtenKeys, gasUsedByTx3); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent() && sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(totalGasInSequential, (long) sublistGasUsed3.get()); + Assertions.assertEquals(totalGasInSequential, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(bigTx, tx2, tx3); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void addABigTransactionAndAnotherWithTheSameWrittenKeyAndTheLastOneShouldGoToSequential() { + short[] expectedTransactionEdgeList = new short[]{1}; + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), writtenKeys, gasUsedByBigTx); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed2 = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(bigTx, tx, expectedTransactionEdgeList); + } + + @Test + void addABigTxAndAnotherWithTheSameReadWrittenKeyAndShouldGoToSequential() { + short[] expectedTransactionEdgeList = new short[]{1}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(bigTx, readKeys, new HashSet<>(), gasUsedByBigTx); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed2 = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(bigTx, tx, expectedTransactionEdgeList); + } + + @Test + void addABigTxAndAnotherWithTheSameWrittenReadKeyAndShouldGoToSequential() { + short[] expectedTransactionEdgeList = new short[]{1}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), writtenKeys, gasUsedByBigTx); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed2 = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(bigTx, tx, expectedTransactionEdgeList); + } + + @Test + void addTwoTransactionsWithTheSameSenderToTheSequentialSublistAndTheSecondShouldBeAddedCorrectly() { + short[] expectedTransactionEdgeList = new short[]{1,2}; + List expectedListOfTxs = Arrays.asList(bigTx, bigTx2, tx, tx); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + handler.addTransaction(bigTx, new HashSet<>(), new HashSet<>(), GasCost.toGas(bigTx.getGasLimit())); + handler.addTransaction(bigTx2, new HashSet<>(), new HashSet<>(), GasCost.toGas(bigTx2.getGasLimit())); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + Assertions.assertTrue(sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed3.get()); + + Optional sublistGasUsed4 = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + Assertions.assertTrue(sublistGasUsed4.isPresent()); + Assertions.assertEquals(2*gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(2*gasUsedByTx, (long) sublistGasUsed4.get()); + + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void twoTransactionWithTheSameSenderShouldBeInTheSameSublist() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{2}; + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(2*gasUsedByTx, (long) sublistGasUsed2.get()); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx, expectedTransactionEdgeList); + } + + @Test + void ifATxHasTheSameSenderThatAnotherAlreadyAddedIntoTheSequentialShouldGoToTheSequential() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx3 = GasCost.toGas(tx3.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1,2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet writtenKeys2 = createASetAndAddKeys(aDifferentWrappedKey); + HashSet readKeys = createASetAndAddKeys(aWrappedKey, aDifferentWrappedKey); + + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys2, gasUsedByTx); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx3, readKeys, new HashSet<>(), gasUsedByTx3); + Optional sublistGasUsed4 = handler.addTransaction(tx3, new HashSet<>(), new HashSet<>(), gasUsedByTx3); + Assertions.assertTrue(sublistGasUsed3.isPresent() && sublistGasUsed4.isPresent()); + Assertions.assertEquals(gasUsedByTx3*2, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(tx, tx2, tx3, tx3); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifATxReadTwoDifferentKeysWrittenByDifferentTxsInDifferentSublistsShouldGoToSequential() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + long gasUsedByTx3 = GasCost.toGas(tx3.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1,2}; + + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + HashSet writtenKeys2 = createASetAndAddKeys(aDifferentWrappedKey); + HashSet readKeys = createASetAndAddKeys(aWrappedKey, aDifferentWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys2, gasUsedByTx2); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx3, readKeys, new HashSet<>(), gasUsedByTx3); + Assertions.assertTrue(sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByTx3, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(tx, tx2, tx3); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifATxWritesAKeyAlreadyReadByTwoTxsInDifferentSublistsShouldGoToTheSequential() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx3 = GasCost.toGas(tx3.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1,2}; + + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys2 = createASetAndAddKeys(aWrappedKey); + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, readKeys2, new HashSet<>(), gasUsedByTx); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx3, new HashSet<>(), writtenKeys, gasUsedByTx3); + Assertions.assertTrue(sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByTx3, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(tx, tx2, tx3); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + @Test + void ifATxReadTwoKeysThatAreWereWrittenByTxsInDifferentSublistsShouldGoToTheSequential() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx3 = GasCost.toGas(tx3.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1,2}; + + HashSet readKeys = createASetAndAddKeys(aWrappedKey); + HashSet readKeys2 = createASetAndAddKeys(aDifferentWrappedKey); + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey, aDifferentWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(tx, readKeys, new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, readKeys2, new HashSet<>(), gasUsedByTx); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx3, new HashSet<>(), writtenKeys, gasUsedByTx3); + Assertions.assertTrue(sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByTx3, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(tx, tx2, tx3); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifATxCollidesWithAnotherOneThatAlsoHasTheSameSenderShouldGoIntoTheSameSublist() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{2}; + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(2*gasUsedByTx, (long) sublistGasUsed2.get()); + assertTwoTransactionsWereAddedProperlyIntoTheSublist(tx, tx, expectedTransactionEdgeList); + } + + @Test + void ifATxCollidesByTheSenderAndAKeyWithTwoTxsShouldBeAddedIntoTheSequential() { + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByTx2 = GasCost.toGas(tx2.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1,2}; + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + Optional sublistGasUsed2 = handler.addTransaction(tx2, new HashSet<>(), writtenKeys, gasUsedByTx2); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx, new HashSet<>(), writtenKeys, gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent() && sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + + List expectedListOfTxs = Arrays.asList(tx, tx2, tx); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifANewTxComesAndAllThePossibleSublistAreFullTheTxShouldNotBeAdded() { + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByBigTx2 = GasCost.toGas(bigTx2.getGasLimit()); + long gasUsedByBigSequentialTx = GasCost.toGas(bigSequentialTx.getGasLimit()); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + short[] expectedTransactionEdgeList = new short[]{1,2}; + + List expectedListOfTxs = new ArrayList<>(); + expectedListOfTxs.add(bigTx); + expectedListOfTxs.add(bigTx2); + expectedListOfTxs.add(bigSequentialTx); + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), new HashSet<>(), gasUsedByBigTx); + Optional sublistGasUsed2 = handler.addTransaction(bigTx2, new HashSet<>(), new HashSet<>(), gasUsedByBigTx2); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(bigSequentialTx, new HashSet<>(), new HashSet<>(), gasUsedByBigSequentialTx); + Optional sublistGasUsed4 = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + + Assertions.assertFalse(sublistGasUsed4.isPresent()); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent() && sublistGasUsed3.isPresent()); + + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByBigTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByBigSequentialTx, (long) sublistGasUsed3.get()); + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifSublistsAreFullAndAnIndependentTxComesShouldBeAddedInTheSequential() { + short[] expectedTransactionEdgeList = new short[]{1,2}; + + List expectedListOfTxs = new ArrayList<>(); + expectedListOfTxs.add(bigTx); + expectedListOfTxs.add(bigTx2); + expectedListOfTxs.add(tx); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByBigTx2 = GasCost.toGas(bigTx2.getGasLimit()); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), new HashSet<>(), gasUsedByBigTx); + Optional sublistGasUsed2 = handler.addTransaction(bigTx2, new HashSet<>(), new HashSet<>(), gasUsedByBigTx2); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent() && sublistGasUsed3.isPresent()); + + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByBigTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(gasUsedByTx, (long) sublistGasUsed3.get()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifAllTheSublistsAreFullTheNewIndependentTxShouldNotBeIncluded() { + short[] expectedTransactionEdgeList = new short[]{1,2}; + List expectedListOfTxs = Arrays.asList(bigTx, bigTx2, bigSequentialTx); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByBigTx2 = GasCost.toGas(bigTx2.getGasLimit()); + long gasUsedByBigSequentialTx = GasCost.toGas(bigSequentialTx.getGasLimit()); + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), new HashSet<>(), gasUsedByBigTx); + Optional sublistGasUsed2 = handler.addTransaction(bigTx2, new HashSet<>(), new HashSet<>(), gasUsedByBigTx2); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(bigSequentialTx, new HashSet<>(), new HashSet<>(), gasUsedByBigSequentialTx); + Assertions.assertTrue(sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByBigSequentialTx, (long) sublistGasUsed3.get()); + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional emptySublist = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), GasCost.toGas(tx.getGasLimit())); + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertFalse(emptySublist.isPresent()); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByBigTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void ifAllTheSublistsAreFullTheNewDependentTxShouldNotBeIncluded() { + short[] expectedTransactionEdgeList = new short[]{1,2}; + List expectedListOfTxs = Arrays.asList(bigTx, bigTx2, bigSequentialTx); + + long gasUsedByBigTx = GasCost.toGas(bigTx.getGasLimit()); + long gasUsedByBigTx2 = GasCost.toGas(bigTx2.getGasLimit()); + long gasUsedByBigSequentialTx = GasCost.toGas(bigSequentialTx.getGasLimit()); + HashSet writtenKeys = createASetAndAddKeys(aWrappedKey); + + Optional sublistGasUsed = handler.addTransaction(bigTx, new HashSet<>(), writtenKeys, gasUsedByBigTx); + Optional sublistGasUsed2 = handler.addTransaction(bigTx2, new HashSet<>(), new HashSet<>(), gasUsedByBigTx2); + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sublistGasUsed3 = handler.addTransaction(bigSequentialTx, new HashSet<>(), new HashSet<>(), gasUsedByBigSequentialTx); + Assertions.assertTrue(sublistGasUsed3.isPresent()); + Assertions.assertEquals(gasUsedByBigSequentialTx, (long) sublistGasUsed3.get()); + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional emptySublist = handler.addTransaction(tx, new HashSet<>(), writtenKeys, GasCost.toGas(tx.getGasLimit())); + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertFalse(emptySublist.isPresent()); + Assertions.assertTrue(sublistGasUsed.isPresent() && sublistGasUsed2.isPresent()); + Assertions.assertEquals(gasUsedByBigTx, (long) sublistGasUsed.get()); + Assertions.assertEquals(gasUsedByBigTx2, (long) sublistGasUsed2.get()); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void aRemascTxAddedShouldBeInTheSequentialSublist() { + List expectedListOfTxs = Collections.singletonList(tx); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + Optional sequentialSublistGasUsed = handler.addRemascTransaction(tx, gasUsedByTx); + + Assertions.assertTrue(sequentialSublistGasUsed.isPresent()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx, (long) sequentialSublistGasUsed.get()); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + } + + @Test + void aTxDirectedToAPrecompiledContractAddedShouldBeInTheSequentialSublist() { + List expectedListOfTxs = Collections.singletonList(bigSequentialTx); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + long gasUsedByBigSequentialTx = GasCost.toGas(bigSequentialTx.getGasLimit()); + + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + + Optional sequentialSublistGasUsedAfterBigTx = handler.addTxToSequentialSublist(bigSequentialTx, gasUsedByBigSequentialTx); + Assertions.assertTrue(sequentialSublistGasUsedAfterBigTx.isPresent()); + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByBigSequentialTx, (long) sequentialSublistGasUsedAfterBigTx.get()); + + Optional sequentialSublistGasUsedAfterTx = handler.addTxToSequentialSublist(tx, gasUsedByTx); + Assertions.assertFalse(sequentialSublistGasUsedAfterTx.isPresent()); + + Assertions.assertEquals(gasUsedByBigSequentialTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + } + + @Test + void aTxDirectedToAPrecompiledContractAddedWithSequentialSublistFullShouldNotBeAdded() { + List expectedListOfTxs = Collections.singletonList(tx); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + Optional sequentialSublistGasUsed = handler.addTxToSequentialSublist(tx, gasUsedByTx); + + Assertions.assertTrue(sequentialSublistGasUsed.isPresent()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx, (long) sequentialSublistGasUsed.get()); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + } + + @Test + void whenATxCallsAPrecompiledAnotherWithTheSameSenderShouldGoToSequential() { + List expectedListOfTxsPreSecondTx = Collections.singletonList(tx); + List expectedListOfTxsPostSecondTx = Arrays.asList(tx, tx); + long gasUsedByTx = GasCost.toGas(tx.getGasLimit()); + + Assertions.assertEquals(0, handler.getGasUsedIn(sequentialSublistNumber)); + Optional sequentialSublistGasUsed = handler.addTxToSequentialSublist(tx, gasUsedByTx); + + Assertions.assertTrue(sequentialSublistGasUsed.isPresent()); + Assertions.assertEquals(gasUsedByTx, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx, (long) sequentialSublistGasUsed.get()); + Assertions.assertEquals(expectedListOfTxsPreSecondTx, handler.getTransactionsInOrder()); + + Optional sequentialSublistGasUsedByTx2 = handler.addTransaction(tx, new HashSet<>(), new HashSet<>(), gasUsedByTx); + + Assertions.assertTrue(sequentialSublistGasUsedByTx2.isPresent()); + Assertions.assertEquals(gasUsedByTx*2, handler.getGasUsedIn(sequentialSublistNumber)); + Assertions.assertEquals(gasUsedByTx*2, (long) sequentialSublistGasUsedByTx2.get()); + Assertions.assertEquals(expectedListOfTxsPostSecondTx, handler.getTransactionsInOrder()); + } + + @Test + void ifItsSequentialTheEdgesListShouldHaveSizeZero() { + handler.addRemascTransaction(tx, GasCost.toGas(bigTx.getGasLimit())); + Assertions.assertEquals(0, handler.getTransactionsPerSublistInOrder().length); + } + + @Test + void callGetGasUsedInWithAnInvalidSublistShouldThrowAnError() { + short invalidSublistId = (short) (sublists +1); + try { + handler.getGasUsedIn(invalidSublistId); + Assertions.fail(); + } catch (NoSuchElementException e) { + Assertions.assertTrue(true); + } + } + + @Test + void callGetGasUsedInWithAnInvalidSublistShouldThrowAnError2() { + short invalidSublistId = -1; + try { + handler.getGasUsedIn(invalidSublistId); + Assertions.fail(); + } catch (NoSuchElementException e) { + Assertions.assertTrue(true); + } + } + + @Test + void senderWritesAKeyAndReadsAnotherThatIsWrittenShouldGoToSequential() { + HashSet writeKeyX = createASetAndAddKeys(aWrappedKey); + HashSet writeKeyY = createASetAndAddKeys(aDifferentWrappedKey); + HashSet readKeyY = createASetAndAddKeys(aDifferentWrappedKey); + + Account senderA = new AccountBuilder().name("sender1").build(); + Account senderB = new AccountBuilder().name("sender2").build(); + + Transaction a_writes_x = new TransactionBuilder().nonce(1).sender(senderA).value(BigInteger.valueOf(0)).gasLimit(BigInteger.valueOf(16000)).build(); + Transaction b_writes_y = new TransactionBuilder().nonce(1).sender(senderB).value(BigInteger.valueOf(0)).gasLimit(BigInteger.valueOf(16000)).build(); + Transaction a_reads_y = new TransactionBuilder().nonce(2).sender(senderA).value(BigInteger.valueOf(0)).gasLimit(BigInteger.valueOf(16000)).build(); + + handler.addTransaction(a_writes_x, new HashSet<>(), writeKeyX, 1000); + handler.addTransaction(b_writes_y, new HashSet<>(), writeKeyY, 1000); + handler.addTransaction(a_reads_y, readKeyY, new HashSet<>(), 1000); + + Assertions.assertArrayEquals(new short[]{ 1, 2 }, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void senderWritesAKeyAndReadsAnotherThatIsWrittenShouldGoToSequentialIfReadingOtherKeys() { + ByteArrayWrapper anotherKey = new ByteArrayWrapper(new byte[]{ 7, 7, 7 }); + HashSet writeKeyX = createASetAndAddKeys(aWrappedKey); + HashSet writeKeyYAndAnother = createASetAndAddKeys(anotherKey, aDifferentWrappedKey); + HashSet readKeyYAndAnother = createASetAndAddKeys(anotherKey, aDifferentWrappedKey); + + Account senderA = new AccountBuilder().name("sender1").build(); + Account senderB = new AccountBuilder().name("sender2").build(); + + Transaction a_writes_x = new TransactionBuilder().nonce(1).sender(senderA).value(BigInteger.valueOf(0)).gasLimit(BigInteger.valueOf(16000)).build(); + Transaction b_writes_y = new TransactionBuilder().nonce(1).sender(senderB).value(BigInteger.valueOf(0)).gasLimit(BigInteger.valueOf(16000)).build(); + Transaction a_reads_y = new TransactionBuilder().nonce(2).sender(senderA).value(BigInteger.valueOf(0)).gasLimit(BigInteger.valueOf(16000)).build(); + + handler.addTransaction(a_writes_x, new HashSet<>(), writeKeyX, 1000); + handler.addTransaction(b_writes_y, new HashSet<>(), writeKeyYAndAnother, 1000); + handler.addTransaction(a_reads_y, readKeyYAndAnother, new HashSet<>(), 1000); + + Assertions.assertArrayEquals(new short[]{ 1, 2 }, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void writeSequentialAfterTwoParallelReadsAndAWriteShouldGoToSequential() { + HashSet setWithX = createASetAndAddKeys(aWrappedKey); + HashSet setWithY = createASetAndAddKeys(aDifferentWrappedKey); + HashSet setWithXAndY = createASetAndAddKeys(aWrappedKey, aDifferentWrappedKey); + + AccountBuilder accountBuilder = new AccountBuilder(); + + // read X + handler.addTransaction( + new TransactionBuilder().sender(accountBuilder.name("sender1").build()).build(), + setWithX, new HashSet<>(), 10000 + ); + + // read Y + handler.addTransaction( + new TransactionBuilder().sender(accountBuilder.name("sender2").build()).build(), + setWithY, new HashSet<>(), 10000 + ); + + // write X and Y + handler.addTransaction( + new TransactionBuilder().sender(accountBuilder.name("sender3").build()).build(), + new HashSet<>(), setWithXAndY, 10000 + ); + + // last write of X is in sequential + Assertions.assertArrayEquals(new short[]{ 1, 2 }, handler.getTransactionsPerSublistInOrder()); + + // write X + handler.addTransaction( + new TransactionBuilder().sender(accountBuilder.name("sender4").build()).build(), + new HashSet<>(), setWithX, 10000 + ); + + // should go to sequential + // [[read x], [read y]] [write x and y, write x] + Assertions.assertArrayEquals(new short[]{ 1, 2 }, handler.getTransactionsPerSublistInOrder()); + } + + @Test + void writeAfterWriteToSequentialForOutOfGasShouldGoToSequential() { + Block executionBlock = mock(Block.class); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(3_000_000L).toByteArray()); + + HashSet setWithX = createASetAndAddKeys(aWrappedKey); + + AccountBuilder accountBuilder = new AccountBuilder(); + + ParallelizeTransactionHandler handler = new ParallelizeTransactionHandler((short) 2, executionBlock, minSequentialSetGasLimit); + + // write X with 800 + handler.addTransaction( + new TransactionBuilder() + .sender(accountBuilder.name("sender1").build()) + .gasLimit(BigInteger.valueOf(800000)) + .build(), + new HashSet<>(), setWithX, 800000 + ); + + // write X with 300 + handler.addTransaction( + new TransactionBuilder() + .sender(accountBuilder.name("sender2").build()) + .gasLimit(BigInteger.valueOf(300000)) + .build(), + new HashSet<>(), setWithX, 300000 + ); + + // last write of X is in sequential because of out of gas. 800 + 300 > 1000 + Assertions.assertArrayEquals(new short[]{ 1 }, handler.getTransactionsPerSublistInOrder()); + + // read X with 100 + handler.addTransaction( + new TransactionBuilder() + .sender(accountBuilder.name("sender3").build()) + .gasLimit(BigInteger.valueOf(100000)) + .build(), + setWithX, new HashSet<>(), 100000 + ); + + // should go to sequential + Assertions.assertArrayEquals(new short[]{ 1 }, handler.getTransactionsPerSublistInOrder()); + } + + private HashSet createASetAndAddKeys(ByteArrayWrapper... aKey) { + return new HashSet<>(Arrays.asList(aKey)); + } + + private void assertTwoTransactionsWereAddedProperlyIntoTheSublist(Transaction tx, Transaction tx2, short[] expectedTransactionEdgeList) { + List expectedListOfTxs = Arrays.asList(tx, tx2); + Assertions.assertEquals(expectedListOfTxs, handler.getTransactionsInOrder()); + Assertions.assertArrayEquals(expectedTransactionEdgeList, handler.getTransactionsPerSublistInOrder()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/core/bc/ReadWrittenKeysTrackerTest.java b/rskj-core/src/test/java/co/rsk/core/bc/ReadWrittenKeysTrackerTest.java new file mode 100644 index 00000000000..ce51d002d87 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/bc/ReadWrittenKeysTrackerTest.java @@ -0,0 +1,551 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * 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.core.bc; + +import org.ethereum.db.ByteArrayWrapper; +import org.ethereum.db.DummyReadWrittenKeysTracker; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + +import java.util.*; +import java.util.concurrent.*; + +class ReadWrittenKeysTrackerTest { + + private IReadWrittenKeysTracker tracker; + private IReadWrittenKeysTracker dummyTracker; + private ByteArrayWrapper key1; + private ByteArrayWrapper key2; + + + @BeforeEach + void setup() { + this.tracker = new ReadWrittenKeysTracker(); + this.dummyTracker = new DummyReadWrittenKeysTracker(); + this.key1 = new ByteArrayWrapper(new byte[]{1}); + this.key2 = new ByteArrayWrapper(new byte[]{2}); + } + + ByteArrayWrapper getKey(int thread, int readWrite,int i ) { + // Supports upto 65536 keys + return new ByteArrayWrapper(new byte[]{(byte)thread, (byte) readWrite, + (byte) (i >> 8), (byte) (i & 0xff)}); + } + + @Test + void collisionWithLongerSets() { + //.. + ReadWrittenKeysTracker myTracker = (ReadWrittenKeysTracker) this.tracker; + int keysPerThread = 10; + int maxThreads = 4; + + // Add read 10 distinct keys for each one of 4 threads + for (int thread=0; thread temporalReadKeys = tracker.getThisThreadReadKeys(); + assertKeyWasAddedInMap(temporalReadKeys, key1); + } + + @Test + void addReadKeyToTheTrackerAndShouldBeInReadKeysForAllThreads() { + tracker.addNewReadKey(key1); + Map> readKeys = tracker.getReadKeysByThread(); + Set readKeysByThisThread = readKeys.get(Thread.currentThread().getId()); + + Assertions.assertEquals(1, readKeys.size()); + Assertions.assertEquals(1, readKeysByThisThread.size()); + Assertions.assertTrue(readKeysByThisThread.contains(key1)); + } + + @Test + void addReadKeyToTheTrackerAndShouldNotBeInWrittenMapForThisThread() { + tracker.addNewReadKey(key1); + Assertions.assertEquals(0, tracker.getThisThreadWrittenKeys().size()); + } + + @Test + void addReadKeyToTheTrackerAndShouldNotBeInWrittenMapForAllThreads() { + tracker.addNewReadKey(key1); + Assertions.assertEquals(0, tracker.getWrittenKeysByThread().size()); + } + + @Test + void addWrittenKeyToTheTrackerAndShouldBeInWrittenMapForThisThread() { + tracker.addNewWrittenKey(key1); + Set temporalWrittenKeys = tracker.getThisThreadWrittenKeys(); + assertKeyWasAddedInMap(temporalWrittenKeys, key1); + } + + @Test + void addWrittenKeyToTheTrackerAndShouldBeInWrittenMapForAllThreads() { + tracker.addNewWrittenKey(key1); + Map> writtenKeys = tracker.getWrittenKeysByThread(); + + Set writtenKeysByThisThread = writtenKeys.get(Thread.currentThread().getId()); + Assertions.assertEquals(1, writtenKeys.size()); + Assertions.assertEquals(1, writtenKeysByThisThread.size()); + Assertions.assertTrue(writtenKeysByThisThread.contains(key1)); + } + + @Test + void addWrittenKeyToTheTrackerAndShouldNotBeInReadMapForThisThread() { + tracker.addNewWrittenKey(key1); + Assertions.assertEquals(0, tracker.getThisThreadReadKeys().size()); + } + + @Test + void addWrittenKeyToTheTrackerAndShouldNotBeInReadMapForAllThreads() { + tracker.addNewWrittenKey(key1); + Assertions.assertEquals(0, tracker.getReadKeysByThread().size()); + } + + @Test + void clearTrackerShouldEmptyAllTheMaps() { + tracker.addNewWrittenKey(key1); + tracker.addNewWrittenKey(key2); + tracker.addNewReadKey(key1); + tracker.addNewReadKey(key2); + + Assertions.assertEquals(1, tracker.getWrittenKeysByThread().size()); + Assertions.assertEquals(2, tracker.getThisThreadWrittenKeys().size()); + Assertions.assertEquals(1, tracker.getReadKeysByThread().size()); + Assertions.assertEquals(2, tracker.getThisThreadReadKeys().size()); + + + tracker.clear(); + + Assertions.assertEquals(0, tracker.getWrittenKeysByThread().size()); + Assertions.assertEquals(0, tracker.getThisThreadWrittenKeys().size()); + Assertions.assertEquals(0, tracker.getReadKeysByThread().size()); + Assertions.assertEquals(0, tracker.getThisThreadReadKeys().size()); + } + + @Test + void createADummyTrackerShouldHaveEmptyMaps() { + Assertions.assertEquals(0, dummyTracker.getReadKeysByThread().size()); + Assertions.assertEquals(0, dummyTracker.getWrittenKeysByThread().size()); + Assertions.assertEquals(0, dummyTracker.getThisThreadReadKeys().size()); + Assertions.assertEquals(0, dummyTracker.getThisThreadWrittenKeys().size()); + } + + @Test + void addReadKeyToTheDummyTrackerShouldDoNothing() { + dummyTracker.addNewReadKey(key1); + Assertions.assertEquals(0, dummyTracker.getReadKeysByThread().size()); + Assertions.assertEquals(0, dummyTracker.getThisThreadReadKeys().size()); + } + + @Test + void addWrittenKeyToTheTrackerShouldDoNothing() { + dummyTracker.addNewWrittenKey(key1); + Assertions.assertEquals(0, dummyTracker.getThisThreadWrittenKeys().size()); + Assertions.assertEquals(0, dummyTracker.getWrittenKeysByThread().size()); + } + + @Test + void clearDummyTrackerShouldDoNothing() { + dummyTracker.addNewWrittenKey(key1); + dummyTracker.addNewReadKey(key1); + dummyTracker.addNewWrittenKey(key2); + dummyTracker.addNewReadKey(key2); + + Assertions.assertEquals(0, dummyTracker.getThisThreadReadKeys().size()); + Assertions.assertEquals(0, dummyTracker.getThisThreadWrittenKeys().size()); + + dummyTracker.clear(); + + Assertions.assertEquals(0, dummyTracker.getThisThreadReadKeys().size()); + Assertions.assertEquals(0, dummyTracker.getThisThreadWrittenKeys().size()); + } + + @Test + void ifAThreadReadsAndWritesTheSameKeyCollideShouldBeFalse() { + int nThreads = 1; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.singleton(key1), Collections.singleton(key1)); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertFalse(tracker.detectCollision()); + } + + @Test + void ifAThreadWritesTwiceTheSameKeyCollideShouldBeFalse() { + ReadWrittenKeysTracker myTracker = (ReadWrittenKeysTracker) this.tracker; + myTracker.addNewWrittenKeyToThread(0, key1); + myTracker.addNewWrittenKeyToThread(0, key1); + Assertions.assertFalse(myTracker.detectCollision()); + } + + @Test + void ifAThreadReadsTwiceTheSameKeyCollideShouldBeFalse() { + ReadWrittenKeysTracker myTracker = (ReadWrittenKeysTracker) this.tracker; + myTracker.addNewReadKeyToThread(0, key1); + myTracker.addNewReadKeyToThread(0, key1); + Assertions.assertFalse(myTracker.detectCollision()); + } + + @Test + void ifTwoThreadsDontWriteAnyKeyCollideShouldBeFalse() { + int nThreads = 2; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.emptySet(), Collections.emptySet()); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertFalse(tracker.detectCollision()); + } + + @Test + void ifTwoThreadsReadDifferentKeysCollideShouldBeFalse() { + int nThreads = 2; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.emptySet(), Collections.singleton(i % 2 ==0 ? key1 : key2)); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertFalse(tracker.detectCollision()); + } + + @Test + void ifTwoThreadsReadTheSameKeyCollideShouldBeFalse() { + int nThreads = 2; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.emptySet(), Collections.singleton(key1)); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertFalse(tracker.detectCollision()); + } + + @Test + void ifTwoThreadsWriteDifferentKeysCollideShouldBeFalse() { + int nThreads = 2; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.singleton(i % 2 ==0 ? key1 : key2), Collections.emptySet()); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertFalse(tracker.detectCollision()); + } + + @Test + void ifTwoThreadsWriteTheSameKeyCollideShouldBeTrue() { + int nThreads = 2; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.singleton(key1), Collections.emptySet()); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertTrue(tracker.detectCollision()); + } + + @Test + void ifTwoThreadsReadAndWriteTheSameKeyCollideShouldBeTrue() { + int nThreads = 2; + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + Set writtenKeys; + Set readKeys; + for (int i = 0; i < nThreads; i++) { + boolean isEven = i % 2 == 0; + writtenKeys = isEven? Collections.singleton(this.key1) : Collections.emptySet(); + readKeys = isEven? Collections.emptySet() : Collections.singleton(this.key1); + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, writtenKeys, readKeys); + completionService.submit(rwKeys); + } + + getTrackerHelperAfterCompletion(nThreads, completionService); + Assertions.assertTrue(tracker.detectCollision()); + } + + @Test + void ifTwoThreadsWriteTheSameKeyShouldBeStored() { + int nThreads = 2; + + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + + for (int i = 0; i < nThreads; i++) { + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, Collections.singleton(key1), Collections.emptySet()); + completionService.submit(rwKeys); + } + + List helpers = getTrackerHelperAfterCompletion(nThreads, completionService); + + Map> writtenKeysByThread = this.tracker.getWrittenKeysByThread(); + Assertions.assertEquals(nThreads, writtenKeysByThread.size()); + Map> readKeysByThread = this.tracker.getReadKeysByThread(); + Assertions.assertEquals(0, readKeysByThread.size()); + assertKeysAreAddedCorrectlyIntoTheTracker(helpers, writtenKeysByThread, readKeysByThread); + } + + @Test + void ifTwoThreadsReadAndWriteAKeyTheyShouldBeStored() { + int nThreads = 2; + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + Set writtenKeys; + Set readKeys; + for (int i = 0; i < nThreads; i++) { + boolean isEven = i % 2 == 0; + writtenKeys = isEven? Collections.singleton(this.key1) : Collections.emptySet(); + readKeys = isEven? Collections.emptySet() : Collections.singleton(this.key1); + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, writtenKeys, readKeys); + completionService.submit(rwKeys); + } + + List helpers = getTrackerHelperAfterCompletion(nThreads, completionService); + + Map> writtenKeysByThread = this.tracker.getWrittenKeysByThread(); + Assertions.assertEquals(1, writtenKeysByThread.size()); + Map> readKeysByThread = this.tracker.getReadKeysByThread(); + Assertions.assertEquals(1, readKeysByThread.size()); + assertKeysAreAddedCorrectlyIntoTheTracker(helpers, writtenKeysByThread, readKeysByThread); + } + + @Test + void ifTwoThreadsReadSomeKeysTheyShouldBeStored() { + int nThreads = 2; + ExecutorService service = Executors.newFixedThreadPool(nThreads); + CompletionService completionService = new ExecutorCompletionService<>(service); + Set writtenKeys; + Set readKeys; + for (int i = 0; i < nThreads; i++) { + writtenKeys = Collections.emptySet(); + readKeys = Collections.singleton(this.key1); + ReadWrittenKeysHelper rwKeys = new ReadWrittenKeysHelper(this.tracker, writtenKeys, readKeys); + completionService.submit(rwKeys); + } + + List helpers = getTrackerHelperAfterCompletion(nThreads, completionService); + Map> writtenKeysByThread = this.tracker.getWrittenKeysByThread(); + Assertions.assertEquals(0, writtenKeysByThread.size()); + Map> readKeysByThread = this.tracker.getReadKeysByThread(); + Assertions.assertEquals(2, readKeysByThread.size()); + assertKeysAreAddedCorrectlyIntoTheTracker(helpers, writtenKeysByThread, readKeysByThread); + } + + private List getTrackerHelperAfterCompletion(int nThreads, CompletionService completionService) { + List helpers = new ArrayList<>(); + for (int i = 0; i < nThreads; i++) { + try { + Future helperFuture = completionService.take(); + helpers.add(helperFuture.get()); + } catch (Exception e) { + Assertions.fail(); + } + } + + return helpers; + } + + private void assertKeysAreAddedCorrectlyIntoTheTracker(List helpers, Map> writtenKeysByThread, Map> readKeysByThread) { + for (ReadWrittenKeysHelper h: helpers) { + if (h.getWrittenKeys().size() == 0) { + Assertions.assertNull(writtenKeysByThread.get(h.getThreadId())); + } else { + Assertions.assertEquals(h.getWrittenKeys().size(), writtenKeysByThread.get(h.getThreadId()).size()); + Assertions.assertTrue(h.getWrittenKeys().containsAll(writtenKeysByThread.get(h.getThreadId()))); + } + + if (h.getReadKeys().size() == 0) { + Assertions.assertNull(readKeysByThread.get(h.getThreadId())); + } else { + Assertions.assertEquals(h.getReadKeys().size(), readKeysByThread.get(h.getThreadId()).size()); + Assertions.assertTrue(h.getReadKeys().containsAll(readKeysByThread.get(h.getThreadId()))); + } + } + } + + private void assertKeyWasAddedInMap(Set map, ByteArrayWrapper key) { + Assertions.assertEquals(1, map.size()); + Assertions.assertTrue(map.contains(key)); + } + private static class ReadWrittenKeysHelper implements Callable { + + private final Set readKeys; + private final Set writtenKeys; + private final IReadWrittenKeysTracker tracker; + private long threadId; + + public ReadWrittenKeysHelper(IReadWrittenKeysTracker tracker, Set writtenKeys, Set readKeys) { + this.tracker = tracker; + this.readKeys = readKeys; + this.writtenKeys = writtenKeys; + this.threadId = -1L; + } + //At first, it reads and then it writes. + public ReadWrittenKeysHelper call() { + + this.threadId = Thread.currentThread().getId(); + + for (ByteArrayWrapper rk : this.readKeys) { + this.tracker.addNewReadKey(rk); + } + + for (ByteArrayWrapper wk : this.writtenKeys) { + this.tracker.addNewWrittenKey(wk); + } + return this; + } + + public Set getReadKeys() { + return this.readKeys; + } + + public Set getWrittenKeys() { + return this.writtenKeys; + } + + public long getThreadId() { + return this.threadId; + } + } + +} diff --git a/rskj-core/src/test/java/co/rsk/core/bc/transactionexecutor/PrecompiledContractHasBeenCalledTest.java b/rskj-core/src/test/java/co/rsk/core/bc/transactionexecutor/PrecompiledContractHasBeenCalledTest.java new file mode 100644 index 00000000000..2a60ee1b099 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/bc/transactionexecutor/PrecompiledContractHasBeenCalledTest.java @@ -0,0 +1,455 @@ +package co.rsk.core.bc.transactionexecutor; + +import co.rsk.blockchain.utils.BlockGenerator; +import co.rsk.config.TestSystemProperties; +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.core.TransactionExecutorFactory; +import co.rsk.db.MutableTrieImpl; +import co.rsk.peg.BridgeSupportFactory; +import co.rsk.peg.BtcBlockStoreWithCache; +import co.rsk.peg.RepositoryBtcBlockStoreWithCache; +import co.rsk.trie.Trie; +import co.rsk.trie.TrieStore; +import co.rsk.trie.TrieStoreImpl; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.config.Constants; +import org.ethereum.core.*; +import org.ethereum.crypto.HashUtil; +import org.ethereum.datasource.HashMapDB; +import org.ethereum.db.BlockStoreDummy; +import org.ethereum.db.MutableRepository; +import org.ethereum.vm.PrecompiledContracts; +import org.ethereum.vm.program.ProgramResult; +import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.util.*; + +import static co.rsk.core.bc.BlockExecutorTest.createAccount; +import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; + +public class PrecompiledContractHasBeenCalledTest { + public static final String SMART_CONTRACT_BYTECODE = "6080604052600160005534801561001557600080fd5b50610115806100256000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80633bccbbc9146037578063853255cc14603f575b600080fd5b603d6047565b005b6045604c565b005b600080fd5b600080815480929190605c90609c565b9190505550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000819050919050565b600060a5826092565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820360d45760d36063565b5b60018201905091905056fea2646970667358221220d0c973fb2823cb683c85b25b597842bf24f5d10e34b28298cd260a17597d433264736f6c63430008120033"; + public static final String PROXY_SMART_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b506040516104eb3803806104eb833981810160405281019061003291906100db565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610108565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100a88261007d565b9050919050565b6100b88161009d565b81146100c357600080fd5b50565b6000815190506100d5816100af565b92915050565b6000602082840312156100f1576100f0610078565b5b60006100ff848285016100c6565b91505092915050565b6103d4806101176000396000f3fe60806040526004361061001e5760003560e01c8063688c62c514610023575b600080fd5b61003d600480360381019061003891906101a1565b610054565b60405161004b929190610299565b60405180910390f35b6000606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163485856040516100a0929190610308565b60006040518083038185875af1925050503d80600081146100dd576040519150601f19603f3d011682016040523d82523d6000602084013e6100e2565b606091505b5080925081935050508161012b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101229061037e565b60405180910390fd5b9250929050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126101615761016061013c565b5b8235905067ffffffffffffffff81111561017e5761017d610141565b5b60208301915083600182028301111561019a57610199610146565b5b9250929050565b600080602083850312156101b8576101b7610132565b5b600083013567ffffffffffffffff8111156101d6576101d5610137565b5b6101e28582860161014b565b92509250509250929050565b60008115159050919050565b610203816101ee565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610243578082015181840152602081019050610228565b60008484015250505050565b6000601f19601f8301169050919050565b600061026b82610209565b6102758185610214565b9350610285818560208601610225565b61028e8161024f565b840191505092915050565b60006040820190506102ae60008301856101fa565b81810360208301526102c08184610260565b90509392505050565b600081905092915050565b82818337600083830152505050565b60006102ef83856102c9565b93506102fc8385846102d4565b82840190509392505050565b60006103158284866102e3565b91508190509392505050565b600082825260208201905092915050565b7f4661696c656420746f2063616c6c000000000000000000000000000000000000600082015250565b6000610368600e83610321565b915061037382610332565b602082019050919050565b600060208201905081810360008301526103978161035b565b905091905056fea2646970667358221220ad54ae56c44b1857061914a1dde2177d2f7158fde81816cdacb47d11b605a9cd64736f6c63430008120033000000000000000000000000"; + public static final String PROXY_TO_PROXY_SMART_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b506040516106d03803806106d0833981810160405281019061003291906100ed565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061011a565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100a88261007d565b9050919050565b60006100ba8261009d565b9050919050565b6100ca816100af565b81146100d557600080fd5b50565b6000815190506100e7816100c1565b92915050565b60006020828403121561010357610102610078565b5b6000610111848285016100d8565b91505092915050565b6105a7806101296000396000f3fe60806040526004361061001e5760003560e01c8063688c62c514610023575b600080fd5b61003d600480360381019061003891906101c3565b610054565b60405161004b9291906102bb565b60405180910390f35b6000606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663688c62c585856040518363ffffffff1660e01b81526004016100b3929190610327565b6000604051808303816000875af11580156100d2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906100fb9190610498565b809250819350505081610143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161013a90610551565b60405180910390fd5b9250929050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126101835761018261015e565b5b8235905067ffffffffffffffff8111156101a05761019f610163565b5b6020830191508360018202830111156101bc576101bb610168565b5b9250929050565b600080602083850312156101da576101d9610154565b5b600083013567ffffffffffffffff8111156101f8576101f7610159565b5b6102048582860161016d565b92509250509250929050565b60008115159050919050565b61022581610210565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561026557808201518184015260208101905061024a565b60008484015250505050565b6000601f19601f8301169050919050565b600061028d8261022b565b6102978185610236565b93506102a7818560208601610247565b6102b081610271565b840191505092915050565b60006040820190506102d0600083018561021c565b81810360208301526102e28184610282565b90509392505050565b82818337600083830152505050565b60006103068385610236565b93506103138385846102eb565b61031c83610271565b840190509392505050565b600060208201905081810360008301526103428184866102fa565b90509392505050565b61035481610210565b811461035f57600080fd5b50565b6000815190506103718161034b565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6103b482610271565b810181811067ffffffffffffffff821117156103d3576103d261037c565b5b80604052505050565b60006103e661014a565b90506103f282826103ab565b919050565b600067ffffffffffffffff8211156104125761041161037c565b5b61041b82610271565b9050602081019050919050565b600061043b610436846103f7565b6103dc565b90508281526020810184848401111561045757610456610377565b5b610462848285610247565b509392505050565b600082601f83011261047f5761047e61015e565b5b815161048f848260208601610428565b91505092915050565b600080604083850312156104af576104ae610154565b5b60006104bd85828601610362565b925050602083015167ffffffffffffffff8111156104de576104dd610159565b5b6104ea8582860161046a565b9150509250929050565b600082825260208201905092915050565b7f4661696c656420746f2063616c6c000000000000000000000000000000000000600082015250565b600061053b600e836104f4565b915061054682610505565b602082019050919050565b6000602082019050818103600083015261056a8161052e565b905091905056fea2646970667358221220465f552de541a4d2292de2fff8f37af0cf3d5b3995b7cadfd358afef3c19f61664736f6c63430008120033000000000000000000000000"; + public static final RskAddress NULL_ADDRESS = RskAddress.nullAddress(); + private TestSystemProperties config; + private TransactionExecutorFactory transactionExecutorFactory; + private Repository track; + private int txIndex; + private Account sender; + + private Account receiver; + + private int difficulty; + private ArrayList uncles; + private BigInteger minGasPrice; + + @BeforeEach + public void setUp() { + config = new TestSystemProperties(); + transactionExecutorFactory = getTransactionExecutorFactory(config); + track = getRepository(); + txIndex = 0; + sender = createAccount("acctest1", track, Coin.valueOf(6000000)); + receiver = createAccount("acctest2", track, Coin.valueOf(6000000)); + initTrackAndAssertIsNotEmpty(track); + difficulty = 1; + uncles = new ArrayList<>(); + minGasPrice = null; + } + + @Test + void whenATxCallsAPrecompiledContractPrecompiledContractHasBeenCalledFlagShouldBeTrue() { + byte[] arbitraryData = Hex.decode("00112233"); + long value = 0L; + Set precompiledContractsCalled = Collections.singleton(PrecompiledContracts.IDENTITY_ADDR); + boolean hasRevert = false; + boolean threwAnException = false; + RskAddress destination = PrecompiledContracts.IDENTITY_ADDR; + executeATransactionAndAssert(getABlockWithATx(track, config, arbitraryData, value, destination, sender), txIndex, precompiledContractsCalled, hasRevert, threwAnException); + } + + + @Test + void whenATxSendsValueToAPrecompiledContractPrecompiledContractHasBeenCalledFlagShouldBeTrue() { + int value = 1; + Set precompiledContractsCalled = Collections.singleton(PrecompiledContracts.IDENTITY_ADDR); + boolean hasRevert = false; + boolean threwAnException = false; + RskAddress destination = PrecompiledContracts.IDENTITY_ADDR; + executeATransactionAndAssert(getABlockWithATx(track, config, null, value, destination, sender), txIndex, precompiledContractsCalled, hasRevert, threwAnException); + } + + @Test + void whenATxCallsAPrecompiledContractAndThrowsAnExceptionPrecompiledContractHasBeenCalledFlagShouldBeTrue() { + byte[] dataThatThrowsAnException = Hex.decode("e674f5e80000000000000000000000000000000000000000000000000000000001000006"); + int value = 0; + Set precompiledContractsCalled = Collections.singleton(PrecompiledContracts.BRIDGE_ADDR); + boolean hasRevert = false; + boolean threwAnException = true; + RskAddress destination = PrecompiledContracts.BRIDGE_ADDR; + executeATransactionAndAssert(getABlockWithATx(track, config, dataThatThrowsAnException, value, destination, sender), txIndex, precompiledContractsCalled, hasRevert, threwAnException); + } + + @Test + void ifAnAccountSendsValueToAnAccountPrecompiledContractHasBeenCalledFlagShouldBeFalse() { + Coin balance_before = track.getBalance(receiver.getAddress()); + executeATransactionAndAssert(getABlockWithATx(track, config, null, 1, receiver.getAddress(), sender), txIndex, Collections.emptySet(), false, false); + Assertions.assertEquals(balance_before.add(Coin.valueOf(1)), track.getBalance(receiver.getAddress())); + } + + @Test + void whenATxCallsANonPrecompiledContractPrecompiledContractHasBeenCalledFlagShouldBeFalse() { + List txs = new LinkedList<>(); + + //Deploy a Smart Contract + BigInteger nonce = track.getNonce(sender.getAddress()); + Transaction tx = buildTransaction(config, Hex.decode(SMART_CONTRACT_BYTECODE), 0, NULL_ADDRESS, sender, nonce); + txs.add(tx); + + //Call the Smart Contract + RskAddress smartContractAddress = getContractAddress(sender, nonce); + byte[] dataToCallTheSmartContract = Hex.decode("853255cc"); + BigInteger nonce2 = incrementNonce(nonce); + Transaction tx2 = buildTransaction(config, dataToCallTheSmartContract, 0, smartContractAddress, sender, nonce2); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.emptySet(), false, false); + } + + @Test + void whenATxCallsANonPrecompiledContractAndRevertsPrecompiledContractHasBeenCalledFlagShouldBeFalse() { + List txs = new LinkedList<>(); + + //Deploy a Smart Contract + BigInteger nonce = track.getNonce(sender.getAddress()); + Transaction tx = buildTransaction(config, Hex.decode(SMART_CONTRACT_BYTECODE), 0, NULL_ADDRESS, sender, nonce); + txs.add(tx); + + //Call the Smart Contract + RskAddress smartContractAddress = getContractAddress(sender, nonce); + byte[] dataToCallTheSmartContract = Hex.decode("3bccbbc9"); //reverts + BigInteger nonce2 = incrementNonce(nonce); + Transaction tx2 = buildTransaction(config, dataToCallTheSmartContract, 0, smartContractAddress, sender, nonce2); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.emptySet(), true, false); + } + + @Test + void whenATxCallsAContractThatCallsAPrecompiledContractPrecompiledContractHasBeenCalledFlagShouldBeTrue() { + List txs = new LinkedList<>(); + + //Deploy Proxy to Identity precompiled contract + BigInteger nonce = track.getNonce(sender.getAddress()); + Transaction tx = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_SMART_CONTRACT_BYTECODE, PrecompiledContracts.IDENTITY_ADDR), 0, NULL_ADDRESS, sender, nonce); + txs.add(tx); + + //Call Proxy + RskAddress proxyContract = getContractAddress(sender, nonce); + byte[] dataToCallAPrecompiledThroughTheProxy = Hex.decode("688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145b38da6a701c568545dcfcb03fcb875f56beddc4000000000000000000000000"); + BigInteger nonce2 = incrementNonce(nonce); + Transaction tx2 = buildTransaction(config, dataToCallAPrecompiledThroughTheProxy, 0, proxyContract, sender, nonce2); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.singleton(PrecompiledContracts.IDENTITY_ADDR), false, false); + } + + @Test + void whenATxCallsAContractThatCallsAPrecompiledContractAndThrowsExceptionPrecompiledContractHasBeenCalledFlagShouldBeTrue() { + List txs = new LinkedList<>(); + + BigInteger nonce = track.getNonce(sender.getAddress()); + Transaction tx = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_SMART_CONTRACT_BYTECODE, PrecompiledContracts.BRIDGE_ADDR), 0, NULL_ADDRESS, sender, nonce); + txs.add(tx); + + //Call Proxy + RskAddress proxyContract = getContractAddress(sender, nonce); + byte[] dataToCallAPrecompiledThroughTheProxy = Hex.decode("688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024e674f5e8000000000000000000000000000000000000000000000000000000000100000600000000000000000000000000000000000000000000000000000000"); + BigInteger nonce1 = incrementNonce(nonce); + Transaction tx1 = buildTransaction(config, dataToCallAPrecompiledThroughTheProxy, 0, proxyContract, sender, nonce1); + txs.add(tx1); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + // As the Precompiled throws an exception, the contract hits the require, and thus reverts. + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.singleton(PrecompiledContracts.BRIDGE_ADDR), true, false); + } + + @Test + void whenAnInternalTxCallsANonPrecompiledContractPrecompiledContractHasBeenCalledFlagShouldBeFalse() { + List txs = new LinkedList<>(); + + //Deploy a Smart Contract + BigInteger nonce = track.getNonce(sender.getAddress()); + Transaction tx = buildTransaction(config, Hex.decode(SMART_CONTRACT_BYTECODE), 0, NULL_ADDRESS, sender, nonce); + RskAddress smartContractAddress = getContractAddress(sender, nonce); + txs.add(tx); + + //Deploy Proxy to Smart Contract + BigInteger nonce1 = incrementNonce(nonce); + Transaction tx1 = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_SMART_CONTRACT_BYTECODE, smartContractAddress), 0, NULL_ADDRESS, sender, nonce1); + txs.add(tx1); + + //Call the Proxy + byte[] dataForProxyToCallTheSmartContract = Hex.decode("688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004853255cc00000000000000000000000000000000000000000000000000000000"); //reverts + BigInteger nonce2 = incrementNonce(nonce1); + RskAddress proxyAddress = getContractAddress(sender, nonce1); + Transaction tx2 = buildTransaction(config, dataForProxyToCallTheSmartContract, 0, proxyAddress, sender, nonce2); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.emptySet(), false, false); + } + + @Test + void whenAnInternalTxCallsANonPrecompiledContractAndRevertsPrecompiledContractHasBeenCalledFlagShouldBeFalse() { + List txs = new LinkedList<>(); + + //Deploy a Smart Contract + BigInteger nonce = track.getNonce(sender.getAddress()); + Transaction tx = buildTransaction(config, Hex.decode(SMART_CONTRACT_BYTECODE), 0, NULL_ADDRESS, sender, nonce); + RskAddress smartContractAddress = getContractAddress(sender, nonce); + txs.add(tx); + + //Deploy Proxy to Smart Contract + BigInteger nonce1 = incrementNonce(nonce); + Transaction tx1 = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_SMART_CONTRACT_BYTECODE, smartContractAddress), 0, NULL_ADDRESS, sender, nonce1); + RskAddress proxyAddress = getContractAddress(sender, nonce1); + txs.add(tx1); + + //Call the Proxy + byte[] dataForProxyToCallTheSmartContract = Hex.decode("688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000043bccbbc900000000000000000000000000000000000000000000000000000000"); //reverts + BigInteger nonce2 = incrementNonce(nonce1); + Transaction tx2 = buildTransaction(config, dataForProxyToCallTheSmartContract, 0, proxyAddress, sender, nonce2); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.emptySet(), true, false); + } + + @Test + void whenAnInternalTxCallsAPrecompiledContractPrecompiledContractHasBeenCalledFlagShouldBeTrue() { + List txs = new LinkedList<>(); + + //Deploy Proxy to Identity precompiled contract + BigInteger nonce = track.getNonce(sender.getAddress()); + RskAddress proxyAddress = getContractAddress(sender, nonce); + Transaction tx = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_SMART_CONTRACT_BYTECODE, PrecompiledContracts.IDENTITY_ADDR), 0, NULL_ADDRESS, sender, nonce); + txs.add(tx); + + //Deploy Proxy to Proxy + BigInteger nonce2 = incrementNonce(nonce); + RskAddress proxyToProxy = getContractAddress(sender, nonce2); + Transaction tx1 = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_TO_PROXY_SMART_CONTRACT_BYTECODE, proxyAddress), 0, NULL_ADDRESS, sender, nonce2); + txs.add(tx1); + + //Call Proxy to Proxy + BigInteger nonce3 = incrementNonce(nonce2); + byte[] dataToCallProxyToProxyContract = Hex.decode("688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145fd6eb55d12e759a21c09ef703fe0cba1dc9d88d000000000000000000000000"); + Transaction tx2 = buildTransaction(config, dataToCallProxyToProxyContract, 0, proxyToProxy, sender, nonce3); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.singleton(PrecompiledContracts.IDENTITY_ADDR), false, false); + } + + @Test + void whenAnInternalTxCallsAPrecompiledContractAndThrowsAnExceptionPrecompiledContractHasBeenCalledFlagShouldBeTrue(){ + List txs = new LinkedList<>(); + + //Deploy Proxy to Bridge precompiled contract + BigInteger nonce = track.getNonce(sender.getAddress()); + RskAddress proxyAddress = getContractAddress(sender, nonce);; + Transaction tx = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_SMART_CONTRACT_BYTECODE, PrecompiledContracts.BRIDGE_ADDR), 0, NULL_ADDRESS, sender, nonce); + txs.add(tx); + + //Deploy Proxy to Proxy + BigInteger nonce2 = incrementNonce(nonce); + RskAddress proxyToProxy = getContractAddress(sender, nonce2); + Transaction tx1 = buildTransaction(config, getDeployDataWithAddressAsParameterToProxyConstructor(PROXY_TO_PROXY_SMART_CONTRACT_BYTECODE, proxyAddress), 0, NULL_ADDRESS, sender, nonce2); + txs.add(tx1); + + //Call Proxy to Proxy with data triggers an exception + BigInteger nonce3 = incrementNonce(nonce2); + byte[] dataToCallProxyToProxyContractThatReverts = Hex.decode("688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024e674f5e8000000000000000000000000000000000000000000000000000000000100000600000000000000000000000000000000000000000000000000000000"); + Transaction tx2 = buildTransaction(config, dataToCallProxyToProxyContractThatReverts, 0, proxyToProxy, sender, nonce3); + txs.add(tx2); + + Block aBlockWithATxToAPrecompiledContract = new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(getGenesisBlock(config, track), txs, uncles, difficulty, minGasPrice); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex++, Collections.emptySet(), false, false); + executeATransactionAndAssert(aBlockWithATxToAPrecompiledContract, txIndex, Collections.singleton(PrecompiledContracts.BRIDGE_ADDR), true, false); + } + + private static TransactionExecutorFactory getTransactionExecutorFactory(TestSystemProperties config) { + BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory( + config.getNetworkConstants().getBridgeConstants().getBtcParams()); + BridgeSupportFactory bridgeSupportFactory = new BridgeSupportFactory( + btcBlockStoreFactory, config.getNetworkConstants().getBridgeConstants(), config.getActivationConfig(), blockTxSignatureCache); + return new TransactionExecutorFactory( + config, + new BlockStoreDummy(), + null, + new BlockFactory(config.getActivationConfig()), + new ProgramInvokeFactoryImpl(), + new PrecompiledContracts(config, bridgeSupportFactory, blockTxSignatureCache), + blockTxSignatureCache + ); + } + + private void executeATransactionAndAssert(Block aBlock, int transactionIndex, Set precompiledContractsCalled, boolean hasRevert, boolean threwAnException) { + TransactionExecutor transactionExecutor = transactionExecutorFactory.newInstance(aBlock.getTransactionsList().get(transactionIndex), transactionIndex, aBlock.getCoinbase(), + track, aBlock, 0L); + + boolean txExecuted = transactionExecutor.executeTransaction(); + assertExecutionFlagAndIfRevertedOrThrewAnException(transactionExecutor, txExecuted, precompiledContractsCalled, hasRevert, threwAnException); + } + + private static BigInteger incrementNonce(BigInteger nonce) { + return nonce.add(BigInteger.ONE); + } + + private Block getGenesisBlock(TestSystemProperties config, Repository track) { + BlockGenerator blockGenerator = new BlockGenerator(Constants.regtest(), config.getActivationConfig()); + Block genesis = blockGenerator.getGenesisBlock(); + genesis.setStateRoot(track.getRoot()); + return genesis; + } + + public RskAddress getContractAddress(Account aSender, BigInteger nonce) { + return new RskAddress(HashUtil.calcNewAddr(aSender.getAddress().getBytes(), nonce.toByteArray())); + } + + private static void assertExecutionFlagAndIfRevertedOrThrewAnException(TransactionExecutor txExecutor, boolean txExecuted, Set precompiledContractsCalled, boolean hasRevert, boolean threwAnException) { + Assertions.assertTrue(txExecuted); + ProgramResult transactionResult = txExecutor.getResult(); + Assertions.assertEquals(precompiledContractsCalled, txExecutor.precompiledContractsCalled()); + Exception exception = transactionResult.getException(); + if (threwAnException) { + Assertions.assertNotNull(exception); + } else { + Assertions.assertNull(exception); + } + Assertions.assertEquals(hasRevert, transactionResult.isRevert()); + } + + public byte[] getDeployDataWithAddressAsParameterToProxyConstructor(String data, RskAddress address) { + return Hex.decode(data + address); + } + +/* +- calls a precomp, flag should be true and tx go to seq X +- calls a precomp and revert, same. X +- sends value to a precomp flag should be true. X +- Internal tx calls a precomp so it should go to sequential X +- Internal tx calls a precomp and reverts so it should go to sequential. X +NEGATIVE CASES, IF A REGULAR CONTRACT IS CALLED, FLAG SHOULD BE FALSE, SAME FOR SEND VALUE TO SC AND EOA. + */ + + private Block getABlockWithATx(Repository track, TestSystemProperties config, byte[] data, long value, RskAddress destination, Account account) { + Transaction tx = buildTransaction(config, data, value, destination, account, track.getNonce(account.getAddress())); + List txs = Collections.singletonList( + tx + ); + + Block genesis = getGenesisBlock(config, track); + return new BlockGenerator(Constants.regtest(), config.getActivationConfig()).createChildBlock(genesis, txs, new ArrayList<>(), 1, null); + } + + private static Transaction buildTransaction(TestSystemProperties config, byte[] data, long value, RskAddress destination, Account account, BigInteger nonce) { + Transaction tx = Transaction + .builder() + .nonce(nonce) + .gasPrice(BigInteger.ONE) + .gasLimit(BigInteger.valueOf(2000000)) + .destination(destination) + .chainId(config.getNetworkConstants().getChainId()) + .value(Coin.valueOf(value)) + .data(data) + .build(); + tx.sign(account.getEcKey().getPrivKeyBytes()); + return tx; + } + + private static void initTrackAndAssertIsNotEmpty(Repository track) { + track.commit(); + Assertions.assertFalse(Arrays.equals(EMPTY_TRIE_HASH, track.getRoot())); + } + + private static Repository getRepository() { + TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); + Repository aRepository = new MutableRepository(new MutableTrieImpl(trieStore, new Trie(trieStore))); + return aRepository.startTracking(); + } +} + + +/* Smart contract whose bytecode is PROXY_SMART_CONTRACT_BYTECODE +* +*pragma solidity ^0.8.9; +*contract Proxy { +* +* address precompiledContract; +* +* constructor(address _precompiled) { +* precompiledContract = _precompiled; +* } +* +* function callPrecompiledContract(bytes calldata _data) public payable returns (bool sent, bytes memory ret) { +* (sent, ret) = precompiledContract.call{value: msg.value}(_data); +* require(sent, "Failed to call"); +* } +*} +* */ + +/* Smart contract whose bytecode is PROXY_TO_PROXY_SMART_CONTRACT_BYTECODE +* +* contract ProxyToProxy { +* +* Proxy precompiledContract; +* +* constructor(Proxy _precompiled) { +* precompiledContract = Proxy(_precompiled); +* } +* +* function callPrecompiledContract(bytes calldata _data) public payable returns (bool sent, bytes memory ret) { +* (sent, ret) = precompiledContract.callPrecompiledContract(_data); +* require(sent, "Failed to call"); +* } +*} +* +* +* +* contract Counter { +* +* uint counter = 1; +* +* function sum() public { +* counter++; +* } +* +* function reverts() public { +* reverts(); +* } +*} +* */ \ No newline at end of file diff --git a/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java b/rskj-core/src/test/java/co/rsk/core/bc/transactionexecutor/TransactionExecutorTest.java similarity index 71% rename from rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java rename to rskj-core/src/test/java/co/rsk/core/bc/transactionexecutor/TransactionExecutorTest.java index 200e646b886..a29828ab286 100644 --- a/rskj-core/src/test/java/org/ethereum/core/TransactionExecutorTest.java +++ b/rskj-core/src/test/java/co/rsk/core/bc/transactionexecutor/TransactionExecutorTest.java @@ -15,17 +15,19 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package org.ethereum.core; +package co.rsk.core.bc.transactionexecutor; -import co.rsk.config.VmConfig; +import co.rsk.config.TestSystemProperties; import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.TransactionExecutorFactory; import co.rsk.crypto.Keccak256; import co.rsk.pcc.environment.Environment; import org.ethereum.TestUtils; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; +import org.ethereum.core.*; import org.ethereum.crypto.HashUtil; import org.ethereum.db.BlockStore; import org.ethereum.db.MutableRepository; @@ -39,9 +41,7 @@ import org.mockito.ArgumentCaptor; import java.math.BigInteger; -import java.util.HashSet; import java.util.Random; -import java.util.Set; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; @@ -52,62 +52,54 @@ class TransactionExecutorTest { private static final int MAX_CACHE_SIZE = 900; private ActivationConfig activationConfig; private Constants constants; - private RskAddress rskAddress; private Repository repository; private BlockStore blockStore; private ReceiptStore receiptStore; private BlockFactory blockFactory; private ProgramInvokeFactory programInvokeFactory; private Block executionBlock; - private VmConfig vmConfig; private PrecompiledContracts precompiledContracts; - private Set deletedAccounts; private int txIndex; - private long gasUsedInTheBlock; + private TestSystemProperties config; + private RskAddress receiver; + private RskAddress sender; @BeforeEach void setUp() { // paperwork: mock a whole nice transaction executor + receiver = new RskAddress("0000000000000000000000000000000000000002"); + sender = new RskAddress("0000000000000000000000000000000000000001"); txIndex = 1; - gasUsedInTheBlock = 0; - activationConfig = ActivationConfigsForTest.all(); constants = mock(Constants.class); - rskAddress = mock(RskAddress.class); repository = mock(Repository.class); blockStore = mock(BlockStore.class); receiptStore = mock(ReceiptStore.class); blockFactory = mock(BlockFactory.class); programInvokeFactory = mock(ProgramInvokeFactory.class); executionBlock = mock(Block.class); - vmConfig = mock(VmConfig.class); precompiledContracts = mock(PrecompiledContracts.class); - deletedAccounts = new HashSet<>(); + config = spy(new TestSystemProperties()); + when(config.getActivationConfig()).thenReturn(activationConfig); + when(config.getNetworkConstants()).thenReturn(constants); when(executionBlock.getNumber()).thenReturn(10L); } @Test void testInitHandlesFreeTransactionsOK() { - BlockTxSignatureCache blockTxSignatureCache = mock(BlockTxSignatureCache.class); Transaction transaction = mock(Transaction.class); - TransactionExecutor txExecutor = new TransactionExecutor( - constants, activationConfig, transaction, txIndex, rskAddress, - repository, blockStore, receiptStore, blockFactory, - programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, - true, precompiledContracts, deletedAccounts, - blockTxSignatureCache - ); - - // paperwork: transaction has high gas limit, execution block has normal gas limit // and the nonces are okey when(transaction.getGasLimit()).thenReturn(BigInteger.valueOf(4000000).toByteArray()); when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex, executionBlock.getCoinbase(), repository, executionBlock, 0L); + when(repository.getNonce(transaction.getSender())).thenReturn(BigInteger.valueOf(1L)); when(transaction.getNonce()).thenReturn(BigInteger.valueOf(1L).toByteArray()); // more paperwork, the receiver is just someone - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000001"); when(transaction.getReceiveAddress()).thenReturn(receiver); when(transaction.acceptTransactionSignature(constants.getChainId())).thenReturn(true); // sender has no balance @@ -125,20 +117,20 @@ void txInBlockIsExecutedAndShouldBeAddedInCache(){ BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(receivedTxSignatureCache); MutableRepository cacheTrack = mock(MutableRepository.class); - when(repository.startTracking()).thenReturn(cacheTrack); - - RskAddress sender = new RskAddress("0000000000000000000000000000000000000001"); - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000002"); byte[] gasLimit = BigInteger.valueOf(4000000).toByteArray(); byte[] txNonce = BigInteger.valueOf(1L).toByteArray(); Coin gasPrice = Coin.valueOf(1); Coin value = new Coin(BigInteger.valueOf(2)); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); + when(repository.startTracking()).thenReturn(cacheTrack); + mockRepositoryForAnAccountWithBalance(sender, 68000L); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value); + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex, executionBlock.getCoinbase(), repository, executionBlock, 0L); - assertTrue(executeValidTransaction(transaction, blockTxSignatureCache)); + assertTrue(txExecutor.executeTransaction()); assertNotNull(blockTxSignatureCache.getSender(transaction)); assertArrayEquals(blockTxSignatureCache.getSender(transaction).getBytes(), sender.getBytes()); } @@ -148,27 +140,27 @@ void TwoTxsAreInBlockAndThemShouldBeContainedInCache() { ReceivedTxSignatureCache receivedTxSignatureCache = mock(ReceivedTxSignatureCache.class); BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(receivedTxSignatureCache); MutableRepository cacheTrack = mock(MutableRepository.class); - when(repository.startTracking()).thenReturn(cacheTrack); - RskAddress sender = new RskAddress("0000000000000000000000000000000000000001"); RskAddress sender2 = new RskAddress("0000000000000000000000000000000000000003"); - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000002"); byte[] gasLimit = BigInteger.valueOf(4000000).toByteArray(); byte[] txNonce = BigInteger.valueOf(1L).toByteArray(); Coin gasPrice = Coin.valueOf(1); Coin value = new Coin(BigInteger.valueOf(2)); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); - Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value, 1); + when(repository.startTracking()).thenReturn(cacheTrack); + mockRepositoryForAnAccountWithBalance(sender, 68000L); + mockRepositoryForAnAccountWithBalance(sender2, 68000L); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); - assertTrue(executeValidTransaction(transaction, blockTxSignatureCache)); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value, 1); + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex++, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor.executeTransaction()); - when(repository.getNonce(sender2)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender2)).thenReturn(new Coin(BigInteger.valueOf(68000L))); Transaction transaction2 = getTransaction(sender2, receiver, gasLimit, txNonce, gasPrice, value, 2); - - assertTrue(executeValidTransaction(transaction2, blockTxSignatureCache)); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + TransactionExecutor txExecutor1 = transactionExecutorFactory.newInstance(transaction2, txIndex, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor1.executeTransaction()); assertNotNull(blockTxSignatureCache.getSender(transaction)); assertArrayEquals(blockTxSignatureCache.getSender(transaction).getBytes(), sender.getBytes()); @@ -197,9 +189,13 @@ void PrecompiledContractInitShouldBeCalledWithCacheTrack() { when(precompiledContracts.getContractForAddress(any(ActivationConfig.ForBlock.class), eq(DataWord.valueOf(receiver.getBytes())))).thenReturn(precompiledContract); when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value, 1); - assertTrue(executeValidTransaction(transaction, blockTxSignatureCache)); + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex++, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor.executeTransaction()); ArgumentCaptor argsCaptor = ArgumentCaptor.forClass(PrecompiledContractArgs.class); @@ -209,32 +205,23 @@ void PrecompiledContractInitShouldBeCalledWithCacheTrack() { } @Test - void InvalidTxsIsInBlockAndShouldntBeInCache(){ + void InvalidTxsIsInBlockAndShouldntBeInCache() { ReceivedTxSignatureCache receivedTxSignatureCache = mock(ReceivedTxSignatureCache.class); BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(receivedTxSignatureCache); MutableRepository cacheTrack = mock(MutableRepository.class); - when(repository.startTracking()).thenReturn(cacheTrack); - - RskAddress sender = new RskAddress("0000000000000000000000000000000000000001"); - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000002"); byte[] gasLimit = BigInteger.valueOf(4000000).toByteArray(); byte[] txNonce = BigInteger.valueOf(1L).toByteArray(); Coin gasPrice = Coin.valueOf(1); Coin value = new Coin(BigInteger.valueOf(2)); - Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value); + when(repository.startTracking()).thenReturn(cacheTrack); + mockRepositoryForAnAccountWithBalance(sender, 0L); when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(0L))); - TransactionExecutor txExecutor = new TransactionExecutor( - constants, activationConfig, transaction, txIndex, rskAddress, - repository, blockStore, receiptStore, blockFactory, - programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, - true, precompiledContracts, deletedAccounts, - blockTxSignatureCache - ); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value); + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex, executionBlock.getCoinbase(), repository, executionBlock, 0L); assertEquals(0, transaction.transactionCost(constants, activationConfig.forBlock(executionBlock.getNumber()), new BlockTxSignatureCache(new ReceivedTxSignatureCache()))); assertFalse(txExecutor.executeTransaction()); @@ -247,27 +234,19 @@ void remascTxIsReceivedAndShouldntBeInCache(){ BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(receivedTxSignatureCache); MutableRepository cacheTrack = mock(MutableRepository.class); - when(repository.startTracking()).thenReturn(cacheTrack); - RskAddress sender = PrecompiledContracts.REMASC_ADDR; - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000002"); byte[] gasLimit = BigInteger.valueOf(4000000).toByteArray(); byte[] txNonce = BigInteger.valueOf(1L).toByteArray(); Coin gasPrice = Coin.valueOf(1); Coin value = new Coin(BigInteger.valueOf(2)); - Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value); + when(repository.startTracking()).thenReturn(cacheTrack); + mockRepositoryForAnAccountWithBalance(sender, 0L); when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(0L))); - TransactionExecutor txExecutor = new TransactionExecutor( - constants, activationConfig, transaction, txIndex, rskAddress, - repository, blockStore, receiptStore, blockFactory, - programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, - true, precompiledContracts, deletedAccounts, - blockTxSignatureCache - ); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value); + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex, executionBlock.getCoinbase(), repository, executionBlock, 0L); assertEquals(0, transaction.transactionCost(constants, activationConfig.forBlock(executionBlock.getNumber()), new BlockTxSignatureCache(new ReceivedTxSignatureCache()))); assertFalse(txExecutor.executeTransaction()); @@ -280,22 +259,25 @@ void txInBlockIsReceivedAndShouldBeUsedInTxExecutorInsteadOfComputeSender(){ BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(receivedTxSignatureCache); MutableRepository cacheTrack = mock(MutableRepository.class); - when(repository.startTracking()).thenReturn(cacheTrack); - - RskAddress sender = new RskAddress("0000000000000000000000000000000000000001"); - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000002"); byte[] gasLimit = BigInteger.valueOf(4000000).toByteArray(); byte[] txNonce = BigInteger.valueOf(1L).toByteArray(); Coin gasPrice = Coin.valueOf(1); Coin value = new Coin(BigInteger.valueOf(2)); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); + when(repository.startTracking()).thenReturn(cacheTrack); + mockRepositoryForAnAccountWithBalance(sender, 68000L); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value); when(receivedTxSignatureCache.getSender(transaction)).thenReturn(sender); - assertTrue(executeValidTransaction(transaction, blockTxSignatureCache)); - assertTrue(executeValidTransaction(transaction, blockTxSignatureCache)); //Execute two times the same tx + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex++, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor.executeTransaction()); + + TransactionExecutor txExecutor1 = transactionExecutorFactory.newInstance(transaction, txIndex, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor1.executeTransaction()); //Execute two times the same tx + verify(receivedTxSignatureCache, times(1)).getSender(transaction); assertArrayEquals(blockTxSignatureCache.getSender(transaction).getBytes(), sender.getBytes()); } @@ -306,19 +288,21 @@ void firstTxIsRemovedWhenTheCacheLimitSizeIsExceeded() { BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(receivedTxSignatureCache); MutableRepository cacheTrack = mock(MutableRepository.class); - when(repository.startTracking()).thenReturn(cacheTrack); - RskAddress sender = new RskAddress("0000000000000000000000000000000000000001"); - RskAddress receiver = new RskAddress("0000000000000000000000000000000000000002"); byte[] gasLimit = BigInteger.valueOf(4000000).toByteArray(); byte[] txNonce = BigInteger.valueOf(1L).toByteArray(); Coin gasPrice = Coin.valueOf(1); Coin value = new Coin(BigInteger.valueOf(2)); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); + when(repository.startTracking()).thenReturn(cacheTrack); + mockRepositoryForAnAccountWithBalance(sender, 68000L); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value, -1); - assertTrue(executeValidTransaction(transaction, blockTxSignatureCache)); + + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex++, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor.executeTransaction()); Random random = new Random(TransactionExecutorTest.class.hashCode()); for (int i = 0; i < MAX_CACHE_SIZE; i++) { @@ -326,10 +310,12 @@ void firstTxIsRemovedWhenTheCacheLimitSizeIsExceeded() { assertNotNull(blockTxSignatureCache.getSender(transaction)); } sender = new RskAddress(TestUtils.generateBytesFromRandom(random,20)); - when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); - when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); + mockRepositoryForAnAccountWithBalance(sender, 68000L); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + Transaction transactionAux = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value, i); - assertTrue(executeValidTransaction(transactionAux, blockTxSignatureCache)); + txExecutor = transactionExecutorFactory.newInstance(transactionAux, txIndex++, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor.executeTransaction()); } assertNotNull(blockTxSignatureCache.getSender(transaction)); @@ -355,9 +341,13 @@ void callInitFromPrecompiledContract() { when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(68000L))); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); + Transaction transaction = getTransaction(sender, receiver, gasLimit, txNonce, gasPrice, value, 1); - executeValidTransaction(transaction, blockTxSignatureCache); + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory(config, blockStore, receiptStore, blockFactory, programInvokeFactory, precompiledContracts, blockTxSignatureCache); + TransactionExecutor txExecutor = transactionExecutorFactory.newInstance(transaction, txIndex++, executionBlock.getCoinbase(), repository, executionBlock, 0L); + assertTrue(txExecutor.executeTransaction()); ArgumentCaptor argsCaptor = ArgumentCaptor.forClass(PrecompiledContractArgs.class); @@ -366,18 +356,9 @@ void callInitFromPrecompiledContract() { assertNull(argsCaptor.getValue().getProgramInvoke()); } - private boolean executeValidTransaction(Transaction transaction, BlockTxSignatureCache blockTxSignatureCache) { - when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(6800000).toByteArray()); - - TransactionExecutor txExecutor = new TransactionExecutor( - constants, activationConfig, transaction, txIndex, rskAddress, - repository, blockStore, receiptStore, blockFactory, - programInvokeFactory, executionBlock, gasUsedInTheBlock, vmConfig, - true, precompiledContracts, deletedAccounts, - blockTxSignatureCache - ); - - return txExecutor.executeTransaction(); + private void mockRepositoryForAnAccountWithBalance(RskAddress sender, long val) { + when(repository.getNonce(sender)).thenReturn(BigInteger.valueOf(1L)); + when(repository.getBalance(sender)).thenReturn(new Coin(BigInteger.valueOf(val))); } private Transaction getTransaction(RskAddress sender, RskAddress receiver, byte[] gasLimit, byte[] txNonce, Coin gasPrice, Coin value) { diff --git a/rskj-core/src/test/java/co/rsk/core/parallel/ParallelExecutionStateTest.java b/rskj-core/src/test/java/co/rsk/core/parallel/ParallelExecutionStateTest.java new file mode 100644 index 00000000000..bcc19ae0620 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/parallel/ParallelExecutionStateTest.java @@ -0,0 +1,1305 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * 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.core.parallel; + +import co.rsk.config.TestSystemProperties; +import co.rsk.core.RskAddress; +import co.rsk.test.World; +import co.rsk.test.dsl.DslParser; +import co.rsk.test.dsl.DslProcessorException; +import co.rsk.test.dsl.WorldDslProcessor; +import com.typesafe.config.ConfigValueFactory; +import org.ethereum.crypto.HashUtil; +import org.ethereum.datasource.HashMapDB; +import org.ethereum.db.ReceiptStore; +import org.ethereum.db.ReceiptStoreImpl; +import org.ethereum.core.Transaction; +import org.ethereum.vm.GasCost; +import org.ethereum.vm.PrecompiledContracts; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nullable; +import java.math.BigInteger; +import java.util.*; + +import static co.rsk.core.bc.transactionexecutor.PrecompiledContractHasBeenCalledTest.PROXY_SMART_CONTRACT_BYTECODE; +import static co.rsk.core.bc.transactionexecutor.PrecompiledContractHasBeenCalledTest.PROXY_TO_PROXY_SMART_CONTRACT_BYTECODE; +import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; + +class ParallelExecutionStateTest { + + public static final byte[] FAILED_STATUS = EMPTY_BYTE_ARRAY; + + private World createWorld(int rskip144) { + return createWorld(rskip144, null); + } + + private World createWorld(int rskip144, @Nullable Set concurrentContractsDisallowed) { + ReceiptStore receiptStore = new ReceiptStoreImpl(new HashMapDB()); + TestSystemProperties config = new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.consensusRules.rskip144", ConfigValueFactory.fromAnyRef(rskip144)) + ); + if (concurrentContractsDisallowed != null) { + config.setConcurrentContractsDisallowed(concurrentContractsDisallowed); + } + + return new World(receiptStore, config); + } + + private World createWorldAndProcess(String dsl, int rskip144ActivationHeight) throws DslProcessorException { + return createWorldAndProcess(dsl, rskip144ActivationHeight, null); + } + + private World createWorldAndProcess(String dsl, int rskip144ActivationHeight, @Nullable Set concurrentContractsDisallowed) throws DslProcessorException { + World world = createWorld(rskip144ActivationHeight, concurrentContractsDisallowed); + + DslParser parser = new DslParser(dsl); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + return world; + } + + /** + * compares the state root of a blockchain with and without rskip 144 + * @param dsl the dsl string of the blockchain + * @param expectedEdges the tx execution edges to assert equals + * @throws DslProcessorException + */ + private void compareStateRootPreAndPostRSKIP144AndTestEdges(String dsl, short[] expectedEdges) throws DslProcessorException { + World parallel = this.createWorldAndProcess(dsl, 0); + World series = this.createWorldAndProcess(dsl, -1); + + compareTwoWorldsAndTestEdges(series, parallel, expectedEdges); + } + + private void compareTwoWorldsAndTestEdges(World series, World parallel, short[] expectedEdges) { + Assertions.assertArrayEquals( + this.getStateRoot(series), + this.getStateRoot(parallel) + ); + + Assertions.assertArrayEquals(expectedEdges, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + private byte[] getStateRoot (World world) { + return world.getBlockChain().getBestBlock().getHeader().getStateRoot(); + } + + /** + * // SPDX-License-Identifier: UNLICENSED + * pragma solidity ^0.8.9; + * + * contract ReadWrite { + * uint x; + * uint another; + * + * receive() external payable {} + * function read() external { another = x; } + * function write(uint value) external { x = value; } + * function update(uint increment) external { x += increment; } + * + * function readWithRevert() external { another = x; revert(); } + * function writeWithRevert(uint value) external { x = value; revert(); } + * function updateWithRevert(uint increment) external { x += increment; revert(); } + * + * mapping (uint => uint) r; + * + * function wasteGas(uint gas, uint writeToX, uint writeToY) external { + * uint i = uint(keccak256(abi.encode(0x12349876))); + * r[writeToX] = i; + * r[writeToY] = i; + * uint gasLeft = gasleft(); + * while (gasLeft < gas + gasleft()) { + * unchecked { + * i = (i / 7 + 10) * 8; + * } + * } + * } + * } + * + * contract Proxy { + * ReadWrite readWrite; + * constructor (ReadWrite _readWrite) { readWrite = _readWrite; } + * function read() external { readWrite.read(); } + * function write(uint value) external { readWrite.write(value); } + * function update(uint increment) external { readWrite.update(increment); } + * } + */ + + // creation codes + + private final String creationData = "608060405234801561001057600080fd5b50610473806100206000396000f3fe6080604052600436106100745760003560e01c806334b091931161004e57806334b09193146100e957806357de26a41461011257806382ab890a14610129578063e2033a13146101525761007b565b80630d2a2d8d146100805780631b892f87146100975780632f048afa146100c05761007b565b3661007b57005b600080fd5b34801561008c57600080fd5b5061009561017b565b005b3480156100a357600080fd5b506100be60048036038101906100b991906102bb565b610188565b005b3480156100cc57600080fd5b506100e760048036038101906100e291906102bb565b6101a4565b005b3480156100f557600080fd5b50610110600480360381019061010b91906102e8565b6101ae565b005b34801561011e57600080fd5b5061012761024f565b005b34801561013557600080fd5b50610150600480360381019061014b91906102bb565b61025a565b005b34801561015e57600080fd5b50610179600480360381019061017491906102bb565b610275565b005b6000546001819055600080fd5b80600080828254610199919061036a565b925050819055600080fd5b8060008190555050565b600063123498766040516020016101c591906103f3565b6040516020818303038152906040528051906020012060001c905080600260008581526020019081526020016000208190555080600260008481526020019081526020016000208190555060005a90505b5a85610222919061036a565b811015610248576008600a6007848161023e5761023d61040e565b5b0401029150610216565b5050505050565b600054600181905550565b8060008082825461026b919061036a565b9250508190555050565b806000819055600080fd5b600080fd5b6000819050919050565b61029881610285565b81146102a357600080fd5b50565b6000813590506102b58161028f565b92915050565b6000602082840312156102d1576102d0610280565b5b60006102df848285016102a6565b91505092915050565b60008060006060848603121561030157610300610280565b5b600061030f868287016102a6565b9350506020610320868287016102a6565b9250506040610331868287016102a6565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061037582610285565b915061038083610285565b92508282019050808211156103985761039761033b565b5b92915050565b6000819050919050565b600063ffffffff82169050919050565b6000819050919050565b60006103dd6103d86103d38461039e565b6103b8565b6103a8565b9050919050565b6103ed816103c2565b82525050565b600060208201905061040860008301846103e4565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea264697066735822122081578079990ee4f4eaa55ebeeedcb31b8f178ab346b989e62541a894e60d381164736f6c63430008110033"; + private String getProxyCreationCode (String address) { + return "608060405234801561001057600080fd5b50604051610417380380610417833981810160405281019061003291906100ed565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061011a565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100a88261007d565b9050919050565b60006100ba8261009d565b9050919050565b6100ca816100af565b81146100d557600080fd5b50565b6000815190506100e7816100c1565b92915050565b60006020828403121561010357610102610078565b5b6000610111848285016100d8565b91505092915050565b6102ee806101296000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632f048afa1461004657806357de26a41461006257806382ab890a1461006c575b600080fd5b610060600480360381019061005b9190610261565b610088565b005b61006a610116565b005b61008660048036038101906100819190610261565b610198565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632f048afa826040518263ffffffff1660e01b81526004016100e1919061029d565b600060405180830381600087803b1580156100fb57600080fd5b505af115801561010f573d6000803e3d6000fd5b5050505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357de26a46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561017e57600080fd5b505af1158015610192573d6000803e3d6000fd5b50505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166382ab890a826040518263ffffffff1660e01b81526004016101f1919061029d565b600060405180830381600087803b15801561020b57600080fd5b505af115801561021f573d6000803e3d6000fd5b5050505050565b600080fd5b6000819050919050565b61023e8161022b565b811461024957600080fd5b50565b60008135905061025b81610235565b92915050565b60006020828403121561027757610276610226565b5b60006102858482850161024c565b91505092915050565b6102978161022b565b82525050565b60006020820190506102b2600083018461028e565b9291505056fea264697066735822122034c249e40cf35f03e8970cf8c91dbaf8426d01814edfcb782e7548b32f6d9e7964736f6c63430008110033000000000000000000000000" + + address; + } + + // call data + + // write(10) + private final String writeTen = "2f048afa000000000000000000000000000000000000000000000000000000000000000a"; + // read() + private final String readData = "57de26a4"; + // update(10) + private final String updateByTen = "82ab890a000000000000000000000000000000000000000000000000000000000000000a"; + // writeWithRevert(10) + private final String writeTenWithRevert = "0d2a2d8d"; + // readWithRevert() + private final String readDataWithRevert = "e2033a13000000000000000000000000000000000000000000000000000000000000000a"; + // updateWithRevert(10) + private final String updateByTenWithRevert = "1b892f87000000000000000000000000000000000000000000000000000000000000000a"; + // wasteGas(1000000, 0, 0) + private final String wasteOneMillionGas = "34b0919300000000000000000000000000000000000000000000000000000000000f4d4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + // wasteGas(100000, 0, 0) + private final String wasteHundredThousandGas = "34b0919300000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + // wasteGas(100000, 1, 1) + private final String writeToX = "34b0919300000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"; + // wasteGas(100000, 2, 2) + private final String writeToY = "34b0919300000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002"; + // wasteGas(100000, 1, 2) + private final String writeToXAndY = "34b0919300000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"; + // wasteGas(1000000, 1, 1) + private final String writeToXWastingGas = "34b0919300000000000000000000000000000000000000000000000000000000000f4d4000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"; + // wasteGas(1000000, 2, 2) + private final String writeToYWastingGas = "34b0919300000000000000000000000000000000000000000000000000000000000f4d4000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002"; + // wasteGas(1000000, 1, 2) + private final String writeToXAndYWastingGas = "34b0919300000000000000000000000000000000000000000000000000000000000f4d4000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"; + + // substrings for dsl text + private final String createThreeAccounts = "account_new acc1 10000000\n" + + "account_new acc2 10000000\n" + + "account_new acc3 10000000\n" + + "\n"; + + private final String createContractInBlock01 = + "transaction_build tx01\n" + + " sender acc3\n" + + " receiverAddress 00\n" + + " data " + creationData + "\n" + + " gas 500000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n"; + + private final String buildBlockWithTwoTxs = "block_build b02\n" + + " parent b01\n" + + " transactions tx02 tx03\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "\n" + + "assert_best b02\n" + + "\n"; + + private final String validateTxs = "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "\n"; + + private String skeleton(String txs, boolean validate) { + return createThreeAccounts + + createContractInBlock01 + + txs + + buildBlockWithTwoTxs + + (validate ? validateTxs : ""); + } + + /** + * creates the contract, performs two calls from different accounts + * tests the state root and the tx edges + * @param firstCall call data for the first tx + * @param secondCall call data for the second tx + * @param edges expected tx edges + * @param validate allows to prevent validating txs are successful + * @throws DslProcessorException + */ + private void createContractAndTestCallWith(String firstCall, String secondCall, short[] edges, boolean validate) throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges(skeleton( + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + firstCall + "\n" + + " gas 100000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + secondCall + "\n" + + " gas 100000\n" + + " build\n" + + "\n", validate), edges); + } + + private void createContractAndTestCall(String firstCall, String secondCall, short[] edges) throws DslProcessorException { + createContractAndTestCallWith(firstCall, secondCall, edges, true); + } + + private void createContractAndTestCallWithRevert(String firstCall, String secondCall, short[] edges) throws DslProcessorException { + createContractAndTestCallWith(firstCall, secondCall, edges, false); + } + + // For tests calling with proxy contract + private World processCallWithContract(String firstCall, String secondCall, int rskip144) throws DslProcessorException { + World world = createWorld(rskip144); + + DslParser parser = new DslParser(createThreeAccounts + + createContractInBlock01 + + "assert_tx_success tx01\n"); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String readWriteAddress = world.getTransactionByName("tx01").getContractAddress().toHexString(); + + String createProxy = "transaction_build tx02\n" + + " sender acc3\n" + + " receiverAddress 00\n" + + " data " + getProxyCreationCode(readWriteAddress) + "\n" + + " gas 600000\n" + + " nonce 1\n" + + " build\n" + + "\n" + + "block_build b02\n" + + " parent b01\n" + + " transactions tx02\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "assert_tx_success tx02\n" + + "\n"; + + String sendTwoTxs = "transaction_build tx03\n" + + " sender acc1\n" + + " contract tx02\n" + + " data " + firstCall + "\n" + + " gas 100000\n" + + " build\n" + + "\n" + + "transaction_build tx04\n" + + " sender acc2\n" + + " contract tx02\n" + + " data " + secondCall + "\n" + + " gas 100000\n" + + " build\n" + + "\n" + + "block_build b03\n" + + " parent b02\n" + + " transactions tx03 tx04\n" + + " build\n" + + "\n" + + "block_connect b03\n" + + "assert_tx_success tx03 tx04\n"; + + parser = new DslParser(createProxy + sendTwoTxs); + processor.processCommands(parser); + + RskAddress proxyAddress = world.getTransactionByName("tx02").getContractAddress(); + Assertions.assertNotNull(world.getRepository().getCode(proxyAddress)); + + List txList = world.getBlockChain().getBestBlock().getTransactionsList(); + Assertions.assertEquals(proxyAddress, txList.get(0).getReceiveAddress()); + Assertions.assertEquals(proxyAddress, txList.get(0).getReceiveAddress()); + + return world; + } + + private void createContractAndTestCallWithContract(String firstCall, String secondCall, short[] expectedEdges) throws DslProcessorException { + World parallel = processCallWithContract(firstCall, secondCall, 0); + World series = processCallWithContract(firstCall, secondCall, -1); + + compareTwoWorldsAndTestEdges(series, parallel, expectedEdges); + } + + @Test + void empty() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges("block_chain g00", null); + } + + @Test + void oneTx() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges("account_new acc1 10000000\n" + + "account_new acc2 0\n" + + "\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiver acc2\n" + + " value 1000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "assert_balance acc2 1000\n" + + "\n", new short[]{ 1 }); + } + + // 1. A and B have the same sender account + @Test + void sameSender() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges("account_new acc1 10000000\n" + + "account_new acc2 0\n" + + "\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiver acc2\n" + + " value 1000\n" + + " nonce 0\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc1\n" + + " receiver acc2\n" + + " value 1000\n" + + " nonce 1\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_balance acc2 2000\n" + + "\n", new short[]{ 2 }); + } + + // 2. A and B transfer value to the same destination account + @Test + void sameRecipient() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges("account_new acc1 10000000\n" + + "account_new acc2 10000000\n" + + "account_new acc3 0\n" + + "\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiver acc3\n" + + " value 1000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc2\n" + + " receiver acc3\n" + + " value 1000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_balance acc3 2000\n" + + "\n", new short[]{ 2 }); + } + + // 3. A and B transfer value to the same smart contract + @Test + void sameContractRecipient() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges(createThreeAccounts + + createContractInBlock01 + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " value 1000\n" + + " gas 100000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc2\n" + + " contract tx01\n" + + " value 1000\n" + + " gas 100000\n" + + " build\n" + + "\n" + + buildBlockWithTwoTxs + validateTxs, new short[]{ 2 }); + } + + // 4. B reads a smart contract variable that A writes + @Test + void readWrite() throws DslProcessorException { + this.createContractAndTestCall(writeTen, readData, new short[]{ 2 }); + } + + @Test + void readWriteWithRevert() throws DslProcessorException { + this.createContractAndTestCallWithRevert(writeTen, readDataWithRevert, new short[]{ 2 }); + } + + @Test + void readWriteWithContract() throws DslProcessorException { + this.createContractAndTestCallWithContract(writeTen, readData, new short[]{ 2 }); + } + + // 5. B reads a smart contract variable that A updates (i.e., +=) + @Test + void readUpdate() throws DslProcessorException { + this.createContractAndTestCall(updateByTen, readData, new short[]{ 2 }); + } + + @Test + void readUpdateWithRevert() throws DslProcessorException { + this.createContractAndTestCallWithRevert(updateByTen, readDataWithRevert, new short[]{ 2 }); + } + + @Test + void readUpdateWithContract() throws DslProcessorException { + this.createContractAndTestCallWithContract(updateByTen, readData, new short[]{ 2 }); + } + + //6. B writes a smart contract variable that A writes + @Test + void writeWrite() throws DslProcessorException { + this.createContractAndTestCall(writeTen, writeTen, new short[]{ 2 }); + } + + @Test + void writeWriteWithRevert() throws DslProcessorException { + this.createContractAndTestCallWithRevert(writeTen, writeTenWithRevert, new short[]{ 2 }); + } + + @Test + void writeWriteWithContract() throws DslProcessorException { + this.createContractAndTestCallWithContract(writeTen, writeTen, new short[]{ 2 }); + } + + // 7. B writes a smart contract variable that A updates + @Test + void writeUpdate() throws DslProcessorException { + this.createContractAndTestCall(updateByTen, writeTen, new short[]{ 2 }); + } + + @Test + void writeUpdateWithRevert() throws DslProcessorException { + this.createContractAndTestCallWithRevert(updateByTen, writeTenWithRevert, new short[]{ 2 }); + } + + @Test + void writeUpdateWithContract() throws DslProcessorException { + this.createContractAndTestCallWithContract(updateByTen, writeTen, new short[]{ 2 }); + } + + // 8. B writes a smart contract variable that A reads + @Test + void writeRead() throws DslProcessorException { + this.createContractAndTestCall(readData, writeTen, new short[]{ 2 }); + } + + @Test + void writeReadWithRevert() throws DslProcessorException { + this.createContractAndTestCallWithRevert(readData, writeTenWithRevert, new short[]{ 2 }); + } + + @Test + void writeReadWithContract() throws DslProcessorException { + this.createContractAndTestCallWithContract(readData, writeTen, new short[]{ 2 }); + } + + // 9. B updates a smart contract variable that A writes + @Test + void updateWrite() throws DslProcessorException { + this.createContractAndTestCall(writeTen, updateByTen, new short[]{ 2 }); + } + + @Test + void updateWriteWithRevert() throws DslProcessorException { + this.createContractAndTestCallWithRevert(writeTen, updateByTenWithRevert, new short[]{ 2 }); + } + + @Test + void updateWriteWithContract() throws DslProcessorException { + this.createContractAndTestCallWithContract(writeTen, updateByTen, new short[]{ 2 }); + } + + // 10. B updates a smart contract variable that A reads + @Test + void updateRead() throws DslProcessorException { + this.createContractAndTestCall(readData, updateByTen, new short[]{ 2 }); + } + + // 11. B updates a smart contract variable that A updates + @Test + void updateUpdate() throws DslProcessorException { + this.createContractAndTestCall(updateByTen, updateByTen, new short[]{ 2 }); + } + + // 12. B calls a smart contract that A creates + @Test + void callCreatedContract() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges("account_new acc1 10000000\n" + + "account_new acc2 10000000\n" + + "\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + creationData + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + writeTen + "\n" + + " gas 100000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 10000000\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "\n", new short[]{ 2 }); + } + + // 13. B transfers value to a smart contract that A creates + @Test + void sendToCreatedContract() throws DslProcessorException { + this.compareStateRootPreAndPostRSKIP144AndTestEdges("account_new acc1 10000000\n" + + "account_new acc2 10000000\n" + + "\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + creationData + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc2\n" + + " contract tx01\n" + + " value 10000\n" + + " gas 100000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_balance tx01 10000\n" + + "\n", new short[]{ 2 }); + } + + // 2. A is in a parallel sublist without enough gas available: B is placed in the sequential sublist + @Test + void useSequentialForGas() throws DslProcessorException { + World parallel = this.createWorldAndProcess(skeleton("transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + wasteOneMillionGas + "\n" + + " gas 1500000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + wasteOneMillionGas + "\n" + + " gas 1500000\n" + + " build\n" + + "\n", true), 0); + + Assertions.assertEquals(7500000L, GasCost.toGas(parallel.getBlockChain().getBestBlock().getHeader().getGasLimit())); + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[] { 1 }, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + // 3. A is in the sequential sublist: B is placed in the sequential sublist + @Test + void useSequentialForCollisionWithSequential() throws DslProcessorException { + World parallel = this.createWorldAndProcess(createThreeAccounts + + createContractInBlock01 + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + wasteOneMillionGas + "\n" + + " gas 1500000\n" + + " nonce 0\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + wasteOneMillionGas + "\n" + + " gas 1500000\n" + + " nonce 1\n" + + " build\n" + + "\n" + // goes to sequential + "transaction_build tx04\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + wasteHundredThousandGas + "\n" + + " gas 200000\n" + + " build\n" + + "\n" + + "block_build b02\n" + + " parent b01\n" + + " transactions tx02 tx03 tx04\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "\n" + + "assert_best b02\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "assert_tx_success tx04\n" + + "\n", 0); + + Assertions.assertEquals(7500000L, GasCost.toGas(parallel.getBlockChain().getBestBlock().getHeader().getGasLimit())); + Assertions.assertEquals(3, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[] { 1 }, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + // 1. A and B are in different parallel sublists with enough gas: C is placed in the sequential sublist + @Test + void useSequentialForCollisionWithTwoParallel() throws DslProcessorException { + World parallel = this.createWorldAndProcess(createThreeAccounts + + "account_new acc4 10000000\n" + + createContractInBlock01 + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + writeToX + "\n" + + " gas 200000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + writeToY + "\n" + + " gas 200000\n" + + " build\n" + + "\n" + + "transaction_build tx04\n" + + " sender acc4\n" + + " contract tx01\n" + + " data " + writeToXAndY + "\n" + + " gas 200000\n" + + " build\n" + + "\n" + + "block_build b02\n" + + " parent b01\n" + + " transactions tx02 tx03 tx04\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "\n" + + "assert_best b02\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "assert_tx_success tx04\n" + + "\n", 0); + + Assertions.assertEquals(7500000L, GasCost.toGas(parallel.getBlockChain().getBestBlock().getHeader().getGasLimit())); + Assertions.assertEquals(3, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[] { 1, 2 }, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + // 2. A and B are in different parallel sublists without enough gas: C is placed in the sequential sublist + @Test + void useSequentialForCollisionWithTwoParallelWithoutGas() throws DslProcessorException { + World parallel = this.createWorldAndProcess(createThreeAccounts + + "account_new acc4 10000000\n" + + createContractInBlock01 + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + writeToXWastingGas + "\n" + + " gas 1500000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + writeToYWastingGas + "\n" + + " gas 1500000\n" + + " build\n" + + "\n" + // goes to sequential + "transaction_build tx04\n" + + " sender acc4\n" + + " contract tx01\n" + + " data " + writeToXAndYWastingGas + "\n" + + " gas 1500000\n" + + " build\n" + + "\n" + + "block_build b02\n" + + " parent b01\n" + + " transactions tx02 tx03 tx04\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "\n" + + "assert_best b02\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "assert_tx_success tx04\n" + + "\n", 0); + + Assertions.assertEquals(7500000L, GasCost.toGas(parallel.getBlockChain().getBestBlock().getHeader().getGasLimit())); + Assertions.assertEquals(3, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[] { 1, 2 }, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + // 3. A is in a parallel sublist and B is in the sequential sublist: C is placed in the sequential sublist + @Test + void useSequentialForCollisionWithSequentialAndParallel() throws DslProcessorException { + World parallel = this.createWorldAndProcess(createThreeAccounts + + "account_new acc4 10000000\n" + + createContractInBlock01 + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + writeToXWastingGas + "\n" + + " gas 1500000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + writeToXWastingGas + "\n" + + " gas 1500000\n" + + " nonce 1\n" + + " build\n" + + "\n" + // goes to sequential + "transaction_build tx04\n" + + " sender acc2\n" + + " contract tx01\n" + + " data " + writeToY + "\n" + + " gas 200000\n" + + " build\n" + + "\n" + + "transaction_build tx05\n" + + " sender acc4\n" + + " contract tx01\n" + + " data " + writeToXAndY + "\n" + + " gas 200000\n" + + " build\n" + + "\n" + + "block_build b02\n" + + " parent b01\n" + + " transactions tx02 tx03 tx04 tx05\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "\n" + + "assert_best b02\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "assert_tx_success tx04\n" + + "assert_tx_success tx05\n" + + "\n", 0); + + Assertions.assertEquals(7500000L, GasCost.toGas(parallel.getBlockChain().getBestBlock().getHeader().getGasLimit())); + Assertions.assertEquals(4, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[] { 1, 2 }, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAPrecompiledItShouldGoToSequentialIfDisabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress " + PrecompiledContracts.IDENTITY_ADDR +"\n"+ + " data " + "1234" + "\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.singleton(PrecompiledContracts.IDENTITY_ADDR)); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAPrecompiledItShouldGoToParallelIfEnabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress " + PrecompiledContracts.IDENTITY_ADDR +"\n"+ + " data " + "1234" + "\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.emptySet()); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxSendsValueToAPrecompiledItShouldGoToSequentialIfDisabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress " + PrecompiledContracts.IDENTITY_ADDR +"\n"+ + " value 1000\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.singleton(PrecompiledContracts.IDENTITY_ADDR)); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxSendsValueToAPrecompiledItShouldGoToParallelIfEnabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress " + PrecompiledContracts.IDENTITY_ADDR +"\n"+ + " value 1000\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.emptySet()); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAPrecompiledThatThrowsAnExceptionShouldGoToSequentialIfDisabled() throws DslProcessorException { + // TX01 throws an exception, though, there is no way to check from out of the execution if the precompiled contract call has failed. + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress " + PrecompiledContracts.BRIDGE_ADDR +"\n"+ + " data " + "e674f5e80000000000000000000000000000000000000000000000000000000001000006" + "\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.singleton(PrecompiledContracts.BRIDGE_ADDR)); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAPrecompiledThatThrowsAnExceptionShouldGoToParallelIfEnabled() throws DslProcessorException { + // TX01 throws an exception, though, there is no way to check from out of the execution if the precompiled contract call has failed. + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress " + PrecompiledContracts.BRIDGE_ADDR +"\n"+ + " data " + "e674f5e80000000000000000000000000000000000000000000000000000000001000006" + "\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.emptySet()); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAContractThatCallsAPrecompiledShouldGoToSequentialIfDisabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + PROXY_SMART_CONTRACT_BYTECODE + PrecompiledContracts.IDENTITY_ADDR + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + "688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145b38da6a701c568545dcfcb03fcb875f56beddc4000000000000000000000000" + "\n" + + " nonce 1\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "\n", 0, Collections.singleton(PrecompiledContracts.IDENTITY_ADDR)); + + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAContractThatCallsAPrecompiledShouldGoToParallelIfEnabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + PROXY_SMART_CONTRACT_BYTECODE + PrecompiledContracts.IDENTITY_ADDR + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + "688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145b38da6a701c568545dcfcb03fcb875f56beddc4000000000000000000000000" + "\n" + + " nonce 1\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "assert_tx_success tx02\n" + + "\n", 0, Collections.emptySet()); + + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{2}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAContractThatCallsAPrecompiledAndRevertsShouldGoToSequentialIfDisabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + PROXY_SMART_CONTRACT_BYTECODE + PrecompiledContracts.BRIDGE_ADDR + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + "688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024e674f5e8000000000000000000000000000000000000000000000000000000000100000600000000000000000000000000000000000000000000000000000000" + "\n" + + " nonce 1\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.singleton(PrecompiledContracts.BRIDGE_ADDR)); + + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(FAILED_STATUS, parallel.getTransactionReceiptByName("tx02").getStatus()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenATxCallsAContractThatCallsAPrecompiledAndRevertsShouldGoToParallelIfEnabled() throws DslProcessorException { + World parallel = this.createWorldAndProcess( + "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + PROXY_SMART_CONTRACT_BYTECODE + PrecompiledContracts.BRIDGE_ADDR + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx02\n" + + " sender acc1\n" + + " contract tx01\n" + + " data " + "688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024e674f5e8000000000000000000000000000000000000000000000000000000000100000600000000000000000000000000000000000000000000000000000000" + "\n" + + " nonce 1\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01 tx02\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n", 0, Collections.emptySet()); + + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(FAILED_STATUS, parallel.getTransactionReceiptByName("tx02").getStatus()); + Assertions.assertArrayEquals(new short[]{2}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenAnInternalTxCallsAContractThatCallsAPrecompiledShouldGoToSequentialIfDisabled() throws DslProcessorException { + World parallel = createWorld(0, Collections.singleton(PrecompiledContracts.IDENTITY_ADDR)); + WorldDslProcessor processor = new WorldDslProcessor(parallel); + String dsl = deployProxyTo(PrecompiledContracts.IDENTITY_ADDR); + DslParser parser = new DslParser(dsl); + processor.processCommands(parser); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + + RskAddress proxyContract = new RskAddress(HashUtil.calcNewAddr(parallel.getAccountByName("acc1").getAddress().getBytes(), BigInteger.ZERO.toByteArray())); + String dataInputToCallProxyToProxyThatReverts = "688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145fd6eb55d12e759a21c09ef703fe0cba1dc9d88d000000000000000000000000"; + String transactionAssertions = "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "\n"; + String dslNext = + deployProxyToProxyCallAContractAndAssert(proxyContract, dataInputToCallProxyToProxyThatReverts, transactionAssertions); + + DslParser parserNext = new DslParser(dslNext); + processor.processCommands(parserNext); + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenAnInternalTxCallsAContractThatCallsAPrecompiledShouldGoToParallelIfEnabled() throws DslProcessorException { + World parallel = createWorld(0, Collections.emptySet()); + WorldDslProcessor processor = new WorldDslProcessor(parallel); + String dsl = deployProxyTo(PrecompiledContracts.IDENTITY_ADDR); + DslParser parser = new DslParser(dsl); + processor.processCommands(parser); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + + RskAddress proxyContract = new RskAddress(HashUtil.calcNewAddr(parallel.getAccountByName("acc1").getAddress().getBytes(), BigInteger.ZERO.toByteArray())); + String dataInputToCallProxyToProxyThatReverts = "688c62c5000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145fd6eb55d12e759a21c09ef703fe0cba1dc9d88d000000000000000000000000"; + String transactionAssertions = "assert_tx_success tx02\n" + + "assert_tx_success tx03\n" + + "\n"; + String dslNext = + deployProxyToProxyCallAContractAndAssert(proxyContract, dataInputToCallProxyToProxyThatReverts, transactionAssertions); + + DslParser parserNext = new DslParser(dslNext); + processor.processCommands(parserNext); + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{2}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenAnInternalTxCallsAContractThatCallsAPrecompiledAndRevertsShouldGoToSequentialIfDisabled() throws DslProcessorException { + World parallel = createWorld(0, Collections.singleton(PrecompiledContracts.BRIDGE_ADDR)); + WorldDslProcessor processor = new WorldDslProcessor(parallel); + String dsl = deployProxyTo(PrecompiledContracts.BRIDGE_ADDR); + DslParser parser = new DslParser(dsl); + processor.processCommands(parser); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + + RskAddress proxyContract = new RskAddress(HashUtil.calcNewAddr(parallel.getAccountByName("acc1").getAddress().getBytes(), BigInteger.ZERO.toByteArray())); + String dataInputToCallProxyToProxy = "688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024e674f5e8000000000000000000000000000000000000000000000000000000000100000600000000000000000000000000000000000000000000000000000000"; + String transactionAssertions = "assert_tx_success tx02\n" + + "\n"; + + String dslNext = + deployProxyToProxyCallAContractAndAssert(proxyContract, dataInputToCallProxyToProxy, transactionAssertions); + + DslParser parserNext = new DslParser(dslNext); + processor.processCommands(parserNext); + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(FAILED_STATUS, parallel.getTransactionReceiptByName("tx03").getStatus()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + @Test + void whenAnInternalTxCallsAContractThatCallsAPrecompiledAndRevertsShouldGoToParallelIfEnabled() throws DslProcessorException { + World parallel = createWorld(0, Collections.emptySet()); + WorldDslProcessor processor = new WorldDslProcessor(parallel); + String dsl = deployProxyTo(PrecompiledContracts.BRIDGE_ADDR); + DslParser parser = new DslParser(dsl); + processor.processCommands(parser); + + Assertions.assertEquals(1, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(new short[]{1}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + + RskAddress proxyContract = new RskAddress(HashUtil.calcNewAddr(parallel.getAccountByName("acc1").getAddress().getBytes(), BigInteger.ZERO.toByteArray())); + String dataInputToCallProxyToProxy = "688c62c500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024e674f5e8000000000000000000000000000000000000000000000000000000000100000600000000000000000000000000000000000000000000000000000000"; + String transactionAssertions = "assert_tx_success tx02\n" + + "\n"; + + String dslNext = + deployProxyToProxyCallAContractAndAssert(proxyContract, dataInputToCallProxyToProxy, transactionAssertions); + + DslParser parserNext = new DslParser(dslNext); + processor.processCommands(parserNext); + Assertions.assertEquals(2, parallel.getBlockChain().getBestBlock().getTransactionsList().size()); + Assertions.assertArrayEquals(FAILED_STATUS, parallel.getTransactionReceiptByName("tx03").getStatus()); + Assertions.assertArrayEquals(new short[]{2}, parallel.getBlockChain().getBestBlock().getHeader().getTxExecutionSublistsEdges()); + } + + private static String deployProxyToProxyCallAContractAndAssert(RskAddress proxyContract, String dataInputToCallProxyToProxyThatReverts, String transactionAssertions) { + return "transaction_build tx02\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + PROXY_TO_PROXY_SMART_CONTRACT_BYTECODE + proxyContract + "\n" + + " nonce 1\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "transaction_build tx03\n" + + " sender acc1\n" + + " contract tx02\n" + + " data " + dataInputToCallProxyToProxyThatReverts + "\n" + + " nonce 2\n" + + " gas 1000000\n" + + " build\n" + + "\n" + + "block_build b02\n" + + " parent b01\n" + + " transactions tx02 tx03\n" + + " build\n" + + "\n" + + "block_connect b02\n" + + "\n" + + "assert_best b02\n" + + transactionAssertions; + } + + private static String deployProxyTo(RskAddress address) { + return "account_new acc1 10000000\n" + + "transaction_build tx01\n" + + " sender acc1\n" + + " receiverAddress 00\n" + + " data " + PROXY_SMART_CONTRACT_BYTECODE + address + "\n" + + " gas 1200000\n" + + " build\n" + + "\n" + + "block_build b01\n" + + " parent g00\n" + + " gasLimit 7500000\n" + + " transactions tx01\n" + + " build\n" + + "\n" + + "block_connect b01\n" + + "\n" + + "assert_best b01\n" + + "assert_tx_success tx01\n" + + "\n"; + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/db/RepositoryTrackingTest.java b/rskj-core/src/test/java/co/rsk/db/RepositoryTrackingTest.java new file mode 100644 index 00000000000..e7d86d083bc --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/db/RepositoryTrackingTest.java @@ -0,0 +1,185 @@ +package co.rsk.db; +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.core.bc.IReadWrittenKeysTracker; +import co.rsk.core.bc.ReadWrittenKeysTracker; +import co.rsk.trie.Trie; +import co.rsk.trie.TrieStore; +import co.rsk.trie.TrieStoreImpl; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.datasource.HashMapDB; +import org.ethereum.db.MutableRepository; +import org.ethereum.vm.DataWord; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + +import java.math.BigInteger; + + +public class RepositoryTrackingTest { + public static final RskAddress COW = new RskAddress("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826"); + + private MutableRepository repository; + private MutableTrieImpl mutableTrie; + private TrieStore trieStore; + private IReadWrittenKeysTracker tracker; + + @BeforeEach + public void setUp() { + trieStore = new TrieStoreImpl(new HashMapDB()); + mutableTrie = new MutableTrieImpl(trieStore, new Trie(trieStore)); + tracker = new ReadWrittenKeysTracker(); + repository = new MutableRepository(mutableTrie, tracker); + } + + void assertRepositoryHasSize(int readRepoSize, int writtenRepoSize) { + Assertions.assertEquals(readRepoSize, tracker.getThisThreadReadKeys().size()); + Assertions.assertEquals(writtenRepoSize, tracker.getThisThreadWrittenKeys().size()); + } + + @Test + void tracksWriteInCreatedAccount() { + repository.createAccount(COW); + + assertRepositoryHasSize(0, 1); + } + + @Test + void tracksWriteInSetupContract() { + repository.createAccount(COW); + tracker.clear(); + + repository.setupContract(COW); + + assertRepositoryHasSize(0, 1); + } + + @Test + void tracksReadInIsExists() { + repository.isExist(COW); + + assertRepositoryHasSize(1, 0); + } + + @Test + void tracksReadInGetAccountState() { + repository.getAccountState(COW); + + assertRepositoryHasSize(1, 0); + } + + @Test + void tracksWriteInDelete() { + repository.createAccount(COW); + tracker.clear(); + + repository.delete(COW); + + assertRepositoryHasSize(0, 1); + } + + @Test + void tracksWriteInAddBalance() { + repository.createAccount(COW); + tracker.clear(); + + repository.addBalance(COW, new Coin(BigInteger.ONE)); + + assertRepositoryHasSize(1, 1); + } + + @Test + void tracksReadOnGetStorageBytes () { + repository.createAccount(COW); + tracker.clear(); + + byte[] cowKey = Hex.decode("A1A2A3"); + + repository.getStorageBytes(COW, DataWord.valueOf(cowKey)); + + assertRepositoryHasSize(1, 0); + } + + @Test + void tracksWriteOnAddStorageBytes() { + repository.createAccount(COW); + tracker.clear(); + + byte[] cowValue = Hex.decode("A4A5A6"); + byte[] cowKey = Hex.decode("A1A2A3"); + + repository.addStorageBytes(COW, DataWord.valueOf(cowKey), cowValue); + + assertRepositoryHasSize(1, 1); + } + + @Test + void tracksWriteOnAddStorageDifferentBytes() { + repository.createAccount(COW); + tracker.clear(); + + byte[] cowValue = Hex.decode("A4A5A6"); + byte[] cowKey = Hex.decode("A1A2A3"); + byte[] cowKey2 = "key-c-2".getBytes(); + byte[] cowValue2 = "val-c-2".getBytes(); + + repository.addStorageBytes(COW, DataWord.valueOf(cowKey), cowValue); + repository.addStorageBytes(COW, DataWord.valueOf(cowKey2), cowValue2); + + assertRepositoryHasSize(1, 2); + } + + @Test + void tracksWriteOnAddStorageSameBytes() { + repository.createAccount(COW); + + byte[] cowValue = Hex.decode("A4A5A6"); + byte[] cowKey = Hex.decode("A1A2A3"); + + repository.addStorageBytes(COW, DataWord.valueOf(cowKey), cowValue); + + tracker.clear(); + + repository.addStorageBytes(COW, DataWord.valueOf(cowKey), cowValue); + + assertRepositoryHasSize(1, 1); + } + + @Test + void tracksReadAndWriteOnAddBalanceOfNonExistent () { + repository.addBalance(COW, Coin.valueOf(1)); + + assertRepositoryHasSize(1, 1); + } + + @Test + void tracksReadAndWriteOnAddBalanceZeroOfNonExistent () { + repository.addBalance(COW, Coin.valueOf(0)); + + assertRepositoryHasSize(1, 1); + } + + @Test + void tracksReadAndWriteOnAddBalanceOfExistent () { + repository.addBalance(COW, Coin.valueOf(1)); + + tracker.clear(); + + repository.addBalance(COW, Coin.valueOf(1)); + + assertRepositoryHasSize(1, 1); + } + + @Test + void doesntTrackWriteOnAddBalanceZeroOfExistent () { + repository.addBalance(COW, Coin.valueOf(1)); + + tracker.clear(); + + repository.addBalance(COW, Coin.valueOf(0)); + + assertRepositoryHasSize(1, 0); + } +} diff --git a/rskj-core/src/test/java/co/rsk/mine/BlockToMineBuilderTest.java b/rskj-core/src/test/java/co/rsk/mine/BlockToMineBuilderTest.java index 8c27ba19e7d..86cf68d0326 100644 --- a/rskj-core/src/test/java/co/rsk/mine/BlockToMineBuilderTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/BlockToMineBuilderTest.java @@ -49,6 +49,7 @@ import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.*; @@ -139,8 +140,7 @@ void BuildBlockHasUnclesWhenCreateAnInvalidBlock() { runMocked(test); } - @Test - void buildBlockBeforeUMMActivation() { + private Block prepareForActivationTest() { Keccak256 parentHash = TestUtils.generateHash("parentHash"); BlockHeader parent = mock(BlockHeader.class); @@ -150,8 +150,6 @@ void buildBlockBeforeUMMActivation() { when(parent.getMinimumGasPrice()).thenReturn(mock(Coin.class)); when(validationRules.isValid(any())).thenReturn(true); - when(activationConfig.isActive(ConsensusRule.RSKIPUMM, 501L)).thenReturn(false); - when(activationConfig.isActive(ConsensusRule.RSKIP252, 501L)).thenReturn(false); BlockResult expectedResult = mock(BlockResult.class); ArgumentCaptor blockCaptor = ArgumentCaptor.forClass(Block.class); @@ -159,7 +157,14 @@ void buildBlockBeforeUMMActivation() { blockBuilder.build(new ArrayList<>(Collections.singletonList(parent)), new byte[0]); - Block actualBlock = blockCaptor.getValue(); + return blockCaptor.getValue(); + } + + @Test + void buildBlockBeforeUMMActivation() { + when(activationConfig.isActive(ConsensusRule.RSKIPUMM, 501L)).thenReturn(false); + when(activationConfig.isActive(ConsensusRule.RSKIP252, 501L)).thenReturn(false); + Block actualBlock = this.prepareForActivationTest(); assertNull(actualBlock.getHeader().getUmmRoot()); } @@ -187,6 +192,20 @@ void buildBlockAfterUMMActivation() { assertThat(actualBlock.getHeader().getUmmRoot(), is(new byte[0])); } + @Test + void buildBlockBeforeRskip351() { + when(activationConfig.getHeaderVersion(501L)).thenReturn((byte) 0x0); + Block actualBlock = this.prepareForActivationTest(); + assertEquals(0, actualBlock.getHeader().getVersion()); + } + + @Test + void buildBlockAfterRskip351() { + when(activationConfig.getHeaderVersion(501L)).thenReturn((byte) 0x1); + Block actualBlock = this.prepareForActivationTest(); + assertEquals(1, actualBlock.getHeader().getVersion()); + } + private void runMocked(Consumer task) { BlockHeader blockHeader = mock(BlockHeader.class); long blockNumber = 42L; @@ -206,14 +225,14 @@ private void runMocked(Consumer task) { } private BlockHeader createBlockHeader() { - return new BlockHeader( + return new BlockHeaderV0( EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY, TestUtils.generateAddress("blockHeader"), EMPTY_TRIE_HASH, null, EMPTY_TRIE_HASH, new Bloom().getData(), BlockDifficulty.ZERO, 1L, EMPTY_BYTE_ARRAY, 0L, 0L, EMPTY_BYTE_ARRAY, Coin.ZERO, EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY, Coin.ZERO, 0, false, true, false, - new byte[0] + new byte[0], null ); } } diff --git a/rskj-core/src/test/java/co/rsk/mine/NetworkUpgrades.java b/rskj-core/src/test/java/co/rsk/mine/NetworkUpgrades.java index 3bded16ed45..e24366673f4 100644 --- a/rskj-core/src/test/java/co/rsk/mine/NetworkUpgrades.java +++ b/rskj-core/src/test/java/co/rsk/mine/NetworkUpgrades.java @@ -65,6 +65,23 @@ public String toString() { public String projectVersionModifier() { return "Orchid"; } + }), + + ARROWHEAD600_PROPERTIES(new TestSystemProperties() { + @Override + public ActivationConfig getActivationConfig() { + return ActivationConfigsForTest.arrowhead600(); + } + + @Override + public String toString() { + return "Arrowhead"; + } + + @Override + public String projectVersionModifier() { + return "Arrowhead"; + } }); private final TestSystemProperties properties; 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 e2ff31e8e8e..c8af85abafd 100644 --- a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java @@ -588,11 +588,9 @@ private Web3Impl internalCreateEnvironment(Blockchain blockchain, this.transactionExecutorFactory = transactionExecutorFactory; MiningConfig miningConfig = ConfigUtils.getDefaultMiningConfig(); BlockExecutor blockExecutor = new BlockExecutor( - config.getActivationConfig(), repositoryLocator, -// stateRootHandler, - this.transactionExecutorFactory - ); + this.transactionExecutorFactory, + config); MinerServer minerServer = new MinerServerImpl( config, diff --git a/rskj-core/src/test/java/co/rsk/net/NodeBlockProcessorTest.java b/rskj-core/src/test/java/co/rsk/net/NodeBlockProcessorTest.java index aa7d92b04fc..94f8f30ad58 100644 --- a/rskj-core/src/test/java/co/rsk/net/NodeBlockProcessorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/NodeBlockProcessorTest.java @@ -27,6 +27,7 @@ import co.rsk.net.sync.SyncConfiguration; import co.rsk.test.builders.BlockChainBuilder; import co.rsk.validators.DummyBlockValidator; +import com.typesafe.config.ConfigValueFactory; import org.ethereum.TestUtils; import org.ethereum.core.Block; import org.ethereum.core.BlockIdentifier; @@ -790,6 +791,40 @@ void processBlockRequestMessageUsingBlockInStore() throws UnknownHostException { Assertions.assertEquals(block.getHash(), bMessage.getBlock().getHash()); } + @Test + void processBodyRequestMessageUsingBlockInBlockchainWithoutRskip351() throws UnknownHostException { + TestSystemProperties config = new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.consensusRules.rskip351", ConfigValueFactory.fromAnyRef(-1)) + ); + final Blockchain blockchain = new BlockChainBuilder() + .setConfig(config) + .ofSize(10, new BlockGenerator(config.getNetworkConstants(), config.getActivationConfig())); + final Block block = blockchain.getBlockByNumber(3); + final NetBlockStore store = new NetBlockStore(); + BlockNodeInformation nodeInformation = new BlockNodeInformation(); + SyncConfiguration syncConfiguration = SyncConfiguration.IMMEDIATE_FOR_TESTING; + BlockSyncService blockSyncService = new BlockSyncService(config, store, blockchain, nodeInformation, syncConfiguration, DummyBlockValidator.VALID_RESULT_INSTANCE); + final NodeBlockProcessor processor = new NodeBlockProcessor(store, blockchain, nodeInformation, blockSyncService, syncConfiguration); + + final SimplePeer sender = new SimplePeer(); + + processor.processBodyRequest(sender, 100, block.getHash().getBytes()); + + Assertions.assertFalse(sender.getMessages().isEmpty()); + Assertions.assertEquals(1, sender.getMessages().size()); + + final Message message = sender.getMessages().get(0); + + Assertions.assertEquals(MessageType.BODY_RESPONSE_MESSAGE, message.getMessageType()); + + final BodyResponseMessage bMessage = (BodyResponseMessage) message; + + Assertions.assertEquals(100, bMessage.getId()); + Assertions.assertEquals(block.getTransactionsList(), bMessage.getTransactions()); + Assertions.assertEquals(block.getUncleList(), bMessage.getUncles()); + Assertions.assertEquals(null, bMessage.getBlockHeaderExtension()); + } + @Test void processBodyRequestMessageUsingBlockInBlockchain() throws UnknownHostException { final Blockchain blockchain = new BlockChainBuilder().ofSize(10); @@ -817,6 +852,11 @@ void processBodyRequestMessageUsingBlockInBlockchain() throws UnknownHostExcepti Assertions.assertEquals(100, bMessage.getId()); Assertions.assertEquals(block.getTransactionsList(), bMessage.getTransactions()); Assertions.assertEquals(block.getUncleList(), bMessage.getUncles()); + Assertions.assertNotNull(bMessage.getBlockHeaderExtension()); + Assertions.assertArrayEquals( + block.getHeader().getExtension().getEncoded(), + bMessage.getBlockHeaderExtension().getEncoded() + ); } @Test 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..04a330f661c 100644 --- a/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/SyncProcessorTest.java @@ -18,6 +18,7 @@ import co.rsk.scoring.PeerScoringManager; import co.rsk.test.builders.BlockChainBuilder; import co.rsk.validators.*; +import com.typesafe.config.ConfigValueFactory; import org.bouncycastle.util.encoders.Hex; import org.ethereum.TestUtils; import org.ethereum.core.*; @@ -579,7 +580,7 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), syncConfigurati mock(Genesis.class), mock(EthereumListener.class)); - BodyResponseMessage response = new BodyResponseMessage(TestUtils.generateLong("response"), null, null); + BodyResponseMessage response = new BodyResponseMessage(TestUtils.generateLong("response"), null, null, null); processor.registerExpectedMessage(response); processor.processBodyResponse(sender, response); @@ -587,21 +588,20 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), syncConfigurati Assertions.assertTrue(processor.getExpectedResponses().isEmpty()); } - @Test - void processBodyResponseAddsToBlockchain() { + void testProcessBodyResponseAddsToBlockchain(TestSystemProperties config) { final NetBlockStore store = new NetBlockStore(); - Blockchain blockchain = new BlockChainBuilder().ofSize(10); + Blockchain blockchain = new BlockChainBuilder().setConfig(config).ofSize(10, new BlockGenerator(config.getNetworkConstants(), config.getActivationConfig())); + SimplePeer sender = new SimplePeer(new byte[] { 0x01 }); Assertions.assertEquals(10, blockchain.getBestBlock().getNumber()); - Block block = new BlockGenerator().createChildBlock(blockchain.getBlockByNumber(10)); + Block block = new BlockGenerator(config.getNetworkConstants(), config.getActivationConfig()).createChildBlock(blockchain.getBlockByNumber(10)); Assertions.assertEquals(11, block.getNumber()); Assertions.assertArrayEquals(blockchain.getBestBlockHash(), block.getParentHash().getBytes()); BlockNodeInformation nodeInformation = new BlockNodeInformation(); - TestSystemProperties config = new TestSystemProperties(); BlockSyncService blockSyncService = new BlockSyncService(config, store, blockchain, nodeInformation, SyncConfiguration.IMMEDIATE_FOR_TESTING, DummyBlockValidator.VALID_RESULT_INSTANCE); SyncProcessor processor = new SyncProcessor( @@ -616,8 +616,9 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), SyncConfigurati mock(EthereumListener.class)); List transactions = blockchain.getBestBlock().getTransactionsList(); List uncles = blockchain.getBestBlock().getUncleList(); + BlockHeaderExtension extension = blockchain.getBestBlock().getHeader().getExtension(); long lastRequestId = TestUtils.generateLong("lastRequestId"); - BodyResponseMessage response = new BodyResponseMessage(lastRequestId, transactions, uncles); + BodyResponseMessage response = new BodyResponseMessage(lastRequestId, transactions, uncles, extension); processor.registerExpectedMessage(response); Deque headerStack = new ArrayDeque<>(); @@ -637,6 +638,19 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), SyncConfigurati Assertions.assertEquals(11, blockchain.getBestBlock().getNumber()); Assertions.assertArrayEquals(block.getHash().getBytes(), blockchain.getBestBlockHash()); Assertions.assertTrue(processor.getExpectedResponses().isEmpty()); + System.out.println(block.getHeader().getVersion()); + } + + @Test + void processBodyResponseAddsToBlockchain() { + testProcessBodyResponseAddsToBlockchain(new TestSystemProperties()); + } + + @Test + void processBodyResponseAddsToBlockchainWithoutFingerroot500() { + testProcessBodyResponseAddsToBlockchain(new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.hardforkActivationHeights.fingerroot500", ConfigValueFactory.fromAnyRef(-1)) + )); } @Test @@ -668,6 +682,7 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), SyncConfigurati mock(Genesis.class), listener); List uncles = blockchain.getBestBlock().getUncleList(); + BlockHeaderExtension extension = blockchain.getBestBlock().getHeader().getExtension(); Account senderAccount = createAccount("sender"); Account receiverAccount = createAccount("receiver"); Transaction tx = createTransaction(senderAccount, receiverAccount, BigInteger.valueOf(1000000), BigInteger.ZERO); @@ -675,7 +690,7 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), SyncConfigurati txs.add(tx); long lastRequestId = TestUtils.generateLong("lastRequestId"); - BodyResponseMessage response = new BodyResponseMessage(lastRequestId, txs, uncles); + BodyResponseMessage response = new BodyResponseMessage(lastRequestId, txs, uncles, extension); processor.registerExpectedMessage(response); Deque headerStack = new ArrayDeque<>(); @@ -731,8 +746,9 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), SyncConfigurati mock(EthereumListener.class)); List transactions = blockchain.getBestBlock().getTransactionsList(); List uncles = blockchain.getBestBlock().getUncleList(); + BlockHeaderExtension extension = blockchain.getBestBlock().getHeader().getExtension(); long lastRequestId = TestUtils.generateLong("lastRequestId"); - BodyResponseMessage response = new BodyResponseMessage(lastRequestId, transactions, uncles); + BodyResponseMessage response = new BodyResponseMessage(lastRequestId, transactions, uncles, extension); processor.registerExpectedMessage(response); Deque headerStack = new ArrayDeque<>(); @@ -788,7 +804,6 @@ void processBodyResponseWithTransactionAddsToBlockchain() { config.getActivationConfig(), signatureCache); BlockExecutor blockExecutor = new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(blockChainBuilder.getTrieStore(), stateRootHandler), new TransactionExecutorFactory( config, @@ -798,8 +813,8 @@ void processBodyResponseWithTransactionAddsToBlockchain() { new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) - ) - ); + ), + config); Assertions.assertEquals(1, block.getTransactionsList().size()); blockExecutor.executeAndFillAll(block, genesis.getHeader()); Assertions.assertEquals(21000, block.getFeesPaidToMiner().asBigInteger().intValueExact()); @@ -824,8 +839,9 @@ DIFFICULTY_CALCULATOR, new PeersInformation(getChannelManager(), SyncConfigurati mock(EthereumListener.class)); List transactions = block.getTransactionsList(); List uncles = block.getUncleList(); + BlockHeaderExtension extension = block.getHeader().getExtension(); long lastRequestId = TestUtils.generateLong("lastRequestId"); - BodyResponseMessage response = new BodyResponseMessage(lastRequestId, transactions, uncles); + BodyResponseMessage response = new BodyResponseMessage(lastRequestId, transactions, uncles, extension); processor.registerExpectedMessage(response); Deque headerStack = new ArrayDeque<>(); diff --git a/rskj-core/src/test/java/co/rsk/net/ThreeAsyncNodeUsingSyncProcessorTest.java b/rskj-core/src/test/java/co/rsk/net/ThreeAsyncNodeUsingSyncProcessorTest.java index 428523f2cf3..7e2f96e496e 100644 --- a/rskj-core/src/test/java/co/rsk/net/ThreeAsyncNodeUsingSyncProcessorTest.java +++ b/rskj-core/src/test/java/co/rsk/net/ThreeAsyncNodeUsingSyncProcessorTest.java @@ -287,7 +287,7 @@ public void synchronizeWithTwoPeers200AndOneFails() { node3.waitUntilNTasksWithTimeout(setupRequests); node3.waitUntilNTasksWithTimeout(5); // synchronize 200 (extra tasks are from old sync protocol messages) - BodyResponseMessage response = new BodyResponseMessage(123123123123L, null, null); + BodyResponseMessage response = new BodyResponseMessage(123123123123L, null, null, null); node3.getSyncProcessor().registerExpectedMessage(response); node3.getSyncProcessor().processBodyResponse(node1.getMessageChannel(node3), response); node3.waitExactlyNTasksWithTimeout(200 + setupRequests - 15); diff --git a/rskj-core/src/test/java/co/rsk/net/handler/TxPendingValidatorTest.java b/rskj-core/src/test/java/co/rsk/net/handler/TxPendingValidatorTest.java new file mode 100644 index 00000000000..4c1aaee1d9e --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/net/handler/TxPendingValidatorTest.java @@ -0,0 +1,181 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * 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.net.handler; + +import co.rsk.config.TestSystemProperties; +import co.rsk.core.Coin; +import co.rsk.core.bc.BlockUtils; +import co.rsk.net.TransactionValidationResult; +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class TxPendingValidatorTest { + + private long minSequentialSetGasLimit; + + @BeforeEach + public void setup() { + minSequentialSetGasLimit = Constants.regtest().getMinSequentialSetGasLimit(); + } + + @Test + void isValid_ShouldBeValid_WhenRSKIP144IsNotActivated() { + // before RSKIP144: block gas limit == 10 and tx gas limit == 10 - should be valid + + Block executionBlock = mock(Block.class); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(10L).toByteArray()); + when(executionBlock.getMinimumGasPrice()).thenReturn(Coin.valueOf(1L)); + + Transaction tx = mock(Transaction.class); + when(tx.getGasLimitAsInteger()).thenReturn(BigInteger.valueOf(10L)); + when(tx.getNonce()).thenReturn(BigInteger.valueOf(1L).toByteArray()); + when(tx.getNonceAsInteger()).thenReturn(BigInteger.valueOf(1L)); + when(tx.getGasPrice()).thenReturn(Coin.valueOf(1L)); + + AccountState state = mock(AccountState.class); + when(state.getNonce()).thenReturn(BigInteger.valueOf(1L)); + + TestSystemProperties config = new TestSystemProperties(); + + ActivationConfig.ForBlock forBlock = mock(ActivationConfig.ForBlock.class); + when(forBlock.isActive(ConsensusRule.RSKIP144)).thenReturn(false); + + ActivationConfig activationConfig = spy(config.getActivationConfig()); + when(activationConfig.forBlock(anyLong())).thenReturn(forBlock); + + SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + TxPendingValidator validator = new TxPendingValidator(config.getNetworkConstants(), activationConfig, config.getNumOfAccountSlots(), signatureCache); + + TransactionValidationResult result = validator.isValid(tx, executionBlock, state); + + assertTrue(result.transactionIsValid()); + } + + @Test + void isValid_ShouldBeInvalid_WhenRSKIP144IsNotActivated() { + // before RSKIP144: block gas limit == 10 and tx gas limit == 11 - should be invalid + + Block executionBlock = mock(Block.class); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(10L).toByteArray()); + when(executionBlock.getMinimumGasPrice()).thenReturn(Coin.valueOf(1L)); + + Transaction tx = mock(Transaction.class); + when(tx.getGasLimitAsInteger()).thenReturn(BigInteger.valueOf(11L)); + when(tx.getNonce()).thenReturn(BigInteger.valueOf(1L).toByteArray()); + when(tx.getNonceAsInteger()).thenReturn(BigInteger.valueOf(1L)); + when(tx.getGasPrice()).thenReturn(Coin.valueOf(1L)); + + AccountState state = mock(AccountState.class); + when(state.getNonce()).thenReturn(BigInteger.valueOf(1L)); + + TestSystemProperties config = new TestSystemProperties(); + + ActivationConfig.ForBlock forBlock = mock(ActivationConfig.ForBlock.class); + when(forBlock.isActive(ConsensusRule.RSKIP144)).thenReturn(false); + + ActivationConfig activationConfig = spy(config.getActivationConfig()); + when(activationConfig.forBlock(anyLong())).thenReturn(forBlock); + + SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + TxPendingValidator validator = new TxPendingValidator(config.getNetworkConstants(), activationConfig, config.getNumOfAccountSlots(), signatureCache); + + TransactionValidationResult result = validator.isValid(tx, executionBlock, state); + + assertFalse(result.transactionIsValid()); + } + + @Test + void isValid_ShouldBeValid_WhenRSKIP144IsAlreadyActivated() { + // after RSKIP144: block gas limit == 10 and tx gas limit == BlockUtils.getSublistGasLimit(executionBlock) - should be valid + + Block executionBlock = mock(Block.class); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(10L).toByteArray()); + when(executionBlock.getMinimumGasPrice()).thenReturn(Coin.valueOf(1L)); + + long sublistGasLimit = BlockUtils.getSublistGasLimit(executionBlock, true, minSequentialSetGasLimit); + + Transaction tx = mock(Transaction.class); + when(tx.getGasLimitAsInteger()).thenReturn(BigInteger.valueOf(sublistGasLimit)); + when(tx.getNonce()).thenReturn(BigInteger.valueOf(1L).toByteArray()); + when(tx.getNonceAsInteger()).thenReturn(BigInteger.valueOf(1L)); + when(tx.getGasPrice()).thenReturn(Coin.valueOf(1L)); + + AccountState state = mock(AccountState.class); + when(state.getNonce()).thenReturn(BigInteger.valueOf(1L)); + + TestSystemProperties config = new TestSystemProperties(); + + ActivationConfig.ForBlock forBlock = mock(ActivationConfig.ForBlock.class); + when(forBlock.isActive(ConsensusRule.RSKIP144)).thenReturn(true); + + ActivationConfig activationConfig = spy(config.getActivationConfig()); + when(activationConfig.forBlock(anyLong())).thenReturn(forBlock); + + SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + TxPendingValidator validator = new TxPendingValidator(config.getNetworkConstants(), activationConfig, config.getNumOfAccountSlots(), signatureCache); + + TransactionValidationResult result = validator.isValid(tx, executionBlock, state); + + assertTrue(result.transactionIsValid()); + } + + @Test + void isValid_ShouldBeInvalid_WhenRSKIP144IsAlreadyActivated() { + // after RSKIP144: block gas limit == 10 and tx gas limit == BlockUtils.getSublistGasLimit(executionBlock) + 1 - should be invalid + + Block executionBlock = mock(Block.class); + when(executionBlock.getGasLimit()).thenReturn(BigInteger.valueOf(10L).toByteArray()); + when(executionBlock.getMinimumGasPrice()).thenReturn(Coin.valueOf(1L)); + + long sublistGasLimit = BlockUtils.getSublistGasLimit(executionBlock, true, minSequentialSetGasLimit); + + Transaction tx = mock(Transaction.class); + when(tx.getGasLimitAsInteger()).thenReturn(BigInteger.valueOf(sublistGasLimit + 1L)); + when(tx.getNonce()).thenReturn(BigInteger.valueOf(1L).toByteArray()); + when(tx.getNonceAsInteger()).thenReturn(BigInteger.valueOf(1L)); + when(tx.getGasPrice()).thenReturn(Coin.valueOf(1L)); + + AccountState state = mock(AccountState.class); + when(state.getNonce()).thenReturn(BigInteger.valueOf(1L)); + + TestSystemProperties config = new TestSystemProperties(); + + ActivationConfig.ForBlock forBlock = mock(ActivationConfig.ForBlock.class); + when(forBlock.isActive(ConsensusRule.RSKIP144)).thenReturn(true); + + ActivationConfig activationConfig = spy(config.getActivationConfig()); + when(activationConfig.forBlock(anyLong())).thenReturn(forBlock); + + SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + TxPendingValidator validator = new TxPendingValidator(config.getNetworkConstants(), activationConfig, config.getNumOfAccountSlots(), signatureCache); + + TransactionValidationResult result = validator.isValid(tx, executionBlock, state); + + assertFalse(result.transactionIsValid()); + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/co/rsk/net/messages/BodyResponseMessageTest.java b/rskj-core/src/test/java/co/rsk/net/messages/BodyResponseMessageTest.java index 29c61376bec..c148c6460f6 100644 --- a/rskj-core/src/test/java/co/rsk/net/messages/BodyResponseMessageTest.java +++ b/rskj-core/src/test/java/co/rsk/net/messages/BodyResponseMessageTest.java @@ -1,12 +1,10 @@ package co.rsk.net.messages; import co.rsk.blockchain.utils.BlockGenerator; +import co.rsk.config.TestSystemProperties; import co.rsk.test.builders.AccountBuilder; import co.rsk.test.builders.TransactionBuilder; -import org.ethereum.core.Account; -import org.ethereum.core.Block; -import org.ethereum.core.BlockHeader; -import org.ethereum.core.Transaction; +import org.ethereum.core.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -18,8 +16,8 @@ import static org.mockito.Mockito.*; class BodyResponseMessageTest { - @Test - void createMessage() { + + private BodyResponseMessage testCreateMessage(BlockHeaderExtension extension) { List transactions = new ArrayList<>(); for (int k = 1; k <= 10; k++) @@ -36,7 +34,7 @@ void createMessage() { parent = block; } - BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles); + BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles, extension); Assertions.assertEquals(100, message.getId()); @@ -50,8 +48,34 @@ void createMessage() { Assertions.assertNotNull(message.getUncles()); Assertions.assertEquals(uncles.size(), message.getUncles().size()); - for (int k = 0; k < uncles.size(); k++) + for (int k = 0; k < uncles.size(); k++) { Assertions.assertArrayEquals(uncles.get(k).getFullEncoded(), message.getUncles().get(k).getFullEncoded()); + } + + return message; + } + + private BodyResponseMessage encodeAndDecodeMessage(BodyResponseMessage message) { + return (BodyResponseMessage) Message.create(new BlockFactory(new TestSystemProperties().getActivationConfig()), message.getEncoded()); + } + + @Test + void createMessage() { + BodyResponseMessage message = testCreateMessage(null); + Assertions.assertNull(message.getBlockHeaderExtension()); + message = encodeAndDecodeMessage(message); + Assertions.assertNull(message.getBlockHeaderExtension()); + } + + @Test + void createMessageWithExtension() { + Bloom bloom = new Bloom(); + short[] edges = new short[]{ 1, 2, 3, 4 }; + BlockHeaderExtension extension = new BlockHeaderExtensionV1(bloom.getData(), edges); + BodyResponseMessage message = testCreateMessage(extension); + Assertions.assertArrayEquals(extension.getEncoded(), message.getBlockHeaderExtension().getEncoded()); + message = encodeAndDecodeMessage(message); + Assertions.assertArrayEquals(extension.getEncoded(), message.getBlockHeaderExtension().getEncoded()); } private static Transaction createTransaction(int number) { @@ -69,7 +93,7 @@ void accept() { List transactions = new LinkedList<>(); List uncles = new LinkedList<>(); - BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles); + BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles, null); MessageVisitor visitor = mock(MessageVisitor.class); diff --git a/rskj-core/src/test/java/co/rsk/net/messages/MessageTest.java b/rskj-core/src/test/java/co/rsk/net/messages/MessageTest.java index 3ef12e48298..d35fb7102c9 100644 --- a/rskj-core/src/test/java/co/rsk/net/messages/MessageTest.java +++ b/rskj-core/src/test/java/co/rsk/net/messages/MessageTest.java @@ -19,6 +19,8 @@ package co.rsk.net.messages; import co.rsk.blockchain.utils.BlockGenerator; +import co.rsk.blockchain.utils.BlockMiner; +import co.rsk.config.MiningConfig; import co.rsk.core.BlockDifficulty; import co.rsk.net.Status; import co.rsk.net.utils.TransactionUtils; @@ -26,19 +28,17 @@ import co.rsk.test.builders.TransactionBuilder; import org.ethereum.TestUtils; import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; -import org.ethereum.core.Account; -import org.ethereum.core.Block; -import org.ethereum.core.BlockFactory; -import org.ethereum.core.BlockHeader; -import org.ethereum.core.BlockIdentifier; -import org.ethereum.core.Transaction; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -196,35 +196,73 @@ void encodeDecodeBlockResponseMessage() { Assertions.assertArrayEquals(block.getEncoded(), newmessage.getBlock().getEncoded()); } - @Test - void encodeDecodeBlockHeadersResponseMessage() { - List headers = new ArrayList<>(); - - for (int k = 1; k <= 4; k++) - headers.add(blockGenerator.getBlock(k).getHeader()); - + private BlockHeadersResponseMessage testBlockHeadersResponseMessage(BlockFactory blockFactory, List headers) { BlockHeadersResponseMessage message = new BlockHeadersResponseMessage(100, headers); - byte[] encoded = message.getEncoded(); - Assertions.assertNotNull(encoded); - - Message result = Message.create(blockFactory, encoded); + BlockHeadersResponseMessage result = (BlockHeadersResponseMessage) Message.create(blockFactory, encoded); + Assertions.assertNotNull(encoded); Assertions.assertNotNull(result); Assertions.assertArrayEquals(encoded, result.getEncoded()); Assertions.assertEquals(MessageType.BLOCK_HEADERS_RESPONSE_MESSAGE, result.getMessageType()); - BlockHeadersResponseMessage newmessage = (BlockHeadersResponseMessage) result; + Assertions.assertEquals(100, message.getId()); + Assertions.assertEquals(headers.size(), message.getBlockHeaders().size()); - Assertions.assertEquals(100, newmessage.getId()); + return result; + } - Assertions.assertEquals(headers.size(), newmessage.getBlockHeaders().size()); + @Test + void encodeDecodeBlockHeadersResponseMessageWithoutRSKIP351() { + ActivationConfig activationConfig = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351); + BlockFactory blockFactory = new BlockFactory(activationConfig); + BlockMiner blockMiner = new BlockMiner(activationConfig); + + List headers = new ArrayList<>(); + for (int k = 1; k <= 4; k++) { + BlockHeader header = blockFactory.getBlockHeaderBuilder() + .setNumber(MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION + k) + .setIncludeForkDetectionData(true) + .build(); + Block block = blockFactory.newBlock(header, Collections.emptyList(), Collections.emptyList(), false); + Block minedBlock = blockMiner.mineBlock(block); + headers.add(minedBlock.getHeader()); + } + + BlockHeadersResponseMessage newMessage = testBlockHeadersResponseMessage(blockFactory, headers); for (int k = 0; k < headers.size(); k++) { - Assertions.assertEquals(headers.get(k).getNumber(), newmessage.getBlockHeaders().get(k).getNumber()); - Assertions.assertEquals(headers.get(k).getHash(), newmessage.getBlockHeaders().get(k).getHash()); - Assertions.assertArrayEquals(headers.get(k).getFullEncoded(), newmessage.getBlockHeaders().get(k).getFullEncoded()); + Assertions.assertEquals(headers.get(k).getNumber(), newMessage.getBlockHeaders().get(k).getNumber()); + Assertions.assertEquals(headers.get(k).getHash(), newMessage.getBlockHeaders().get(k).getHash()); + Assertions.assertArrayEquals(headers.get(k).getEncodedCompressed(), newMessage.getBlockHeaders().get(k).getEncodedCompressed()); + Assertions.assertArrayEquals(headers.get(k).getMiningForkDetectionData(), newMessage.getBlockHeaders().get(k).getMiningForkDetectionData()); + } + } + + @Test + void encodeDecodeBlockHeadersResponseMessage() { + List headers = new ArrayList<>(); + ActivationConfig activationConfig = ActivationConfigsForTest.all(); + BlockMiner blockMiner = new BlockMiner(activationConfig); + + for (int k = 1; k <= 4; k++) { + BlockHeader header = blockFactory.getBlockHeaderBuilder() + .setNumber(MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION + k) + .setIncludeForkDetectionData(true) + .build(); + Block block = blockFactory.newBlock(header, Collections.emptyList(), Collections.emptyList(), false); + Block minedBlock = blockMiner.mineBlock(block); + headers.add(minedBlock.getHeader()); + } + + BlockHeadersResponseMessage newMessage = testBlockHeadersResponseMessage(blockFactory, headers); + + for (int k = 0; k < headers.size(); k++) { + Assertions.assertEquals(headers.get(k).getNumber(), newMessage.getBlockHeaders().get(k).getNumber()); + Assertions.assertEquals(headers.get(k).getHash(), newMessage.getBlockHeaders().get(k).getHash()); + Assertions.assertArrayEquals(headers.get(k).getEncodedCompressed(), newMessage.getBlockHeaders().get(k).getEncodedCompressed()); + Assertions.assertArrayEquals(headers.get(k).getMiningForkDetectionData(), newMessage.getBlockHeaders().get(k).getMiningForkDetectionData()); } } @@ -477,7 +515,7 @@ void encodeDecodeBodyResponseMessage() { parent = block; } - BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles); + BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles, null); byte[] encoded = message.getEncoded(); @@ -505,6 +543,59 @@ void encodeDecodeBodyResponseMessage() { Assertions.assertArrayEquals(uncles.get(k).getFullEncoded(), newmessage.getUncles().get(k).getFullEncoded()); } + @Test + void encodeDecodeBodyResponseMessageWithExtension() { + List transactions = new ArrayList<>(); + + for (int k = 1; k <= 10; k++) + transactions.add(createTransaction(k)); + + List uncles = new ArrayList<>(); + + BlockGenerator blockGenerator = this.blockGenerator; + Block parent = blockGenerator.getGenesisBlock(); + + for (int k = 1; k < 10; k++) { + Block block = blockGenerator.createChildBlock(parent); + uncles.add(block.getHeader()); + parent = block; + } + + byte[] bloom = new byte[]{ 1, 2, 3, 4 }; + short[] edges = new short[]{ 1, 2, 3, 4 }; + BlockHeaderExtension extension = new BlockHeaderExtensionV1(bloom, edges); + + BodyResponseMessage message = new BodyResponseMessage(100, transactions, uncles, extension); + + byte[] encoded = message.getEncoded(); + + Message result = Message.create(blockFactory, encoded); + + Assertions.assertNotNull(result); + Assertions.assertArrayEquals(encoded, result.getEncoded()); + Assertions.assertEquals(MessageType.BODY_RESPONSE_MESSAGE, result.getMessageType()); + + BodyResponseMessage newmessage = (BodyResponseMessage)result; + + Assertions.assertNotNull(newmessage); + + Assertions.assertEquals(100, newmessage.getId()); + + Assertions.assertNotNull(newmessage.getTransactions()); + Assertions.assertEquals(transactions.size(), newmessage.getTransactions().size()); + + Assertions.assertEquals(transactions, newmessage.getTransactions()); + + Assertions.assertNotNull(newmessage.getUncles()); + Assertions.assertEquals(uncles.size(), newmessage.getUncles().size()); + + for (int k = 0; k < uncles.size(); k++) + Assertions.assertArrayEquals(uncles.get(k).getFullEncoded(), newmessage.getUncles().get(k).getFullEncoded()); + + Assertions.assertNotNull(newmessage.getBlockHeaderExtension()); + Assertions.assertArrayEquals(extension.getEncoded(), newmessage.getBlockHeaderExtension().getEncoded()); + } + private static Transaction createTransaction(int number) { AccountBuilder acbuilder = new AccountBuilder(); acbuilder.name("sender" + number); diff --git a/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncStateTest.java b/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncStateTest.java index d5a7ceac832..52379f07723 100644 --- a/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncStateTest.java +++ b/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBackwardsBodiesSyncStateTest.java @@ -25,10 +25,7 @@ import co.rsk.net.messages.BodyResponseMessage; import co.rsk.scoring.EventType; import org.ethereum.TestUtils; -import org.ethereum.core.Block; -import org.ethereum.core.BlockFactory; -import org.ethereum.core.BlockHeader; -import org.ethereum.core.Genesis; +import org.ethereum.core.*; import org.ethereum.db.BlockStore; import org.ethereum.util.ByteUtil; import org.junit.jupiter.api.Assertions; @@ -184,7 +181,7 @@ void connectingUntilGenesis() { toRequest.addFirst(headerToRequest); when(syncEventsHandler.sendBodyRequest(any(), eq(headerToRequest))).thenReturn(i); - BodyResponseMessage response = new BodyResponseMessage(i, new LinkedList<>(), new LinkedList<>()); + BodyResponseMessage response = new BodyResponseMessage(i, new LinkedList<>(), new LinkedList<>(), null); responses.addFirst(response); Block block = mock(Block.class); @@ -230,6 +227,76 @@ void connectingUntilGenesis() { } } + @Test + void connectingWithBlockHeaderExtension() { + LinkedList toRequest = new LinkedList<>(); + LinkedList responses = new LinkedList<>(); + LinkedList expectedBlocks = new LinkedList<>(); + Function difficultyForBlockNumber = + (n) -> new BlockDifficulty(BigInteger.valueOf(n * (n + 1) / 2)); + + // This setup initializes responses and blocks so that the blocks have the same number and difficulty as + // their indexes and each one is the children of the previous block. + for (long i = 1; i <= 10; i++) { + BlockHeader headerToRequest = mock(BlockHeader.class); + Keccak256 headerHash = new Keccak256(ByteUtil.leftPadBytes(ByteUtil.longToBytes(i), 32)); + BlockHeaderExtension blockHeaderExtension = mock(BlockHeaderExtension.class); + + when(headerToRequest.getExtension()).thenReturn(blockHeaderExtension); + when(headerToRequest.getHash()).thenReturn(headerHash); + when(headerToRequest.getNumber()).thenReturn(i); + + toRequest.addFirst(headerToRequest); + + when(syncEventsHandler.sendBodyRequest(any(), eq(headerToRequest))).thenReturn(i); + + BodyResponseMessage response = new BodyResponseMessage(i, new LinkedList<>(), new LinkedList<>(), blockHeaderExtension); + responses.addFirst(response); + + Block block = mock(Block.class); + expectedBlocks.addFirst(block); + when(block.getNumber()).thenReturn(i); + when(block.getHash()).thenReturn(headerHash); + when(blockFactory.newBlock(headerToRequest, response.getTransactions(), response.getUncles())) + .thenReturn(block); + + when(block.isParentOf(any())).thenReturn(true); + when(blockStore.getTotalDifficultyForHash(headerHash.getBytes())) + .thenReturn(difficultyForBlockNumber.apply(i)); + when(block.getCumulativeDifficulty()).thenReturn(new BlockDifficulty(BigInteger.valueOf(i))); + + when(block.getHeader()).thenReturn(headerToRequest); + } + when(genesis.isParentOf(expectedBlocks.getLast())).thenReturn(true); + when(genesis.getCumulativeDifficulty()).thenReturn(new BlockDifficulty(BigInteger.valueOf(0L))); + + Keccak256 childHash = new Keccak256(ByteUtil.leftPadBytes(ByteUtil.intToBytes(11), 32)); + when(child.getHash()).thenReturn(childHash); + when(blockStore.getTotalDifficultyForHash(childHash.getBytes())) + .thenReturn(difficultyForBlockNumber.apply(11L)); + when(child.getCumulativeDifficulty()).thenReturn(new BlockDifficulty(BigInteger.valueOf(11L))); + when(child.getNumber()).thenReturn(11L); + + DownloadingBackwardsBodiesSyncState target = new DownloadingBackwardsBodiesSyncState( + syncConfiguration, + syncEventsHandler, + peersInformation, + genesis, + blockFactory, + blockStore, + child, + toRequest, + peer); + + while (!responses.isEmpty()) { + target.onEnter(); + BodyResponseMessage response = responses.pop(); + target.newBody(response, mock(Peer.class)); + Block block = expectedBlocks.pop(); + verify(block.getHeader()).setExtension(response.getBlockHeaderExtension()); + } + } + @Test void connecting_notGenesis() { LinkedList toRequest = new LinkedList<>(); @@ -250,7 +317,7 @@ void connecting_notGenesis() { toRequest.addFirst(headerToRequest); when(syncEventsHandler.sendBodyRequest(any(), eq(headerToRequest))).thenReturn(i); - BodyResponseMessage response = new BodyResponseMessage(i, new LinkedList<>(), new LinkedList<>()); + BodyResponseMessage response = new BodyResponseMessage(i, new LinkedList<>(), new LinkedList<>(), null); responses.addFirst(response); Block block = mock(Block.class); diff --git a/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBodiesSyncStateTest.java b/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBodiesSyncStateTest.java index 0b83d2dfd59..9a60de83fe0 100644 --- a/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBodiesSyncStateTest.java +++ b/rskj-core/src/test/java/co/rsk/net/sync/DownloadingBodiesSyncStateTest.java @@ -85,7 +85,7 @@ void newBodyWhenUnexpectedMessageLogEvent() { pendingBodyResponses.put(messageId, pendingBodyResponse); TestUtils.setInternalState(state, "pendingBodyResponses", pendingBodyResponses); - BodyResponseMessage message = new BodyResponseMessage(33L, Collections.emptyList(), Collections.emptyList()); + BodyResponseMessage message = new BodyResponseMessage(33L, Collections.emptyList(), Collections.emptyList(), null); state.newBody(message, peer); verify(peersInformation, times(1)) .reportEventToPeerScoring(peer, EventType.UNEXPECTED_MESSAGE, @@ -111,7 +111,7 @@ void newBodyWhenUnexpectedMessageFromPeerLogEvent() { pendingBodyResponses.put(messageId, pendingBodyResponse); TestUtils.setInternalState(state, "pendingBodyResponses", pendingBodyResponses); - BodyResponseMessage message = new BodyResponseMessage(messageId, Collections.emptyList(), Collections.emptyList()); + BodyResponseMessage message = new BodyResponseMessage(messageId, Collections.emptyList(), Collections.emptyList(), null); state.newBody(message, peer); verify(peersInformation, times(1)) .reportEventToPeerScoring(peer, EventType.UNEXPECTED_MESSAGE, diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java index 1fbe8101c0b..274226115c1 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java @@ -91,7 +91,7 @@ void failsUponInvalidPublicKey() { }); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertEquals("Invalid extended public key 'tpubD6NzVbkrYhZ4YHQqwWz3Tm1ESZ9AidobeyLG4mEezB6hN8gFFWrcjczyF77L...'", e.getMessage()); + Assertions.assertEquals("Invalid extended public key 'tpubD6NzVbkrYhZ4YHQqwWz3Tm1ESZ9AidobeyLG4mEezB6hN8gFFWrcjczyF77Lw3...'", e.getMessage()); } } diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java index 7722487229c..c295bed1a83 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java @@ -63,7 +63,7 @@ void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidXpub() { void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidLongXpub() { NativeContractIllegalArgumentException exception = Assertions.assertThrows( NativeContractIllegalArgumentException.class, - () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidLongLongLongLongLongLongLongLongLongLongLonStuff")); - assertEquals("Invalid extended public key 'completelyInvalidLongLongLongLongLongLongLongLongLongLongLonStuf...'", exception.getMessage()); + () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidLongLongLongLongLongLongLongLongLongLongLongLStuff")); + assertEquals("Invalid extended public key 'completelyInvalidLongLongLongLongLongLongLongLongLongLongLongLStuf...'", exception.getMessage()); } } 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..eddf087aff2 100644 --- a/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/RskForksBridgeTest.java @@ -18,13 +18,15 @@ package co.rsk.peg; -import co.rsk.bitcoinj.core.*; -import co.rsk.peg.constants.BridgeRegTestConstants; +import co.rsk.bitcoinj.core.AddressFormatException; +import co.rsk.bitcoinj.core.BtcECKey; +import co.rsk.bitcoinj.core.Coin; import co.rsk.config.TestSystemProperties; import co.rsk.core.RskAddress; import co.rsk.core.TransactionExecutorFactory; import co.rsk.core.bc.BlockChainImpl; import co.rsk.db.RepositoryLocator; +import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.test.World; import co.rsk.test.builders.BlockBuilder; import co.rsk.trie.TrieStore; @@ -254,7 +256,7 @@ private Transaction buildWhitelistTx() { long nonce = 0; long value = 0; BigInteger gasPrice = BigInteger.valueOf(0); - BigInteger gasLimit = BigInteger.valueOf(1000000); + BigInteger gasLimit = BigInteger.valueOf(500000); Transaction rskTx = CallTransaction.createCallTransaction(nonce, gasPrice.longValue(), gasLimit.longValue(), PrecompiledContracts.BRIDGE_ADDR, value, Bridge.ADD_ONE_OFF_LOCK_WHITELIST_ADDRESS, Constants.REGTEST_CHAIN_ID, "mhxk5q8QdGFoaP4SJ3DPtXjrbxAgxjNm3C", BigInteger.valueOf(Coin.COIN.multiply(4).value)); @@ -380,7 +382,7 @@ private Transaction buildReceiveHeadersTx() { long nonce = 0; long value = 0; BigInteger gasPrice = BigInteger.valueOf(0); - BigInteger gasLimit = BigInteger.valueOf(1000000); + BigInteger gasLimit = BigInteger.valueOf(500000); Transaction rskTx = CallTransaction.createCallTransaction(nonce, gasPrice.longValue(), gasLimit.longValue(), PrecompiledContracts.BRIDGE_ADDR, value, Bridge.RECEIVE_HEADERS, Constants.REGTEST_CHAIN_ID, new Object[]{headerArray}); diff --git a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java index 4d908493635..c6cff78fc17 100644 --- a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinUtilsTest.java @@ -348,7 +348,7 @@ void removeSignaturesFromTransaction_whenNotAllTransactionInputsHaveP2shMultiSig // arrange Federation federation = P2shErpFederationBuilder.builder().build(); Script p2shMultiSigScriptSig = federation.getP2SHScript().createEmptyInputScript(null, federation.getRedeemScript()); - BtcECKey pubKey = new BtcECKey(); + BtcECKey pubKey = BitcoinTestUtils.getBtcEcKeyFromSeed("abc"); Script p2pkhScriptSig = ScriptBuilder.createInputScript(null, pubKey); BtcTransaction transaction = new BtcTransaction(btcMainnetParams); 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 1028665acfe..462dbf071b2 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascProcessMinerFeesTest.java @@ -1031,7 +1031,6 @@ private BlockExecutor buildBlockExecutor(RepositoryLocator repositoryLocator, Bl config.getActivationConfig(), signatureCache); return new BlockExecutor( - config.getActivationConfig(), repositoryLocator, new TransactionExecutorFactory( config, @@ -1041,7 +1040,7 @@ private BlockExecutor buildBlockExecutor(RepositoryLocator repositoryLocator, Bl new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) - ) - ); + ), + config); } } 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..abe5aa481a9 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascStorageProviderTest.java @@ -484,7 +484,6 @@ void paysOnlyBlocksWithEnoughBalanceAccumulatedAfterRFS() { config.getNetworkConstants().getBridgeConstants(), config.getActivationConfig(), signatureCache); BlockExecutor blockExecutor = new BlockExecutor( - config.getActivationConfig(), repositoryLocator, new TransactionExecutorFactory( config, @@ -494,8 +493,8 @@ void paysOnlyBlocksWithEnoughBalanceAccumulatedAfterRFS() { new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, signatureCache), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) - ) - ); + ), + config); for (Block b : blocks) { blockExecutor.executeAndFillAll(b, blockchain.getBestBlock().getHeader()); 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..be2ace22948 100644 --- a/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java +++ b/rskj-core/src/test/java/co/rsk/remasc/RemascTestRunner.java @@ -137,7 +137,6 @@ public void start() { builder.getConfig().getActivationConfig(), blockTxSignatureCache); PrecompiledContracts precompiledContracts = new PrecompiledContracts(builder.getConfig(), bridgeSupportFactory, blockTxSignatureCache); BlockExecutor blockExecutor = new BlockExecutor( - builder.getConfig().getActivationConfig(), builder.getRepositoryLocator(), new TransactionExecutorFactory( builder.getConfig(), @@ -147,8 +146,9 @@ public void start() { programInvokeFactory, precompiledContracts, blockTxSignatureCache - ) - ); + ), + builder.getConfig()); + Random random = new Random(RemascTestRunner.class.hashCode()); for(int i = 0; i <= this.initialHeight; i++) { int finalI = i; @@ -282,7 +282,7 @@ public static Block createBlock(Block genesis, Block parentBlock, Keccak256 bloc ); } - private static class HardcodedHashBlockHeader extends BlockHeader { + private static class HardcodedHashBlockHeader extends BlockHeaderV0 { private final Keccak256 blockHash; public HardcodedHashBlockHeader( @@ -294,7 +294,7 @@ public HardcodedHashBlockHeader( HashUtil.EMPTY_TRIE_HASH, new Bloom().getData(), finalDifficulty, parentBlock.getNumber() + 1, parentBlock.getGasLimit(), parentBlock.getGasUsed(), parentBlock.getTimestamp(), new byte[0], paidFees, null, null, null, new byte[0], - Coin.valueOf(10), uncles.size(), false, true, false, new byte[0] + Coin.valueOf(10), uncles.size(), false, true, false, new byte[0], null ); this.blockHash = blockHash; } diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/subscribe/EthSubscriptionNotificationTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/subscribe/EthSubscriptionNotificationTest.java index dca4ae7a98f..970144db69f 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/subscribe/EthSubscriptionNotificationTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/subscribe/EthSubscriptionNotificationTest.java @@ -20,6 +20,9 @@ import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.rpc.JacksonBasedRpcSerializer; import co.rsk.rpc.JsonRpcSerializer; +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.Block; import org.junit.jupiter.api.Test; @@ -29,10 +32,10 @@ import static org.hamcrest.MatcherAssert.assertThat; class EthSubscriptionNotificationTest { - private static final Block TEST_BLOCK = new BlockGenerator().createBlock(12, 0); - private static final String TEST_BLOCK_RESULT_JSON = "{\"difficulty\":\"0x20000\",\"extraData\":\"0x\",\"gasLimit\":\"0x2fefd8\",\"gasUsed\":\"0x0\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0xe94aef644e428941ee0a3741f28d80255fddba7f\",\"number\":\"0xc\",\"parentHash\":\"0xbe5de0c9c661653c979ec457f610444dcd0048007e683b2d04ce05729af56280\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"timestamp\":\"0x1\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"hash\":\"0x35b063d13f7d7b3c13ae508e2c2b3aa7e7ba110d4dda17f3d822ac24b1f952b7\"}"; - private static final Block TEST_BLOCK_2 = new BlockGenerator().createBlock(12, 0, 1000000L); - private static final String TEST_BLOCK_RESULT_JSON_2 = "{\"difficulty\":\"0x20000\",\"extraData\":\"0x\",\"gasLimit\":\"0xf4240\",\"gasUsed\":\"0x0\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0xe94aef644e428941ee0a3741f28d80255fddba7f\",\"number\":\"0xc\",\"parentHash\":\"0x82d804adc43b6382427216a764963f77c612694065f19b3b97c804338c6ceeec\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"timestamp\":\"0x1\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"hash\":\"0xa31b89729ad3f84b988a9418e629adf1de918dfcff8286ed65e06837574e80d8\"}"; + private static final Block TEST_BLOCK = new BlockGenerator(Constants.regtest(), ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351)).createBlock(12, 0); + private static final String TEST_BLOCK_RESULT_JSON = "{\"difficulty\":\"0x20000\",\"extraData\":\"0x\",\"gasLimit\":\"0x2fefd8\",\"gasUsed\":\"0x0\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0xe94aef644e428941ee0a3741f28d80255fddba7f\",\"number\":\"0xc\",\"parentHash\":\"0xbe5de0c9c661653c979ec457f610444dcd0048007e683b2d04ce05729af56280\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"timestamp\":\"0x1\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"hash\":\"0xae2699897284d434f3139376fbc606aabf2eade4b2cd1e551d37395f0b095dca\"}"; + private static final Block TEST_BLOCK_2 = new BlockGenerator(Constants.regtest(), ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351)).createBlock(12, 0, 1000000L); + private static final String TEST_BLOCK_RESULT_JSON_2 = "{\"difficulty\":\"0x20000\",\"extraData\":\"0x\",\"gasLimit\":\"0xf4240\",\"gasUsed\":\"0x0\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0xe94aef644e428941ee0a3741f28d80255fddba7f\",\"number\":\"0xc\",\"parentHash\":\"0x82d804adc43b6382427216a764963f77c612694065f19b3b97c804338c6ceeec\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"timestamp\":\"0x1\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"hash\":\"0x644f8371116ee86c675cc1eadaddfd97c49617b01dd0deb47bc978fcdef86dfc\"}"; private static final String TEST_SYNC_RESULT_JSON = "{\"syncing\":true,\"status\":{\"startingBlock\":0,\"currentBlock\":1,\"highestBlock\":1000}}"; 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..94694fd3bb5 100644 --- a/rskj-core/src/test/java/co/rsk/test/World.java +++ b/rskj-core/src/test/java/co/rsk/test/World.java @@ -80,6 +80,7 @@ public World() { this(new BlockChainBuilder()); } + public World(RskSystemProperties config) { this(new BlockChainBuilder().setConfig(config)); } @@ -88,6 +89,10 @@ public World(ReceiptStore receiptStore) { this(new BlockChainBuilder().setReceiptStore(receiptStore)); } + public World(ReceiptStore receiptStore, RskSystemProperties config) { + this(new BlockChainBuilder().setReceiptStore(receiptStore).setConfig(config)); + } + @VisibleForTesting public World(BlockChainBuilder blockChainBuilder) { this(blockChainBuilder.build(), blockChainBuilder.getBlockStore(), blockChainBuilder.getReceiptStore(), blockChainBuilder.getTrieStore(), blockChainBuilder.getRepository(), blockChainBuilder.getTransactionPool(), null, @@ -174,7 +179,6 @@ public BlockExecutor getBlockExecutor() { if (this.blockExecutor == null) { this.blockExecutor = new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(getTrieStore(), stateRootHandler), new TransactionExecutorFactory( config, @@ -184,8 +188,8 @@ public BlockExecutor getBlockExecutor() { programInvokeFactory, new PrecompiledContracts(config, bridgeSupportFactory, blockTxSignatureCache), blockTxSignatureCache - ) - ); + ), + config); } return this.blockExecutor; 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..073ca769464 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 @@ -19,6 +19,7 @@ package co.rsk.test.builders; import co.rsk.blockchain.utils.BlockGenerator; +import co.rsk.config.RskSystemProperties; import co.rsk.config.TestSystemProperties; import co.rsk.core.TransactionExecutorFactory; import co.rsk.core.bc.BlockExecutor; @@ -53,13 +54,17 @@ public class BlockBuilder { private final BridgeSupportFactory bridgeSupportFactory; private BlockStore blockStore; - public BlockBuilder(Blockchain blockChain, BridgeSupportFactory bridgeSupportFactory, BlockStore blockStore) { + public BlockBuilder(Blockchain blockChain, BridgeSupportFactory bridgeSupportFactory, BlockStore blockStore, BlockGenerator blockGenerator) { this.blockChain = blockChain; - this.blockGenerator = new BlockGenerator(); + this.blockGenerator = blockGenerator; this.bridgeSupportFactory = bridgeSupportFactory; this.blockStore = blockStore; } + public BlockBuilder(Blockchain blockChain, BridgeSupportFactory bridgeSupportFactory, BlockStore blockStore) { + this(blockChain, bridgeSupportFactory, blockStore, new BlockGenerator()); + } + public BlockBuilder parent(Block parent) { this.parent = parent; this.gasLimit = parent.getGasLimit(); @@ -100,13 +105,16 @@ public BlockBuilder trieStore(TrieStore store) { } public Block build() { + final TestSystemProperties config = new TestSystemProperties(); + return this.build(config); + } + + public Block build(final RskSystemProperties config) { Block block = blockGenerator.createChildBlock(parent, txs, uncles, difficulty, this.minGasPrice, gasLimit); if (blockChain != null) { - final TestSystemProperties config = new TestSystemProperties(); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); BlockExecutor executor = new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(trieStore, stateRootHandler), new TransactionExecutorFactory( config, @@ -116,8 +124,8 @@ public Block build() { new ProgramInvokeFactoryImpl(), new PrecompiledContracts(config, bridgeSupportFactory, new BlockTxSignatureCache(new ReceivedTxSignatureCache())), new BlockTxSignatureCache(new ReceivedTxSignatureCache()) - ) - ); + ), + config); 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..ad30260fb2f 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 @@ -247,10 +247,9 @@ public BlockChainImpl build() { config, repositoryLocator, this.blockStore, blockFactory, new TestCompositeEthereumListener(), transactionExecutorFactory, new ReceivedTxSignatureCache(), 10, 100, Mockito.mock(TxQuotaChecker.class), Mockito.mock(GasPriceTracker.class)); BlockExecutor blockExecutor = new BlockExecutor( - config.getActivationConfig(), repositoryLocator, - transactionExecutorFactory - ); + transactionExecutorFactory, + config); BlockChainImpl blockChain = new BlockChainLoader( blockStore, receiptStore, @@ -284,12 +283,20 @@ public Blockchain ofSize(int size) { return ofSize(size, false); } + public Blockchain ofSize(int size, BlockGenerator blockGenerator) { + return ofSize(size, false, Collections.emptyMap(), blockGenerator); + } + public Blockchain ofSize(int size, boolean mining) { return ofSize(size, mining, Collections.emptyMap()); } + public Blockchain ofSize(int size, boolean mining, Map accounts) { - BlockGenerator blockGenerator = new BlockGenerator(); + return ofSize(size, mining, accounts, new BlockGenerator()); + } + + public Blockchain ofSize(int size, boolean mining, Map accounts, BlockGenerator blockGenerator) { Genesis genesis = blockGenerator.getGenesisBlock(accounts); BlockChainImpl blockChain = setGenesis(genesis).build(); diff --git a/rskj-core/src/test/java/co/rsk/test/dsl/BlockBuildDslProcessor.java b/rskj-core/src/test/java/co/rsk/test/dsl/BlockBuildDslProcessor.java index aac2768e3fd..666c8c53c1b 100644 --- a/rskj-core/src/test/java/co/rsk/test/dsl/BlockBuildDslProcessor.java +++ b/rskj-core/src/test/java/co/rsk/test/dsl/BlockBuildDslProcessor.java @@ -18,6 +18,7 @@ package co.rsk.test.dsl; +import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.test.World; import co.rsk.test.builders.BlockBuilder; import org.ethereum.core.Block; @@ -34,11 +35,15 @@ public class BlockBuildDslProcessor { private World world; private String name; - private BlockBuilder builder = new BlockBuilder(null, null, null); + private BlockBuilder builder; public BlockBuildDslProcessor(World world, String name) { this.world = world; this.name = name; + + this.builder = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), + world.getBlockStore(), new BlockGenerator(world.getConfig().getNetworkConstants(), world.getConfig().getActivationConfig()) + ).trieStore(world.getTrieStore()); } public void processCommands(DslParser parser) throws DslProcessorException { @@ -55,7 +60,7 @@ private void processCommand(DslCommand cmd) throws DslProcessorException { else if (cmd.isCommand("gasLimit")) this.builder.gasLimit(BigInteger.valueOf(Long.parseLong(cmd.getArgument(0)))); else if (cmd.isCommand("build")) { - Block block = this.builder.build(); + Block block = this.builder.build(this.world.getConfig()); this.world.saveBlock(this.name, block); } else if (cmd.isCommand("uncles")) { 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..8c4f09722a2 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 @@ -18,6 +18,7 @@ package co.rsk.test.dsl; +import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.config.TestSystemProperties; import co.rsk.core.Coin; import co.rsk.core.RskAddress; @@ -55,7 +56,8 @@ public class WorldDslProcessor { public WorldDslProcessor(World world) { this.world = world; BlockBuilder blockBuilder = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()); + world.getBlockStore(), new BlockGenerator(world.getConfig().getNetworkConstants(), world.getConfig().getActivationConfig()) + ).trieStore(world.getTrieStore()); blockBuilder.parent(world.getBlockChain().getBestBlock()); this.blockBuilder = blockBuilder; } @@ -314,7 +316,6 @@ private void processBlockChainCommand(DslCommand cmd) { final TestSystemProperties config = new TestSystemProperties(); StateRootHandler stateRootHandler = new StateRootHandler(config.getActivationConfig(), new StateRootsStoreImpl(new HashMapDB())); BlockExecutor executor = new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(world.getTrieStore(), stateRootHandler), new TransactionExecutorFactory( config, @@ -324,8 +325,8 @@ private void processBlockChainCommand(DslCommand cmd) { programInvokeFactory, null, world.getBlockTxSignatureCache() - ) - ); + ), + config); executor.executeAndFill(block, parent.getHeader()); world.saveBlock(name, block); parent = block; diff --git a/rskj-core/src/test/java/co/rsk/test/dsltest/WorldDslProcessorTest.java b/rskj-core/src/test/java/co/rsk/test/dsltest/WorldDslProcessorTest.java index f2b3d4a5c5f..0239814ffff 100644 --- a/rskj-core/src/test/java/co/rsk/test/dsltest/WorldDslProcessorTest.java +++ b/rskj-core/src/test/java/co/rsk/test/dsltest/WorldDslProcessorTest.java @@ -520,9 +520,9 @@ void processBlockBuildCommandWithTransactions() throws DslProcessorException { WorldDslProcessor processor = new WorldDslProcessor(world); - DslParser parser = new DslParser("account_new acc1\naccount_new acc2\n" + - "transaction_build tx01\nsender acc1\nreceiver acc2\nvalue 1000\nbuild\n" + - "transaction_build tx02\nsender acc1\nreceiver acc2\nvalue 1000\nbuild\n" + + DslParser parser = new DslParser("account_new acc1 100000000000\naccount_new acc2 100000000000\n" + + "transaction_build tx01\nsender acc1\nreceiver acc2\nvalue 1000\nnonce 0\nbuild\n" + + "transaction_build tx02\nsender acc1\nreceiver acc2\nvalue 1000\nnonce 1\nbuild\n" + "block_build b01\nparent g00\ntransactions tx01 tx02\nbuild\n"); processor.processCommands(parser); diff --git a/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java b/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java index 2cd58093e6f..6cfaaf5c5b8 100644 --- a/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java @@ -24,8 +24,8 @@ class StringUtilsTest { - private static final String STR_64_CHARS = "ee5c851e70650111887bb6c04e18ef4353391abe37846234c17895a9ca2b33d5"; - private static final String STR_65_CHARS = STR_64_CHARS + "a"; + private static final String STR_66_CHARS = "0xee5c851e70650111887bb6c04e18ef4353391abe37846234c17895a9ca2b33d5"; + private static final String STR_67_CHARS = STR_66_CHARS + "a"; @Test void testTrim() { @@ -33,11 +33,11 @@ void testTrim() { assertEquals("", StringUtils.trim("")); assertEquals("a", StringUtils.trim("a")); - assertEquals(64, STR_64_CHARS.length()); - assertEquals(65, STR_65_CHARS.length()); + assertEquals(66, STR_66_CHARS.length()); + assertEquals(67, STR_67_CHARS.length()); - assertEquals(STR_64_CHARS, StringUtils.trim(STR_64_CHARS)); - assertEquals(STR_64_CHARS + "...", StringUtils.trim(STR_65_CHARS)); + assertEquals(STR_66_CHARS, StringUtils.trim(STR_66_CHARS)); + assertEquals(STR_66_CHARS + "...", StringUtils.trim(STR_67_CHARS)); } @Test diff --git a/rskj-core/src/test/java/co/rsk/validators/ValidTxExecutionSublistsEdgesTest.java b/rskj-core/src/test/java/co/rsk/validators/ValidTxExecutionSublistsEdgesTest.java new file mode 100644 index 00000000000..4a508e25102 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/validators/ValidTxExecutionSublistsEdgesTest.java @@ -0,0 +1,117 @@ +package co.rsk.validators; + +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.Block; +import org.ethereum.core.BlockHeader; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.LinkedList; +import java.util.List; + +class ValidTxExecutionSublistsEdgesTest { + + private BlockHeader blockHeader; + private Block block; + private List txList; + private ValidTxExecutionSublistsEdgesRule rule; + private ActivationConfig activationConfig; + private long blockNumber = 1L; + + @BeforeEach + public void setUp() { + blockHeader = Mockito.mock(org.ethereum.core.BlockHeader.class); + block = Mockito.mock(Block.class); + txList = Mockito.mock(LinkedList.class); + activationConfig = Mockito.mock(ActivationConfig.class); + Mockito.when(block.getHeader()).thenReturn(blockHeader); + Mockito.when(block.getTransactionsList()).thenReturn(txList); + Mockito.when(blockHeader.getNumber()).thenReturn(blockNumber); + Mockito.when(txList.size()).thenReturn(10); + + rule = new ValidTxExecutionSublistsEdgesRule(activationConfig); + } + + private void mockGetTxExecutionListsEdges (short[] edges, boolean rskip144Activated) { + Mockito.when(blockHeader.getTxExecutionSublistsEdges()).thenReturn(edges); + Mockito.when(activationConfig.isActive(ConsensusRule.RSKIP144, blockNumber)).thenReturn(rskip144Activated); + } + + // valid cases + @Test + void blockWithRSKIP144Deactivated() { + mockGetTxExecutionListsEdges(null, false); + + Assertions.assertTrue(rule.isValid(block)); + } + + @Test + void blockWithValidEdges() { + mockGetTxExecutionListsEdges(new short[]{2, 5}, true); + + Assertions.assertTrue(rule.isValid(block)); + } + + @Test + void blockWithEmptyEdges() { + mockGetTxExecutionListsEdges(new short[0], true); + + Assertions.assertTrue(rule.isValid(block)); + } + + // invalid cases + @Test + void blockWithTooManyEdges() { + mockGetTxExecutionListsEdges(new short[]{1, 2, 3, 4, 5}, true); + + Assertions.assertFalse(rule.isValid(block)); + } + + @Test + void blockWithOutOfBoundsEdgesBecauseOfRemascTx() { + // include the last tx in a parallelized thread + // shouldn't be valid because the last transaction + // is the remasc transaction and cannot be parallelized + mockGetTxExecutionListsEdges(new short[]{10}, true); + + Assertions.assertFalse(rule.isValid(block)); + } + + @Test + void blockWithOutOfBoundsEdges() { + mockGetTxExecutionListsEdges(new short[]{12}, true); + + Assertions.assertFalse(rule.isValid(block)); + } + + @Test + void blockWithNegativeEdge() { + mockGetTxExecutionListsEdges(new short[]{-2}, true); + + Assertions.assertFalse(rule.isValid(block)); + } + + @Test + void blockWithEdgeZero() { + mockGetTxExecutionListsEdges(new short[]{0, 2}, true); + + Assertions.assertFalse(rule.isValid(block)); + } + + @Test + void blockWithRepeatedEdge() { + mockGetTxExecutionListsEdges(new short[]{2, 2}, true); + + Assertions.assertFalse(rule.isValid(block)); + } + + @Test + void blockWithEdgesNotInOrder() { + mockGetTxExecutionListsEdges(new short[]{2, 4, 3}, true); + + Assertions.assertFalse(rule.isValid(block)); + } +} 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..ada53ff10c4 100644 --- a/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java +++ b/rskj-core/src/test/java/co/rsk/vm/MinerHelper.java @@ -97,6 +97,19 @@ public void processBlock( Block block, Block parent) { BlockTxSignatureCache blockTxSignatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); for (Transaction tx : block.getTransactionsList()) { + + /* + * This method is a helper of the test "testSEND_1". It is replicating the + * behavior of BlockExecutor but slightly different. In the BlockExecutor, the + * fees are sent to the Remasc address once all the transactions are executed. + * Since the only test using this helper processes one transaction, so the loop makes no sense. + * */ + + /*boolean isRemascTx = tx.isRemascTransaction(txindex, block.getTransactionsList().size()); + if (config.isRemascEnabled() && isRemascTx && totalPaidFees.compareTo(Coin.ZERO) > 0) { + track.addBalance(PrecompiledContracts.REMASC_ADDR, totalPaidFees); + }*/ + TransactionExecutorFactory transactionExecutorFactory = new TransactionExecutorFactory( config, null, @@ -109,11 +122,16 @@ public void processBlock( Block block, Block parent) { executor.executeTransaction(); - long gasUsed = executor.getGasUsed(); + long gasUsed = executor.getGasConsumed(); Coin paidFees = executor.getPaidFees(); totalGasUsed += gasUsed; totalPaidFees = totalPaidFees.add(paidFees); + /*boolean isLastTx = txindex == block.getTransactionsList().size(); + if (config.isRemascEnabled() && isLastTx && !isRemascTx && totalPaidFees.compareTo(Coin.ZERO) > 0) { + track.addBalance(PrecompiledContracts.REMASC_ADDR, totalPaidFees); + }*/ + track.commit(); TransactionReceipt receipt = new TransactionReceipt(); diff --git a/rskj-core/src/test/java/org/ethereum/TestUtils.java b/rskj-core/src/test/java/org/ethereum/TestUtils.java index 668a038e9e6..83710936f65 100644 --- a/rskj-core/src/test/java/org/ethereum/TestUtils.java +++ b/rskj-core/src/test/java/org/ethereum/TestUtils.java @@ -43,6 +43,8 @@ import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.security.SecureRandom; import java.util.*; @@ -64,6 +66,13 @@ public static Keccak256 generateHash(String discriminator) { return new Keccak256(generateBytes(TestUtils.class, discriminator, 32)); } + public static short[] randomShortArray(@Nonnull String discriminator, int length) { + short[] result = new short[length]; + byte[] bytes = generateBytes(TestUtils.class, discriminator, length * 2); + ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(result); + return result; + } + public static Long generateLong(@Nonnull String discriminator) { return new Random(discriminator.hashCode()).nextLong(); } 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 cff14eb6cef..167d30f3f8b 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 @@ -105,7 +105,9 @@ class ActivationConfigTest { " rskip290: hop400", " rskip293: hop400", " rskip294: hop400", + " rskip144: arrowhead600", " rskip297: hop400", + " rskip351: arrowhead600", " rskip326: fingerroot500", " rskip353: hop401", " rskip357: hop401", @@ -190,4 +192,16 @@ void failsReadingWithUnknownUpgradeConfiguration() { Config config = BASE_CONFIG.withValue("consensusRules.rskip420", ConfigValueFactory.fromAnyRef("orchid")); Assertions.assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); } + + @Test + void headerVersion0() { + ActivationConfig config = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351); + Assertions.assertEquals((byte) 0x0, config.getHeaderVersion(10)); + } + + @Test + void headerVersion1() { + ActivationConfig config = ActivationConfigsForTest.all(); + Assertions.assertEquals((byte) 0x1, config.getHeaderVersion(10)); + } } 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..889f5db90cf 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 @@ -185,7 +185,9 @@ private static List getArrowhead600Rskips() { ConsensusRule.RSKIP398, ConsensusRule.RSKIP400, ConsensusRule.RSKIP415, - ConsensusRule.RSKIP417 + ConsensusRule.RSKIP417, + ConsensusRule.RSKIP144, + ConsensusRule.RSKIP351 )); return rskips; diff --git a/rskj-core/src/test/java/org/ethereum/core/BlockHeaderBuilderTest.java b/rskj-core/src/test/java/org/ethereum/core/BlockHeaderBuilderTest.java index 401c4cc0764..041e7de4e9d 100644 --- a/rskj-core/src/test/java/org/ethereum/core/BlockHeaderBuilderTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/BlockHeaderBuilderTest.java @@ -23,6 +23,7 @@ import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import org.ethereum.TestUtils; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.crypto.HashUtil; @@ -35,12 +36,15 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; +import org.mockito.Mockito; import java.math.BigInteger; import java.util.Arrays; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.AdditionalMatchers.geq; +import static org.mockito.Mockito.when; class BlockHeaderBuilderTest { private static final byte[] EMPTY_UNCLES_LIST_HASH = HashUtil.keccak256(RLP.encodeList(new byte[0])); @@ -257,7 +261,10 @@ void createsHeaderWithEmptyMergedMiningFields() { @ParameterizedTest(name = "createHeader: when createConsensusCompliantHeader {0} and useRskip92Encoding {1} then expectedSize {2}") @ArgumentsSource(CreateHeaderArgumentsProvider.class) - void createsHeaderWith(boolean createConsensusCompliantHeader, boolean useRskip92Encoding, int expectedSize) { + void createsHeaderWith(boolean createConsensusCompliantHeader, boolean useRskip92Encoding, boolean useRSKIP351, int expectedSize) { + BlockHeaderBuilder blockHeaderBuilder = useRSKIP351 + ? this.blockHeaderBuilder + : new BlockHeaderBuilder(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351)); byte[] btcCoinbase = TestUtils.generateBytes(BlockHeaderBuilderTest.class, "btcCoinbase",128); byte[] btcHeader = TestUtils.generateBytes(BlockHeaderBuilderTest.class, "btcHeader",80); byte[] merkleProof = TestUtils.generateBytes(BlockHeaderBuilderTest.class, "merkleProof",32); @@ -400,15 +407,134 @@ void createsHeaderWithNullUmmrootButUmmCompliantHeaderOffAndRskipUmmOff() { assertArrayEquals(null, header.getUmmRoot()); } - private static class CreateHeaderArgumentsProvider implements ArgumentsProvider { + @Test + void createsHeaderWithParallelCompliant() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + + BlockHeader header = builder + .setCreateParallelCompliantHeader(true) + .build(); + + assertArrayEquals(new short[0], header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithoutParallelCompliant() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + + BlockHeader header = builder + .setCreateParallelCompliantHeader(false) + .build(); + + assertArrayEquals(null, header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithEdges() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = builder + .setTxExecutionSublistsEdges(edges) + .build(); + + assertArrayEquals(edges, header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithNullEdges() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + + BlockHeader header = builder + .setTxExecutionSublistsEdges(null) + .build(); + + assertArrayEquals(null, header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithNullEdgesButParallelCompliant() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + + BlockHeader header = builder + .setTxExecutionSublistsEdges(null) + .setCreateParallelCompliantHeader(true) + .build(); + assertArrayEquals(new short[0], header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithoutParallelCompliantButWithEdges() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = builder + .setCreateParallelCompliantHeader(false) + .setTxExecutionSublistsEdges(edges) + .build(); + + assertArrayEquals(edges, header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithEdgesButWithoutParallelCompliant() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + short[] edges = TestUtils.randomShortArray("edges", 4); + + BlockHeader header = builder + .setTxExecutionSublistsEdges(edges) + .setCreateParallelCompliantHeader(false) + .build(); + + assertArrayEquals(null, header.getTxExecutionSublistsEdges()); + } + + @Test + void createsHeaderWithParallelCompliantButWithNullEdges() { + BlockHeaderBuilder builder = new BlockHeaderBuilder(ActivationConfigsForTest.all()); + + BlockHeader header = builder + .setCreateParallelCompliantHeader(true) + .setTxExecutionSublistsEdges(null) + .build(); + + assertArrayEquals(null, header.getTxExecutionSublistsEdges()); + } + private static class CreateHeaderArgumentsProvider implements ArgumentsProvider { @Override public Stream provideArguments(ExtensionContext context) { return Stream.of( - Arguments.of(false, false, 20), - Arguments.of(false, true, 18), - Arguments.of(true, false, 18) + Arguments.of(false, false, false, 21), + Arguments.of(false, true, false, 19), + Arguments.of(true, false, false, 19), + Arguments.of(false, false, true, 22), + Arguments.of(false, true, true, 20), + Arguments.of(true, false, true, 20) ); } } + + @Test + void createsHeaderWithVersion0WithNoRskip351() { + // RSKIP351 = -1 + BlockHeader header = new BlockHeaderBuilder(ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351)).build(); + assertEquals((byte) 0x0, header.getVersion()); + } + + @Test + void createsHeaderWithVersion0BeforeRskip351() { + // RSKIP351 > header number + ActivationConfig activationConfig = Mockito.mock(ActivationConfig.class); + when(activationConfig.getHeaderVersion(geq(2))).thenReturn((byte) 0x0); + BlockHeader header = new BlockHeaderBuilder(activationConfig).setNumber(1).build(); + assertEquals((byte) 0x0, header.getVersion()); + } + + @Test + void createHeaderWithVersion1AfterRskip351() { + // RSKIP351 = 0 + BlockHeader header = new BlockHeaderBuilder(ActivationConfigsForTest.all()).build(); + assertEquals((byte) 0x1, header.getVersion()); + } } 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..3d1489a4680 100644 --- a/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -86,10 +86,9 @@ public static BlockChainImpl createBlockchain( listener, new DummyBlockValidator(), new BlockExecutor( - config.getActivationConfig(), repositoryLocator, - transactionExecutorFactory - ), + transactionExecutorFactory, + config), stateRootHandler ); 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..1109dcec96c 100644 --- a/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java +++ b/rskj-core/src/test/java/org/ethereum/jsontestsuite/TestRunner.java @@ -163,10 +163,9 @@ public List runTestCase(BlockTestingCase testCase) { null, new DummyBlockValidator(), new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(trieStore, stateRootHandler), - transactionExecutorFactory - ), + transactionExecutorFactory, + config), 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 dcd7877c3d6..ea1d8339986 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 @@ -20,6 +20,7 @@ import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.config.TestSystemProperties; +import co.rsk.core.Coin; import co.rsk.core.RskAddress; import co.rsk.core.TransactionExecutorFactory; import co.rsk.core.bc.BlockChainImpl; @@ -126,11 +127,15 @@ protected ProgramResult executeTransaction() { try{ executor.executeTransaction(); - } catch (StackOverflowError soe){ + } catch (StackOverflowError soe) { logger.error(" !!! StackOverflowError: update your java run command with -Xss32M !!!"); System.exit(-1); } + if (config.isRemascEnabled() && executor.getPaidFees().compareTo(Coin.ZERO) > 0) { + track.addBalance(PrecompiledContracts.REMASC_ADDR, executor.getPaidFees()); + } + track.commit(); return executor.getResult(); } @@ -153,7 +158,6 @@ public List runImpl() { null, null, new BlockExecutor( - config.getActivationConfig(), new RepositoryLocator(trieStore, stateRootHandler), new TransactionExecutorFactory( config, @@ -163,8 +167,8 @@ public List runImpl() { new ProgramInvokeFactoryImpl(), precompiledContracts, new BlockTxSignatureCache(new ReceivedTxSignatureCache()) - ) - ), + ), + config), stateRootHandler ); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/LogFilterTest.java b/rskj-core/src/test/java/org/ethereum/rpc/LogFilterTest.java index abd6715394e..443242a265a 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/LogFilterTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/LogFilterTest.java @@ -271,7 +271,7 @@ public static Block addBlockToBlockchain(Block parent, Account account, BlockBui Transaction tx = new TransactionBuilder() .nonce(parent.getNumber()) // just to increase nonce .sender(account) - .gasLimit(BigInteger.valueOf(1000000)) + .gasLimit(BigInteger.valueOf(500000)) .gasPrice(BigInteger.ONE) .data(compiled_0_4_11) .build(); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java index 63ec5209565..e7109268fb5 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java @@ -18,35 +18,11 @@ package org.ethereum.rpc; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; - -import java.math.BigInteger; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -import com.typesafe.config.ConfigValueFactory; -import org.ethereum.core.*; -import org.ethereum.datasource.HashMapDB; -import org.ethereum.db.BlockStore; -import org.ethereum.db.ReceiptStore; -import org.ethereum.facade.Ethereum; -import org.ethereum.rpc.Simples.SimpleConfigCapabilities; -import org.ethereum.rpc.dto.TransactionReceiptDTO; -import org.ethereum.rpc.exception.RskJsonRpcRequestException; -import org.ethereum.rpc.parameters.TxHashParam; -import org.ethereum.util.ByteUtil; -import org.ethereum.util.RskTestFactory; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - +import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.config.TestSystemProperties; import co.rsk.core.Coin; import co.rsk.core.Wallet; import co.rsk.core.WalletFactory; -import co.rsk.core.bc.MiningMainchainView; import co.rsk.crypto.Keccak256; import co.rsk.db.RepositoryLocator; import co.rsk.logfilter.BlocksBloomStore; @@ -67,6 +43,9 @@ import co.rsk.test.builders.TransactionBuilder; import co.rsk.trie.TrieStore; import co.rsk.util.HexUtils; +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.datasource.HashMapDB; import org.ethereum.db.BlockStore; @@ -137,7 +116,6 @@ class Web3ImplLogsTest { private Web3Impl web3; private TrieStore trieStore; private BlockStore blockStore; - private SignatureCache signatureCache; private BlocksBloomStore blocksBloomStore; @@ -866,7 +844,7 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterBySecondTopic() throws E @Test void getLogsFromBlockchainWithEventInContractCreationReturnsAsExpectedWithBlockHashFilter() throws Exception { addEventInContractCreation(); - final String blockHash = TRACKED_TEST_BLOCK_HASH; + final String blockHash = "0xed4afd31173a73c4c5135aae72b940507b97605a5129790de00510894f58f5ce"; FilterRequestParam fr = new FilterRequestParam(null, null, null, null, new BlockHashParam(blockHash)); Object[] logs = web3.eth_getLogs(fr); @@ -1204,7 +1182,7 @@ public static void addEmptyBlockToBlockchain( List txs = new ArrayList<>(); txs.add(tx); - Block block1 = new BlockBuilder(blockChain, null, blockStore) + Block block1 = new BlockBuilder(blockChain, null, blockStore, new BlockGenerator(Constants.regtest(), ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351))) .trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); } @@ -1350,7 +1328,7 @@ function getValue() constant returns (uint) { } */ return new TransactionBuilder() .sender(acc1) - .gasLimit(BigInteger.valueOf(1000000)) + .gasLimit(BigInteger.valueOf(500000)) .gasPrice(BigInteger.ONE) .data(compiled_0_4_11) .build(); @@ -1393,7 +1371,7 @@ function emit(uint n){ return new TransactionBuilder() .sender(acc1) - .gasLimit(BigInteger.valueOf(1000000)) + .gasLimit(BigInteger.valueOf(500000)) .gasPrice(BigInteger.ONE) .data(compiledLogExample) .build(); @@ -1423,7 +1401,7 @@ function doSomething(address mainAddr) { String compiledCaller = "606060405234610000576040516020806101f8833981016040528080519060200190919050505b8073ffffffffffffffffffffffffffffffffffffffff1663195977a66130396040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b156100005760325a03f115610000575050507f2012ef02e82e91abf55727cc31c3b6e3375003aa9e879f855db72d9e78822c40607b6040518082815260200191505060405180910390a15b505b610111806100e76000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e60c2d4414603c575b6000565b34600057606a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050606c565b005b8073ffffffffffffffffffffffffffffffffffffffff1663195977a661303a6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1560005760325a03f1156000575050505b505600a165627a7a72305820f8bc730651ba568de3f84a81088f94a8701c5c41f732d5c7a447077ee40f97a80029"; return new TransactionBuilder() .sender(acc1) - .gasLimit(BigInteger.valueOf(1000000)) + .gasLimit(BigInteger.valueOf(500000)) .gasPrice(BigInteger.ONE) .data(compiledCaller + address) .nonce(1) @@ -1441,7 +1419,7 @@ private static Transaction getCallerContractTransactionWithInvoke(Account acc1, return new TransactionBuilder() .sender(acc1) .receiverAddress(receiverAddress) - .gasLimit(BigInteger.valueOf(1000000)) + .gasLimit(BigInteger.valueOf(500000)) .gasPrice(BigInteger.ONE) .data(ByteUtil.toHexString(func.encode("0x" + address))) .nonce(2) 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 dc651c0d29d..5fcf46a1e34 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java @@ -19,6 +19,7 @@ package org.ethereum.rpc; import co.rsk.Flusher; +import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.config.RskSystemProperties; import co.rsk.config.TestSystemProperties; import co.rsk.core.*; @@ -62,6 +63,7 @@ import co.rsk.util.HexUtils; import co.rsk.util.NodeStopper; import co.rsk.util.TestContract; +import com.typesafe.config.ConfigValueFactory; import org.bouncycastle.util.encoders.Hex; import org.ethereum.TestUtils; import org.ethereum.core.*; @@ -1238,27 +1240,36 @@ private Web3Impl createWeb3WithMocks(EthModule ethModule) { blocksBloomStore, web3InformationRetriever, syncProcessor, signatureCache); } - @Test - void getBlockByNumber() { - World world = new World(); + private BlockBuilder createBlockBuilder(World world) { + return new BlockBuilder( + world.getBlockChain(), + world.getBridgeSupportFactory(), + world.getBlockStore(), + new BlockGenerator(world.getConfig().getNetworkConstants(), world.getConfig().getActivationConfig())); + } + void testBlockByNumber(RskSystemProperties config) { + World world = new World(config); Web3Impl web3 = createWeb3(world); Block genesis = world.getBlockChain().getBestBlock(); - Block block1 = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()).difficulty(10).parent(genesis).build(); + Block block1 = createBlockBuilder(world) + .trieStore(world.getTrieStore()).difficulty(10).parent(genesis).build(config); + assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); - Block block1b = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()).difficulty(2).parent(genesis).build(); + + Block block1b = createBlockBuilder(world) + .trieStore(world.getTrieStore()).difficulty(2).parent(genesis).build(config); block1b.setBitcoinMergedMiningHeader(new byte[]{0x01}); - Block block2b = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()).difficulty(11).parent(block1b).build(); + + Block block2b = createBlockBuilder(world) + .trieStore(world.getTrieStore()).difficulty(11).parent(block1b).build(config); block2b.setBitcoinMergedMiningHeader(new byte[]{0x02}); + assertEquals(ImportResult.IMPORTED_NOT_BEST, world.getBlockChain().tryToConnect(block1b)); assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block2b)); BlockResultDTO bresult = web3.eth_getBlockByNumber(new BlockIdentifierParam("0x1"), false); - assertNotNull(bresult); String blockHash = "0x" + block1b.getHash(); @@ -1266,15 +1277,25 @@ void getBlockByNumber() { String bnOrId = "0x2"; bresult = web3.eth_getBlockByNumber(new BlockIdentifierParam("0x2"), true); - assertNotNull(bresult); blockHash = "0x" + block2b.getHash(); assertEquals(blockHash, bresult.getHash()); String hexString = web3.rsk_getRawBlockHeaderByNumber(bnOrId).replace("0x", ""); - Keccak256 obtainedBlockHash = new Keccak256(HashUtil.keccak256(Hex.decode(hexString))); - assertEquals(blockHash, obtainedBlockHash.toJsonString()); + assertArrayEquals(block2b.getHeader().getEncoded(), Hex.decode(hexString)); + } + + @Test + void getBlockByNumberWithoutFingerroot500() { + testBlockByNumber(new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.hardforkActivationHeights.fingerroot500", ConfigValueFactory.fromAnyRef(2)) + )); + } + + @Test + void getBlockByNumber() { + testBlockByNumber(new TestSystemProperties()); } @Test @@ -1404,23 +1425,23 @@ void shutdownExitsWithZeroStatusCode() { verify(stopperMock).stop(0); } - @Test - void getBlockByHash() { + void testGetBlockByHash(RskSystemProperties config) { World world = new World(); Web3Impl web3 = createWeb3(world); Block genesis = world.getBlockChain().getBestBlock(); - Block block1 = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()).difficulty(10).parent(genesis).build(); + + Block block1 = createBlockBuilder(world).trieStore(world.getTrieStore()).difficulty(10).parent(genesis).build(); block1.setBitcoinMergedMiningHeader(new byte[]{0x01}); assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); - Block block1b = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()).difficulty(block1.getDifficulty().asBigInteger().longValue() - 1).parent(genesis).build(); + + Block block1b = createBlockBuilder(world).trieStore(world.getTrieStore()).difficulty(block1.getDifficulty().asBigInteger().longValue() - 1).parent(genesis).build(); block1b.setBitcoinMergedMiningHeader(new byte[]{0x01}); - Block block2b = new BlockBuilder(world.getBlockChain(), world.getBridgeSupportFactory(), - world.getBlockStore()).trieStore(world.getTrieStore()).difficulty(2).parent(block1b).build(); + + Block block2b = createBlockBuilder(world).trieStore(world.getTrieStore()).difficulty(2).parent(block1b).build(); block2b.setBitcoinMergedMiningHeader(new byte[]{0x02}); + assertEquals(ImportResult.IMPORTED_NOT_BEST, world.getBlockChain().tryToConnect(block1b)); assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block2b)); @@ -1446,8 +1467,7 @@ void getBlockByHash() { assertEquals(block1bHashString, bresult.getHash()); String hexString = web3.rsk_getRawBlockHeaderByHash(block1bHashString).replace("0x", ""); - Keccak256 blockHash = new Keccak256(HashUtil.keccak256(Hex.decode(hexString))); - assertEquals(blockHash.toJsonString(), block1bHashString); + assertArrayEquals(block1b.getHeader().getEncoded(), Hex.decode(hexString)); bresult = web3.eth_getBlockByHash(blockHashParam2, true); @@ -1455,8 +1475,19 @@ void getBlockByHash() { assertEquals(block2bHashString, bresult.getHash()); hexString = web3.rsk_getRawBlockHeaderByHash(block2bHashString).replace("0x", ""); - blockHash = new Keccak256(HashUtil.keccak256(Hex.decode(hexString))); - assertEquals(blockHash.toJsonString(), block2bHashString); + assertArrayEquals(block2b.getHeader().getEncoded(), Hex.decode(hexString)); + } + + @Test + void getBlockByHashWithoutFingerroot500() { + testGetBlockByHash(new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.hardforkActivationHeights.fingerroot500", ConfigValueFactory.fromAnyRef(2)) + )); + } + + @Test + void getBlockByHash() { + testGetBlockByHash(new TestSystemProperties()); } @Test diff --git a/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java b/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java index b5eee54f482..9b2677db62b 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java @@ -142,6 +142,7 @@ void getBlockResultDTOWithoutRemascAndFullTransactions() { Assertions.assertEquals(1, blockResultDTO.getTransactions().size()); Assertions.assertTrue(transactionResultsHashes.contains(TRANSACTION.getHash().toJsonString())); Assertions.assertFalse(transactionResultsHashes.contains(REMASC_TRANSACTION.getHash().toJsonString())); + Assertions.assertNotNull(blockResultDTO.getRskPteEdges()); } private List transactionResultsByBlock(BlockResultDTO blockResultDTO) { diff --git a/rskj-core/src/test/java/org/ethereum/util/ByteUtilTest.java b/rskj-core/src/test/java/org/ethereum/util/ByteUtilTest.java index 9741a99ef15..2f2c4ead3bd 100644 --- a/rskj-core/src/test/java/org/ethereum/util/ByteUtilTest.java +++ b/rskj-core/src/test/java/org/ethereum/util/ByteUtilTest.java @@ -513,4 +513,10 @@ void testToBytesWithLeadingZeros_WithLeadingZeros() { Assertions.assertEquals(src[i - srcStart], actualResult[i]); } } + + @Test + void shortsRLP() { + short[] shorts = new short[]{ 1, 2, 3, 5, 8, 13 }; + Assertions.assertArrayEquals(shorts, ByteUtil.rlpToShorts(RLP.decode2(ByteUtil.shortsToRLP(shorts)).get(0).getRLPData())); + } } diff --git a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleArrowhead600Test.java b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleArrowhead600Test.java new file mode 100644 index 00000000000..7cef67a14b9 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleArrowhead600Test.java @@ -0,0 +1,32 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * 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 org.ethereum.validator; + +import co.rsk.mine.NetworkUpgrades; +import org.junit.jupiter.api.BeforeEach; + +@SuppressWarnings("java:S2187") +class ProofOfWorkRuleArrowhead600Test extends ProofOfWorkRuleTest { + + @BeforeEach + void beforeEach() { + setUp(NetworkUpgrades.ARROWHEAD600_PROPERTIES.getProperties()); + } + +} diff --git a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleBambooTest.java b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleBambooTest.java index fc8bff68473..4516b50ecae 100644 --- a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleBambooTest.java +++ b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleBambooTest.java @@ -21,6 +21,7 @@ import co.rsk.mine.NetworkUpgrades; import org.junit.jupiter.api.BeforeEach; +@SuppressWarnings("java:S2187") class ProofOfWorkRuleBambooTest extends ProofOfWorkRuleTest { @BeforeEach diff --git a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleOrchidTest.java b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleOrchidTest.java index 4203d592e7b..3d0d737a8f5 100644 --- a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleOrchidTest.java +++ b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleOrchidTest.java @@ -21,6 +21,7 @@ import co.rsk.mine.NetworkUpgrades; import org.junit.jupiter.api.BeforeEach; +@SuppressWarnings("java:S2187") class ProofOfWorkRuleOrchidTest extends ProofOfWorkRuleTest { @BeforeEach diff --git a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleTest.java b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleTest.java index bb9249b368f..80f0baeae55 100644 --- a/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleTest.java +++ b/rskj-core/src/test/java/org/ethereum/validator/ProofOfWorkRuleTest.java @@ -21,6 +21,7 @@ import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.blockchain.utils.BlockMiner; +import co.rsk.config.MiningConfig; import co.rsk.config.RskMiningConstants; import co.rsk.config.RskSystemProperties; import co.rsk.config.TestSystemProperties; @@ -28,20 +29,25 @@ import co.rsk.mine.MinerUtils; import co.rsk.util.DifficultyUtils; import co.rsk.validators.ProofOfWorkRule; +import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.core.Block; import org.ethereum.core.BlockFactory; -import org.junit.jupiter.api.*; +import org.ethereum.core.BlockHeader; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; -import org.bouncycastle.util.encoders.Hex; +import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -66,7 +72,7 @@ protected void setUp(TestSystemProperties config) { void test_1() { // mined block Block b = new BlockMiner(activationConfig).mineBlock(new BlockGenerator(networkConstants, activationConfig).getBlock(1)); - Assertions.assertTrue(rule.isValid(b)); + assertTrue(rule.isValid(b)); } @Disabled("TODO improve, the mutated block header could be still valid") @@ -94,8 +100,8 @@ void test_RLPEncoding() { byte[] lastField2 = b2.getBitcoinMergedMiningCoinbaseTransaction(); // last field b2.flushRLP();// force re-encode byte[] encoded2 = b2.getEncoded(); - Assertions.assertTrue(Arrays.equals(encoded,encoded2)); - Assertions.assertTrue(Arrays.equals(lastField,lastField2)); + assertTrue(Arrays.equals(encoded,encoded2)); + assertTrue(Arrays.equals(lastField,lastField2)); } @Disabled("stress test") @@ -113,7 +119,7 @@ void test_3() { long total = System.currentTimeMillis() - start; - Assertions.assertTrue(total > 0); + assertTrue(total > 0); System.out.printf("Time: total = %d ms, per block = %.2f ms%n", total, (double) total / iterCnt); } @@ -141,6 +147,22 @@ void test_RSKTagInCoinbaseTransactionTooFar() { Assertions.assertFalse(rule.isValid(b)); } + @Test + void test_validAfterEncodingAndDecoding() { + BlockHeader header = blockFactory.getBlockHeaderBuilder() + .setNumber(MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION) + .setIncludeForkDetectionData(true) + .build(); + Block block = blockFactory.newBlock(header, Collections.emptyList(), Collections.emptyList(), false); + Block minedBlock = new BlockMiner(activationConfig).mineBlock(block); + BlockHeader minedBlockHeader = minedBlock.getHeader(); + + byte[] encodedCompressed = minedBlockHeader.getFullEncoded(); + BlockHeader decodedHeader = blockFactory.decodeHeader(encodedCompressed, false); + + assertTrue(rule.isValid(decodedHeader)); + } + @Test void bytesAfterMergedMiningHashAreLessThan128() { RskSystemProperties props = new TestSystemProperties() { @@ -169,7 +191,7 @@ public ActivationConfig getActivationConfig() { Block newBlock1 = new BlockMiner(config).mineBlock(newBlock, bitcoinMergedMiningCoinbaseTransaction); ProofOfWorkRule rule = new ProofOfWorkRule(props); - Assertions.assertTrue(rule.isValid(newBlock1)); + assertTrue(rule.isValid(newBlock1)); } @Test diff --git a/rskj-core/src/test/java/org/ethereum/vm/VMTest.java b/rskj-core/src/test/java/org/ethereum/vm/VMTest.java index 0f9e95cd2fb..4564d0104dc 100644 --- a/rskj-core/src/test/java/org/ethereum/vm/VMTest.java +++ b/rskj-core/src/test/java/org/ethereum/vm/VMTest.java @@ -3380,6 +3380,50 @@ void testBASEFEE() { assertEquals("000000000000000000000000000000000000000000000000000003104e60a000", ByteUtil.toHexString(program.getStack().peek().getData())); } + @Test + void whenProgramIsInitializedPrecompiledCalledShouldBeFalse() { + Program program = getProgram(new byte[]{}); + Assertions.assertTrue(program.precompiledContractsCalled().isEmpty()); + } + + @Test + void ifATxCallsAPrecompiledContractPrecompiledContractHasBeenCalledShouldBeTrue() { + program = getProgram(compile("PUSH1 0x00" + + " PUSH1 0x00" + + " PUSH1 0x01" + + " PUSH1 0x00" + + " PUSH1 0x01" + + " PUSH1 0x00" + + " PUSH1 0x00" + + " PUSH20 0x" + PrecompiledContracts.IDENTITY_ADDR_STR + + " PUSH4 0x005B8D80" + + " CALL" + )); + vm.steps(program, Long.MAX_VALUE); + Assertions.assertFalse(program.precompiledContractsCalled().isEmpty()); + Assertions.assertFalse(program.getResult().isRevert()); + } + + @Test + void ifATxCallsANonPrecompiledContractPrecompiledContractHasBeenCalledShouldBeFalse() { + invoke = new ProgramInvokeMockImpl(compile("PUSH1 0x01 PUSH1 0x02 SUB"), null); + + program = getProgram(compile("PUSH1 0x00" + + " PUSH1 0x00" + + " PUSH1 0x01" + //out size + " PUSH1 0x00" + //out off + " PUSH1 0x01" + //in size + " PUSH1 0x00" + //in off + " PUSH1 0x00" + + " PUSH20 0x" + invoke.getContractAddress() + + " PUSH4 0x005B8D80" + + " CALL" + )); + vm.steps(program, Long.MAX_VALUE); + Assertions.assertTrue(program.precompiledContractsCalled().isEmpty()); + Assertions.assertFalse(program.getResult().isRevert()); + } + private VM getSubject() { return new VM(vmConfig, precompiledContracts); } diff --git a/rskj-core/src/test/resources/dsl/blake2b/eip_152_example.txt b/rskj-core/src/test/resources/dsl/blake2b/eip_152_example.txt index e6043a6fb16..5663d776711 100644 --- a/rskj-core/src/test/resources/dsl/blake2b/eip_152_example.txt +++ b/rskj-core/src/test/resources/dsl/blake2b/eip_152_example.txt @@ -69,7 +69,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50610693806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806382fe1c9b1461003b578063fc75ac4714610045575b600080fd5b61004361008b565b005b61004d6101f6565b6040518082600260200280838360005b8381101561007857808201518184015260208101905061005d565b5050505090500191505060405180910390f35b60007fba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1905060007f7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd400992390506100dd610591565b6100e56101f6565b9050600083826000600281106100f757fe5b60200201511490506000838360016002811061010f57fe5b60200201511490508161016d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603381526020018061062c6033913960400191505060405180910390fd5b806101c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260348152602001806105f86034913960400191505060405180910390fd5b7f28ac248877e8517478dfc963b8e1f727f15b62bc721ea3aa078bd81873f8a88160405160405180910390a15050505050565b6101fe610591565b6000600c905061020c610591565b7f48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa58160006002811061023a57fe5b6020020181815250507fd182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b8160016002811061027157fe5b6020020181815250506102826105b3565b7f6162630000000000000000000000000000000000000000000000000000000000816000600481106102b057fe5b6020020181815250506000816001600481106102c857fe5b6020020181815250506000816002600481106102e057fe5b6020020181815250506000816003600481106102f857fe5b6020020181815250506103096105d5565b7f03000000000000000000000000000000000000000000000000000000000000008160006002811061033757fe5b602002019077ffffffffffffffffffffffffffffffffffffffffffffffff1916908177ffffffffffffffffffffffffffffffffffffffffffffffff19168152505060008160016002811061038757fe5b602002019077ffffffffffffffffffffffffffffffffffffffffffffffff1916908177ffffffffffffffffffffffffffffffffffffffffffffffff1916815250506000600190506103db85858585856103e5565b9550505050505090565b6103ed610591565b6103f5610591565b6060878760006002811061040557fe5b60200201518860016002811061041757fe5b60200201518860006004811061042957fe5b60200201518960016004811061043b57fe5b60200201518a60026004811061044d57fe5b60200201518b60036004811061045f57fe5b60200201518b60006002811061047157fe5b60200201518c60016002811061048357fe5b60200201518c604051602001808b63ffffffff1663ffffffff1660e01b81526004018a81526020018981526020018881526020018781526020018681526020018581526020018477ffffffffffffffffffffffffffffffffffffffffffffffff191677ffffffffffffffffffffffffffffffffffffffffffffffff191681526008018377ffffffffffffffffffffffffffffffffffffffffffffffff191677ffffffffffffffffffffffffffffffffffffffffffffffff19168152600801821515151560f81b81526001019a5050505050505050505050604051602081830303815290604052905060408260d5602084016009600019fa61058357600080fd5b819250505095945050505050565b6040518060400160405280600290602082028038833980820191505090505090565b6040518060800160405280600490602082028038833980820191505090505090565b604051806040016040528060029060208202803883398082019150509050509056fe626c616b6532622e663a207365636f6e642076616c756520646f65736e2774206d617463682065787065637465642076616c7565626c616b6532622e663a2066697273742076616c756520646f65736e2774206d617463682065787065637465642076616c7565a265627a7a72315820f6f4c217e94a3b7f87cedfc47c7b5b9a9ab1b048c36a62bcba4d0f9c20c6fc6264736f6c63430005100032 - gas 2000000 + gas 1000000 build # invoke runTest() @@ -81,11 +81,12 @@ transaction_build tx02 value 0 #data 12ca565c data 82fe1c9b - gas 2000000000 + gas 100000000 build block_build b01 parent g00 + gasLimit 3000000000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/bridgeDelegateCall.txt b/rskj-core/src/test/resources/dsl/bridgeDelegateCall.txt index 610b47b2ad1..369ddb28311 100644 --- a/rskj-core/src/test/resources/dsl/bridgeDelegateCall.txt +++ b/rskj-core/src/test/resources/dsl/bridgeDelegateCall.txt @@ -5,7 +5,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 5f600060006000600073000000000000000000000000000000000100000663005b8d80f1 - gas 1200000 + gas 600000 build transaction_build tx02 @@ -13,7 +13,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 5f600060006000600073000000000000000000000000000000000100000663005b8d80f4 - gas 1200000 + gas 600000 nonce 1 build @@ -22,7 +22,7 @@ transaction_build tx03 receiverAddress 00 value 0 data 5f600060006000600073000000000000000000000000000000000100000663005b8d80f2 - gas 1200000 + gas 600000 nonce 2 build @@ -31,7 +31,7 @@ transaction_build tx04 receiverAddress 00 value 0 data 5f600060006000600073000000000000000000000000000000000100000663005b8d80fa - gas 1200000 + gas 600000 nonce 3 build diff --git a/rskj-core/src/test/resources/dsl/call01.txt b/rskj-core/src/test/resources/dsl/call01.txt index 5b81c63351e..af368679a26 100644 --- a/rskj-core/src/test/resources/dsl/call01.txt +++ b/rskj-core/src/test/resources/dsl/call01.txt @@ -36,6 +36,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/codeSizeAfterSuicide.txt b/rskj-core/src/test/resources/dsl/codeSizeAfterSuicide.txt index 63ef04301f7..2469ecb6f4b 100644 --- a/rskj-core/src/test/resources/dsl/codeSizeAfterSuicide.txt +++ b/rskj-core/src/test/resources/dsl/codeSizeAfterSuicide.txt @@ -6,7 +6,7 @@ transaction_build createCreatorAndRun nonce 0 value 0 data 608060405234801561001057600080fd5b50606060405180602001610023906100ba565b6020820181038252601f19601f82011660405250905060008090506000818351602085016000f5905060008190508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561009957600080fd5b505af11580156100ad573d6000803e3d6000fd5b50505050505050506100c7565b6101768061011383390190565b603e806100d56000396000f3fe6080604052600080fdfea265627a7a72305820a7e17e7e5eb7b65cf24fc5474caad0c255ba2c294b137214a1ec5ec7ddd7548364736f6c63430005090032608060405234801561001057600080fd5b50610156806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b6060604051806020016045906073565b6020820181038252601f19601f82011660405250905060008090506000818351602085016000f59050505050565b60a2806100808339019056fe6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b600073ffffffffffffffffffffffffffffffffffffffff16fffea265627a7a723058201116e4763485ea3809dcd4a200f7c55712ae437dab27c860563fe1c4884f2a3664736f6c63430005090032a265627a7a7230582038b99a100f4e2adb982bfa08a60406860f9ea5d73b082a02670cf258bfc89e0264736f6c63430005090032 - gas 2000000 + gas 1000000 build transaction_build runSuicider @@ -27,6 +27,7 @@ transaction_build callCodeSizeChecker block_build b01 parent g00 + gasLimit 7500000 transactions createCreatorAndRun build @@ -34,6 +35,7 @@ block_connect b01 block_build b02 parent b01 + gasLimit 7500000 transactions runSuicider callCodeSizeChecker build diff --git a/rskj-core/src/test/resources/dsl/contract_call/contract_nested_abi_calls.txt b/rskj-core/src/test/resources/dsl/contract_call/contract_nested_abi_calls.txt index edb8e699a7c..6cb0f3933e2 100644 --- a/rskj-core/src/test/resources/dsl/contract_call/contract_nested_abi_calls.txt +++ b/rskj-core/src/test/resources/dsl/contract_call/contract_nested_abi_calls.txt @@ -73,7 +73,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 6080604052600b60005534801561001557600080fd5b5061011d806100256000396000f3fe608060405260043610601c5760003560e01c8063d96a094a146021575b600080fd5b604a60048036036020811015603557600080fd5b81019080803590602001909291905050506060565b6040518082815260200191505060405180910390f35b600080821160d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e656761746976652076616c75652e000000000000000000000000000000000081525060200191505060405180910390fd5b81600081905550600054905091905056fea26469706673582212209d6bb30c4cdfb29525a661c56652bb5676e62de7e1fa11da6baee0122871d73764736f6c63430006010033 - gas 2000000 + gas 1000000 build # Deploy ContractB (address: 56aa252dd82173789984fa164ee26ce2da9336ff) @@ -86,7 +86,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 6080604052600b60015534801561001557600080fd5b506040516102b73803806102b78339818101604052602081101561003857600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061021e806100996000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d96a094a14610030575b600080fd5b61005c6004803603602081101561004657600080fd5b8101908080359060200190929190505050610072565b6040518082815260200191505060405180910390f35b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682604051602401808281526020019150506040516020818303038152906040527fd96a094a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b6020831061016d578051825260208201915060208101905060208303925061014a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146101cf576040519150601f19603f3d011682016040523d82523d6000602084013e6101d4565b606091505b50505081600181905550600154905091905056fea264697066735822122020ecc8df14a8b94f9ab73c0cdd1558fc3c9d92e7d0b6ce196cc7c2972250ee6c64736f6c634300060100330000000000000000000000006252703f5ba322ec64d3ac45e56241b7d9e481ad - gas 2000000 + gas 1000000 build # Deploy ContractA (address: 27444fbce96cb2d27b94e116d1506d7739c05862) @@ -99,11 +99,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 6080604052600b60015534801561001557600080fd5b506040516102b73803806102b78339818101604052602081101561003857600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061021e806100996000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d96a094a14610030575b600080fd5b61005c6004803603602081101561004657600080fd5b8101908080359060200190929190505050610072565b6040518082815260200191505060405180910390f35b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682604051602401808281526020019150506040516020818303038152906040527fd96a094a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b6020831061016d578051825260208201915060208101905060208303925061014a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146101cf576040519150601f19603f3d011682016040523d82523d6000602084013e6101d4565b606091505b50505081600181905550600154905091905056fea26469706673582212200990ca360d90787a3bd0042e6267b7476cf8decb859f92a92c6b6b109d316ade64736f6c6343000601003300000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 10000000 transactions tx01 tx02 tx03 build @@ -120,13 +121,13 @@ transaction_build tx04 receiverAddress 27444fbce96cb2d27b94e116d1506d7739c05862 value 0 data d96a094a0000000000000000000000000000000000000000000000000000000000000000 - gas 2000000 + gas 500000 build block_build b02 parent b01 transactions tx04 - gasLimit 6500000 + gasLimit 10000000 build block_connect b02 @@ -147,7 +148,7 @@ transaction_build tx05 block_build b03 parent b02 transactions tx05 - gasLimit 6500000 + gasLimit 10000000 build block_connect b03 diff --git a/rskj-core/src/test/resources/dsl/contract_call/contract_nested_interface_calls.txt b/rskj-core/src/test/resources/dsl/contract_call/contract_nested_interface_calls.txt index c09e08e3a31..74c56e41f1d 100644 --- a/rskj-core/src/test/resources/dsl/contract_call/contract_nested_interface_calls.txt +++ b/rskj-core/src/test/resources/dsl/contract_call/contract_nested_interface_calls.txt @@ -67,7 +67,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 6080604052600b60005534801561001557600080fd5b5061015f806100256000396000f3fe6080604052600436106100295760003560e01c80630dbe671f1461002e578063d96a094a14610059575b600080fd5b34801561003a57600080fd5b5061004361009b565b6040518082815260200191505060405180910390f35b6100856004803603602081101561006f57600080fd5b81019080803590602001909291905050506100a1565b6040518082815260200191505060405180910390f35b60005481565b6000808211610118576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e656761746976652076616c75652e000000000000000000000000000000000081525060200191505060405180910390fd5b81600081905550600054905091905056fea264697066735822122059b4c86b4cc24c6a58060fc78f3e3bae4bc889144ec64ad30416d58d549e9c9e64736f6c63430006010033 - gas 2000000 + gas 1000000 build # Deploy ContractB (address: 56aa252dd82173789984fa164ee26ce2da9336ff) @@ -80,7 +80,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 6080604052600b60015534801561001557600080fd5b506040516102163803806102168339818101604052602081101561003857600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061017d806100996000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80630dbe671f1461003b578063d96a094a14610059575b600080fd5b610043610087565b6040518082815260200191505060405180910390f35b6100856004803603602081101561006f57600080fd5b810190808035906020019092919050505061008d565b005b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d96a094a826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561010157600080fd5b505af1158015610115573d6000803e3d6000fd5b505050506040513d602081101561012b57600080fd5b810190808051906020019092919050505050806001819055505056fea26469706673582212202ea598ad7db9f0f4fd9f2fe977c221997dc15e3bd0bb426c469d882099df084264736f6c634300060100330000000000000000000000006252703f5ba322ec64d3ac45e56241b7d9e481ad - gas 2000000 + gas 1000000 build # Deploy ContractA (address: 27444fbce96cb2d27b94e116d1506d7739c05862) @@ -93,11 +93,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 6080604052600b60015534801561001557600080fd5b506040516101f23803806101f28339818101604052602081101561003857600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610159806100996000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80630dbe671f1461003b578063d96a094a14610059575b600080fd5b610043610087565b6040518082815260200191505060405180910390f35b6100856004803603602081101561006f57600080fd5b810190808035906020019092919050505061008d565b005b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d96a094a826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561010157600080fd5b505af1158015610115573d6000803e3d6000fd5b50505050806001819055505056fea2646970667358221220e01a719553468e6072c3d9c5b718164b705c2e4550a5168446d6fa86d09dc55d64736f6c6343000601003300000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 10000000 transactions tx01 tx02 tx03 build @@ -113,13 +114,13 @@ transaction_build tx04 receiverAddress 27444fbce96cb2d27b94e116d1506d7739c05862 value 0 data d96a094a0000000000000000000000000000000000000000000000000000000000000000 - gas 2000000 + gas 500000 build block_build b02 parent b01 transactions tx04 - gasLimit 6500000 + gasLimit 10000000 build block_connect b02 @@ -140,7 +141,7 @@ transaction_build tx05 block_build b03 parent b02 transactions tx05 - gasLimit 6500000 + gasLimit 10000000 build block_connect b03 diff --git a/rskj-core/src/test/resources/dsl/contracts01.txt b/rskj-core/src/test/resources/dsl/contracts01.txt index 1b727bc67ea..66972166f69 100644 --- a/rskj-core/src/test/resources/dsl/contracts01.txt +++ b/rskj-core/src/test/resources/dsl/contracts01.txt @@ -10,6 +10,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/contracts02.txt b/rskj-core/src/test/resources/dsl/contracts02.txt index 50b29cc46e6..40bdc334c5d 100644 --- a/rskj-core/src/test/resources/dsl/contracts02.txt +++ b/rskj-core/src/test/resources/dsl/contracts02.txt @@ -10,6 +10,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 3000000000 transactions tx01 build @@ -29,6 +30,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 3000000000 transactions tx02 build diff --git a/rskj-core/src/test/resources/dsl/contracts03.txt b/rskj-core/src/test/resources/dsl/contracts03.txt index 2334cbd53c1..5208023ffae 100644 --- a/rskj-core/src/test/resources/dsl/contracts03.txt +++ b/rskj-core/src/test/resources/dsl/contracts03.txt @@ -10,6 +10,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build @@ -29,6 +30,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 7500000 transactions tx02 build @@ -51,6 +53,7 @@ transaction_build tx03 block_build b03 parent b02 + gasLimit 7500000 transactions tx03 build @@ -73,6 +76,7 @@ transaction_build tx04 block_build b04 parent b03 + gasLimit 75000000 transactions tx04 build @@ -120,7 +124,7 @@ transaction_build tx06 contract tx01 # created in tx01 value 5000 data 9530dcee - gas 1000000 + gas 500000 build block_build b06 diff --git a/rskj-core/src/test/resources/dsl/contracts05.txt b/rskj-core/src/test/resources/dsl/contracts05.txt index 11203b619c3..332ff29ebc0 100644 --- a/rskj-core/src/test/resources/dsl/contracts05.txt +++ b/rskj-core/src/test/resources/dsl/contracts05.txt @@ -10,6 +10,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/contracts06.txt b/rskj-core/src/test/resources/dsl/contracts06.txt index 3b09b09b929..189f0d797ec 100644 --- a/rskj-core/src/test/resources/dsl/contracts06.txt +++ b/rskj-core/src/test/resources/dsl/contracts06.txt @@ -16,6 +16,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/contracts07.txt b/rskj-core/src/test/resources/dsl/contracts07.txt index 54b6bdb4432..50fddc13fbd 100644 --- a/rskj-core/src/test/resources/dsl/contracts07.txt +++ b/rskj-core/src/test/resources/dsl/contracts07.txt @@ -13,6 +13,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build @@ -34,6 +35,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 7500000 transactions tx02 build @@ -50,11 +52,12 @@ transaction_build tx03 contract tx01 # created in tx01 value 0 data 45d9a1ce00000000000000000000000028fdc38c327f4a3bbdf9501fd3a01ac7228c7af700000000000000000000000067bde3af536b093abcee56fbdf2e003453186dc500000000000000000000000000000000000000000000000000000000000001f4 - gas 3000000 + gas 1000000 build block_build b03 parent b02 + gasLimit 7500000 transactions tx03 build diff --git a/rskj-core/src/test/resources/dsl/contracts08.txt b/rskj-core/src/test/resources/dsl/contracts08.txt index ba4f9559f60..561752bf98d 100644 --- a/rskj-core/src/test/resources/dsl/contracts08.txt +++ b/rskj-core/src/test/resources/dsl/contracts08.txt @@ -107,6 +107,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build @@ -129,6 +130,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 6800000 transactions tx02 build @@ -150,6 +152,7 @@ transaction_build tx03 block_build b03 parent b02 + gasLimit 6800000 transactions tx03 build @@ -171,6 +174,7 @@ transaction_build tx04 block_build b04 parent b03 + gasLimit 6800000 transactions tx04 build diff --git a/rskj-core/src/test/resources/dsl/contracts09.txt b/rskj-core/src/test/resources/dsl/contracts09.txt index 36b698d77f7..271d610024a 100644 --- a/rskj-core/src/test/resources/dsl/contracts09.txt +++ b/rskj-core/src/test/resources/dsl/contracts09.txt @@ -14,6 +14,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/create01.txt b/rskj-core/src/test/resources/dsl/create01.txt index 91981e389dc..bb3aa07d067 100644 --- a/rskj-core/src/test/resources/dsl/create01.txt +++ b/rskj-core/src/test/resources/dsl/create01.txt @@ -7,7 +7,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820b25edb28bec763685838b8044760e105b5385638276b4768c8045237b8fc6bf10029 - gas 1200000 + gas 500000 build block_build b01 diff --git a/rskj-core/src/test/resources/dsl/create02.txt b/rskj-core/src/test/resources/dsl/create02.txt index 3356bf77cbc..dee1b5104e5 100644 --- a/rskj-core/src/test/resources/dsl/create02.txt +++ b/rskj-core/src/test/resources/dsl/create02.txt @@ -13,15 +13,17 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b504361001a61017b565b80828152602001915050604051809103906000f080158015610040573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f80ae3ec8027d0c5d1f3e47fb4bf1d9fc28225e7f4bcb1971b36efb81fe40574d6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561012657600080fd5b505af115801561013a573d6000803e3d6000fd5b505050506040513d602081101561015057600080fd5b81019080805190602001909291905050506040518082815260200191505060405180910390a161018b565b6040516101e38061028283390190565b60e9806101996000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806361bc221a146044575b600080fd5b348015604f57600080fd5b5060566098565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058209aa0690aab1fdc50c2666446294d07319939d78fbf0060b72ebeb7f23be19c620029608060405234801561001057600080fd5b506040516020806101e383398101806040528101908080519060200190929190505050806000819055507f06acbfb32bcf8383f3b0a768b70ac9ec234ea0f2d3b9c77fa6a2de69b919aad16000546040518082815260200191505060405180910390a150610160806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632096525514610051578063d09de08a1461007c575b600080fd5b34801561005d57600080fd5b50610066610093565b6040518082815260200191505060405180910390f35b34801561008857600080fd5b506100916100d6565b005b60007f1ee041944547858a75ebef916083b6d4f5ae04bea9cd809334469dd07dbf441b6000546040518082815260200191505060405180910390a1600054905090565b600080815460010191905081905550600160026000548115156100f557fe5b061415157f6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad6000546040518082815260200191505060405180910390a25600a165627a7a723058205f51e4885fb38fdd8afbd598712eec4c95c6b0d690be063b728631de76bcb2730029 - gas 2000000 + gas 1000000 build block_build b01b parent g00 + gasLimit 7500000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx02 build @@ -29,6 +31,7 @@ block_connect b01b block_build b02b parent b01b + gasLimit 7500000 transactions tx02 build diff --git a/rskj-core/src/test/resources/dsl/create201.txt b/rskj-core/src/test/resources/dsl/create201.txt index c00b7a619a3..9fccb1e3079 100644 --- a/rskj-core/src/test/resources/dsl/create201.txt +++ b/rskj-core/src/test/resources/dsl/create201.txt @@ -24,6 +24,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/createAfterSuicide.txt b/rskj-core/src/test/resources/dsl/createAfterSuicide.txt index 27a4ab2b37f..b594174c4e8 100644 --- a/rskj-core/src/test/resources/dsl/createAfterSuicide.txt +++ b/rskj-core/src/test/resources/dsl/createAfterSuicide.txt @@ -6,7 +6,7 @@ transaction_build createCreatorAndRun nonce 0 value 0 data 608060405234801561001057600080fd5b50606060405180602001610023906100ba565b6020820181038252601f19601f82011660405250905060008090506000818351602085016000f5905060008190508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561009957600080fd5b505af11580156100ad573d6000803e3d6000fd5b50505050505050506100c7565b6101768061011383390190565b603e806100d56000396000f3fe6080604052600080fdfea265627a7a72305820a7e17e7e5eb7b65cf24fc5474caad0c255ba2c294b137214a1ec5ec7ddd7548364736f6c63430005090032608060405234801561001057600080fd5b50610156806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b6060604051806020016045906073565b6020820181038252601f19601f82011660405250905060008090506000818351602085016000f59050505050565b60a2806100808339019056fe6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b600073ffffffffffffffffffffffffffffffffffffffff16fffea265627a7a723058201116e4763485ea3809dcd4a200f7c55712ae437dab27c860563fe1c4884f2a3664736f6c63430005090032a265627a7a7230582038b99a100f4e2adb982bfa08a60406860f9ea5d73b082a02670cf258bfc89e0264736f6c63430005090032 - gas 2000000 + gas 1000000 build transaction_build runSuicider @@ -27,6 +27,7 @@ transaction_build callSecondCreator block_build b01 parent g00 + gasLimit 6800000 transactions createCreatorAndRun build diff --git a/rskj-core/src/test/resources/dsl/create_and_preserve_balance.txt b/rskj-core/src/test/resources/dsl/create_and_preserve_balance.txt index e278173938e..661bc25c69e 100644 --- a/rskj-core/src/test/resources/dsl/create_and_preserve_balance.txt +++ b/rskj-core/src/test/resources/dsl/create_and_preserve_balance.txt @@ -46,7 +46,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820b25edb28bec763685838b8044760e105b5385638276b4768c8045237b8fc6bf10029 - gas 1200000 + gas 500000 build # build block #5 with rskip174 activated diff --git a/rskj-core/src/test/resources/dsl/create_and_preserve_no_balance.txt b/rskj-core/src/test/resources/dsl/create_and_preserve_no_balance.txt index 960f0b6e44c..204620b99bc 100644 --- a/rskj-core/src/test/resources/dsl/create_and_preserve_no_balance.txt +++ b/rskj-core/src/test/resources/dsl/create_and_preserve_no_balance.txt @@ -31,7 +31,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820b25edb28bec763685838b8044760e105b5385638276b4768c8045237b8fc6bf10029 - gas 1200000 + gas 500000 build block_build b02 diff --git a/rskj-core/src/test/resources/dsl/delegatecall01.txt b/rskj-core/src/test/resources/dsl/delegatecall01.txt index 9cc1a3a8dd6..c958d9dc366 100644 --- a/rskj-core/src/test/resources/dsl/delegatecall01.txt +++ b/rskj-core/src/test/resources/dsl/delegatecall01.txt @@ -35,6 +35,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/delegatecall02.txt b/rskj-core/src/test/resources/dsl/delegatecall02.txt index 27a66edbca5..a897cb1dda8 100644 --- a/rskj-core/src/test/resources/dsl/delegatecall02.txt +++ b/rskj-core/src/test/resources/dsl/delegatecall02.txt @@ -30,6 +30,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValue.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValue.txt index 7452fa8349b..141f7bf0a72 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValue.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValue.txt @@ -21,11 +21,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 6080604052348015600f57600080fd5b5060a98061001e6000396000f3fe608060405260043610601f5760003560e01c8063c3cefd36146022576020565b5b005b6028602a565b005b3073ffffffffffffffffffffffffffffffffffffffff166108fc60019081150290604051600060405180830381858888f193505050501580156070573d6000803e3d6000fd5b5056fea264697066735822122088f249a82f3007a2761278a171ae52bad97182b2fd8cfe635e9f0a7f8082d50864736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build @@ -38,11 +39,12 @@ transaction_build tx02 nonce 1 value 100 data c3cefd36 - gas 2000000 + gas 1000000 build block_build b02 parent b01 + gasLimit 6800000 #transactions tx02 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValuePlusSstoreRefund.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValuePlusSstoreRefund.txt index d097aecdaa5..b100b39b83e 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValuePlusSstoreRefund.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/callWithValuePlusSstoreRefund.txt @@ -32,11 +32,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50602a600060016064811061002157fe5b018190555061016e806100356000396000f3fe6080604052600436106100385760003560e01c80635b3f81401461003b5780635e383d211461004557806394b3f5ee1461009457610039565b5b005b6100436100ab565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b8101908080359060200190929190505050610109565b6040518082815260200191505060405180910390f35b3480156100a057600080fd5b506100a9610121565b005b6000806001606481106100ba57fe5b01819055503073ffffffffffffffffffffffffffffffffffffffff166108fc60019081150290604051600060405180830381858888f19350505050158015610106573d6000803e3d6000fd5b50565b6000816064811061011657fe5b016000915090505481565b602a600060016064811061013157fe5b018190555056fea26469706673582212204f4296fafbb59e65b8ab38addc7f71380bbcba3f71112e6f4c4304298ed663c864736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build @@ -51,13 +52,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 1 data 5b3f8140 - gas 6800000 + gas 3400000 build block_build b02 parent b01 transactions tx02 - gasLimit 6800000 + gasLimit 7500000 build #block_connect b02 diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/firstCallMoveAllRemainingSecondNot.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/firstCallMoveAllRemainingSecondNot.txt index 7c82fe387d3..3c73e309eaa 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/firstCallMoveAllRemainingSecondNot.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/firstCallMoveAllRemainingSecondNot.txt @@ -29,6 +29,7 @@ transaction_build tx01 block_build b01 parent g00 + gasLimit 10000000 transactions tx01 build @@ -46,6 +47,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 10000000 #transactions tx02 build @@ -54,6 +56,7 @@ assert_best b02 block_build b03 parent b02 + gasLimit 10000000 transactions tx02 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/gasCap.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/gasCap.txt index 4b4ae942803..370c100af4f 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/gasCap.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/gasCap.txt @@ -22,11 +22,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5060a78061001f6000396000f3fe608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806331fe52e8146044575b600080fd5b348015604f57600080fd5b5060566058565b005b60008090505b60005a11156078576000819050508080600101915050605e565b5056fea165627a7a72305820189bbcc31f3f86bceb6648ec2f3ce61273ec572330bae05a5890d64703648c5d0029 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValue.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValue.txt index 6ed781f8fb8..17406b79474 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValue.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValue.txt @@ -41,7 +41,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b5061023f8061003a6000396000f3fe6080604052600436106100385760003560e01c80633aecee241461003b578063ba26473514610052578063fb60f709146100a357610039565b5b005b34801561004757600080fd5b506100506100ad565b005b34801561005e57600080fd5b506100a16004803603602081101561007557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100ca565b005b6100ab61010d565b005b6001600060146101000a81548160ff021916908315150217905550565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff166101da5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f709346127105a03906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561018f57600080fd5b5088f11580156101a3573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610207565b7faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220a49fa0e8a4947075a1ccbc823ca128cf2b35d6dc594337da9924f07596c2285b64736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx02 @@ -50,7 +50,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b5061023f8061003a6000396000f3fe6080604052600436106100385760003560e01c80633aecee241461003b578063ba26473514610052578063fb60f709146100a357610039565b5b005b34801561004757600080fd5b506100506100ad565b005b34801561005e57600080fd5b506100a16004803603602081101561007557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100ca565b005b6100ab61010d565b005b6001600060146101000a81548160ff021916908315150217905550565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff166101da5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f709346127105a03906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561018f57600080fd5b5088f11580156101a3573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610207565b7faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220a49fa0e8a4947075a1ccbc823ca128cf2b35d6dc594337da9924f07596c2285b64736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx03 @@ -59,11 +59,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b5061023f8061003a6000396000f3fe6080604052600436106100385760003560e01c80633aecee241461003b578063ba26473514610052578063fb60f709146100a357610039565b5b005b34801561004757600080fd5b506100506100ad565b005b34801561005e57600080fd5b506100a16004803603602081101561007557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100ca565b005b6100ab61010d565b005b6001600060146101000a81548160ff021916908315150217905550565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff166101da5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f709346127105a03906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561018f57600080fd5b5088f11580156101a3573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610207565b7faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220a49fa0e8a4947075a1ccbc823ca128cf2b35d6dc594337da9924f07596c2285b64736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 tx02 tx03 build @@ -76,7 +77,7 @@ transaction_build tx04 nonce 3 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad data ba26473500000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build # init next address 27444fbce96cb2d27b94e116d1506d7739c05862 @@ -85,7 +86,7 @@ transaction_build tx05 nonce 4 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data ba26473500000000000000000000000027444fbce96cb2d27b94e116d1506d7739c05862 - gas 2000000 + gas 1000000 build # init last call @@ -94,11 +95,12 @@ transaction_build tx06 nonce 5 receiverAddress 27444fbce96cb2d27b94e116d1506d7739c05862 data 3aecee24 - gas 2000000 + gas 1000000 build block_build b02 parent b01 + gasLimit 7500000 transactions tx04 tx05 tx06 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueAndStorageRefund.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueAndStorageRefund.txt index 5ce34b98e24..22aac21db9c 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueAndStorageRefund.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueAndStorageRefund.txt @@ -56,7 +56,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b50602a600160006001815260200190815260200160002081905550602a600160006002815260200190815260200160002081905550602a600160006003815260200190815260200160002081905550602a600160006004815260200190815260200160002081905550602a60016000600581526020019081526020016000208190555061037a806100bc6000396000f3fe6080604052600436106100435760003560e01c80633aecee24146100465780635e383d211461005d578063ba264735146100ac578063fb60f709146100fd57610044565b5b005b34801561005257600080fd5b5061005b610107565b005b34801561006957600080fd5b506100966004803603602081101561008057600080fd5b8101908080359060200190929190505050610124565b6040518082815260200191505060405180910390f35b3480156100b857600080fd5b506100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013c565b005b61010561017f565b005b6001600060146101000a81548160ff021916908315150217905550565b60016020528060005260406000206000915090505481565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff1661024c5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f709346127105a03906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561020157600080fd5b5088f1158015610215573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610342565b600060016000600181526020019081526020016000208190555060006001600060028152602001908152602001600020819055506000600160006003815260200190815260200160002081905550600060016000600481526020019081526020016000208190555060006001600060058152602001908152602001600020819055503073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610314573d6000803e3d6000fd5b507faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220597bb4cb03e45f2e30e7bec4738d5b1056f3f8f5156d8fd74ef927091ce7968d64736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx02 @@ -65,7 +65,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b50602a600160006001815260200190815260200160002081905550602a600160006002815260200190815260200160002081905550602a600160006003815260200190815260200160002081905550602a600160006004815260200190815260200160002081905550602a60016000600581526020019081526020016000208190555061037a806100bc6000396000f3fe6080604052600436106100435760003560e01c80633aecee24146100465780635e383d211461005d578063ba264735146100ac578063fb60f709146100fd57610044565b5b005b34801561005257600080fd5b5061005b610107565b005b34801561006957600080fd5b506100966004803603602081101561008057600080fd5b8101908080359060200190929190505050610124565b6040518082815260200191505060405180910390f35b3480156100b857600080fd5b506100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013c565b005b61010561017f565b005b6001600060146101000a81548160ff021916908315150217905550565b60016020528060005260406000206000915090505481565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff1661024c5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f709346127105a03906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561020157600080fd5b5088f1158015610215573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610342565b600060016000600181526020019081526020016000208190555060006001600060028152602001908152602001600020819055506000600160006003815260200190815260200160002081905550600060016000600481526020019081526020016000208190555060006001600060058152602001908152602001600020819055503073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610314573d6000803e3d6000fd5b507faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220597bb4cb03e45f2e30e7bec4738d5b1056f3f8f5156d8fd74ef927091ce7968d64736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx03 @@ -74,11 +74,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b50602a600160006001815260200190815260200160002081905550602a600160006002815260200190815260200160002081905550602a600160006003815260200190815260200160002081905550602a600160006004815260200190815260200160002081905550602a60016000600581526020019081526020016000208190555061037a806100bc6000396000f3fe6080604052600436106100435760003560e01c80633aecee24146100465780635e383d211461005d578063ba264735146100ac578063fb60f709146100fd57610044565b5b005b34801561005257600080fd5b5061005b610107565b005b34801561006957600080fd5b506100966004803603602081101561008057600080fd5b8101908080359060200190929190505050610124565b6040518082815260200191505060405180910390f35b3480156100b857600080fd5b506100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013c565b005b61010561017f565b005b6001600060146101000a81548160ff021916908315150217905550565b60016020528060005260406000206000915090505481565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff1661024c5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f709346127105a03906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561020157600080fd5b5088f1158015610215573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610342565b600060016000600181526020019081526020016000208190555060006001600060028152602001908152602001600020819055506000600160006003815260200190815260200160002081905550600060016000600481526020019081526020016000208190555060006001600060058152602001908152602001600020819055503073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610314573d6000803e3d6000fd5b507faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220597bb4cb03e45f2e30e7bec4738d5b1056f3f8f5156d8fd74ef927091ce7968d64736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 tx02 tx03 build @@ -91,7 +92,7 @@ transaction_build tx04 nonce 3 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad data ba26473500000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build # init next address 27444fbce96cb2d27b94e116d1506d7739c05862 @@ -100,7 +101,7 @@ transaction_build tx05 nonce 4 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data ba26473500000000000000000000000027444fbce96cb2d27b94e116d1506d7739c05862 - gas 2000000 + gas 1000000 build # init last call @@ -109,11 +110,12 @@ transaction_build tx06 nonce 5 receiverAddress 27444fbce96cb2d27b94e116d1506d7739c05862 data 3aecee24 - gas 2000000 + gas 1000000 build block_build b02 parent b01 + gasLimit 7500000 transactions tx04 tx05 tx06 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueStorageRefundAndFixedGas.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueStorageRefundAndFixedGas.txt index 17674bc585d..e0a47bfef3c 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueStorageRefundAndFixedGas.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/nestedCallsWithValueStorageRefundAndFixedGas.txt @@ -56,7 +56,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b50602a600160006001815260200190815260200160002081905550602a600160006002815260200190815260200160002081905550602a600160006003815260200190815260200160002081905550602a600160006004815260200190815260200160002081905550602a600160006005815260200190815260200160002081905550610379806100bc6000396000f3fe6080604052600436106100435760003560e01c80633aecee24146100465780635e383d211461005d578063ba264735146100ac578063fb60f709146100fd57610044565b5b005b34801561005257600080fd5b5061005b610107565b005b34801561006957600080fd5b506100966004803603602081101561008057600080fd5b8101908080359060200190929190505050610124565b6040518082815260200191505060405180910390f35b3480156100b857600080fd5b506100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013c565b005b61010561017f565b005b6001600060146101000a81548160ff021916908315150217905550565b60016020528060005260406000206000915090505481565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff1661024b5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f70934620186a0906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561020057600080fd5b5088f1158015610214573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610341565b600060016000600181526020019081526020016000208190555060006001600060028152602001908152602001600020819055506000600160006003815260200190815260200160002081905550600060016000600481526020019081526020016000208190555060006001600060058152602001908152602001600020819055503073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610313573d6000803e3d6000fd5b507faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220c905291e932b21b40fd3481b37e86ccdc27a82c41d4b79c2b9ba1493e806168e64736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx02 @@ -65,7 +65,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b50602a600160006001815260200190815260200160002081905550602a600160006002815260200190815260200160002081905550602a600160006003815260200190815260200160002081905550602a600160006004815260200190815260200160002081905550602a600160006005815260200190815260200160002081905550610379806100bc6000396000f3fe6080604052600436106100435760003560e01c80633aecee24146100465780635e383d211461005d578063ba264735146100ac578063fb60f709146100fd57610044565b5b005b34801561005257600080fd5b5061005b610107565b005b34801561006957600080fd5b506100966004803603602081101561008057600080fd5b8101908080359060200190929190505050610124565b6040518082815260200191505060405180910390f35b3480156100b857600080fd5b506100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013c565b005b61010561017f565b005b6001600060146101000a81548160ff021916908315150217905550565b60016020528060005260406000206000915090505481565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff1661024b5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f70934620186a0906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561020057600080fd5b5088f1158015610214573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610341565b600060016000600181526020019081526020016000208190555060006001600060028152602001908152602001600020819055506000600160006003815260200190815260200160002081905550600060016000600481526020019081526020016000208190555060006001600060058152602001908152602001600020819055503073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610313573d6000803e3d6000fd5b507faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220c905291e932b21b40fd3481b37e86ccdc27a82c41d4b79c2b9ba1493e806168e64736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx03 @@ -74,11 +74,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405260008060146101000a81548160ff02191690831515021790555034801561002a57600080fd5b50602a600160006001815260200190815260200160002081905550602a600160006002815260200190815260200160002081905550602a600160006003815260200190815260200160002081905550602a600160006004815260200190815260200160002081905550602a600160006005815260200190815260200160002081905550610379806100bc6000396000f3fe6080604052600436106100435760003560e01c80633aecee24146100465780635e383d211461005d578063ba264735146100ac578063fb60f709146100fd57610044565b5b005b34801561005257600080fd5b5061005b610107565b005b34801561006957600080fd5b506100966004803603602081101561008057600080fd5b8101908080359060200190929190505050610124565b6040518082815260200191505060405180910390f35b3480156100b857600080fd5b506100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013c565b005b61010561017f565b005b6001600060146101000a81548160ff021916908315150217905550565b60016020528060005260406000206000915090505481565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060149054906101000a900460ff1661024b5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fb60f70934620186a0906040518363ffffffff1660e01b81526004016000604051808303818589803b15801561020057600080fd5b5088f1158015610214573d6000803e3d6000fd5b5050505050507fde0f1ac890b93f05f29eb21d0298f6bf3b9954213c196fefecdb445b4ed047a560405160405180910390a1610341565b600060016000600181526020019081526020016000208190555060006001600060028152602001908152602001600020819055506000600160006003815260200190815260200160002081905550600060016000600481526020019081526020016000208190555060006001600060058152602001908152602001600020819055503073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610313573d6000803e3d6000fd5b507faf10f11658b97bcc0ed656fdfe4e20ca91e4a2a150f363233da11ec1d4898a4760405160405180910390a15b56fea2646970667358221220c905291e932b21b40fd3481b37e86ccdc27a82c41d4b79c2b9ba1493e806168e64736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 tx02 tx03 build @@ -91,7 +92,7 @@ transaction_build tx04 nonce 3 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad data ba26473500000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build # init next address 27444fbce96cb2d27b94e116d1506d7739c05862 @@ -100,7 +101,7 @@ transaction_build tx05 nonce 4 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data ba26473500000000000000000000000027444fbce96cb2d27b94e116d1506d7739c05862 - gas 2000000 + gas 1000000 build # init last call @@ -109,11 +110,12 @@ transaction_build tx06 nonce 5 receiverAddress 27444fbce96cb2d27b94e116d1506d7739c05862 data 3aecee24 - gas 2000000 + gas 1000000 build block_build b02 parent b01 + gasLimit 7500000 transactions tx04 tx05 tx06 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase1.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase1.txt index 78fc7d33004..99791f0e461 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase1.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase1.txt @@ -48,7 +48,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061031d806100206000396000f3fe6080604052600436106100385760003560e01c806318d3af631461003b5780636efb15df14610045578063ba2647351461008057610039565b5b005b6100436100d1565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b810190808035906020019092919050505061029a565b005b34801561008c57600080fd5b506100cf600480360360208110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506102a4565b005b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561012b57610298565b600060015411156101ea5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636001546040518263ffffffff1660e01b81526004016000604051808303818588803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050507fd99f0cfde566379669cb08fdc25d80461af2e181833081dd90ca21eaabfc1f9560405160405180910390a1610297565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561025257600080fd5b505af1158015610266573d6000803e3d6000fd5b505050507fc912088d570658c8656f32ff15e09d77c5d9eb8c4304e077777143ba6225dc8860405160405180910390a15b5b565b8060018190555050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea26469706673582212209458b89f68ed66dc26086396962dad91224bfad1e1711e6151d84b91dfe798c564736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx02 @@ -57,7 +57,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061031d806100206000396000f3fe6080604052600436106100385760003560e01c806318d3af631461003b5780636efb15df14610045578063ba2647351461008057610039565b5b005b6100436100d1565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b810190808035906020019092919050505061029a565b005b34801561008c57600080fd5b506100cf600480360360208110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506102a4565b005b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561012b57610298565b600060015411156101ea5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636001546040518263ffffffff1660e01b81526004016000604051808303818588803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050507fd99f0cfde566379669cb08fdc25d80461af2e181833081dd90ca21eaabfc1f9560405160405180910390a1610297565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561025257600080fd5b505af1158015610266573d6000803e3d6000fd5b505050507fc912088d570658c8656f32ff15e09d77c5d9eb8c4304e077777143ba6225dc8860405160405180910390a15b5b565b8060018190555050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea26469706673582212209458b89f68ed66dc26086396962dad91224bfad1e1711e6151d84b91dfe798c564736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx03 @@ -66,11 +66,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061031d806100206000396000f3fe6080604052600436106100385760003560e01c806318d3af631461003b5780636efb15df14610045578063ba2647351461008057610039565b5b005b6100436100d1565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b810190808035906020019092919050505061029a565b005b34801561008c57600080fd5b506100cf600480360360208110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506102a4565b005b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561012b57610298565b600060015411156101ea5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636001546040518263ffffffff1660e01b81526004016000604051808303818588803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050507fd99f0cfde566379669cb08fdc25d80461af2e181833081dd90ca21eaabfc1f9560405160405180910390a1610297565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561025257600080fd5b505af1158015610266573d6000803e3d6000fd5b505050507fc912088d570658c8656f32ff15e09d77c5d9eb8c4304e077777143ba6225dc8860405160405180910390a15b5b565b8060018190555050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea26469706673582212209458b89f68ed66dc26086396962dad91224bfad1e1711e6151d84b91dfe798c564736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 tx02 tx03 build @@ -83,7 +84,7 @@ transaction_build tx04 nonce 3 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad data ba26473500000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build # init next address 27444fbce96cb2d27b94e116d1506d7739c05862 @@ -92,7 +93,7 @@ transaction_build tx05 nonce 4 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data ba26473500000000000000000000000027444fbce96cb2d27b94e116d1506d7739c05862 - gas 2000000 + gas 1000000 build # set 1000 wei to send for second contract @@ -101,7 +102,7 @@ transaction_build tx06 nonce 5 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data 6efb15df00000000000000000000000000000000000000000000000000000000000003e8 - gas 2000000 + gas 1000000 build # deposit 1000 wei to second contract @@ -110,11 +111,12 @@ transaction_build tx07 nonce 6 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff value 1000 - gas 2000000 + gas 1000000 build block_build b02 parent b01 + gasLimit 7500000 transactions tx04 tx05 tx06 tx07 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase2.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase2.txt index cb2817c9555..79842272f00 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase2.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/subsequentCallWithValueCase2.txt @@ -48,7 +48,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061031d806100206000396000f3fe6080604052600436106100385760003560e01c806318d3af631461003b5780636efb15df14610045578063ba2647351461008057610039565b5b005b6100436100d1565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b810190808035906020019092919050505061029a565b005b34801561008c57600080fd5b506100cf600480360360208110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506102a4565b005b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561012b57610298565b600060015411156101ea5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636001546040518263ffffffff1660e01b81526004016000604051808303818588803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050507fd99f0cfde566379669cb08fdc25d80461af2e181833081dd90ca21eaabfc1f9560405160405180910390a1610297565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561025257600080fd5b505af1158015610266573d6000803e3d6000fd5b505050507fc912088d570658c8656f32ff15e09d77c5d9eb8c4304e077777143ba6225dc8860405160405180910390a15b5b565b8060018190555050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea26469706673582212209458b89f68ed66dc26086396962dad91224bfad1e1711e6151d84b91dfe798c564736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx02 @@ -57,7 +57,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061031d806100206000396000f3fe6080604052600436106100385760003560e01c806318d3af631461003b5780636efb15df14610045578063ba2647351461008057610039565b5b005b6100436100d1565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b810190808035906020019092919050505061029a565b005b34801561008c57600080fd5b506100cf600480360360208110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506102a4565b005b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561012b57610298565b600060015411156101ea5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636001546040518263ffffffff1660e01b81526004016000604051808303818588803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050507fd99f0cfde566379669cb08fdc25d80461af2e181833081dd90ca21eaabfc1f9560405160405180910390a1610297565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561025257600080fd5b505af1158015610266573d6000803e3d6000fd5b505050507fc912088d570658c8656f32ff15e09d77c5d9eb8c4304e077777143ba6225dc8860405160405180910390a15b5b565b8060018190555050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea26469706673582212209458b89f68ed66dc26086396962dad91224bfad1e1711e6151d84b91dfe798c564736f6c63430007030033 - gas 2000000 + gas 1000000 build transaction_build tx03 @@ -66,11 +66,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061031d806100206000396000f3fe6080604052600436106100385760003560e01c806318d3af631461003b5780636efb15df14610045578063ba2647351461008057610039565b5b005b6100436100d1565b005b34801561005157600080fd5b5061007e6004803603602081101561006857600080fd5b810190808035906020019092919050505061029a565b005b34801561008c57600080fd5b506100cf600480360360208110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506102a4565b005b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561012b57610298565b600060015411156101ea5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636001546040518263ffffffff1660e01b81526004016000604051808303818588803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050507fd99f0cfde566379669cb08fdc25d80461af2e181833081dd90ca21eaabfc1f9560405160405180910390a1610297565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318d3af636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561025257600080fd5b505af1158015610266573d6000803e3d6000fd5b505050507fc912088d570658c8656f32ff15e09d77c5d9eb8c4304e077777143ba6225dc8860405160405180910390a15b5b565b8060018190555050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea26469706673582212209458b89f68ed66dc26086396962dad91224bfad1e1711e6151d84b91dfe798c564736f6c63430007030033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 tx02 tx03 build @@ -83,7 +84,7 @@ transaction_build tx04 nonce 3 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad data ba26473500000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 1000000 build # init next address 27444fbce96cb2d27b94e116d1506d7739c05862 @@ -92,7 +93,7 @@ transaction_build tx05 nonce 4 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data ba26473500000000000000000000000027444fbce96cb2d27b94e116d1506d7739c05862 - gas 2000000 + gas 1000000 build # set 1000 wei to send for first contract @@ -101,7 +102,7 @@ transaction_build tx06 nonce 5 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad data 6efb15df00000000000000000000000000000000000000000000000000000000000003e8 - gas 2000000 + gas 1000000 build # deposit 1000 wei to first contract @@ -110,7 +111,7 @@ transaction_build tx07 nonce 6 receiverAddress 6252703f5ba322ec64d3ac45e56241b7d9e481ad value 1000 - gas 2000000 + gas 1000000 build # set 1000 wei to send for second contract @@ -119,7 +120,7 @@ transaction_build tx08 nonce 7 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff data 6efb15df00000000000000000000000000000000000000000000000000000000000003e8 - gas 2000000 + gas 1000000 build # deposit 1000 wei to second contract @@ -128,11 +129,12 @@ transaction_build tx09 nonce 8 receiverAddress 56aa252dd82173789984fa164ee26ce2da9336ff value 1000 - gas 2000000 + gas 1000000 build block_build b02 parent b01 + gasLimit 7500000 transactions tx04 tx05 tx06 tx07 tx08 tx09 build diff --git a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/updateStorage.txt b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/updateStorage.txt index 72317ab1377..31c7106fbab 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/estimateGas/updateStorage.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/estimateGas/updateStorage.txt @@ -27,11 +27,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50610144806100206000396000f3fe60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635e383d21146100515780637b8d56e3146100a0575b600080fd5b34801561005d57600080fd5b5061008a6004803603602081101561007457600080fd5b81019080803590602001909291905050506100e5565b6040518082815260200191505060405180910390f35b3480156100ac57600080fd5b506100e3600480360360408110156100c357600080fd5b8101908080359060200190929190803590602001909291905050506100ff565b005b6000816064811015156100f457fe5b016000915090505481565b8060008360648110151561010f57fe5b0181905550505056fea165627a7a72305820d27e1f1cce816508bdc0611d325d8a6695742256aac16b8ea5b69034d0da31830029 - gas 2000000 + gas 500000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build @@ -48,7 +49,7 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data 7b8d56e30000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002a - gas 6400000 + gas 500000 build transaction_build tx03 @@ -57,13 +58,13 @@ transaction_build tx03 contract tx01 # created in tx01 value 0 data 7b8d56e30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a - gas 6400000 + gas 500000 build block_build b02 parent b01 transactions tx02 tx03 - gasLimit 6800000 + gasLimit 7500000 build block_connect b02 diff --git a/rskj-core/src/test/resources/dsl/eth_module/revert_reason.txt b/rskj-core/src/test/resources/dsl/eth_module/revert_reason.txt index 1a5ac29a8d6..9e745363b81 100644 --- a/rskj-core/src/test/resources/dsl/eth_module/revert_reason.txt +++ b/rskj-core/src/test/resources/dsl/eth_module/revert_reason.txt @@ -30,12 +30,13 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061010f806100206000396000f3fe6080604052600436106039576000357c010000000000000000000000000000000000000000000000000000000090048063d96a094a14603e575b600080fd5b606760048036036020811015605257600080fd5b81019080803590602001909291905050506069565b005b60008111151560e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e656761746976652076616c75652e000000000000000000000000000000000081525060200191505060405180910390fd5b5056fea165627a7a7230582028a98e792c3f36ab792c10a5bd8d5f46b19e22fbc9c43635c77fec5a5858254e0029 - gas 2000000 + gas 500000 build block_build b01 parent g00 transactions tx01 + gasLimit 7500000 build block_connect b01 @@ -51,13 +52,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data d96a094a0000000000000000000000000000000000000000000000000000000000000000 - gas 6400000 + gas 500000 build block_build b02 parent b01 transactions tx02 - gasLimit 6500000 + gasLimit 7500000 build block_connect b02 diff --git a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_does_not_exist.txt b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_does_not_exist.txt index 87bc51d9c0e..0ad9510a9b6 100644 --- a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_does_not_exist.txt +++ b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_does_not_exist.txt @@ -28,11 +28,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061015c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631db2d21f14610046578063a696053f14610090578063d13319c4146100ae575b600080fd5b61004e6100cc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100986100f1565b6040518082815260200191505060405180910390f35b6100b66100f7565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b600080600073f55de706d4277ab783c8505b0f47c1e82648ba1e9050803f91508160018190555081925050509056fea264697066735822122071cdf36b83787a689e547268ef6d896410a3e67433ee452bf2295b5b9b6506dd64736f6c634300060b0033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build @@ -47,13 +48,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b02 parent b01 transactions tx02 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b02 @@ -81,13 +82,13 @@ transaction_build tx03 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b05 parent b04 transactions tx03 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b05 diff --git a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_exists_but_not_contract.txt b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_exists_but_not_contract.txt index ccc6610f84e..d24e699f5c8 100644 --- a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_exists_but_not_contract.txt +++ b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_address_exists_but_not_contract.txt @@ -29,11 +29,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061015c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631db2d21f14610046578063a696053f14610090578063d13319c4146100ae575b600080fd5b61004e6100cc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100986100f1565b6040518082815260200191505060405180910390f35b6100b66100f7565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b600080600073cd2a3d9f938e13cd947ec05abc7fe734df8dd8269050803f91508160018190555081925050509056fea2646970667358221220a6e3e81bfb2357b1b84953afbf2f2154a6967f09e175f68a7061c86dbcf2fc2964736f6c634300060b0033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build @@ -48,13 +49,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b02 parent b01 transactions tx02 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b02 @@ -82,13 +83,13 @@ transaction_build tx03 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b05 parent b04 transactions tx03 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b05 diff --git a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_with_cache_empty_deploy.txt b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_with_cache_empty_deploy.txt index fd3cff0932c..fb7b0bdd5bf 100644 --- a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_with_cache_empty_deploy.txt +++ b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_with_cache_empty_deploy.txt @@ -39,11 +39,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b506101d9806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631db2d21f14610051578063775c300c1461009b578063a696053f146100a5578063d13319c4146100c3575b600080fd5b6100596100e1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100a3610106565b005b6100ad610161565b6040518082815260200191505060405180910390f35b6100cb610167565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600080600080f59150813f9050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806001819055505050565b60015481565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050803f91508160018190555081925050509056fea2646970667358221220eca721e5908cc7ae068ebb47cdea1d0d71dc84902e0df17c516889dbc7d8b5fc64736f6c634300060b0033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build @@ -58,13 +59,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data 775c300c - gas 2000000000 + gas 1000000 build block_build b02 parent b01 transactions tx02 - gasLimit 3000000000 + gasLimit 6800000 build block_connect b02 @@ -79,11 +80,12 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b506101d9806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631db2d21f14610051578063775c300c1461009b578063a696053f146100a5578063d13319c4146100c3575b600080fd5b6100596100e1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100a3610106565b005b6100ad610161565b6040518082815260200191505060405180910390f35b6100cb610167565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600080600080f59150813f9050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806001819055505050565b60015481565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050803f91508160018190555081925050509056fea2646970667358221220eca721e5908cc7ae068ebb47cdea1d0d71dc84902e0df17c516889dbc7d8b5fc64736f6c634300060b0033 - gas 2000000 + gas 1000000 build block_build b03 parent b02 + gasLimit 6800000 transactions tx03 build @@ -93,6 +95,7 @@ assert_best b03 # empty block just to get to the activation block_build b04 parent b03 + gasLimit 6800000 build block_connect b04 @@ -105,13 +108,13 @@ transaction_build tx04 contract tx03 # created in tx01 value 0 data 775c300c - gas 2000000000 + gas 1000000 build block_build b05 parent b04 transactions tx04 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b05 diff --git a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_without_cache_empty_deploy.txt b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_without_cache_empty_deploy.txt index f20efd3e309..5c87b8b3121 100644 --- a/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_without_cache_empty_deploy.txt +++ b/rskj-core/src/test/resources/dsl/extcodehash/extcodehash_without_cache_empty_deploy.txt @@ -39,11 +39,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b506101d9806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631db2d21f14610051578063775c300c1461009b578063a696053f146100a5578063d13319c4146100c3575b600080fd5b6100596100e1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100a3610106565b005b6100ad610161565b6040518082815260200191505060405180910390f35b6100cb610167565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600080600080f59150813f9050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806001819055505050565b60015481565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050803f91508160018190555081925050509056fea2646970667358221220eca721e5908cc7ae068ebb47cdea1d0d71dc84902e0df17c516889dbc7d8b5fc64736f6c634300060b0033 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 6800000 transactions tx01 build @@ -58,13 +59,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data 775c300c - gas 2000000000 + gas 1000000 build block_build b02 parent b01 transactions tx02 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b02 @@ -78,13 +79,13 @@ transaction_build tx03 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b03 parent b02 transactions tx03 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b03 @@ -99,13 +100,13 @@ transaction_build tx04 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b04 parent b03 transactions tx04 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b04 @@ -118,13 +119,13 @@ transaction_build tx05 contract tx01 # created in tx01 value 0 data d13319c4 - gas 2000000000 + gas 1000000 build block_build b05 parent b04 transactions tx05 - gasLimit 3000000000 + gasLimit 30000000 build block_connect b05 diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt index a6f1a5d63c6..947eca67428 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50610cde806100206000396000f3fe6080604052600436106200002c5760003560e01c8063490af4231462000031578063fdaaa16f1462000067575b600080fd5b6200004f6004803603810190620000499190620002c1565b620000ab565b6040516200005e919062000357565b60405180910390f35b3480156200007457600080fd5b506200009360048036038101906200008d9190620002c1565b620000fb565b604051620000a2919062000357565b60405180910390f35b600080600160001b90508083604051620000c5906200013d565b620000d19190620003fd565b8190604051809103906000f5905080158015620000f2573d6000803e3d6000fd5b50915050919050565b6000816040516200010c906200013d565b620001189190620003fd565b604051809103906000f08015801562000135573d6000803e3d6000fd5b509050919050565b610887806200042283390190565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620001b48262000169565b810181811067ffffffffffffffff82111715620001d657620001d56200017a565b5b80604052505050565b6000620001eb6200014b565b9050620001f98282620001a9565b919050565b600067ffffffffffffffff8211156200021c576200021b6200017a565b5b620002278262000169565b9050602081019050919050565b82818337600083830152505050565b60006200025a6200025484620001fe565b620001df565b90508281526020810184848401111562000279576200027862000164565b5b6200028684828562000234565b509392505050565b600082601f830112620002a657620002a56200015f565b5b8135620002b884826020860162000243565b91505092915050565b600060208284031215620002da57620002d962000155565b5b600082013567ffffffffffffffff811115620002fb57620002fa6200015a565b5b62000309848285016200028e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200033f8262000312565b9050919050565b620003518162000332565b82525050565b60006020820190506200036e600083018462000346565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015620003b057808201518184015260208101905062000393565b60008484015250505050565b6000620003c98262000374565b620003d581856200037f565b9350620003e781856020860162000390565b620003f28162000169565b840191505092915050565b60006020820190508181036000830152620004198184620003bc565b90509291505056fe60806040523480156200001157600080fd5b506040516200088738038062000887833981810160405281019062000037919062000223565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019081620000889190620004bf565b5050620005a6565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000f982620000ae565b810181811067ffffffffffffffff821117156200011b576200011a620000bf565b5b80604052505050565b60006200013062000090565b90506200013e8282620000ee565b919050565b600067ffffffffffffffff821115620001615762000160620000bf565b5b6200016c82620000ae565b9050602081019050919050565b60005b83811015620001995780820151818401526020810190506200017c565b60008484015250505050565b6000620001bc620001b68462000143565b62000124565b905082815260208101848484011115620001db57620001da620000a9565b5b620001e884828562000179565b509392505050565b600082601f830112620002085762000207620000a4565b5b81516200021a848260208601620001a5565b91505092915050565b6000602082840312156200023c576200023b6200009a565b5b600082015167ffffffffffffffff8111156200025d576200025c6200009f565b5b6200026b84828501620001f0565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002c757607f821691505b602082108103620002dd57620002dc6200027f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000308565b62000353868362000308565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003a06200039a62000394846200036b565b62000375565b6200036b565b9050919050565b6000819050919050565b620003bc836200037f565b620003d4620003cb82620003a7565b84845462000315565b825550505050565b600090565b620003eb620003dc565b620003f8818484620003b1565b505050565b5b81811015620004205762000414600082620003e1565b600181019050620003fe565b5050565b601f8211156200046f576200043981620002e3565b6200044484620002f8565b8101602085101562000454578190505b6200046c6200046385620002f8565b830182620003fd565b50505b505050565b600082821c905092915050565b6000620004946000198460080262000474565b1980831691505092915050565b6000620004af838362000481565b9150826002028217905092915050565b620004ca8262000274565b67ffffffffffffffff811115620004e657620004e5620000bf565b5b620004f28254620002ae565b620004ff82828562000424565b600060209050601f83116001811462000537576000841562000522578287015190505b6200052e8582620004a1565b8655506200059e565b601f1984166200054786620002e3565b60005b8281101562000571578489015182556001820191506020850194506020810190506200054a565b868310156200059157848901516200058d601f89168262000481565b8355505b6001600288020188555050505b505050505050565b6102d180620005b66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122071163cf749253f921b29799fb8f2b856a099dcdc627d7622ee7536e5e392509464736f6c63430008180033a2646970667358221220bd9fa3c126989a1d6a7a7fe44541a0bf9a4b43a3d2e12733f1208d6beaf0ede564736f6c63430008180033 - gas 6500000 + gas 800000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -69,7 +68,7 @@ transaction_build txCreateContractViaOpCodeCreate2 block_build b02 parent b01 - gasLimit 10000000 + gasLimit 30000000 transactions txCreateContractViaOpCodeCreate2 build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_fail_with_RSKIP_activated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_fail_with_RSKIP_activated.txt index 26e56ea6c64..852c650dceb 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_fail_with_RSKIP_activated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_fail_with_RSKIP_activated.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50610cde806100206000396000f3fe6080604052600436106200002c5760003560e01c8063490af4231462000031578063fdaaa16f1462000067575b600080fd5b6200004f6004803603810190620000499190620002c1565b620000ab565b6040516200005e919062000357565b60405180910390f35b3480156200007457600080fd5b506200009360048036038101906200008d9190620002c1565b620000fb565b604051620000a2919062000357565b60405180910390f35b600080600160001b90508083604051620000c5906200013d565b620000d19190620003fd565b8190604051809103906000f5905080158015620000f2573d6000803e3d6000fd5b50915050919050565b6000816040516200010c906200013d565b620001189190620003fd565b604051809103906000f08015801562000135573d6000803e3d6000fd5b509050919050565b610887806200042283390190565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620001b48262000169565b810181811067ffffffffffffffff82111715620001d657620001d56200017a565b5b80604052505050565b6000620001eb6200014b565b9050620001f98282620001a9565b919050565b600067ffffffffffffffff8211156200021c576200021b6200017a565b5b620002278262000169565b9050602081019050919050565b82818337600083830152505050565b60006200025a6200025484620001fe565b620001df565b90508281526020810184848401111562000279576200027862000164565b5b6200028684828562000234565b509392505050565b600082601f830112620002a657620002a56200015f565b5b8135620002b884826020860162000243565b91505092915050565b600060208284031215620002da57620002d962000155565b5b600082013567ffffffffffffffff811115620002fb57620002fa6200015a565b5b62000309848285016200028e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200033f8262000312565b9050919050565b620003518162000332565b82525050565b60006020820190506200036e600083018462000346565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015620003b057808201518184015260208101905062000393565b60008484015250505050565b6000620003c98262000374565b620003d581856200037f565b9350620003e781856020860162000390565b620003f28162000169565b840191505092915050565b60006020820190508181036000830152620004198184620003bc565b90509291505056fe60806040523480156200001157600080fd5b506040516200088738038062000887833981810160405281019062000037919062000223565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019081620000889190620004bf565b5050620005a6565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000f982620000ae565b810181811067ffffffffffffffff821117156200011b576200011a620000bf565b5b80604052505050565b60006200013062000090565b90506200013e8282620000ee565b919050565b600067ffffffffffffffff821115620001615762000160620000bf565b5b6200016c82620000ae565b9050602081019050919050565b60005b83811015620001995780820151818401526020810190506200017c565b60008484015250505050565b6000620001bc620001b68462000143565b62000124565b905082815260208101848484011115620001db57620001da620000a9565b5b620001e884828562000179565b509392505050565b600082601f830112620002085762000207620000a4565b5b81516200021a848260208601620001a5565b91505092915050565b6000602082840312156200023c576200023b6200009a565b5b600082015167ffffffffffffffff8111156200025d576200025c6200009f565b5b6200026b84828501620001f0565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002c757607f821691505b602082108103620002dd57620002dc6200027f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000308565b62000353868362000308565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003a06200039a62000394846200036b565b62000375565b6200036b565b9050919050565b6000819050919050565b620003bc836200037f565b620003d4620003cb82620003a7565b84845462000315565b825550505050565b600090565b620003eb620003dc565b620003f8818484620003b1565b505050565b5b81811015620004205762000414600082620003e1565b600181019050620003fe565b5050565b601f8211156200046f576200043981620002e3565b6200044484620002f8565b8101602085101562000454578190505b6200046c6200046385620002f8565b830182620003fd565b50505b505050565b600082821c905092915050565b6000620004946000198460080262000474565b1980831691505092915050565b6000620004af838362000481565b9150826002028217905092915050565b620004ca8262000274565b67ffffffffffffffff811115620004e657620004e5620000bf565b5b620004f28254620002ae565b620004ff82828562000424565b600060209050601f83116001811462000537576000841562000522578287015190505b6200052e8582620004a1565b8655506200059e565b601f1984166200054786620002e3565b60005b8281101562000571578489015182556001820191506020850194506020810190506200054a565b868310156200059157848901516200058d601f89168262000481565b8355505b6001600288020188555050505b505050505050565b6102d180620005b66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122071163cf749253f921b29799fb8f2b856a099dcdc627d7622ee7536e5e392509464736f6c63430008180033a2646970667358221220bd9fa3c126989a1d6a7a7fe44541a0bf9a4b43a3d2e12733f1208d6beaf0ede564736f6c63430008180033 - gas 6500000 + gas 800000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -64,12 +63,11 @@ transaction_build txCreateContractViaOpCodeCreate2 contract txCreateContractFactory # created in txCreateContractFactory value 0 data 490af4230000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000b7bd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 - gas 6500000 + gas 600000 build block_build b02 parent b01 - gasLimit 6500000 transactions txCreateContractViaOpCodeCreate2 build @@ -79,4 +77,4 @@ block_connect b02 assert_best b02 # Assert balance after have created the contract via opcode create2 -assert_balance acc1 12739631 \ No newline at end of file +assert_balance acc1 18639631 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_with_initcode_cost.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_with_initcode_cost.txt index 1c4e524a778..e1411dc0544 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_with_initcode_cost.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_with_initcode_cost.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061081b806100206000396000f3fe6080604052600436106100295760003560e01c806313a0432e1461002e5780635d828e9a1461004c575b600080fd5b610036610077565b6040516100439190610133565b60405180910390f35b34801561005857600080fd5b506100616100b5565b60405161006e9190610133565b60405180910390f35b600080600160001b90508060405161008e906100e5565b8190604051809103906000f59050801580156100ae573d6000803e3d6000fd5b5091505090565b60006040516100c3906100e5565b604051809103906000f0801580156100df573d6000803e3d6000fd5b50905090565b6106978061014f83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061011d826100f2565b9050919050565b61012d81610112565b82525050565b60006020820190506101486000830184610124565b9291505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600781526020017901000000000000000000000000000000000000000000000000008152506001908161008f91906102e5565b506103b7565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061011657607f821691505b602082108103610129576101286100cf565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026101917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610154565b61019b8683610154565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006101e26101dd6101d8846101b3565b6101bd565b6101b3565b9050919050565b6000819050919050565b6101fc836101c7565b610210610208826101e9565b848454610161565b825550505050565b600090565b610225610218565b6102308184846101f3565b505050565b5b818110156102545761024960008261021d565b600181019050610236565b5050565b601f8211156102995761026a8161012f565b61027384610144565b81016020851015610282578190505b61029661028e85610144565b830182610235565b50505b505050565b600082821c905092915050565b60006102bc6000198460080261029e565b1980831691505092915050565b60006102d583836102ab565b9150826002028217905092915050565b6102ee82610095565b67ffffffffffffffff811115610307576103066100a0565b5b61031182546100fe565b61031c828285610258565b600060209050601f83116001811461034f576000841561033d578287015190505b61034785826102c9565b8655506103af565b601f19841661035d8661012f565b60005b8281101561038557848901518255600182019150602085019450602081019050610360565b868310156103a2578489015161039e601f8916826102ab565b8355505b6001600288020188555050505b505050505050565b6102d1806103c66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122049d311e90db3a44f73eb3cf557d8a87356f3317e1459eda82ef2a687d7a18b3a64736f6c63430008180033a26469706673582212202aef06f0c7e6b0968848c66b5849bb66c58dda606e71a6ad568f4ab402c878bd64736f6c63430008180033 - gas 4700000 + gas 600000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -64,12 +63,11 @@ transaction_build txCreateContractViaOpCodeCreate2 contract txCreateContractFactory # created in txCreateContractFactory value 0 data 13a0432e - gas 1000000 + gas 600000 build block_build b02 parent b01 - gasLimit 6500000 transactions txCreateContractViaOpCodeCreate2 build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_without_initcode_cost.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_without_initcode_cost.txt index e775e285b4c..ee380040af1 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_without_initcode_cost.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE2_opcode_validation_success_without_initcode_cost.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061081b806100206000396000f3fe6080604052600436106100295760003560e01c806313a0432e1461002e5780635d828e9a1461004c575b600080fd5b610036610077565b6040516100439190610133565b60405180910390f35b34801561005857600080fd5b506100616100b5565b60405161006e9190610133565b60405180910390f35b600080600160001b90508060405161008e906100e5565b8190604051809103906000f59050801580156100ae573d6000803e3d6000fd5b5091505090565b60006040516100c3906100e5565b604051809103906000f0801580156100df573d6000803e3d6000fd5b50905090565b6106978061014f83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061011d826100f2565b9050919050565b61012d81610112565b82525050565b60006020820190506101486000830184610124565b9291505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600781526020017901000000000000000000000000000000000000000000000000008152506001908161008f91906102e5565b506103b7565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061011657607f821691505b602082108103610129576101286100cf565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026101917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610154565b61019b8683610154565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006101e26101dd6101d8846101b3565b6101bd565b6101b3565b9050919050565b6000819050919050565b6101fc836101c7565b610210610208826101e9565b848454610161565b825550505050565b600090565b610225610218565b6102308184846101f3565b505050565b5b818110156102545761024960008261021d565b600181019050610236565b5050565b601f8211156102995761026a8161012f565b61027384610144565b81016020851015610282578190505b61029661028e85610144565b830182610235565b50505b505050565b600082821c905092915050565b60006102bc6000198460080261029e565b1980831691505092915050565b60006102d583836102ab565b9150826002028217905092915050565b6102ee82610095565b67ffffffffffffffff811115610307576103066100a0565b5b61031182546100fe565b61031c828285610258565b600060209050601f83116001811461034f576000841561033d578287015190505b61034785826102c9565b8655506103af565b601f19841661035d8661012f565b60005b8281101561038557848901518255600182019150602085019450602081019050610360565b868310156103a2578489015161039e601f8916826102ab565b8355505b6001600288020188555050505b505050505050565b6102d1806103c66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122049d311e90db3a44f73eb3cf557d8a87356f3317e1459eda82ef2a687d7a18b3a64736f6c63430008180033a26469706673582212202aef06f0c7e6b0968848c66b5849bb66c58dda606e71a6ad568f4ab402c878bd64736f6c63430008180033 - gas 4700000 + gas 600000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -64,12 +63,11 @@ transaction_build txCreateContractViaOpCodeCreate2 contract txCreateContractFactory # created in txCreateContractFactory value 0 data 13a0432e - gas 1000000 + gas 600000 build block_build b02 parent b01 - gasLimit 6500000 transactions txCreateContractViaOpCodeCreate2 build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt index f8e0c54db8a..34ee3daa399 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_doesnt_fail_with_RSKIP_deactivated.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50610cde806100206000396000f3fe6080604052600436106200002c5760003560e01c8063490af4231462000031578063fdaaa16f1462000067575b600080fd5b6200004f6004803603810190620000499190620002c1565b620000ab565b6040516200005e919062000357565b60405180910390f35b3480156200007457600080fd5b506200009360048036038101906200008d9190620002c1565b620000fb565b604051620000a2919062000357565b60405180910390f35b600080600160001b90508083604051620000c5906200013d565b620000d19190620003fd565b8190604051809103906000f5905080158015620000f2573d6000803e3d6000fd5b50915050919050565b6000816040516200010c906200013d565b620001189190620003fd565b604051809103906000f08015801562000135573d6000803e3d6000fd5b509050919050565b610887806200042283390190565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620001b48262000169565b810181811067ffffffffffffffff82111715620001d657620001d56200017a565b5b80604052505050565b6000620001eb6200014b565b9050620001f98282620001a9565b919050565b600067ffffffffffffffff8211156200021c576200021b6200017a565b5b620002278262000169565b9050602081019050919050565b82818337600083830152505050565b60006200025a6200025484620001fe565b620001df565b90508281526020810184848401111562000279576200027862000164565b5b6200028684828562000234565b509392505050565b600082601f830112620002a657620002a56200015f565b5b8135620002b884826020860162000243565b91505092915050565b600060208284031215620002da57620002d962000155565b5b600082013567ffffffffffffffff811115620002fb57620002fa6200015a565b5b62000309848285016200028e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200033f8262000312565b9050919050565b620003518162000332565b82525050565b60006020820190506200036e600083018462000346565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015620003b057808201518184015260208101905062000393565b60008484015250505050565b6000620003c98262000374565b620003d581856200037f565b9350620003e781856020860162000390565b620003f28162000169565b840191505092915050565b60006020820190508181036000830152620004198184620003bc565b90509291505056fe60806040523480156200001157600080fd5b506040516200088738038062000887833981810160405281019062000037919062000223565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019081620000889190620004bf565b5050620005a6565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000f982620000ae565b810181811067ffffffffffffffff821117156200011b576200011a620000bf565b5b80604052505050565b60006200013062000090565b90506200013e8282620000ee565b919050565b600067ffffffffffffffff821115620001615762000160620000bf565b5b6200016c82620000ae565b9050602081019050919050565b60005b83811015620001995780820151818401526020810190506200017c565b60008484015250505050565b6000620001bc620001b68462000143565b62000124565b905082815260208101848484011115620001db57620001da620000a9565b5b620001e884828562000179565b509392505050565b600082601f830112620002085762000207620000a4565b5b81516200021a848260208601620001a5565b91505092915050565b6000602082840312156200023c576200023b6200009a565b5b600082015167ffffffffffffffff8111156200025d576200025c6200009f565b5b6200026b84828501620001f0565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002c757607f821691505b602082108103620002dd57620002dc6200027f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000308565b62000353868362000308565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003a06200039a62000394846200036b565b62000375565b6200036b565b9050919050565b6000819050919050565b620003bc836200037f565b620003d4620003cb82620003a7565b84845462000315565b825550505050565b600090565b620003eb620003dc565b620003f8818484620003b1565b505050565b5b81811015620004205762000414600082620003e1565b600181019050620003fe565b5050565b601f8211156200046f576200043981620002e3565b6200044484620002f8565b8101602085101562000454578190505b6200046c6200046385620002f8565b830182620003fd565b50505b505050565b600082821c905092915050565b6000620004946000198460080262000474565b1980831691505092915050565b6000620004af838362000481565b9150826002028217905092915050565b620004ca8262000274565b67ffffffffffffffff811115620004e657620004e5620000bf565b5b620004f28254620002ae565b620004ff82828562000424565b600060209050601f83116001811462000537576000841562000522578287015190505b6200052e8582620004a1565b8655506200059e565b601f1984166200054786620002e3565b60005b8281101562000571578489015182556001820191506020850194506020810190506200054a565b868310156200059157848901516200058d601f89168262000481565b8355505b6001600288020188555050505b505050505050565b6102d180620005b66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122071163cf749253f921b29799fb8f2b856a099dcdc627d7622ee7536e5e392509464736f6c63430008180033a2646970667358221220bd9fa3c126989a1d6a7a7fe44541a0bf9a4b43a3d2e12733f1208d6beaf0ede564736f6c63430008180033 - gas 7500000 + gas 800000 build block_build b01 parent g00 - gasLimit 7500000 transactions txCreateContractFactory build @@ -69,7 +68,7 @@ transaction_build txCreateContractViaOpCodeCreate block_build b02 parent b01 - gasLimit 10000000 + gasLimit 30000000 transactions txCreateContractViaOpCodeCreate build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_fail_with_RSKIP_activated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_fail_with_RSKIP_activated.txt index b89dc32aa78..adfed8b06c0 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_fail_with_RSKIP_activated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_fail_with_RSKIP_activated.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b50610cde806100206000396000f3fe6080604052600436106200002c5760003560e01c8063490af4231462000031578063fdaaa16f1462000067575b600080fd5b6200004f6004803603810190620000499190620002c1565b620000ab565b6040516200005e919062000357565b60405180910390f35b3480156200007457600080fd5b506200009360048036038101906200008d9190620002c1565b620000fb565b604051620000a2919062000357565b60405180910390f35b600080600160001b90508083604051620000c5906200013d565b620000d19190620003fd565b8190604051809103906000f5905080158015620000f2573d6000803e3d6000fd5b50915050919050565b6000816040516200010c906200013d565b620001189190620003fd565b604051809103906000f08015801562000135573d6000803e3d6000fd5b509050919050565b610887806200042283390190565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620001b48262000169565b810181811067ffffffffffffffff82111715620001d657620001d56200017a565b5b80604052505050565b6000620001eb6200014b565b9050620001f98282620001a9565b919050565b600067ffffffffffffffff8211156200021c576200021b6200017a565b5b620002278262000169565b9050602081019050919050565b82818337600083830152505050565b60006200025a6200025484620001fe565b620001df565b90508281526020810184848401111562000279576200027862000164565b5b6200028684828562000234565b509392505050565b600082601f830112620002a657620002a56200015f565b5b8135620002b884826020860162000243565b91505092915050565b600060208284031215620002da57620002d962000155565b5b600082013567ffffffffffffffff811115620002fb57620002fa6200015a565b5b62000309848285016200028e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200033f8262000312565b9050919050565b620003518162000332565b82525050565b60006020820190506200036e600083018462000346565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015620003b057808201518184015260208101905062000393565b60008484015250505050565b6000620003c98262000374565b620003d581856200037f565b9350620003e781856020860162000390565b620003f28162000169565b840191505092915050565b60006020820190508181036000830152620004198184620003bc565b90509291505056fe60806040523480156200001157600080fd5b506040516200088738038062000887833981810160405281019062000037919062000223565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019081620000889190620004bf565b5050620005a6565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000f982620000ae565b810181811067ffffffffffffffff821117156200011b576200011a620000bf565b5b80604052505050565b60006200013062000090565b90506200013e8282620000ee565b919050565b600067ffffffffffffffff821115620001615762000160620000bf565b5b6200016c82620000ae565b9050602081019050919050565b60005b83811015620001995780820151818401526020810190506200017c565b60008484015250505050565b6000620001bc620001b68462000143565b62000124565b905082815260208101848484011115620001db57620001da620000a9565b5b620001e884828562000179565b509392505050565b600082601f830112620002085762000207620000a4565b5b81516200021a848260208601620001a5565b91505092915050565b6000602082840312156200023c576200023b6200009a565b5b600082015167ffffffffffffffff8111156200025d576200025c6200009f565b5b6200026b84828501620001f0565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002c757607f821691505b602082108103620002dd57620002dc6200027f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000308565b62000353868362000308565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003a06200039a62000394846200036b565b62000375565b6200036b565b9050919050565b6000819050919050565b620003bc836200037f565b620003d4620003cb82620003a7565b84845462000315565b825550505050565b600090565b620003eb620003dc565b620003f8818484620003b1565b505050565b5b81811015620004205762000414600082620003e1565b600181019050620003fe565b5050565b601f8211156200046f576200043981620002e3565b6200044484620002f8565b8101602085101562000454578190505b6200046c6200046385620002f8565b830182620003fd565b50505b505050565b600082821c905092915050565b6000620004946000198460080262000474565b1980831691505092915050565b6000620004af838362000481565b9150826002028217905092915050565b620004ca8262000274565b67ffffffffffffffff811115620004e657620004e5620000bf565b5b620004f28254620002ae565b620004ff82828562000424565b600060209050601f83116001811462000537576000841562000522578287015190505b6200052e8582620004a1565b8655506200059e565b601f1984166200054786620002e3565b60005b8281101562000571578489015182556001820191506020850194506020810190506200054a565b868310156200059157848901516200058d601f89168262000481565b8355505b6001600288020188555050505b505050505050565b6102d180620005b66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122071163cf749253f921b29799fb8f2b856a099dcdc627d7622ee7536e5e392509464736f6c63430008180033a2646970667358221220bd9fa3c126989a1d6a7a7fe44541a0bf9a4b43a3d2e12733f1208d6beaf0ede564736f6c63430008180033 - gas 6500000 + gas 800000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -64,12 +63,11 @@ transaction_build txCreateContractViaOpCodeCreate contract txCreateContractFactory # created in txCreateContractFactory value 0 data fdaaa16f0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000b7bd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 - gas 6500000 + gas 600000 build block_build b02 parent b01 - gasLimit 6500000 transactions txCreateContractViaOpCodeCreate build @@ -79,4 +77,4 @@ block_connect b02 assert_best b02 # Assert balance after have created the contract via opcode create -assert_balance acc1 12739631 \ No newline at end of file +assert_balance acc1 18639631 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_with_initcode_cost.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_with_initcode_cost.txt index 25e0987b277..f21c5794fe3 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_with_initcode_cost.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_with_initcode_cost.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061081b806100206000396000f3fe6080604052600436106100295760003560e01c806313a0432e1461002e5780635d828e9a1461004c575b600080fd5b610036610077565b6040516100439190610133565b60405180910390f35b34801561005857600080fd5b506100616100b5565b60405161006e9190610133565b60405180910390f35b600080600160001b90508060405161008e906100e5565b8190604051809103906000f59050801580156100ae573d6000803e3d6000fd5b5091505090565b60006040516100c3906100e5565b604051809103906000f0801580156100df573d6000803e3d6000fd5b50905090565b6106978061014f83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061011d826100f2565b9050919050565b61012d81610112565b82525050565b60006020820190506101486000830184610124565b9291505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600781526020017901000000000000000000000000000000000000000000000000008152506001908161008f91906102e5565b506103b7565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061011657607f821691505b602082108103610129576101286100cf565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026101917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610154565b61019b8683610154565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006101e26101dd6101d8846101b3565b6101bd565b6101b3565b9050919050565b6000819050919050565b6101fc836101c7565b610210610208826101e9565b848454610161565b825550505050565b600090565b610225610218565b6102308184846101f3565b505050565b5b818110156102545761024960008261021d565b600181019050610236565b5050565b601f8211156102995761026a8161012f565b61027384610144565b81016020851015610282578190505b61029661028e85610144565b830182610235565b50505b505050565b600082821c905092915050565b60006102bc6000198460080261029e565b1980831691505092915050565b60006102d583836102ab565b9150826002028217905092915050565b6102ee82610095565b67ffffffffffffffff811115610307576103066100a0565b5b61031182546100fe565b61031c828285610258565b600060209050601f83116001811461034f576000841561033d578287015190505b61034785826102c9565b8655506103af565b601f19841661035d8661012f565b60005b8281101561038557848901518255600182019150602085019450602081019050610360565b868310156103a2578489015161039e601f8916826102ab565b8355505b6001600288020188555050505b505050505050565b6102d1806103c66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122049d311e90db3a44f73eb3cf557d8a87356f3317e1459eda82ef2a687d7a18b3a64736f6c63430008180033a26469706673582212202aef06f0c7e6b0968848c66b5849bb66c58dda606e71a6ad568f4ab402c878bd64736f6c63430008180033 - gas 4700000 + gas 600000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -64,12 +63,11 @@ transaction_build txCreateContractViaOpCode contract txCreateContractFactory # created in txCreateContractFactory value 0 data 5d828e9a - gas 1000000 + gas 600000 build block_build b02 parent b01 - gasLimit 6500000 transactions txCreateContractViaOpCode build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_without_initcode_cost.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_without_initcode_cost.txt index 64afce4caba..c5c14d1221c 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_without_initcode_cost.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/CREATE_opcode_validation_success_without_initcode_cost.txt @@ -40,12 +40,11 @@ transaction_build txCreateContractFactory receiverAddress 00 value 0 data 608060405234801561001057600080fd5b5061081b806100206000396000f3fe6080604052600436106100295760003560e01c806313a0432e1461002e5780635d828e9a1461004c575b600080fd5b610036610077565b6040516100439190610133565b60405180910390f35b34801561005857600080fd5b506100616100b5565b60405161006e9190610133565b60405180910390f35b600080600160001b90508060405161008e906100e5565b8190604051809103906000f59050801580156100ae573d6000803e3d6000fd5b5091505090565b60006040516100c3906100e5565b604051809103906000f0801580156100df573d6000803e3d6000fd5b50905090565b6106978061014f83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061011d826100f2565b9050919050565b61012d81610112565b82525050565b60006020820190506101486000830184610124565b9291505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600781526020017901000000000000000000000000000000000000000000000000008152506001908161008f91906102e5565b506103b7565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061011657607f821691505b602082108103610129576101286100cf565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026101917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610154565b61019b8683610154565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006101e26101dd6101d8846101b3565b6101bd565b6101b3565b9050919050565b6000819050919050565b6101fc836101c7565b610210610208826101e9565b848454610161565b825550505050565b600090565b610225610218565b6102308184846101f3565b505050565b5b818110156102545761024960008261021d565b600181019050610236565b5050565b601f8211156102995761026a8161012f565b61027384610144565b81016020851015610282578190505b61029661028e85610144565b830182610235565b50505b505050565b600082821c905092915050565b60006102bc6000198460080261029e565b1980831691505092915050565b60006102d583836102ab565b9150826002028217905092915050565b6102ee82610095565b67ffffffffffffffff811115610307576103066100a0565b5b61031182546100fe565b61031c828285610258565b600060209050601f83116001811461034f576000841561033d578287015190505b61034785826102c9565b8655506103af565b601f19841661035d8661012f565b60005b8281101561038557848901518255600182019150602085019450602081019050610360565b868310156103a2578489015161039e601f8916826102ab565b8355505b6001600288020188555050505b505050505050565b6102d1806103c66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b5780638da5cb5b14610059575b600080fd5b610043610077565b60405161005091906101bd565b60405180910390f35b610061610109565b60405161006e9190610220565b60405180910390f35b6060600180546100869061026a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b29061026a565b80156100ff5780601f106100d4576101008083540402835291602001916100ff565b820191906000526020600020905b8154815290600101906020018083116100e257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600081519050919050565b600082825260208201905092915050565b60005b8381101561016757808201518184015260208101905061014c565b60008484015250505050565b6000601f19601f8301169050919050565b600061018f8261012d565b6101998185610138565b93506101a9818560208601610149565b6101b281610173565b840191505092915050565b600060208201905081810360008301526101d78184610184565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061020a826101df565b9050919050565b61021a816101ff565b82525050565b60006020820190506102356000830184610211565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061028257607f821691505b6020821081036102955761029461023b565b5b5091905056fea264697066735822122049d311e90db3a44f73eb3cf557d8a87356f3317e1459eda82ef2a687d7a18b3a64736f6c63430008180033a26469706673582212202aef06f0c7e6b0968848c66b5849bb66c58dda606e71a6ad568f4ab402c878bd64736f6c63430008180033 - gas 4700000 + gas 600000 build block_build b01 parent g00 - gasLimit 6500000 transactions txCreateContractFactory build @@ -64,12 +63,11 @@ transaction_build txCreateContractViaOpCodeCreate contract txCreateContractFactory # created in txCreateContractFactory value 0 data 5d828e9a - gas 1000000 + gas 600000 build block_build b02 parent b01 - gasLimit 6500000 transactions txCreateContractViaOpCodeCreate build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_doesnt_fails_due_not_enough_gas_with_rskip_deactivated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_doesnt_fails_due_not_enough_gas_with_rskip_deactivated.txt index 828794eb76f..88b426499de 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_doesnt_fails_due_not_enough_gas_with_rskip_deactivated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_doesnt_fails_due_not_enough_gas_with_rskip_deactivated.txt @@ -32,7 +32,7 @@ transaction_build txCreateContract block_build b01 parent g00 - gasLimit 6500000 + gasLimit 15000000 transactions txCreateContract build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_activated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_activated.txt index caa4dde29e5..8b1b8330446 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_activated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_activated.txt @@ -32,7 +32,7 @@ transaction_build txCreateContract block_build b01 parent g00 - gasLimit 6500000 + gasLimit 15000000 transactions txCreateContract build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated.txt index a244da6d7c5..94a5b270041 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated.txt @@ -32,7 +32,7 @@ transaction_build txCreateContract block_build b01 parent g00 - gasLimit 6500000 + gasLimit 15000000 transactions txCreateContract build diff --git a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated_with_initcode_size_max_reached.txt b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated_with_initcode_size_max_reached.txt index 826b18d09eb..20b4e32f8e4 100644 --- a/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated_with_initcode_size_max_reached.txt +++ b/rskj-core/src/test/resources/dsl/initcode_size_rskip438/tx_creation_validation_success_with_rskip_deactivated_with_initcode_size_max_reached.txt @@ -32,7 +32,7 @@ transaction_build txCreateContract block_build b01 parent g00 - gasLimit 30000000 + gasLimit 90000000 transactions txCreateContract build diff --git a/rskj-core/src/test/resources/dsl/logs01.txt b/rskj-core/src/test/resources/dsl/logs01.txt index fe2df498ab9..5d47d8db641 100644 --- a/rskj-core/src/test/resources/dsl/logs01.txt +++ b/rskj-core/src/test/resources/dsl/logs01.txt @@ -8,11 +8,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 6060604052341561000f57600080fd5b5b610018610151565b604051809103906000f080151561002e57600080fd5b6000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f80ae3ec8027d0c5d1f3e47fb4bf1d9fc28225e7f4bcb1971b36efb81fe40574d6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663209652556000604051602001526040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561011b57600080fd5b6102c65a03f1151561012c57600080fd5b505050604051805190506040518082815260200191505060405180910390a15b610161565b6040516101b8806101a583390190565b60368061016f6000396000f30060606040525b600080fd00a165627a7a7230582009dde7c398f78ed62145cdd71de22468ae180f49faf182761851a96e601e785600296060604052341561000f57600080fd5b5b60466000819055507f06acbfb32bcf8383f3b0a768b70ac9ec234ea0f2d3b9c77fa6a2de69b919aad16000546040518082815260200191505060405180910390a15b5b610156806100626000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632096525514610049578063d09de08a14610072575b600080fd5b341561005457600080fd5b61005c610087565b6040518082815260200191505060405180910390f35b341561007d57600080fd5b6100856100cb565b005b60007f1ee041944547858a75ebef916083b6d4f5ae04bea9cd809334469dd07dbf441b6000546040518082815260200191505060405180910390a160005490505b90565b600080815460010191905081905550600160026000548115156100ea57fe5b061415157f6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad6000546040518082815260200191505060405180910390a25b5600a165627a7a7230582038120cf814b0bf518df643fa226e3c7323c39ac92e8d558d548537ec43a152b10029 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build diff --git a/rskj-core/src/test/resources/dsl/nested_environment_calls.txt b/rskj-core/src/test/resources/dsl/nested_environment_calls.txt index 2d6ac2b6c9d..bd81b8ec273 100644 --- a/rskj-core/src/test/resources/dsl/nested_environment_calls.txt +++ b/rskj-core/src/test/resources/dsl/nested_environment_calls.txt @@ -64,7 +64,7 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405263010000116000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561005457600080fd5b506102d3806100646000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636ead0b3314610030575b600080fd5b61003861004e565b604051610045919061019c565b60405180910390f35b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527fe8ce2274000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161011b9190610228565b6000604051808303816000865af19150503d8060008114610158576040519150601f19603f3d011682016040523d82523d6000602084013e61015d565b606091505b50915091506000818060200190518101906101789190610270565b905080935050505090565b6000819050919050565b61019681610183565b82525050565b60006020820190506101b1600083018461018d565b92915050565b600081519050919050565b600081905092915050565b60005b838110156101eb5780820151818401526020810190506101d0565b60008484015250505050565b6000610202826101b7565b61020c81856101c2565b935061021c8185602086016101cd565b80840191505092915050565b600061023482846101f7565b915081905092915050565b600080fd5b61024d81610183565b811461025857600080fd5b50565b60008151905061026a81610244565b92915050565b6000602082840312156102865761028561023f565b5b60006102948482850161025b565b9150509291505056fea2646970667358221220c12e258eb9996e6b57889014c9e757277bda37a4d213412a7a743df2d933d78264736f6c63430008130033 - gas 2000000 + gas 300000 build # Deploy CallStackDepthCallerB (address: 56aa252dd82173789984fa164ee26ce2da9336ff) @@ -77,7 +77,7 @@ transaction_build tx02 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b506040516103ea3803806103ea833981810160405281019061003291906100db565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610108565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100a88261007d565b9050919050565b6100b88161009d565b81146100c357600080fd5b50565b6000815190506100d5816100af565b92915050565b6000602082840312156100f1576100f0610078565b5b60006100ff848285016100c6565b91505092915050565b6102d3806101176000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636ead0b3314610030575b600080fd5b61003861004e565b604051610045919061019c565b60405180910390f35b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f6ead0b33000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161011b9190610228565b6000604051808303816000865af19150503d8060008114610158576040519150601f19603f3d011682016040523d82523d6000602084013e61015d565b606091505b50915091506000818060200190518101906101789190610270565b905080935050505090565b6000819050919050565b61019681610183565b82525050565b60006020820190506101b1600083018461018d565b92915050565b600081519050919050565b600081905092915050565b60005b838110156101eb5780820151818401526020810190506101d0565b60008484015250505050565b6000610202826101b7565b61020c81856101c2565b935061021c8185602086016101cd565b80840191505092915050565b600061023482846101f7565b915081905092915050565b600080fd5b61024d81610183565b811461025857600080fd5b50565b60008151905061026a81610244565b92915050565b6000602082840312156102865761028561023f565b5b60006102948482850161025b565b9150509291505056fea2646970667358221220f43c69f5bd9e47ba08907635b0a417ce030df5ab2b586b557a4231dda5c2610f64736f6c634300081300330000000000000000000000006252703f5ba322ec64d3ac45e56241b7d9e481ad - gas 2000000 + gas 300000 build # Deploy CallStackDepthCallerA (address: 27444fbce96cb2d27b94e116d1506d7739c05862) @@ -90,7 +90,7 @@ transaction_build tx03 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b506040516103ea3803806103ea833981810160405281019061003291906100db565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610108565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100a88261007d565b9050919050565b6100b88161009d565b81146100c357600080fd5b50565b6000815190506100d5816100af565b92915050565b6000602082840312156100f1576100f0610078565b5b60006100ff848285016100c6565b91505092915050565b6102d3806101176000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636ead0b3314610030575b600080fd5b61003861004e565b604051610045919061019c565b60405180910390f35b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f6ead0b33000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161011b9190610228565b6000604051808303816000865af19150503d8060008114610158576040519150601f19603f3d011682016040523d82523d6000602084013e61015d565b606091505b50915091506000818060200190518101906101789190610270565b905080935050505090565b6000819050919050565b61019681610183565b82525050565b60006020820190506101b1600083018461018d565b92915050565b600081519050919050565b600081905092915050565b60005b838110156101eb5780820151818401526020810190506101d0565b60008484015250505050565b6000610202826101b7565b61020c81856101c2565b935061021c8185602086016101cd565b80840191505092915050565b600061023482846101f7565b915081905092915050565b600080fd5b61024d81610183565b811461025857600080fd5b50565b60008151905061026a81610244565b92915050565b6000602082840312156102865761028561023f565b5b60006102948482850161025b565b9150509291505056fea264697066735822122057591f048da89b79d6769503b7a37a2a1f5c39831c3c8f75d430d1ea3927ce8a64736f6c6343000813003300000000000000000000000056aa252dd82173789984fa164ee26ce2da9336ff - gas 2000000 + gas 300000 build block_build b01 diff --git a/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt index 5cc27c797c6..e3443a064f5 100644 --- a/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt +++ b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeActivatedTest.txt @@ -51,7 +51,7 @@ transaction_build txTestBasefee receiverAddress 00 value 0 data 608060405234801561000f575f80fd5b506101498061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636b11a75f1461002d575b5f80fd5b610047600480360381019061004291906100e8565b610049565b005b804803610081577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100ae565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50565b5f80fd5b5f819050919050565b6100c7816100b5565b81146100d1575f80fd5b50565b5f813590506100e2816100be565b92915050565b5f602082840312156100fd576100fc6100b1565b5b5f61010a848285016100d4565b9150509291505056fea2646970667358221220af033c2d8dcac1c830549d1c3144ac62d2ce6d74e5363841f42152caab9ec22a64736f6c63430008170033 - gas 1200000 + gas 600000 build # Create block to hold txTestBasefee transaction diff --git a/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt index 6ce240f312e..6db0ca2320c 100644 --- a/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt +++ b/rskj-core/src/test/resources/dsl/opcode/basefee/baseFeeNotActivatedTest.txt @@ -47,7 +47,7 @@ transaction_build txTestBasefee receiverAddress 00 value 0 data 608060405234801561000f575f80fd5b506101498061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636b11a75f1461002d575b5f80fd5b610047600480360381019061004291906100e8565b610049565b005b804803610081577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100ae565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50565b5f80fd5b5f819050919050565b6100c7816100b5565b81146100d1575f80fd5b50565b5f813590506100e2816100be565b92915050565b5f602082840312156100fd576100fc6100b1565b5b5f61010a848285016100d4565b9150509291505056fea2646970667358221220af033c2d8dcac1c830549d1c3144ac62d2ce6d74e5363841f42152caab9ec22a64736f6c63430008170033 - gas 1200000 + gas 600000 build # Create block to hold txTestBasefee transaction diff --git a/rskj-core/src/test/resources/dsl/opcode_revert1.txt b/rskj-core/src/test/resources/dsl/opcode_revert1.txt index b3d8652a34f..949c2abe683 100644 --- a/rskj-core/src/test/resources/dsl/opcode_revert1.txt +++ b/rskj-core/src/test/resources/dsl/opcode_revert1.txt @@ -10,6 +10,7 @@ transaction_build contract_with_revert block_build b01 parent g00 + gasLimit 7500000 transactions contract_with_revert build @@ -31,6 +32,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 7500000 transactions tx02 build @@ -53,6 +55,7 @@ transaction_build tx03 block_build b03 parent b02 + gasLimit 7500000 transactions tx03 build diff --git a/rskj-core/src/test/resources/dsl/opcode_revert2.txt b/rskj-core/src/test/resources/dsl/opcode_revert2.txt index 4f50f832283..d70844fb067 100644 --- a/rskj-core/src/test/resources/dsl/opcode_revert2.txt +++ b/rskj-core/src/test/resources/dsl/opcode_revert2.txt @@ -10,6 +10,7 @@ transaction_build contract_with_revert block_build b01 parent g00 + gasLimit 7500000 transactions contract_with_revert build @@ -31,6 +32,7 @@ transaction_build tx02 block_build b02 parent b01 + gasLimit 7500000 transactions tx02 build @@ -53,6 +55,7 @@ transaction_build tx03 block_build b03 parent b02 + gasLimit 7500000 transactions tx03 build diff --git a/rskj-core/src/test/resources/dsl/push0test.txt b/rskj-core/src/test/resources/dsl/push0test.txt index 9ba75e52b73..d5f6560987a 100644 --- a/rskj-core/src/test/resources/dsl/push0test.txt +++ b/rskj-core/src/test/resources/dsl/push0test.txt @@ -21,7 +21,7 @@ transaction_build txCreateNew receiverAddress 00 value 0 data 608060405234801561000f575f80fd5b506101238061001d5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063771602f714602a575b5f80fd5b60406004803603810190603c91906092565b6054565b604051604b919060d6565b60405180910390f35b5f818301905092915050565b5f80fd5b5f819050919050565b6074816064565b8114607d575f80fd5b50565b5f81359050608c81606d565b92915050565b5f806040838503121560a55760a46060565b5b5f60b0858286016080565b925050602060bf858286016080565b9150509250929050565b60d0816064565b82525050565b5f60208201905060e75f83018460c9565b9291505056fea264697066735822122045ed7bb05dd9f1947b2804a8d76b6b7336f31495e814ca7c00a1c4bf60828d8364736f6c63430008140033 - gas 1200000 + gas 600000 build block_build b01 @@ -62,7 +62,7 @@ transaction_build txCreateOld nonce 2 value 0 data 608060405234801561001057600080fd5b5061012f806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063771602f714602d575b600080fd5b60436004803603810190603f9190609a565b6057565b604051604e919060e0565b60405180910390f35b6000818301905092915050565b600080fd5b6000819050919050565b607a816069565b8114608457600080fd5b50565b6000813590506094816073565b92915050565b6000806040838503121560ae5760ad6064565b5b600060ba858286016087565b925050602060c9858286016087565b9150509250929050565b60da816069565b82525050565b600060208201905060f3600083018460d3565b9291505056fea2646970667358221220b386c5fbaa1f4fa300a7ba86a498ed9bdf2b01bffc7263abc34cc285d973482264736f6c63430008110033 - gas 1200000 + gas 600000 build block_build b03 diff --git a/rskj-core/src/test/resources/dsl/recursive01.txt b/rskj-core/src/test/resources/dsl/recursive01.txt index 396f989317a..134062f2a3e 100644 --- a/rskj-core/src/test/resources/dsl/recursive01.txt +++ b/rskj-core/src/test/resources/dsl/recursive01.txt @@ -76,11 +76,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b503060405161001e906100b6565b808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f080158015610070573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506100c3565b610285806102c283390190565b6101f0806100d26000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806361bc221a146100465780637cf5dab01461006457806399c93b7b14610092575b600080fd5b61004e6100dc565b6040518082815260200191505060405180910390f35b6100906004803603602081101561007a57600080fd5b81019080803590602001909291905050506100e2565b005b61009a610195565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60005481565b60008114156100f057610192565b6000808154809291906001019190505550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637cf5dab0600183036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561017957600080fd5b505af115801561018d573d6000803e3d6000fd5b505050505b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820902aa0324b2c98c86efd82a6d396a26f478dc098874af497ccf57dba64c0014f64736f6c63430005100032608060405234801561001057600080fd5b506040516102853803806102858339818101604052602081101561003357600080fd5b810190808051906020019092919050505080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101f0806100956000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806361bc221a146100465780637cf5dab01461006457806399c93b7b14610092575b600080fd5b61004e6100dc565b6040518082815260200191505060405180910390f35b6100906004803603602081101561007a57600080fd5b81019080803590602001909291905050506100e2565b005b61009a610195565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60005481565b60008114156100f057610192565b6000808154809291906001019190505550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637cf5dab0600183036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561017957600080fd5b505af115801561018d573d6000803e3d6000fd5b505050505b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820fcf11fb16267f8707a34d30e6b2c980491bc4c79582a4b80c3d0958f83f4e3b964736f6c63430005100032 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build @@ -97,13 +98,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data 7cf5dab00000000000000000000000000000000000000000000000000000000000000190 - gas 6400000 + gas 3200000 build block_build b02 parent b01 transactions tx02 - gasLimit 6500000 + gasLimit 65000000 build block_connect b02 diff --git a/rskj-core/src/test/resources/dsl/recursive02.txt b/rskj-core/src/test/resources/dsl/recursive02.txt index 10762f4066a..97d7df47d9a 100644 --- a/rskj-core/src/test/resources/dsl/recursive02.txt +++ b/rskj-core/src/test/resources/dsl/recursive02.txt @@ -76,11 +76,12 @@ transaction_build tx01 receiverAddress 00 value 0 data 608060405234801561001057600080fd5b503060405161001e906100b6565b808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f080158015610070573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506100c3565b610285806102c283390190565b6101f0806100d26000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806361bc221a146100465780637cf5dab01461006457806399c93b7b14610092575b600080fd5b61004e6100dc565b6040518082815260200191505060405180910390f35b6100906004803603602081101561007a57600080fd5b81019080803590602001909291905050506100e2565b005b61009a610195565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60005481565b60008114156100f057610192565b6000808154809291906001019190505550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637cf5dab0600183036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561017957600080fd5b505af115801561018d573d6000803e3d6000fd5b505050505b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820902aa0324b2c98c86efd82a6d396a26f478dc098874af497ccf57dba64c0014f64736f6c63430005100032608060405234801561001057600080fd5b506040516102853803806102858339818101604052602081101561003357600080fd5b810190808051906020019092919050505080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101f0806100956000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806361bc221a146100465780637cf5dab01461006457806399c93b7b14610092575b600080fd5b61004e6100dc565b6040518082815260200191505060405180910390f35b6100906004803603602081101561007a57600080fd5b81019080803590602001909291905050506100e2565b005b61009a610195565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60005481565b60008114156100f057610192565b6000808154809291906001019190505550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637cf5dab0600183036040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561017957600080fd5b505af115801561018d573d6000803e3d6000fd5b505050505b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820fcf11fb16267f8707a34d30e6b2c980491bc4c79582a4b80c3d0958f83f4e3b964736f6c63430005100032 - gas 2000000 + gas 1000000 build block_build b01 parent g00 + gasLimit 7500000 transactions tx01 build @@ -97,13 +98,13 @@ transaction_build tx02 contract tx01 # created in tx01 value 0 data 7cf5dab00000000000000000000000000000000000000000000000000000000000000191 - gas 6500000 + gas 2500000 build block_build b02 parent b01 transactions tx02 - gasLimit 6500000 + gasLimit 13000000 build block_connect b02