21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 | @pytest.mark.ported_from(
[
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/Cancun/stEIP1153-transientStorage/04_tloadAfterCallFiller.yml",
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/Cancun/stEIP1153-transientStorage/12_tloadDelegateCallFiller.yml",
],
pr=["https://github.com/ethereum/execution-spec-tests/pull/440"],
)
@pytest.mark.valid_from("Cancun")
@pytest.mark.parametrize("call_type", [Op.CALL, Op.CALLCODE, Op.DELEGATECALL])
def test_tload_calls(
state_test: StateTestFiller, pre: Alloc, call_type: Op
) -> None:
"""
Ported .json vectors.
(04_tloadAfterCallFiller.yml) Loading a slot after a call to another
contract is 0.
(12_tloadDelegateCallFiller.yml) delegatecall reads transient storage in
the context of the current address
"""
# Storage variables
slot_a_tload_after_subcall_result = 0
slot_a_subcall_result = 1
slot_b_subcall_tload_result = 2
slot_b_subcall_updated_tload_result = 3
def make_call(call_type: Op, address: Address) -> Bytecode:
if call_type == Op.DELEGATECALL or call_type == Op.STATICCALL:
return call_type(Op.GAS(), address, 0, 32, 0, 0)
else:
return call_type(Op.GAS(), address, 0, 0, 32, 0, 0)
address_call = pre.deploy_contract(
balance=1_000_000_000_000_000_000,
code=Op.JUMPDEST()
+ Op.SSTORE(slot_b_subcall_tload_result, Op.TLOAD(0))
+ Op.TSTORE(0, 20)
+ Op.SSTORE(slot_b_subcall_updated_tload_result, Op.TLOAD(0)),
storage={
slot_b_subcall_tload_result: 0xFF,
slot_b_subcall_updated_tload_result: 0xFF,
},
)
address_to = pre.deploy_contract(
balance=1_000_000_000_000_000_000,
code=Op.JUMPDEST()
+ Op.TSTORE(0, 10)
+ Op.SSTORE(slot_a_subcall_result, make_call(call_type, address_call))
+ Op.SSTORE(slot_a_tload_after_subcall_result, Op.TLOAD(0)),
storage={
slot_a_subcall_result: 0xFF,
slot_a_tload_after_subcall_result: 0xFF,
},
)
post = {
address_to: Account(
storage={
# other calls don't change context, therefore tload updated in
# this account
slot_a_tload_after_subcall_result: 10
if call_type == Op.CALL
else 20,
slot_a_subcall_result: 1,
# since context unchanged the subcall works as if continued
# execution
slot_b_subcall_tload_result: 0 if call_type == Op.CALL else 10,
slot_b_subcall_updated_tload_result: 0
if call_type == Op.CALL
else 20,
}
),
address_call: Account(
storage={
slot_b_subcall_tload_result: 0
if call_type == Op.CALL
else 0xFF,
slot_b_subcall_updated_tload_result: 20
if call_type == Op.CALL
else 0xFF,
}
),
}
tx = Transaction(
sender=pre.fund_eoa(7_000_000_000_000_000_000),
to=address_to,
gas_price=10,
data=b"",
gas_limit=5000000,
value=0,
)
state_test(env=Environment(), pre=pre, post=post, tx=tx)
|