-
Notifications
You must be signed in to change notification settings - Fork 267
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
6 changed files
with
523 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
rskj-core/src/test/java/co/rsk/vm/opcode/TransientStorageTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* This file is part of RskJ | ||
* Copyright (C) 2024 RSK Labs Ltd. | ||
* (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>) | ||
* | ||
* 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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
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"; | ||
Check notice Code scanning / CodeQL Unread local variable Note test
Variable 'String expected' is never read.
|
||
|
||
//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; | ||
} | ||
} |
127 changes: 127 additions & 0 deletions
127
...est/resources/dsl/transaction_storage_rskip446/dynamic_execution_context_call_subcall.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.