From 61a3a2347c8fab4dee1276255154b5fc7fbd2525 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Mon, 11 Nov 2024 12:32:11 +0100 Subject: [PATCH 1/3] Added tests for dynamic execution contexts - WIP - Now we will add unit tests for underflow execution tests --- .../src/main/java/org/ethereum/vm/VM.java | 4 + .../vm/opcode/TransientStorageDslTest.java | 30 +++++ ...dynamic_execution_context_call_subcall.txt | 127 ++++++++++++++++++ ...text_staticcall_subcall_can_call_tload.txt | 105 +++++++++++++++ ...xt_staticcall_subcall_cant_call_tstore.txt | 106 +++++++++++++++ 5 files changed, 372 insertions(+) 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 ea19eb5f29..02d88476ed 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() && program.getActivations().isActive(RSKIP91)) { + 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 eb365c94ad..c6ad737821 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/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 0000000000..7d6f256c59 --- /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 0000000000..23ec7b497e --- /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 0000000000..4bc0112232 --- /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 79b166a98e4fd87acc62f916b29eda4344fcaca1 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Mon, 11 Nov 2024 12:32:11 +0100 Subject: [PATCH 2/3] 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 --- .../rsk/vm/opcode/TransientStorageTest.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java 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 0000000000..a033b4e190 --- /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; + } +} From d64cd9d4a1bfa428b87f110fc4e4182f6ba7eb52 Mon Sep 17 00:00:00 2001 From: frederico leal Date: Thu, 14 Nov 2024 14:55:01 +0100 Subject: [PATCH 3/3] Addressing review comments --- rskj-core/src/main/java/org/ethereum/vm/VM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 02d88476ed..0c4d3f999d 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -1361,7 +1361,7 @@ 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() && program.getActivations().isActive(RSKIP91)) { + if (program.isStaticCall()) { throw Program.ExceptionHelper.modificationException(program); }