From 729dbae7e521d34a2f70425c9b02c8f3066cdaf0 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Mon, 30 Sep 2024 11:51:42 +0200 Subject: [PATCH 01/22] Adding the structure for transient storage opcodes --- .../blockchain/upgrades/ConsensusRule.java | 3 +- .../src/main/java/org/ethereum/vm/OpCode.java | 9 ++++++ .../main/java/org/ethereum/vm/OpCodes.java | 8 ++++++ .../src/main/java/org/ethereum/vm/VM.java | 28 ++++++++++++++++++- rskj-core/src/main/resources/expected.conf | 1 + rskj-core/src/main/resources/reference.conf | 1 + 6 files changed, 48 insertions(+), 2 deletions(-) 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 36ae79b5ebf..d9f306d0951 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 @@ -95,7 +95,8 @@ public enum ConsensusRule { RSKIP417("rskip417"), RSKIP428("rskip428"), RSKIP434("rskip434"), - RSKIP438("rskip438") + RSKIP438("rskip438"), + RSKIP446("rskip446") // Transient storage opcodes addition implementing EIP-1153 ; private String configKey; diff --git a/rskj-core/src/main/java/org/ethereum/vm/OpCode.java b/rskj-core/src/main/java/org/ethereum/vm/OpCode.java index f9de1515e87..e550c38665a 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/OpCode.java +++ b/rskj-core/src/main/java/org/ethereum/vm/OpCode.java @@ -329,6 +329,15 @@ public enum OpCode { */ JUMPDEST(0x5b, 0, 0, SPECIAL_TIER), + /** + * (0x5c) Load word from transient storage at address + */ + TLOAD(0x5c, 1, 1, SPECIAL_TIER), + + /** + * (0x5c) Store word from transient storage at address + */ + TSTORE(0x5d, 2, 1, SPECIAL_TIER), /* Push Operations */ /** diff --git a/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java b/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java index 7b483642fb7..e447e7616db 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java +++ b/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java @@ -325,6 +325,14 @@ private OpCodes() { * (0x5b) */ static final byte OP_JUMPDEST =0x5b ; + /** + * (0x5c) + */ + static final byte OP_TLOAD =0x5c ; + /** + * (0x5d) + */ + static final byte OP_TSTORE =0x5d ; /* Push Operations */ /** 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 11912eb97a8..8af764f2cea 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1326,6 +1326,28 @@ else if (oldValue != null && newValue.isZero()) { program.step(); } + protected void doTLOAD(){ + + DataWord key = program.stackPop(); + DataWord value = program.stackPop(); + DataWord address = program.getOwnerAddress(); + + if (isLogEnabled) { + logger.info("Executing TLOAD with parameters: address={} | key = {} | value = {}", address, key, value); + } + } + + protected void doTSTORE(){ + + DataWord key = program.stackPop(); + DataWord value = program.stackPop(); + DataWord address = program.getOwnerAddress(); + + if (isLogEnabled) { + logger.info("Executing TLOAD with parameters: address={} | key = {} | value = {}", address, key, value); + } + } + protected void doJUMP(){ spendOpCodeGas(); // EXECUTION PHASE @@ -1939,7 +1961,11 @@ protected void executeOpcode() { case OpCodes.OP_SLOAD: doSLOAD(); break; case OpCodes.OP_SSTORE: doSSTORE(); - break; + break; + case OpCodes.OP_TLOAD: doTLOAD(); + break; + case OpCodes.OP_TSTORE: doTSTORE(); + break; case OpCodes.OP_JUMP: doJUMP(); break; case OpCodes.OP_JUMPI: doJUMPI(); diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 18a0eb82706..74091ce8ab0 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -97,6 +97,7 @@ blockchain = { rskip428 = rskip434 = rskip438 = + rskip446 = } } gc = { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index cb42c94872f..9cd09885d95 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -82,6 +82,7 @@ blockchain = { rskip428 = lovell700 rskip434 = arrowhead631 rskip438 = lovell700 + rskip446 = lovell700 } } gc = { From d66eba6781769774a0e314f1c79974271d94641d Mon Sep 17 00:00:00 2001 From: frederico leal Date: Tue, 1 Oct 2024 09:12:36 +0200 Subject: [PATCH 02/22] Adding scratch from the DSL tests and contracts for tests The tests are still failing, I am investigating to find the root cause --- .../src/main/java/org/ethereum/vm/OpCode.java | 4 +- .../src/main/java/org/ethereum/vm/VM.java | 9 +- .../vm/opcode/TransientStorageDslTest.java | 89 ++++++++++++ .../tload_tstore_basic_contract.txt | 127 ++++++++++++++++++ 4 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt diff --git a/rskj-core/src/main/java/org/ethereum/vm/OpCode.java b/rskj-core/src/main/java/org/ethereum/vm/OpCode.java index e550c38665a..31350089488 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/OpCode.java +++ b/rskj-core/src/main/java/org/ethereum/vm/OpCode.java @@ -332,12 +332,12 @@ public enum OpCode { /** * (0x5c) Load word from transient storage at address */ - TLOAD(0x5c, 1, 1, SPECIAL_TIER), + TLOAD(0x5c, 1, 1, SPECIAL_TIER), // Will adjust the correct inputs and outputs later /** * (0x5c) Store word from transient storage at address */ - TSTORE(0x5d, 2, 1, SPECIAL_TIER), + TSTORE(0x5d, 1, 1, SPECIAL_TIER), // Will adjust the correct inputs and outputs later /* Push Operations */ /** 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 8af764f2cea..a383b38e098 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1327,24 +1327,19 @@ else if (oldValue != null && newValue.isZero()) { } protected void doTLOAD(){ - - DataWord key = program.stackPop(); - DataWord value = program.stackPop(); DataWord address = program.getOwnerAddress(); if (isLogEnabled) { - logger.info("Executing TLOAD with parameters: address={} | key = {} | value = {}", address, key, value); + logger.info("Executing TLOAD with parameters: address={} ",address); } } protected void doTSTORE(){ - DataWord key = program.stackPop(); - DataWord value = program.stackPop(); DataWord address = program.getOwnerAddress(); if (isLogEnabled) { - logger.info("Executing TLOAD with parameters: address={} | key = {} | value = {}", address, key, value); + logger.info("Executing TSTORE with parameters: address={} ", address); } } diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java new file mode 100644 index 00000000000..2e5dc2e854f --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -0,0 +1,89 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.vm.opcode; + +import co.rsk.config.TestSystemProperties; +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.core.Block; +import org.ethereum.core.Transaction; +import org.ethereum.core.TransactionReceipt; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.FileNotFoundException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class TransientStorageDslTest { + + @Test + void testTransientStorageOpcodesExecutionsWithRSKIPActivated() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String contractCreationTx = "txTestTransientStorageContract"; + Transaction contractTransaction = world.getTransactionByName("txTestTransientStorageContract"); + assertNotNull(contractTransaction); + + Block bestBlock = world.getBlockByName("b01"); + Assertions.assertEquals(1, bestBlock.getTransactionsList().size()); + TransactionReceipt contractTransactionReceipt = world.getTransactionReceiptByName(contractCreationTx); + + assertNotNull(contractTransactionReceipt); + byte[] status = contractTransactionReceipt.getStatus(); + assertNotNull(status); + assertEquals(1, status.length); + assertEquals(1, status[0]); + } + + @Test + void testTransientStorageOpcodesExecutionsWithRSKIPDeactivated() throws FileNotFoundException, DslProcessorException { + TestSystemProperties rskip446Disabled = new TestSystemProperties(rawConfig -> + rawConfig.withValue("blockchain.config.hardforkActivationHeights.lovell700", ConfigValueFactory.fromAnyRef(-1)) + ); + + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt"); + World world = new World(rskip446Disabled); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String contractCreationTx = "txTestTransientStorageContract"; + Transaction contractTransaction = world.getTransactionByName("txTestTransientStorageContract"); + assertNotNull(contractTransaction); + + Block bestBlock = world.getBlockByName("b01"); + Assertions.assertEquals(1, bestBlock.getTransactionsList().size()); + TransactionReceipt contractTransactionReceipt = world.getTransactionReceiptByName(contractCreationTx); + + assertNotNull(contractTransactionReceipt); + byte[] status = contractTransactionReceipt.getStatus(); + assertNotNull(status); + assertEquals(1, status.length); + assertEquals(1, status[0]); + } + +} diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt new file mode 100644 index 00000000000..55b0ad02a53 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt @@ -0,0 +1,127 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TestTransientStorage { + constructor() {} + + event OK(); + event ERROR(); + + function checkTStore() external { + bytes32 valueToSave = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f; + address contractAddress = address(this); + assembly { + tstore(contractAddress, valueToSave) // Use TSTORE to save the value at the contract address on the transient storage + } + } + + function checkTLoad() external { + bytes32 valueSaved = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f; + bytes32 valueLoaded; + address contractAddress = address(this); + assembly { + valueLoaded := tload(contractAddress) // Use TLOAD to load the value into the temporary variable + } + if (valueLoaded == valueSaved) { + emit OK(); + } else { + emit ERROR(); + } + } +} + +// DESCRIPTION + +This contract contains two functions: checkTStore and checkTLoad. + +* checkTStore simply checks if the transaction finished with success and it's expected to have saved the value on the address + +* checkTLoad simply checks if the transaction finished with success and check if the value loaded is the same as the value saved + + +// CONTRACT BYTECODE + +608060405234801561000f575f80fd5b5061014a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063a36ca99d14610038578063d5ad4e0b14610042575b5f80fd5b61004061004c565b005b61004a61007c565b005b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f30905081815d5050565b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f80309050805c91508282036100e2577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161010f565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50505056fea2646970667358221220c97a07f12090a982975e295ffa092efe648f43916b098afb2523daffb7e42df464736f6c63430008180033 + +// CONTRACT CALL + +- checkTStore() -> a36ca99d +- checkTLoad() -> d5ad4e0b + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorage contract +transaction_build txTestTransientStorageContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b5061014a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063a36ca99d14610038578063d5ad4e0b14610042575b5f80fd5b61004061004c565b005b61004a61007c565b005b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f30905081815d5050565b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f80309050805c91508282036100e2577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161010f565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50505056fea2646970667358221220c97a07f12090a982975e295ffa092efe648f43916b098afb2523daffb7e42df464736f6c63430008180033 + gas 1200000 + build + +# Create block to hold txTestTransientStorageContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageContract + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Check txTestTransientStorageContract succeded +assert_tx_success txTestTransientStorageContract + +# Create transaction to execute checkTStore() method +transaction_build txTestTStore + sender acc1 + nonce 1 + contract txTestTransientStorageContract + value 0 + data a36ca99d + gas 30000 + build + +# Create block to hold txTestTStore transaction +block_build b02 + parent b01 + transactions txTestTStore + gasLimit 6500000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute checkTLoad() method +transaction_build txTestTLoad + sender acc1 + nonce 2 + contract txTestTransientStorageContract + value 0 + data d5ad4e0b + gas 30000 + build + +# Create block to hold txTestTLoad transaction +block_build b03 + parent b02 + transactions txTestTLoad + gasLimit 6500000 + build + +# Connect block +block_connect b03 + +# Check b02 is best block +assert_best b03 \ No newline at end of file From 47388c37c8ced1d49c3524431664c7de5f7d2135 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Wed, 2 Oct 2024 08:58:41 +0200 Subject: [PATCH 03/22] Some adjustments in DSL file and tests --- .../src/main/java/org/ethereum/vm/OpCode.java | 2 +- rskj-core/src/main/java/org/ethereum/vm/VM.java | 15 +++++++++++++-- .../java/org/ethereum/vm/program/Program.java | 8 ++++++++ .../co/rsk/vm/opcode/TransientStorageDslTest.java | 4 ++-- .../tload_tstore_basic_contract.txt | 3 --- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/rskj-core/src/main/java/org/ethereum/vm/OpCode.java b/rskj-core/src/main/java/org/ethereum/vm/OpCode.java index 31350089488..eed1d4eae06 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/OpCode.java +++ b/rskj-core/src/main/java/org/ethereum/vm/OpCode.java @@ -337,7 +337,7 @@ public enum OpCode { /** * (0x5c) Store word from transient storage at address */ - TSTORE(0x5d, 1, 1, SPECIAL_TIER), // Will adjust the correct inputs and outputs later + TSTORE(0x5d, 2, 0, SPECIAL_TIER), // Will adjust the correct inputs and outputs later /* Push Operations */ /** 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 a383b38e098..e3297ebfff7 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1327,20 +1327,31 @@ else if (oldValue != null && newValue.isZero()) { } protected void doTLOAD(){ + + DataWord key = program.stackPop(); DataWord address = program.getOwnerAddress(); if (isLogEnabled) { - logger.info("Executing TLOAD with parameters: address={} ",address); + logger.info("Executing TLOAD with parameters: address={} | key = {}", address, key); } + + program.transientStorageSave(key, address); + // key could be returned to the pool, but storageLoad semantics should be checked + // to make sure storageLoad always gets a copy, not a reference. + program.step(); } protected void doTSTORE(){ + DataWord value = program.stackPop(); DataWord address = program.getOwnerAddress(); + DataWord key = DataWord.ZERO; if (isLogEnabled) { - logger.info("Executing TSTORE with parameters: address={} ", address); + logger.info("Executing TSTORE with parameters: address={} | key = {} | value = {}", address, key, value); } + program.transientStorageLoad(address, key, value); + program.step(); } protected void doJUMP(){ 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 9edacb01d14..680c651438e 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 @@ -984,6 +984,10 @@ private void storageSave(byte[] key, byte[] val) { getStorage().addStorageRow(getOwnerRskAddress(), keyWord, valWord); } + public void transientStorageSave(DataWord key, DataWord address) { + + } + private RskAddress getOwnerRskAddress() { if (rskOwnerAddress == null) { rskOwnerAddress = new RskAddress(getOwnerAddress()); @@ -1094,6 +1098,10 @@ public DataWord storageLoad(DataWord key) { return getStorage().getStorageValue(getOwnerRskAddress(), key); } + public void transientStorageLoad(DataWord address, DataWord key, DataWord value) { + + } + public DataWord getPrevHash() { return invoke.getPrevHash(); } diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index 2e5dc2e854f..1eec762bb0f 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -49,7 +49,7 @@ void testTransientStorageOpcodesExecutionsWithRSKIPActivated() throws FileNotFou Transaction contractTransaction = world.getTransactionByName("txTestTransientStorageContract"); assertNotNull(contractTransaction); - Block bestBlock = world.getBlockByName("b01"); + Block bestBlock = world.getBlockByName("b03"); Assertions.assertEquals(1, bestBlock.getTransactionsList().size()); TransactionReceipt contractTransactionReceipt = world.getTransactionReceiptByName(contractCreationTx); @@ -75,7 +75,7 @@ void testTransientStorageOpcodesExecutionsWithRSKIPDeactivated() throws FileNotF Transaction contractTransaction = world.getTransactionByName("txTestTransientStorageContract"); assertNotNull(contractTransaction); - Block bestBlock = world.getBlockByName("b01"); + Block bestBlock = world.getBlockByName("b03"); Assertions.assertEquals(1, bestBlock.getTransactionsList().size()); TransactionReceipt contractTransactionReceipt = world.getTransactionReceiptByName(contractCreationTx); diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt index 55b0ad02a53..e8312fc8cb4 100644 --- a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt @@ -77,9 +77,6 @@ block_connect b01 # Check b01 is best block assert_best b01 -# Check txTestTransientStorageContract succeded -assert_tx_success txTestTransientStorageContract - # Create transaction to execute checkTStore() method transaction_build txTestTStore sender acc1 From 762f0dfa3ee124c5555dfd55567537a4376bf52a Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 27 Sep 2024 11:19:16 -0300 Subject: [PATCH 04/22] Update test in BitcoinUtilsTest to use deterministic keys --- .../co/rsk/peg/bitcoin/BitcoinTestUtils.java | 23 +++++++++---------- .../co/rsk/peg/bitcoin/BitcoinUtilsTest.java | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java index 4ba69f1fc7c..146d389f73f 100644 --- a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java +++ b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java @@ -1,28 +1,27 @@ package co.rsk.peg.bitcoin; +import static co.rsk.bitcoinj.script.ScriptBuilder.createP2SHOutputScript; +import static co.rsk.peg.bitcoin.BitcoinUtils.extractRedeemScriptFromInput; + import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.crypto.TransactionSignature; import co.rsk.bitcoinj.script.*; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; - -import co.rsk.bitcoinj.script.ScriptChunk; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.HashUtil; -import static co.rsk.bitcoinj.script.ScriptBuilder.createP2SHOutputScript; -import static co.rsk.peg.bitcoin.BitcoinUtils.extractRedeemScriptFromInput; - public class BitcoinTestUtils { + public static BtcECKey getBtcEcKeyFromSeed(String seed) { + byte[] serializedSeed = HashUtil.keccak256(seed.getBytes(StandardCharsets.UTF_8)); + return BtcECKey.fromPrivate(serializedSeed); + } + public static List getBtcEcKeysFromSeeds(String[] seeds, boolean sorted) { - List keys = Arrays - .stream(seeds) - .map(seed -> BtcECKey.fromPrivate( - HashUtil.keccak256(seed.getBytes(StandardCharsets.UTF_8)))) + List keys = Arrays.stream(seeds) + .map(BitcoinTestUtils::getBtcEcKeyFromSeed) .collect(Collectors.toList()); if (sorted) { 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 5740f641af0..4d908493635 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 @@ -333,7 +333,7 @@ void removeSignaturesFromTransaction_whenTransactionIsSegwit_shouldThrowIllegalA void removeSignaturesFromTransaction_whenTransactionInputsDoNotHaveP2shMultiSigInputScript_shouldThrowIllegalArgumentException() { // arrange BtcTransaction transaction = new BtcTransaction(btcMainnetParams); - BtcECKey pubKey = new BtcECKey(); + BtcECKey pubKey = BitcoinTestUtils.getBtcEcKeyFromSeed("abc"); Script p2pkhScriptSig = ScriptBuilder.createInputScript(null, pubKey); transaction.addInput(BitcoinTestUtils.createHash(1), 0, p2pkhScriptSig); From 08cd200768bd34d0aff06f5d9fe4f417de73f7a2 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Fri, 27 Sep 2024 13:35:41 +0300 Subject: [PATCH 05/22] build: run rit check overnight; allow plus symbol in branch names --- .github/workflows/rit.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rit.yml b/.github/workflows/rit.yml index 889ea657130..9fac1b2cf9d 100644 --- a/.github/workflows/rit.yml +++ b/.github/workflows/rit.yml @@ -1,6 +1,8 @@ name: Rootstock Integration Tests on: + schedule: + - cron: '0 0 * * *' pull_request: types: [ opened, synchronize, reopened ] branches: ["master", "*-rc"] @@ -37,7 +39,7 @@ jobs: run: | PR_DESCRIPTION=pr-description.txt - ALLOWED_BRANCH_CHARACTERS='[-./0-9A-Z_a-z]' + ALLOWED_BRANCH_CHARACTERS='[-+./0-9A-Z_a-z]' default_rskj_branch=master default_powpeg_branch=master From 53eca957664367a7b599b690db61ff318d9dc789 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Fri, 26 Jul 2024 15:16:53 +0300 Subject: [PATCH 06/22] refactor: update Bytes and BytesSlice to 'mimic' System.arraycopy and Arrays.copyOfRange; add more tests --- .../java/co/rsk/core/types/bytes/Bytes.java | 5 +- .../co/rsk/core/types/bytes/BytesSlice.java | 84 +++++++++++++++-- .../core/types/bytes/HexPrintableBytes.java | 2 +- .../main/java/co/rsk/util/StringUtils.java | 2 + .../rsk/core/types/bytes/BytesSliceTest.java | 85 +++++++++++++++++- .../co/rsk/core/types/bytes/BytesTest.java | 89 ++++++++++++++++++- .../src/test/java/co/rsk/util/Functions.java | 30 +++++++ 7 files changed, 279 insertions(+), 18 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/util/Functions.java diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java index ce988888068..cb4c16d17d3 100644 --- a/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java @@ -23,7 +23,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Arrays; import java.util.Objects; /** @@ -140,8 +139,8 @@ public byte byteAt(int index) { } @Override - public byte[] copyArrayOfRange(int from, int to) { - return Arrays.copyOfRange(byteArray, from, to); + public void arraycopy(int srcPos, byte[] dest, int destPos, int length) { + System.arraycopy(byteArray, srcPos, dest, destPos, length); } @Override diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java index 5210ff8eea0..ac3616fd8f0 100644 --- a/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java @@ -18,11 +18,62 @@ package co.rsk.core.types.bytes; +import java.util.Arrays; + /** * A {@link BytesSlice} is a subsequence of bytes backed by another broader byte sequence. */ public interface BytesSlice extends HexPrintableBytes { + /** + * Copies an array from the {@link BytesSlice} source, beginning at the + * specified position, to the specified position of the destination array. + * A subsequence of array components are copied from this instance to the + * destination array referenced by {@code dest}. The number of components + * copied is equal to the {@code length} argument. The components at + * positions {@code srcPos} through {@code srcPos+length-1} in the source + * array are copied into positions {@code destPos} through + * {@code destPos+length-1}, respectively, of the destination + * array. + *

+ * If the underlying byte array and {@code dest} argument refer to the + * same array object, then the copying is performed as if the + * components at positions {@code srcPos} through + * {@code srcPos+length-1} were first copied to a temporary + * array with {@code length} components and then the contents of + * the temporary array were copied into positions + * {@code destPos} through {@code destPos+length-1} of the + * destination array. + *

+ * If {@code dest} is {@code null}, then a + * {@code NullPointerException} is thrown. + *

+ * Otherwise, if any of the following is true, an + * {@code IndexOutOfBoundsException} is + * thrown and the destination is not modified: + *

    + *
  • The {@code srcPos} argument is negative. + *
  • The {@code destPos} argument is negative. + *
  • The {@code length} argument is negative. + *
  • {@code srcPos+length} is greater than + * {@code src.length}, the length of the source array. + *
  • {@code destPos+length} is greater than + * {@code dest.length}, the length of the destination array. + *
+ * + *

+ * Note: this method mimics behaviour of {@link System#arraycopy(Object, int, Object, int, int)} + * + * @param srcPos starting position in the source array. + * @param dest the destination array. + * @param destPos starting position in the destination data. + * @param length the number of array elements to be copied. + * @throws IndexOutOfBoundsException if copying would cause + * access of data outside array bounds. + * @throws NullPointerException if {@code dest} is {@code null}. + */ + void arraycopy(int srcPos, byte[] dest, int destPos, int length); + /** * Copies the specified range of the specified array into a new array. * The initial index of the range (from) must lie between zero @@ -37,17 +88,30 @@ public interface BytesSlice extends HexPrintableBytes { * greater than or equal to original.length - from. The length * of the returned array will be to - from. * + *

+ * Note: this method mimics behaviour of {@link Arrays#copyOfRange(Object[], int, int)} + * * @param from the initial index of the range to be copied, inclusive * @param to the final index of the range to be copied, exclusive. * (This index may lie outside the array.) * @return a new array containing the specified range from the original array, * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * @throws IndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null */ - byte[] copyArrayOfRange(int from, int to); + default byte[] copyArrayOfRange(int from, int to) { + if (from < 0 || from > length()) { + throw new IndexOutOfBoundsException("invalid 'from': " + from); + } + int newLength = to - from; + if (newLength < 0) { + throw new IllegalArgumentException(from + " > " + to); + } + byte[] copy = new byte[newLength]; + arraycopy(from, copy, 0, Math.min(length() - from, newLength)); + return copy; + } default byte[] copyArray() { return copyArrayOfRange(0, length()); @@ -104,11 +168,17 @@ public byte byteAt(int index) { } @Override - public byte[] copyArrayOfRange(int from, int to) { - if (from < 0 || from > to || to > length()) { - throw new IndexOutOfBoundsException("invalid 'from' and/or 'to': [" + from + ";" + to + ")"); + public void arraycopy(int srcPos, byte[] dest, int destPos, int length) { + if (length < 0) { + throw new IndexOutOfBoundsException("invalid 'length': " + length); + } + if (srcPos < 0 || srcPos + length > length()) { + throw new IndexOutOfBoundsException("invalid 'srcPos' and/or 'length': [" + srcPos + ";" + length + ")"); + } + if (destPos < 0 || destPos + length > dest.length) { + throw new IndexOutOfBoundsException("invalid 'destPos' and/or 'length': [" + destPos + ";" + length + ")"); } - return originBytes.copyArrayOfRange(this.from + from, this.from + to); + originBytes.arraycopy(this.from + srcPos, dest, destPos, length); } @Override diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java index d700c0cc6a6..3f91f918eda 100644 --- a/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java @@ -77,7 +77,7 @@ public String toFormattedString(@Nonnull HexPrintableBytes printableBytes, int o } if (length > 32) { - return printableBytes.toHexString(off, 15) + ".." + printableBytes.toHexString(off + length - 15, 15); + return printableBytes.toHexString(off, 16) + ".." + printableBytes.toHexString(off + length - 15, 15); } return printableBytes.toHexString(off, length); } 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 a7c58a322b3..02ef4106555 100644 --- a/rskj-core/src/main/java/co/rsk/util/StringUtils.java +++ b/rskj-core/src/main/java/co/rsk/util/StringUtils.java @@ -24,6 +24,8 @@ public class StringUtils { private static final int DEFAULT_MAX_LEN = 64; + private StringUtils() { /* hidden */ } + public static String trim(@Nullable String src) { return trim(src, DEFAULT_MAX_LEN); } diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java index 93707953604..001aee51f35 100644 --- a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java @@ -19,17 +19,56 @@ package co.rsk.core.types.bytes; +import co.rsk.util.Functions; import org.junit.jupiter.api.Test; +import java.util.Arrays; + import static org.junit.jupiter.api.Assertions.*; class BytesSliceTest { + @Test + void testBytesLength() { + assertEquals(0, Bytes.of(new byte[]{}).slice(0, 0).length()); + assertEquals(0, Bytes.of(new byte[]{1}).slice(0, 0).length()); + assertEquals(1, Bytes.of(new byte[]{1}).slice(0, 1).length()); + assertEquals(0, Bytes.of(new byte[]{1,2,3}).slice(1, 1).length()); + assertEquals(1, Bytes.of(new byte[]{1,2,3}).slice(1, 2).length()); + assertEquals(2, Bytes.of(new byte[]{1,2,3}).slice(0, 2).length()); + assertEquals(3, Bytes.of(new byte[]{1,2,3}).slice(0, 3).length()); + } + + @Test + void testBytesAt() { + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{}).slice(0, 0).byteAt(0)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).slice(0, 1).byteAt(1)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).slice(0, 1).byteAt(-1)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1,2,3}).slice(1, 2).byteAt(1)); + assertEquals(1, Bytes.of(new byte[]{1}).slice(0, 1).byteAt(0)); + assertEquals(2, Bytes.of(new byte[]{1,2}).slice(0, 2).byteAt(1)); + assertEquals(2, Bytes.of(new byte[]{1,2,3}).slice(1, 2).byteAt(0)); + assertEquals(4, Bytes.of(new byte[]{1,2,3,4}).slice(2, 4).byteAt(1)); + } + + @Test + void testBytesSliceArraycopy() { + checkArraycopy((src, srcPos, dest, destPos, length) -> Bytes.of((byte[]) src).slice(1, 4).arraycopy(srcPos, (byte[]) dest, destPos, length)); + } + + @Test + void testBytesSliceArraycopyMimicsSystemOne() { + checkArraycopy((src, srcPos, dest, destPos, length) -> System.arraycopy(Arrays.copyOfRange((byte[]) src, 1, 4), srcPos, dest, destPos, length)); + } + @Test void testCopyArrayOfRange() { - byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; - byte[] expectedResult = new byte[]{3, 4, 5}; - assertArrayEquals(expectedResult, Bytes.of(bArray).slice(0, bArray.length).copyArrayOfRange(2, 5)); + checkCopyOfRange(BytesSlice::copyArrayOfRange, (origin, from, to) -> Bytes.of(origin).slice(from, to)); + } + + @Test + void testCopyArrayOfRangeMimicsSystemOne() { + checkCopyOfRange(Arrays::copyOfRange, Arrays::copyOfRange); } @Test @@ -74,4 +113,44 @@ void testEmptySlice() { assertEquals(0, actualResult.length()); assertArrayEquals(expectedResult, actualResult.copyArray()); } + + private static void checkArraycopy(Functions.Action5 fun) { + byte[] dest = new byte[3]; + byte[] origin = new byte[]{1,2,3,4,5}; + + assertThrows(NullPointerException.class, () -> fun.apply(origin, 0, null, 0, 3)); + + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, -1, dest, 0, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, -1, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, 0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, 0, 4)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 1, dest, 0, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, 1, 3)); + + assertArrayEquals(new byte[3], dest); // yet unmodified + + fun.apply(origin, 0, dest, 0, 3); + assertArrayEquals(new byte[]{2,3,4}, dest); + + byte[] dest2 = new byte[3]; + fun.apply(origin, 1, dest2, 1, 1); + assertArrayEquals(new byte[]{0,3,0}, dest2); + } + + private static void checkCopyOfRange(Functions.Function3 fun, + Functions.Function3 slicer) { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + + assertEquals(bArray.length, fun.apply(slicer.apply(bArray, 0, 6), 0, 6).length); + assertNotSame(bArray, fun.apply(slicer.apply(bArray, 0, 6), 0, 6)); + + assertArrayEquals(new byte[]{3, 4, 5}, fun.apply(slicer.apply(bArray, 0, 6), 2, 5)); + assertArrayEquals(new byte[]{3, 4}, fun.apply(slicer.apply(bArray, 1, 5), 1, 3)); + assertArrayEquals(new byte[]{3, 4, 5, 0, 0, 0, 0}, fun.apply(slicer.apply(bArray, 1, 5), 1, 8)); + assertArrayEquals(new byte[]{}, fun.apply(slicer.apply(bArray, 1, 5), 4, 4)); + + assertThrows(IllegalArgumentException.class, () -> fun.apply(slicer.apply(bArray, 1, 5), 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(slicer.apply(bArray, 1, 5), -1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(slicer.apply(bArray, 1, 5), 5, 5)); + } } diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java index b60ca431ddc..7cce5532f17 100644 --- a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java @@ -19,10 +19,13 @@ package co.rsk.core.types.bytes; +import co.rsk.util.Functions; import org.ethereum.TestUtils; import org.ethereum.util.ByteUtil; import org.junit.jupiter.api.Test; +import java.util.Arrays; + import static org.junit.jupiter.api.Assertions.*; class BytesTest { @@ -34,6 +37,41 @@ void testBytesOf() { assertNotNull(Bytes.of(new byte[]{1})); } + @Test + void testBytesLength() { + assertEquals(0, Bytes.of(new byte[]{}).length()); + assertEquals(1, Bytes.of(new byte[]{1}).length()); + } + + @Test + void testBytesAt() { + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{}).byteAt(0)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).byteAt(1)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).byteAt(-1)); + assertEquals(1, Bytes.of(new byte[]{1}).byteAt(0)); + assertEquals(2, Bytes.of(new byte[]{1,2}).byteAt(1)); + } + + @Test + void testBytesArraycopy() { + checkArraycopy((src, srcPos, dest, destPos, length) -> Bytes.of((byte[]) src).arraycopy(srcPos, (byte[]) dest, destPos, length)); + } + + @Test + void testBytesArraycopyMimicsSystemOne() { + checkArraycopy(System::arraycopy); + } + + @Test + void testCopyArrayOfRange() { + checkCopyOfRange((original, from, to) -> Bytes.of(original).copyArrayOfRange(from, to)); + } + + @Test + void testCopyArrayOfRangeMimicsSystemOne() { + checkCopyOfRange(Arrays::copyOfRange); + } + @Test void testToPrintableString() { assertEquals("0a", Bytes.toPrintableString(new byte[]{10})); @@ -83,13 +121,17 @@ void testShortEnoughBytesToString() { @Test void testLongBytesToString() { - byte[] bArray1 = TestUtils.generateBytes("hash1",15); + byte[] bArray1 = TestUtils.generateBytes("hash1",16); byte[] bArray2 = TestUtils.generateBytes("hash2",15); byte[] finalArray = ByteUtil.merge(bArray1, new byte[]{1, 2, 3}, bArray2); - assertEquals(33, finalArray.length); + assertEquals(34, finalArray.length); + + Bytes bytes = Bytes.of(finalArray); + + assertEquals(64, String.format("%s", bytes).length()); - String actualMessage = String.format("Some '%s' hex", Bytes.of(finalArray)); + String actualMessage = String.format("Some '%s' hex", bytes); String expectedMessage = "Some '" + ByteUtil.toHexString(bArray1) + ".." @@ -116,4 +158,43 @@ void testEmptyBytesToString() { assertEquals(expectedMessage, actualMessage); } -} \ No newline at end of file + + private static void checkArraycopy(Functions.Action5 fun) { + byte[] dest = new byte[5]; + byte[] origin = new byte[]{1,2,3,4,5}; + + assertThrows(NullPointerException.class, () -> fun.apply(origin, 0, null, 0, 5)); + + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, -1, dest, 0, 5)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, -1, 5)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, 0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, 0, 6)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 1, dest, 0, 5)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(origin, 0, dest, 1, 5)); + + assertArrayEquals(new byte[5], dest); // yet unmodified + + fun.apply(origin, 0, dest, 0, 5); + assertArrayEquals(new byte[]{1,2,3,4,5}, dest); + + byte[] dest2 = new byte[5]; + fun.apply(origin, 1, dest2, 1, 3); + assertArrayEquals(new byte[]{0,2,3,4,0}, dest2); + } + + private static void checkCopyOfRange(Functions.Function3 fun) { + byte[] bArray = new byte[]{1, 2, 3, 4, 5}; + + assertEquals(bArray.length, fun.apply(bArray, 0, 5).length); + assertNotSame(bArray, fun.apply(bArray, 0, 5)); + + assertArrayEquals(new byte[]{2, 3, 4}, fun.apply(bArray, 1, 4)); + assertArrayEquals(new byte[]{2}, fun.apply(bArray, 1, 2)); + assertArrayEquals(new byte[]{2, 3, 4, 5, 0, 0, 0}, fun.apply(bArray, 1, 8)); + assertArrayEquals(new byte[]{}, fun.apply(bArray, 3, 3)); + + assertThrows(IllegalArgumentException.class, () -> fun.apply(bArray, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(bArray, -1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> fun.apply(bArray, 6, 6)); + } +} diff --git a/rskj-core/src/test/java/co/rsk/util/Functions.java b/rskj-core/src/test/java/co/rsk/util/Functions.java new file mode 100644 index 00000000000..de687407e28 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/util/Functions.java @@ -0,0 +1,30 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.util; + +public interface Functions { + interface Function3 { + TResult apply(T1 arg1, T2 arg2, T3 arg3); + } + + interface Action5 { + void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + } +} From 22b6f96efe1cb1012f4b7171986da77ea87a8bbf Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Fri, 26 Jul 2024 15:20:58 +0300 Subject: [PATCH 07/22] perf: improve decoding in CallTransaction --- .../org/ethereum/core/CallTransaction.java | 23 ++++++++-------- .../org/ethereum/solidity/SolidityType.java | 27 ++++++++++--------- .../main/java/org/ethereum/util/Utils.java | 9 ++++--- .../java/co/rsk/core/CallTransactionTest.java | 3 ++- .../java/co/rsk/core/TransactionTest.java | 3 ++- .../org/ethereum/core/TransactionTest.java | 3 ++- .../ethereum/solidity/SolidityTypeTest.java | 21 ++++++++------- .../java/org/ethereum/util/UtilsTest.java | 27 +++++++++---------- 8 files changed, 61 insertions(+), 55 deletions(-) diff --git a/rskj-core/src/main/java/org/ethereum/core/CallTransaction.java b/rskj-core/src/main/java/org/ethereum/core/CallTransaction.java index 4c6cf7a8296..50750a55ba2 100644 --- a/rskj-core/src/main/java/org/ethereum/core/CallTransaction.java +++ b/rskj-core/src/main/java/org/ethereum/core/CallTransaction.java @@ -20,6 +20,8 @@ package org.ethereum.core; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; +import co.rsk.core.types.bytes.BytesSlice; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonInclude; @@ -36,7 +38,6 @@ import java.util.Arrays; import static java.lang.String.format; -import static org.apache.commons.lang3.ArrayUtils.subarray; import static org.apache.commons.lang3.StringUtils.stripEnd; import static org.ethereum.util.ByteUtil.longToBytesNoLeadZeroes; @@ -119,9 +120,9 @@ public static Type getType(String typeName) { */ public abstract byte[] encode(Object value); - public abstract Object decode(byte[] encoded, int offset); + public abstract Object decode(BytesSlice encoded, int offset); - public Object decode(byte[] encoded) { + public Object decode(BytesSlice encoded) { return decode(encoded, 0); } @@ -187,12 +188,12 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { return decodeInt(encoded, offset); } - public static BigInteger decodeInt(byte[] encoded, int offset) { - return new BigInteger(Arrays.copyOfRange(encoded, offset, offset + 32)); + public static BigInteger decodeInt(BytesSlice encoded, int offset) { + return new BigInteger(encoded.copyArrayOfRange(offset, offset + 32)); } public static byte[] encodeInt(int i) { @@ -222,7 +223,7 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { return Boolean.valueOf(((Number) super.decode(encoded, offset)).intValue() != 0); } } @@ -350,7 +351,7 @@ public Object[] decodeEventData(byte[] encodedData) { checkFunctionType(FunctionType.event); Param[] dataInputs = Arrays.stream(inputs).filter(i -> !i.indexed).toArray(Param[]::new); - return decode(encodedData, dataInputs); + return decode(Bytes.of(encodedData), dataInputs); } private void checkFunctionType(FunctionType expected) { @@ -405,7 +406,7 @@ public byte[] encodeOutputs(Object... args) { return encodeArguments(outputs, args); } - private Object[] decode(byte[] encoded, Param[] params) { + private Object[] decode(BytesSlice encoded, Param[] params) { Object[] ret = new Object[params.length]; int off = 0; @@ -421,11 +422,11 @@ private Object[] decode(byte[] encoded, Param[] params) { } public Object[] decode(byte[] encoded) { - return decode(subarray(encoded, 4, encoded.length), inputs); + return decode(Bytes.of(encoded).slice(4, encoded.length), inputs); } public Object[] decodeResult(byte[] encodedRet) { - return decode(encodedRet, outputs); + return decode(Bytes.of(encodedRet), outputs); } public String formatSignature() { diff --git a/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java b/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java index a4ef7aa34be..23d6197fc6c 100644 --- a/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java +++ b/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java @@ -20,6 +20,7 @@ package org.ethereum.solidity; import co.rsk.core.types.bytes.Bytes; +import co.rsk.core.types.bytes.BytesSlice; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import org.ethereum.util.ByteUtil; @@ -101,9 +102,9 @@ public static SolidityType getType(String typeName) { */ public abstract byte[] encode(Object value); - public abstract Object decode(byte[] encoded, int offset); + public abstract Object decode(BytesSlice encoded, int offset); - public Object decode(byte[] encoded) { + public Object decode(BytesSlice encoded) { return decode(encoded, 0); } @@ -196,7 +197,7 @@ public byte[] encodeList(List l) { } @Override - public Object[] decode(byte[] encoded, int offset) { + public Object[] decode(BytesSlice encoded, int offset) { Utils.validateArrayAllegedSize(encoded, offset, getFixedSize()); Object[] result = new Object[size]; for (int i = 0; i < size; i++) { @@ -247,8 +248,8 @@ public byte[] encodeList(List l) { } @Override - public Object decode(byte[] encoded, int origOffset) { - if (encoded.length == 0) { + public Object decode(BytesSlice encoded, int origOffset) { + if (encoded.length() == 0) { return new Object[0]; } int len = IntType.decodeInt(encoded, origOffset).intValue(); @@ -299,7 +300,7 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { int len = IntType.decodeInt(encoded, offset).intValue(); offset += IntType.INT_SIZE; return Utils.safeCopyOfRange(encoded, offset, len); @@ -325,7 +326,7 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { return new String((byte[]) super.decode(encoded, offset), StandardCharsets.UTF_8); } } @@ -357,7 +358,7 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { return Utils.safeCopyOfRange(encoded, offset, getFixedSize()); } } @@ -383,7 +384,7 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { BigInteger asBigInteger = (BigInteger) super.decode(encoded, offset); return DataWord.valueOf(asBigInteger.toByteArray()); } @@ -434,14 +435,14 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { return decodeInt(encoded, offset); } - public static BigInteger decodeInt(byte[] encoded, int offset) { + public static BigInteger decodeInt(BytesSlice encoded, int offset) { // This is here because getGasForData might send an empty payload which will produce an exception // But currently the bridge would return the cost of RELEASE_BTC in this situation - if (encoded.length == 0) { + if (encoded.length() == 0) { return BigInteger.ZERO; } return new BigInteger(Utils.safeCopyOfRange(encoded, offset, INT_SIZE)); @@ -474,7 +475,7 @@ public byte[] encode(Object value) { } @Override - public Object decode(byte[] encoded, int offset) { + public Object decode(BytesSlice encoded, int offset) { return Boolean.valueOf(((Number) super.decode(encoded, offset)).intValue() != 0); } } diff --git a/rskj-core/src/main/java/org/ethereum/util/Utils.java b/rskj-core/src/main/java/org/ethereum/util/Utils.java index 0738853cc32..5f1682cea68 100644 --- a/rskj-core/src/main/java/org/ethereum/util/Utils.java +++ b/rskj-core/src/main/java/org/ethereum/util/Utils.java @@ -19,6 +19,7 @@ package org.ethereum.util; +import co.rsk.core.types.bytes.BytesSlice; import org.bouncycastle.util.encoders.DecoderException; import org.bouncycastle.util.encoders.Hex; import java.lang.reflect.Array; @@ -206,15 +207,15 @@ public static boolean contains(List list, byte[] valueToFind) { return false; } - public static void validateArrayAllegedSize(byte[] data, int offset, int allegedSize) { - if (data.length < Math.addExact(allegedSize, offset)) { + public static void validateArrayAllegedSize(BytesSlice data, int offset, int allegedSize) { + if (data.length() < Math.addExact(allegedSize, offset)) { throw new IllegalArgumentException("The specified size exceeds the size of the payload"); } } - public static byte[] safeCopyOfRange(byte[] data, int from, int size) { + public static byte[] safeCopyOfRange(BytesSlice data, int from, int size) { validateArrayAllegedSize(data, from, size); - return Arrays.copyOfRange(data, from, from + size); + return data.copyArrayOfRange(from, from + size); } public static boolean isDecimalString(String s) { diff --git a/rskj-core/src/test/java/co/rsk/core/CallTransactionTest.java b/rskj-core/src/test/java/co/rsk/core/CallTransactionTest.java index e3320bf3380..4fe0c0c870b 100644 --- a/rskj-core/src/test/java/co/rsk/core/CallTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/core/CallTransactionTest.java @@ -18,6 +18,7 @@ package co.rsk.core; +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.util.encoders.Hex; import org.ethereum.core.CallTransaction; import org.ethereum.solidity.SolidityType; @@ -115,7 +116,7 @@ void decodeString() { // string 104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - Assertions.assertEquals("hello", type.decode(toDecode)); + Assertions.assertEquals("hello", type.decode(Bytes.of(toDecode))); } @Test diff --git a/rskj-core/src/test/java/co/rsk/core/TransactionTest.java b/rskj-core/src/test/java/co/rsk/core/TransactionTest.java index 9d357c6fe38..a5a208c8854 100644 --- a/rskj-core/src/test/java/co/rsk/core/TransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/core/TransactionTest.java @@ -19,6 +19,7 @@ package co.rsk.core; import co.rsk.config.TestSystemProperties; +import co.rsk.core.types.bytes.Bytes; import co.rsk.peg.BridgeSupportFactory; import co.rsk.peg.RepositoryBtcBlockStoreWithCache; import co.rsk.peg.constants.BridgeMainNetConstants; @@ -282,7 +283,7 @@ protected ProgramResult executeTransaction() { track.rollback(); - System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(executor.getResult().getHReturn())); + System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(Bytes.of(executor.getResult().getHReturn()))); } // now executing the JSON test transaction diff --git a/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java b/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java index 7374a146754..05c4719b63c 100644 --- a/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/TransactionTest.java @@ -23,6 +23,7 @@ import co.rsk.core.RskAddress; import co.rsk.core.TransactionExecutorFactory; import co.rsk.core.genesis.TestGenesisLoader; +import co.rsk.core.types.bytes.Bytes; import co.rsk.crypto.Keccak256; import co.rsk.db.HashMapBlocksIndex; import co.rsk.db.MutableTrieImpl; @@ -504,7 +505,7 @@ protected ProgramResult executeTransaction() { track.rollback(); - System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(executor.getResult().getHReturn())); + System.out.println("Return value: " + new CallTransaction.IntType("uint").decode(Bytes.of(executor.getResult().getHReturn()))); } // now executing the JSON test transaction diff --git a/rskj-core/src/test/java/org/ethereum/solidity/SolidityTypeTest.java b/rskj-core/src/test/java/org/ethereum/solidity/SolidityTypeTest.java index 23258e97cfd..36659028521 100644 --- a/rskj-core/src/test/java/org/ethereum/solidity/SolidityTypeTest.java +++ b/rskj-core/src/test/java/org/ethereum/solidity/SolidityTypeTest.java @@ -1,5 +1,6 @@ package org.ethereum.solidity; +import co.rsk.core.types.bytes.Bytes; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -16,7 +17,7 @@ void TestDynamicArrayTypeWithInvalidDataSize() { input[31] = 0x10; // Indicating we should have 16 elements in the array should fail try { - dat.decode(input, 0); + dat.decode(Bytes.of(input), 0); Assertions.fail(); } catch (IllegalArgumentException e) { // Only acceptable exception @@ -35,7 +36,7 @@ void TestDynamicArrayTypeWithInvalidDataSize() { input[97] = 0x69; try { - dat.decode(input, 0); + dat.decode(Bytes.of(input), 0); Assertions.fail(); } catch (IllegalArgumentException e) { // Only acceptable exception @@ -60,7 +61,7 @@ void TestDynamicArrayTypeWithInvalidDataSize() { input[163] = 0x69; try { - dat.decode(input, 0); + dat.decode(Bytes.of(input), 0); Assertions.fail(); } catch (IllegalArgumentException e) { // Only acceptable exception @@ -96,7 +97,7 @@ void TestDynamicArrayTypeWithValidDataSize() { input[229] = 0x68; input[230] = 0x75; - Object[] ret = (Object[])dat.decode(input, 0); + Object[] ret = (Object[])dat.decode(Bytes.of(input), 0); Assertions.assertEquals(3, ret.length); Assertions.assertTrue(ret[0].toString().contains("hi")); Assertions.assertTrue(ret[1].toString().contains("ih")); @@ -114,7 +115,7 @@ void TestStaticArrayTypeWithInvalidSize() { // the actual data input[32] = 0x68; input[33] = 0x69; - dat.decode(input, 0); + dat.decode(Bytes.of(input), 0); Assertions.fail("should have failed"); } catch (IllegalArgumentException e) { @@ -130,7 +131,7 @@ void TestStaticArrayTypeWithInvalidSize() { // the actual data input[32] = 0x68; input[33] = 0x69; - dat.decode(input, 0); + dat.decode(Bytes.of(input), 0); Assertions.fail("should have failed"); } catch (IllegalArgumentException e) { @@ -149,7 +150,7 @@ void TestStaticArrayType() { input[32] = 0x68; input[33] = 0x69; - Object[] ret = dat.decode(input, 0); + Object[] ret = dat.decode(Bytes.of(input), 0); Assertions.assertEquals(1, ret.length); Assertions.assertTrue(ret[0].toString().contains("hi")); } @@ -159,7 +160,7 @@ void TestIntType() { // Should fail, the array is smaller than the offset we define try { byte[] input = new byte[] {0x4f, 0x4f}; - SolidityType.IntType.decodeInt(input, 12); + SolidityType.IntType.decodeInt(Bytes.of(input), 12); Assertions.fail("should have failed to deserialize the array"); } catch (IllegalArgumentException e) { // Only acceptable exception @@ -168,11 +169,11 @@ void TestIntType() { // Should get a valid number input[31] = 0x01; - BigInteger value = SolidityType.IntType.decodeInt(input, 0); + BigInteger value = SolidityType.IntType.decodeInt(Bytes.of(input), 0); Assertions.assertEquals(1, value.intValue()); // Should get a valid number - value = SolidityType.IntType.decodeInt(input, 32); + value = SolidityType.IntType.decodeInt(Bytes.of(input), 32); Assertions.assertEquals(0, value.intValue()); } diff --git a/rskj-core/src/test/java/org/ethereum/util/UtilsTest.java b/rskj-core/src/test/java/org/ethereum/util/UtilsTest.java index a42711cb4ec..bb301d035e1 100644 --- a/rskj-core/src/test/java/org/ethereum/util/UtilsTest.java +++ b/rskj-core/src/test/java/org/ethereum/util/UtilsTest.java @@ -19,12 +19,11 @@ package org.ethereum.util; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.math.BigInteger; @@ -112,7 +111,7 @@ void testAddressStringToBytes() { @Test void TestValidateArrayWithOffset() { - byte[] data = new byte[10]; + Bytes data = Bytes.of(new byte[10]); // Valid indices Utils.validateArrayAllegedSize(data, 1, 0); Utils.validateArrayAllegedSize(data, 8, 1); @@ -137,13 +136,13 @@ void TestValidateArrayWithOffset() { // Only type of exception expected } try { - Utils.validateArrayAllegedSize(new byte[0], 1, 0); + Utils.validateArrayAllegedSize(Bytes.of(new byte[0]), 1, 0); fail("should have failed"); } catch (IllegalArgumentException e) { // Only type of exception expected } - byte[] noData = null; + Bytes noData = null; try { Utils.validateArrayAllegedSize(noData, 1, 1); fail("should have failed"); @@ -156,33 +155,33 @@ void TestValidateArrayWithOffset() { @Test void TestSafeCopyOfRangeWithValidArrays() { - Assertions.assertDoesNotThrow(() -> Utils.safeCopyOfRange(new byte[2], 0, 1)); - Assertions.assertDoesNotThrow(() -> Utils.safeCopyOfRange(new byte[100], 97, 3)); - Assertions.assertDoesNotThrow(() -> Utils.safeCopyOfRange(new byte[0], 0, 0)); + Assertions.assertDoesNotThrow(() -> Utils.safeCopyOfRange(Bytes.of(new byte[2]), 0, 1)); + Assertions.assertDoesNotThrow(() -> Utils.safeCopyOfRange(Bytes.of(new byte[100]), 97, 3)); + Assertions.assertDoesNotThrow(() -> Utils.safeCopyOfRange(Bytes.of(new byte[0]), 0, 0)); } @Test void TestSafeCopyOfRangeWithInvalidArrays() { try { - Utils.safeCopyOfRange(new byte[2], 1, 2); + Utils.safeCopyOfRange(Bytes.of(new byte[2]), 1, 2); fail("should have failed"); } catch (IllegalArgumentException e){ } try { - Utils.safeCopyOfRange(new byte[100], 98, 3); + Utils.safeCopyOfRange(Bytes.of(new byte[100]), 98, 3); fail("should have failed"); } catch (IllegalArgumentException e){ } try { - Utils.safeCopyOfRange(new byte[0], 0, 1); + Utils.safeCopyOfRange(Bytes.of(new byte[0]), 0, 1); fail("should have failed"); } catch (IllegalArgumentException e){ } try { - Utils.safeCopyOfRange(new byte[0], 1, 0); + Utils.safeCopyOfRange(Bytes.of(new byte[0]), 1, 0); fail("should have failed"); } catch (IllegalArgumentException e){ From 286968078fcb8962069069dd8ff8f14185e25597 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Fri, 26 Jul 2024 18:03:17 +0300 Subject: [PATCH 08/22] perf: improve decoding in RLP --- .../src/main/java/org/ethereum/util/RLP.java | 176 ++++-------------- .../main/java/org/ethereum/util/RLPItem.java | 21 ++- .../main/java/org/ethereum/util/RLPList.java | 9 +- .../test/java/org/ethereum/util/RLPTest.java | 99 ++++++++++ 4 files changed, 154 insertions(+), 151 deletions(-) diff --git a/rskj-core/src/main/java/org/ethereum/util/RLP.java b/rskj-core/src/main/java/org/ethereum/util/RLP.java index 5caf38f071f..4a0e1728baa 100644 --- a/rskj-core/src/main/java/org/ethereum/util/RLP.java +++ b/rskj-core/src/main/java/org/ethereum/util/RLP.java @@ -22,7 +22,10 @@ import co.rsk.core.BlockDifficulty; import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; +import co.rsk.core.types.bytes.BytesSlice; import co.rsk.util.RLPException; +import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang3.tuple.Pair; import org.bouncycastle.util.BigIntegers; import org.ethereum.db.ByteArrayWrapper; @@ -100,7 +103,8 @@ public class RLP { * byte with value 0x80 plus the length of the string followed by the * string. The range of the first byte is thus [0x80, 0xb7]. */ - private static final int OFFSET_SHORT_ITEM = 0x80; + @VisibleForTesting + static final int OFFSET_SHORT_ITEM = 0x80; /** * [0xb7] @@ -111,7 +115,8 @@ public class RLP { * \xb9\x04\x00 followed by the string. The range of the first byte is thus * [0xb8, 0xbf]. */ - private static final int OFFSET_LONG_ITEM = 0xb7; + @VisibleForTesting + static final int OFFSET_LONG_ITEM = 0xb7; /** * [0xc0] @@ -121,7 +126,8 @@ public class RLP { * of the RLP encodings of the items. The range of the first byte is thus * [0xc0, 0xf7]. */ - private static final int OFFSET_SHORT_LIST = 0xc0; + @VisibleForTesting + static final int OFFSET_SHORT_LIST = 0xc0; /** * [0xf7] @@ -131,29 +137,14 @@ public class RLP { * followed by the concatenation of the RLP encodings of the items. The * range of the first byte is thus [0xf8, 0xff]. */ - private static final int OFFSET_LONG_LIST = 0xf7; + @VisibleForTesting + static final int OFFSET_LONG_LIST = 0xf7; /* ****************************************************** * DECODING * * ******************************************************/ - private static byte decodeOneByteItem(byte[] data, int index) { - // null item - if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM) { - return (byte) (data[index] - OFFSET_SHORT_ITEM); - } - // single byte item - if ((data[index] & 0xFF) < OFFSET_SHORT_ITEM) { - return data[index]; - } - // single byte item - if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM + 1) { - return data[index + 1]; - } - return 0; - } - public static int decodeInt(byte[] data, int index) { // NOTE: there are two ways zero can be encoded - 0x00 and OFFSET_SHORT_ITEM @@ -239,108 +230,7 @@ public static int getNextElementIndex(byte[] payload, int pos) { return -1; } - /** - * Get exactly one message payload - */ - public static void fullTraverse(byte[] msgData, int level, int startPos, - int endPos, int levelToIndex, Queue index) { - - try { - - if (msgData == null || msgData.length == 0) { - return; - } - int pos = startPos; - - while (pos < endPos) { - - if (level == levelToIndex) { - index.add(pos); - } - - // It's a list with a payload more than 55 bytes - // data[0] - 0xF7 = how many next bytes allocated - // for the length of the list - if ((msgData[pos] & 0xFF) >= OFFSET_LONG_LIST) { - - byte lengthOfLength = (byte) (msgData[pos] - OFFSET_LONG_LIST); - int length = calcLength(lengthOfLength, msgData, pos); - - // now we can parse an item for data[1]..data[length] - System.out.println("-- level: [" + level - + "] Found big list length: " + length); - - fullTraverse(msgData, level + 1, pos + lengthOfLength + 1, - pos + lengthOfLength + length, levelToIndex, index); - - pos += lengthOfLength + length + 1; - continue; - } - // It's a list with a payload less than 55 bytes - if ((msgData[pos] & 0xFF) >= OFFSET_SHORT_LIST - && (msgData[pos] & 0xFF) < OFFSET_LONG_LIST) { - - byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_LIST); - - System.out.println("-- level: [" + level - + "] Found small list length: " + length); - - fullTraverse(msgData, level + 1, pos + 1, pos + length + 1, - levelToIndex, index); - - pos += 1 + length; - continue; - } - // It's an item with a payload more than 55 bytes - // data[0] - 0xB7 = how much next bytes allocated for - // the length of the string - if ((msgData[pos] & 0xFF) >= OFFSET_LONG_ITEM - && (msgData[pos] & 0xFF) < OFFSET_SHORT_LIST) { - - byte lengthOfLength = (byte) (msgData[pos] - OFFSET_LONG_ITEM); - int length = calcLength(lengthOfLength, msgData, pos); - - // now we can parse an item for data[1]..data[length] - System.out.println("-- level: [" + level - + "] Found big item length: " + length); - pos += lengthOfLength + length + 1; - - continue; - } - // It's an item less than 55 bytes long, - // data[0] - 0x80 == length of the item - if ((msgData[pos] & 0xFF) > OFFSET_SHORT_ITEM - && (msgData[pos] & 0xFF) < OFFSET_LONG_ITEM) { - - byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_ITEM); - - System.out.println("-- level: [" + level - + "] Found small item length: " + length); - pos += 1 + length; - continue; - } - // null item - if ((msgData[pos] & 0xFF) == OFFSET_SHORT_ITEM) { - System.out.println("-- level: [" + level - + "] Found null item: "); - pos += 1; - continue; - } - // single byte item - if ((msgData[pos] & 0xFF) < OFFSET_SHORT_ITEM) { - System.out.println("-- level: [" + level - + "] Found single item: "); - pos += 1; - continue; - } - } - } catch (Throwable th) { - throw new RuntimeException("RLP wrong encoding", - th.fillInStackTrace()); - } - } - - private static int calcLength(int lengthOfLength, byte[] msgData, int pos) { + static int calcLength(int lengthOfLength, byte[] msgData, int pos) { byte pow = (byte) (lengthOfLength - 1); int length = 0; for (int i = 1; i <= lengthOfLength; ++i) { @@ -350,6 +240,11 @@ private static int calcLength(int lengthOfLength, byte[] msgData, int pos) { return length; } + @Nonnull + public static ArrayList decode2(@CheckForNull byte[] msgData) { + return decode2(Bytes.of(msgData)); + } + /** * Parse wire byte[] message into RLP elements * @@ -358,14 +253,14 @@ private static int calcLength(int lengthOfLength, byte[] msgData, int pos) { * - outcome of recursive RLP structure */ @Nonnull - public static ArrayList decode2(@CheckForNull byte[] msgData) { + public static ArrayList decode2(@CheckForNull BytesSlice msgData) { ArrayList elements = new ArrayList<>(); if (msgData == null) { return elements; } - int tlength = msgData.length; + int tlength = msgData.length(); int position = 0; while (position < tlength) { @@ -382,11 +277,11 @@ public static RLPElement decodeFirstElement(@CheckForNull byte[] msgData, int po return null; } - return decodeElement(msgData, position).getKey(); + return decodeElement(Bytes.of(msgData), position).getKey(); } - private static Pair decodeElement(byte[] msgData, int position) { // NOSONAR - int b0 = msgData[position] & 0xff; + private static Pair decodeElement(BytesSlice msgData, int position) { + int b0 = msgData.byteAt(position) & 0xff; if (b0 >= 192) { int length; @@ -403,24 +298,23 @@ private static Pair decodeElement(byte[] msgData, int posit int endingIndex = safeAdd(length, position); - if (endingIndex > msgData.length) { + if (endingIndex > msgData.length()) { throw new RLPException("The RLP byte array doesn't have enough space to hold an element with the specified length"); } - byte[] bytes = Arrays.copyOfRange(msgData, position, endingIndex); - RLPList list = new RLPList(bytes, offset); + RLPList list = new RLPList(msgData.slice(position, endingIndex), offset); return Pair.of(list, endingIndex); } if (b0 == EMPTY_MARK) { - return Pair.of(new RLPItem(ByteUtil.EMPTY_BYTE_ARRAY), position + 1); + return Pair.of(new RLPItem(Bytes.of(ByteUtil.EMPTY_BYTE_ARRAY)), position + 1); } if (b0 < EMPTY_MARK) { byte[] data = new byte[1]; - data[0] = msgData[position]; - return Pair.of(new RLPItem(data), position + 1); + data[0] = msgData.byteAt(position); + return Pair.of(new RLPItem(Bytes.of(data)), position + 1); } int length; @@ -439,15 +333,13 @@ private static Pair decodeElement(byte[] msgData, int posit } int endingIndex = position + offset + length; - if ( endingIndex < 0 || endingIndex > msgData.length) { + if (endingIndex < 0 || endingIndex > msgData.length()) { throw new RLPException("The RLP byte array doesn't have enough space to hold an element with the specified length"); } - byte[] decoded = new byte[length]; - - System.arraycopy(msgData, position + offset, decoded, 0, length); - - return Pair.of(new RLPItem(decoded), position + offset + length); + int from = position + offset; + int to = from + length; + return Pair.of(new RLPItem(msgData.slice(from, to)), to); } private static int safeAdd(int a, int b) { @@ -458,8 +350,8 @@ private static int safeAdd(int a, int b) { } } - private static int bytesToLength(byte[] bytes, int position, int size) { - if (position + size > bytes.length) { + private static int bytesToLength(BytesSlice bytes, int position, int size) { + if (position + size > bytes.length()) { throw new RLPException("The length of the RLP item length can't possibly fit the data byte array"); } @@ -467,7 +359,7 @@ private static int bytesToLength(byte[] bytes, int position, int size) { for (int k = 0; k < size; k++) { length <<= 8; - length += bytes[position + k] & 0xff; + length += bytes.byteAt(position + k) & 0xff; } if (length < 0) { diff --git a/rskj-core/src/main/java/org/ethereum/util/RLPItem.java b/rskj-core/src/main/java/org/ethereum/util/RLPItem.java index 2ca8f7f81e3..49ce56965f1 100644 --- a/rskj-core/src/main/java/org/ethereum/util/RLPItem.java +++ b/rskj-core/src/main/java/org/ethereum/util/RLPItem.java @@ -19,29 +19,40 @@ package org.ethereum.util; +import co.rsk.core.types.bytes.BytesSlice; + /** * @author Roman Mandeleil * @since 21.04.14 */ public class RLPItem implements RLPElement { - private final byte[] rlpData; + private final BytesSlice rlpData; - public RLPItem(byte[] rlpData) { + public RLPItem(BytesSlice rlpData) { this.rlpData = rlpData; } + protected BytesSlice getRLPBytes() { + if (rlpData.length() == 0) { + return null; + } + + return rlpData; + } + @Override public byte[] getRLPData() { - if (rlpData.length == 0) { + BytesSlice rlpBytes = getRLPBytes(); + if (rlpBytes == null) { return null; } - return rlpData; + return rlpBytes.copyArray(); } @Override public byte[] getRLPRawData() { - return rlpData; + return rlpData.copyArray(); } } diff --git a/rskj-core/src/main/java/org/ethereum/util/RLPList.java b/rskj-core/src/main/java/org/ethereum/util/RLPList.java index c4a5f035f53..e9ec39a2dc0 100644 --- a/rskj-core/src/main/java/org/ethereum/util/RLPList.java +++ b/rskj-core/src/main/java/org/ethereum/util/RLPList.java @@ -19,7 +19,8 @@ package org.ethereum.util; -import java.util.Arrays; +import co.rsk.core.types.bytes.BytesSlice; + import java.util.List; /** @@ -30,7 +31,7 @@ public class RLPList extends RLPItem implements RLPElement { private List elements; private final int offset; - public RLPList(byte[] rlpData, int offset) { + public RLPList(BytesSlice rlpData, int offset) { super(rlpData); this.offset = offset; } @@ -52,8 +53,8 @@ private void checkElements() { return; } - byte[] bytes = this.getRLPData(); - byte[] content = Arrays.copyOfRange(bytes, offset, bytes.length); + BytesSlice bytes = getRLPBytes(); + BytesSlice content = bytes.slice(offset, bytes.length()); this.elements = RLP.decode2(content); } diff --git a/rskj-core/src/test/java/org/ethereum/util/RLPTest.java b/rskj-core/src/test/java/org/ethereum/util/RLPTest.java index 58bbaa5218f..6c5b9d3a2df 100644 --- a/rskj-core/src/test/java/org/ethereum/util/RLPTest.java +++ b/rskj-core/src/test/java/org/ethereum/util/RLPTest.java @@ -1071,4 +1071,103 @@ void testIncorrectDecodeInt(){ byte[] payload = {(byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0x84, (byte) 0x00, (byte) 0x0f, (byte) 0xab}; assertThrows(RLPException.class, () -> RLP.decodeInt(payload, 3)); } + + /** + * Get exactly one message payload + */ + private static void fullTraverse(byte[] msgData, int level, int startPos, int endPos, int levelToIndex, Queue index) { + try { + + if (msgData == null || msgData.length == 0) { + return; + } + int pos = startPos; + + while (pos < endPos) { + + if (level == levelToIndex) { + index.add(pos); + } + + // It's a list with a payload more than 55 bytes + // data[0] - 0xF7 = how many next bytes allocated + // for the length of the list + if ((msgData[pos] & 0xFF) >= OFFSET_LONG_LIST) { + + byte lengthOfLength = (byte) (msgData[pos] - OFFSET_LONG_LIST); + int length = calcLength(lengthOfLength, msgData, pos); + + // now we can parse an item for data[1]..data[length] + System.out.println("-- level: [" + level + + "] Found big list length: " + length); + + fullTraverse(msgData, level + 1, pos + lengthOfLength + 1, + pos + lengthOfLength + length, levelToIndex, index); + + pos += lengthOfLength + length + 1; + continue; + } + // It's a list with a payload less than 55 bytes + if ((msgData[pos] & 0xFF) >= OFFSET_SHORT_LIST + && (msgData[pos] & 0xFF) < OFFSET_LONG_LIST) { + + byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_LIST); + + System.out.println("-- level: [" + level + + "] Found small list length: " + length); + + fullTraverse(msgData, level + 1, pos + 1, pos + length + 1, + levelToIndex, index); + + pos += 1 + length; + continue; + } + // It's an item with a payload more than 55 bytes + // data[0] - 0xB7 = how much next bytes allocated for + // the length of the string + if ((msgData[pos] & 0xFF) >= OFFSET_LONG_ITEM + && (msgData[pos] & 0xFF) < OFFSET_SHORT_LIST) { + + byte lengthOfLength = (byte) (msgData[pos] - OFFSET_LONG_ITEM); + int length = calcLength(lengthOfLength, msgData, pos); + + // now we can parse an item for data[1]..data[length] + System.out.println("-- level: [" + level + + "] Found big item length: " + length); + pos += lengthOfLength + length + 1; + + continue; + } + // It's an item less than 55 bytes long, + // data[0] - 0x80 == length of the item + if ((msgData[pos] & 0xFF) > OFFSET_SHORT_ITEM + && (msgData[pos] & 0xFF) < OFFSET_LONG_ITEM) { + + byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_ITEM); + + System.out.println("-- level: [" + level + + "] Found small item length: " + length); + pos += 1 + length; + continue; + } + // null item + if ((msgData[pos] & 0xFF) == OFFSET_SHORT_ITEM) { + System.out.println("-- level: [" + level + + "] Found null item: "); + pos += 1; + continue; + } + // single byte item + if ((msgData[pos] & 0xFF) < OFFSET_SHORT_ITEM) { + System.out.println("-- level: [" + level + + "] Found single item: "); + pos += 1; + continue; + } + } + } catch (Throwable th) { + throw new RuntimeException("RLP wrong encoding", + th.fillInStackTrace()); + } + } } From c48edca96287f4c0f649c182bd62044f064d73be Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Fri, 9 Aug 2024 15:32:52 +0300 Subject: [PATCH 09/22] perf: refactor some tests --- .../rsk/core/types/bytes/BytesSliceTest.java | 42 ++++++++++++++++--- .../co/rsk/core/types/bytes/BytesTest.java | 19 +++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java index 001aee51f35..5abc98a8838 100644 --- a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java @@ -29,7 +29,7 @@ class BytesSliceTest { @Test - void testBytesLength() { + void testBytesLength() { assertEquals(0, Bytes.of(new byte[]{}).slice(0, 0).length()); assertEquals(0, Bytes.of(new byte[]{1}).slice(0, 0).length()); assertEquals(1, Bytes.of(new byte[]{1}).slice(0, 1).length()); @@ -41,16 +41,20 @@ void testBytesLength() { @Test void testBytesAt() { - assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{}).slice(0, 0).byteAt(0)); - assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).slice(0, 1).byteAt(1)); - assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).slice(0, 1).byteAt(-1)); - assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1,2,3}).slice(1, 2).byteAt(1)); assertEquals(1, Bytes.of(new byte[]{1}).slice(0, 1).byteAt(0)); assertEquals(2, Bytes.of(new byte[]{1,2}).slice(0, 2).byteAt(1)); assertEquals(2, Bytes.of(new byte[]{1,2,3}).slice(1, 2).byteAt(0)); assertEquals(4, Bytes.of(new byte[]{1,2,3,4}).slice(2, 4).byteAt(1)); } + @Test + void testBytesAtIndexOutOfBoundsException() { + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{}).slice(0, 0).byteAt(0)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).slice(0, 1).byteAt(1)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1}).slice(0, 1).byteAt(-1)); + assertThrows(IndexOutOfBoundsException.class, () -> Bytes.of(new byte[]{1,2,3}).slice(1, 2).byteAt(1)); + } + @Test void testBytesSliceArraycopy() { checkArraycopy((src, srcPos, dest, destPos, length) -> Bytes.of((byte[]) src).slice(1, 4).arraycopy(srcPos, (byte[]) dest, destPos, length)); @@ -115,6 +119,14 @@ void testEmptySlice() { } private static void checkArraycopy(Functions.Action5 fun) { + /* + 'fun' signature: + @src – the source array. + @srcPos – starting position in the source array. + @dest – the destination array. + @destPos – starting position in the destination data. + @length – the number of array elements to be copied. + */ byte[] dest = new byte[3]; byte[] origin = new byte[]{1,2,3,4,5}; @@ -139,6 +151,26 @@ private static void checkArraycopy(Functions.Action5 void checkCopyOfRange(Functions.Function3 fun, Functions.Function3 slicer) { + /* + 'fun' signature: + @original – the array from which a range is to be copied + @from – the initial index of the range to be copied, inclusive + @to – the final index of the range to be copied, exclusive. (This index may lie outside the array.) + + @return a new array containing the specified range from the original array, truncated or padded with zeros + to obtain the required length + */ + + /* + 'slicer' signature: + @original – the array from which a range is to be copied + @from – the initial index of the range to be copied, inclusive + @to – the final index of the range to be copied, exclusive. (This index may lie outside the array.) + + @return a new entity containing the specified range from the original array, truncated or padded with zeros + to obtain the required length + */ + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; assertEquals(bArray.length, fun.apply(slicer.apply(bArray, 0, 6), 0, 6).length); diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java index 7cce5532f17..dd28d5b2e63 100644 --- a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java @@ -160,6 +160,15 @@ void testEmptyBytesToString() { } private static void checkArraycopy(Functions.Action5 fun) { + /* + 'fun' signature: + @src – the source array. + @srcPos – starting position in the source array. + @dest – the destination array. + @destPos – starting position in the destination data. + @length – the number of array elements to be copied. + */ + byte[] dest = new byte[5]; byte[] origin = new byte[]{1,2,3,4,5}; @@ -183,6 +192,16 @@ private static void checkArraycopy(Functions.Action5 fun) { + /* + 'fun' signature: + @original – the array from which a range is to be copied + @from – the initial index of the range to be copied, inclusive + @to – the final index of the range to be copied, exclusive. (This index may lie outside the array.) + + @return a new array containing the specified range from the original array, truncated or padded with zeros + to obtain the required length + */ + byte[] bArray = new byte[]{1, 2, 3, 4, 5}; assertEquals(bArray.length, fun.apply(bArray, 0, 5).length); From fa2eb47c355e84dd51ae5079893fdec45f768031 Mon Sep 17 00:00:00 2001 From: fmacleal <157636304+fmacleal@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:25:57 +0200 Subject: [PATCH 10/22] Update rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nazaret García Revetria --- .../src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java index 5abc98a8838..cdea74403bd 100644 --- a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java @@ -29,7 +29,7 @@ class BytesSliceTest { @Test - void testBytesLength() { + void testBytesLength() { assertEquals(0, Bytes.of(new byte[]{}).slice(0, 0).length()); assertEquals(0, Bytes.of(new byte[]{1}).slice(0, 0).length()); assertEquals(1, Bytes.of(new byte[]{1}).slice(0, 1).length()); From 551df4264ee24f296407e5e7a275e8dbfcf135e7 Mon Sep 17 00:00:00 2001 From: fmacleal <157636304+fmacleal@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:15:09 +0100 Subject: [PATCH 11/22] Adding transient storage maps with TLOAD/TSTORE implementation (#2801) * Adding the structure for transient storage opcodes - Finishing test validation for basic scenarios of TLOAD/TSTORE * Refactor from code to get advantage from the MutableRepository - In order to get advantage from the whole flow of tracking, rollback and commits already present in the MutableRepository. We refactored a bit the logic of transient storage, now it's simpler. * Adding more tests defined on the EIP-1153 spec * Adding tests for the different create contexts EIP1153 * Addressing comments from review * Adding more scenarios of test with dynamic execution context --- .../java/org/ethereum/core/Repository.java | 2 +- .../ethereum/core/TransientRepository.java | 40 +++ .../org/ethereum/db/MutableRepository.java | 76 ++++- .../src/main/java/org/ethereum/vm/VM.java | 53 +++- .../java/org/ethereum/vm/program/Program.java | 9 +- .../java/org/ethereum/vm/program/Storage.java | 28 ++ .../vm/opcode/TransientStorageDslTest.java | 294 ++++++++++++++++-- .../rsk/vm/opcode/TransientStorageTest.java | 23 ++ .../upgrades/ActivationConfigTest.java | 3 +- ...ctor_and_deploy_code_v0_create_context.txt | 142 +++++++++ ...ctor_and_deploy_code_v1_create_context.txt | 146 +++++++++ .../dynamic_execution_context_simple.txt | 147 +++++++++ ...dynamic_execution_context_with_invalid.txt | 166 ++++++++++ .../dynamic_execution_context_with_revert.txt | 166 ++++++++++ ..._execution_context_with_stack_overflow.txt | 173 +++++++++++ .../eip1153_basic_tests.txt | 223 +++++++++++++ ...tructor_and_deploy_code_create_context.txt | 142 +++++++++ .../no_constructor_code_create_context.txt | 137 ++++++++ .../only_constructor_code_create_context.txt | 133 ++++++++ .../tload_tstore_basic_contract.txt | 124 -------- .../tload_tstore_basic_tests.txt | 246 +++++++++++++++ 21 files changed, 2299 insertions(+), 174 deletions(-) create mode 100644 rskj-core/src/main/java/org/ethereum/core/TransientRepository.java create mode 100644 rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/eip1153_basic_tests.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt delete mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt diff --git a/rskj-core/src/main/java/org/ethereum/core/Repository.java b/rskj-core/src/main/java/org/ethereum/core/Repository.java index 0cf1bfa183d..38b10af2f68 100644 --- a/rskj-core/src/main/java/org/ethereum/core/Repository.java +++ b/rskj-core/src/main/java/org/ethereum/core/Repository.java @@ -27,7 +27,7 @@ import java.math.BigInteger; -public interface Repository extends RepositorySnapshot { +public interface Repository extends RepositorySnapshot, TransientRepository { Trie getTrie(); /** diff --git a/rskj-core/src/main/java/org/ethereum/core/TransientRepository.java b/rskj-core/src/main/java/org/ethereum/core/TransientRepository.java new file mode 100644 index 00000000000..eee1f29d4ab --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/core/TransientRepository.java @@ -0,0 +1,40 @@ +/* + * 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 org.ethereum.core; + +import co.rsk.core.RskAddress; +import org.ethereum.vm.DataWord; + +import javax.annotation.Nullable; + +public interface TransientRepository { + + void addTransientStorageRow(RskAddress addr, DataWord key, DataWord value); + + void addTransientStorageBytes(RskAddress addr, DataWord key, byte[] value); + + void clearTransientStorage(); + + @Nullable + DataWord getTransientStorageValue(RskAddress addr, DataWord key); + + @Nullable + byte[] getTransientStorageBytes(RskAddress addr, DataWord key); +} \ No newline at end of file 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 42dd7336b25..643d778f937 100644 --- a/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java +++ b/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java @@ -25,19 +25,29 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; import co.rsk.db.MutableTrieImpl; -import co.rsk.trie.*; +import co.rsk.trie.IterationElement; +import co.rsk.trie.MutableTrie; +import co.rsk.trie.Trie; +import co.rsk.trie.TrieKeySlice; +import co.rsk.trie.TrieStore; +import co.rsk.trie.TrieStoreImpl; import com.google.common.annotations.VisibleForTesting; import org.ethereum.core.AccountState; import org.ethereum.core.Repository; import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.Keccak256Helper; +import org.ethereum.datasource.HashMapDB; import org.ethereum.vm.DataWord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.math.BigInteger; -import java.util.*; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; public class MutableRepository implements Repository { private static final Logger logger = LoggerFactory.getLogger("repository"); @@ -47,21 +57,32 @@ public class MutableRepository implements Repository { private final TrieKeyMapper trieKeyMapper; private final MutableTrie mutableTrie; + private MutableTrie transientTrie; private final IReadWrittenKeysTracker tracker; public MutableRepository(TrieStore trieStore, Trie trie) { - this(new MutableTrieImpl(trieStore, trie)); + this(new MutableTrieImpl(trieStore, trie), new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie())); } public MutableRepository(MutableTrie mutableTrie) { + this(mutableTrie, new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie())); + } + + public MutableRepository(MutableTrie mutableTrie, IReadWrittenKeysTracker tracker) { + this(mutableTrie, new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie()), tracker); + } + + public MutableRepository(MutableTrie mutableTrie, MutableTrie transientTrie) { this.trieKeyMapper = new TrieKeyMapper(); this.mutableTrie = mutableTrie; + this.transientTrie = transientTrie; this.tracker = new DummyReadWrittenKeysTracker(); } - public MutableRepository(MutableTrie mutableTrie, IReadWrittenKeysTracker tracker) { + public MutableRepository(MutableTrie mutableTrie, MutableTrie transientTrie, IReadWrittenKeysTracker tracker) { this.trieKeyMapper = new TrieKeyMapper(); this.mutableTrie = mutableTrie; + this.transientTrie = transientTrie; this.tracker = tracker; } @@ -327,7 +348,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), tracker); + return new MutableRepository(new MutableTrieCache(mutableTrie), new MutableTrieCache(transientTrie), tracker); } @Override @@ -338,11 +359,13 @@ public void save() { @Override public synchronized void commit() { mutableTrie.commit(); + transientTrie.commit(); } @Override public synchronized void rollback() { mutableTrie.rollback(); + transientTrie.rollback(); } @Override @@ -406,4 +429,47 @@ private Optional internalGetValueHash(byte[] key) { tracker.addNewReadKey(new ByteArrayWrapper(key)); return mutableTrie.getValueHash(key); } + + @Override + public void addTransientStorageRow(RskAddress addr, DataWord key, DataWord value) { + addTransientStorageBytes(addr, key, value.getByteArrayForStorage()); + } + + @Override + public void addTransientStorageBytes(RskAddress addr, DataWord key, byte[] value) { + byte[] triekey = trieKeyMapper.getAccountStorageKey(addr, key); + + // Special case: if the value is an empty vector, we pass "null" which commands the trie to remove the item. + // Note that if the call comes from addStorageRow(), this method will already have replaced 0 by null, so the + // 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) { + transientTrie.put(triekey, null); + } else { + transientTrie.put(triekey, value); + } + } + + @Override + public void clearTransientStorage() { + this.transientTrie = new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie()); + } + + @Nullable + @Override + public DataWord getTransientStorageValue(RskAddress addr, DataWord key) { + byte[] value = getTransientStorageBytes(addr, key); + if (value == null) { + return null; + } + + return DataWord.valueOf(value); + } + + @Nullable + @Override + public byte[] getTransientStorageBytes(RskAddress addr, DataWord key) { + byte[] triekey = trieKeyMapper.getAccountStorageKey(addr, key); + return transientTrie.get(triekey); + } } 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 6c5adc79246..7a3b7e771fa 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -42,7 +42,20 @@ import java.util.Iterator; import java.util.List; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP103; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP120; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP125; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP140; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP150; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP151; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP152; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP169; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP191; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP398; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP412; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP446; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP90; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP91; import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; import static org.ethereum.vm.OpCode.CALL; @@ -1327,30 +1340,34 @@ else if (oldValue != null && newValue.isZero()) { } protected void doTLOAD(){ - + //TODO: Gas cost calculation will be done here and also shared contexts verifications for + // different types of calls DataWord key = program.stackPop(); - DataWord address = program.getOwnerAddress(); - if (isLogEnabled) { - logger.info("Executing TLOAD with parameters: address={} | key = {}", address, key); + logger.info("Executing TLOAD with parameters: key = {}", key); } + DataWord val = program.transientStorageLoad(key); - program.transientStorageSave(key, address); - // key could be returned to the pool, but storageLoad semantics should be checked + if (val == null) { + val = DataWord.ZERO; + } + + program.stackPush(val); + // key could be returned to the pool, but transientStorageLoad semantics should be checked // to make sure storageLoad always gets a copy, not a reference. program.step(); } protected void doTSTORE(){ - + //TODO: Gas cost calculation will be done here and also shared contexts verifications for + // different types of calls + DataWord key = program.stackPop(); DataWord value = program.stackPop(); - DataWord address = program.getOwnerAddress(); - DataWord key = DataWord.ZERO; if (isLogEnabled) { - logger.info("Executing TSTORE with parameters: address={} | key = {} | value = {}", address, key, value); + logger.info("Executing TSTORE with parameters: address={} | value = {}", key, value); } - program.transientStorageLoad(address, key, value); + program.transientStorageSave(key, value); program.step(); } @@ -1967,9 +1984,17 @@ protected void executeOpcode() { break; case OpCodes.OP_SSTORE: doSSTORE(); break; - case OpCodes.OP_TLOAD: doTLOAD(); + case OpCodes.OP_TLOAD: + if (!activations.isActive(RSKIP446)) { + throw Program.ExceptionHelper.invalidOpCode(program); + } + doTLOAD(); break; - case OpCodes.OP_TSTORE: doTSTORE(); + case OpCodes.OP_TSTORE: + if (!activations.isActive(RSKIP446)) { + throw Program.ExceptionHelper.invalidOpCode(program); + } + doTSTORE(); break; case OpCodes.OP_JUMP: doJUMP(); break; 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 2029b0c6f3b..7b417cf52fa 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 @@ -95,7 +95,6 @@ public class Program { private static final Logger logger = LoggerFactory.getLogger("VM"); private static final Logger gasLogger = LoggerFactory.getLogger("gas"); - public static final long MAX_MEMORY = (1<<30); //Max size for stack checks @@ -985,8 +984,8 @@ private void storageSave(byte[] key, byte[] val) { getStorage().addStorageRow(getOwnerRskAddress(), keyWord, valWord); } - public void transientStorageSave(DataWord key, DataWord address) { - + public void transientStorageSave(DataWord key, DataWord value) { + getStorage().addTransientStorageRow(getOwnerRskAddress(), key, value); } private RskAddress getOwnerRskAddress() { @@ -1099,8 +1098,8 @@ public DataWord storageLoad(DataWord key) { return getStorage().getStorageValue(getOwnerRskAddress(), key); } - public void transientStorageLoad(DataWord address, DataWord key, DataWord value) { - + public DataWord transientStorageLoad(DataWord key) { + return getStorage().getTransientStorageValue(getOwnerRskAddress(), key); } public DataWord getPrevHash() { diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java b/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java index 836e4d4122a..99802802b9b 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java @@ -30,6 +30,7 @@ import org.ethereum.vm.program.listener.ProgramListener; import org.ethereum.vm.program.listener.ProgramListenerAware; +import javax.annotation.Nullable; import java.math.BigInteger; import java.util.Iterator; import java.util.Set; @@ -223,4 +224,31 @@ public byte[] getRoot() { public void updateAccountState(RskAddress addr, AccountState accountState) { throw new UnsupportedOperationException(); } + + @Override + public void addTransientStorageRow(RskAddress addr, DataWord key, DataWord value) { + repository.addTransientStorageRow(addr, key, value); + } + + @Override + public void addTransientStorageBytes(RskAddress addr, DataWord key, byte[] value) { + repository.addTransientStorageBytes(addr, key, value); + } + + @Override + public void clearTransientStorage() { + repository.clearTransientStorage(); + } + + @Nullable + @Override + public DataWord getTransientStorageValue(RskAddress addr, DataWord key) { + return repository.getTransientStorageValue(addr, key); + } + + @Nullable + @Override + public byte[] getTransientStorageBytes(RskAddress addr, DataWord key) { + return repository.getTransientStorageBytes(addr, key); + } } diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index 1eec762bb0f..a7d8349adaf 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -28,62 +28,308 @@ import org.ethereum.core.Block; import org.ethereum.core.Transaction; import org.ethereum.core.TransactionReceipt; +import org.ethereum.core.util.TransactionReceiptUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.FileNotFoundException; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TransientStorageDslTest { @Test void testTransientStorageOpcodesExecutionsWithRSKIPActivated() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt"); + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); - String contractCreationTx = "txTestTransientStorageContract"; - Transaction contractTransaction = world.getTransactionByName("txTestTransientStorageContract"); - assertNotNull(contractTransaction); + String mainContractTransientStorageCreationTxName = "txTestTransientStorageContract"; + assertTransactionReceiptWithStatus(world, mainContractTransientStorageCreationTxName, "b01", true); - Block bestBlock = world.getBlockByName("b03"); - Assertions.assertEquals(1, bestBlock.getTransactionsList().size()); - TransactionReceipt contractTransactionReceipt = world.getTransactionReceiptByName(contractCreationTx); + String secondaryContractTransientStorageCreationTxName = "txTestTransientStorageOtherContract"; + assertTransactionReceiptWithStatus(world, secondaryContractTransientStorageCreationTxName, "b02", true); - assertNotNull(contractTransactionReceipt); - byte[] status = contractTransactionReceipt.getStatus(); - assertNotNull(status); - assertEquals(1, status.length); - assertEquals(1, status[0]); + String checkingOpcodesTxName = "txTestTransientStorageOpCodes"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, checkingOpcodesTxName, "b03", true); + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String checkingOpcodesTxName2 = "txTestTransientStorageOpCodesOtherValue"; + TransactionReceipt txReceipt2 = assertTransactionReceiptWithStatus(world, checkingOpcodesTxName2, "b04", true); + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt2, "OK", null)); } @Test - void testTransientStorageOpcodesExecutionsWithRSKIPDeactivated() throws FileNotFoundException, DslProcessorException { + void testTransientStorageOpcodesShareMemorySameTransaction() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String mainContractTransientStorageCreationTxName = "txTestTransientStorageContract"; + assertTransactionReceiptWithStatus(world, mainContractTransientStorageCreationTxName, "b01", true); + + String secondaryContractTransientStorageCreationTxName = "txTestTransientStorageOtherContract"; + assertTransactionReceiptWithStatus(world, secondaryContractTransientStorageCreationTxName, "b02", true); + + String checkingOpcodesTxName = "txTestTransientStorageNestedTransactionShareMemory"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, checkingOpcodesTxName, "b05", true); + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testTransientStorageOpcodesDoesntShareMemoryFromOtherContract() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String mainContractTransientStorageCreationTxName = "txTestTransientStorageContract"; + assertTransactionReceiptWithStatus(world, mainContractTransientStorageCreationTxName, "b01", true); + + String secondaryContractTransientStorageCreationTxName = "txTestTransientStorageOtherContract"; + assertTransactionReceiptWithStatus(world, secondaryContractTransientStorageCreationTxName, "b02", true); + + String checkingOpcodesTxName = "txTestTransientStorageNestedTransactionOtherContractDoesntShareMemory"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, checkingOpcodesTxName, "b06", true); + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "ERROR", new String[]{"bytes32"})); + } + + @Test + void testTransientStorageOpcodesExecutionFailsWithRSKIPDeactivated() throws FileNotFoundException, DslProcessorException { TestSystemProperties rskip446Disabled = new TestSystemProperties(rawConfig -> rawConfig.withValue("blockchain.config.hardforkActivationHeights.lovell700", ConfigValueFactory.fromAnyRef(-1)) ); - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt"); + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); World world = new World(rskip446Disabled); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); - String contractCreationTx = "txTestTransientStorageContract"; - Transaction contractTransaction = world.getTransactionByName("txTestTransientStorageContract"); - assertNotNull(contractTransaction); + String mainContractTransientStorageCreationTxName = "txTestTransientStorageContract"; + assertTransactionReceiptWithStatus(world, mainContractTransientStorageCreationTxName, "b01", true); + + String secondaryContractTransientStorageCreationTxName = "txTestTransientStorageOtherContract"; + assertTransactionReceiptWithStatus(world, secondaryContractTransientStorageCreationTxName, "b02", true); + + String checkingOpcodesTxName = "txTestTransientStorageOpCodes"; + assertTransactionReceiptWithStatus(world, checkingOpcodesTxName, "b03", false); + } + + @Test + void testTransientStorageTestsEip1153BasicScenarios() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/eip1153_basic_tests.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String mainContractTransientStorageCreationTxName = "txTestTransientStorageContract"; + assertTransactionReceiptWithStatus(world, mainContractTransientStorageCreationTxName, "b01", true); + + String txTestTloadAfterSstore = "txTestTloadAfterSstore"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTestTloadAfterSstore, "b02", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txTestTloadAfterTstore = "txTestTloadAfterTstore"; + txReceipt = assertTransactionReceiptWithStatus(world, txTestTloadAfterTstore, "b03", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txTestTransientUnsetValues = "txTestTransientUnsetValues"; + txReceipt = assertTransactionReceiptWithStatus(world, txTestTransientUnsetValues, "b04", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txTestTloadAfterTstoreIsZero = "txTestTloadAfterTstoreIsZero"; + txReceipt = assertTransactionReceiptWithStatus(world, txTestTloadAfterTstoreIsZero, "b04", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testOnlyConstructorCodeCreateContext() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + + String txOnlyConstructorCode = "txOnlyConstructorCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txOnlyConstructorCode, "b02", true); + Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testInConstructorAndCodeCreateContext() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + + String txInConstructorAndCode = "txInConstructorAndCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txInConstructorAndCode, "b02", true); + Assertions.assertEquals(6, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testAccrossConstructorAndCodeV0CreateContext() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + + String txAcrossConstructorAndCodeV0 = "txAcrossConstructorAndCodeV0"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txAcrossConstructorAndCodeV0, "b02", true); + Assertions.assertEquals(6, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testAccrossConstructorAndCodeV1CreateContext() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + + String txAcrossConstructorAndCodeV1 = "txAcrossConstructorAndCodeV1"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txAcrossConstructorAndCodeV1, "b02", true); + Assertions.assertEquals(7, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testNoConstructorCodeCreateContext() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + + String txNoConstructorCode = "txNoConstructorCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txNoConstructorCode, "b02", true); + Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testDynamicExecutionContextSimpleScenario() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txCallAndDelegateCallSimpleTest = "txCallAndDelegateCallSimpleTest"; + assertTransactionReceiptWithStatus(world, txCallAndDelegateCallSimpleTest, "b01", true); + + String txExecuteCallCode = "txExecuteCallCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txExecuteDelegateCall = "txExecuteDelegateCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testDynamicExecutionContextWithRevert() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txDynamicExecutionContextWithRevertTest = "txDynamicExecutionContextWithRevertTest"; + assertTransactionReceiptWithStatus(world, txDynamicExecutionContextWithRevertTest, "b01", true); + + String txExecuteCallCode = "txExecuteCallCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txExecuteDelegateCall = "txExecuteDelegateCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); - Block bestBlock = world.getBlockByName("b03"); - Assertions.assertEquals(1, bestBlock.getTransactionsList().size()); - TransactionReceipt contractTransactionReceipt = world.getTransactionReceiptByName(contractCreationTx); + String txExecuteCall = "txExecuteCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b04", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testDynamicExecutionContextWithInvalid() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txDynamicExecutionContextWithInvalidTest = "txDynamicExecutionContextWithInvalidTest"; + assertTransactionReceiptWithStatus(world, txDynamicExecutionContextWithInvalidTest, "b01", true); + + String txExecuteCallCode = "txExecuteCallCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txExecuteDelegateCall = "txExecuteDelegateCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txExecuteCall = "txExecuteCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b04", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } - assertNotNull(contractTransactionReceipt); - byte[] status = contractTransactionReceipt.getStatus(); + @Test + void testDynamicExecutionContextWithStackOverflow() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txDynamicExecutionContextWithStackOverflowTest = "txDynamicExecutionContextWithStackOverflowTest"; + assertTransactionReceiptWithStatus(world, txDynamicExecutionContextWithStackOverflowTest, "b01", true); + + String txExecuteCallCode = "txExecuteCallCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txExecuteDelegateCall = "txExecuteDelegateCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txExecuteCall = "txExecuteCall"; + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b04", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { + Transaction txCreation = world.getTransactionByName(txName); + assertNotNull(txCreation); + + Block block = world.getBlockByName(blockName); + assertEquals(1, block.getTransactionsList().size()); + + TransactionReceipt txReceipt = world.getTransactionReceiptByName(txName); + assertNotNull(txReceipt); + + byte[] status = txReceipt.getStatus(); assertNotNull(status); - assertEquals(1, status.length); - assertEquals(1, status[0]); + + if(withSuccess) { + assertTrue(txReceipt.isSuccessful()); + } else { + assertFalse(txReceipt.isSuccessful()); + } + return txReceipt; } } diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java new file mode 100644 index 00000000000..a206186f226 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java @@ -0,0 +1,23 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.vm.opcode; + +public class TransientStorageTest { +} 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 d94e90569ce..fb0f8fe3c2e 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 @@ -126,7 +126,8 @@ class ActivationConfigTest { " rskip428: lovell700", " rskip434: arrowhead631", " rskip438: lovell700", - "}" + " rskip446: lovell700", + "}" )); @Test diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt new file mode 100644 index 00000000000..a44ede8746c --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt @@ -0,0 +1,142 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; +contract AcrossConstructorAndCodeV0 { + constructor() { + assembly{ + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000111) + } + } + + event OK(); + event ERROR(string, bytes32); + + function deployedCode() external { + bytes32 valueLoadedInitially; + bytes32 valueLoadedAfterStore; + bytes32 valueLoadedAfterStore2; + + assembly{ + valueLoadedInitially := tload(0) + valueLoadedAfterStore := tload(1) + + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000222) + valueLoadedAfterStore2 := tload(2) + } + checkReturnValueExpected(valueLoadedInitially, 'Checking value loaded in 0 from creator is inacessible', 0x00); + checkReturnValueExpected(valueLoadedAfterStore, 'Checking value stored in 1 from constructor is accesible', 0x0000000000000000000000000000000000000000000000000000000000000111); + checkReturnValueExpected(valueLoadedAfterStore2, 'Checking value stored in 2 from deployed code is accesible', 0x0000000000000000000000000000000000000000000000000000000000000222); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract TestStorageCreateContexts { + constructor(){ + } + + event OK(); + event ERROR(string, bytes32); + + function testAcrossConstructorAndCodeV0() external { + configureTransientStorageFromCaller(); + AcrossConstructorAndCodeV0 testContract = new AcrossConstructorAndCodeV0(); + testContract.deployedCode(); + checkTransientStorageFromCaller(); + } + + function configureTransientStorageFromCaller() private { + assembly{ + tstore(0, 0x0000000000000000000000000000000000000000000000000000000000000002) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000003) + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000004) + calldatacopy(0, 0, calldatasize()) + } + } + + function checkTransientStorageFromCaller() private { + bytes32 valueIn0Received; + bytes32 valueIn1Received; + bytes32 valueIn2Received; + + assembly{ + valueIn0Received := tload(0) + valueIn1Received := tload(1) + valueIn2Received := tload(2) + } + checkReturnValueExpected(valueIn0Received, 'Checking value in 0', 0x0000000000000000000000000000000000000000000000000000000000000002); + checkReturnValueExpected(valueIn1Received, 'Checking value in 1', 0x0000000000000000000000000000000000000000000000000000000000000003); + checkReturnValueExpected(valueIn2Received, 'Checking value in 2', 0x0000000000000000000000000000000000000000000000000000000000000004); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TestStorageCreateContexts: 6080604052348015600e575f80fd5b506106248061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063573d900a1461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b6102f3806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe6080604052348015600e575f80fd5b5061011160015d6102d1806100225f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f805c925060015c915061022260025d60025c90506100738360405180606001604052806036815260200161022e603691395f801b6100c6565b61009a82604051806060016040528060388152602001610264603891396101115f1b6100c6565b6100c1816040518060600160405280603a81526020016101f4603a91396102225f1b6100c6565b505050565b8083036100fe577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610138565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161012f9291906101c5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61017f8261013d565b6101898185610147565b9350610199818560208601610157565b6101a281610165565b840191505092915050565b5f819050919050565b6101bf816101ad565b82525050565b5f6040820190508181035f8301526101dd8185610175565b90506101ec60208301846101b6565b939250505056fe436865636b696e672076616c75652073746f72656420696e20322066726f6d206465706c6f79656420636f646520697320616363657369626c65436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c65436865636b696e672076616c75652073746f72656420696e20312066726f6d20636f6e7374727563746f7220697320616363657369626c65a26469706673582212209ee2571c29b98956bca0378cdf0ab06bb7e365dd067acd313c71a9295485b99c64736f6c634300081a0033a26469706673582212204abfd877c203d9e5adee353b20835eede1e284ac7e4b6640e27f13a7e025750d64736f6c634300081a0033 + +573d900a: testAcrossConstructorAndCodeV0() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCreateContextsContract contract +transaction_build txTestTransientStorageCreateContextsContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b506106248061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063573d900a1461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b6102f3806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe6080604052348015600e575f80fd5b5061011160015d6102d1806100225f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f805c925060015c915061022260025d60025c90506100738360405180606001604052806036815260200161022e603691395f801b6100c6565b61009a82604051806060016040528060388152602001610264603891396101115f1b6100c6565b6100c1816040518060600160405280603a81526020016101f4603a91396102225f1b6100c6565b505050565b8083036100fe577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610138565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161012f9291906101c5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61017f8261013d565b6101898185610147565b9350610199818560208601610157565b6101a281610165565b840191505092915050565b5f819050919050565b6101bf816101ad565b82525050565b5f6040820190508181035f8301526101dd8185610175565b90506101ec60208301846101b6565b939250505056fe436865636b696e672076616c75652073746f72656420696e20322066726f6d206465706c6f79656420636f646520697320616363657369626c65436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c65436865636b696e672076616c75652073746f72656420696e20312066726f6d20636f6e7374727563746f7220697320616363657369626c65a26469706673582212209ee2571c29b98956bca0378cdf0ab06bb7e365dd067acd313c71a9295485b99c64736f6c634300081a0033a26469706673582212204abfd877c203d9e5adee353b20835eede1e284ac7e4b6640e27f13a7e025750d64736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageCreateContextsContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txInConstructorAndCode transaction +transaction_build txAcrossConstructorAndCodeV0 + sender acc1 + nonce 1 + contract txTestTransientStorageCreateContextsContract + value 0 + data 573d900a + gas 1000000 + build + +# Create block to hold txAcrossConstructorAndCodeV0 transaction +block_build b02 + parent b01 + transactions txAcrossConstructorAndCodeV0 + gasLimit 3000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt new file mode 100644 index 00000000000..ea98b332054 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt @@ -0,0 +1,146 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract AcrossConstructorAndCodeV1 { + constructor() { + bytes32 valueLoadedInitially; + assembly{ + valueLoadedInitially := tload(0) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000333) + } + checkReturnValueExpected(valueLoadedInitially, 'Checking value loaded in 0 from creator is inacessible in constructor', 0x00); + } + + event OK(); + event ERROR(string, bytes32); + + function deployedCode() external { + bytes32 valueLoadedInitially; + bytes32 valueLoadedAfterStore; + bytes32 valueLoadedAfterStore2; + + assembly{ + valueLoadedInitially := tload(0) + valueLoadedAfterStore := tload(1) + + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000444) + valueLoadedAfterStore2 := tload(2) + } + checkReturnValueExpected(valueLoadedInitially, 'Checking value loaded in 0 from creator is inacessible', 0x00); + checkReturnValueExpected(valueLoadedAfterStore, 'Checking value stored in 1 from constructor is accesible', 0x0000000000000000000000000000000000000000000000000000000000000333); + checkReturnValueExpected(valueLoadedAfterStore2, 'Checking value stored in 2 from deployed code is accesible', 0x0000000000000000000000000000000000000000000000000000000000000444); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract TestStorageCreateContexts { + constructor(){ + } + + event OK(); + event ERROR(string, bytes32); + + function testAcrossConstructorAndCodeV1() external { + configureTransientStorageFromCaller(); + AcrossConstructorAndCodeV1 testContract = new AcrossConstructorAndCodeV1(); + testContract.deployedCode(); + checkTransientStorageFromCaller(); + } + + function configureTransientStorageFromCaller() private { + assembly{ + tstore(0, 0x0000000000000000000000000000000000000000000000000000000000000002) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000003) + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000004) + calldatacopy(0, 0, calldatasize()) + } + } + + function checkTransientStorageFromCaller() private { + bytes32 valueIn0Received; + bytes32 valueIn1Received; + bytes32 valueIn2Received; + + assembly{ + valueIn0Received := tload(0) + valueIn1Received := tload(1) + valueIn2Received := tload(2) + } + checkReturnValueExpected(valueIn0Received, 'Checking value in 0', 0x0000000000000000000000000000000000000000000000000000000000000002); + checkReturnValueExpected(valueIn1Received, 'Checking value in 1', 0x0000000000000000000000000000000000000000000000000000000000000003); + checkReturnValueExpected(valueIn2Received, 'Checking value in 2', 0x0000000000000000000000000000000000000000000000000000000000000004); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TestStorageCreateContexts: 6080604052348015600e575f80fd5b506107cd8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636fc138181461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b61049c806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe608060405234801561000f575f80fd5b505f805c905061033360015d61004681604051806080016040528060458152602001610457604591395f801b61004c60201b60201c565b50610179565b808303610084577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100be565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd382846040516100b592919061014b565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610105826100c3565b61010f81856100cd565b935061011f8185602086016100dd565b610128816100eb565b840191505092915050565b5f819050919050565b61014581610133565b82525050565b5f6040820190508181035f83015261016381856100fb565b9050610172602083018461013c565b9392505050565b6102d1806101865f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f805c925060015c915061044460025d60025c90506100738360405180606001604052806036815260200161022e603691395f801b6100c6565b61009a82604051806060016040528060388152602001610264603891396103335f1b6100c6565b6100c1816040518060600160405280603a81526020016101f4603a91396104445f1b6100c6565b505050565b8083036100fe577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610138565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161012f9291906101c5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61017f8261013d565b6101898185610147565b9350610199818560208601610157565b6101a281610165565b840191505092915050565b5f819050919050565b6101bf816101ad565b82525050565b5f6040820190508181035f8301526101dd8185610175565b90506101ec60208301846101b6565b939250505056fe436865636b696e672076616c75652073746f72656420696e20322066726f6d206465706c6f79656420636f646520697320616363657369626c65436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c65436865636b696e672076616c75652073746f72656420696e20312066726f6d20636f6e7374727563746f7220697320616363657369626c65a264697066735822122016cae860d0cda920784f1ab4923dc095d7567876a114712426ec01cebbc6b2d464736f6c634300081a0033436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e20636f6e7374727563746f72a2646970667358221220da71a4ccc0ab9bca47a26db221968eb2cee1c312408b5ce77ce1aeecd4e8459164736f6c634300081a0033 + +6fc13818: testAcrossConstructorAndCodeV1() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCreateContextsContract contract +transaction_build txTestTransientStorageCreateContextsContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b506107cd8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80636fc138181461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b61049c806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe608060405234801561000f575f80fd5b505f805c905061033360015d61004681604051806080016040528060458152602001610457604591395f801b61004c60201b60201c565b50610179565b808303610084577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100be565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd382846040516100b592919061014b565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610105826100c3565b61010f81856100cd565b935061011f8185602086016100dd565b610128816100eb565b840191505092915050565b5f819050919050565b61014581610133565b82525050565b5f6040820190508181035f83015261016381856100fb565b9050610172602083018461013c565b9392505050565b6102d1806101865f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f805c925060015c915061044460025d60025c90506100738360405180606001604052806036815260200161022e603691395f801b6100c6565b61009a82604051806060016040528060388152602001610264603891396103335f1b6100c6565b6100c1816040518060600160405280603a81526020016101f4603a91396104445f1b6100c6565b505050565b8083036100fe577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610138565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161012f9291906101c5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61017f8261013d565b6101898185610147565b9350610199818560208601610157565b6101a281610165565b840191505092915050565b5f819050919050565b6101bf816101ad565b82525050565b5f6040820190508181035f8301526101dd8185610175565b90506101ec60208301846101b6565b939250505056fe436865636b696e672076616c75652073746f72656420696e20322066726f6d206465706c6f79656420636f646520697320616363657369626c65436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c65436865636b696e672076616c75652073746f72656420696e20312066726f6d20636f6e7374727563746f7220697320616363657369626c65a264697066735822122016cae860d0cda920784f1ab4923dc095d7567876a114712426ec01cebbc6b2d464736f6c634300081a0033436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e20636f6e7374727563746f72a2646970667358221220da71a4ccc0ab9bca47a26db221968eb2cee1c312408b5ce77ce1aeecd4e8459164736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageCreateContextsContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txInConstructorAndCode transaction +transaction_build txAcrossConstructorAndCodeV1 + sender acc1 + nonce 1 + contract txTestTransientStorageCreateContextsContract + value 0 + data 6fc13818 + gas 1000000 + build + +# Create block to hold txAcrossConstructorAndCodeV1 transaction +block_build b02 + parent b01 + transactions txAcrossConstructorAndCodeV1 + gasLimit 3000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt new file mode 100644 index 00000000000..36eac43363a --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt @@ -0,0 +1,147 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestTransientStorageCallAndDelegateCall { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testCallCodeAndDelegateCall(uint256 useCallCode) external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + uint256 valueLoadedFrom1; + uint256 valueLoadedSstore2; + uint256 valueLoadedSstore3; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + + // If useCallCode is 0, execute callCode otherwise execute delegateCall + switch useCallCode + case 1 { + success := callcode(gas(), calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + default { + success := delegatecall(gas(), calleeAddress, availablePointer, 0x4, availablePointer, 0x20) + } + valueLoadedFrom0 := tload(0) + valueLoadedSstore2 := sload(2) + valueLoadedSstore3 := sload(3) + valueLoadedFrom1 := tload(1) + } + + checkReturnValueExpected(success, 'Checking result callee execution', 1); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + checkReturnValueExpected(valueLoadedSstore2, 'Checking value from sstore 2', 420); + checkReturnValueExpected(valueLoadedSstore3, 'Checking value from sstore 3', 69); + checkReturnValueExpected(valueLoadedFrom1, 'Checking value from tload 1', 69); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute() external { + assembly { + sstore(2, tload(0)) + tstore(1, 69) + sstore(3, tload(1)) + } + } +} + +// CONTRACT BYTECODE + +TestTransientStorageCallAndDelegateCall: 6080604052348015600e575f5ffd5b5061048e8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063a61face91461002d575b5f5ffd5b610047600480360381019061004291906102ec565b610049565b005b5f604051610056906102a9565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d60405181815288600181146100bf576020826004848c5af497506100cc565b6020826004845f8d5af297505b505f5c95506002549350600354925060015c945050610122866040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152506001610232565b610164856040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a4610232565b6101a6836040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652032000000008152506101a4610232565b6101e7826040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652033000000008152506045610232565b610228846040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506045610232565b5050505050505050565b80830361026a577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16102a4565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161029b929190610396565b60405180910390a15b505050565b6094806103c583390190565b5f5ffd5b5f819050919050565b6102cb816102b9565b81146102d5575f5ffd5b50565b5f813590506102e6816102c2565b92915050565b5f60208284031215610301576103006102b5565b5b5f61030e848285016102d8565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61035982610317565b6103638185610321565b9350610373818560208601610331565b61037c8161033f565b840191505092915050565b610390816102b9565b82525050565b5f6040820190508181035f8301526103ae818561034f565b90506103bd6020830184610387565b939250505056fe6080604052348015600e575f5ffd5b50607a80601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636146195414602a575b5f5ffd5b60306032565b005b5f5c600255604560015d60015c60035556fea26469706673582212201771c67495697664bc8f0b297a683b4e7dbb7e31feaf9cf735faf209a14d64fa64736f6c634300081c0033a2646970667358221220ce4a7e6da5344a1d5a34ebef6c0267ac15796a3a9529427da9ba17a9cc4bee0864736f6c634300081c0033 + +a61face9: testCallCodeAndDelegateCall(uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCallAndDelegateCall contract +transaction_build txCallAndDelegateCallSimpleTest + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b5061048e8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063a61face91461002d575b5f5ffd5b610047600480360381019061004291906102ec565b610049565b005b5f604051610056906102a9565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d60405181815288600181146100bf576020826004848c5af497506100cc565b6020826004845f8d5af297505b505f5c95506002549350600354925060015c945050610122866040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152506001610232565b610164856040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a4610232565b6101a6836040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652032000000008152506101a4610232565b6101e7826040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652033000000008152506045610232565b610228846040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506045610232565b5050505050505050565b80830361026a577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16102a4565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161029b929190610396565b60405180910390a15b505050565b6094806103c583390190565b5f5ffd5b5f819050919050565b6102cb816102b9565b81146102d5575f5ffd5b50565b5f813590506102e6816102c2565b92915050565b5f60208284031215610301576103006102b5565b5b5f61030e848285016102d8565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61035982610317565b6103638185610321565b9350610373818560208601610331565b61037c8161033f565b840191505092915050565b610390816102b9565b82525050565b5f6040820190508181035f8301526103ae818561034f565b90506103bd6020830184610387565b939250505056fe6080604052348015600e575f5ffd5b50607a80601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636146195414602a575b5f5ffd5b60306032565b005b5f5c600255604560015d60015c60035556fea26469706673582212201771c67495697664bc8f0b297a683b4e7dbb7e31feaf9cf735faf209a14d64fa64736f6c634300081c0033a2646970667358221220ce4a7e6da5344a1d5a34ebef6c0267ac15796a3a9529427da9ba17a9cc4bee0864736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txCallAndDelegateCallSimpleTest transaction +block_build b01 + parent g00 + transactions txCallAndDelegateCallSimpleTest + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteCallCode transaction +transaction_build txExecuteCallCode + sender acc1 + nonce 1 + contract txCallAndDelegateCallSimpleTest + value 0 + data a61face90000000000000000000000000000000000000000000000000000000000000001 + gas 1000000 + build + +# Create block to hold txExecuteCallCode transaction +block_build b02 + parent b01 + transactions txExecuteCallCode + gasLimit 2000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteDelegateCall + sender acc1 + nonce 2 + contract txCallAndDelegateCallSimpleTest + value 0 + data a61face90000000000000000000000000000000000000000000000000000000000000000 + gas 1000000 + build + +# Create block to hold txExecuteDelegateCall transaction +block_build b03 + parent b02 + transactions txExecuteDelegateCall + gasLimit 2000000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt new file mode 100644 index 00000000000..96321e7ead6 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt @@ -0,0 +1,166 @@ +comment +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestTStorageDynamicExecutionContextWithInvalid{ + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testCallSelectingContractCallOpcode(uint256 contractCallSelector) external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + uint256 valueLoadedFrom1; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + tstore(1, 420) + + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + // If useDelegateCall is greater than 0, execute delegateCall otherwise execute callCode + switch contractCallSelector + case 0 { + success := callcode(0xFF, calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + case 1 { + success := delegatecall(0xFF, calleeAddress, availablePointer, 0x4, availablePointer, 0x20) + } + default { + success := call(0xFF, calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + valueLoadedFrom0 := tload(0) + valueLoadedFrom1 := tload(1) + } + + checkReturnValueExpected(success, 'Checking result callee execution', 0); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + checkReturnValueExpected(valueLoadedFrom1, 'Checking value from tload 1', 420); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute() external { + assembly { + tstore(1, 69) + invalid() + } + } +} + +// CONTRACT BYTECODE + +TestTStorageDynamicExecutionContextWithInvalid: 6080604052348015600e575f5ffd5b506104138061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80639823c4061461002d575b5f5ffd5b6100476004803603810190610042919061027c565b610049565b005b5f60405161005690610239565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6101a460015d604051818152865f81146100cc57600181146100de576020826004845f8b60fff195506100eb565b6020826004845f8b60fff295506100eb565b6020826004848a60fff495505b505f5c935060015c925050610136846040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152505f6101c2565b610178836040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101c2565b6101ba826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506101a46101c2565b505050505050565b8083036101fa577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610234565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161022b929190610326565b60405180910390a15b505050565b60898061035583390190565b5f5ffd5b5f819050919050565b61025b81610249565b8114610265575f5ffd5b50565b5f8135905061027681610252565b92915050565b5f6020828403121561029157610290610245565b5b5f61029e84828501610268565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102e9826102a7565b6102f381856102b1565b93506103038185602086016102c1565b61030c816102cf565b840191505092915050565b61032081610249565b82525050565b5f6040820190508181035f83015261033e81856102df565b905061034d6020830184610317565b939250505056fe6080604052348015600e575f5ffd5b50606f80601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636146195414602a575b5f5ffd5b60306032565b005b604560015dfefea26469706673582212207c61e75cb53c4ad046d081a86c932bf15e83580e0d3ceae3fa417efcab11607e64736f6c634300081c0033a264697066735822122099e5211521504bd8cd35e3f045924e1065174f722e1fb24d137b65571be0fbb364736f6c634300081c0033 + +9823c406: testCallSelectingContractCallOpcode(uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCallAndDelegateCall contract +transaction_build txDynamicExecutionContextWithInvalidTest + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b506104138061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80639823c4061461002d575b5f5ffd5b6100476004803603810190610042919061027c565b610049565b005b5f60405161005690610239565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6101a460015d604051818152865f81146100cc57600181146100de576020826004845f8b60fff195506100eb565b6020826004845f8b60fff295506100eb565b6020826004848a60fff495505b505f5c935060015c925050610136846040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152505f6101c2565b610178836040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101c2565b6101ba826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506101a46101c2565b505050505050565b8083036101fa577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610234565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161022b929190610326565b60405180910390a15b505050565b60898061035583390190565b5f5ffd5b5f819050919050565b61025b81610249565b8114610265575f5ffd5b50565b5f8135905061027681610252565b92915050565b5f6020828403121561029157610290610245565b5b5f61029e84828501610268565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102e9826102a7565b6102f381856102b1565b93506103038185602086016102c1565b61030c816102cf565b840191505092915050565b61032081610249565b82525050565b5f6040820190508181035f83015261033e81856102df565b905061034d6020830184610317565b939250505056fe6080604052348015600e575f5ffd5b50606f80601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636146195414602a575b5f5ffd5b60306032565b005b604560015dfefea26469706673582212207c61e75cb53c4ad046d081a86c932bf15e83580e0d3ceae3fa417efcab11607e64736f6c634300081c0033a264697066735822122099e5211521504bd8cd35e3f045924e1065174f722e1fb24d137b65571be0fbb364736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txDynamicExecutionContextWithInvalidTest transaction +block_build b01 + parent g00 + transactions txDynamicExecutionContextWithInvalidTest + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteCallCode transaction +transaction_build txExecuteCallCode + sender acc1 + nonce 1 + contract txDynamicExecutionContextWithInvalidTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000000 + gas 500000 + build + +# Create block to hold txExecuteCallCode transaction +block_build b02 + parent b01 + transactions txExecuteCallCode + gasLimit 550000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteDelegateCall + sender acc1 + nonce 2 + contract txDynamicExecutionContextWithInvalidTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000001 + gas 500000 + build + +# Create block to hold txExecuteDelegateCall transaction +block_build b03 + parent b02 + transactions txExecuteDelegateCall + gasLimit 550000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteCall + sender acc1 + nonce 3 + contract txDynamicExecutionContextWithInvalidTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000002 + gas 500000 + build + +# Create block to hold txExecuteCall transaction +block_build b04 + parent b03 + transactions txExecuteCall + gasLimit 550000 + build + +# Connect block +block_connect b04 + +# Check b04 is best block +assert_best b04 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt new file mode 100644 index 00000000000..39ba6b71be9 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt @@ -0,0 +1,166 @@ +comment +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestTStorageDynamicExecutionContextWithRevert { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testCallSelectingContractCallOpcode(uint256 contractCallSelector) external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + uint256 valueLoadedFrom1; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + tstore(1, 420) + + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + // If useDelegateCall is greater than 0, execute delegateCall otherwise execute callCode + switch contractCallSelector + case 0 { + success := callcode(gas(), calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + case 1 { + success := delegatecall(gas(), calleeAddress, availablePointer, 0x4, availablePointer, 0x20) + } + default { + success := call(gas(), calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + valueLoadedFrom0 := tload(0) + valueLoadedFrom1 := tload(1) + } + + checkReturnValueExpected(success, 'Checking result callee execution', 0); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + checkReturnValueExpected(valueLoadedFrom1, 'Checking value from tload 1', 420); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute() external { + assembly { + tstore(1, 69) + revert(0,0) + } + } +} + +// CONTRACT BYTECODE + +TestTStorageDynamicExecutionContextWithRevert: 6080604052348015600e575f5ffd5b506104128061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80639823c4061461002d575b5f5ffd5b61004760048036038101906100429190610279565b610049565b005b5f60405161005690610236565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6101a460015d604051818152865f81146100cb57600181146100dc576020826004845f8b5af195506100e8565b6020826004845f8b5af295506100e8565b6020826004848a5af495505b505f5c935060015c925050610133846040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152505f6101bf565b610175836040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101bf565b6101b7826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506101a46101bf565b505050505050565b8083036101f7577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610231565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610228929190610323565b60405180910390a15b505050565b608b8061035283390190565b5f5ffd5b5f819050919050565b61025881610246565b8114610262575f5ffd5b50565b5f813590506102738161024f565b92915050565b5f6020828403121561028e5761028d610242565b5b5f61029b84828501610265565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102e6826102a4565b6102f081856102ae565b93506103008185602086016102be565b610309816102cc565b840191505092915050565b61031d81610246565b82525050565b5f6040820190508181035f83015261033b81856102dc565b905061034a6020830184610314565b939250505056fe6080604052348015600e575f5ffd5b50607180601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636146195414602a575b5f5ffd5b60306032565b005b604560015d5f5ffdfea264697066735822122012b2acf84430846181c2090e00f142a45789288a3094ef935604fa5b2cb44e1f64736f6c634300081c0033a26469706673582212200323b022738aab6530f9ff3cde3c2b7774d6dc76d7ee932e8bd4edb7b517a59064736f6c634300081c0033 + +9823c406: testCallSelectingContractCallOpcode(uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCallAndDelegateCall contract +transaction_build txDynamicExecutionContextWithRevertTest + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b506104128061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80639823c4061461002d575b5f5ffd5b61004760048036038101906100429190610279565b610049565b005b5f60405161005690610236565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6101a460015d604051818152865f81146100cb57600181146100dc576020826004845f8b5af195506100e8565b6020826004845f8b5af295506100e8565b6020826004848a5af495505b505f5c935060015c925050610133846040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152505f6101bf565b610175836040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101bf565b6101b7826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506101a46101bf565b505050505050565b8083036101f7577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610231565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610228929190610323565b60405180910390a15b505050565b608b8061035283390190565b5f5ffd5b5f819050919050565b61025881610246565b8114610262575f5ffd5b50565b5f813590506102738161024f565b92915050565b5f6020828403121561028e5761028d610242565b5b5f61029b84828501610265565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102e6826102a4565b6102f081856102ae565b93506103008185602086016102be565b610309816102cc565b840191505092915050565b61031d81610246565b82525050565b5f6040820190508181035f83015261033b81856102dc565b905061034a6020830184610314565b939250505056fe6080604052348015600e575f5ffd5b50607180601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636146195414602a575b5f5ffd5b60306032565b005b604560015d5f5ffdfea264697066735822122012b2acf84430846181c2090e00f142a45789288a3094ef935604fa5b2cb44e1f64736f6c634300081c0033a26469706673582212200323b022738aab6530f9ff3cde3c2b7774d6dc76d7ee932e8bd4edb7b517a59064736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txDynamicExecutionContextWithRevertTest transaction +block_build b01 + parent g00 + transactions txDynamicExecutionContextWithRevertTest + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteCallCode transaction +transaction_build txExecuteCallCode + sender acc1 + nonce 1 + contract txDynamicExecutionContextWithRevertTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000000 + gas 500000 + build + +# Create block to hold txExecuteCallCode transaction +block_build b02 + parent b01 + transactions txExecuteCallCode + gasLimit 550000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteDelegateCall + sender acc1 + nonce 2 + contract txDynamicExecutionContextWithRevertTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000001 + gas 500000 + build + +# Create block to hold txExecuteDelegateCall transaction +block_build b03 + parent b02 + transactions txExecuteDelegateCall + gasLimit 550000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteCall + sender acc1 + nonce 3 + contract txDynamicExecutionContextWithRevertTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000002 + gas 500000 + build + +# Create block to hold txExecuteCall transaction +block_build b04 + parent b03 + transactions txExecuteCall + gasLimit 550000 + build + +# Connect block +block_connect b04 + +# Check b04 is best block +assert_best b04 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt new file mode 100644 index 00000000000..8b937302c20 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt @@ -0,0 +1,173 @@ +comment +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestTStorageDynamicExecutionContextWithStackOverflow { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testCallSelectingContractCallOpcode(uint256 contractCallSelector) external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + uint256 valueLoadedFrom1; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + tstore(1, 420) + + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + // If useDelegateCall is greater than 0, execute delegateCall otherwise execute callCode + switch contractCallSelector + case 0 { + success := callcode(0xFFFF, calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + case 1 { + success := delegatecall(0xFFFF, calleeAddress, availablePointer, 0x4, availablePointer, 0x20) + } + default { + success := call(0xFFFF, calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + } + valueLoadedFrom0 := tload(0) + valueLoadedFrom1 := tload(1) + } + + checkReturnValueExpected(success, 'Checking result callee execution', 0); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + checkReturnValueExpected(valueLoadedFrom1, 'Checking value from tload 1', 420); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute() external { + assembly { + tstore(1,69) + } + this.executeRecursive(0); + } + + function executeRecursive(uint256 counter) external { + if(counter < 1026){ + counter ++; + this.executeRecursive(counter); + } + } +} + +// CONTRACT BYTECODE + +TestTStorageDynamicExecutionContextWithStackOverflow: 6080604052348015600e575f5ffd5b506106868061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80639823c4061461002d575b5f5ffd5b61004760048036038101906100429190610280565b610049565b005b5f6040516100569061023c565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6101a460015d604051818152865f81146100cd57600181146100e0576020826004845f8b61fffff195506100ee565b6020826004845f8b61fffff295506100ee565b6020826004848a61fffff495505b505f5c935060015c925050610139846040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152505f6101c5565b61017b836040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101c5565b6101bd826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506101a46101c5565b505050505050565b8083036101fd577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610237565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161022e92919061032a565b60405180910390a15b505050565b6102f88061035983390190565b5f5ffd5b5f819050919050565b61025f8161024d565b8114610269575f5ffd5b50565b5f8135905061027a81610256565b92915050565b5f6020828403121561029557610294610249565b5b5f6102a28482850161026c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102ed826102ab565b6102f781856102b5565b93506103078185602086016102c5565b610310816102d3565b840191505092915050565b6103248161024d565b82525050565b5f6040820190508181035f83015261034281856102e3565b9050610351602083018461031b565b939250505056fe6080604052348015600e575f5ffd5b506102dc8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80636146195414610038578063fccbafb914610042575b5f5ffd5b61004061005e565b005b61005c60048036038101906100579190610184565b6100cb565b005b604560015d3073ffffffffffffffffffffffffffffffffffffffff1663fccbafb95f6040518263ffffffff1660e01b815260040161009c91906101f1565b5f604051808303815f87803b1580156100b3575f5ffd5b505af11580156100c5573d5f5f3e3d5ffd5b50505050565b61040281101561014a5780806100e090610237565b9150503073ffffffffffffffffffffffffffffffffffffffff1663fccbafb9826040518263ffffffff1660e01b815260040161011c919061028d565b5f604051808303815f87803b158015610133575f5ffd5b505af1158015610145573d5f5f3e3d5ffd5b505050505b50565b5f5ffd5b5f819050919050565b61016381610151565b811461016d575f5ffd5b50565b5f8135905061017e8161015a565b92915050565b5f602082840312156101995761019861014d565b5b5f6101a684828501610170565b91505092915050565b5f819050919050565b5f819050919050565b5f6101db6101d66101d1846101af565b6101b8565b610151565b9050919050565b6101eb816101c1565b82525050565b5f6020820190506102045f8301846101e2565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61024182610151565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036102735761027261020a565b5b600182019050919050565b61028781610151565b82525050565b5f6020820190506102a05f83018461027e565b9291505056fea26469706673582212208c06dbf10708fcc54598b88ca5465d5b4189bd294c289c13db194e75762635f764736f6c634300081c0033a2646970667358221220c007921bf7d900df9462a49fe9fca543537ec9f988ce2d601da8182ad224485364736f6c634300081c0033 + +9823c406: testCallSelectingContractCallOpcode(uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCallAndDelegateCall contract +transaction_build txDynamicExecutionContextWithStackOverflowTest + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b506106868061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80639823c4061461002d575b5f5ffd5b61004760048036038101906100429190610280565b610049565b005b5f6040516100569061023c565b604051809103905ff08015801561006f573d5f5f3e3d5ffd5b5090505f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6101a460015d604051818152865f81146100cd57600181146100e0576020826004845f8b61fffff195506100ee565b6020826004845f8b61fffff295506100ee565b6020826004848a61fffff495505b505f5c935060015c925050610139846040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e8152505f6101c5565b61017b836040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101c5565b6101bd826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152506101a46101c5565b505050505050565b8083036101fd577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610237565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161022e92919061032a565b60405180910390a15b505050565b6102f88061035983390190565b5f5ffd5b5f819050919050565b61025f8161024d565b8114610269575f5ffd5b50565b5f8135905061027a81610256565b92915050565b5f6020828403121561029557610294610249565b5b5f6102a28482850161026c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102ed826102ab565b6102f781856102b5565b93506103078185602086016102c5565b610310816102d3565b840191505092915050565b6103248161024d565b82525050565b5f6040820190508181035f83015261034281856102e3565b9050610351602083018461031b565b939250505056fe6080604052348015600e575f5ffd5b506102dc8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80636146195414610038578063fccbafb914610042575b5f5ffd5b61004061005e565b005b61005c60048036038101906100579190610184565b6100cb565b005b604560015d3073ffffffffffffffffffffffffffffffffffffffff1663fccbafb95f6040518263ffffffff1660e01b815260040161009c91906101f1565b5f604051808303815f87803b1580156100b3575f5ffd5b505af11580156100c5573d5f5f3e3d5ffd5b50505050565b61040281101561014a5780806100e090610237565b9150503073ffffffffffffffffffffffffffffffffffffffff1663fccbafb9826040518263ffffffff1660e01b815260040161011c919061028d565b5f604051808303815f87803b158015610133575f5ffd5b505af1158015610145573d5f5f3e3d5ffd5b505050505b50565b5f5ffd5b5f819050919050565b61016381610151565b811461016d575f5ffd5b50565b5f8135905061017e8161015a565b92915050565b5f602082840312156101995761019861014d565b5b5f6101a684828501610170565b91505092915050565b5f819050919050565b5f819050919050565b5f6101db6101d66101d1846101af565b6101b8565b610151565b9050919050565b6101eb816101c1565b82525050565b5f6020820190506102045f8301846101e2565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61024182610151565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036102735761027261020a565b5b600182019050919050565b61028781610151565b82525050565b5f6020820190506102a05f83018461027e565b9291505056fea26469706673582212208c06dbf10708fcc54598b88ca5465d5b4189bd294c289c13db194e75762635f764736f6c634300081c0033a2646970667358221220c007921bf7d900df9462a49fe9fca543537ec9f988ce2d601da8182ad224485364736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txDynamicExecutionContextWithStackOverflowTest transaction +block_build b01 + parent g00 + transactions txDynamicExecutionContextWithStackOverflowTest + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteCallCode transaction +transaction_build txExecuteCallCode + sender acc1 + nonce 1 + contract txDynamicExecutionContextWithStackOverflowTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000000 + gas 500000 + build + +# Create block to hold txExecuteCallCode transaction +block_build b02 + parent b01 + transactions txExecuteCallCode + gasLimit 550000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteDelegateCall + sender acc1 + nonce 2 + contract txDynamicExecutionContextWithStackOverflowTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000001 + gas 500000 + build + +# Create block to hold txExecuteDelegateCall transaction +block_build b03 + parent b02 + transactions txExecuteDelegateCall + gasLimit 550000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 + +# Create transaction to execute txExecuteDelegateCall transaction +transaction_build txExecuteCall + sender acc1 + nonce 3 + contract txDynamicExecutionContextWithStackOverflowTest + value 0 + data 9823c4060000000000000000000000000000000000000000000000000000000000000002 + gas 500000 + build + +# Create block to hold txExecuteCall transaction +block_build b04 + parent b03 + transactions txExecuteCall + gasLimit 550000 + build + +# Connect block +block_connect b04 + +# Check b04 is best block +assert_best b04 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/eip1153_basic_tests.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/eip1153_basic_tests.txt new file mode 100644 index 00000000000..3f5f30ac8a8 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/eip1153_basic_tests.txt @@ -0,0 +1,223 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestsTransientStorageEip1153BasicScenarios { + bytes32[] slotsToTest = new bytes32[](4); + + constructor() { + slotsToTest[0] = 0x0000000000000000000000000000000000000000000000000000000000000001; + slotsToTest[1] = 0x0000000000000000000000000000000000000000000000000000000000000002; + slotsToTest[2] = 0x0000000000000000000000000000000100000000000000000000000000000000; + slotsToTest[3] = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + } + + event OK(); + event ERROR(bytes32); + + // Test that loading an arbitrary value is 0 at beginning of transaction: TLOAD(x) is 0 + function testTransientUnsetValues() external { + bytes32 valueLoaded; + for (uint i = 0; i < slotsToTest.length; i++) { + bytes32 currentSlot = slotsToTest[i]; + assembly { + valueLoaded := tload(currentSlot) + } + if (valueLoaded == 0x0) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } + } + + // Test that Loading after storing returns the stored value: TSTORE(x, y), TLOAD(x) returns y + function testTloadAfterTstore() external { + bytes32 valueLoaded; + for (uint i = 0; i < slotsToTest.length; i++) { + bytes32 currentSlot = slotsToTest[i]; + assembly { + tstore(currentSlot, currentSlot) + valueLoaded := tload(currentSlot) + } + if (valueLoaded == currentSlot) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } + } + + // Transient loading after storing does not return the stored value: STORE(x, y), TLOAD(x) returns 0 + function testTloadAfterSstore() external { + bytes32 valueLoaded; + for (uint i = 0; i < slotsToTest.length; i++) { + bytes32 currentSlot = slotsToTest[i]; + assembly { + sstore(currentSlot, 0xFF) + valueLoaded := tload(currentSlot) + } + if (valueLoaded == 0x0) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } + } + + // Transient loading after storing does not return the stored value: STORE(x, y), TLOAD(x) returns 0 + function testTloadAfterTstoreIsZero() external { + bytes32 valueLoaded; + bytes32[] memory slotsDifferentKeys = new bytes32[](4); + slotsDifferentKeys[0] = 0x0000000000000000000000000000000000000000000000000000000000000003; + slotsDifferentKeys[1] = 0x0000000000000000000000000000000000000000000000000000000000000004; + slotsDifferentKeys[2] = 0x0000000000000000000000000000000100000000000000000000000000000001; + slotsDifferentKeys[3] = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe; + for (uint i = 0; i < slotsToTest.length; i++) { + bytes32 currentSlot = slotsToTest[i]; + bytes32 currentSlotDifferent = slotsDifferentKeys[i]; + assembly { + tstore(currentSlot, 0x4D2) + valueLoaded := tload(currentSlotDifferent) + } + if (valueLoaded == 0x0) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } + } +} + +// CONTRACT BYTECODE + +TestsTransientStorageEip1153BasicScenarios: 6080604052600467ffffffffffffffff81111561001f5761001e610198565b5b60405190808252806020026020018201604052801561004d5781602001602082028036833780820191505090505b505f9080519060200190610062929190610132565b5034801561006e575f80fd5b5060015f1b5f8081548110610086576100856101c5565b5b905f5260205f20018190555060025f1b5f6001815481106100aa576100a96101c5565b5b905f5260205f2001819055507001000000000000000000000000000000005f1b5f6002815481106100de576100dd6101c5565b5b905f5260205f2001819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f1b5f600381548110610121576101206101c5565b5b905f5260205f2001819055506101f2565b828054828255905f5260205f2090810192821561016c579160200282015b8281111561016b578251825591602001919060010190610150565b5b509050610179919061017d565b5090565b5b80821115610194575f815f90555060010161017e565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b61054d806101ff5f395ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c806308cf7e911461004e5780633ba13899146100585780634f3f02ee14610062578063d0519a7f1461006c575b5f80fd5b610056610076565b005b610060610130565b005b61006a610316565b005b6100746103cf565b005b5f805f90505b5f8054905081101561012c575f80828154811061009c5761009b61048c565b5b905f5260205f200154905080815d805c92508083036100e6577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161011e565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd98360405161011591906104d1565b60405180910390a15b50808060010191505061007c565b5050565b5f80600467ffffffffffffffff81111561014d5761014c6104ea565b5b60405190808252806020026020018201604052801561017b5781602001602082028036833780820191505090505b50905060035f1b815f815181106101955761019461048c565b5b60200260200101818152505060045f1b816001815181106101b9576101b861048c565b5b6020026020010181815250507001000000000000000000000000000000015f1b816002815181106101ed576101ec61048c565b5b6020026020010181815250507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5f1b816003815181106102305761022f61048c565b5b6020026020010181815250505f5b5f80549050811015610311575f80828154811061025e5761025d61048c565b5b905f5260205f20015490505f83838151811061027d5761027c61048c565b5b602002602001015190506104d2825d805c94505f801b85036102ca577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610302565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9856040516102f991906104d1565b60405180910390a15b5050808060010191505061023e565b505050565b5f805f90505b5f805490508110156103cb575f80828154811061033c5761033b61048c565b5b905f5260205f2001549050805c92505f801b8303610385577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16103bd565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9836040516103b491906104d1565b60405180910390a15b50808060010191505061031c565b5050565b5f805f90505b5f80549050811015610488575f8082815481106103f5576103f461048c565b5b905f5260205f200154905060ff8155805c92505f801b8303610442577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161047a565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd98360405161047191906104d1565b60405180910390a15b5080806001019150506103d5565b5050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f819050919050565b6104cb816104b9565b82525050565b5f6020820190506104e45f8301846104c2565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea26469706673582212204bf46b78c1fcafe2ef7b46d0b4632777b5d37316aed745194ce7eac231a4f4c464736f6c634300081a0033 + +// CONTRACT CALLS + +TestsTransientStorageEip1153BasicScenarios: + + - d0519a7f: testTloadAfterSstore() + - 08cf7e91: testTloadAfterTstore() + - 4f3f02ee: testTransientUnsetValues() + - 3ba13899: testTloadAfterTstoreIsZero() + +end + + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorage contract +transaction_build txTestTransientStorageContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052600467ffffffffffffffff81111561001f5761001e610198565b5b60405190808252806020026020018201604052801561004d5781602001602082028036833780820191505090505b505f9080519060200190610062929190610132565b5034801561006e575f80fd5b5060015f1b5f8081548110610086576100856101c5565b5b905f5260205f20018190555060025f1b5f6001815481106100aa576100a96101c5565b5b905f5260205f2001819055507001000000000000000000000000000000005f1b5f6002815481106100de576100dd6101c5565b5b905f5260205f2001819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f1b5f600381548110610121576101206101c5565b5b905f5260205f2001819055506101f2565b828054828255905f5260205f2090810192821561016c579160200282015b8281111561016b578251825591602001919060010190610150565b5b509050610179919061017d565b5090565b5b80821115610194575f815f90555060010161017e565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b61054d806101ff5f395ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c806308cf7e911461004e5780633ba13899146100585780634f3f02ee14610062578063d0519a7f1461006c575b5f80fd5b610056610076565b005b610060610130565b005b61006a610316565b005b6100746103cf565b005b5f805f90505b5f8054905081101561012c575f80828154811061009c5761009b61048c565b5b905f5260205f200154905080815d805c92508083036100e6577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161011e565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd98360405161011591906104d1565b60405180910390a15b50808060010191505061007c565b5050565b5f80600467ffffffffffffffff81111561014d5761014c6104ea565b5b60405190808252806020026020018201604052801561017b5781602001602082028036833780820191505090505b50905060035f1b815f815181106101955761019461048c565b5b60200260200101818152505060045f1b816001815181106101b9576101b861048c565b5b6020026020010181815250507001000000000000000000000000000000015f1b816002815181106101ed576101ec61048c565b5b6020026020010181815250507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5f1b816003815181106102305761022f61048c565b5b6020026020010181815250505f5b5f80549050811015610311575f80828154811061025e5761025d61048c565b5b905f5260205f20015490505f83838151811061027d5761027c61048c565b5b602002602001015190506104d2825d805c94505f801b85036102ca577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610302565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9856040516102f991906104d1565b60405180910390a15b5050808060010191505061023e565b505050565b5f805f90505b5f805490508110156103cb575f80828154811061033c5761033b61048c565b5b905f5260205f2001549050805c92505f801b8303610385577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16103bd565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9836040516103b491906104d1565b60405180910390a15b50808060010191505061031c565b5050565b5f805f90505b5f80549050811015610488575f8082815481106103f5576103f461048c565b5b905f5260205f200154905060ff8155805c92505f801b8303610442577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161047a565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd98360405161047191906104d1565b60405180910390a15b5080806001019150506103d5565b5050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f819050919050565b6104cb816104b9565b82525050565b5f6020820190506104e45f8301846104c2565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea26469706673582212204bf46b78c1fcafe2ef7b46d0b4632777b5d37316aed745194ce7eac231a4f4c464736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageContract + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute +transaction_build txTestTloadAfterSstore + sender acc1 + nonce 1 + contract txTestTransientStorageContract + value 0 + data d0519a7f + gas 200000 + build + +# Create block to hold TloadAfterSstore transaction +block_build b02 + parent b01 + transactions txTestTloadAfterSstore + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute +transaction_build txTestTloadAfterTstore + sender acc1 + nonce 2 + contract txTestTransientStorageContract + value 0 + data 08cf7e91 + gas 200000 + build + +# Create block to hold txTest transaction +block_build b03 + parent b02 + transactions txTestTloadAfterTstore + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b02 is best block +assert_best b03 + +# Create transaction to execute +transaction_build txTestTransientUnsetValues + sender acc1 + nonce 3 + contract txTestTransientStorageContract + value 0 + data 4f3f02ee + gas 200000 + build + +# Create block to hold txTestTransientUnsetValues transaction +block_build b04 + parent b03 + transactions txTestTransientUnsetValues + gasLimit 350000 + build + +# Connect block +block_connect b04 + +# Check b02 is best block +assert_best b04 + +# Create transaction to execute +transaction_build txTestTloadAfterTstoreIsZero + sender acc1 + nonce 4 + contract txTestTransientStorageContract + value 0 + data 3ba13899 + gas 200000 + build + +# Create block to hold txTestTloadAfterTstoreIsZero transaction +block_build b05 + parent b04 + transactions txTestTloadAfterTstoreIsZero + gasLimit 350000 + build + +# Connect block +block_connect b05 + +# Check b02 is best block +assert_best b05 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt new file mode 100644 index 00000000000..75461e5b2f9 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt @@ -0,0 +1,142 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract InConstructorAndCode { + + constructor() { + bytes32 valueLoadedInitially; + assembly{ + valueLoadedInitially := tload(0) + } + checkReturnValueExpected(valueLoadedInitially, 'Checking value loaded in 0 from creator is inacessible in constructor', 0x00); + } + + event OK(); + event ERROR(string, bytes32); + + function deployedCode() external { + bytes32 valueLoadedInitially; + bytes32 valueLoadedAfterStore; + assembly{ + valueLoadedInitially := tload(0) + tstore(1,0x0000000000000000000000000000000100000000000000000000000000000001) + valueLoadedAfterStore := tload(1) + } + checkReturnValueExpected(valueLoadedInitially, 'Checking value loaded in 0 from creator is inacessible in deployed code', 0x00); + checkReturnValueExpected(valueLoadedAfterStore, 'Checking value stored in 1 from deployed is accessible', 0x0000000000000000000000000000000100000000000000000000000000000001); + } + + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract TestStorageCreateContexts { + constructor(){ + } + + event OK(); + event ERROR(string, bytes32); + + function testInConstructorAndCode() external { + configureTransientStorageFromCaller(); + InConstructorAndCode testContract = new InConstructorAndCode(); + testContract.deployedCode(); + checkTransientStorageFromCaller(); + } + + function configureTransientStorageFromCaller() private { + assembly{ + tstore(0, 0x0000000000000000000000000000000000000000000000000000000000000002) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000003) + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000004) + calldatacopy(0, 0, calldatasize()) + } + } + + function checkTransientStorageFromCaller() private { + bytes32 valueIn0Received; + bytes32 valueIn1Received; + bytes32 valueIn2Received; + + assembly{ + valueIn0Received := tload(0) + valueIn1Received := tload(1) + valueIn2Received := tload(2) + } + checkReturnValueExpected(valueIn0Received, 'Checking value in 0', 0x0000000000000000000000000000000000000000000000000000000000000002); + checkReturnValueExpected(valueIn1Received, 'Checking value in 1', 0x0000000000000000000000000000000000000000000000000000000000000003); + checkReturnValueExpected(valueIn2Received, 'Checking value in 2', 0x0000000000000000000000000000000000000000000000000000000000000004); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TestStorageCreateContexts: 6080604052348015600e575f80fd5b5061078c8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c806324182ad51461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b61045b806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe608060405234801561000f575f80fd5b505f805c905061004081604051806080016040528060458152602001610416604591395f801b61004660201b60201c565b50610173565b80830361007e577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100b8565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd382846040516100af929190610145565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ff826100bd565b61010981856100c7565b93506101198185602086016100d7565b610122816100e5565b840191505092915050565b5f819050919050565b61013f8161012d565b82525050565b5f6040820190508181035f83015261015d81856100f5565b905061016c6020830184610136565b9392505050565b610296806101805f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f5c915070010000000000000000000000000000000160015d60015c905061007c826040518060800160405280604781526020016101e4604791395f801b6100b6565b6100b28160405180606001604052806036815260200161022b603691397001000000000000000000000000000000015f1b6100b6565b5050565b8083036100ee577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610128565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161011f9291906101b5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61016f8261012d565b6101798185610137565b9350610189818560208601610147565b61019281610155565b840191505092915050565b5f819050919050565b6101af8161019d565b82525050565b5f6040820190508181035f8301526101cd8185610165565b90506101dc60208301846101a6565b939250505056fe436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e206465706c6f79656420636f6465436865636b696e672076616c75652073746f72656420696e20312066726f6d206465706c6f7965642069732061636365737369626c65a26469706673582212204ceee425512f119ce702deae18164eee3232e3d3df3030b9259ae7cf48cce05d64736f6c634300081a0033436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e20636f6e7374727563746f72a26469706673582212201a9e5334b9d41459e465fb8c2d62cd42e734141dc331c5944ff8be6dcae694e764736f6c634300081a0033 + +24182ad5: testInConstructorAndCode() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCreateContextsContract contract +transaction_build txTestTransientStorageCreateContextsContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b5061078c8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c806324182ad51461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b61045b806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe608060405234801561000f575f80fd5b505f805c905061004081604051806080016040528060458152602001610416604591395f801b61004660201b60201c565b50610173565b80830361007e577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100b8565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd382846040516100af929190610145565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ff826100bd565b61010981856100c7565b93506101198185602086016100d7565b610122816100e5565b840191505092915050565b5f819050919050565b61013f8161012d565b82525050565b5f6040820190508181035f83015261015d81856100f5565b905061016c6020830184610136565b9392505050565b610296806101805f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f5c915070010000000000000000000000000000000160015d60015c905061007c826040518060800160405280604781526020016101e4604791395f801b6100b6565b6100b28160405180606001604052806036815260200161022b603691397001000000000000000000000000000000015f1b6100b6565b5050565b8083036100ee577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610128565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161011f9291906101b5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61016f8261012d565b6101798185610137565b9350610189818560208601610147565b61019281610155565b840191505092915050565b5f819050919050565b6101af8161019d565b82525050565b5f6040820190508181035f8301526101cd8185610165565b90506101dc60208301846101a6565b939250505056fe436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e206465706c6f79656420636f6465436865636b696e672076616c75652073746f72656420696e20312066726f6d206465706c6f7965642069732061636365737369626c65a26469706673582212204ceee425512f119ce702deae18164eee3232e3d3df3030b9259ae7cf48cce05d64736f6c634300081a0033436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e20636f6e7374727563746f72a26469706673582212201a9e5334b9d41459e465fb8c2d62cd42e734141dc331c5944ff8be6dcae694e764736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageCreateContextsContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txInConstructorAndCode transaction +transaction_build txInConstructorAndCode + sender acc1 + nonce 1 + contract txTestTransientStorageCreateContextsContract + value 0 + data 24182ad5 + gas 1000000 + build + +# Create block to hold txInConstructorAndCode transaction +block_build b02 + parent b01 + transactions txInConstructorAndCode + gasLimit 3000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt new file mode 100644 index 00000000000..80b69f93731 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt @@ -0,0 +1,137 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract NoConstructorCode { + + constructor() { + } + + event OK(); + event ERROR(string, bytes32); + + function deployedCode() external { + bytes32 valueLoadedInitially; + bytes32 valueLoadedAfterStore; + assembly{ + valueLoadedInitially := tload(0) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000555) + valueLoadedAfterStore := tload(1) + } + checkReturnValueExpected(valueLoadedInitially, 'Checking value loaded in 0 from creator is inacessible in deployed code', 0x00); + checkReturnValueExpected(valueLoadedAfterStore, 'Checking value stored in 1 from deployed is accessible', 0x0000000000000000000000000000000000000000000000000000000000000555); + } + + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract TestStorageCreateContexts { + constructor(){ + } + + event OK(); + event ERROR(string, bytes32); + + function testNoConstructorCode() external { + configureTransientStorageFromCaller(); + NoConstructorCode testContract = new NoConstructorCode(); + testContract.deployedCode(); + checkTransientStorageFromCaller(); + } + + function configureTransientStorageFromCaller() private { + assembly{ + tstore(0, 0x0000000000000000000000000000000000000000000000000000000000000002) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000003) + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000004) + calldatacopy(0, 0, calldatasize()) + } + } + + function checkTransientStorageFromCaller() private { + bytes32 valueIn0Received; + bytes32 valueIn1Received; + bytes32 valueIn2Received; + + assembly{ + valueIn0Received := tload(0) + valueIn1Received := tload(1) + valueIn2Received := tload(2) + } + checkReturnValueExpected(valueIn0Received, 'Checking value in 0', 0x0000000000000000000000000000000000000000000000000000000000000002); + checkReturnValueExpected(valueIn1Received, 'Checking value in 1', 0x0000000000000000000000000000000000000000000000000000000000000003); + checkReturnValueExpected(valueIn2Received, 'Checking value in 2', 0x0000000000000000000000000000000000000000000000000000000000000004); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TestStorageCreateContexts: 6080604052348015600e575f80fd5b506105c58061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063aeb8338c1461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b610294806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe6080604052348015600e575f80fd5b506102788061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f5c915061055560015d60015c905061006d826040518060800160405280604781526020016101c6604791395f801b610098565b6100948160405180606001604052806036815260200161020d603691396105555f1b610098565b5050565b8083036100d0577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161010a565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd38284604051610101929190610197565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6101518261010f565b61015b8185610119565b935061016b818560208601610129565b61017481610137565b840191505092915050565b5f819050919050565b6101918161017f565b82525050565b5f6040820190508181035f8301526101af8185610147565b90506101be6020830184610188565b939250505056fe436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e206465706c6f79656420636f6465436865636b696e672076616c75652073746f72656420696e20312066726f6d206465706c6f7965642069732061636365737369626c65a26469706673582212207a7362f3095add92a0a854cee8d39f155bec093d65abc358095a3c70c8517c3164736f6c634300081a0033a2646970667358221220f92680fe2ad24e88124b423703506fbb1ee4964eebdc02acdfe21bb7b036a13c64736f6c634300081a0033 + +06c31e01: testNoConstructorCode() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCreateContextsContract contract +transaction_build txTestTransientStorageCreateContextsContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b506105c58061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063aeb8338c1461002d575b5f80fd5b610035610037565b005b61003f6100ce565b5f60405161004c90610238565b604051809103905ff080158015610065573d5f803e3d5ffd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663a45449eb6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156100ad575f80fd5b505af11580156100bf573d5f803e3d5ffd5b505050506100cb6100e2565b50565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c9050610136836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b6101c1565b610179826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b6101c1565b6101bc816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b6101c1565b505050565b8083036101f9577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610233565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd3828460405161022a9291906102cd565b60405180910390a15b505050565b610294806102fc83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61028782610245565b610291818561024f565b93506102a181856020860161025f565b6102aa8161026d565b840191505092915050565b5f819050919050565b6102c7816102b5565b82525050565b5f6040820190508181035f8301526102e5818561027d565b90506102f460208301846102be565b939250505056fe6080604052348015600e575f80fd5b506102788061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063a45449eb1461002d575b5f80fd5b610035610037565b005b5f805f5c915061055560015d60015c905061006d826040518060800160405280604781526020016101c6604791395f801b610098565b6100948160405180606001604052806036815260200161020d603691396105555f1b610098565b5050565b8083036100d0577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161010a565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd38284604051610101929190610197565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6101518261010f565b61015b8185610119565b935061016b818560208601610129565b61017481610137565b840191505092915050565b5f819050919050565b6101918161017f565b82525050565b5f6040820190508181035f8301526101af8185610147565b90506101be6020830184610188565b939250505056fe436865636b696e672076616c7565206c6f6164656420696e20302066726f6d2063726561746f7220697320696e616365737369626c6520696e206465706c6f79656420636f6465436865636b696e672076616c75652073746f72656420696e20312066726f6d206465706c6f7965642069732061636365737369626c65a26469706673582212207a7362f3095add92a0a854cee8d39f155bec093d65abc358095a3c70c8517c3164736f6c634300081a0033a2646970667358221220f92680fe2ad24e88124b423703506fbb1ee4964eebdc02acdfe21bb7b036a13c64736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageCreateContextsContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txNoConstructorCode transaction +transaction_build txNoConstructorCode + sender acc1 + nonce 1 + contract txTestTransientStorageCreateContextsContract + value 0 + data aeb8338c + gas 1000000 + build + +# Create block to hold txNoConstructorCode transaction +block_build b02 + parent b01 + transactions txNoConstructorCode + gasLimit 2000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt new file mode 100644 index 00000000000..a4b4dc88923 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt @@ -0,0 +1,133 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract OnlyConstructorCode { + + constructor() { + bytes32 valueLoadedInitially; + bytes32 valueLoadedAfterStore; + assembly{ + valueLoadedInitially := tload(0) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000002) + valueLoadedAfterStore := tload(1) + } + if(valueLoadedInitially == 0x0000){ + emit OK(); + } else { + emit ERROR(valueLoadedInitially); + } + + if(valueLoadedAfterStore == 0x0000000000000000000000000000000000000000000000000000000000000002){ + emit OK(); + } else { + emit ERROR(valueLoadedAfterStore); + } + } + + event OK(); + event ERROR(bytes32); +} + +contract TestStorageCreateContexts { + constructor(){ + } + + event OK(); + event ERROR(string, bytes32); + + function testOnlyConstructorCode() external { + configureTransientStorageFromCaller(); + new OnlyConstructorCode(); + checkTransientStorageFromCaller(); + } + + function configureTransientStorageFromCaller() private { + assembly{ + tstore(0, 0x0000000000000000000000000000000000000000000000000000000000000002) + tstore(1, 0x0000000000000000000000000000000000000000000000000000000000000003) + tstore(2, 0x0000000000000000000000000000000000000000000000000000000000000004) + calldatacopy(0, 0, calldatasize()) + } + } + + function checkTransientStorageFromCaller() private { + bytes32 valueIn0Received; + bytes32 valueIn1Received; + bytes32 valueIn2Received; + + assembly{ + valueIn0Received := tload(0) + valueIn1Received := tload(1) + valueIn2Received := tload(2) + } + checkReturnValueExpected(valueIn0Received, 'Checking value in 0', 0x0000000000000000000000000000000000000000000000000000000000000002); + checkReturnValueExpected(valueIn1Received, 'Checking value in 1', 0x0000000000000000000000000000000000000000000000000000000000000003); + checkReturnValueExpected(valueIn2Received, 'Checking value in 2', 0x0000000000000000000000000000000000000000000000000000000000000004); + } + + function checkReturnValueExpected(bytes32 valueReceived, string memory message, bytes32 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TestStorageCreateContexts: 6080604052348015600e575f80fd5b5061045a8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c806306c31e011461002d575b5f80fd5b610035610037565b005b61003f610070565b60405161004b906101da565b604051809103905ff080158015610064573d5f803e3d5ffd5b505061006e610084565b565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c90506100d8836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b610163565b61011b826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b610163565b61015e816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b610163565b505050565b80830361019b577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101d5565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd382846040516101cc92919061026f565b60405180910390a15b505050565b6101878061029e83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610229826101e7565b61023381856101f1565b9350610243818560208601610201565b61024c8161020f565b840191505092915050565b5f819050919050565b61026981610257565b82525050565b5f6040820190508181035f830152610287818561021f565b90506102966020830184610260565b939250505056fe608060405234801561000f575f80fd5b505f805f5c9150600260015d60015c90505f801b820361005a577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610092565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9826040516100899190610124565b60405180910390a15b60025f1b81036100cd577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610105565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516100fc9190610124565b60405180910390a15b505061013d565b5f819050919050565b61011e8161010c565b82525050565b5f6020820190506101375f830184610115565b92915050565b603e806101495f395ff3fe60806040525f80fdfea26469706673582212208c7f41dc7ce3e60c1ac6a8857d261787c82e80556c6e9301ddc90b0332365ae764736f6c634300081a0033a2646970667358221220dd0d78a91f17116a6d00e03e0496b3200f5de2bc835011e5943baa5b8dab956e64736f6c634300081a0033 + +06c31e01: testOnlyConstructorCode() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCreateContextsContract contract +transaction_build txTestTransientStorageCreateContextsContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b5061045a8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c806306c31e011461002d575b5f80fd5b610035610037565b005b61003f610070565b60405161004b906101da565b604051809103905ff080158015610064573d5f803e3d5ffd5b505061006e610084565b565b60025f5d600360015d600460025d365f8037565b5f805f805c925060015c915060025c90506100d8836040518060400160405280601381526020017f436865636b696e672076616c756520696e20300000000000000000000000000081525060025f1b610163565b61011b826040518060400160405280601381526020017f436865636b696e672076616c756520696e20310000000000000000000000000081525060035f1b610163565b61015e816040518060400160405280601381526020017f436865636b696e672076616c756520696e20320000000000000000000000000081525060045f1b610163565b505050565b80830361019b577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101d5565b7f76846b797b13411b14ef41db4387da9918f2f43457c5528a2423c48d45704bd382846040516101cc92919061026f565b60405180910390a15b505050565b6101878061029e83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610229826101e7565b61023381856101f1565b9350610243818560208601610201565b61024c8161020f565b840191505092915050565b5f819050919050565b61026981610257565b82525050565b5f6040820190508181035f830152610287818561021f565b90506102966020830184610260565b939250505056fe608060405234801561000f575f80fd5b505f805f5c9150600260015d60015c90505f801b820361005a577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610092565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9826040516100899190610124565b60405180910390a15b60025f1b81036100cd577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610105565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516100fc9190610124565b60405180910390a15b505061013d565b5f819050919050565b61011e8161010c565b82525050565b5f6020820190506101375f830184610115565b92915050565b603e806101495f395ff3fe60806040525f80fdfea26469706673582212208c7f41dc7ce3e60c1ac6a8857d261787c82e80556c6e9301ddc90b0332365ae764736f6c634300081a0033a2646970667358221220dd0d78a91f17116a6d00e03e0496b3200f5de2bc835011e5943baa5b8dab956e64736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageCreateContextsContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txOnlyConstructorCode transaction +transaction_build txOnlyConstructorCode + sender acc1 + nonce 1 + contract txTestTransientStorageCreateContextsContract + value 0 + data 06c31e01 + gas 1000000 + build + +# Create block to hold txOnlyConstructorCode transaction +block_build b02 + parent b01 + transactions txOnlyConstructorCode + gasLimit 1200000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt deleted file mode 100644 index e8312fc8cb4..00000000000 --- a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_contract.txt +++ /dev/null @@ -1,124 +0,0 @@ -comment - -// CONTRACT CODE - -pragma solidity ^0.8.24; - -contract TestTransientStorage { - constructor() {} - - event OK(); - event ERROR(); - - function checkTStore() external { - bytes32 valueToSave = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f; - address contractAddress = address(this); - assembly { - tstore(contractAddress, valueToSave) // Use TSTORE to save the value at the contract address on the transient storage - } - } - - function checkTLoad() external { - bytes32 valueSaved = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f; - bytes32 valueLoaded; - address contractAddress = address(this); - assembly { - valueLoaded := tload(contractAddress) // Use TLOAD to load the value into the temporary variable - } - if (valueLoaded == valueSaved) { - emit OK(); - } else { - emit ERROR(); - } - } -} - -// DESCRIPTION - -This contract contains two functions: checkTStore and checkTLoad. - -* checkTStore simply checks if the transaction finished with success and it's expected to have saved the value on the address - -* checkTLoad simply checks if the transaction finished with success and check if the value loaded is the same as the value saved - - -// CONTRACT BYTECODE - -608060405234801561000f575f80fd5b5061014a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063a36ca99d14610038578063d5ad4e0b14610042575b5f80fd5b61004061004c565b005b61004a61007c565b005b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f30905081815d5050565b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f80309050805c91508282036100e2577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161010f565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50505056fea2646970667358221220c97a07f12090a982975e295ffa092efe648f43916b098afb2523daffb7e42df464736f6c63430008180033 - -// CONTRACT CALL - -- checkTStore() -> a36ca99d -- checkTLoad() -> d5ad4e0b - -end - -# Create and fund new account -account_new acc1 10000000 - -# Create transaction to deploy TestTransientStorage contract -transaction_build txTestTransientStorageContract - sender acc1 - receiverAddress 00 - value 0 - data 608060405234801561000f575f80fd5b5061014a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063a36ca99d14610038578063d5ad4e0b14610042575b5f80fd5b61004061004c565b005b61004a61007c565b005b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f30905081815d5050565b5f7e0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f5f1b90505f80309050805c91508282036100e2577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161010f565b7f1c9c433b57013295d61f5c5738f5e2cb1de70bb5ba5b2896edfa8efae345965e60405160405180910390a15b50505056fea2646970667358221220c97a07f12090a982975e295ffa092efe648f43916b098afb2523daffb7e42df464736f6c63430008180033 - gas 1200000 - build - -# Create block to hold txTestTransientStorageContract transaction -block_build b01 - parent g00 - transactions txTestTransientStorageContract - build - -# Connect block -block_connect b01 - -# Check b01 is best block -assert_best b01 - -# Create transaction to execute checkTStore() method -transaction_build txTestTStore - sender acc1 - nonce 1 - contract txTestTransientStorageContract - value 0 - data a36ca99d - gas 30000 - build - -# Create block to hold txTestTStore transaction -block_build b02 - parent b01 - transactions txTestTStore - gasLimit 6500000 - build - -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - -# Create transaction to execute checkTLoad() method -transaction_build txTestTLoad - sender acc1 - nonce 2 - contract txTestTransientStorageContract - value 0 - data d5ad4e0b - gas 30000 - build - -# Create block to hold txTestTLoad transaction -block_build b03 - parent b02 - transactions txTestTLoad - gasLimit 6500000 - build - -# Connect block -block_connect b03 - -# Check b02 is best block -assert_best b03 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt new file mode 100644 index 00000000000..0607af0de7a --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt @@ -0,0 +1,246 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestTransientStorage { + constructor() {} + + event OK(); + event ERROR(bytes32); + + function checkTransientStorage(bytes32 key, bytes32 value) external { + bytes32 valueLoaded; + assembly { + tstore(key, value) + valueLoaded := tload(key) + } + if (valueLoaded == value) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } + + function checkDataEqualsTheValuePassed(bytes32 key, bytes32 valueExpected) external { + bytes32 valueLoaded; + assembly { + valueLoaded := tload(key) + } + if (valueLoaded == valueExpected) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } + + function checkIfNestedTransactionSameContractShareMemory(bytes32 key, bytes32 value) external { + assembly { + tstore(key, value) + } + this.checkDataEqualsTheValuePassed(key, value); + } + + function checkIfNestedTransactionFromOtherContractShareMemory(bytes32 key, bytes32 value) external { + assembly { + tstore(key, value) + } + new TestTransientStorageOtherContract().checkDataEqualsTheValuePassed(key, value); + } +} + +contract TestTransientStorageOtherContract{ + constructor() {} + + event OK(); + event ERROR(bytes32); + + function checkDataEqualsTheValuePassed(bytes32 key, bytes32 valueExpected) external { + bytes32 valueLoaded; + assembly { + valueLoaded := tload(key) + } + if (valueLoaded == valueExpected) { + emit OK(); + } else { + emit ERROR(valueLoaded); + } + } +} + +// DESCRIPTION + +TestTransientStorage has the following functions: + +* checkTransientStorage simply checks if the TSTORE and TLOAD functions are working properly. It stores a value in the transient storage and then loads it. If the loaded value is the same as the stored value, it emits an OK event. Otherwise, it emits an ERROR event. + +* checkDataEqualsTheValuePassed simply checks if the transaction TLOAD doesn't load a value that was not stored in the transient storage. It loads a value from the transient storage, if we haven't loaded with a nested transaction it will return 0 otherwise it will return the value stored. +If the value loaded is the same as the value passed as a parameter, it emits an OK event. Otherwise, it emits an ERROR event. + +* checkIfNestedTransactionSameContractShareMemory stores a value in the transient storage and then calls a function from the same contract that loads the value from the transient storage. This is to check if the transient storage is shared between nested transactions. + +* checkIfNestedTransactionFromOtherContractShareMemory stores a value in the transient storage and then calls a function from another contract that loads the value from the transient storage. This is to check if the transient storage is not shared between transactions. + +TestTransientStorageOtherContract has the following functions: + +* checkDataEqualsTheValuePassed simply checks if the transaction TLOAD doesn't load a value that was not stored in the transient storage. It loads a value from the transient storage, if we haven't loaded with a nested transaction it will return 0 otherwise it will return the value stored. +If the value loaded is the same as the value passed as a parameter, it emits an OK event. Otherwise, it emits an ERROR event. + +// CONTRACT BYTECODE + +TestTransientStorage: 6080604052348015600e575f80fd5b506105718061001c5f395ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c80635dbdd0ce1461004e5780637b70ef4e1461006a5780637dccab6614610086578063f5cc67a1146100a2575b5f80fd5b610068600480360381019061006391906102fc565b6100be565b005b610084600480360381019061007f91906102fc565b61012d565b005b6100a0600480360381019061009b91906102fc565b6101c1565b005b6100bc60048036038101906100b791906102fc565b61023b565b005b80825d3073ffffffffffffffffffffffffffffffffffffffff16637dccab6683836040518363ffffffff1660e01b81526004016100fc929190610349565b5f604051808303815f87803b158015610113575f80fd5b505af1158015610125573d5f803e3d5ffd5b505050505050565b80825d60405161013c906102b8565b604051809103905ff080158015610155573d5f803e3d5ffd5b5073ffffffffffffffffffffffffffffffffffffffff16637dccab6683836040518363ffffffff1660e01b8152600401610190929190610349565b5f604051808303815f87803b1580156101a7575f80fd5b505af11580156101b9573d5f803e3d5ffd5b505050505050565b5f825c90508181036101fe577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610236565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd98160405161022d9190610370565b60405180910390a15b505050565b5f81835d825c905081810361027b577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16102b3565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516102aa9190610370565b60405180910390a15b505050565b6101b28061038a83390190565b5f80fd5b5f819050919050565b6102db816102c9565b81146102e5575f80fd5b50565b5f813590506102f6816102d2565b92915050565b5f8060408385031215610312576103116102c5565b5b5f61031f858286016102e8565b9250506020610330858286016102e8565b9150509250929050565b610343816102c9565b82525050565b5f60408201905061035c5f83018561033a565b610369602083018461033a565b9392505050565b5f6020820190506103835f83018461033a565b9291505056fe6080604052348015600e575f80fd5b506101968061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80637dccab661461002d575b5f80fd5b610047600480360381019061004291906100fa565b610049565b005b5f825c9050818103610086577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100be565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516100b59190610147565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6100d9816100c7565b81146100e3575f80fd5b50565b5f813590506100f4816100d0565b92915050565b5f80604083850312156101105761010f6100c3565b5b5f61011d858286016100e6565b925050602061012e858286016100e6565b9150509250929050565b610141816100c7565b82525050565b5f60208201905061015a5f830184610138565b9291505056fea2646970667358221220299e78f210bb50b25e55a7d3d761eb697663f501d6b877c5f17e651d5c7111fb64736f6c634300081a0033a2646970667358221220d99f2c2087ad3b0f2283262f95bb66f6becb8b8538af83c1a9a571716f0abb1b64736f6c634300081a0033 + +TestTransientStorageOtherContract: 6080604052348015600e575f80fd5b506101968061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80637dccab661461002d575b5f80fd5b610047600480360381019061004291906100fa565b610049565b005b5f825c9050818103610086577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100be565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516100b59190610147565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6100d9816100c7565b81146100e3575f80fd5b50565b5f813590506100f4816100d0565b92915050565b5f80604083850312156101105761010f6100c3565b5b5f61011d858286016100e6565b925050602061012e858286016100e6565b9150509250929050565b610141816100c7565b82525050565b5f60208201905061015a5f830184610138565b9291505056fea2646970667358221220299e78f210bb50b25e55a7d3d761eb697663f501d6b877c5f17e651d5c7111fb64736f6c634300081a0033 + +// CONTRACT CALLS + +TestTransientStorage: + + 7dccab66: checkDataEqualsTheValuePassed(bytes32,bytes32) + 7b70ef4e: checkIfNestedTransactionFromOtherContractShareMemory(bytes32,bytes32) + 5dbdd0ce: checkIfNestedTransactionSameContractShareMemory(bytes32,bytes32) + f5cc67a1: checkTransientStorage(bytes32,bytes32) + +TestTransientStorageOtherContract: +- 7dccab66 -> checkDataEqualsTheValuePassed(bytes32,bytes32) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorage contract +transaction_build txTestTransientStorageContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b506105718061001c5f395ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c80635dbdd0ce1461004e5780637b70ef4e1461006a5780637dccab6614610086578063f5cc67a1146100a2575b5f80fd5b610068600480360381019061006391906102fc565b6100be565b005b610084600480360381019061007f91906102fc565b61012d565b005b6100a0600480360381019061009b91906102fc565b6101c1565b005b6100bc60048036038101906100b791906102fc565b61023b565b005b80825d3073ffffffffffffffffffffffffffffffffffffffff16637dccab6683836040518363ffffffff1660e01b81526004016100fc929190610349565b5f604051808303815f87803b158015610113575f80fd5b505af1158015610125573d5f803e3d5ffd5b505050505050565b80825d60405161013c906102b8565b604051809103905ff080158015610155573d5f803e3d5ffd5b5073ffffffffffffffffffffffffffffffffffffffff16637dccab6683836040518363ffffffff1660e01b8152600401610190929190610349565b5f604051808303815f87803b1580156101a7575f80fd5b505af11580156101b9573d5f803e3d5ffd5b505050505050565b5f825c90508181036101fe577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610236565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd98160405161022d9190610370565b60405180910390a15b505050565b5f81835d825c905081810361027b577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16102b3565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516102aa9190610370565b60405180910390a15b505050565b6101b28061038a83390190565b5f80fd5b5f819050919050565b6102db816102c9565b81146102e5575f80fd5b50565b5f813590506102f6816102d2565b92915050565b5f8060408385031215610312576103116102c5565b5b5f61031f858286016102e8565b9250506020610330858286016102e8565b9150509250929050565b610343816102c9565b82525050565b5f60408201905061035c5f83018561033a565b610369602083018461033a565b9392505050565b5f6020820190506103835f83018461033a565b9291505056fe6080604052348015600e575f80fd5b506101968061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80637dccab661461002d575b5f80fd5b610047600480360381019061004291906100fa565b610049565b005b5f825c9050818103610086577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100be565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516100b59190610147565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6100d9816100c7565b81146100e3575f80fd5b50565b5f813590506100f4816100d0565b92915050565b5f80604083850312156101105761010f6100c3565b5b5f61011d858286016100e6565b925050602061012e858286016100e6565b9150509250929050565b610141816100c7565b82525050565b5f60208201905061015a5f830184610138565b9291505056fea2646970667358221220299e78f210bb50b25e55a7d3d761eb697663f501d6b877c5f17e651d5c7111fb64736f6c634300081a0033a2646970667358221220d99f2c2087ad3b0f2283262f95bb66f6becb8b8538af83c1a9a571716f0abb1b64736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageContract transaction +block_build b01 + parent g00 + transactions txTestTransientStorageContract + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to deploy TestTransientStorageOtherContract contract +transaction_build txTestTransientStorageOtherContract + sender acc1 + nonce 1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b506101968061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80637dccab661461002d575b5f80fd5b610047600480360381019061004291906100fa565b610049565b005b5f825c9050818103610086577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100be565b7f2fe0d3bd8bbb632441eefda46ec52f1ddda3a9e827d14c40f422037320f28bd9816040516100b59190610147565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6100d9816100c7565b81146100e3575f80fd5b50565b5f813590506100f4816100d0565b92915050565b5f80604083850312156101105761010f6100c3565b5b5f61011d858286016100e6565b925050602061012e858286016100e6565b9150509250929050565b610141816100c7565b82525050565b5f60208201905061015a5f830184610138565b9291505056fea2646970667358221220299e78f210bb50b25e55a7d3d761eb697663f501d6b877c5f17e651d5c7111fb64736f6c634300081a0033 + gas 1000000 + build + +# Create block to hold txTestTransientStorageOtherContract transaction +block_build b02 + parent b01 + transactions txTestTransientStorageOtherContract + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute checkTransientStorage(bytes32 key, bytes32 value) method +transaction_build txTestTransientStorageOpCodes + sender acc1 + nonce 2 + contract txTestTransientStorageContract + value 0 + data f5cc67a131000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000 + gas 200000 + build + +# Create block to hold txTestTransientStorageOpCodes transaction +block_build b03 + parent b02 + transactions txTestTransientStorageOpCodes + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b02 is best block +assert_best b03 + +# Create transaction to execute checkTransientStorage(bytes32 key, bytes32 value) method +transaction_build txTestTransientStorageOpCodesOtherValue + sender acc1 + nonce 3 + contract txTestTransientStorageContract + value 0 + data f5cc67a132000000000000000000000000000000000000000000000000000000000000003132333435000000000000000000000000000000000000000000000000000000 + gas 200000 + build + +# Create block to hold txTestTransientStorageOpCodesOtherValue transaction +block_build b04 + parent b03 + transactions txTestTransientStorageOpCodesOtherValue + gasLimit 350000 + build + +# Connect block +block_connect b04 + +# Check b02 is best block +assert_best b04 + +# Create transaction to execute checkIfNestedTransactionSameContractShareMemory(bytes32 key, bytes32 value) method +transaction_build txTestTransientStorageNestedTransactionShareMemory + sender acc1 + nonce 4 + contract txTestTransientStorageContract + value 0 + data f5cc67a131300000000000000000000000000000000000000000000000000000000000003230000000000000000000000000000000000000000000000000000000000000 + gas 200000 + build + +# Create block to hold txTestTransientStorageNestedTransactionShareMemory transaction +block_build b05 + parent b04 + transactions txTestTransientStorageNestedTransactionShareMemory + gasLimit 350000 + build + +# Connect block +block_connect b05 + +# Check b02 is best block +assert_best b05 + +# Create transaction to execute checkIfNestedTransactionFromOtherContractShareMemory(bytes32 key, bytes32 value) method +transaction_build txTestTransientStorageNestedTransactionOtherContractDoesntShareMemory + sender acc1 + nonce 5 + contract txTestTransientStorageContract + value 0 + data 7b70ef4e31300000000000000000000000000000000000000000000000000000000000003230000000000000000000000000000000000000000000000000000000000000 + gas 200000 + build + +# Create block to hold txTestTransientStorageNestedTransactionOtherContractDoesntShareMemory transaction +block_build b06 + parent b05 + transactions txTestTransientStorageNestedTransactionOtherContractDoesntShareMemory + gasLimit 350000 + build + +# Connect block +block_connect b06 + +# Check b02 is best block +assert_best b06 + From 99599fb9b1d7913ccdf30de7223ccba481b679c3 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Tue, 5 Nov 2024 14:45:12 +0100 Subject: [PATCH 12/22] Fixing some sonar issues --- .../main/java/org/ethereum/vm/OpCodes.java | 13 +- .../src/main/java/org/ethereum/vm/VM.java | 167 +++++++++--------- .../vm/opcode/TransientStorageDslTest.java | 2 +- .../rsk/vm/opcode/TransientStorageTest.java | 23 --- 4 files changed, 92 insertions(+), 113 deletions(-) delete mode 100644 rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java diff --git a/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java b/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java index e447e7616db..5d48550238f 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java +++ b/rskj-core/src/main/java/org/ethereum/vm/OpCodes.java @@ -24,11 +24,6 @@ * Created by Sergio on 07/07/2016. */ public class OpCodes { - - private OpCodes() { - - } - /** * Halts execution (0x00) */ @@ -328,11 +323,11 @@ private OpCodes() { /** * (0x5c) */ - static final byte OP_TLOAD =0x5c ; + public static final byte OP_TLOAD =0x5c ; /** * (0x5d) */ - static final byte OP_TSTORE =0x5d ; + public static final byte OP_TSTORE =0x5d ; /* Push Operations */ /** @@ -672,4 +667,8 @@ private OpCodes() { * later deletion */ static final byte OP_SUICIDE =(byte)0xff; + + private OpCodes() { + + } } 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 7a3b7e771fa..ea19eb5f292 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1860,14 +1860,15 @@ protected void executeOpcode() { break; case OpCodes.OP_CALLDATACOPY: doCALLDATACOPY(); break; - case OpCodes.OP_CODESIZE: - case OpCodes.OP_EXTCODESIZE: doCODESIZE(); + case OpCodes.OP_CODESIZE, + OpCodes.OP_EXTCODESIZE: + doCODESIZE(); break; - case OpCodes.OP_CODECOPY: - case OpCodes.OP_EXTCODECOPY: doCODECOPY(); + case OpCodes.OP_CODECOPY, + OpCodes.OP_EXTCODECOPY: + doCODECOPY(); break; - case OpCodes.OP_EXTCODEHASH: if (!activations.isActive(RSKIP140)) { throw Program.ExceptionHelper.invalidOpCode(program); @@ -1925,39 +1926,41 @@ protected void executeOpcode() { case OpCodes.OP_POP: doPOP(); break; - case OpCodes.OP_DUP_1: - case OpCodes.OP_DUP_2: - case OpCodes.OP_DUP_3: - case OpCodes.OP_DUP_4: - case OpCodes.OP_DUP_5: - case OpCodes.OP_DUP_6: - case OpCodes.OP_DUP_7: - case OpCodes.OP_DUP_8: - case OpCodes.OP_DUP_9: - case OpCodes.OP_DUP_10: - case OpCodes.OP_DUP_11: - case OpCodes.OP_DUP_12: - case OpCodes.OP_DUP_13: - case OpCodes.OP_DUP_14: - case OpCodes.OP_DUP_15: - case OpCodes.OP_DUP_16: doDUP(); - break; - case OpCodes.OP_SWAP_1: - case OpCodes.OP_SWAP_2: - case OpCodes.OP_SWAP_3: - case OpCodes.OP_SWAP_4: - case OpCodes.OP_SWAP_5: - case OpCodes.OP_SWAP_6: - case OpCodes.OP_SWAP_7: - case OpCodes.OP_SWAP_8: - case OpCodes.OP_SWAP_9: - case OpCodes.OP_SWAP_10: - case OpCodes.OP_SWAP_11: - case OpCodes.OP_SWAP_12: - case OpCodes.OP_SWAP_13: - case OpCodes.OP_SWAP_14: - case OpCodes.OP_SWAP_15: - case OpCodes.OP_SWAP_16: doSWAP(); + case OpCodes.OP_DUP_1 , + OpCodes.OP_DUP_2 , + OpCodes.OP_DUP_3 , + OpCodes.OP_DUP_4 , + OpCodes.OP_DUP_5 , + OpCodes.OP_DUP_6 , + OpCodes.OP_DUP_7 , + OpCodes.OP_DUP_8 , + OpCodes.OP_DUP_9 , + OpCodes.OP_DUP_10 , + OpCodes.OP_DUP_11 , + OpCodes.OP_DUP_12 , + OpCodes.OP_DUP_13 , + OpCodes.OP_DUP_14 , + OpCodes.OP_DUP_15 , + OpCodes.OP_DUP_16: + doDUP(); + break; + case OpCodes.OP_SWAP_1, + OpCodes.OP_SWAP_2, + OpCodes.OP_SWAP_3, + OpCodes.OP_SWAP_4, + OpCodes.OP_SWAP_5, + OpCodes.OP_SWAP_6, + OpCodes.OP_SWAP_7, + OpCodes.OP_SWAP_8, + OpCodes.OP_SWAP_9, + OpCodes.OP_SWAP_10, + OpCodes.OP_SWAP_11, + OpCodes.OP_SWAP_12, + OpCodes.OP_SWAP_13, + OpCodes.OP_SWAP_14, + OpCodes.OP_SWAP_15, + OpCodes.OP_SWAP_16: + doSWAP(); break; case OpCodes.OP_SWAPN: if (activations.isActive(RSKIP191)) { @@ -1968,11 +1971,12 @@ protected void executeOpcode() { break; - case OpCodes.OP_LOG_0: - case OpCodes.OP_LOG_1: - case OpCodes.OP_LOG_2: - case OpCodes.OP_LOG_3: - case OpCodes.OP_LOG_4: doLOG(); + case OpCodes.OP_LOG_0, + OpCodes.OP_LOG_1, + OpCodes.OP_LOG_2, + OpCodes.OP_LOG_3, + OpCodes.OP_LOG_4: + doLOG(); break; case OpCodes.OP_MLOAD: doMLOAD(); break; @@ -2014,38 +2018,39 @@ protected void executeOpcode() { doPUSH0(); break; - case OpCodes.OP_PUSH_1: - case OpCodes.OP_PUSH_2: - case OpCodes.OP_PUSH_3: - case OpCodes.OP_PUSH_4: - case OpCodes.OP_PUSH_5: - case OpCodes.OP_PUSH_6: - case OpCodes.OP_PUSH_7: - case OpCodes.OP_PUSH_8: - case OpCodes.OP_PUSH_9: - case OpCodes.OP_PUSH_10: - case OpCodes.OP_PUSH_11: - case OpCodes.OP_PUSH_12: - case OpCodes.OP_PUSH_13: - case OpCodes.OP_PUSH_14: - case OpCodes.OP_PUSH_15: - case OpCodes.OP_PUSH_16: - case OpCodes.OP_PUSH_17: - case OpCodes.OP_PUSH_18: - case OpCodes.OP_PUSH_19: - case OpCodes.OP_PUSH_20: - case OpCodes.OP_PUSH_21: - case OpCodes.OP_PUSH_22: - case OpCodes.OP_PUSH_23: - case OpCodes.OP_PUSH_24: - case OpCodes.OP_PUSH_25: - case OpCodes.OP_PUSH_26: - case OpCodes.OP_PUSH_27: - case OpCodes.OP_PUSH_28: - case OpCodes.OP_PUSH_29: - case OpCodes.OP_PUSH_30: - case OpCodes.OP_PUSH_31: - case OpCodes.OP_PUSH_32: doPUSH(); + case OpCodes.OP_PUSH_1, + OpCodes.OP_PUSH_2, + OpCodes.OP_PUSH_3, + OpCodes.OP_PUSH_4, + OpCodes.OP_PUSH_5, + OpCodes.OP_PUSH_6, + OpCodes.OP_PUSH_7, + OpCodes.OP_PUSH_8, + OpCodes.OP_PUSH_9, + OpCodes.OP_PUSH_10, + OpCodes.OP_PUSH_11, + OpCodes.OP_PUSH_12, + OpCodes.OP_PUSH_13, + OpCodes.OP_PUSH_14, + OpCodes.OP_PUSH_15, + OpCodes.OP_PUSH_16, + OpCodes.OP_PUSH_17, + OpCodes.OP_PUSH_18, + OpCodes.OP_PUSH_19, + OpCodes.OP_PUSH_20, + OpCodes.OP_PUSH_21, + OpCodes.OP_PUSH_22, + OpCodes.OP_PUSH_23, + OpCodes.OP_PUSH_24, + OpCodes.OP_PUSH_25, + OpCodes.OP_PUSH_26, + OpCodes.OP_PUSH_27, + OpCodes.OP_PUSH_28, + OpCodes.OP_PUSH_29, + OpCodes.OP_PUSH_30, + OpCodes.OP_PUSH_31, + OpCodes.OP_PUSH_32: + doPUSH(); break; case OpCodes.OP_JUMPDEST: doJUMPDEST(); break; @@ -2057,10 +2062,10 @@ protected void executeOpcode() { } doCREATE2(); break; - case OpCodes.OP_CALL: - case OpCodes.OP_CALLCODE: - case OpCodes.OP_DELEGATECALL: - doCALL(); + case OpCodes.OP_CALL, + OpCodes.OP_CALLCODE, + OpCodes.OP_DELEGATECALL: + doCALL(); break; case OpCodes.OP_STATICCALL: if (!activations.isActive(RSKIP91)) { @@ -2227,9 +2232,7 @@ private void dumpLine(OpCode op, long gasBefore, long gasCost, long memWords, Pr RskAddress ownerAddress = new RskAddress(program.getOwnerAddress()); if ("standard+".equals(vmConfig.dumpStyle())) { switch (op) { - case STOP: - case RETURN: - case SUICIDE: + case STOP, RETURN, SUICIDE: Iterator keysIterator = storage.getStorageKeys(ownerAddress); while (keysIterator.hasNext()) { DataWord key = keysIterator.next(); diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index a7d8349adaf..eb365c94adc 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -40,7 +40,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -public class TransientStorageDslTest { +class TransientStorageDslTest { @Test void testTransientStorageOpcodesExecutionsWithRSKIPActivated() throws FileNotFoundException, DslProcessorException { diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java deleted file mode 100644 index a206186f226..00000000000 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of RskJ - * Copyright (C) 2024 RSK Labs Ltd. - * (derived from ethereumJ library, Copyright (c) 2016 ) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package co.rsk.vm.opcode; - -public class TransientStorageTest { -} From ea7d304954394e9448621d811d664abf01c7f80c Mon Sep 17 00:00:00 2001 From: fmacleal <157636304+fmacleal@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:08:57 +0100 Subject: [PATCH 13/22] fmacleal/integrate tstorage in transaction execution (#2844) * Added tests for dynamic execution contexts - WIP - Now we will add unit tests for underflow execution tests * Added tests for dynamic execution contexts - We had to add unit tests for underflow execution tests since isn't possible write contract for these scenarios - Now we have all the tests regarding execution context with different types of calls, missing the gas cost calculation that will be done in a later task * Addressing review comments --- .../src/main/java/org/ethereum/vm/VM.java | 4 + .../vm/opcode/TransientStorageDslTest.java | 30 ++++ .../rsk/vm/opcode/TransientStorageTest.java | 151 ++++++++++++++++++ ...dynamic_execution_context_call_subcall.txt | 127 +++++++++++++++ ...text_staticcall_subcall_can_call_tload.txt | 105 ++++++++++++ ...xt_staticcall_subcall_cant_call_tstore.txt | 106 ++++++++++++ 6 files changed, 523 insertions(+) create mode 100644 rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt 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 ea19eb5f292..0c4d3f999de 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1361,6 +1361,10 @@ protected void doTLOAD(){ protected void doTSTORE(){ //TODO: Gas cost calculation will be done here and also shared contexts verifications for // different types of calls + if (program.isStaticCall()) { + throw Program.ExceptionHelper.modificationException(program); + } + DataWord key = program.stackPop(); DataWord value = program.stackPop(); diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index eb365c94adc..c6ad7378210 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -311,6 +311,36 @@ void testDynamicExecutionContextWithStackOverflow() throws FileNotFoundException Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } + @Test + void testDynamicExecutionCallContextSubcall() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txContextCallSubcallContract = "txContextCallSubcallContract"; + assertTransactionReceiptWithStatus(world, txContextCallSubcallContract, "b01", true); + + String txExecuteCallCode = "txExecuteCallCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + Assertions.assertEquals(6, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testDynamicExecutionStaticCallSubcallCantUseTstore() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txContextStaticCallCantCallTstoreContract = "txContextStaticCallCantCallTstoreContract"; + assertTransactionReceiptWithStatus(world, txContextStaticCallCantCallTstoreContract, "b01", true); + + String txExecuteStaticCallCode = "txExecuteStaticCallCode"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteStaticCallCode, "b02", true); + Assertions.assertEquals(2, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java new file mode 100644 index 00000000000..a033b4e1901 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java @@ -0,0 +1,151 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.vm.opcode; + +import co.rsk.config.TestSystemProperties; +import co.rsk.config.VmConfig; +import co.rsk.vm.BytecodeCompiler; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.core.BlockFactory; +import org.ethereum.core.BlockTxSignatureCache; +import org.ethereum.core.ReceivedTxSignatureCache; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.PrecompiledContracts; +import org.ethereum.vm.VM; +import org.ethereum.vm.program.Program; +import org.ethereum.vm.program.Stack; +import org.ethereum.vm.program.invoke.ProgramInvokeMockImpl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; + +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP446; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class TransientStorageTest { + private final TestSystemProperties config = new TestSystemProperties(); + private final BlockFactory blockFactory = new BlockFactory(config.getActivationConfig()); + private final PrecompiledContracts precompiledContracts = new PrecompiledContracts(config, null, new BlockTxSignatureCache(new ReceivedTxSignatureCache())); + private VmConfig vmConfig = config.getVmConfig(); + private ProgramInvokeMockImpl invoke; + private BytecodeCompiler compiler; + + @BeforeEach + void setup() { + invoke = new ProgramInvokeMockImpl(); + compiler = new BytecodeCompiler(); + } + + @Test + void testTLoadDynamicExecutionContextUnderflow(){ + //given + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + when(activations.isActive(RSKIP446)).thenReturn(true); + + //when-then + Assertions.assertThrows(Program.StackTooSmallException.class, () -> executeCodeWithActivationConfig("TLOAD", 2, activations)); + } + + @Test + void testTLoadDynamicExecutionContextWorksFine(){ + //given + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + when(activations.isActive(RSKIP446)).thenReturn(true); + String expected = "0000000000000000000000000000000000000000000000000000000000000000"; + + //when + Program program = executeCodeWithActivationConfig("PUSH32 0x0000000000000000000000000000000000000000000000000000000000000001 TLOAD", 2, activations); + Stack stack = program.getStack(); + + //then + assertEquals(1, stack.size()); + assertEquals(DataWord.valueFromHex(expected), stack.peek()); + } + + + @Test + void testTStoreDynamicExecutionContextUnderflow(){ + //given + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + when(activations.isActive(RSKIP446)).thenReturn(true); + + //when-then + Assertions.assertThrows(Program.StackTooSmallException.class, () -> executeCodeWithActivationConfig("TSTORE", 3, activations)); + } + + + @Test + void testTStoreDynamicExecutionContextWorksFine(){ + //given + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + when(activations.isActive(RSKIP446)).thenReturn(true); + String expected = "0000000000000000000000000000000000000000000000000000000000000000"; + + //when + Program program = executeCodeWithActivationConfig("PUSH32 0x0000000000000000000000000000000000000000000000000000000000000420 " + + "PUSH32 0x0000000000000000000000000000000000000000000000000000000000000001 " + + "TSTORE", 3, activations); + Stack stack = program.getStack(); + + //then + assertEquals(0, stack.size()); + assertNull(program.getResult().getException()); + } + + @Test + void testTStoreTloadDynamicExecutionContextWorksFine(){ + //given + ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + when(activations.isActive(RSKIP446)).thenReturn(true); + String expected = "0000000000000000000000000000000000000000000000000000000000000420"; + + //when + Program program = executeCodeWithActivationConfig("PUSH32 0x0000000000000000000000000000000000000000000000000000000000000420 " + + "PUSH32 0x0000000000000000000000000000000000000000000000000000000000000001 " + + "TSTORE " + + "PUSH32 0x0000000000000000000000000000000000000000000000000000000000000001 " + + "TLOAD ", 5, activations); + Stack stack = program.getStack(); + + //then + assertEquals(1, stack.size()); + assertEquals(DataWord.valueFromHex(expected), stack.peek()); + } + + + private Program executeCodeWithActivationConfig(String code, int nsteps, ActivationConfig.ForBlock activations) { + return executeCodeWithActivationConfig(compiler.compile(code), nsteps, activations); + } + private Program executeCodeWithActivationConfig(byte[] code, int nsteps, ActivationConfig.ForBlock activations) { + VM vm = new VM(vmConfig, precompiledContracts); + Program program = new Program(vmConfig, precompiledContracts, blockFactory, activations, code, invoke,null, new HashSet<>(), new BlockTxSignatureCache(new ReceivedTxSignatureCache())); + + for (int k = 0; k < nsteps; k++) { + vm.step(program); + } + + return program; + } +} diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt new file mode 100644 index 00000000000..7d6f256c59a --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt @@ -0,0 +1,127 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TestTransientStorageCallContext { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testCall() external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + uint256 valueLoadedFrom1; + uint256 valueLoadedSstore0; + uint256 valueLoadedSstore1; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + success := call(gas(), calleeAddress, 0, availablePointer, 0x4, availablePointer, 0x20) + valueLoadedFrom0 := tload(0) + valueLoadedFrom1 := tload(1) + valueLoadedSstore0 := sload(0) + valueLoadedSstore1 := sload(1) + } + + checkReturnValueExpected(success, 'Checking result callee execution', 1); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + checkReturnValueExpected(valueLoadedFrom1, 'Checking value from tload 1', 0); + + checkReturnValueExpected(valueLoadedSstore0, 'Checking value from sstore 0', 0); + checkReturnValueExpected(valueLoadedSstore1, 'Checking value from sstore 1', 0); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + event OK(); + event ERROR(string, uint256); + + function execute() external { + uint256 valueLoadedFrom1; + assembly { + sstore(0, tload(0)) + tstore(1, 69) + sstore(1, tload(1)) + valueLoadedFrom1 := tload(1) + } + if( valueLoadedFrom1 == 69){ + emit OK(); + } else { + emit ERROR('Checking value from tload 1 in callee', valueLoadedFrom1); + } + } +} + +// CONTRACT BYTECODE + +TestTransientStorageCallContext: 6080604052348015600e575f5ffd5b506105458061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b7f058361461002d575b5f5ffd5b610035610037565b005b5f60405161004490610276565b604051809103905ff08015801561005d573d5f5f3e3d5ffd5b5090505f5f5f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6040518181526020816004835f8c5af196505f5c955060015c94505f5493506001549250506100f4866040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e81525060016101ff565b610136856040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101ff565b610176846040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152505f6101ff565b6101b6836040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652030000000008152505f6101ff565b6101f6826040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652031000000008152505f6101ff565b50505050505050565b808303610237577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610271565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161026892919061030b565b60405180910390a15b505050565b6101d68061033a83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102c582610283565b6102cf818561028d565b93506102df81856020860161029d565b6102e8816102ab565b840191505092915050565b5f819050919050565b610305816102f3565b82525050565b5f6040820190508181035f83015261032381856102bb565b905061033260208301846102fc565b939250505056fe6080604052348015600e575f5ffd5b506101ba8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063614619541461002d575b5f5ffd5b610035610037565b005b5f5f5c5f55604560015d60015c60015560015c905060458103610085577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100bd565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f816040516100b49190610158565b60405180910390a15b50565b5f82825260208201905092915050565b7f436865636b696e672076616c75652066726f6d20746c6f6164203120696e20635f8201527f616c6c6565000000000000000000000000000000000000000000000000000000602082015250565b5f61012a6025836100c0565b9150610135826100d0565b604082019050919050565b5f819050919050565b61015281610140565b82525050565b5f6040820190508181035f83015261016f8161011e565b905061017e6020830184610149565b9291505056fea2646970667358221220525015013274fe464b5371de8d79b5a498b2073f16a0ead556b61bb8daa945d664736f6c634300081c0033a2646970667358221220fe0d0f67ed34e641f6305bc910b9eb817769785a12a0f1837fe2371e930c5d1a64736f6c634300081c0033 + +b7f05836: testCall() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TestTransientStorageCallContext contract +transaction_build txContextCallSubcallContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b506105458061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b7f058361461002d575b5f5ffd5b610035610037565b005b5f60405161004490610276565b604051809103905ff08015801561005d573d5f5f3e3d5ffd5b5090505f5f5f5f5f5f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6040518181526020816004835f8c5af196505f5c955060015c94505f5493506001549250506100f4866040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e81525060016101ff565b610136856040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a46101ff565b610176846040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203100000000008152505f6101ff565b6101b6836040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652030000000008152505f6101ff565b6101f6826040518060400160405280601c81526020017f436865636b696e672076616c75652066726f6d207373746f72652031000000008152505f6101ff565b50505050505050565b808303610237577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610271565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161026892919061030b565b60405180910390a15b505050565b6101d68061033a83390190565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102c582610283565b6102cf818561028d565b93506102df81856020860161029d565b6102e8816102ab565b840191505092915050565b5f819050919050565b610305816102f3565b82525050565b5f6040820190508181035f83015261032381856102bb565b905061033260208301846102fc565b939250505056fe6080604052348015600e575f5ffd5b506101ba8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063614619541461002d575b5f5ffd5b610035610037565b005b5f5f5c5f55604560015d60015c60015560015c905060458103610085577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16100bd565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f816040516100b49190610158565b60405180910390a15b50565b5f82825260208201905092915050565b7f436865636b696e672076616c75652066726f6d20746c6f6164203120696e20635f8201527f616c6c6565000000000000000000000000000000000000000000000000000000602082015250565b5f61012a6025836100c0565b9150610135826100d0565b604082019050919050565b5f819050919050565b61015281610140565b82525050565b5f6040820190508181035f83015261016f8161011e565b905061017e6020830184610149565b9291505056fea2646970667358221220525015013274fe464b5371de8d79b5a498b2073f16a0ead556b61bb8daa945d664736f6c634300081c0033a2646970667358221220fe0d0f67ed34e641f6305bc910b9eb817769785a12a0f1837fe2371e930c5d1a64736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txContextCallSubcallContract transaction +block_build b01 + parent g00 + transactions txContextCallSubcallContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteCallCode transaction +transaction_build txExecuteCallCode + sender acc1 + nonce 1 + contract txContextCallSubcallContract + value 0 + data b7f05836 + gas 1000000 + build + +# Create block to hold txExecuteCallCode transaction +block_build b02 + parent b01 + transactions txExecuteCallCode + gasLimit 2000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt new file mode 100644 index 00000000000..23ec7b497ea --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt @@ -0,0 +1,105 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstorageExecutionContextsStaticCallCanCallTload { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testStaticCall() external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + success := staticcall(gas(), calleeAddress, availablePointer, 0x4, availablePointer, 0x20) + valueLoadedFrom0 := tload(0) + } + + checkReturnValueExpected(success, 'Checking result callee execution', 1); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute() external { + uint256 valueLoadedFrom0; + assembly { + valueLoadedFrom0 := tload(0) + } + } +} +// CONTRACT BYTECODE + +TstorageExecutionContextsStaticCallCanCallTload: 608060405234801561000f575f80fd5b5061033d8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063d411defb1461002d575b5f80fd5b610035610037565b005b5f604051610044906101a1565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f805f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d604051818152602081600483885afa93505f5c9250506100e2836040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e815250600161012a565b610124826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a461012a565b50505050565b808303610162577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161019c565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161019392919061024f565b60405180910390a15b505050565b608a8061027e83390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101e45780820151818401526020810190506101c9565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610209826101ad565b61021381856101b7565b93506102238185602086016101c7565b61022c816101ef565b840191505092915050565b5f819050919050565b61024981610237565b82525050565b5f6040820190508181035f83015261026781856101ff565b90506102766020830184610240565b939250505056fe6080604052348015600e575f80fd5b50607080601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80636146195414602a575b5f80fd5b60306032565b005b5f805c90505056fea26469706673582212208f7b43026cae3d8abeeba9ec0dbacdfc50382579f514a511fcb33502ea8b0b3164736f6c63430008180033a2646970667358221220faf33c612e077d0439d4663f3700736865523f14d281f5a1ac59f82062390bd664736f6c63430008180033 + +d411defb: testStaticCall() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageExecutionContextsStaticCallCanCallTload contract +transaction_build txContextStaticCallCanCallTloadContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b5061033d8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063d411defb1461002d575b5f80fd5b610035610037565b005b5f604051610044906101a1565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f805f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d604051818152602081600483885afa93505f5c9250506100e2836040518060400160405280602081526020017f436865636b696e6720726573756c742063616c6c656520657865637574696f6e815250600161012a565b610124826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a461012a565b50505050565b808303610162577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161019c565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161019392919061024f565b60405180910390a15b505050565b608a8061027e83390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101e45780820151818401526020810190506101c9565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610209826101ad565b61021381856101b7565b93506102238185602086016101c7565b61022c816101ef565b840191505092915050565b5f819050919050565b61024981610237565b82525050565b5f6040820190508181035f83015261026781856101ff565b90506102766020830184610240565b939250505056fe6080604052348015600e575f80fd5b50607080601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80636146195414602a575b5f80fd5b60306032565b005b5f805c90505056fea26469706673582212208f7b43026cae3d8abeeba9ec0dbacdfc50382579f514a511fcb33502ea8b0b3164736f6c63430008180033a2646970667358221220faf33c612e077d0439d4663f3700736865523f14d281f5a1ac59f82062390bd664736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txContextStaticCallCanCallTloadContract transaction +block_build b01 + parent g00 + transactions txContextStaticCallCanCallTloadContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteStaticCallCode transaction +transaction_build txExecuteStaticCallCode + sender acc1 + nonce 1 + contract txContextStaticCallCanCallTloadContract + value 0 + data d411defb + gas 1000000 + build + +# Create block to hold txExecuteStaticCallCode transaction +block_build b02 + parent b01 + transactions txExecuteStaticCallCode + gasLimit 2000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt new file mode 100644 index 00000000000..4bc0112232a --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt @@ -0,0 +1,106 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstorageExecutionContextsStaticCallCantCallTstore { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function testCall() external { + // Deploy the Callee contract + address calleeAddress = address(new Callee()); + uint256 success; + uint256 valueLoadedFrom0; + bytes4 executeSignature = bytes4(keccak256("execute()")); + + assembly { + tstore(0, 420) + let availablePointer := mload(0x40) + mstore(availablePointer, executeSignature) + success := staticcall(0xFFFF, calleeAddress, availablePointer, 0x4, availablePointer, 0x20) + valueLoadedFrom0 := tload(0) + } + + checkReturnValueExpected(success, 'Checking result callee execution fails', 0); + checkReturnValueExpected(valueLoadedFrom0, 'Checking value from tload 0', 420); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + + function execute() external { + assembly { + tstore(1, 69) + } + } +} + +// CONTRACT BYTECODE + +TstorageExecutionContextsStaticCallCantCallTstore: 608060405234801561000f575f80fd5b506103468061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063d411defb1461002d575b5f80fd5b610035610037565b005b5f60405161004490610185565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f805f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6040518181526020816004838861fffffa93505f5c9250506100c6836040518060600160405280602681526020016102eb602691395f61010e565b610108826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a461010e565b50505050565b808303610146577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610180565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610177929190610233565b60405180910390a15b505050565b60898061026283390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101c85780820151818401526020810190506101ad565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6101ed82610191565b6101f7818561019b565b93506102078185602086016101ab565b610210816101d3565b840191505092915050565b5f819050919050565b61022d8161021b565b82525050565b5f6040820190508181035f83015261024b81856101e3565b905061025a6020830184610224565b939250505056fe6080604052348015600e575f80fd5b50606f80601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80636146195414602a575b5f80fd5b60306032565b005b604560015d56fea2646970667358221220a5f01eceb4465312039e37fe5b8913c77743ea042f64eb0e55a16f3e422abde864736f6c63430008180033436865636b696e6720726573756c742063616c6c656520657865637574696f6e206661696c73a2646970667358221220c2660b49032f7ee7ddf39afb75369768bfdc123aa7021d49df042a9ba368053164736f6c63430008180033 + +d411defb: testStaticCall() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageExecutionContextsStaticCallCantCallTstore contract +transaction_build txContextStaticCallCantCallTstoreContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b506103468061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063d411defb1461002d575b5f80fd5b610035610037565b005b5f60405161004490610185565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f805f7f614619540b5b5abe478b88f28a37eb328054be3b41a7570ad5e8b701113364c490506101a45f5d6040518181526020816004838861fffffa93505f5c9250506100c6836040518060600160405280602681526020016102eb602691395f61010e565b610108826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d20746c6f6164203000000000008152506101a461010e565b50505050565b808303610146577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610180565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610177929190610233565b60405180910390a15b505050565b60898061026283390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101c85780820151818401526020810190506101ad565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6101ed82610191565b6101f7818561019b565b93506102078185602086016101ab565b610210816101d3565b840191505092915050565b5f819050919050565b61022d8161021b565b82525050565b5f6040820190508181035f83015261024b81856101e3565b905061025a6020830184610224565b939250505056fe6080604052348015600e575f80fd5b50606f80601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80636146195414602a575b5f80fd5b60306032565b005b604560015d56fea2646970667358221220a5f01eceb4465312039e37fe5b8913c77743ea042f64eb0e55a16f3e422abde864736f6c63430008180033436865636b696e6720726573756c742063616c6c656520657865637574696f6e206661696c73a2646970667358221220c2660b49032f7ee7ddf39afb75369768bfdc123aa7021d49df042a9ba368053164736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txContextStaticCallCantCallTstoreContract transaction +block_build b01 + parent g00 + transactions txContextStaticCallCantCallTstoreContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txExecuteStaticCallCode transaction +transaction_build txExecuteStaticCallCode + sender acc1 + nonce 1 + contract txContextStaticCallCantCallTstoreContract + value 0 + data d411defb + gas 1000000 + build + +# Create block to hold txExecuteStaticCallCode transaction +block_build b02 + parent b01 + transactions txExecuteStaticCallCode + gasLimit 2000000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file From f42093b2278b6994ddb854fc6fc1095335c1bbe9 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Sat, 23 Nov 2024 20:11:53 +0100 Subject: [PATCH 14/22] Added tests for dynamic reentrant contexts - Added scenarios for dynamic executions with revert and invalid --- .../vm/opcode/TransientStorageDslTest.java | 90 ++++++++++ ...y_context_revert_or_invalid_undoes_all.txt | 154 ++++++++++++++++++ ...before_revert_or_invalid_has_no_effect.txt | 144 ++++++++++++++++ ...y_context_manipulate_in_reentrant_call.txt | 136 ++++++++++++++++ ...y_context_tload_after_reentrant_tstore.txt | 133 +++++++++++++++ ...cy_context_tstore_after_reentrant_call.txt | 131 +++++++++++++++ 6 files changed, 788 insertions(+) create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index c6ad7378210..587fef5d36a 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -341,6 +341,96 @@ void testDynamicExecutionStaticCallSubcallCantUseTstore() throws FileNotFoundExc Assertions.assertEquals(2, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } + @Test + void testDynamicReentrancyContextsTstoreBeforeRevertOrInvalidHasNoEffect() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageDynamicReentrancyContextContract = "txTstorageDynamicReentrancyContextContract"; + assertTransactionReceiptWithStatus(world, txTstorageDynamicReentrancyContextContract, "b01", true); + + String txTestReentrantContextRevert = "txTestReentrantContextRevert"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTestReentrantContextRevert, "b02", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txTestReentrantContextInvalid = "txTestReentrantContextInvalid"; + assertTransactionReceiptWithStatus(world, txTestReentrantContextInvalid, "b03", false); + } + + @Test + void testDynamicReentrancyContextsRevertOrInvalidUndoesAll() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageDynamicReentrancyContextContract = "txTstorageDynamicReentrancyContextContract"; + assertTransactionReceiptWithStatus(world, txTstorageDynamicReentrancyContextContract, "b01", true); + + String txTestReentrantContextRevert = "txTestReentrantContextRevert"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTestReentrantContextRevert, "b02", true); + Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txTestReentrantContextInvalid = "txTestReentrantContextInvalid"; + assertTransactionReceiptWithStatus(world, txTestReentrantContextInvalid, "b03", false); + } + + @Test + void testReentrancyContextsTstoreAfterReentrantCall() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageReentrancyContextTestContract = "txTstorageReentrancyContextTestContract"; + assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); + + String txTstoreInReentrantCall = "txTstoreInReentrantCall"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTstoreInReentrantCall, "b02", true); + + String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; + txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testReentrancyContextsTloadAfterReentrantTstore() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageReentrancyContextTestContract = "txTstorageReentrancyContextTestContract"; + assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); + + String txTloadAfterReentrantTstore = "txTloadAfterReentrantTstore"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTloadAfterReentrantTstore, "b02", true); + + String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; + txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + @Test + void testReentrancyContextsManipulateInReentrantCall() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageReentrancyContextTestContract = "txTstorageReentrancyContextTestContract"; + assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); + + String txManipulateInReentrantCall = "txManipulateInReentrantCall"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txManipulateInReentrantCall, "b02", true); + + String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; + txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt new file mode 100644 index 00000000000..23f19e6fa2e --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt @@ -0,0 +1,154 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstorageDynamicReentrancyContext { + bool reentrant = false; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function opcodeUndoesAll(uint256 opcodeSelector) external { + bytes memory data = abi.encodeWithSignature("opcodeUndoesAll(uint256)", opcodeSelector); + uint256 fail; + uint256 valueLoadedFromFEBefore; + uint256 valueLoadedFromFFBefore; + uint256 valueLoadedFromFEAfter; + uint256 valueLoadedFromFFAfter; + + assembly { + let reentrantValue := sload(reentrant.slot) + switch reentrantValue + case 0 { + sstore(reentrant.slot, true) + + tstore(0xFE, 0x100) + tstore(0xFF, 0x101) + valueLoadedFromFEBefore := tload(0xFE) + valueLoadedFromFFBefore := tload(0xFF) + + mstore(0, 2) + switch opcodeSelector + case 0 { + fail := call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0) + } + case 1 { + fail := call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0) + } + valueLoadedFromFEAfter := tload(0xFE) + valueLoadedFromFFAfter := tload(0xFF) + + } + default { + tstore(0xFE, 0x201) + tstore(0xFE, 0x202) + tstore(0xFF, 0x201) + tstore(0xFF, 0x202) + switch opcodeSelector + case 0 { + revert(0, 0) + } + case 1 { + invalid() + } + } + } + checkReturnValueExpected(fail, 'Checking result callee execution fails', 0); + checkReturnValueExpected(valueLoadedFromFEBefore, 'Checking value from tload FE before', 0x100); + checkReturnValueExpected(valueLoadedFromFEAfter, 'Checking value from tload FE after', 0x100); + checkReturnValueExpected(valueLoadedFromFFBefore, 'Checking value from tload FF before', 0x101); + checkReturnValueExpected(valueLoadedFromFFAfter, 'Checking value from tload FF after', 0x101); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageDynamicReentrancyContext: 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b506104e4806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630b35f95c1461002d575b5f80fd5b610047600480360381019061004291906102f3565b610049565b005b5f8160405160240161005b919061032d565b6040516020818303038152906040527f0b35f95c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f805f805f8054805f81146101225761020160fe5d61020260fe5d61020160ff5d61020260ff5d885f8114610116576001811461011a5761011c565b5f80fd5bfe5b50610183565b60015f5561010060fe5d61010160ff5d60fe5c955060ff5c945060025f52885f8114610155576001811461016857610177565b5f808a5160208c015f305af19750610177565b5f808a5160208c015f305af197505b5060fe5c935060ff5c92505b50506101a885604051806060016040528060268152602001610421602691395f610245565b6101cd8460405180606001604052806023815260200161046960239139610100610245565b6101f28260405180606001604052806022815260200161044760229139610100610245565b6102178360405180606001604052806023815260200161048c60239139610101610245565b61023c816040518060600160405280602281526020016103ff60229139610101610245565b50505050505050565b80830361027d577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16102b7565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516102ae9291906103d0565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6102d2816102c0565b81146102dc575f80fd5b50565b5f813590506102ed816102c9565b92915050565b5f60208284031215610308576103076102bc565b5b5f610315848285016102df565b91505092915050565b610327816102c0565b82525050565b5f6020820190506103405f83018461031e565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561037d578082015181840152602081019050610362565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6103a282610346565b6103ac8185610350565b93506103bc818560208601610360565b6103c581610388565b840191505092915050565b5f6040820190508181035f8301526103e88185610398565b90506103f7602083018461031e565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164204646206166746572436865636b696e6720726573756c742063616c6c656520657865637574696f6e206661696c73436865636b696e672076616c75652066726f6d20746c6f6164204645206166746572436865636b696e672076616c75652066726f6d20746c6f6164204645206265666f7265436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f7265a264697066735822122014d79ec53d86680fbb087e64cebf51f7c1e829ea7683527c492cf3316530d26964736f6c63430008180033 + +0b35f95c: opcodeUndoesAll(uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageDynamicReentrancyContext contract +transaction_build txTstorageDynamicReentrancyContextContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b506104e4806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630b35f95c1461002d575b5f80fd5b610047600480360381019061004291906102f3565b610049565b005b5f8160405160240161005b919061032d565b6040516020818303038152906040527f0b35f95c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f805f805f8054805f81146101225761020160fe5d61020260fe5d61020160ff5d61020260ff5d885f8114610116576001811461011a5761011c565b5f80fd5bfe5b50610183565b60015f5561010060fe5d61010160ff5d60fe5c955060ff5c945060025f52885f8114610155576001811461016857610177565b5f808a5160208c015f305af19750610177565b5f808a5160208c015f305af197505b5060fe5c935060ff5c92505b50506101a885604051806060016040528060268152602001610421602691395f610245565b6101cd8460405180606001604052806023815260200161046960239139610100610245565b6101f28260405180606001604052806022815260200161044760229139610100610245565b6102178360405180606001604052806023815260200161048c60239139610101610245565b61023c816040518060600160405280602281526020016103ff60229139610101610245565b50505050505050565b80830361027d577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16102b7565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516102ae9291906103d0565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6102d2816102c0565b81146102dc575f80fd5b50565b5f813590506102ed816102c9565b92915050565b5f60208284031215610308576103076102bc565b5b5f610315848285016102df565b91505092915050565b610327816102c0565b82525050565b5f6020820190506103405f83018461031e565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561037d578082015181840152602081019050610362565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6103a282610346565b6103ac8185610350565b93506103bc818560208601610360565b6103c581610388565b840191505092915050565b5f6040820190508181035f8301526103e88185610398565b90506103f7602083018461031e565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164204646206166746572436865636b696e6720726573756c742063616c6c656520657865637574696f6e206661696c73436865636b696e672076616c75652066726f6d20746c6f6164204645206166746572436865636b696e672076616c75652066726f6d20746c6f6164204645206265666f7265436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f7265a264697066735822122014d79ec53d86680fbb087e64cebf51f7c1e829ea7683527c492cf3316530d26964736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageDynamicReentrancyContextContract transaction +block_build b01 + parent g00 + transactions txTstorageDynamicReentrancyContextContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txTestReentrantContextRevert transaction +transaction_build txTestReentrantContextRevert + sender acc1 + nonce 1 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 0b35f95c0000000000000000000000000000000000000000000000000000000000000000 + gas 300000 + build + +# Create block to hold txTestReentrantContextRevert transaction +block_build b02 + parent b01 + transactions txTestReentrantContextRevert + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txTestReentrantContextInvalid transaction +transaction_build txTestReentrantContextInvalid transaction + sender acc1 + nonce 2 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 0b35f95c0000000000000000000000000000000000000000000000000000000000000001 + gas 1000000 + build + +# Create block to hold txTestReentrantContextInvalid transaction +block_build b03 + parent b02 + transactions txTestReentrantContextInvalid + gasLimit 1200000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt new file mode 100644 index 00000000000..68e2c9996bf --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt @@ -0,0 +1,144 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstorageDynamicReentrancyContext { + bool reentrant = false; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function tstoreBeforeOpcodeHasNoEffect(uint256 opcodeSelector) external { + bytes memory data = abi.encodeWithSignature("tstoreBeforeOpcodeHasNoEffect(uint256)", opcodeSelector); + uint256 fail; + uint256 valueLoadedFromFFBefore; + uint256 valueLoadedFromFFAfter; + + assembly { + let reentrantValue := sload(reentrant.slot) + switch reentrantValue + case 0 { + sstore(reentrant.slot, true) + + tstore(0xFF, 0x100) + valueLoadedFromFFBefore := tload(0xFF) + + mstore(0, 2) + switch opcodeSelector + case 0 { + fail := call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0) + } + case 1 { + fail := call(0xFFFF, address(), 0, add(data, 0x20), mload(data), 0, 0) + } + valueLoadedFromFFAfter := tload(0xFF) + + } + default { + tstore(0xFF, 0x101) + switch opcodeSelector + case 0 { + revert(0, 0) + } + case 1 { + invalid() + } + } + } + checkReturnValueExpected(fail, 'Checking result callee execution fails', 0); + checkReturnValueExpected(valueLoadedFromFFBefore, 'Checking value from tload FF before', 0x100); + checkReturnValueExpected(valueLoadedFromFFAfter, 'Checking value from tload FF after', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageDynamicReentrancyContext: 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b50610431806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063902b3cc81461002d575b5f80fd5b61004760048036038101906100429190610285565b610049565b005b5f8160405160240161005b91906102bf565b6040516020818303038152906040527f902b3cc8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f805f8054805f811461010e5761010160ff5d865f8114610102576001811461010657610108565b5f80fd5bfe5b50610161565b60015f5561010060ff5d60ff5c935060025f52865f811461013657600181146101495761015a565b5f80885160208a015f305af1955061015a565b5f80885160208a015f3061fffff195505b5060ff5c92505b5050610186836040518060600160405280602681526020016103b3602691395f6101d7565b6101ab826040518060600160405280602381526020016103d9602391396101006101d7565b6101d081604051806060016040528060228152602001610391602291396101006101d7565b5050505050565b80830361020f577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610249565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610240929190610362565b60405180910390a15b505050565b5f80fd5b5f819050919050565b61026481610252565b811461026e575f80fd5b50565b5f8135905061027f8161025b565b92915050565b5f6020828403121561029a5761029961024e565b5b5f6102a784828501610271565b91505092915050565b6102b981610252565b82525050565b5f6020820190506102d25f8301846102b0565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561030f5780820151818401526020810190506102f4565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610334826102d8565b61033e81856102e2565b935061034e8185602086016102f2565b6103578161031a565b840191505092915050565b5f6040820190508181035f83015261037a818561032a565b905061038960208301846102b0565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164204646206166746572436865636b696e6720726573756c742063616c6c656520657865637574696f6e206661696c73436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f7265a26469706673582212209e3cc9ab852f09a8d8d7e1daa468813b380a77f02875c4641d7e0e9942b30c1464736f6c63430008180033 + +902b3cc8: tstoreBeforeOpcodeHasNoEffect(uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageDynamicReentrancyContext contract +transaction_build txTstorageDynamicReentrancyContextContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b50610431806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063902b3cc81461002d575b5f80fd5b61004760048036038101906100429190610285565b610049565b005b5f8160405160240161005b91906102bf565b6040516020818303038152906040527f902b3cc8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f805f8054805f811461010e5761010160ff5d865f8114610102576001811461010657610108565b5f80fd5bfe5b50610161565b60015f5561010060ff5d60ff5c935060025f52865f811461013657600181146101495761015a565b5f80885160208a015f305af1955061015a565b5f80885160208a015f3061fffff195505b5060ff5c92505b5050610186836040518060600160405280602681526020016103b3602691395f6101d7565b6101ab826040518060600160405280602381526020016103d9602391396101006101d7565b6101d081604051806060016040528060228152602001610391602291396101006101d7565b5050505050565b80830361020f577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610249565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610240929190610362565b60405180910390a15b505050565b5f80fd5b5f819050919050565b61026481610252565b811461026e575f80fd5b50565b5f8135905061027f8161025b565b92915050565b5f6020828403121561029a5761029961024e565b5b5f6102a784828501610271565b91505092915050565b6102b981610252565b82525050565b5f6020820190506102d25f8301846102b0565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561030f5780820151818401526020810190506102f4565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610334826102d8565b61033e81856102e2565b935061034e8185602086016102f2565b6103578161031a565b840191505092915050565b5f6040820190508181035f83015261037a818561032a565b905061038960208301846102b0565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164204646206166746572436865636b696e6720726573756c742063616c6c656520657865637574696f6e206661696c73436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f7265a26469706673582212209e3cc9ab852f09a8d8d7e1daa468813b380a77f02875c4641d7e0e9942b30c1464736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageDynamicReentrancyContextContract transaction +block_build b01 + parent g00 + transactions txTstorageDynamicReentrancyContextContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txTestReentrantContextRevert transaction +transaction_build txTestReentrantContextRevert + sender acc1 + nonce 1 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 902b3cc80000000000000000000000000000000000000000000000000000000000000000 + gas 300000 + build + +# Create block to hold txTestReentrantContextRevert transaction +block_build b02 + parent b01 + transactions txTestReentrantContextRevert + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txTestReentrantContextInvalid transaction +transaction_build txTestReentrantContextInvalid transaction + sender acc1 + nonce 2 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 902b3cc80000000000000000000000000000000000000000000000000000000000000001 + gas 1000000 + build + +# Create block to hold txTestReentrantContextInvalid transaction +block_build b03 + parent b02 + transactions txTestReentrantContextInvalid + gasLimit 1200000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt new file mode 100644 index 00000000000..8cc99938734 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt @@ -0,0 +1,136 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstorageReentrancyContextTest { + bool reentrant = false; + uint256 success; + uint256 valueLoadedAfterSubcall; + uint256 valueLoadedBeforeSubcall; + uint256 valueLoadedInSubcall; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function manipulateInReentrantCall() external { + bytes memory data = abi.encodeWithSignature("manipulateInReentrantCall()"); + + assembly { + let reentrantValue := sload(reentrant.slot) + switch reentrantValue + case 0 { + sstore(reentrant.slot, true) + + tstore(0xFF, 0x100) + sstore(valueLoadedBeforeSubcall.slot, tload(0xFF)) + mstore(0, 2) + sstore(success.slot, call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0)) + sstore(valueLoadedAfterSubcall.slot, tload(0xFF)) + } + default { + tstore(0xFF, 0x101) + sstore(valueLoadedInSubcall.slot, tload(0xFF)) + } + } + } + + function checkValuesStoredInTstorage() external { + checkReturnValueExpected(valueLoadedBeforeSubcall, 'Checking value from tload before subcall', 0x100); + checkReturnValueExpected(success, 'Checking result callee execution is with success', 1); + checkReturnValueExpected(valueLoadedInSubcall, 'Checking value from tload inside subcall', 0x101); + checkReturnValueExpected(valueLoadedAfterSubcall, 'Checking value from tload after subcall ', 0x101); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageReentrancyContextTest: 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b506103de806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80631ff644ef146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a61011c565b005b5f6040516024016040516020818303038152906040527f1ff644ef000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f54805f81146100ed5761010160ff5d60ff5c600455610117565b60015f5561010060ff5d60ff5c60035560025f525f808451602086015f305af160015560ff5c6002555b505050565b610143600354604051806060016040528060288152602001610301602891396101006101b9565b6101696001546040518060600160405280603081526020016103296030913960016101b9565b610190600454604051806060016040528060288152602001610381602891396101016101b9565b6101b7600254604051806060016040528060288152602001610359602891396101016101b9565b565b8083036101f1577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161022b565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516102229291906102d2565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561026757808201518184015260208101905061024c565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61028c82610230565b610296818561023a565b93506102a681856020860161024a565b6102af81610272565b840191505092915050565b5f819050919050565b6102cc816102ba565b82525050565b5f6040820190508181035f8301526102ea8185610282565b90506102f960208301846102c3565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164206265666f72652073756263616c6c436865636b696e6720726573756c742063616c6c656520657865637574696f6e20697320776974682073756363657373436865636b696e672076616c75652066726f6d20746c6f61642061667465722073756263616c6c20436865636b696e672076616c75652066726f6d20746c6f616420696e736964652073756263616c6ca26469706673582212205eaa2b45243abfc23eb1044a5fe2ff7c133a9d27dc7ee1836eed96d02a8919ea64736f6c63430008180033 + +5f6813d1: checkValuesStoredInTstorage() +1ff644ef: manipulateInReentrantCall() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageReentrancyContextTest contract +transaction_build txTstorageReentrancyContextTestContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b506103de806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80631ff644ef146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a61011c565b005b5f6040516024016040516020818303038152906040527f1ff644ef000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f54805f81146100ed5761010160ff5d60ff5c600455610117565b60015f5561010060ff5d60ff5c60035560025f525f808451602086015f305af160015560ff5c6002555b505050565b610143600354604051806060016040528060288152602001610301602891396101006101b9565b6101696001546040518060600160405280603081526020016103296030913960016101b9565b610190600454604051806060016040528060288152602001610381602891396101016101b9565b6101b7600254604051806060016040528060288152602001610359602891396101016101b9565b565b8083036101f1577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161022b565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516102229291906102d2565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561026757808201518184015260208101905061024c565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61028c82610230565b610296818561023a565b93506102a681856020860161024a565b6102af81610272565b840191505092915050565b5f819050919050565b6102cc816102ba565b82525050565b5f6040820190508181035f8301526102ea8185610282565b90506102f960208301846102c3565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164206265666f72652073756263616c6c436865636b696e6720726573756c742063616c6c656520657865637574696f6e20697320776974682073756363657373436865636b696e672076616c75652066726f6d20746c6f61642061667465722073756263616c6c20436865636b696e672076616c75652066726f6d20746c6f616420696e736964652073756263616c6ca26469706673582212205eaa2b45243abfc23eb1044a5fe2ff7c133a9d27dc7ee1836eed96d02a8919ea64736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageReentrancyContextTestContract transaction +block_build b01 + parent g00 + transactions txTstorageReentrancyContextTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txManipulateInReentrantCall transaction +transaction_build txManipulateInReentrantCall + sender acc1 + nonce 1 + contract txTstorageReentrancyContextTestContract + value 0 + data 1ff644ef + gas 300000 + build + +# Create block to hold txManipulateInReentrantCall transaction +block_build b02 + parent b01 + transactions txManipulateInReentrantCall + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txCheckValuesStoredInTstorage transaction +transaction_build txCheckValuesStoredInTstorage transaction + sender acc1 + nonce 2 + contract txTstorageReentrancyContextTestContract + value 0 + data 5f6813d1 + gas 300000 + build + +# Create block to hold txCheckValuesStoredInTstorage transaction +block_build b03 + parent b02 + transactions txCheckValuesStoredInTstorage + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt new file mode 100644 index 00000000000..e807c54741f --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt @@ -0,0 +1,133 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstorageReentrancyContextTest { + bool reentrant = false; + uint256 success; + uint256 valueLoadedAfterSubcall; + uint256 valueLoadedBeforeSubcall; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function tLoadAfterReentrantTstore() external { + bytes memory data = abi.encodeWithSignature("tLoadAfterReentrantTstore()"); + + assembly { + let reentrantValue := sload(reentrant.slot) + switch reentrantValue + case 0 { + sstore(reentrant.slot, true) + + tstore(0xFF, 0x100) + sstore(valueLoadedBeforeSubcall.slot, tload(0xFF)) + mstore(0, 2) + sstore(success.slot, call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0)) + sstore(valueLoadedAfterSubcall.slot, tload(0xFF)) + } + default { + tstore(0xFF, 0x101) + } + } + } + + function checkValuesStoredInTstorageCase() external { + checkReturnValueExpected(valueLoadedBeforeSubcall, 'Checking value from tload before subcall', 0x100); + checkReturnValueExpected(success, 'Checking result callee execution is with success', 1); + checkReturnValueExpected(valueLoadedAfterSubcall, 'Checking value from tload after subcall ', 0x101); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageReentrancyContextTest: 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b50610389806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80635ecc5be5146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a610116565b005b5f6040516024016040516020818303038152906040527f5ecc5be5000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f54805f81146100e75761010160ff5d610111565b60015f5561010060ff5d60ff5c60035560025f525f808451602086015f305af160015560ff5c6002555b505050565b61013d6003546040518060600160405280602881526020016102d46028913961010061018c565b6101636001546040518060600160405280603081526020016102fc60309139600161018c565b61018a60025460405180606001604052806028815260200161032c6028913961010161018c565b565b8083036101c4577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101fe565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101f59291906102a5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561023a57808201518184015260208101905061021f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61025f82610203565b610269818561020d565b935061027981856020860161021d565b61028281610245565b840191505092915050565b5f819050919050565b61029f8161028d565b82525050565b5f6040820190508181035f8301526102bd8185610255565b90506102cc6020830184610296565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164206265666f72652073756263616c6c436865636b696e6720726573756c742063616c6c656520657865637574696f6e20697320776974682073756363657373436865636b696e672076616c75652066726f6d20746c6f61642061667465722073756263616c6c20a264697066735822122051c2d1c8d7ba9ee8ee19a56961f0bb6c1a00450d360d92729994011b727dafac64736f6c63430008180033 + +5f6813d1: checkValuesStoredInTstorage() +5ecc5be5: tLoadAfterReentrantTstore() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageReentrancyContextTest contract +transaction_build txTstorageReentrancyContextTestContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b50610389806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80635ecc5be5146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a610116565b005b5f6040516024016040516020818303038152906040527f5ecc5be5000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f54805f81146100e75761010160ff5d610111565b60015f5561010060ff5d60ff5c60035560025f525f808451602086015f305af160015560ff5c6002555b505050565b61013d6003546040518060600160405280602881526020016102d46028913961010061018c565b6101636001546040518060600160405280603081526020016102fc60309139600161018c565b61018a60025460405180606001604052806028815260200161032c6028913961010161018c565b565b8083036101c4577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101fe565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101f59291906102a5565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561023a57808201518184015260208101905061021f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61025f82610203565b610269818561020d565b935061027981856020860161021d565b61028281610245565b840191505092915050565b5f819050919050565b61029f8161028d565b82525050565b5f6040820190508181035f8301526102bd8185610255565b90506102cc6020830184610296565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164206265666f72652073756263616c6c436865636b696e6720726573756c742063616c6c656520657865637574696f6e20697320776974682073756363657373436865636b696e672076616c75652066726f6d20746c6f61642061667465722073756263616c6c20a264697066735822122051c2d1c8d7ba9ee8ee19a56961f0bb6c1a00450d360d92729994011b727dafac64736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageReentrancyContextTestContract transaction +block_build b01 + parent g00 + transactions txTstorageReentrancyContextTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txTloadAfterReentrantTstorel transaction +transaction_build txTloadAfterReentrantTstore + sender acc1 + nonce 1 + contract txTstorageReentrancyContextTestContract + value 0 + data 5ecc5be5 + gas 300000 + build + +# Create block to hold txTloadAfterReentrantTstore transaction +block_build b02 + parent b01 + transactions txTloadAfterReentrantTstore + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txCheckValuesStoredInTstorage transaction +transaction_build txCheckValuesStoredInTstorage transaction + sender acc1 + nonce 2 + contract txTstorageReentrancyContextTestContract + value 0 + data 5f6813d1 + gas 300000 + build + +# Create block to hold txCheckValuesStoredInTstorage transaction +block_build b03 + parent b02 + transactions txCheckValuesStoredInTstorage + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt new file mode 100644 index 00000000000..9206a0fc715 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt @@ -0,0 +1,131 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstorageReentrancyContextTest { + bool reentrant = false; + uint256 success; + uint256 valueLoadedAfterSubcall; + uint256 valueLoadedInsideSubcall; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function tstoreInReentrantCall() external { + bytes memory data = abi.encodeWithSignature("tstoreInReentrantCall()"); + + assembly { + let reentrantValue := sload(reentrant.slot) + switch reentrantValue + case 0 { + sstore(reentrant.slot, true) + + tstore(0, 0x100) + mstore(0, 2) + sstore(success.slot, call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0)) + sstore(valueLoadedAfterSubcall.slot, tload(0)) + } + default { + sstore(valueLoadedInsideSubcall.slot, tload(0)) + } + } + } + + function checkValuesStoredInTstorage() external { + checkReturnValueExpected(valueLoadedInsideSubcall, 'Checking value from tload inside subcall', 0x100); + checkReturnValueExpected(success, 'Checking result callee execution is with success', 1); + checkReturnValueExpected(valueLoadedAfterSubcall, 'Checking value from tload after subcall ', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageReentrancyContextTest: 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b50610380806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806321b76bb4146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a61010d565b005b5f6040516024016040516020818303038152906040527f21b76bb4000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f54805f81146100e6575f5c600355610108565b60015f556101005f5d60025f525f808451602086015f305af16001555f5c6002555b505050565b61013460035460405180606001604052806028815260200161032360289139610100610183565b61015a6001546040518060600160405280603081526020016102cb603091396001610183565b6101816002546040518060600160405280602881526020016102fb60289139610100610183565b565b8083036101bb577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101f5565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101ec92919061029c565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610231578082015181840152602081019050610216565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610256826101fa565b6102608185610204565b9350610270818560208601610214565b6102798161023c565b840191505092915050565b5f819050919050565b61029681610284565b82525050565b5f6040820190508181035f8301526102b4818561024c565b90506102c3602083018461028d565b939250505056fe436865636b696e6720726573756c742063616c6c656520657865637574696f6e20697320776974682073756363657373436865636b696e672076616c75652066726f6d20746c6f61642061667465722073756263616c6c20436865636b696e672076616c75652066726f6d20746c6f616420696e736964652073756263616c6ca2646970667358221220aa4b50d0af36690596f713b131408b71aefedd3207a7ddee4c16a2924f23811464736f6c63430008180033 + +5f6813d1: checkValuesStoredInTstorage() +21b76bb4: tstoreInReentrantCall() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageReentrancyContextTest contract +transaction_build txTstorageReentrancyContextTestContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f805f6101000a81548160ff021916908315150217905550348015610027575f80fd5b50610380806100355f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806321b76bb4146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a61010d565b005b5f6040516024016040516020818303038152906040527f21b76bb4000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f54805f81146100e6575f5c600355610108565b60015f556101005f5d60025f525f808451602086015f305af16001555f5c6002555b505050565b61013460035460405180606001604052806028815260200161032360289139610100610183565b61015a6001546040518060600160405280603081526020016102cb603091396001610183565b6101816002546040518060600160405280602881526020016102fb60289139610100610183565b565b8083036101bb577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101f5565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101ec92919061029c565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610231578082015181840152602081019050610216565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610256826101fa565b6102608185610204565b9350610270818560208601610214565b6102798161023c565b840191505092915050565b5f819050919050565b61029681610284565b82525050565b5f6040820190508181035f8301526102b4818561024c565b90506102c3602083018461028d565b939250505056fe436865636b696e6720726573756c742063616c6c656520657865637574696f6e20697320776974682073756363657373436865636b696e672076616c75652066726f6d20746c6f61642061667465722073756263616c6c20436865636b696e672076616c75652066726f6d20746c6f616420696e736964652073756263616c6ca2646970667358221220aa4b50d0af36690596f713b131408b71aefedd3207a7ddee4c16a2924f23811464736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageReentrancyContextTestContract transaction +block_build b01 + parent g00 + transactions txTstorageReentrancyContextTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txTstoreInReentrantCall transaction +transaction_build txTstoreInReentrantCall + sender acc1 + nonce 1 + contract txTstorageReentrancyContextTestContract + value 0 + data 21b76bb4 + gas 300000 + build + +# Create block to hold txTstoreInReentrantCall transaction +block_build b02 + parent b01 + transactions txTstoreInReentrantCall + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txCheckValuesStoredInTstorage transaction +transaction_build txCheckValuesStoredInTstorage transaction + sender acc1 + nonce 2 + contract txTstorageReentrancyContextTestContract + value 0 + data 5f6813d1 + gas 300000 + build + +# Create block to hold txCheckValuesStoredInTstorage transaction +block_build b03 + parent b02 + transactions txCheckValuesStoredInTstorage + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file From 13afb227f40f98a691558495ac66d870d6a4846a Mon Sep 17 00:00:00 2001 From: frederico leal Date: Mon, 25 Nov 2024 21:14:01 +0100 Subject: [PATCH 15/22] Added another scenarios of test with multiple reentrant calls - All the tests from the EIP for reentrancy contexts are covered now --- .../vm/opcode/TransientStorageDslTest.java | 43 ++++ ...undoes_tstorage_after_successfull_call.txt | 200 ++++++++++++++++++ ..._call_then_tload_return_in_static_call.txt | 149 +++++++++++++ 3 files changed, 392 insertions(+) create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index 587fef5d36a..71a762f555e 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -377,6 +377,31 @@ void testDynamicReentrancyContextsRevertOrInvalidUndoesAll() throws FileNotFound assertTransactionReceiptWithStatus(world, txTestReentrantContextInvalid, "b03", false); } + @Test + void testDynamicReentrancyContextsRevertOrInvalidUndoesTstorageAfterSuccessfullCall() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageDynamicReentrancyContextContract = "txTstorageDynamicReentrancyContextContract"; + assertTransactionReceiptWithStatus(world, txTstorageDynamicReentrancyContextContract, "b01", true); + + String txTstoreInDoubleReentrantCallWithRevert = "txTstoreInDoubleReentrantCallWithRevert"; + assertTransactionReceiptWithStatus(world, txTstoreInDoubleReentrantCallWithRevert, "b02", true); + + String txCheckValuesStoredInTstorageForRevert = "txCheckValuesStoredInTstorageForRevert"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorageForRevert, "b03", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + + String txTstoreInDoubleReentrantCallWithInvalid = "txTstoreInDoubleReentrantCallWithInvalid"; + assertTransactionReceiptWithStatus(world, txTstoreInDoubleReentrantCallWithInvalid, "b04", false); + + String txCheckValuesStoredInTstorageForInvalid = "txCheckValuesStoredInTstorageForInvalid"; + txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorageForInvalid, "b05", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + @Test void testReentrancyContextsTstoreAfterReentrantCall() throws FileNotFoundException, DslProcessorException { DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt"); @@ -431,6 +456,24 @@ void testReentrancyContextsManipulateInReentrantCall() throws FileNotFoundExcept Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } + @Test + void testReentrancyContextsTstoreInCallThenTloadReturnInStaticCall() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageReentrancyContextTestContract = "txTstorageReentrancyContextTestContract"; + assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); + + String txTstorageInReentrantCallTest = "txTstorageInReentrantCallTest"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTstorageInReentrantCallTest, "b02", true); + + String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; + txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt new file mode 100644 index 00000000000..75f8a46b6f0 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt @@ -0,0 +1,200 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstorageDynamicReentrancyContext { + uint256 reentrantCounter = 0; + uint256 valueLoadedFromFFBefore; + uint256 valueLoadedFromFFAfter; + uint256 resultFirstReentrantCall; + uint256 resultSecondReentrantCall; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function opcodeUndoesTstorageAfterSuccessfullCall(uint256 opcodeSelector) external { + bytes memory data = abi.encodeWithSignature("opcodeUndoesTstorageAfterSuccessfullCall(uint256)", opcodeSelector); + + assembly { + let reentrantValue := sload(reentrantCounter.slot) + switch reentrantValue + case 1 { + // +1 to the counter so it goes to the other case from reentrant call + reentrantValue := add(reentrantValue, 1) + sstore(reentrantCounter.slot, reentrantValue) + // Switch to select if failure will be caused by opcode revert or invalid opcode + switch opcodeSelector + case 0 { + sstore(resultSecondReentrantCall.slot, call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0)) + revert(0, 32) + } + case 1 { + sstore(resultSecondReentrantCall.slot, call(0xFFFF, address(), 0, add(data, 0x20), mload(data), 0, 0)) + invalid() + } + } + case 2 { + tstore(0xFF, 0x101) + } + default { + // +1 to the counter so it goes to the other case from reentrant call + reentrantValue := add(reentrantValue, 1) + sstore(reentrantCounter.slot, reentrantValue) + + // Setup the conditions to be tested + tstore(0xFF, 0x100) + sstore(valueLoadedFromFFBefore.slot, tload(0xFF)) + sstore(resultFirstReentrantCall.slot, call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0)) // saves result from the call so we can check later + sstore(valueLoadedFromFFAfter.slot, tload(0xFF)) + } + } + } + + function checkValuesStoredInTstorage() external { + checkReturnValueExpected(resultFirstReentrantCall, 'Checking result callee execution resultFirstReentrantCall is failed', 0); + checkReturnValueExpected(resultSecondReentrantCall, 'Checking result callee execution resultSecondReentrantCall is failed', 0); + checkReturnValueExpected(valueLoadedFromFFBefore, 'Checking value from tload FF before', 0x100); + checkReturnValueExpected(valueLoadedFromFFAfter, 'Checking value from tload FF after', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageDynamicReentrancyContext: 60806040525f8055348015610012575f80fd5b506104de806100205f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634abdbf22146100385780635f6813d114610054575b5f80fd5b610052600480360381019061004d91906102d1565b61005e565b005b61005c610189565b005b5f81604051602401610070919061030b565b6040516020818303038152906040527f4abdbf22000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f548060018114610131576002811461017c57600182019150815f5561010060ff5d60ff5c6001555f808451602086015f305af160035560ff5c600255610183565b600182019150815f55835f811461014f576001811461016357610176565b5f808551602087015f305af160045560205ffd5b5f808551602087015f3061fffff1600455fe5b50610183565b61010160ff5d5b50505050565b6101ae6003546040518060800160405280604381526020016103ff604391395f610223565b6101d3600454604051806080016040528060448152602001610442604491395f610223565b6101fa60015460405180606001604052806023815260200161048660239139610100610223565b6102216002546040518060600160405280602281526020016103dd60229139610100610223565b565b80830361025b577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610295565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161028c9291906103ae565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6102b08161029e565b81146102ba575f80fd5b50565b5f813590506102cb816102a7565b92915050565b5f602082840312156102e6576102e561029a565b5b5f6102f3848285016102bd565b91505092915050565b6103058161029e565b82525050565b5f60208201905061031e5f8301846102fc565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561035b578082015181840152602081019050610340565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61038082610324565b61038a818561032e565b935061039a81856020860161033e565b6103a381610366565b840191505092915050565b5f6040820190508181035f8301526103c68185610376565b90506103d560208301846102fc565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164204646206166746572436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c7446697273745265656e7472616e7443616c6c206973206661696c6564436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c745365636f6e645265656e7472616e7443616c6c206973206661696c6564436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f7265a2646970667358221220ddbb9e72364b1b79e927453462ad5f3aa80de1475c599317f83708e1ef5ca17b64736f6c63430008180033 + +Function hashes + +4abdbf22: opcodeUndoesTstorageAfterSuccessfullCall(uint256) +5f6813d1: checkValuesStoredInTstorage() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageDynamicReentrancyContext contract +transaction_build txTstorageDynamicReentrancyContextContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f8055348015610012575f80fd5b506104de806100205f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634abdbf22146100385780635f6813d114610054575b5f80fd5b610052600480360381019061004d91906102d1565b61005e565b005b61005c610189565b005b5f81604051602401610070919061030b565b6040516020818303038152906040527f4abdbf22000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f548060018114610131576002811461017c57600182019150815f5561010060ff5d60ff5c6001555f808451602086015f305af160035560ff5c600255610183565b600182019150815f55835f811461014f576001811461016357610176565b5f808551602087015f305af160045560205ffd5b5f808551602087015f3061fffff1600455fe5b50610183565b61010160ff5d5b50505050565b6101ae6003546040518060800160405280604381526020016103ff604391395f610223565b6101d3600454604051806080016040528060448152602001610442604491395f610223565b6101fa60015460405180606001604052806023815260200161048660239139610100610223565b6102216002546040518060600160405280602281526020016103dd60229139610100610223565b565b80830361025b577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610295565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161028c9291906103ae565b60405180910390a15b505050565b5f80fd5b5f819050919050565b6102b08161029e565b81146102ba575f80fd5b50565b5f813590506102cb816102a7565b92915050565b5f602082840312156102e6576102e561029a565b5b5f6102f3848285016102bd565b91505092915050565b6103058161029e565b82525050565b5f60208201905061031e5f8301846102fc565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561035b578082015181840152602081019050610340565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61038082610324565b61038a818561032e565b935061039a81856020860161033e565b6103a381610366565b840191505092915050565b5f6040820190508181035f8301526103c68185610376565b90506103d560208301846102fc565b939250505056fe436865636b696e672076616c75652066726f6d20746c6f6164204646206166746572436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c7446697273745265656e7472616e7443616c6c206973206661696c6564436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c745365636f6e645265656e7472616e7443616c6c206973206661696c6564436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f7265a2646970667358221220ddbb9e72364b1b79e927453462ad5f3aa80de1475c599317f83708e1ef5ca17b64736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageDynamicReentrancyContextContract transaction +block_build b01 + parent g00 + transactions txTstorageDynamicReentrancyContextContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txTstoreInDoubleReentrantCallWithRevert transaction +transaction_build txTstoreInDoubleReentrantCallWithRevert + sender acc1 + nonce 1 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 4abdbf220000000000000000000000000000000000000000000000000000000000000000 + gas 300000 + build + +# Create block to hold txTstoreInDoubleReentrantCallWithRevert transaction +block_build b02 + parent b01 + transactions txTstoreInDoubleReentrantCallWithRevert + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txCheckValuesStoredInTstorageForRevert transaction +transaction_build txCheckValuesStoredInTstorageForRevert transaction + sender acc1 + nonce 2 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 5f6813d1 + gas 300000 + build + +# Create block to hold txCheckValuesStoredInTstorageForRevert transaction +block_build b03 + parent b02 + transactions txCheckValuesStoredInTstorageForRevert + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 + +# Create transaction to execute txTstoreInDoubleReentrantCallWithInvalid transaction +transaction_build txTstoreInDoubleReentrantCallWithInvalid + sender acc1 + nonce 3 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 4abdbf220000000000000000000000000000000000000000000000000000000000000001 + gas 300000 + build + +# Create block to hold txTstoreInDoubleReentrantCallWithInvalid transaction +block_build b04 + parent b03 + transactions txTstoreInDoubleReentrantCallWithInvalid + gasLimit 350000 + build + +# Connect block +block_connect b04 + +# Check b04 is best block +assert_best b04 + +# Create transaction to execute txCheckValuesStoredInTstorageForInvalid transaction +transaction_build txCheckValuesStoredInTstorageForInvalid transaction + sender acc1 + nonce 4 + contract txTstorageDynamicReentrancyContextContract + value 0 + data 5f6813d1 + gas 300000 + build + +# Create block to hold txCheckValuesStoredInTstorageForInvalid transaction +block_build b05 + parent b04 + transactions txCheckValuesStoredInTstorageForInvalid + gasLimit 350000 + build + +# Connect block +block_connect b05 + +# Check b05 is best block +assert_best b05 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt new file mode 100644 index 00000000000..68bbcf8c046 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt @@ -0,0 +1,149 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstorageReentrancyContext { + uint256 reentrantCounter = 0; + uint256 valueLoadedFromFFBeforeDefaultCall; + uint256 valueLoadedFromFEAfterCall; + uint256 valueLoadedFromMloadAfterSecondReentrantCall; + uint256 resultFirstReentrantCall; + uint256 resultSecondReentrantStaticCall; + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function tstoreInCallThenTloadReturnInStaticCall() external { + bytes memory data = abi.encodeWithSignature("tstoreInCallThenTloadReturnInStaticCall()"); + + assembly { + let reentrantValue := sload(reentrantCounter.slot) + switch reentrantValue + case 1 { + // +1 to the counter so it goes to the other case from reentrant call + reentrantValue := add(reentrantValue, 1) + sstore(reentrantCounter.slot, reentrantValue) + tstore(0xFE, 0x101) + sstore(resultSecondReentrantStaticCall.slot, staticcall(gas(), address(), add(data, 0x20), mload(data), 0, 32)) + sstore(valueLoadedFromMloadAfterSecondReentrantCall.slot, mload(0)) + } + case 2 { + let value := tload(0xFE) + mstore(0, value) + return(0, 32) + } + default { + // +1 to the counter so it goes to the other case from reentrant call + reentrantValue := add(reentrantValue, 1) + sstore(reentrantCounter.slot, reentrantValue) + + // Setup the conditions to be tested + tstore(0xFF, 0x100) + sstore(valueLoadedFromFFBeforeDefaultCall.slot, tload(0xFF)) + sstore(resultFirstReentrantCall.slot, call(gas(), address(), 0, add(data, 0x20), mload(data), 0, 0)) // saves result from the call so we can check later + sstore(valueLoadedFromFEAfterCall.slot, tload(0xFE)) + } + } + } + + function checkValuesStoredInTstorage() external { + checkReturnValueExpected(resultFirstReentrantCall, 'Checking result callee execution resultFirstReentrantCall is success', 1); + checkReturnValueExpected(resultSecondReentrantStaticCall, 'Checking result callee execution resultSecondReentrantCall is success', 1); + checkReturnValueExpected(valueLoadedFromFFBeforeDefaultCall, 'Checking value from tload FF before default call', 0x100); + checkReturnValueExpected(valueLoadedFromMloadAfterSecondReentrantCall, 'Checking value from FE after second reentrant call', 0x101); + checkReturnValueExpected(valueLoadedFromFEAfterCall, 'Checking value from tload FE after defaul call', 0x101); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +// CONTRACT BYTECODE + +TstorageReentrancyContext: 60806040525f8055348015610012575f80fd5b506104a5806100205f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063586c69f3146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a61014c565b005b5f6040516024016040516020818303038152906040527f586c69f3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f548060018114610114576002811461013c57600182019150815f5561010060ff5d60ff5c6001555f808451602086015f305af160045560fe5c600255610147565b600182019150815f5561010160fe5d60205f845160208601305afa6005555f51600355610147565b60fe5c805f5260205ff35b505050565b6101726004546040518060800160405280604481526020016103ce60449139600161020f565b61019860055460405180608001604052806045815260200161035760459139600161020f565b6101bf6001546040518060600160405280603081526020016104126030913961010061020f565b6101e660035460405180606001604052806032815260200161039c6032913961010161020f565b61020d6002546040518060600160405280602e8152602001610442602e913961010161020f565b565b808303610247577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610281565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610278929190610328565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156102bd5780820151818401526020810190506102a2565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6102e282610286565b6102ec8185610290565b93506102fc8185602086016102a0565b610305816102c8565b840191505092915050565b5f819050919050565b61032281610310565b82525050565b5f6040820190508181035f83015261034081856102d8565b905061034f6020830184610319565b939250505056fe436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c745365636f6e645265656e7472616e7443616c6c2069732073756363657373436865636b696e672076616c75652066726f6d204645206166746572207365636f6e64207265656e7472616e742063616c6c436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c7446697273745265656e7472616e7443616c6c2069732073756363657373436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f72652064656661756c742063616c6c436865636b696e672076616c75652066726f6d20746c6f61642046452061667465722064656661756c2063616c6ca2646970667358221220fb81ff9160d8fbb79af6b7a0900873b90768b55016a5ae78f0763585a925688064736f6c63430008180033 + +5f6813d1: checkValuesStoredInTstorage() +586c69f3: tstoreInCallThenTloadReturnInStaticCall() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageReentrancyContextTest contract +transaction_build txTstorageReentrancyContextTestContract + sender acc1 + receiverAddress 00 + value 0 + data 60806040525f8055348015610012575f80fd5b506104a5806100205f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063586c69f3146100385780635f6813d114610042575b5f80fd5b61004061004c565b005b61004a61014c565b005b5f6040516024016040516020818303038152906040527f586c69f3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f548060018114610114576002811461013c57600182019150815f5561010060ff5d60ff5c6001555f808451602086015f305af160045560fe5c600255610147565b600182019150815f5561010160fe5d60205f845160208601305afa6005555f51600355610147565b60fe5c805f5260205ff35b505050565b6101726004546040518060800160405280604481526020016103ce60449139600161020f565b61019860055460405180608001604052806045815260200161035760459139600161020f565b6101bf6001546040518060600160405280603081526020016104126030913961010061020f565b6101e660035460405180606001604052806032815260200161039c6032913961010161020f565b61020d6002546040518060600160405280602e8152602001610442602e913961010161020f565b565b808303610247577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610281565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610278929190610328565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156102bd5780820151818401526020810190506102a2565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6102e282610286565b6102ec8185610290565b93506102fc8185602086016102a0565b610305816102c8565b840191505092915050565b5f819050919050565b61032281610310565b82525050565b5f6040820190508181035f83015261034081856102d8565b905061034f6020830184610319565b939250505056fe436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c745365636f6e645265656e7472616e7443616c6c2069732073756363657373436865636b696e672076616c75652066726f6d204645206166746572207365636f6e64207265656e7472616e742063616c6c436865636b696e6720726573756c742063616c6c656520657865637574696f6e20726573756c7446697273745265656e7472616e7443616c6c2069732073756363657373436865636b696e672076616c75652066726f6d20746c6f6164204646206265666f72652064656661756c742063616c6c436865636b696e672076616c75652066726f6d20746c6f61642046452061667465722064656661756c2063616c6ca2646970667358221220fb81ff9160d8fbb79af6b7a0900873b90768b55016a5ae78f0763585a925688064736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstorageReentrancyContextTestContract transaction +block_build b01 + parent g00 + transactions txTstorageReentrancyContextTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txTstorageInReentrantCallTest transaction +transaction_build txTstorageInReentrantCallTest + sender acc1 + nonce 1 + contract txTstorageReentrancyContextTestContract + value 0 + data 586c69f3 + gas 300000 + build + +# Create block to hold txTstorageInReentrantCallTest transaction +block_build b02 + parent b01 + transactions txTstorageInReentrantCallTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 + +# Create transaction to execute txCheckValuesStoredInTstorage transaction +transaction_build txCheckValuesStoredInTstorage transaction + sender acc1 + nonce 2 + contract txTstorageReentrancyContextTestContract + value 0 + data 5f6813d1 + gas 300000 + build + +# Create block to hold txCheckValuesStoredInTstorage transaction +block_build b03 + parent b02 + transactions txCheckValuesStoredInTstorage + gasLimit 350000 + build + +# Connect block +block_connect b03 + +# Check b03 is best block +assert_best b03 \ No newline at end of file From 498cd951bd3ab08563444311de61e9e876d848fe Mon Sep 17 00:00:00 2001 From: frederico leal Date: Tue, 3 Dec 2024 09:02:27 +0100 Subject: [PATCH 16/22] Added gas cost calculation for TLOAD and TSTORE - Added basic scenario of gas measure costs for Transient Storage - Stil needed to add more scenarios of tests for run out of gas --- .../main/java/org/ethereum/vm/GasCost.java | 3 + .../src/main/java/org/ethereum/vm/VM.java | 14 +- .../vm/opcode/TransientStorageDslTest.java | 15 ++ .../tstorage_gas_measure_tests.txt | 130 ++++++++++++++++++ 4 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt diff --git a/rskj-core/src/main/java/org/ethereum/vm/GasCost.java b/rskj-core/src/main/java/org/ethereum/vm/GasCost.java index c9da2ebc095..c9c786841ff 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/GasCost.java +++ b/rskj-core/src/main/java/org/ethereum/vm/GasCost.java @@ -61,6 +61,9 @@ public class GasCost { public static final long REFUND_SSTORE = 15000; public static final long CREATE = 32000; + public static final long TLOAD = 100; + public static final long TSTORE = 100; + public static final long JUMPDEST = 1; public static final long CREATE_DATA_BYTE = 5; public static final long CALL = 700; 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 0c4d3f999de..6802028fab5 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1340,8 +1340,11 @@ else if (oldValue != null && newValue.isZero()) { } protected void doTLOAD(){ - //TODO: Gas cost calculation will be done here and also shared contexts verifications for - // different types of calls + if (computeGas) { + gasCost = GasCost.TLOAD; + spendOpCodeGas(); + } + DataWord key = program.stackPop(); if (isLogEnabled) { logger.info("Executing TLOAD with parameters: key = {}", key); @@ -1359,8 +1362,11 @@ protected void doTLOAD(){ } protected void doTSTORE(){ - //TODO: Gas cost calculation will be done here and also shared contexts verifications for - // different types of calls + if (computeGas) { + gasCost = GasCost.TSTORE; + spendOpCodeGas(); + } + if (program.isStaticCall()) { throw Program.ExceptionHelper.modificationException(program); } diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index 71a762f555e..f4a059ef637 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -474,6 +474,21 @@ void testReentrancyContextsTstoreInCallThenTloadReturnInStaticCall() throws File Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } + @Test + void testTransientStorageGasMeasureTests() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstorageGasMeasureTestContract = "txTstorageGasMeasureTestContract"; + assertTransactionReceiptWithStatus(world, txTstorageGasMeasureTestContract, "b01", true); + + String txCheckGasMeasures = "txCheckGasMeasures"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckGasMeasures, "b02", true); + Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt new file mode 100644 index 00000000000..93afe260621 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt @@ -0,0 +1,130 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstorageGasMeasureTestCases { + uint public gasUsed; + + constructor() + { + + } + + event OK(); + event ERROR(string, uint256); + + function checkGasMeasures() external { + // Checking tload gas cost + uint gasBefore; + uint gasAfter; + assembly { + gasBefore := gas() + let value := tload(0x10) + gasAfter := gas() + } + gasUsed = gasBefore - gasAfter; + checkReturnValueExpected(gasUsed, 'Checking tload gas spent is the expected', 110); + + // Checking tstore and tload gas cost + assembly { + gasBefore := gas() + tstore(0x10, 0x10) + let value := tload(0x10) + gasAfter := gas() + } + gasUsed = gasBefore - gasAfter; + checkReturnValueExpected(gasUsed, 'Checking tstore and tload gas spent is the expected', 216); + + // Checking tstore in a cold slot + assembly { + gasBefore := gas() + tstore(0xFF, 0x10) + gasAfter := gas() + } + gasUsed = gasBefore - gasAfter; + checkReturnValueExpected(gasUsed, 'Checking tstore cold gas spent is the expected', 113); + + // Checking tstore warm + assembly { + gasBefore := gas() + tstore(0xFF, 0x10) + tstore(0xFF, 0x11) + gasAfter := gas() + } + gasUsed = gasBefore - gasAfter; + checkReturnValueExpected(gasUsed, 'Checking tstore warm gas spent is the expected', 219); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} +// DESCRIPTION + +TstorageGasMeasureTestCases has the following functions: + + + +// CONTRACT BYTECODE + +TstorageGasMeasureTestCases: 6080604052348015600e575f5ffd5b506104098061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806307e5ab1e14610038578063592cdadd14610042575b5f5ffd5b610040610060565b005b61004a610171565b6040516100579190610205565b60405180910390f35b5f5f5a915060105c5a9150508082610078919061024b565b5f819055506100a25f5460405180606001604052806028815260200161037e60289139606e610176565b5a91506010805d60105c5a91505080826100bc919061024b565b5f819055506100e65f5460405180606001604052806033815260200161034b6033913960d8610176565b5a9150601060ff5d5a905080826100fd919061024b565b5f819055506101275f546040518060600160405280602e81526020016103a6602e91396071610176565b5a9150601060ff5d601160ff5d5a90508082610143919061024b565b5f8190555061016d5f546040518060600160405280602e815260200161031d602e913960db610176565b5050565b5f5481565b8083036101ae577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101e8565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101df9291906102ee565b60405180910390a15b505050565b5f819050919050565b6101ff816101ed565b82525050565b5f6020820190506102185f8301846101f6565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610255826101ed565b9150610260836101ed565b92508282039050818111156102785761027761021e565b5b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102c08261027e565b6102ca8185610288565b93506102da818560208601610298565b6102e3816102a6565b840191505092915050565b5f6040820190508181035f83015261030681856102b6565b905061031560208301846101f6565b939250505056fe436865636b696e67207473746f7265207761726d20676173207370656e7420697320746865206578706563746564436865636b696e67207473746f726520616e6420746c6f616420676173207370656e7420697320746865206578706563746564436865636b696e6720746c6f616420676173207370656e7420697320746865206578706563746564436865636b696e67207473746f726520636f6c6420676173207370656e7420697320746865206578706563746564a2646970667358221220b17e2b2108ab28708c0fb481438a67aaae5b4c10a6e07af3125fe9d609eb498c64736f6c634300081c0033 + +function hashes: + +- 07e5ab1e: checkGasMeasures() +- 592cdadd: gasUsed() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstorageGasMeasureTestCases contract +transaction_build txTstorageGasMeasureTestContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b506104098061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806307e5ab1e14610038578063592cdadd14610042575b5f5ffd5b610040610060565b005b61004a610171565b6040516100579190610205565b60405180910390f35b5f5f5a915060105c5a9150508082610078919061024b565b5f819055506100a25f5460405180606001604052806028815260200161037e60289139606e610176565b5a91506010805d60105c5a91505080826100bc919061024b565b5f819055506100e65f5460405180606001604052806033815260200161034b6033913960d8610176565b5a9150601060ff5d5a905080826100fd919061024b565b5f819055506101275f546040518060600160405280602e81526020016103a6602e91396071610176565b5a9150601060ff5d601160ff5d5a90508082610143919061024b565b5f8190555061016d5f546040518060600160405280602e815260200161031d602e913960db610176565b5050565b5f5481565b8083036101ae577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101e8565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101df9291906102ee565b60405180910390a15b505050565b5f819050919050565b6101ff816101ed565b82525050565b5f6020820190506102185f8301846101f6565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610255826101ed565b9150610260836101ed565b92508282039050818111156102785761027761021e565b5b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102c08261027e565b6102ca8185610288565b93506102da818560208601610298565b6102e3816102a6565b840191505092915050565b5f6040820190508181035f83015261030681856102b6565b905061031560208301846101f6565b939250505056fe436865636b696e67207473746f7265207761726d20676173207370656e7420697320746865206578706563746564436865636b696e67207473746f726520616e6420746c6f616420676173207370656e7420697320746865206578706563746564436865636b696e6720746c6f616420676173207370656e7420697320746865206578706563746564436865636b696e67207473746f726520636f6c6420676173207370656e7420697320746865206578706563746564a2646970667358221220b17e2b2108ab28708c0fb481438a67aaae5b4c10a6e07af3125fe9d609eb498c64736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txTstorageGasMeasureTestContract transaction +block_build b01 + parent g00 + transactions txTstorageGasMeasureTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txCheckGasMeasures function +transaction_build txCheckGasMeasures + sender acc1 + nonce 1 + contract txTstorageGasMeasureTestContract + value 0 + data 07e5ab1e + gas 350000 + build + +# Create block to hold txCheckGasMeasures transaction +block_build b02 + parent b01 + transactions txCheckGasMeasures + gasLimit 400000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file From d86e88b04c93952ea0b77522e0031464047d02e5 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Wed, 4 Dec 2024 01:22:09 +0100 Subject: [PATCH 17/22] Added gas cost calculation for TLOAD and TSTORE - Added basic scenario of gas measure costs for Transient Storage - Added scenarios of run out of gas exception loops - Still missing some tests with gas consumption for some execution contexts --- .../src/main/java/org/ethereum/vm/VM.java | 14 ++-- .../vm/opcode/TransientStorageDslTest.java | 66 +++++++++++++-- .../tstorage_gas_measure_tests.txt | 4 - ...tstore_and_tload_loop_until_out_of_gas.txt | 84 +++++++++++++++++++ .../tstore_loop_until_out_of_gas.txt | 79 +++++++++++++++++ ...de_address_space_loop_until_out_of_gas.txt | 83 ++++++++++++++++++ 6 files changed, 310 insertions(+), 20 deletions(-) create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt create mode 100644 rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt 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 6802028fab5..946b0f838ef 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -63,37 +63,37 @@ /** * The Ethereum Virtual Machine (EVM) is responsible for initialization * and executing a transaction on a contract. - * + * It is a quasi-Turing-complete machine; the quasi qualification * comes from the fact that the computation is intrinsically bounded * through a parameter, gas, which limits the total amount of computation done. - * + * The EVM is a simple stack-based architecture. The word size of the machine * (and thus size of stack item) is 256-bit. This was chosen to facilitate * the SHA3-256 hash scheme and elliptic-curve computations. The memory model * is a simple word-addressed byte array. The stack has an unlimited size. * The machine also has an independent storage model; this is similar in concept * to the memory but rather than a byte array, it is a word-addressable word array. - * + * Unlike memory, which is volatile, storage is non volatile and is * maintained as part of the system state. All locations in both storage * and memory are well-defined initially as zero. - * + * The machine does not follow the standard von Neumann architecture. * Rather than storing program code in generally-accessible memory or storage, * it is stored separately in a virtual ROM interactable only though * a specialised instruction. - * + * The machine can have exceptional execution for several reasons, * including stack underflows and invalid instructions. These unambiguously * and validly result in immediate halting of the machine with all state changes * left intact. The one piece of exceptional execution that does not leave * state changes intact is the out-of-gas (OOG) exception. - * + * Here, the machine halts immediately and reports the issue to * the execution agent (either the transaction processor or, recursively, * the spawning execution environment) and which will deal with it separately. - * + * @author Roman Mandeleil * @since 01.06.2014 */ diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index f4a059ef637..b47b3eb9a52 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -33,11 +33,11 @@ import org.junit.jupiter.api.Test; import java.io.FileNotFoundException; +import java.math.BigInteger; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; class TransientStorageDslTest { @@ -413,10 +413,10 @@ void testReentrancyContextsTstoreAfterReentrantCall() throws FileNotFoundExcepti assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); String txTstoreInReentrantCall = "txTstoreInReentrantCall"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTstoreInReentrantCall, "b02", true); + assertTransactionReceiptWithStatus(world, txTstoreInReentrantCall, "b02", true); String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; - txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -431,10 +431,10 @@ void testReentrancyContextsTloadAfterReentrantTstore() throws FileNotFoundExcept assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); String txTloadAfterReentrantTstore = "txTloadAfterReentrantTstore"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTloadAfterReentrantTstore, "b02", true); + assertTransactionReceiptWithStatus(world, txTloadAfterReentrantTstore, "b02", true); String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; - txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -449,10 +449,10 @@ void testReentrancyContextsManipulateInReentrantCall() throws FileNotFoundExcept assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); String txManipulateInReentrantCall = "txManipulateInReentrantCall"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txManipulateInReentrantCall, "b02", true); + assertTransactionReceiptWithStatus(world, txManipulateInReentrantCall, "b02", true); String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; - txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -467,10 +467,10 @@ void testReentrancyContextsTstoreInCallThenTloadReturnInStaticCall() throws File assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); String txTstorageInReentrantCallTest = "txTstorageInReentrantCallTest"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTstorageInReentrantCallTest, "b02", true); + assertTransactionReceiptWithStatus(world, txTstorageInReentrantCallTest, "b02", true); String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; - txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -489,6 +489,54 @@ void testTransientStorageGasMeasureTests() throws FileNotFoundException, DslProc Assertions.assertEquals(4, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } + @Test + void testTstoreLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstoreLoopUntilOutOfGasContract = "txTstoreLoopUntilOutOfGasContract"; + assertTransactionReceiptWithStatus(world, txTstoreLoopUntilOutOfGasContract, "b01", true); + + String txRunTstoreUntilOutOfGas = "txRunTstoreUntilOutOfGas"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txRunTstoreUntilOutOfGas, "b02", false); + long txRunOutOfGas = new BigInteger(1, txReceipt.getGasUsed()).longValue(); + assertEquals(300000, txRunOutOfGas); // Assert that it consumed all the gas configured in the transaction + } + + @Test + void testTstoreWideAddressSpaceLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstoreWideAddressSpaceLoopUntilOutOfGasContract = "txTstoreWideAddressSpaceLoopUntilOutOfGasContract"; + assertTransactionReceiptWithStatus(world, txTstoreWideAddressSpaceLoopUntilOutOfGasContract, "b01", true); + + String txRunTstoreWideAddressSpaceUntilOutOfGas = "txRunTstoreWideAddressSpaceUntilOutOfGas"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txRunTstoreWideAddressSpaceUntilOutOfGas, "b02", false); + long txRunOutOfGas = new BigInteger(1, txReceipt.getGasUsed()).longValue(); + assertEquals(500000, txRunOutOfGas); // Assert that it consumed all the gas configured in the transaction + } + + @Test + void testTstoreAndTloadLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTstoreAndTloadLoopUntilOutOfGasContract = "txTstoreAndTloadLoopUntilOutOfGasContract"; + assertTransactionReceiptWithStatus(world, txTstoreAndTloadLoopUntilOutOfGasContract, "b01", true); + + String txRunTstoreAndTloadUntilOutOfGas = "txRunTstoreAndTloadUntilOutOfGas"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txRunTstoreAndTloadUntilOutOfGas, "b02", false); + long txRunOutOfGas = new BigInteger(1, txReceipt.getGasUsed()).longValue(); + assertEquals(700000, txRunOutOfGas); // Assert that it consumed all the gas configured in the transaction + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt index 93afe260621..c560ad5aef6 100644 --- a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt @@ -66,10 +66,6 @@ contract TstorageGasMeasureTestCases { } // DESCRIPTION -TstorageGasMeasureTestCases has the following functions: - - - // CONTRACT BYTECODE TstorageGasMeasureTestCases: 6080604052348015600e575f5ffd5b506104098061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806307e5ab1e14610038578063592cdadd14610042575b5f5ffd5b610040610060565b005b61004a610171565b6040516100579190610205565b60405180910390f35b5f5f5a915060105c5a9150508082610078919061024b565b5f819055506100a25f5460405180606001604052806028815260200161037e60289139606e610176565b5a91506010805d60105c5a91505080826100bc919061024b565b5f819055506100e65f5460405180606001604052806033815260200161034b6033913960d8610176565b5a9150601060ff5d5a905080826100fd919061024b565b5f819055506101275f546040518060600160405280602e81526020016103a6602e91396071610176565b5a9150601060ff5d601160ff5d5a90508082610143919061024b565b5f8190555061016d5f546040518060600160405280602e815260200161031d602e913960db610176565b5050565b5f5481565b8083036101ae577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101e8565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101df9291906102ee565b60405180910390a15b505050565b5f819050919050565b6101ff816101ed565b82525050565b5f6020820190506102185f8301846101f6565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610255826101ed565b9150610260836101ed565b92508282039050818111156102785761027761021e565b5b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6102c08261027e565b6102ca8185610288565b93506102da818560208601610298565b6102e3816102a6565b840191505092915050565b5f6040820190508181035f83015261030681856102b6565b905061031560208301846101f6565b939250505056fe436865636b696e67207473746f7265207761726d20676173207370656e7420697320746865206578706563746564436865636b696e67207473746f726520616e6420746c6f616420676173207370656e7420697320746865206578706563746564436865636b696e6720746c6f616420676173207370656e7420697320746865206578706563746564436865636b696e67207473746f726520636f6c6420676173207370656e7420697320746865206578706563746564a2646970667358221220b17e2b2108ab28708c0fb481438a67aaae5b4c10a6e07af3125fe9d609eb498c64736f6c634300081c0033 diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt new file mode 100644 index 00000000000..2ab80ad6cea --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt @@ -0,0 +1,84 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstoreAndTloadLoopUntilOutOfGas { + + constructor() + { + + } + + function runTstoreAndTloadUntilOutOfGas() external { + // Run tstore and tload in loop until out of gas + for (uint256 i = 0; i < 1000000; i++) { + assembly { + let gasValue := gas() + tstore(gasValue, gas()) + let loadedValue := tload(gasValue) + pop(0) + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TstoreAndTloadLoopUntilOutOfGas: 6080604052348015600e575f80fd5b5060888061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063ae1978d714602a575b5f80fd5b60306032565b005b5f5b620f4240811015604f575a5a815d5080806001019150506034565b5056fea2646970667358221220db37ed7fb5e1de866d127a5da76e02d895a6014e4de7965e57f66ae94ad5d1d764736f6c63430008180033 + +function hashes: + +- ae1978d7: runTstoreAndTloadUntilOutOfGas() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstoreWideAddressSpaceLoopUntilOutOfGas contract +transaction_build txTstoreAndTloadLoopUntilOutOfGasContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b5060888061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063ae1978d714602a575b5f80fd5b60306032565b005b5f5b620f4240811015604f575a5a815d5080806001019150506034565b5056fea2646970667358221220db37ed7fb5e1de866d127a5da76e02d895a6014e4de7965e57f66ae94ad5d1d764736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstoreAndTloadLoopUntilOutOfGasContract transaction +block_build b01 + parent g00 + transactions txTstoreAndTloadLoopUntilOutOfGasContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txRunTstoreUntilOutOfGas function +transaction_build txRunTstoreAndTloadUntilOutOfGas + sender acc1 + nonce 1 + contract txTstoreAndTloadLoopUntilOutOfGasContract + value 0 + data ae1978d7 + gas 700000 + build + +# Create block to hold txRunTstoreAndTloadUntilOutOfGas transaction +block_build b02 + parent b01 + transactions txRunTstoreAndTloadUntilOutOfGas + gasLimit 750000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt new file mode 100644 index 00000000000..62d3361b6bd --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt @@ -0,0 +1,79 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstoreLoopUntilOutOfGas { + + constructor() + { + } + + function runTstoreUntilOutOfGas() external { + // Run tstore in loop until out of gas + for (uint256 i = 0; i < 1000000; i++) { + assembly { + tstore(gas(), gas()) + } + } + } +} +// DESCRIPTION + +// CONTRACT BYTECODE + +TstoreLoopUntilOutOfGas: 6080604052348015600e575f80fd5b5060868061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80637b17abde14602a575b5f80fd5b60306032565b005b5f5b620f4240811015604d575a5a5d80806001019150506034565b5056fea2646970667358221220460f7f44d313897b5627f933b4969a97d228645b5447a4ea286119f6cc66155964736f6c63430008180033 + +function hashes: + +- 7b17abde: runTstoreUntilOutOfGas() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstoreLoopUntilOutOfGas contract +transaction_build txTstoreLoopUntilOutOfGasContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b5060868061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80637b17abde14602a575b5f80fd5b60306032565b005b5f5b620f4240811015604d575a5a5d80806001019150506034565b5056fea2646970667358221220460f7f44d313897b5627f933b4969a97d228645b5447a4ea286119f6cc66155964736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstoreLoopUntilOutOfGasContract transaction +block_build b01 + parent g00 + transactions txTstoreLoopUntilOutOfGasContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txRunTstoreUntilOutOfGas function +transaction_build txRunTstoreUntilOutOfGas + sender acc1 + nonce 1 + contract txTstoreLoopUntilOutOfGasContract + value 0 + data 7b17abde + gas 300000 + build + +# Create block to hold txRunTstoreUntilOutOfGas transaction +block_build b02 + parent b01 + transactions txRunTstoreUntilOutOfGas + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt new file mode 100644 index 00000000000..68b0e91fba8 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt @@ -0,0 +1,83 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TstoreWideAddressSpaceLoopUntilOutOfGas { + + constructor() + { + } + + function runTstoreWideAddressSpaceUntilOutOfGas() external { + // Run tstore in loop until out of gas, using a wide address space + for (uint256 i = 0; i < 1000000; i++) { + assembly { + let pcValue := codesize() + let shiftedPc := shl(pcValue, 1) + let addResult := add(shiftedPc, gas()) + tstore(addResult, gas()) + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TstoreWideAddressSpaceLoopUntilOutOfGas: 6080604052348015600e575f80fd5b5060918061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806309fdcd3f14602a575b5f80fd5b60306032565b005b5f5b620f4240811015605857386001811b5a81015a815d50505080806001019150506034565b5056fea264697066735822122098cf088d672ad1d70c2d2a0edbbba6202aff9669702ae83d6e9eb1050fc6622864736f6c63430008180033 + +function hashes: + +- 09fdcd3f: runTstoreWideAddressSpaceUntilOutOfGas() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TstoreWideAddressSpaceLoopUntilOutOfGas contract +transaction_build txTstoreWideAddressSpaceLoopUntilOutOfGasContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f80fd5b5060918061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806309fdcd3f14602a575b5f80fd5b60306032565b005b5f5b620f4240811015605857386001811b5a81015a815d50505080806001019150506034565b5056fea264697066735822122098cf088d672ad1d70c2d2a0edbbba6202aff9669702ae83d6e9eb1050fc6622864736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txTstoreWideAddressSpaceLoopUntilOutOfGasContract transaction +block_build b01 + parent g00 + transactions txTstoreWideAddressSpaceLoopUntilOutOfGasContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute txRunTstoreUntilOutOfGas function +transaction_build txRunTstoreWideAddressSpaceUntilOutOfGas + sender acc1 + nonce 1 + contract txTstoreWideAddressSpaceLoopUntilOutOfGasContract + value 0 + data 09fdcd3f + gas 500000 + build + +# Create block to hold txRunTstoreWideAddressSpaceUntilOutOfGas transaction +block_build b02 + parent b01 + transactions txRunTstoreWideAddressSpaceUntilOutOfGas + gasLimit 550000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file From 2c53f3e738aa98a3b6ff731b210fa5210a4b6d06 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 3 Dec 2024 16:23:16 -0300 Subject: [PATCH 18/22] Update bitcoinj-thin version to 0.14.4-rsk-16 --- gradle/verification-metadata.xml | 10 +++++----- rskj-core/build.gradle | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index adc09c6f6ab..6509e80486f 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -54,12 +54,12 @@ - - - + + + - - + + diff --git a/rskj-core/build.gradle b/rskj-core/build.gradle index 39b637eddae..2afc42feed6 100644 --- a/rskj-core/build.gradle +++ b/rskj-core/build.gradle @@ -273,7 +273,7 @@ ext { jaxwsRtVer : '2.3.5', picocliVer : '4.6.3', - bitcoinjThinVer: '0.14.4-rsk-16-SNAPSHOT', + bitcoinjThinVer: '0.14.4-rsk-16', rskjNativeVer: '1.3.0', ] From ec733ddb85d39b09328fcd57cfc7ac0515e56074 Mon Sep 17 00:00:00 2001 From: fmacleal <157636304+fmacleal@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:54:04 +0100 Subject: [PATCH 19/22] Apply suggestions from code review Co-authored-by: Vovchyk --- rskj-core/src/main/java/org/ethereum/db/MutableRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 643d778f937..0138b990d9c 100644 --- a/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java +++ b/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java @@ -440,7 +440,7 @@ public void addTransientStorageBytes(RskAddress addr, DataWord key, byte[] value byte[] triekey = trieKeyMapper.getAccountStorageKey(addr, key); // Special case: if the value is an empty vector, we pass "null" which commands the trie to remove the item. - // Note that if the call comes from addStorageRow(), this method will already have replaced 0 by null, so the + // Note that if the call comes from addTransientStorageRow(), this method will already have replaced 0 by null, so the // 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) { From 750cdca1331081cbae1a0003833c11578ef84bc2 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Mon, 16 Dec 2024 13:47:21 +0100 Subject: [PATCH 20/22] Added test scenarios for selfdestruct cases - As specified in the EIP-1153, it was added test scenarios for reentrancy after selfdestruct. - Besides that, we refactored the folder that contained the DSL tests files --- .../vm/opcode/TransientStorageDslTest.java | 87 +++++++---- ...ctor_and_deploy_code_v0_create_context.txt | 0 ...ctor_and_deploy_code_v1_create_context.txt | 0 ...dynamic_execution_context_call_subcall.txt | 0 .../dynamic_execution_context_simple.txt | 0 ...text_staticcall_subcall_can_call_tload.txt | 0 ...xt_staticcall_subcall_cant_call_tstore.txt | 0 ...dynamic_execution_context_with_invalid.txt | 0 .../dynamic_execution_context_with_revert.txt | 0 ..._execution_context_with_stack_overflow.txt | 0 ...y_context_revert_or_invalid_undoes_all.txt | 0 ...undoes_tstorage_after_successfull_call.txt | 0 ...before_revert_or_invalid_has_no_effect.txt | 0 .../eip1153_basic_tests.txt | 0 ...tructor_and_deploy_code_create_context.txt | 0 .../no_constructor_code_create_context.txt | 0 .../only_constructor_code_create_context.txt | 0 ...y_context_manipulate_in_reentrant_call.txt | 0 ...y_context_tload_after_reentrant_tstore.txt | 0 ...cy_context_tstore_after_reentrant_call.txt | 0 ..._call_then_tload_return_in_static_call.txt | 0 ..._after_inner_selfdestruct_new_contract.txt | 136 ++++++++++++++++ ...ner_selfdestruct_pre_existing_contract.txt | 136 ++++++++++++++++ .../tload_after_selfdestruct_new_contract.txt | 132 ++++++++++++++++ ...ter_selfdestruct_pre_existing_contract.txt | 130 ++++++++++++++++ .../tload_tstore_basic_tests.txt | 0 .../tstorage_gas_measure_tests.txt | 0 ...tstore_after_selfdestruct_new_contract.txt | 146 +++++++++++++++++ ...ter_selfdestruct_pre_existing_contract.txt | 147 ++++++++++++++++++ ...tstore_and_tload_loop_until_out_of_gas.txt | 0 .../tstore_loop_until_out_of_gas.txt | 0 ...de_address_space_loop_until_out_of_gas.txt | 0 32 files changed, 887 insertions(+), 27 deletions(-) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/accross_constructor_and_deploy_code_v0_create_context.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/accross_constructor_and_deploy_code_v1_create_context.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_call_subcall.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_simple.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_staticcall_subcall_can_call_tload.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_with_invalid.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_with_revert.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_execution_context_with_stack_overflow.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/eip1153_basic_tests.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/in_constructor_and_deploy_code_create_context.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/no_constructor_code_create_context.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/only_constructor_code_create_context.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/reentrancy_context_manipulate_in_reentrant_call.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/reentrancy_context_tload_after_reentrant_tstore.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/reentrancy_context_tstore_after_reentrant_call.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt (100%) create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_new_contract.txt create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_pre_existing_contract.txt create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_new_contract.txt create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_pre_existing_contract.txt rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/tload_tstore_basic_tests.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/tstorage_gas_measure_tests.txt (100%) create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_new_contract.txt create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_pre_existing_contract.txt rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/tstore_and_tload_loop_until_out_of_gas.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/tstore_loop_until_out_of_gas.txt (100%) rename rskj-core/src/test/resources/dsl/{transaction_storage_rskip446 => transient_storage_rskip446}/tstore_wide_address_space_loop_until_out_of_gas.txt (100%) diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index b47b3eb9a52..00502ca38d9 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -31,9 +31,13 @@ import org.ethereum.core.util.TransactionReceiptUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.io.FileNotFoundException; import java.math.BigInteger; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -44,7 +48,7 @@ class TransientStorageDslTest { @Test void testTransientStorageOpcodesExecutionsWithRSKIPActivated() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tload_tstore_basic_tests.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -66,7 +70,7 @@ void testTransientStorageOpcodesExecutionsWithRSKIPActivated() throws FileNotFou @Test void testTransientStorageOpcodesShareMemorySameTransaction() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tload_tstore_basic_tests.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -84,7 +88,7 @@ void testTransientStorageOpcodesShareMemorySameTransaction() throws FileNotFound @Test void testTransientStorageOpcodesDoesntShareMemoryFromOtherContract() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tload_tstore_basic_tests.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -106,7 +110,7 @@ void testTransientStorageOpcodesExecutionFailsWithRSKIPDeactivated() throws File rawConfig.withValue("blockchain.config.hardforkActivationHeights.lovell700", ConfigValueFactory.fromAnyRef(-1)) ); - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tload_tstore_basic_tests.txt"); World world = new World(rskip446Disabled); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -123,7 +127,7 @@ void testTransientStorageOpcodesExecutionFailsWithRSKIPDeactivated() throws File @Test void testTransientStorageTestsEip1153BasicScenarios() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/eip1153_basic_tests.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/eip1153_basic_tests.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -150,7 +154,7 @@ void testTransientStorageTestsEip1153BasicScenarios() throws FileNotFoundExcepti @Test void testOnlyConstructorCodeCreateContext() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/only_constructor_code_create_context.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -165,7 +169,7 @@ void testOnlyConstructorCodeCreateContext() throws FileNotFoundException, DslPro @Test void testInConstructorAndCodeCreateContext() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -180,7 +184,7 @@ void testInConstructorAndCodeCreateContext() throws FileNotFoundException, DslPr @Test void testAccrossConstructorAndCodeV0CreateContext() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -195,7 +199,7 @@ void testAccrossConstructorAndCodeV0CreateContext() throws FileNotFoundException @Test void testAccrossConstructorAndCodeV1CreateContext() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -210,7 +214,7 @@ void testAccrossConstructorAndCodeV1CreateContext() throws FileNotFoundException @Test void testNoConstructorCodeCreateContext() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/no_constructor_code_create_context.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -225,7 +229,7 @@ void testNoConstructorCodeCreateContext() throws FileNotFoundException, DslProce @Test void testDynamicExecutionContextSimpleScenario() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -244,7 +248,7 @@ void testDynamicExecutionContextSimpleScenario() throws FileNotFoundException, D @Test void testDynamicExecutionContextWithRevert() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -267,7 +271,7 @@ void testDynamicExecutionContextWithRevert() throws FileNotFoundException, DslPr @Test void testDynamicExecutionContextWithInvalid() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -290,7 +294,7 @@ void testDynamicExecutionContextWithInvalid() throws FileNotFoundException, DslP @Test void testDynamicExecutionContextWithStackOverflow() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -313,7 +317,7 @@ void testDynamicExecutionContextWithStackOverflow() throws FileNotFoundException @Test void testDynamicExecutionCallContextSubcall() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_execution_context_call_subcall.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -328,7 +332,7 @@ void testDynamicExecutionCallContextSubcall() throws FileNotFoundException, DslP @Test void testDynamicExecutionStaticCallSubcallCantUseTstore() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -343,7 +347,7 @@ void testDynamicExecutionStaticCallSubcallCantUseTstore() throws FileNotFoundExc @Test void testDynamicReentrancyContextsTstoreBeforeRevertOrInvalidHasNoEffect() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -361,7 +365,7 @@ void testDynamicReentrancyContextsTstoreBeforeRevertOrInvalidHasNoEffect() throw @Test void testDynamicReentrancyContextsRevertOrInvalidUndoesAll() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -379,7 +383,7 @@ void testDynamicReentrancyContextsRevertOrInvalidUndoesAll() throws FileNotFound @Test void testDynamicReentrancyContextsRevertOrInvalidUndoesTstorageAfterSuccessfullCall() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -404,7 +408,7 @@ void testDynamicReentrancyContextsRevertOrInvalidUndoesTstorageAfterSuccessfullC @Test void testReentrancyContextsTstoreAfterReentrantCall() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -422,7 +426,7 @@ void testReentrancyContextsTstoreAfterReentrantCall() throws FileNotFoundExcepti @Test void testReentrancyContextsTloadAfterReentrantTstore() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -440,7 +444,7 @@ void testReentrancyContextsTloadAfterReentrantTstore() throws FileNotFoundExcept @Test void testReentrancyContextsManipulateInReentrantCall() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -458,7 +462,7 @@ void testReentrancyContextsManipulateInReentrantCall() throws FileNotFoundExcept @Test void testReentrancyContextsTstoreInCallThenTloadReturnInStaticCall() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -476,7 +480,7 @@ void testReentrancyContextsTstoreInCallThenTloadReturnInStaticCall() throws File @Test void testTransientStorageGasMeasureTests() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tstorage_gas_measure_tests.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -491,7 +495,7 @@ void testTransientStorageGasMeasureTests() throws FileNotFoundException, DslProc @Test void testTstoreLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tstore_loop_until_out_of_gas.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -507,7 +511,7 @@ void testTstoreLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorExc @Test void testTstoreWideAddressSpaceLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -523,7 +527,7 @@ void testTstoreWideAddressSpaceLoopUntilOutOfGas() throws FileNotFoundException, @Test void testTstoreAndTloadLoopUntilOutOfGas() throws FileNotFoundException, DslProcessorException { - DslParser parser = DslParser.fromResource("dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt"); + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt"); World world = new World(); WorldDslProcessor processor = new WorldDslProcessor(world); processor.processCommands(parser); @@ -537,6 +541,35 @@ void testTstoreAndTloadLoopUntilOutOfGas() throws FileNotFoundException, DslProc assertEquals(700000, txRunOutOfGas); // Assert that it consumed all the gas configured in the transaction } + + @ParameterizedTest + @MethodSource("provideParametersForSelfDestructCases") + void testTstorageSelfDestructCases_OnEachTest_TheEventsEmittedAreTheExpected(String dslFile, Integer numberOfOksEmitted) throws FileNotFoundException, DslProcessorException { + + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/" + dslFile); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txDeployTestContract = "txDeployTestContract"; + assertTransactionReceiptWithStatus(world, txDeployTestContract, "b01", true); + + String txCheckValuesStoredInTstorage = "txPerformTest"; + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b02", true); + Assertions.assertEquals(numberOfOksEmitted, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); + } + + private static Stream provideParametersForSelfDestructCases() { + return Stream.of( + Arguments.of("tload_after_selfdestruct_pre_existing_contract.txt", 3 ), + Arguments.of("tload_after_selfdestruct_new_contract.txt", 3 ), + Arguments.of("tload_after_inner_selfdestruct_pre_existing_contract.txt", 2 ), + Arguments.of("tload_after_inner_selfdestruct_new_contract.txt", 2 ), + Arguments.of("tstore_after_selfdestruct_pre_existing_contract.txt", 4 ), + Arguments.of("tstore_after_selfdestruct_new_contract.txt", 4 ) + ); + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v1_create_context.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_call_subcall.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_call_subcall.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_simple.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_staticcall_subcall_can_call_tload.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_staticcall_subcall_cant_call_tstore.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_invalid.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_revert.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_all.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_revert_or_invalid_undoes_tstorage_after_successfull_call.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/eip1153_basic_tests.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/eip1153_basic_tests.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/eip1153_basic_tests.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/eip1153_basic_tests.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/in_constructor_and_deploy_code_create_context.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/no_constructor_code_create_context.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/no_constructor_code_create_context.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/no_constructor_code_create_context.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/only_constructor_code_create_context.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/only_constructor_code_create_context.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/only_constructor_code_create_context.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_manipulate_in_reentrant_call.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tload_after_reentrant_tstore.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_in_call_then_tload_return_in_static_call.txt diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_new_contract.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_new_contract.txt new file mode 100644 index 00000000000..4aeaf2dbd12 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_new_contract.txt @@ -0,0 +1,136 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TloadAfterInnerSelfdestructingNewContract { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function performTest() external { + Callee callee = new Callee(); + address calleeAddress = address(callee); + uint256 resultCallOption1; + uint256 valueLoadedFromMemory; + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + + assembly { + // Call Option 1: Executes tstore, inner call to selfdestruct and then tload and return data + let availablePointerCallOption1 := mload(0x40) + mstore(availablePointerCallOption1, executeSignature) + mstore(add(availablePointerCallOption1, 4), 1) + resultCallOption1 := call(gas(), calleeAddress, 0, availablePointerCallOption1, 0x24, availablePointerCallOption1, 0x20) + + // Copy returndata into memory to retrieve the returned value + returndatacopy(availablePointerCallOption1, 0, returndatasize()) + valueLoadedFromMemory := mload(availablePointerCallOption1) + } + + checkReturnValueExpected(resultCallOption1, 'Checking result call option 1', 0x01); + checkReturnValueExpected(valueLoadedFromMemory, 'Checking value from mload 0', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + event OK(); + event ERROR(string, uint256); + + function execute(uint256 callOption) external returns (uint256) { + address calleeAddress = address(this); + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + uint256 resultCallOption2; + assembly { + switch callOption + case 1 { + tstore(0xFF, 0x100) + // Call Option 2: Executes tload and returns data + let availablePointerCallOption2 := mload(0x40) + mstore(availablePointerCallOption2, executeSignature) + mstore(add(availablePointerCallOption2, 4), 2) + resultCallOption2 := call(gas(), calleeAddress, 0, availablePointerCallOption2, 0x24, availablePointerCallOption2, 0x20) + + // Load value from transient storage + let value := tload(0xFF) + mstore(0x00, value) // Store it in memory to return + return(0x00, 0x20) // Return 32 bytes from memory + } + case 2 { + selfdestruct(0) + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TloadAfterInnerSelfdestructingNewContract: 608060405234801561000f575f80fd5b506104708061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f604051610044906101ad565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f8190505f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f895af193503d5f823e80519250506100ed836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20310000008152506001610136565b61012f826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f616420300000000000815250610100610136565b5050505050565b80830361016e577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101a8565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161019f92919061025c565b60405180910390a15b505050565b6101b08061028b83390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101f15780820151818401526020810190506101d6565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610216826101ba565b61022081856101c4565b93506102308185602086016101d4565b610239816101fc565b840191505092915050565b5f819050919050565b61025681610244565b82525050565b5f6040820190508181035f830152610274818561020c565b9050610283602083018461024d565b939250505056fe608060405234801561000f575f80fd5b506101938061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b6100476004803603810190610042919061010a565b61005d565b6040516100549190610144565b60405180910390f35b5f803090505f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b90505f846001811461009d57600281146100c7576100ca565b61010060ff5d604051838152600260048201526020816024835f895af1925060ff5c805f5260205ff35b5fff5b50505050919050565b5f80fd5b5f819050919050565b6100e9816100d7565b81146100f3575f80fd5b50565b5f81359050610104816100e0565b92915050565b5f6020828403121561011f5761011e6100d3565b5b5f61012c848285016100f6565b91505092915050565b61013e816100d7565b82525050565b5f6020820190506101575f830184610135565b9291505056fea2646970667358221220df3fda34f805973d73508c3bff5aa075ac36fd7769240906d19a4ade4713155464736f6c63430008180033a26469706673582212202ee0175c4410ed0d1259c8ad0377835933ddf29c77105e09bac218f55b6c5f3464736f6c63430008180033 + +function hashes:s + +- 0d0b85f1: performTest() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadAfterSelfdestructPreExistingContract contract +transaction_build txDeployTestContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b506104708061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f604051610044906101ad565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f8190505f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f895af193503d5f823e80519250506100ed836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20310000008152506001610136565b61012f826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f616420300000000000815250610100610136565b5050505050565b80830361016e577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101a8565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161019f92919061025c565b60405180910390a15b505050565b6101b08061028b83390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101f15780820151818401526020810190506101d6565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610216826101ba565b61022081856101c4565b93506102308185602086016101d4565b610239816101fc565b840191505092915050565b5f819050919050565b61025681610244565b82525050565b5f6040820190508181035f830152610274818561020c565b9050610283602083018461024d565b939250505056fe608060405234801561000f575f80fd5b506101938061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b6100476004803603810190610042919061010a565b61005d565b6040516100549190610144565b60405180910390f35b5f803090505f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b90505f846001811461009d57600281146100c7576100ca565b61010060ff5d604051838152600260048201526020816024835f895af1925060ff5c805f5260205ff35b5fff5b50505050919050565b5f80fd5b5f819050919050565b6100e9816100d7565b81146100f3575f80fd5b50565b5f81359050610104816100e0565b92915050565b5f6020828403121561011f5761011e6100d3565b5b5f61012c848285016100f6565b91505092915050565b61013e816100d7565b82525050565b5f6020820190506101575f830184610135565b9291505056fea2646970667358221220df3fda34f805973d73508c3bff5aa075ac36fd7769240906d19a4ade4713155464736f6c63430008180033a26469706673582212202ee0175c4410ed0d1259c8ad0377835933ddf29c77105e09bac218f55b6c5f3464736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txDeployTestContract transaction +block_build b01 + parent g00 + transactions txDeployTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute performTest function from contract +transaction_build txPerformTest + sender acc1 + nonce 1 + contract txDeployTestContract + value 0 + data 0d0b85f1 + gas 300000 + build + +# Create block to hold txPerformTest transaction +block_build b02 + parent b01 + transactions txPerformTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_pre_existing_contract.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_pre_existing_contract.txt new file mode 100644 index 00000000000..c9aa4f4565f --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_inner_selfdestruct_pre_existing_contract.txt @@ -0,0 +1,136 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TloadAfterInnerSelfdestructingPreExistingContract { + Callee callee; + + constructor() { + callee = new Callee(); + } + + event OK(); + event ERROR(string, uint256); + + function performTest() external { + address calleeAddress = address(callee); + uint256 resultCallOption1; + uint256 valueLoadedFromMemory; + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + + assembly { + // Call Option 1: Executes tstore, inner call to selfdestruct and then tload and return data + let availablePointerCallOption1 := mload(0x40) + mstore(availablePointerCallOption1, executeSignature) + mstore(add(availablePointerCallOption1, 4), 1) + resultCallOption1 := call(gas(), calleeAddress, 0, availablePointerCallOption1, 0x24, availablePointerCallOption1, 0x20) + + // Copy returndata into memory to retrieve the returned value + returndatacopy(availablePointerCallOption1, 0, returndatasize()) + valueLoadedFromMemory := mload(availablePointerCallOption1) + } + + checkReturnValueExpected(resultCallOption1, 'Checking result call option 1', 0x01); + checkReturnValueExpected(valueLoadedFromMemory, 'Checking value from mload 0', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + event OK(); + event ERROR(string, uint256); + + function execute(uint256 callOption) external returns (uint256) { + address calleeAddress = address(this); + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + uint256 resultCallOption2; + assembly { + switch callOption + case 1 { + tstore(0xFF, 0x100) + // Call Option 2: Executes tload and returns data + let availablePointerCallOption2 := mload(0x40) + mstore(availablePointerCallOption2, executeSignature) + mstore(add(availablePointerCallOption2, 4), 2) + resultCallOption2 := call(gas(), calleeAddress, 0, availablePointerCallOption2, 0x24, availablePointerCallOption2, 0x20) + + // Load value from transient storage + let value := tload(0xFF) + mstore(0x00, value) // Store it in memory to return + return(0x00, 0x20) // Return 32 bytes from memory + } + case 2 { + selfdestruct(0) + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TloadAfterInnerSelfdestructingPreExistingContract: 608060405234801561000f575f80fd5b5060405161001c90610079565b604051809103905ff080158015610035573d5f803e3d5ffd5b505f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610086565b6101b08061033c83390190565b6102a9806100935f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f895af193503d5f823e80519250506100e4836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e2031000000815250600161012c565b610126826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f61642030000000000081525061010061012c565b50505050565b808303610164577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161019e565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610195929190610245565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101da5780820151818401526020810190506101bf565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6101ff826101a3565b61020981856101ad565b93506102198185602086016101bd565b610222816101e5565b840191505092915050565b5f819050919050565b61023f8161022d565b82525050565b5f6040820190508181035f83015261025d81856101f5565b905061026c6020830184610236565b939250505056fea2646970667358221220314f4ea23497493d6086e14a2ebfdd4290728740c02f4713001e260d7d662c4164736f6c63430008180033608060405234801561000f575f80fd5b506101938061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b6100476004803603810190610042919061010a565b61005d565b6040516100549190610144565b60405180910390f35b5f803090505f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b90505f846001811461009d57600281146100c7576100ca565b61010060ff5d604051838152600260048201526020816024835f895af1925060ff5c805f5260205ff35b5fff5b50505050919050565b5f80fd5b5f819050919050565b6100e9816100d7565b81146100f3575f80fd5b50565b5f81359050610104816100e0565b92915050565b5f6020828403121561011f5761011e6100d3565b5b5f61012c848285016100f6565b91505092915050565b61013e816100d7565b82525050565b5f6020820190506101575f830184610135565b9291505056fea264697066735822122000dadba91902cd6d3eaf38fdb47cdccbbf9036448d79da3ff9b15dc0012e4a0864736f6c63430008180033 + +function hashes:s + +- 0d0b85f1: performTest() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadAfterSelfdestructPreExistingContract contract +transaction_build txDeployTestContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b5060405161001c90610079565b604051809103905ff080158015610035573d5f803e3d5ffd5b505f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610086565b6101b08061033c83390190565b6102a9806100935f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f895af193503d5f823e80519250506100e4836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e2031000000815250600161012c565b610126826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f61642030000000000081525061010061012c565b50505050565b808303610164577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161019e565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610195929190610245565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156101da5780820151818401526020810190506101bf565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6101ff826101a3565b61020981856101ad565b93506102198185602086016101bd565b610222816101e5565b840191505092915050565b5f819050919050565b61023f8161022d565b82525050565b5f6040820190508181035f83015261025d81856101f5565b905061026c6020830184610236565b939250505056fea2646970667358221220314f4ea23497493d6086e14a2ebfdd4290728740c02f4713001e260d7d662c4164736f6c63430008180033608060405234801561000f575f80fd5b506101938061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b6100476004803603810190610042919061010a565b61005d565b6040516100549190610144565b60405180910390f35b5f803090505f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b90505f846001811461009d57600281146100c7576100ca565b61010060ff5d604051838152600260048201526020816024835f895af1925060ff5c805f5260205ff35b5fff5b50505050919050565b5f80fd5b5f819050919050565b6100e9816100d7565b81146100f3575f80fd5b50565b5f81359050610104816100e0565b92915050565b5f6020828403121561011f5761011e6100d3565b5b5f61012c848285016100f6565b91505092915050565b61013e816100d7565b82525050565b5f6020820190506101575f830184610135565b9291505056fea264697066735822122000dadba91902cd6d3eaf38fdb47cdccbbf9036448d79da3ff9b15dc0012e4a0864736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txDeployTestContract transaction +block_build b01 + parent g00 + transactions txDeployTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute performTest function from contract +transaction_build txPerformTest + sender acc1 + nonce 1 + contract txDeployTestContract + value 0 + data 0d0b85f1 + gas 300000 + build + +# Create block to hold txPerformTest transaction +block_build b02 + parent b01 + transactions txPerformTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_new_contract.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_new_contract.txt new file mode 100644 index 00000000000..ef46b4f70d3 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_new_contract.txt @@ -0,0 +1,132 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TloadAfterSelfdestructNewContract { + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function performTest() external { + Callee callee = new Callee(); + address calleeAddress = address(callee); + uint256 resultCallOption1; + uint256 resultCallOption2; + uint256 valueLoadedFromMemory; + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + + assembly { + // Call Option 1: Executes tstore and selfdestruct + let availablePointerCallOption1 := mload(0x40) + mstore(availablePointerCallOption1, executeSignature) + mstore(add(availablePointerCallOption1, 4), 1) + resultCallOption1 := call(gas(), calleeAddress, 0, availablePointerCallOption1, 0x24, availablePointerCallOption1, 0x20) + // Note: Callee will self-destruct, no return data expected for callOption == 1. + + // Call Option 2: Executes tload and returns data + let availablePointerCallOption2 := mload(0x40) + mstore(availablePointerCallOption2, executeSignature) + mstore(add(availablePointerCallOption2, 4), 2) + resultCallOption2 := call(gas(), calleeAddress, 0, availablePointerCallOption2, 0x24, availablePointerCallOption2, 0x2) + + // Copy returndata into memory to retrieve the returned value + returndatacopy(availablePointerCallOption2, 0, returndatasize()) + valueLoadedFromMemory := mload(availablePointerCallOption2) + } + + checkReturnValueExpected(resultCallOption1, 'Checking result call option 1', 0x01); + checkReturnValueExpected(resultCallOption2, 'Checking result call option 2', 0x01); + checkReturnValueExpected(valueLoadedFromMemory, 'Checking value from mload 0', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute(uint256 callOption) external returns (uint256) { + assembly { + switch callOption + case 1 { + tstore(0xFF, 0x100) + selfdestruct(0) + } + case 2 { + // Load value from transient storage + let value := tload(0xFF) + mstore(0x00, value) // Store it in memory to return + return(0x00, 0x20) // Return 32 bytes from memory + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TloadAfterSelfdestructNewContract: 608060405234801561000f575f80fd5b506104888061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f6040516100449061020a565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f8190505f805f807ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8a5af19450604051828152600260048201526002816024835f8b5af194503d5f823e805193505050610108846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20310000008152506001610193565b610149836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20320000008152506001610193565b61018b826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f616420300000000000815250610100610193565b505050505050565b8083036101cb577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610205565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101fc9291906102b9565b60405180910390a15b505050565b61016b806102e883390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561024e578082015181840152602081019050610233565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61027382610217565b61027d8185610221565b935061028d818560208601610231565b61029681610259565b840191505092915050565b5f819050919050565b6102b3816102a1565b82525050565b5f6040820190508181035f8301526102d18185610269565b90506102e060208301846102aa565b939250505056fe608060405234801561000f575f80fd5b5061014e8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100c5565b61005d565b60405161005491906100ff565b60405180910390f35b5f8160018114610074576002811461007d57610088565b61010060ff5d5fff5b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100a481610092565b81146100ae575f80fd5b50565b5f813590506100bf8161009b565b92915050565b5f602082840312156100da576100d961008e565b5b5f6100e7848285016100b1565b91505092915050565b6100f981610092565b82525050565b5f6020820190506101125f8301846100f0565b9291505056fea264697066735822122055ccf41b608b610b0f0b3c6343fb66efe3d487da32a8a6981a907e22d0d4722e64736f6c63430008180033a264697066735822122076e62ebfbdf54923ba4920877ca4a8354142b8a1b5a18492fd7b0f1da3956cb964736f6c63430008180033 + +function hashes:s + +- 0d0b85f1: performTest() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadAfterSelfdestructPreExistingContract contract +transaction_build txDeployTestContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b506104888061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f6040516100449061020a565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f8190505f805f807ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8a5af19450604051828152600260048201526002816024835f8b5af194503d5f823e805193505050610108846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20310000008152506001610193565b610149836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20320000008152506001610193565b61018b826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f616420300000000000815250610100610193565b505050505050565b8083036101cb577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610205565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101fc9291906102b9565b60405180910390a15b505050565b61016b806102e883390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561024e578082015181840152602081019050610233565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61027382610217565b61027d8185610221565b935061028d818560208601610231565b61029681610259565b840191505092915050565b5f819050919050565b6102b3816102a1565b82525050565b5f6040820190508181035f8301526102d18185610269565b90506102e060208301846102aa565b939250505056fe608060405234801561000f575f80fd5b5061014e8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100c5565b61005d565b60405161005491906100ff565b60405180910390f35b5f8160018114610074576002811461007d57610088565b61010060ff5d5fff5b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100a481610092565b81146100ae575f80fd5b50565b5f813590506100bf8161009b565b92915050565b5f602082840312156100da576100d961008e565b5b5f6100e7848285016100b1565b91505092915050565b6100f981610092565b82525050565b5f6020820190506101125f8301846100f0565b9291505056fea264697066735822122055ccf41b608b610b0f0b3c6343fb66efe3d487da32a8a6981a907e22d0d4722e64736f6c63430008180033a264697066735822122076e62ebfbdf54923ba4920877ca4a8354142b8a1b5a18492fd7b0f1da3956cb964736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txDeployTestContract transaction +block_build b01 + parent g00 + transactions txDeployTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute performTest function from contract +transaction_build txPerformTest + sender acc1 + nonce 1 + contract txDeployTestContract + value 0 + data 0d0b85f1 + gas 300000 + build + +# Create block to hold txPerformTest transaction +block_build b02 + parent b01 + transactions txPerformTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_pre_existing_contract.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_pre_existing_contract.txt new file mode 100644 index 00000000000..2ae3bbe240f --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_after_selfdestruct_pre_existing_contract.txt @@ -0,0 +1,130 @@ +comment + +// CONTRACT CODE +pragma solidity ^0.8.24; + +contract TloadAfterSelfdestructPreExistingContract { + Callee callee; + + constructor() { + callee = new Callee(); + } + + event OK(); + event ERROR(string, uint256); + + function performTest() external { + address calleeAddress = address(callee); + uint256 resultCallOption1; + uint256 resultCallOption2; + uint256 valueLoadedFromMemory; + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + + assembly { + let availablePointerCallOption1 := mload(0x40) + mstore(availablePointerCallOption1, executeSignature) + mstore(add(availablePointerCallOption1, 4), 1) + resultCallOption1 := call(gas(), calleeAddress, 0, availablePointerCallOption1, 0x24, availablePointerCallOption1, 0x20) + + let availablePointerCallOption2 := mload(0x40) + mstore(availablePointerCallOption2, executeSignature) + mstore(add(availablePointerCallOption2, 4), 2) + resultCallOption2 := call(gas(), calleeAddress, 0, availablePointerCallOption2, 0x24, availablePointerCallOption2, 0x2) + + // Copy returndata into memory to retrieve the returned value + returndatacopy(availablePointerCallOption2, 0, returndatasize()) + valueLoadedFromMemory := mload(availablePointerCallOption2) + } + + checkReturnValueExpected(resultCallOption1, 'Checking result call option 1', 0x01); + checkReturnValueExpected(resultCallOption2, 'Checking result call option 2', 0x01); + checkReturnValueExpected(valueLoadedFromMemory, 'Checking value from mload 0', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + function execute(uint256 callOption) external returns (uint256) { + assembly { + switch callOption + case 1 { + tstore(0xFF, 0x100) + selfdestruct(0) + } + case 2 { + // Load value from transient storage + let value := tload(0xFF) + mstore(0x00, value) // Store it in memory to return + return(0x00, 0x20) // Return 32 bytes from memory + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TloadAfterSelfdestructPreExistingContract: 608060405234801561000f575f80fd5b5060405161001c90610079565b604051809103905ff080158015610035573d5f803e3d5ffd5b505f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610086565b61016b8061039983390190565b610306806100935f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f805f807ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8a5af19450604051828152600260048201526002816024835f8b5af194503d5f823e8051935050506100ff846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20310000008152506001610189565b610140836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20320000008152506001610189565b610182826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f616420300000000000815250610100610189565b5050505050565b8083036101c1577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101fb565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101f29291906102a2565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561023757808201518184015260208101905061021c565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61025c82610200565b610266818561020a565b935061027681856020860161021a565b61027f81610242565b840191505092915050565b5f819050919050565b61029c8161028a565b82525050565b5f6040820190508181035f8301526102ba8185610252565b90506102c96020830184610293565b939250505056fea26469706673582212205534fa1e929c43e2b37b29d413d4548878f2de78cb0752060df934815275576864736f6c63430008180033608060405234801561000f575f80fd5b5061014e8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100c5565b61005d565b60405161005491906100ff565b60405180910390f35b5f8160018114610074576002811461007d57610088565b61010060ff5d5fff5b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100a481610092565b81146100ae575f80fd5b50565b5f813590506100bf8161009b565b92915050565b5f602082840312156100da576100d961008e565b5b5f6100e7848285016100b1565b91505092915050565b6100f981610092565b82525050565b5f6020820190506101125f8301846100f0565b9291505056fea26469706673582212209845c65124ff773997c6f9fecd143ae783a790c95fab788e181664dce3129d7d64736f6c63430008180033 + +function hashes:s + +- 0d0b85f1: performTest() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadAfterSelfdestructPreExistingContract contract +transaction_build txDeployTestContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b5060405161001c90610079565b604051809103905ff080158015610035573d5f803e3d5ffd5b505f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610086565b61016b8061039983390190565b610306806100935f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f805f807ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8a5af19450604051828152600260048201526002816024835f8b5af194503d5f823e8051935050506100ff846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20310000008152506001610189565b610140836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e20320000008152506001610189565b610182826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f616420300000000000815250610100610189565b5050505050565b8083036101c1577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a16101fb565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f82846040516101f29291906102a2565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561023757808201518184015260208101905061021c565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61025c82610200565b610266818561020a565b935061027681856020860161021a565b61027f81610242565b840191505092915050565b5f819050919050565b61029c8161028a565b82525050565b5f6040820190508181035f8301526102ba8185610252565b90506102c96020830184610293565b939250505056fea26469706673582212205534fa1e929c43e2b37b29d413d4548878f2de78cb0752060df934815275576864736f6c63430008180033608060405234801561000f575f80fd5b5061014e8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100c5565b61005d565b60405161005491906100ff565b60405180910390f35b5f8160018114610074576002811461007d57610088565b61010060ff5d5fff5b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100a481610092565b81146100ae575f80fd5b50565b5f813590506100bf8161009b565b92915050565b5f602082840312156100da576100d961008e565b5b5f6100e7848285016100b1565b91505092915050565b6100f981610092565b82525050565b5f6020820190506101125f8301846100f0565b9291505056fea26469706673582212209845c65124ff773997c6f9fecd143ae783a790c95fab788e181664dce3129d7d64736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txDeployTestContract transaction +block_build b01 + parent g00 + transactions txDeployTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute performTest function from contract +transaction_build txPerformTest + sender acc1 + nonce 1 + contract txDeployTestContract + value 0 + data 0d0b85f1 + gas 300000 + build + +# Create block to hold txPerformTest transaction +block_build b02 + parent b01 + transactions txPerformTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_tstore_basic_tests.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tload_tstore_basic_tests.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_tstore_basic_tests.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstorage_gas_measure_tests.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstorage_gas_measure_tests.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstorage_gas_measure_tests.txt diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_new_contract.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_new_contract.txt new file mode 100644 index 00000000000..7902b36f366 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_new_contract.txt @@ -0,0 +1,146 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstoreAfterSelfdestructingNewContract { + + constructor() { + } + + event OK(); + event ERROR(string, uint256); + + function performtTest() external { + Callee callee = new Callee(); + address calleeAddress = address(callee); + uint256 resultCallOption1; + uint256 resultCallOption2; + uint256 resultCallOption3; + uint256 valueLoadedFromMemory; + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + + assembly { + // Call Option 1: Executes selfdestruct in callee contract + let availablePointerCallOption1 := mload(0x40) + mstore(availablePointerCallOption1, executeSignature) + mstore(add(availablePointerCallOption1, 4), 1) + resultCallOption1 := call(gas(), calleeAddress, 0, availablePointerCallOption1, 0x24, availablePointerCallOption1, 0x20) + + // Call Option 2: Executes tstore in callee contract + let availablePointerCallOption2 := mload(0x40) + mstore(availablePointerCallOption2, executeSignature) + mstore(add(availablePointerCallOption2, 4), 2) + resultCallOption2 := call(gas(), calleeAddress, 0, availablePointerCallOption2, 0x24, availablePointerCallOption2, 0x20) + + + // Call Option 3: Executes tload, store it in memory and return data + let availablePointerCallOption3 := mload(0x40) + mstore(availablePointerCallOption3, executeSignature) + mstore(add(availablePointerCallOption3, 4), 3) + resultCallOption3 := call(gas(), calleeAddress, 0, availablePointerCallOption3, 0x24, availablePointerCallOption3, 0x20) + + // Copy returndata into memory to retrieve the returned value + returndatacopy(availablePointerCallOption3, 0, returndatasize()) + valueLoadedFromMemory := mload(availablePointerCallOption3) + } + + checkReturnValueExpected(resultCallOption1, 'Checking result call option 1', 0x01); + checkReturnValueExpected(resultCallOption2, 'Checking result call option 2', 0x01); + checkReturnValueExpected(resultCallOption3, 'Checking result call option 3', 0x01); + checkReturnValueExpected(valueLoadedFromMemory, 'Checking value from mload 0', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + event OK(); + event ERROR(string, uint256); + + function execute(uint256 callOption) external returns (uint256) { + assembly { + switch callOption + case 1 { + selfdestruct(0) + } + case 2 { + tstore(0xFF, 0x100) + } + case 3 { + // Load value from transient storage + let value := tload(0xFF) + mstore(0x00, value) // Store it in memory to return + return(0x00, 0x20) // Return 32 bytes from memory + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TstoreAfterSelfdestructingNewContract: 608060405234801561000f575f80fd5b506104f28061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f60405161004490610267565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f8190505f805f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8b5af19550604051828152600260048201526020816024835f8c5af19550604051838152600360048201526020816024835f8d5af195503d5f823e80519450505050610123856040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203100000081525060016101f0565b610164846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203200000081525060016101f0565b6101a5836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203300000081525060016101f0565b6101e7826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f6164203000000000008152506101006101f0565b50505050505050565b808303610228577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610262565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610259929190610316565b60405180910390a15b505050565b6101788061034583390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156102ab578082015181840152602081019050610290565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6102d082610274565b6102da818561027e565b93506102ea81856020860161028e565b6102f3816102b6565b840191505092915050565b5f819050919050565b610310816102fe565b82525050565b5f6040820190508181035f83015261032e81856102c6565b905061033d6020830184610307565b939250505056fe608060405234801561000f575f80fd5b5061015b8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100d2565b61005d565b604051610054919061010c565b60405180910390f35b5f816001811461007c576002811461007f576003811461008a57610095565b5fff5b61010060ff5d610095565b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100b18161009f565b81146100bb575f80fd5b50565b5f813590506100cc816100a8565b92915050565b5f602082840312156100e7576100e661009b565b5b5f6100f4848285016100be565b91505092915050565b6101068161009f565b82525050565b5f60208201905061011f5f8301846100fd565b9291505056fea264697066735822122052a1869c2ba9a2749479c068cda41ba0a57aa6967098ab6a0fdc351722448d5d64736f6c63430008180033a264697066735822122004e2a48494b3e22b144f5f63708a43173ddd8cff969f549ce7636f99245196da64736f6c63430008180033 + +function hashes: + +- 0d0b85f1: performTest() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadAfterSelfdestructPreExistingContract contract +transaction_build txDeployTestContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b506104f28061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f60405161004490610267565b604051809103905ff08015801561005d573d5f803e3d5ffd5b5090505f8190505f805f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8b5af19550604051828152600260048201526020816024835f8c5af19550604051838152600360048201526020816024835f8d5af195503d5f823e80519450505050610123856040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203100000081525060016101f0565b610164846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203200000081525060016101f0565b6101a5836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203300000081525060016101f0565b6101e7826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f6164203000000000008152506101006101f0565b50505050505050565b808303610228577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610262565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8284604051610259929190610316565b60405180910390a15b505050565b6101788061034583390190565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156102ab578082015181840152602081019050610290565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6102d082610274565b6102da818561027e565b93506102ea81856020860161028e565b6102f3816102b6565b840191505092915050565b5f819050919050565b610310816102fe565b82525050565b5f6040820190508181035f83015261032e81856102c6565b905061033d6020830184610307565b939250505056fe608060405234801561000f575f80fd5b5061015b8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100d2565b61005d565b604051610054919061010c565b60405180910390f35b5f816001811461007c576002811461007f576003811461008a57610095565b5fff5b61010060ff5d610095565b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100b18161009f565b81146100bb575f80fd5b50565b5f813590506100cc816100a8565b92915050565b5f602082840312156100e7576100e661009b565b5b5f6100f4848285016100be565b91505092915050565b6101068161009f565b82525050565b5f60208201905061011f5f8301846100fd565b9291505056fea264697066735822122052a1869c2ba9a2749479c068cda41ba0a57aa6967098ab6a0fdc351722448d5d64736f6c63430008180033a264697066735822122004e2a48494b3e22b144f5f63708a43173ddd8cff969f549ce7636f99245196da64736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txDeployTestContract transaction +block_build b01 + parent g00 + transactions txDeployTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute performTest function from contract +transaction_build txPerformTest + sender acc1 + nonce 1 + contract txDeployTestContract + value 0 + data 0d0b85f1 + gas 300000 + build + +# Create block to hold txPerformTest transaction +block_build b02 + parent b01 + transactions txPerformTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_pre_existing_contract.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_pre_existing_contract.txt new file mode 100644 index 00000000000..3766de47657 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_after_selfdestruct_pre_existing_contract.txt @@ -0,0 +1,147 @@ +comment + +// CONTRACT CODE + +pragma solidity ^0.8.24; + +contract TstoreAfterSelfdestructingPreExistingContract { + Callee callee; + + constructor() { + callee = new Callee(); + } + + event OK(); + event ERROR(string, uint256); + + function performTest() external { + address calleeAddress = address(callee); + uint256 resultCallOption1; + uint256 resultCallOption2; + uint256 resultCallOption3; + uint256 valueLoadedFromMemory; + bytes4 executeSignature = bytes4(keccak256("execute(uint256)")); + + assembly { + // Call Option 1: Executes selfdestruct in callee contract + let availablePointerCallOption1 := mload(0x40) + mstore(availablePointerCallOption1, executeSignature) + mstore(add(availablePointerCallOption1, 4), 1) + resultCallOption1 := call(gas(), calleeAddress, 0, availablePointerCallOption1, 0x24, availablePointerCallOption1, 0x20) + + // Call Option 2: Executes tstore in callee contract + let availablePointerCallOption2 := mload(0x40) + mstore(availablePointerCallOption2, executeSignature) + mstore(add(availablePointerCallOption2, 4), 2) + resultCallOption2 := call(gas(), calleeAddress, 0, availablePointerCallOption2, 0x24, availablePointerCallOption2, 0x20) + + + // Call Option 3: Executes tload, store it in memory and return data + let availablePointerCallOption3 := mload(0x40) + mstore(availablePointerCallOption3, executeSignature) + mstore(add(availablePointerCallOption3, 4), 3) + resultCallOption3 := call(gas(), calleeAddress, 0, availablePointerCallOption3, 0x24, availablePointerCallOption3, 0x20) + + // Copy returndata into memory to retrieve the returned value + returndatacopy(availablePointerCallOption3, 0, returndatasize()) + valueLoadedFromMemory := mload(availablePointerCallOption3) + } + + checkReturnValueExpected(resultCallOption1, 'Checking result call option 1', 0x01); + checkReturnValueExpected(resultCallOption2, 'Checking result call option 2', 0x01); + checkReturnValueExpected(resultCallOption3, 'Checking result call option 3', 0x01); + checkReturnValueExpected(valueLoadedFromMemory, 'Checking value from mload 0', 0x100); + } + + function checkReturnValueExpected(uint256 valueReceived, string memory message, uint256 expectedValue) private { + if( valueReceived == expectedValue){ + emit OK(); + } else { + emit ERROR(message, valueReceived); + } + } +} + +contract Callee { + + event OK(); + event ERROR(string, uint256); + + function execute(uint256 callOption) external returns (uint256) { + assembly { + switch callOption + case 1 { + selfdestruct(0) + } + case 2 { + tstore(0xFF, 0x100) + } + case 3 { + // Load value from transient storage + let value := tload(0xFF) + mstore(0x00, value) // Store it in memory to return + return(0x00, 0x20) // Return 32 bytes from memory + } + } + } +} + +// DESCRIPTION + +// CONTRACT BYTECODE + +TstoreAfterSelfdestructingPreExistingContract: 608060405234801561000f575f80fd5b5060405161001c90610079565b604051809103905ff080158015610035573d5f803e3d5ffd5b505f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610086565b610178806103f683390190565b610363806100935f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f805f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8b5af19550604051828152600260048201526020816024835f8c5af19550604051838152600360048201526020816024835f8d5af195503d5f823e8051945050505061011a856040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203100000081525060016101e6565b61015b846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203200000081525060016101e6565b61019c836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203300000081525060016101e6565b6101de826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f6164203000000000008152506101006101e6565b505050505050565b80830361021e577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610258565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161024f9291906102ff565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610294578082015181840152602081019050610279565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6102b98261025d565b6102c38185610267565b93506102d3818560208601610277565b6102dc8161029f565b840191505092915050565b5f819050919050565b6102f9816102e7565b82525050565b5f6040820190508181035f83015261031781856102af565b905061032660208301846102f0565b939250505056fea2646970667358221220430065adaea3ec55b26991f3b100cb73215160e30134979bc834001868b7049464736f6c63430008180033608060405234801561000f575f80fd5b5061015b8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100d2565b61005d565b604051610054919061010c565b60405180910390f35b5f816001811461007c576002811461007f576003811461008a57610095565b5fff5b61010060ff5d610095565b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100b18161009f565b81146100bb575f80fd5b50565b5f813590506100cc816100a8565b92915050565b5f602082840312156100e7576100e661009b565b5b5f6100f4848285016100be565b91505092915050565b6101068161009f565b82525050565b5f60208201905061011f5f8301846100fd565b9291505056fea26469706673582212202863e4706ef82faa6ad13fcf9e1ee1699e2008d0c74aa076910f6421a8bacd5b64736f6c63430008180033 + +function hashes: + +- 0d0b85f1: performTest() + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadAfterSelfdestructPreExistingContract contract +transaction_build txDeployTestContract + sender acc1 + receiverAddress 00 + value 0 + data 608060405234801561000f575f80fd5b5060405161001c90610079565b604051809103905ff080158015610035573d5f803e3d5ffd5b505f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610086565b610178806103f683390190565b610363806100935f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630d0b85f11461002d575b5f80fd5b610035610037565b005b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f805f805f7ffe0d94c1a8f5608a1172c49cc7704ac011b690506896af15ba9aab651ff44e1b9050604051818152600160048201526020816024835f8b5af19550604051828152600260048201526020816024835f8c5af19550604051838152600360048201526020816024835f8d5af195503d5f823e8051945050505061011a856040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203100000081525060016101e6565b61015b846040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203200000081525060016101e6565b61019c836040518060400160405280601d81526020017f436865636b696e6720726573756c742063616c6c206f7074696f6e203300000081525060016101e6565b6101de826040518060400160405280601b81526020017f436865636b696e672076616c75652066726f6d206d6c6f6164203000000000008152506101006101e6565b505050505050565b80830361021e577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a1610258565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f828460405161024f9291906102ff565b60405180910390a15b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610294578082015181840152602081019050610279565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6102b98261025d565b6102c38185610267565b93506102d3818560208601610277565b6102dc8161029f565b840191505092915050565b5f819050919050565b6102f9816102e7565b82525050565b5f6040820190508181035f83015261031781856102af565b905061032660208301846102f0565b939250505056fea2646970667358221220430065adaea3ec55b26991f3b100cb73215160e30134979bc834001868b7049464736f6c63430008180033608060405234801561000f575f80fd5b5061015b8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063fe0d94c11461002d575b5f80fd5b610047600480360381019061004291906100d2565b61005d565b604051610054919061010c565b60405180910390f35b5f816001811461007c576002811461007f576003811461008a57610095565b5fff5b61010060ff5d610095565b60ff5c805f5260205ff35b50919050565b5f80fd5b5f819050919050565b6100b18161009f565b81146100bb575f80fd5b50565b5f813590506100cc816100a8565b92915050565b5f602082840312156100e7576100e661009b565b5b5f6100f4848285016100be565b91505092915050565b6101068161009f565b82525050565b5f60208201905061011f5f8301846100fd565b9291505056fea26469706673582212202863e4706ef82faa6ad13fcf9e1ee1699e2008d0c74aa076910f6421a8bacd5b64736f6c63430008180033 + gas 1000000 + build + +# Create block to hold txDeployTestContract transaction +block_build b01 + parent g00 + transactions txDeployTestContract + gasLimit 1200000 + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute performTest function from contract +transaction_build txPerformTest + sender acc1 + nonce 1 + contract txDeployTestContract + value 0 + data 0d0b85f1 + gas 300000 + build + +# Create block to hold txPerformTest transaction +block_build b02 + parent b01 + transactions txPerformTest + gasLimit 350000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_and_tload_loop_until_out_of_gas.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_loop_until_out_of_gas.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_loop_until_out_of_gas.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_loop_until_out_of_gas.txt diff --git a/rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt similarity index 100% rename from rskj-core/src/test/resources/dsl/transaction_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt rename to rskj-core/src/test/resources/dsl/transient_storage_rskip446/tstore_wide_address_space_loop_until_out_of_gas.txt From 0209975b6da0881694c15d2c07faaeead18acfb8 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Tue, 17 Dec 2024 16:08:49 +0100 Subject: [PATCH 21/22] Added the scenario of tx execution inside same block - After have added a scenario of DSL test where two we check storage between transactions inside same block, we noticed a bug. This commit fixes it clearing the transient storage after the tx finishes. --- .../ethereum/core/TransactionExecutor.java | 2 + .../vm/opcode/TransientStorageDslTest.java | 38 +++++- .../eip1153_basic_tests.txt | 6 +- ...d_tstore_checking_between_transactions.txt | 116 ++++++++++++++++++ 4 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_tstore_checking_between_transactions.txt 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 b3f53e028ab..19846e9a92e 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -583,6 +583,8 @@ private void finalization() { // Traverse list of suicides result.getDeleteAccounts().forEach(address -> track.delete(new RskAddress(address))); + track.clearTransientStorage(); + logger.trace("tx listener done"); logger.trace("tx finalization done"); diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index 00502ca38d9..cca45ec1c36 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -541,7 +541,6 @@ void testTstoreAndTloadLoopUntilOutOfGas() throws FileNotFoundException, DslProc assertEquals(700000, txRunOutOfGas); // Assert that it consumed all the gas configured in the transaction } - @ParameterizedTest @MethodSource("provideParametersForSelfDestructCases") void testTstorageSelfDestructCases_OnEachTest_TheEventsEmittedAreTheExpected(String dslFile, Integer numberOfOksEmitted) throws FileNotFoundException, DslProcessorException { @@ -570,6 +569,43 @@ private static Stream provideParametersForSelfDestructCases() { ); } + @Test + void testTloadTstoreCheckingBetweenTransactions() throws FileNotFoundException, DslProcessorException { + DslParser parser = DslParser.fromResource("dsl/transient_storage_rskip446/tload_tstore_checking_between_transactions.txt"); + World world = new World(); + WorldDslProcessor processor = new WorldDslProcessor(world); + processor.processCommands(parser); + + String txTloadTstoreCheckingBetweenTransactionsContract = "txTloadTstoreCheckingBetweenTransactionsContract"; + assertTransactionReceiptWithStatus(world, txTloadTstoreCheckingBetweenTransactionsContract, "b01", true); + + String txTstoreAndTloadSomeValue = "txTstoreAndTloadSomeValue"; + Transaction txCreation = world.getTransactionByName(txTstoreAndTloadSomeValue); + assertNotNull(txCreation); + + Block block = world.getBlockByName("b02"); + assertEquals(2, block.getTransactionsList().size()); + + TransactionReceipt txReceipt = world.getTransactionReceiptByName(txTstoreAndTloadSomeValue); + assertNotNull(txReceipt); + byte[] status = txReceipt.getStatus(); + assertNotNull(status); + assertTrue(txReceipt.isSuccessful()); + + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "ValueStored", new String[]{"uint256","uint256"})); + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "ValueLoaded", new String[]{"uint256","uint256"})); + + String txTloadSomeValueAndCheckWithExpected = "txTloadSomeValueAndCheckWithExpected"; + TransactionReceipt txReceipt2 = world.getTransactionReceiptByName(txTloadSomeValueAndCheckWithExpected); + assertNotNull(txReceipt2); + status = txReceipt2.getStatus(); + assertNotNull(status); + assertTrue(txReceipt2.isSuccessful()); + + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt2, "ValueLoaded", new String[]{"uint256","uint256"})); + Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt2, "OK", null)); + } + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/eip1153_basic_tests.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/eip1153_basic_tests.txt index 3f5f30ac8a8..ab650a093bb 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/eip1153_basic_tests.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/eip1153_basic_tests.txt @@ -173,7 +173,7 @@ block_build b03 # Connect block block_connect b03 -# Check b02 is best block +# Check b03 is best block assert_best b03 # Create transaction to execute @@ -196,7 +196,7 @@ block_build b04 # Connect block block_connect b04 -# Check b02 is best block +# Check b04 is best block assert_best b04 # Create transaction to execute @@ -219,5 +219,5 @@ block_build b05 # Connect block block_connect b05 -# Check b02 is best block +# Check b05 is best block assert_best b05 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_tstore_checking_between_transactions.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_tstore_checking_between_transactions.txt new file mode 100644 index 00000000000..f71eb82d0a2 --- /dev/null +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/tload_tstore_checking_between_transactions.txt @@ -0,0 +1,116 @@ +comment + +// CONTRACT CODE +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +contract TloadTstoreCheckingBetweenTransactions { + constructor() { + } + + event OK(); + event ERROR(string, uint256); + event ValueStored(uint256 key, uint256 value); + event ValueLoaded(uint256 key, uint256 value); + + // Function to test TSTORE some value + function tstoreAndTloadSomeValue(uint256 key, uint256 value) external { + uint256 loadedValue; + assembly { + // Store a value in transient storage + tstore(key, value) + } + emit ValueStored(key, value); + + assembly { + // Load the value from transient storage + loadedValue := tload(key) + } + emit ValueLoaded(key, loadedValue); + } + + // Function to test TSTORE some value + function tloadSomeValueAndCheckWithExpected(uint256 key, uint256 valueExpected) external { + uint256 loadedValue; + assembly { + // Load the value from transient storage + loadedValue := tload(key) + } + emit ValueLoaded(key, loadedValue); + if (loadedValue == valueExpected) { + emit OK(); + } else { + emit ERROR('Value loaded is different from the expected',loadedValue); + } + } +} + +// CONTRACT BYTECODE + +TloadTstoreCheckingBetweenTransactions: 6080604052348015600e575f5ffd5b5061032f8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806398c051f414610038578063a042e69514610054575b5f5ffd5b610052600480360381019061004d91906101d9565b610070565b005b61006e600480360381019061006991906101d9565b6100ef565b005b5f81835d7f310f8ed862379d5c76886cc6d311ff93d07260f8609687c75d38a3916f469b5583836040516100a5929190610226565b60405180910390a1825c90507f9852f8e8d49fd9a2e49e060d8d3b08d73a4cad92444150877509d7ab57f2e5ef83826040516100e2929190610226565b60405180910390a1505050565b5f825c90507f9852f8e8d49fd9a2e49e060d8d3b08d73a4cad92444150877509d7ab57f2e5ef8382604051610125929190610226565b60405180910390a1818103610165577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161019d565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8160405161019491906102cd565b60405180910390a15b505050565b5f5ffd5b5f819050919050565b6101b8816101a6565b81146101c2575f5ffd5b50565b5f813590506101d3816101af565b92915050565b5f5f604083850312156101ef576101ee6101a2565b5b5f6101fc858286016101c5565b925050602061020d858286016101c5565b9150509250929050565b610220816101a6565b82525050565b5f6040820190506102395f830185610217565b6102466020830184610217565b9392505050565b5f82825260208201905092915050565b7f56616c7565206c6f6164656420697320646966666572656e742066726f6d20745f8201527f6865206578706563746564000000000000000000000000000000000000000000602082015250565b5f6102b7602b8361024d565b91506102c28261025d565b604082019050919050565b5f6040820190508181035f8301526102e4816102ab565b90506102f36020830184610217565b9291505056fea2646970667358221220433294a89265547198272c5831a9646c55777d997ff5f31e3d70a38fb431c2ea64736f6c634300081c0033 + +// CONTRACT CALLS + +TloadTstoreCheckingBetweenTransactions: + +- a042e695: tloadSomeValueAndCheckWithExpected(uint256,uint256) +- 98c051f4: tstoreAndTloadSomeValue(uint256,uint256) + +end + +# Create and fund new account +account_new acc1 10000000 + +# Create transaction to deploy TloadTstoreCheckingBetweenTransactions contract +transaction_build txTloadTstoreCheckingBetweenTransactionsContract + sender acc1 + receiverAddress 00 + value 0 + data 6080604052348015600e575f5ffd5b5061032f8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806398c051f414610038578063a042e69514610054575b5f5ffd5b610052600480360381019061004d91906101d9565b610070565b005b61006e600480360381019061006991906101d9565b6100ef565b005b5f81835d7f310f8ed862379d5c76886cc6d311ff93d07260f8609687c75d38a3916f469b5583836040516100a5929190610226565b60405180910390a1825c90507f9852f8e8d49fd9a2e49e060d8d3b08d73a4cad92444150877509d7ab57f2e5ef83826040516100e2929190610226565b60405180910390a1505050565b5f825c90507f9852f8e8d49fd9a2e49e060d8d3b08d73a4cad92444150877509d7ab57f2e5ef8382604051610125929190610226565b60405180910390a1818103610165577fd48fe2800bace8f5ca2450feacbd6efc681b1cd0115019bb49fa529b6171bf6760405160405180910390a161019d565b7fc9e730d5b570f89e168eb8c3d29f8c396b957e540af248c95c9519ac47c2c69f8160405161019491906102cd565b60405180910390a15b505050565b5f5ffd5b5f819050919050565b6101b8816101a6565b81146101c2575f5ffd5b50565b5f813590506101d3816101af565b92915050565b5f5f604083850312156101ef576101ee6101a2565b5b5f6101fc858286016101c5565b925050602061020d858286016101c5565b9150509250929050565b610220816101a6565b82525050565b5f6040820190506102395f830185610217565b6102466020830184610217565b9392505050565b5f82825260208201905092915050565b7f56616c7565206c6f6164656420697320646966666572656e742066726f6d20745f8201527f6865206578706563746564000000000000000000000000000000000000000000602082015250565b5f6102b7602b8361024d565b91506102c28261025d565b604082019050919050565b5f6040820190508181035f8301526102e4816102ab565b90506102f36020830184610217565b9291505056fea2646970667358221220433294a89265547198272c5831a9646c55777d997ff5f31e3d70a38fb431c2ea64736f6c634300081c0033 + gas 1000000 + build + +# Create block to hold txTloadTstoreCheckingBetweenTransactionsContract transaction +block_build b01 + parent g00 + transactions txTloadTstoreCheckingBetweenTransactionsContract + build + +# Connect block +block_connect b01 + +# Check b01 is best block +assert_best b01 + +# Create transaction to execute +transaction_build txTstoreAndTloadSomeValue + sender acc1 + nonce 1 + contract txTloadTstoreCheckingBetweenTransactionsContract + value 0 + data 98c051f400000000000000000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000000000000000000000000064 + gas 200000 + build + +# Create transaction to execute +transaction_build txTloadSomeValueAndCheckWithExpected + sender acc1 + nonce 2 + contract txTloadTstoreCheckingBetweenTransactionsContract + value 0 + data a042e69500000000000000000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000000000000000000000000000 + gas 200000 + build + +# Create block to hold txTloadSomeValueAndCheckWithExpected transaction +block_build b02 + parent b01 + transactions txTstoreAndTloadSomeValue txTloadSomeValueAndCheckWithExpected + gasLimit 500000 + build + +# Connect block +block_connect b02 + +# Check b02 is best block +assert_best b02 From adab6b3433286dbb6e8450ab1f71571f3be0bd15 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Fri, 20 Dec 2024 18:06:56 +0100 Subject: [PATCH 22/22] Refactor some test scenarios to not create new blocks after every new tx - In order to have a better validation of real use of TLOAD/TSTORE, we changed some DSL tests to not create a new block after every tx. This way, we validate that the transient storage it's correctly managed across the different tx. - Small refactor was added in the MutableTrie creation with a better name stating that we are creating an in memory trie. --- .../org/ethereum/db/MutableRepository.java | 12 ++-- .../vm/opcode/TransientStorageDslTest.java | 66 ++++++++----------- ...ctor_and_deploy_code_v0_create_context.txt | 25 ++----- .../dynamic_execution_context_simple.txt | 33 +++------- ...dynamic_execution_context_with_invalid.txt | 42 +++--------- .../dynamic_execution_context_with_revert.txt | 44 +++---------- ..._execution_context_with_stack_overflow.txt | 42 +++--------- ...before_revert_or_invalid_has_no_effect.txt | 40 ++--------- ...tructor_and_deploy_code_create_context.txt | 25 ++----- ...cy_context_tstore_after_reentrant_call.txt | 40 ++--------- 10 files changed, 97 insertions(+), 272 deletions(-) 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 0138b990d9c..f92bf4a9eee 100644 --- a/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java +++ b/rskj-core/src/main/java/org/ethereum/db/MutableRepository.java @@ -61,15 +61,19 @@ public class MutableRepository implements Repository { private final IReadWrittenKeysTracker tracker; public MutableRepository(TrieStore trieStore, Trie trie) { - this(new MutableTrieImpl(trieStore, trie), new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie())); + this(new MutableTrieImpl(trieStore, trie), aInMemoryMutableTrie()); } public MutableRepository(MutableTrie mutableTrie) { - this(mutableTrie, new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie())); + this(mutableTrie, aInMemoryMutableTrie()); } public MutableRepository(MutableTrie mutableTrie, IReadWrittenKeysTracker tracker) { - this(mutableTrie, new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie()), tracker); + this(mutableTrie, aInMemoryMutableTrie(), tracker); + } + + private static MutableTrieImpl aInMemoryMutableTrie() { + return new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie()); } public MutableRepository(MutableTrie mutableTrie, MutableTrie transientTrie) { @@ -452,7 +456,7 @@ public void addTransientStorageBytes(RskAddress addr, DataWord key, byte[] value @Override public void clearTransientStorage() { - this.transientTrie = new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie()); + this.transientTrie = aInMemoryMutableTrie(); } @Nullable diff --git a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java index cca45ec1c36..9bff2017b6b 100644 --- a/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java +++ b/rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageDslTest.java @@ -175,10 +175,10 @@ void testInConstructorAndCodeCreateContext() throws FileNotFoundException, DslPr processor.processCommands(parser); String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; - assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true, 2); String txInConstructorAndCode = "txInConstructorAndCode"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txInConstructorAndCode, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txInConstructorAndCode, "b01", true, 2); Assertions.assertEquals(6, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -190,10 +190,10 @@ void testAccrossConstructorAndCodeV0CreateContext() throws FileNotFoundException processor.processCommands(parser); String txTestTransientStorageCreateContextsContract = "txTestTransientStorageCreateContextsContract"; - assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true); + assertTransactionReceiptWithStatus(world, txTestTransientStorageCreateContextsContract, "b01", true, 2); String txAcrossConstructorAndCodeV0 = "txAcrossConstructorAndCodeV0"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txAcrossConstructorAndCodeV0, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txAcrossConstructorAndCodeV0, "b01", true, 2); Assertions.assertEquals(6, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -238,11 +238,11 @@ void testDynamicExecutionContextSimpleScenario() throws FileNotFoundException, D assertTransactionReceiptWithStatus(world, txCallAndDelegateCallSimpleTest, "b01", true); String txExecuteCallCode = "txExecuteCallCode"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true,2); Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteDelegateCall = "txExecuteDelegateCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b02", true, 2); Assertions.assertEquals(5, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -257,15 +257,15 @@ void testDynamicExecutionContextWithRevert() throws FileNotFoundException, DslPr assertTransactionReceiptWithStatus(world, txDynamicExecutionContextWithRevertTest, "b01", true); String txExecuteCallCode = "txExecuteCallCode"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteDelegateCall = "txExecuteDelegateCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteCall = "txExecuteCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b04", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -280,15 +280,15 @@ void testDynamicExecutionContextWithInvalid() throws FileNotFoundException, DslP assertTransactionReceiptWithStatus(world, txDynamicExecutionContextWithInvalidTest, "b01", true); String txExecuteCallCode = "txExecuteCallCode"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteDelegateCall = "txExecuteDelegateCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteCall = "txExecuteCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b04", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -303,15 +303,15 @@ void testDynamicExecutionContextWithStackOverflow() throws FileNotFoundException assertTransactionReceiptWithStatus(world, txDynamicExecutionContextWithStackOverflowTest, "b01", true); String txExecuteCallCode = "txExecuteCallCode"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCallCode, "b02", true,3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteDelegateCall = "txExecuteDelegateCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b03", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteDelegateCall, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txExecuteCall = "txExecuteCall"; - txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b04", true); + txReceipt = assertTransactionReceiptWithStatus(world, txExecuteCall, "b02", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -353,14 +353,14 @@ void testDynamicReentrancyContextsTstoreBeforeRevertOrInvalidHasNoEffect() throw processor.processCommands(parser); String txTstorageDynamicReentrancyContextContract = "txTstorageDynamicReentrancyContextContract"; - assertTransactionReceiptWithStatus(world, txTstorageDynamicReentrancyContextContract, "b01", true); + assertTransactionReceiptWithStatus(world, txTstorageDynamicReentrancyContextContract, "b01", true, 3); String txTestReentrantContextRevert = "txTestReentrantContextRevert"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTestReentrantContextRevert, "b02", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTestReentrantContextRevert, "b01", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); String txTestReentrantContextInvalid = "txTestReentrantContextInvalid"; - assertTransactionReceiptWithStatus(world, txTestReentrantContextInvalid, "b03", false); + assertTransactionReceiptWithStatus(world, txTestReentrantContextInvalid, "b01", false, 3); } @Test @@ -414,13 +414,13 @@ void testReentrancyContextsTstoreAfterReentrantCall() throws FileNotFoundExcepti processor.processCommands(parser); String txTstorageReentrancyContextTestContract = "txTstorageReentrancyContextTestContract"; - assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true); + assertTransactionReceiptWithStatus(world, txTstorageReentrancyContextTestContract, "b01", true, 3); String txTstoreInReentrantCall = "txTstoreInReentrantCall"; - assertTransactionReceiptWithStatus(world, txTstoreInReentrantCall, "b02", true); + assertTransactionReceiptWithStatus(world, txTstoreInReentrantCall, "b01", true, 3); String txCheckValuesStoredInTstorage = "txCheckValuesStoredInTstorage"; - TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b03", true); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txCheckValuesStoredInTstorage, "b01", true, 3); Assertions.assertEquals(3, TransactionReceiptUtil.getEventCount(txReceipt, "OK", null)); } @@ -580,38 +580,28 @@ void testTloadTstoreCheckingBetweenTransactions() throws FileNotFoundException, assertTransactionReceiptWithStatus(world, txTloadTstoreCheckingBetweenTransactionsContract, "b01", true); String txTstoreAndTloadSomeValue = "txTstoreAndTloadSomeValue"; - Transaction txCreation = world.getTransactionByName(txTstoreAndTloadSomeValue); - assertNotNull(txCreation); - - Block block = world.getBlockByName("b02"); - assertEquals(2, block.getTransactionsList().size()); - - TransactionReceipt txReceipt = world.getTransactionReceiptByName(txTstoreAndTloadSomeValue); - assertNotNull(txReceipt); - byte[] status = txReceipt.getStatus(); - assertNotNull(status); - assertTrue(txReceipt.isSuccessful()); + TransactionReceipt txReceipt = assertTransactionReceiptWithStatus(world, txTstoreAndTloadSomeValue, "b02", true, 2); Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "ValueStored", new String[]{"uint256","uint256"})); Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt, "ValueLoaded", new String[]{"uint256","uint256"})); String txTloadSomeValueAndCheckWithExpected = "txTloadSomeValueAndCheckWithExpected"; - TransactionReceipt txReceipt2 = world.getTransactionReceiptByName(txTloadSomeValueAndCheckWithExpected); - assertNotNull(txReceipt2); - status = txReceipt2.getStatus(); - assertNotNull(status); - assertTrue(txReceipt2.isSuccessful()); + TransactionReceipt txReceipt2 = assertTransactionReceiptWithStatus(world, txTloadSomeValueAndCheckWithExpected, "b02", true, 2); Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt2, "ValueLoaded", new String[]{"uint256","uint256"})); Assertions.assertEquals(1, TransactionReceiptUtil.getEventCount(txReceipt2, "OK", null)); } private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess) { + return assertTransactionReceiptWithStatus(world, txName, blockName, withSuccess, 1); + } + + private static TransactionReceipt assertTransactionReceiptWithStatus(World world, String txName, String blockName, boolean withSuccess, int numberOfTransactionsInBlock) { Transaction txCreation = world.getTransactionByName(txName); assertNotNull(txCreation); Block block = world.getBlockByName(blockName); - assertEquals(1, block.getTransactionsList().size()); + assertEquals(numberOfTransactionsInBlock, block.getTransactionsList().size()); TransactionReceipt txReceipt = world.getTransactionReceiptByName(txName); assertNotNull(txReceipt); diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt index a44ede8746c..d7be1e8d157 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/accross_constructor_and_deploy_code_v0_create_context.txt @@ -105,19 +105,6 @@ transaction_build txTestTransientStorageCreateContextsContract gas 1000000 build -# Create block to hold txTestTransientStorageCreateContextsContract transaction -block_build b01 - parent g00 - transactions txTestTransientStorageCreateContextsContract - gasLimit 1200000 - build - -# Connect block -block_connect b01 - -# Check b01 is best block -assert_best b01 - # Create transaction to execute txInConstructorAndCode transaction transaction_build txAcrossConstructorAndCodeV0 sender acc1 @@ -129,14 +116,14 @@ transaction_build txAcrossConstructorAndCodeV0 build # Create block to hold txAcrossConstructorAndCodeV0 transaction -block_build b02 - parent b01 - transactions txAcrossConstructorAndCodeV0 +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract txAcrossConstructorAndCodeV0 gasLimit 3000000 build # Connect block -block_connect b02 +block_connect b01 -# Check b02 is best block -assert_best b02 \ No newline at end of file +# Check b01 is best block +assert_best b01 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt index 36eac43363a..cdc4bf846ab 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_simple.txt @@ -107,22 +107,9 @@ transaction_build txExecuteCallCode contract txCallAndDelegateCallSimpleTest value 0 data a61face90000000000000000000000000000000000000000000000000000000000000001 - gas 1000000 - build - -# Create block to hold txExecuteCallCode transaction -block_build b02 - parent b01 - transactions txExecuteCallCode - gasLimit 2000000 + gas 300000 build -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - # Create transaction to execute txExecuteDelegateCall transaction transaction_build txExecuteDelegateCall sender acc1 @@ -130,18 +117,18 @@ transaction_build txExecuteDelegateCall contract txCallAndDelegateCallSimpleTest value 0 data a61face90000000000000000000000000000000000000000000000000000000000000000 - gas 1000000 + gas 300000 build -# Create block to hold txExecuteDelegateCall transaction -block_build b03 - parent b02 - transactions txExecuteDelegateCall - gasLimit 2000000 +# Create block to hold transactions +block_build b02 + parent b01 + transactions txExecuteCallCode txExecuteDelegateCall + gasLimit 1500000 build # Connect block -block_connect b03 +block_connect b02 -# Check b03 is best block -assert_best b03 \ No newline at end of file +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt index 96321e7ead6..6064b09506b 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_invalid.txt @@ -106,19 +106,6 @@ transaction_build txExecuteCallCode gas 500000 build -# Create block to hold txExecuteCallCode transaction -block_build b02 - parent b01 - transactions txExecuteCallCode - gasLimit 550000 - build - -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - # Create transaction to execute txExecuteDelegateCall transaction transaction_build txExecuteDelegateCall sender acc1 @@ -129,19 +116,6 @@ transaction_build txExecuteDelegateCall gas 500000 build -# Create block to hold txExecuteDelegateCall transaction -block_build b03 - parent b02 - transactions txExecuteDelegateCall - gasLimit 550000 - build - -# Connect block -block_connect b03 - -# Check b03 is best block -assert_best b03 - # Create transaction to execute txExecuteDelegateCall transaction transaction_build txExecuteCall sender acc1 @@ -152,15 +126,15 @@ transaction_build txExecuteCall gas 500000 build -# Create block to hold txExecuteCall transaction -block_build b04 - parent b03 - transactions txExecuteCall - gasLimit 550000 +# Create block to hold transactions +block_build b02 + parent b01 + transactions txExecuteCallCode txExecuteDelegateCall txExecuteCall + gasLimit 2000000 build # Connect block -block_connect b04 +block_connect b02 -# Check b04 is best block -assert_best b04 \ No newline at end of file +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt index 39ba6b71be9..05446336061 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_revert.txt @@ -106,19 +106,6 @@ transaction_build txExecuteCallCode gas 500000 build -# Create block to hold txExecuteCallCode transaction -block_build b02 - parent b01 - transactions txExecuteCallCode - gasLimit 550000 - build - -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - # Create transaction to execute txExecuteDelegateCall transaction transaction_build txExecuteDelegateCall sender acc1 @@ -129,20 +116,7 @@ transaction_build txExecuteDelegateCall gas 500000 build -# Create block to hold txExecuteDelegateCall transaction -block_build b03 - parent b02 - transactions txExecuteDelegateCall - gasLimit 550000 - build - -# Connect block -block_connect b03 - -# Check b03 is best block -assert_best b03 - -# Create transaction to execute txExecuteDelegateCall transaction +# Create transaction to execute txExecuteCall transaction transaction_build txExecuteCall sender acc1 nonce 3 @@ -152,15 +126,15 @@ transaction_build txExecuteCall gas 500000 build -# Create block to hold txExecuteCall transaction -block_build b04 - parent b03 - transactions txExecuteCall - gasLimit 550000 +# Create block to hold transactions +block_build b02 + parent b01 + transactions txExecuteCallCode txExecuteDelegateCall txExecuteCall + gasLimit 2000000 build # Connect block -block_connect b04 +block_connect b02 -# Check b04 is best block -assert_best b04 \ No newline at end of file +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt index 8b937302c20..040e7143202 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_execution_context_with_stack_overflow.txt @@ -113,19 +113,6 @@ transaction_build txExecuteCallCode gas 500000 build -# Create block to hold txExecuteCallCode transaction -block_build b02 - parent b01 - transactions txExecuteCallCode - gasLimit 550000 - build - -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - # Create transaction to execute txExecuteDelegateCall transaction transaction_build txExecuteDelegateCall sender acc1 @@ -136,19 +123,6 @@ transaction_build txExecuteDelegateCall gas 500000 build -# Create block to hold txExecuteDelegateCall transaction -block_build b03 - parent b02 - transactions txExecuteDelegateCall - gasLimit 550000 - build - -# Connect block -block_connect b03 - -# Check b03 is best block -assert_best b03 - # Create transaction to execute txExecuteDelegateCall transaction transaction_build txExecuteCall sender acc1 @@ -159,15 +133,15 @@ transaction_build txExecuteCall gas 500000 build -# Create block to hold txExecuteCall transaction -block_build b04 - parent b03 - transactions txExecuteCall - gasLimit 550000 +# Create block to hold transactions +block_build b02 + parent b01 + transactions txExecuteCallCode txExecuteDelegateCall txExecuteCall + gasLimit 2000000 build # Connect block -block_connect b04 +block_connect b02 -# Check b04 is best block -assert_best b04 \ No newline at end of file +# Check b02 is best block +assert_best b02 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt index 68e2c9996bf..8d784690e49 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/dynamic_reentrancy_context_tstore_before_revert_or_invalid_has_no_effect.txt @@ -84,19 +84,6 @@ transaction_build txTstorageDynamicReentrancyContextContract gas 1000000 build -# Create block to hold txTstorageDynamicReentrancyContextContract transaction -block_build b01 - parent g00 - transactions txTstorageDynamicReentrancyContextContract - gasLimit 1200000 - build - -# Connect block -block_connect b01 - -# Check b01 is best block -assert_best b01 - # Create transaction to execute txTestReentrantContextRevert transaction transaction_build txTestReentrantContextRevert sender acc1 @@ -107,19 +94,6 @@ transaction_build txTestReentrantContextRevert gas 300000 build -# Create block to hold txTestReentrantContextRevert transaction -block_build b02 - parent b01 - transactions txTestReentrantContextRevert - gasLimit 350000 - build - -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - # Create transaction to execute txTestReentrantContextInvalid transaction transaction_build txTestReentrantContextInvalid transaction sender acc1 @@ -131,14 +105,14 @@ transaction_build txTestReentrantContextInvalid transaction build # Create block to hold txTestReentrantContextInvalid transaction -block_build b03 - parent b02 - transactions txTestReentrantContextInvalid - gasLimit 1200000 +block_build b01 + parent g00 + transactions txTstorageDynamicReentrancyContextContract txTestReentrantContextRevert txTestReentrantContextInvalid + gasLimit 3000000 build # Connect block -block_connect b03 +block_connect b01 -# Check b03 is best block -assert_best b03 \ No newline at end of file +# Check b01 is best block +assert_best b01 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt index 75461e5b2f9..e8d276915bb 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/in_constructor_and_deploy_code_create_context.txt @@ -105,19 +105,6 @@ transaction_build txTestTransientStorageCreateContextsContract gas 1000000 build -# Create block to hold txTestTransientStorageCreateContextsContract transaction -block_build b01 - parent g00 - transactions txTestTransientStorageCreateContextsContract - gasLimit 1200000 - build - -# Connect block -block_connect b01 - -# Check b01 is best block -assert_best b01 - # Create transaction to execute txInConstructorAndCode transaction transaction_build txInConstructorAndCode sender acc1 @@ -129,14 +116,14 @@ transaction_build txInConstructorAndCode build # Create block to hold txInConstructorAndCode transaction -block_build b02 - parent b01 - transactions txInConstructorAndCode +block_build b01 + parent g00 + transactions txTestTransientStorageCreateContextsContract txInConstructorAndCode gasLimit 3000000 build # Connect block -block_connect b02 +block_connect b01 -# Check b02 is best block -assert_best b02 \ No newline at end of file +# Check b01 is best block +assert_best b01 \ No newline at end of file diff --git a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt index 9206a0fc715..eee111ba94c 100644 --- a/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt +++ b/rskj-core/src/test/resources/dsl/transient_storage_rskip446/reentrancy_context_tstore_after_reentrant_call.txt @@ -71,19 +71,6 @@ transaction_build txTstorageReentrancyContextTestContract gas 1000000 build -# Create block to hold txTstorageReentrancyContextTestContract transaction -block_build b01 - parent g00 - transactions txTstorageReentrancyContextTestContract - gasLimit 1200000 - build - -# Connect block -block_connect b01 - -# Check b01 is best block -assert_best b01 - # Create transaction to execute txTstoreInReentrantCall transaction transaction_build txTstoreInReentrantCall sender acc1 @@ -94,19 +81,6 @@ transaction_build txTstoreInReentrantCall gas 300000 build -# Create block to hold txTstoreInReentrantCall transaction -block_build b02 - parent b01 - transactions txTstoreInReentrantCall - gasLimit 350000 - build - -# Connect block -block_connect b02 - -# Check b02 is best block -assert_best b02 - # Create transaction to execute txCheckValuesStoredInTstorage transaction transaction_build txCheckValuesStoredInTstorage transaction sender acc1 @@ -118,14 +92,14 @@ transaction_build txCheckValuesStoredInTstorage transaction build # Create block to hold txCheckValuesStoredInTstorage transaction -block_build b03 - parent b02 - transactions txCheckValuesStoredInTstorage - gasLimit 350000 +block_build b01 + parent g00 + transactions txTstorageReentrancyContextTestContract txTstoreInReentrantCall txCheckValuesStoredInTstorage + gasLimit 3500000 build # Connect block -block_connect b03 +block_connect b01 -# Check b03 is best block -assert_best b03 \ No newline at end of file +# Check b01 is best block +assert_best b01 \ No newline at end of file