-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
502 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
""" | ||
Ethereum Transient Storage EIP Tests | ||
https://eips.ethereum.org/EIPS/eip-1153 | ||
""" | ||
|
||
from typing import Dict, Union | ||
|
||
import pytest | ||
|
||
from ethereum_test_tools import ( | ||
Account, | ||
Address, | ||
Environment, | ||
StateTestFiller, | ||
TestAddress, | ||
Transaction, | ||
) | ||
from ethereum_test_tools.vm.opcode import Opcodes as Op | ||
|
||
REFERENCE_SPEC_GIT_PATH = "EIPS/eip-1153.md" | ||
REFERENCE_SPEC_VERSION = "2f8299df31bb8173618901a03a8366a3183479b0" | ||
|
||
|
||
@pytest.mark.valid_from("Cancun") | ||
def test_basic_tload( | ||
state_test: StateTestFiller, | ||
): | ||
""" | ||
Covered .json vectors: | ||
(01_tloadBeginningTxnFiller.yml) | ||
load arbitrary value is 0 at beginning of transaction | ||
(02_tloadAfterTstoreFiller.yml) | ||
tload from same slot after tstore returns correct value | ||
(03_tloadAfterStoreIs0Filler.yml) | ||
Loading any other slot after storing to a slot returns 0. | ||
(16_tloadGasFiller.yml) | ||
tload costs 100 gas same as a warm sload | ||
(18_tloadAfterStoreFiller.yml) | ||
tload from same slot after store returns 0 | ||
""" | ||
|
||
address_to = Address("A00000000000000000000000000000000000000A") | ||
tload_at_transaction_begin_result = 1 | ||
|
||
tstore_value = 88 | ||
tload_after_tstore_result = 2 | ||
tload_after_tstore_result_second_time = 3 | ||
tload_wrong_after_tstore_result = 4 | ||
|
||
# N OPNAME GAS_COST TOTAL_GAS REMAINING_GAS STACK | ||
# 28-1 MSTORE 2 20748 4958252 2:[4ba82f,0,] | ||
# MSTORE [0] = 4958255 | ||
# 29-1 PUSH1 3 20754 4958246 | ||
# 30-1 TLOAD 100 20757 4958243 1:[10,] | ||
# 31-1 GAS 2 20857 4958143 1:[2,] | ||
# 32-1 PUSH1 3 20859 4958141 2:[2,4ba7bd,] | ||
# 33-1 MSTORE 6 20862 4958138 3:[2,4ba7bd,20,] | ||
# MSTORE [32] = 4958141 | ||
extra_opcode_gas = 11 # mstore(3), push1(3),gas(2),push1(3) | ||
|
||
tload_nonzero_gas_price_result = 16 | ||
tload_zero_gas_price_result = 1601 | ||
|
||
tload_from_sstore_result = 18 | ||
|
||
pre = { | ||
address_to: Account( | ||
balance=1000000000000000000, | ||
nonce=0, | ||
code=Op.JUMPDEST() | ||
# 01_tloadBeginningTxnFiller.yml | ||
+ Op.SSTORE(tload_at_transaction_begin_result, Op.TLOAD(0)) | ||
# 02_tloadAfterTstoreFiller.yml | ||
+ Op.TSTORE(2, tstore_value) | ||
+ Op.SSTORE(tload_after_tstore_result, Op.TLOAD(2)) | ||
+ Op.SSTORE(tload_after_tstore_result_second_time, Op.TLOAD(2)) | ||
# 03_tloadAfterStoreIs0Filler.yml | ||
+ Op.TSTORE(3, tstore_value) + Op.SSTORE(tload_wrong_after_tstore_result, Op.TLOAD(0)) | ||
# 16_tloadGasFiller.yml calculate tload gas | ||
+ Op.TSTORE(16, 2) | ||
+ Op.MSTORE(0, Op.GAS()) # hot load the memory | ||
+ Op.MSTORE(0, Op.GAS()) | ||
+ Op.TLOAD(16) | ||
+ Op.MSTORE(32, Op.GAS()) | ||
+ Op.SSTORE(tload_nonzero_gas_price_result, Op.SUB(Op.MLOAD(0), Op.MLOAD(32))) | ||
+ Op.SSTORE(tload_nonzero_gas_price_result, Op.SUB(Op.SLOAD(16), extra_opcode_gas)) | ||
# from zero slot | ||
+ Op.MSTORE(0, Op.GAS()) | ||
+ Op.TLOAD(5) | ||
+ Op.MSTORE(32, Op.GAS()) | ||
+ Op.SSTORE(tload_zero_gas_price_result, Op.SUB(Op.MLOAD(0), Op.MLOAD(32))) | ||
+ Op.SSTORE(tload_zero_gas_price_result, Op.SUB(Op.SLOAD(1601), extra_opcode_gas)) | ||
# 18_tloadAfterStoreFiller.yml | ||
+ Op.SSTORE(18, 22) + Op.SSTORE(tload_from_sstore_result, Op.TLOAD(18)), | ||
storage={ | ||
tload_at_transaction_begin_result: 0xFF, | ||
tload_after_tstore_result: 0xFF, | ||
tload_after_tstore_result_second_time: 0xFF, | ||
tload_wrong_after_tstore_result: 0xFF, | ||
tload_nonzero_gas_price_result: 0xFF, | ||
tload_zero_gas_price_result: 0xFF, | ||
tload_from_sstore_result: 0xFF, | ||
}, | ||
), | ||
TestAddress: Account( | ||
balance=7000000000000000000, | ||
nonce=0, | ||
code="0x", | ||
storage={}, | ||
), | ||
} | ||
|
||
post: Dict[Address, Union[Account, object]] = {} | ||
|
||
post[address_to] = Account( | ||
storage={ | ||
tload_at_transaction_begin_result: 0x00, | ||
tload_after_tstore_result: tstore_value, | ||
tload_after_tstore_result_second_time: tstore_value, | ||
tload_wrong_after_tstore_result: 0x00, | ||
tload_nonzero_gas_price_result: 100, | ||
tload_zero_gas_price_result: 100, | ||
tload_from_sstore_result: 0x00, | ||
} | ||
) | ||
|
||
tx = Transaction( | ||
nonce=0, | ||
to=address_to, | ||
gas_price=10, | ||
data=b"", | ||
gas_limit=5000000, | ||
value=0, | ||
) | ||
|
||
state_test(env=Environment(), pre=pre, post=post, tx=tx) |
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,108 @@ | ||
""" | ||
Ethereum Transient Storage EIP Tests | ||
https://eips.ethereum.org/EIPS/eip-1153 | ||
""" | ||
|
||
from typing import Dict, Union | ||
|
||
import pytest | ||
|
||
from ethereum_test_tools import ( | ||
Account, | ||
Address, | ||
Environment, | ||
StateTestFiller, | ||
TestAddress, | ||
Transaction, | ||
) | ||
from ethereum_test_tools.vm.opcode import Opcodes as Op | ||
|
||
REFERENCE_SPEC_GIT_PATH = "EIPS/eip-1153.md" | ||
REFERENCE_SPEC_VERSION = "2f8299df31bb8173618901a03a8366a3183479b0" | ||
|
||
|
||
@pytest.mark.valid_from("Cancun") | ||
@pytest.mark.parametrize("call_type", [Op.CALL, Op.CALLCODE, Op.DELEGATECALL]) | ||
def test_tload_calls(state_test: StateTestFiller, call_type: Op): | ||
""" | ||
Covered .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 | ||
""" | ||
|
||
address_to = Address("A00000000000000000000000000000000000000A") | ||
address_call = Address("B00000000000000000000000000000000000000B") | ||
|
||
# Storages | ||
str_a_tload_after_subcall_result = 0 | ||
str_a_subcall_result = 1 | ||
str_b_subcall_tload_result = 2 | ||
str_b_subcall_updated_tload_result = 3 | ||
|
||
pre = { | ||
address_to: Account( | ||
balance=1000000000000000000, | ||
nonce=0, | ||
code=Op.JUMPDEST() | ||
+ Op.TSTORE(0, 10) | ||
+ Op.SSTORE(str_a_subcall_result, call_type(Op.GAS(), address_call, 0, 0, 32, 0, 0)) | ||
+ Op.SSTORE(str_a_tload_after_subcall_result, Op.TLOAD(0)), | ||
storage={ | ||
str_a_subcall_result: 0xFF, | ||
str_a_tload_after_subcall_result: 0xFF, | ||
}, | ||
), | ||
address_call: Account( | ||
balance=7000000000000000000, | ||
nonce=0, | ||
code=Op.JUMPDEST() | ||
+ Op.SSTORE(str_b_subcall_tload_result, Op.TLOAD(0)) | ||
+ Op.TSTORE(0, 20) | ||
+ Op.SSTORE(str_b_subcall_updated_tload_result, Op.TLOAD(0)), | ||
storage={ | ||
str_b_subcall_tload_result: 0xFF, | ||
str_b_subcall_updated_tload_result: 0xFF, | ||
}, | ||
), | ||
TestAddress: Account( | ||
balance=7000000000000000000, | ||
nonce=0, | ||
code="0x", | ||
storage={}, | ||
), | ||
} | ||
|
||
post: Dict[Address, Union[Account, object]] = {} | ||
|
||
post[address_to] = Account( | ||
storage={ | ||
# other calls don't change context, there for tload updated in this account | ||
str_a_tload_after_subcall_result: 10 if call_type == Op.CALL else 20, | ||
str_a_subcall_result: 1, | ||
# since context unchanged the subcall works as if continued execution | ||
str_b_subcall_tload_result: 0 if call_type == Op.CALL else 10, | ||
str_b_subcall_updated_tload_result: 0 if call_type == Op.CALL else 20, | ||
} | ||
) | ||
|
||
post[address_call] = Account( | ||
storage={ | ||
str_b_subcall_tload_result: 0 if call_type == Op.CALL else 0xFF, | ||
str_b_subcall_updated_tload_result: 20 if call_type == Op.CALL else 0xFF, | ||
} | ||
) | ||
|
||
tx = Transaction( | ||
nonce=0, | ||
to=address_to, | ||
gas_price=10, | ||
data=b"", | ||
gas_limit=5000000, | ||
value=0, | ||
) | ||
|
||
state_test(env=Environment(), pre=pre, post=post, tx=tx) |
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,112 @@ | ||
""" | ||
Ethereum Transient Storage EIP Tests | ||
https://eips.ethereum.org/EIPS/eip-1153 | ||
""" | ||
|
||
from typing import Dict, Union | ||
|
||
import pytest | ||
|
||
from ethereum_test_tools import ( | ||
Account, | ||
Address, | ||
Case, | ||
Environment, | ||
Hash, | ||
StateTestFiller, | ||
Switch, | ||
TestAddress, | ||
Transaction, | ||
) | ||
from ethereum_test_tools.vm.opcode import Opcodes as Op | ||
|
||
REFERENCE_SPEC_GIT_PATH = "EIPS/eip-1153.md" | ||
REFERENCE_SPEC_VERSION = "2f8299df31bb8173618901a03a8366a3183479b0" | ||
|
||
|
||
@pytest.mark.valid_from("Cancun") | ||
@pytest.mark.parametrize("call_type", [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL]) | ||
@pytest.mark.parametrize("call_return", [Op.RETURN, Op.REVERT, Op.OOG]) | ||
def test_tload_reentrancy(state_test: StateTestFiller, call_type: Op, call_return: Op): | ||
""" | ||
Covered .json vectors: | ||
(05_tloadReentrancyFiller.yml) | ||
Reentrant calls access the same transient storage | ||
""" | ||
|
||
address_to = Address("A00000000000000000000000000000000000000A") | ||
|
||
# Storages | ||
str_tload_in_reentrancy_result = 1 | ||
str_tload_after_reentrancy_result = 2 | ||
str_reentrancy_call_worked = 3 | ||
|
||
# Function names | ||
do_load = 1 | ||
do_reenter = 2 | ||
|
||
def make_call(call_type: Op) -> bytes: | ||
if call_type == Op.DELEGATECALL or call_type == Op.STATICCALL: | ||
return call_type(Op.GAS(), Op.ADDRESS(), 0, 32, 32, 32) | ||
else: | ||
return call_type(Op.GAS(), Op.ADDRESS(), 0, 0, 32, 32, 32) | ||
|
||
pre = { | ||
address_to: Account( | ||
balance=1000000000000000000, | ||
nonce=0, | ||
code=Switch( | ||
cases=[ | ||
Case( | ||
condition=Op.EQ(Op.CALLDATALOAD(0), do_load), | ||
action=Op.MSTORE(0, Op.TLOAD(0)) + call_return(0, 32), | ||
), | ||
Case( | ||
condition=Op.EQ(Op.CALLDATALOAD(0), do_reenter), | ||
action=Op.TSTORE(0, 44) | ||
+ Op.MSTORE(0, do_load) + Op.MSTORE(32, 0xFF) | ||
+ Op.SSTORE(str_reentrancy_call_worked, make_call(call_type)) | ||
+ Op.SSTORE(str_tload_in_reentrancy_result, Op.MLOAD(32)) | ||
+ Op.SSTORE(str_tload_after_reentrancy_result, Op.TLOAD(0)), | ||
), | ||
], | ||
default_action=b"", | ||
), | ||
storage={ | ||
str_tload_in_reentrancy_result: 0xFF, | ||
str_tload_after_reentrancy_result: 0xFF, | ||
str_reentrancy_call_worked: 0xFF, | ||
}, | ||
), | ||
TestAddress: Account( | ||
balance=7000000000000000000, | ||
nonce=0, | ||
code="0x", | ||
storage={}, | ||
), | ||
} | ||
|
||
post: Dict[Address, Union[Account, object]] = {} | ||
|
||
post[address_to] = Account( | ||
storage={ | ||
# if call OOG, we fail to obtain the result | ||
str_tload_in_reentrancy_result: 0xFF if call_return == Op.OOG else 44, | ||
str_tload_after_reentrancy_result: 44, | ||
str_reentrancy_call_worked: ( | ||
0 if call_return == Op.REVERT or call_return == Op.OOG else 1 | ||
), | ||
} | ||
) | ||
|
||
tx = Transaction( | ||
nonce=0, | ||
to=address_to, | ||
gas_price=10, | ||
data=Hash(do_reenter), | ||
gas_limit=5000000, | ||
value=0, | ||
) | ||
|
||
state_test(env=Environment(), pre=pre, post=post, tx=tx) |
Oops, something went wrong.