Skip to content

Commit

Permalink
oog
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed Mar 11, 2024
1 parent 24ded3e commit df6bc6b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 22 deletions.
17 changes: 10 additions & 7 deletions src/ethereum_test_tools/vm/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def __new__(
"""
Creates a new opcode instance.
"""
if type(opcode_or_byte) is Opcode:
if type(opcode_or_byte) is Opcode or type(opcode_or_byte) is Macro:
# Required because Enum class calls the base class with the instantiated object as
# parameter.
return opcode_or_byte
Expand All @@ -73,7 +73,7 @@ def __new__(
obj.min_stack_height = min_stack_height
obj.data_portion_length = data_portion_length
return obj
assert False
raise TypeError("Opcode constructor '__new__' didn't return an instance!")

def __call__(self, *args_t: Union[int, bytes, str, "Opcode", FixedSizeBytes]) -> bytes:
"""
Expand Down Expand Up @@ -4582,8 +4582,8 @@ class Opcodes(Opcode, Enum):
Inputs
----
- value: value in wei to send to the new account
- offset: byte offset in the memory in bytes, the initialisation code for the new account
- size: byte size to copy (size of the initialisation code)
- offset: byte offset in the memory in bytes, the initialization code for the new account
- size: byte size to copy (size of the initialization code)
Outputs
----
Expand Down Expand Up @@ -4769,8 +4769,8 @@ class Opcodes(Opcode, Enum):
Inputs
----
- value: value in wei to send to the new account
- offset: byte offset in the memory in bytes, the initialisation code of the new account
- size: byte size to copy (size of the initialisation code)
- offset: byte offset in the memory in bytes, the initialization code of the new account
- size: byte size to copy (size of the initialization code)
- salt: 32-byte value used to create the new account at a deterministic address
Outputs
Expand Down Expand Up @@ -4928,6 +4928,9 @@ class Opcodes(Opcode, Enum):
Gas
----
This operation will result in gasprice = 19073514453125027
Add a little more and geth report gasprice = 30 with oog exception
Make it 0 - 1 and geth report gasprice > u64 error
Source: SHA3(0, 100000000000)
"""
21 changes: 16 additions & 5 deletions tests/cancun/eip1153_tstore/test_tload_reentrancy.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ def test_tload_reentrancy(
"""

address_to = Address("A00000000000000000000000000000000000000A")
tload_value = 44
empty_value = 0

# Storages
str_tload_in_subcall_result = 1
str_tload_after_subcall_result = 2
str_subcall_worked = 3
str_code_worked = 4

# Function names
do_load = 1
Expand All @@ -70,12 +73,13 @@ def make_call(call_type: Op) -> bytes:
),
Case(
condition=Op.EQ(Op.CALLDATALOAD(0), do_reenter),
action=Op.TSTORE(0, 44)
action=Op.TSTORE(0, tload_value)
+ Op.MSTORE(0, do_load)
+ Op.MSTORE(32, 0xFF)
+ Op.SSTORE(str_subcall_worked, make_call(call_type))
+ Op.SSTORE(str_tload_in_subcall_result, Op.MLOAD(32))
+ Op.SSTORE(str_tload_after_subcall_result, Op.TLOAD(0)),
+ Op.SSTORE(str_tload_after_subcall_result, Op.TLOAD(0))
+ Op.SSTORE(str_code_worked, 1),
),
],
default_action=b"",
Expand All @@ -84,6 +88,7 @@ def make_call(call_type: Op) -> bytes:
str_tload_in_subcall_result: 0xFF,
str_tload_after_subcall_result: 0xFF,
str_subcall_worked: 0xFF,
str_code_worked: 0xFF,
},
),
address_code: Account(
Expand All @@ -106,9 +111,10 @@ def make_call(call_type: Op) -> bytes:
# if reentrancy
post[address_to] = Account(
storage={
str_code_worked: 1,
# if call OOG, we fail to obtain the result
str_tload_in_subcall_result: 0xFF if call_return == Op.OOG else 44,
str_tload_after_subcall_result: 44,
str_tload_in_subcall_result: 0xFF if call_return == Op.OOG else tload_value,
str_tload_after_subcall_result: tload_value,
str_subcall_worked: (
0 if call_return == Op.REVERT or call_return == Op.OOG else 1
),
Expand All @@ -118,11 +124,16 @@ def make_call(call_type: Op) -> bytes:
# if external call
post[address_to] = Account(
storage={
str_code_worked: 1,
str_tload_in_subcall_result: (
0xFF # if call OOG, we fail to obtain the result
if call_return == Op.OOG
# else delegate and callcode are working in the same context so tload works
else 44 if call_type == Op.DELEGATECALL or call_type == Op.CALLCODE else 0
else (
tload_value
if call_type == Op.DELEGATECALL or call_type == Op.CALLCODE
else empty_value
)
),
# no subcall errors can change the tload result
str_tload_after_subcall_result: 44,
Expand Down
45 changes: 35 additions & 10 deletions tests/cancun/eip1153_tstore/test_tstore_reentrancy.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,27 @@ def test_tstore_reentrancy(
(09_revertUndoesAllFiller.yml)
Revert undoes all the transient storage writes to the same key from the failed call.
(11_tstoreDelegateCallFiller.yml)
delegatecall manipulates transient storage in the context of the current address.
(13_tloadStaticCallFiller.yml)
Transient storage cannot be manipulated in a static context, tstore reverts
(20_oogUndoesTransientStoreInCallFiller.yml)
Out of gas undoes the transient storage writes from a call.
"""
address_to = Address("A00000000000000000000000000000000000000A")
tload_value_set_before_call = 80
tload_value_set_in_call = 90

# Storages
# Storage cells
str_tload_before_call = 0
str_tload_in_subcall_result = 1
str_tload_after_call = 2
str_subcall_worked = 3
str_tload_1_after_call = 4
str_tstore_overwrite = 5
str_code_worked = 6

# Function names
do_tstore = 1
Expand All @@ -71,7 +81,7 @@ def make_call(call_type: Op) -> bytes:

subcall_code = (
Op.TSTORE(0, 89)
+ Op.TSTORE(0, 90)
+ Op.TSTORE(0, tload_value_set_in_call)
+ Op.TSTORE(1, 11)
+ Op.TSTORE(1, 12)
+ Op.MSTORE(0, Op.TLOAD(0))
Expand All @@ -90,14 +100,17 @@ def make_call(call_type: Op) -> bytes:
),
Case(
condition=Op.EQ(Op.CALLDATALOAD(0), do_reenter),
action=Op.TSTORE(0, 80)
action=Op.TSTORE(0, tload_value_set_before_call)
+ Op.SSTORE(str_tload_before_call, Op.TLOAD(0))
+ Op.MSTORE(0, do_tstore)
+ Op.MSTORE(32, 0xFF)
+ Op.SSTORE(str_subcall_worked, make_call(call_type))
+ Op.SSTORE(str_tload_in_subcall_result, Op.MLOAD(32))
+ Op.SSTORE(str_tload_after_call, Op.TLOAD(0))
+ Op.SSTORE(str_tload_1_after_call, Op.TLOAD(1)),
+ Op.SSTORE(str_tload_1_after_call, Op.TLOAD(1))
+ Op.TSTORE(0, 50)
+ Op.SSTORE(str_tstore_overwrite, Op.TLOAD(0))
+ Op.SSTORE(str_code_worked, 1),
),
],
default_action=b"",
Expand All @@ -108,6 +121,8 @@ def make_call(call_type: Op) -> bytes:
str_tload_after_call: 0xFF,
str_subcall_worked: 0xFF,
str_tload_1_after_call: 0xFF,
str_tstore_overwrite: 0xFF,
str_code_worked: 0xFF,
},
),
address_code: Account(
Expand Down Expand Up @@ -140,16 +155,20 @@ def successful_delegate_or_callcode() -> bool:
# if reentrancy
post[address_to] = Account(
storage={
str_tload_before_call: 80,
str_code_worked: 1,
str_tload_before_call: tload_value_set_before_call,
str_tload_in_subcall_result: (
# we fail to obtain in call result if it fails
0xFF
if call_type == Op.STATICCALL or call_return == Op.OOG
else 90
else tload_value_set_in_call
),
# reentrant tstore overrides value in upper level
str_tload_after_call: 80 if failing_calls() else 90,
str_tload_after_call: (
tload_value_set_before_call if failing_calls() else tload_value_set_in_call
),
str_tload_1_after_call: 0 if failing_calls() else 12,
str_tstore_overwrite: 50,
# tstore in static call not allowed
str_subcall_worked: 0 if failing_calls() else 1,
}
Expand All @@ -158,16 +177,22 @@ def successful_delegate_or_callcode() -> bool:
post[address_to] = Account(
# if external call
storage={
str_tload_before_call: 80,
str_code_worked: 1,
str_tload_before_call: tload_value_set_before_call,
str_tload_in_subcall_result: (
# we fail to obtain in call result if it fails
0xFF
if call_type == Op.STATICCALL or call_return == Op.OOG
else 90
else tload_value_set_in_call
),
# external tstore overrides value in upper level only in delegate and callcode
str_tload_after_call: 90 if successful_delegate_or_callcode() else 80,
str_tload_after_call: (
tload_value_set_in_call
if successful_delegate_or_callcode()
else tload_value_set_before_call
),
str_tload_1_after_call: 12 if successful_delegate_or_callcode() else 0,
str_tstore_overwrite: 50,
# tstore in static call not allowed, reentrancy means external call here
str_subcall_worked: 0 if failing_calls() else 1,
}
Expand Down
1 change: 1 addition & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ div
sdiv
mod
smod
smlxl
addmod
mulmod
exp
Expand Down

0 comments on commit df6bc6b

Please sign in to comment.