diff --git a/tests/frontier/create/test_create_suicide_store.py b/tests/frontier/create/test_create_suicide_store.py new file mode 100644 index 00000000000..607c158a4b6 --- /dev/null +++ b/tests/frontier/create/test_create_suicide_store.py @@ -0,0 +1,158 @@ +""" +Test dynamically created address is still callable and perform storage operations +after being called for self destruct in a call. +""" + +from enum import Enum + +import pytest + +from ethereum_test_forks import Byzantium, Fork +from ethereum_test_tools import ( + Account, + Alloc, + Case, + Environment, + Initcode, + StateTestFiller, + Storage, + Switch, + Transaction, + compute_create_address, +) +from ethereum_test_tools import Opcodes as Op + + +class Operation(Enum): + """Enum for created contract actions.""" + + SUICIDE = 1 + ADD_STORAGE = 2 + GET_STORAGE = 3 + + def __int__(self): + """Convert to int.""" + return int(self.value) + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stCreateTest/CREATE_AcreateB_BSuicide_BStoreFiller.json", + ], + pr=["https://github.com/ethereum/execution-spec-tests/pull/1867"], + # coverage_missed_reason="Converting solidity code result in following opcode not being used:" + # "PUSH29, DUP4, DUP8, SWAP2, ISZERO, AND, MUL, DIV, CALLVALUE, EXTCODESIZE", +) +@pytest.mark.valid_from("Frontier") +@pytest.mark.with_all_create_opcodes +def test_create_suicide_store( + state_test: StateTestFiller, + fork: Fork, + pre: Alloc, + create_opcode: Op, +): + """ + Create dynamic contract that suicides, then called to push some storage + and then called to return that storage value. + """ + tload_support = fork.valid_opcodes().count(Op.TLOAD) + subcall_storage = 0x12 + suicide_initcode: Initcode = Initcode( + deploy_code=Switch( + cases=[ + Case( + condition=Op.EQ(Op.CALLDATALOAD(0), int(Operation.SUICIDE)), + action=Op.SELFDESTRUCT(0x11), + ), + Case( + condition=Op.EQ(Op.CALLDATALOAD(0), int(Operation.ADD_STORAGE)), + action=Op.SSTORE(1, Op.ADD(Op.SLOAD(1), subcall_storage)) + + ( + Op.TSTORE(1, Op.ADD(Op.TLOAD(1), subcall_storage)) + if tload_support + else Op.STOP + ), + ), + Case( + condition=Op.EQ(Op.CALLDATALOAD(0), int(Operation.GET_STORAGE)), + action=( + Op.MSTORE(0, Op.ADD(Op.SLOAD(1), Op.TLOAD(1))) + if tload_support + else Op.MSTORE(0, Op.SLOAD(1)) + ) + + Op.RETURN(0, 32), + ), + ], + default_action=None, + ) + ) + + sender = pre.fund_eoa() + expect_post = Storage() + + slot_create_result = 0 + slot_after_suicide_sstore_return = 1 + slot_program_success = 2 + create_contract = pre.deploy_contract( + code=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + + Op.SSTORE(slot_create_result, create_opcode(size=Op.CALLDATASIZE())) + # Put some storage before suicide + + Op.MSTORE(64, int(Operation.ADD_STORAGE)) + + Op.CALL( + gas=Op.SUB(Op.GAS, 300_000), + address=Op.SLOAD(slot_create_result), + args_offset=64, + args_size=32, + ) + + Op.MSTORE(64, int(Operation.SUICIDE)) + + Op.CALL( + gas=Op.SUB(Op.GAS, 300_000), + address=Op.SLOAD(slot_create_result), + args_offset=64, + args_size=32, + ) + # Put some storage after suicide + + Op.MSTORE(64, int(Operation.ADD_STORAGE)) + + Op.CALL( + gas=Op.SUB(Op.GAS, 300_000), + address=Op.SLOAD(slot_create_result), + args_offset=64, + args_size=32, + ) + + Op.MSTORE(64, int(Operation.GET_STORAGE)) + + Op.CALL( + gas=Op.SUB(Op.GAS, 300_000), + address=Op.SLOAD(0), + args_offset=64, + args_size=32, + ret_offset=100, + ret_size=32, + ) + + Op.SSTORE(slot_after_suicide_sstore_return, Op.MLOAD(100)) + + Op.SSTORE(slot_program_success, 1) + ) + + expected_create_address = compute_create_address( + address=create_contract, nonce=1, initcode=suicide_initcode, opcode=create_opcode + ) + expect_post[slot_create_result] = expected_create_address + expect_post[slot_after_suicide_sstore_return] = ( + subcall_storage * 2 # added value before and after suicide + + (subcall_storage * 2 if tload_support else 0) # tload value added + ) + expect_post[slot_program_success] = 1 + + tx = Transaction( + gas_limit=1_000_000, + to=create_contract, + data=suicide_initcode, + nonce=0, + sender=sender, + protected=fork >= Byzantium, + ) + + post = { + create_contract: Account(storage=expect_post), + expected_create_address: Account.NONEXISTENT, + } + state_test(env=Environment(), pre=pre, post=post, tx=tx) diff --git a/tests/static/state_tests/stCreateTest/CREATE_AcreateB_BSuicide_BStoreFiller.json b/tests/static/state_tests/stCreateTest/CREATE_AcreateB_BSuicide_BStoreFiller.json deleted file mode 100644 index 85bebceedc5..00000000000 --- a/tests/static/state_tests/stCreateTest/CREATE_AcreateB_BSuicide_BStoreFiller.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "CREATE_AcreateB_BSuicide_BStore" : { - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "0x020000", - "currentGasLimit" : "10000000", - "currentNumber" : "1", - "currentTimestamp" : "1000" - }, - "expect" : [ - { - "indexes" : { - "data" : -1, - "gas" : -1, - "value" : -1 - }, - "network" : [">=Cancun"], - "result" : { - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "storage" : { - "0x00" : "0x01", - "0x01" : "0x0c" - } - } - } - } - ], - "pre" : - { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000000000", - "code" : "", - "nonce" : "0", - "storage" : { - } - }, - "1000000000000000000000000000000000000000" : { - "balance" : "1", - "code" : "", - "nonce" : "0", - "storage" : { - } - }, - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000000000", - "//00 code" : "pragma solidity ^0.4.0; Better Make it with LLL", - "//01 code" : "contract CSuicide", - "//02 code" : "{", - "//03 code" : " uint v;", - "//04 code" : " function killitself()", - "//05 code" : " {", - "//06 code" : " suicide(0x11);", - "//07 code" : " }", - "//08 code" : " ", - "//09 code" : " function storesmth()", - "//0a code" : " {", - "//0b code" : " v = 12;", - "//0c code" : " }", - "//0d code" : " ", - "//0e code" : " function getsmth() returns(uint)", - "//0f code" : " {", - "//10 code" : " return v;", - "//11 code" : " }", - "//12 code" : "}", - "//13 code" : "", - "//14 code" : "contract CreateTest {", - "//15 code" : " uint res;", - "//16 code" : " uint resV;", - "//17 code" : " function run()", - "//18 code" : " {", - "//19 code" : " CSuicide a = new CSuicide();", - "//1a code" : " a.killitself();", - "//1b code" : " a.storesmth();", - "//1c code" : " resV = a.getsmth();", - "//1d code" : " res = 1;", - "//1e code" : " }", - "//1f code" : "}", - "//20 code" : "", - "code" : ":raw 0x60606040526000357c010000000000000000000000000000000000000000000000000000000090048063c04062261461003c57610037565b610002565b346100025761004e6004805050610050565b005b600060405160c9806101d3833901809050604051809103906000f080156100025790508073ffffffffffffffffffffffffffffffffffffffff166369bda7aa604051817c0100000000000000000000000000000000000000000000000000000000028152600401809050600060405180830381600087803b156100025760325a03f115610002575050508073ffffffffffffffffffffffffffffffffffffffff16633ac6dff3604051817c0100000000000000000000000000000000000000000000000000000000028152600401809050600060405180830381600087803b156100025760325a03f115610002575050508073ffffffffffffffffffffffffffffffffffffffff16636f118b2b600060405160200152604051817c0100000000000000000000000000000000000000000000000000000000028152600401809050602060405180830381600087803b156100025760325a03f115610002575050506040518051906020015060016000508190555060016000600050819055505b5056606060405260b98060106000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480633ac6dff314604d57806369bda7aa14605e5780636f118b2b14606f576049565b6002565b34600257605c60048050506094565b005b34600257606d600480505060a2565b005b34600257607e600480505060a8565b6040518082815260200191505060405180910390f35b600c6000600050819055505b565b6011ff5b565b6000600060005054905060b6565b9056", - "nonce" : "0", - "storage" : { - } - } - }, - "transaction" : { - "// data" : "run()", - "data" : [ - ":raw 0xc0406226" - ], - "gasLimit" : [ - "600000" - ], - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "value" : [ - "0" - ] - } - } -}