From 7b15c686fab3eb532671e59e01377db1bd4e8195 Mon Sep 17 00:00:00 2001 From: Guruprasad Kamath Date: Sat, 7 Sep 2024 17:04:40 +0200 Subject: [PATCH] Implement EIP-7610 --- src/ethereum/arrow_glacier/state.py | 21 ++++++++++++++++++- .../arrow_glacier/vm/instructions/system.py | 5 ++++- src/ethereum/arrow_glacier/vm/interpreter.py | 3 ++- src/ethereum/berlin/state.py | 21 ++++++++++++++++++- src/ethereum/berlin/vm/instructions/system.py | 5 ++++- src/ethereum/berlin/vm/interpreter.py | 3 ++- src/ethereum/byzantium/state.py | 21 ++++++++++++++++++- .../byzantium/vm/instructions/system.py | 5 ++++- src/ethereum/byzantium/vm/interpreter.py | 3 ++- src/ethereum/cancun/state.py | 21 ++++++++++++++++++- src/ethereum/cancun/vm/instructions/system.py | 5 ++++- src/ethereum/cancun/vm/interpreter.py | 3 ++- src/ethereum/constantinople/state.py | 21 ++++++++++++++++++- .../constantinople/vm/instructions/system.py | 5 ++++- src/ethereum/constantinople/vm/interpreter.py | 3 ++- src/ethereum/dao_fork/state.py | 21 ++++++++++++++++++- .../dao_fork/vm/instructions/system.py | 5 ++++- src/ethereum/dao_fork/vm/interpreter.py | 3 ++- src/ethereum/frontier/state.py | 21 ++++++++++++++++++- .../frontier/vm/instructions/system.py | 5 ++++- src/ethereum/frontier/vm/interpreter.py | 3 ++- src/ethereum/gray_glacier/state.py | 21 ++++++++++++++++++- .../gray_glacier/vm/instructions/system.py | 5 ++++- src/ethereum/gray_glacier/vm/interpreter.py | 3 ++- src/ethereum/homestead/state.py | 21 ++++++++++++++++++- .../homestead/vm/instructions/system.py | 5 ++++- src/ethereum/homestead/vm/interpreter.py | 3 ++- src/ethereum/istanbul/state.py | 21 ++++++++++++++++++- .../istanbul/vm/instructions/system.py | 5 ++++- src/ethereum/istanbul/vm/interpreter.py | 3 ++- src/ethereum/london/state.py | 21 ++++++++++++++++++- src/ethereum/london/vm/instructions/system.py | 5 ++++- src/ethereum/london/vm/interpreter.py | 3 ++- src/ethereum/muir_glacier/state.py | 21 ++++++++++++++++++- .../muir_glacier/vm/instructions/system.py | 5 ++++- src/ethereum/muir_glacier/vm/interpreter.py | 3 ++- src/ethereum/paris/state.py | 21 ++++++++++++++++++- src/ethereum/paris/vm/instructions/system.py | 5 ++++- src/ethereum/paris/vm/interpreter.py | 3 ++- src/ethereum/prague/state.py | 21 ++++++++++++++++++- src/ethereum/prague/vm/instructions/system.py | 5 ++++- src/ethereum/prague/vm/interpreter.py | 3 ++- src/ethereum/shanghai/state.py | 21 ++++++++++++++++++- .../shanghai/vm/instructions/system.py | 5 ++++- src/ethereum/shanghai/vm/interpreter.py | 3 ++- src/ethereum/spurious_dragon/state.py | 21 ++++++++++++++++++- .../spurious_dragon/vm/instructions/system.py | 5 ++++- .../spurious_dragon/vm/interpreter.py | 3 ++- src/ethereum/tangerine_whistle/state.py | 21 ++++++++++++++++++- .../vm/instructions/system.py | 5 ++++- .../tangerine_whistle/vm/interpreter.py | 3 ++- tests/helpers/__init__.py | 2 +- 52 files changed, 443 insertions(+), 52 deletions(-) diff --git a/src/ethereum/arrow_glacier/state.py b/src/ethereum/arrow_glacier/state.py index 801fa16657..35245a97be 100644 --- a/src/ethereum/arrow_glacier/state.py +++ b/src/ethereum/arrow_glacier/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/arrow_glacier/vm/instructions/system.py b/src/ethereum/arrow_glacier/vm/instructions/system.py index 986b091c52..500c5e994a 100644 --- a/src/ethereum/arrow_glacier/vm/instructions/system.py +++ b/src/ethereum/arrow_glacier/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -88,7 +89,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/arrow_glacier/vm/interpreter.py b/src/ethereum/arrow_glacier/vm/interpreter.py index 18c81996b5..8f01a64588 100644 --- a/src/ethereum/arrow_glacier/vm/interpreter.py +++ b/src/ethereum/arrow_glacier/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -107,7 +108,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/berlin/state.py b/src/ethereum/berlin/state.py index 801fa16657..35245a97be 100644 --- a/src/ethereum/berlin/state.py +++ b/src/ethereum/berlin/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/berlin/vm/instructions/system.py b/src/ethereum/berlin/vm/instructions/system.py index 168f6ef7b7..5d190d24b6 100644 --- a/src/ethereum/berlin/vm/instructions/system.py +++ b/src/ethereum/berlin/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -89,7 +90,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/berlin/vm/interpreter.py b/src/ethereum/berlin/vm/interpreter.py index cfd72a5814..b58e4f7859 100644 --- a/src/ethereum/berlin/vm/interpreter.py +++ b/src/ethereum/berlin/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -106,7 +107,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/byzantium/state.py b/src/ethereum/byzantium/state.py index 1760e0b126..aa1ab626c3 100644 --- a/src/ethereum/byzantium/state.py +++ b/src/ethereum/byzantium/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/byzantium/vm/instructions/system.py b/src/ethereum/byzantium/vm/instructions/system.py index 8bb0efd958..1b014a3ec9 100644 --- a/src/ethereum/byzantium/vm/instructions/system.py +++ b/src/ethereum/byzantium/vm/instructions/system.py @@ -17,6 +17,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -95,7 +96,9 @@ def create(evm: Evm) -> None: ): push(evm.stack, U256(0)) evm.gas_left += create_message_gas - elif account_has_code_or_nonce(evm.env.state, contract_address): + elif account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) else: diff --git a/src/ethereum/byzantium/vm/interpreter.py b/src/ethereum/byzantium/vm/interpreter.py index 58700d6aa7..2144f99df8 100644 --- a/src/ethereum/byzantium/vm/interpreter.py +++ b/src/ethereum/byzantium/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -105,7 +106,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/cancun/state.py b/src/ethereum/cancun/state.py index 58280b3cf9..4dd49c122d 100644 --- a/src/ethereum/cancun/state.py +++ b/src/ethereum/cancun/state.py @@ -395,13 +395,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/cancun/vm/instructions/system.py b/src/ethereum/cancun/vm/instructions/system.py index fa0e181775..2bdeea399f 100644 --- a/src/ethereum/cancun/vm/instructions/system.py +++ b/src/ethereum/cancun/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -101,7 +102,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/cancun/vm/interpreter.py b/src/ethereum/cancun/vm/interpreter.py index c5cee57ac1..691efe2804 100644 --- a/src/ethereum/cancun/vm/interpreter.py +++ b/src/ethereum/cancun/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -107,7 +108,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/constantinople/state.py b/src/ethereum/constantinople/state.py index 1760e0b126..aa1ab626c3 100644 --- a/src/ethereum/constantinople/state.py +++ b/src/ethereum/constantinople/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/constantinople/vm/instructions/system.py b/src/ethereum/constantinople/vm/instructions/system.py index 03d0d6168b..17e12c40d4 100644 --- a/src/ethereum/constantinople/vm/instructions/system.py +++ b/src/ethereum/constantinople/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -86,7 +87,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/constantinople/vm/interpreter.py b/src/ethereum/constantinople/vm/interpreter.py index b7a0186d83..fc896ac519 100644 --- a/src/ethereum/constantinople/vm/interpreter.py +++ b/src/ethereum/constantinople/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -105,7 +106,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/dao_fork/state.py b/src/ethereum/dao_fork/state.py index 0ccf16b1ec..4b5ffd86fd 100644 --- a/src/ethereum/dao_fork/state.py +++ b/src/ethereum/dao_fork/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def modify_state( state: State, address: Address, f: Callable[[Account], None] ) -> None: diff --git a/src/ethereum/dao_fork/vm/instructions/system.py b/src/ethereum/dao_fork/vm/instructions/system.py index 27e567302b..12366623fe 100644 --- a/src/ethereum/dao_fork/vm/instructions/system.py +++ b/src/ethereum/dao_fork/vm/instructions/system.py @@ -16,6 +16,7 @@ from ...fork_types import Address from ...state import ( account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, set_account_balance, @@ -85,7 +86,9 @@ def create(evm: Evm) -> None: ): push(evm.stack, U256(0)) evm.gas_left += create_message_gas - elif account_has_code_or_nonce(evm.env.state, contract_address): + elif account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) else: diff --git a/src/ethereum/dao_fork/vm/interpreter.py b/src/ethereum/dao_fork/vm/interpreter.py index 1f52f4f67d..c689e932d3 100644 --- a/src/ethereum/dao_fork/vm/interpreter.py +++ b/src/ethereum/dao_fork/vm/interpreter.py @@ -30,6 +30,7 @@ from ..fork_types import Address from ..state import ( account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, move_ether, @@ -97,7 +98,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), AddressCollision() diff --git a/src/ethereum/frontier/state.py b/src/ethereum/frontier/state.py index 0ccf16b1ec..4b5ffd86fd 100644 --- a/src/ethereum/frontier/state.py +++ b/src/ethereum/frontier/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def modify_state( state: State, address: Address, f: Callable[[Account], None] ) -> None: diff --git a/src/ethereum/frontier/vm/instructions/system.py b/src/ethereum/frontier/vm/instructions/system.py index 80dd071370..0d95ee75e8 100644 --- a/src/ethereum/frontier/vm/instructions/system.py +++ b/src/ethereum/frontier/vm/instructions/system.py @@ -16,6 +16,7 @@ from ...fork_types import Address from ...state import ( account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, set_account_balance, @@ -84,7 +85,9 @@ def create(evm: Evm) -> None: ): push(evm.stack, U256(0)) evm.gas_left += create_message_gas - elif account_has_code_or_nonce(evm.env.state, contract_address): + elif account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) else: diff --git a/src/ethereum/frontier/vm/interpreter.py b/src/ethereum/frontier/vm/interpreter.py index 891093b06b..7542e7d3b2 100644 --- a/src/ethereum/frontier/vm/interpreter.py +++ b/src/ethereum/frontier/vm/interpreter.py @@ -30,6 +30,7 @@ from ..fork_types import Address from ..state import ( account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -98,7 +99,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), AddressCollision() diff --git a/src/ethereum/gray_glacier/state.py b/src/ethereum/gray_glacier/state.py index 801fa16657..35245a97be 100644 --- a/src/ethereum/gray_glacier/state.py +++ b/src/ethereum/gray_glacier/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/gray_glacier/vm/instructions/system.py b/src/ethereum/gray_glacier/vm/instructions/system.py index 986b091c52..500c5e994a 100644 --- a/src/ethereum/gray_glacier/vm/instructions/system.py +++ b/src/ethereum/gray_glacier/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -88,7 +89,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/gray_glacier/vm/interpreter.py b/src/ethereum/gray_glacier/vm/interpreter.py index 18c81996b5..8f01a64588 100644 --- a/src/ethereum/gray_glacier/vm/interpreter.py +++ b/src/ethereum/gray_glacier/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -107,7 +108,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/homestead/state.py b/src/ethereum/homestead/state.py index 0ccf16b1ec..4b5ffd86fd 100644 --- a/src/ethereum/homestead/state.py +++ b/src/ethereum/homestead/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def modify_state( state: State, address: Address, f: Callable[[Account], None] ) -> None: diff --git a/src/ethereum/homestead/vm/instructions/system.py b/src/ethereum/homestead/vm/instructions/system.py index 27e567302b..12366623fe 100644 --- a/src/ethereum/homestead/vm/instructions/system.py +++ b/src/ethereum/homestead/vm/instructions/system.py @@ -16,6 +16,7 @@ from ...fork_types import Address from ...state import ( account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, set_account_balance, @@ -85,7 +86,9 @@ def create(evm: Evm) -> None: ): push(evm.stack, U256(0)) evm.gas_left += create_message_gas - elif account_has_code_or_nonce(evm.env.state, contract_address): + elif account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) else: diff --git a/src/ethereum/homestead/vm/interpreter.py b/src/ethereum/homestead/vm/interpreter.py index 35626338b7..4fede8a950 100644 --- a/src/ethereum/homestead/vm/interpreter.py +++ b/src/ethereum/homestead/vm/interpreter.py @@ -30,6 +30,7 @@ from ..fork_types import Address from ..state import ( account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -98,7 +99,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), AddressCollision() diff --git a/src/ethereum/istanbul/state.py b/src/ethereum/istanbul/state.py index 801fa16657..35245a97be 100644 --- a/src/ethereum/istanbul/state.py +++ b/src/ethereum/istanbul/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/istanbul/vm/instructions/system.py b/src/ethereum/istanbul/vm/instructions/system.py index 03d0d6168b..17e12c40d4 100644 --- a/src/ethereum/istanbul/vm/instructions/system.py +++ b/src/ethereum/istanbul/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -86,7 +87,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/istanbul/vm/interpreter.py b/src/ethereum/istanbul/vm/interpreter.py index aa09d5a498..535313c560 100644 --- a/src/ethereum/istanbul/vm/interpreter.py +++ b/src/ethereum/istanbul/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -106,7 +107,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/london/state.py b/src/ethereum/london/state.py index 801fa16657..35245a97be 100644 --- a/src/ethereum/london/state.py +++ b/src/ethereum/london/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/london/vm/instructions/system.py b/src/ethereum/london/vm/instructions/system.py index 986b091c52..500c5e994a 100644 --- a/src/ethereum/london/vm/instructions/system.py +++ b/src/ethereum/london/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -88,7 +89,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/london/vm/interpreter.py b/src/ethereum/london/vm/interpreter.py index 18c81996b5..8f01a64588 100644 --- a/src/ethereum/london/vm/interpreter.py +++ b/src/ethereum/london/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -107,7 +108,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/muir_glacier/state.py b/src/ethereum/muir_glacier/state.py index 801fa16657..35245a97be 100644 --- a/src/ethereum/muir_glacier/state.py +++ b/src/ethereum/muir_glacier/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/muir_glacier/vm/instructions/system.py b/src/ethereum/muir_glacier/vm/instructions/system.py index 03d0d6168b..17e12c40d4 100644 --- a/src/ethereum/muir_glacier/vm/instructions/system.py +++ b/src/ethereum/muir_glacier/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -86,7 +87,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/muir_glacier/vm/interpreter.py b/src/ethereum/muir_glacier/vm/interpreter.py index b807521e1d..a56f43f906 100644 --- a/src/ethereum/muir_glacier/vm/interpreter.py +++ b/src/ethereum/muir_glacier/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -106,7 +107,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/paris/state.py b/src/ethereum/paris/state.py index 887d0e569e..748db6223d 100644 --- a/src/ethereum/paris/state.py +++ b/src/ethereum/paris/state.py @@ -362,13 +362,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/paris/vm/instructions/system.py b/src/ethereum/paris/vm/instructions/system.py index 986b091c52..500c5e994a 100644 --- a/src/ethereum/paris/vm/instructions/system.py +++ b/src/ethereum/paris/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -88,7 +89,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/paris/vm/interpreter.py b/src/ethereum/paris/vm/interpreter.py index 7e9b7b098c..47c2dbec0a 100644 --- a/src/ethereum/paris/vm/interpreter.py +++ b/src/ethereum/paris/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -107,7 +108,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/prague/state.py b/src/ethereum/prague/state.py index 58280b3cf9..4dd49c122d 100644 --- a/src/ethereum/prague/state.py +++ b/src/ethereum/prague/state.py @@ -395,13 +395,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/prague/vm/instructions/system.py b/src/ethereum/prague/vm/instructions/system.py index fa0e181775..2bdeea399f 100644 --- a/src/ethereum/prague/vm/instructions/system.py +++ b/src/ethereum/prague/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -101,7 +102,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/prague/vm/interpreter.py b/src/ethereum/prague/vm/interpreter.py index a290d297de..050aa89a67 100644 --- a/src/ethereum/prague/vm/interpreter.py +++ b/src/ethereum/prague/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -109,7 +110,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), diff --git a/src/ethereum/shanghai/state.py b/src/ethereum/shanghai/state.py index cb3d6e1a03..8109148d55 100644 --- a/src/ethereum/shanghai/state.py +++ b/src/ethereum/shanghai/state.py @@ -363,13 +363,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/shanghai/vm/instructions/system.py b/src/ethereum/shanghai/vm/instructions/system.py index ea7463104d..1f72e30191 100644 --- a/src/ethereum/shanghai/vm/instructions/system.py +++ b/src/ethereum/shanghai/vm/instructions/system.py @@ -18,6 +18,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -100,7 +101,9 @@ def generic_create( push(evm.stack, U256(0)) return - if account_has_code_or_nonce(evm.env.state, contract_address): + if account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) return diff --git a/src/ethereum/shanghai/vm/interpreter.py b/src/ethereum/shanghai/vm/interpreter.py index 5c568c0af1..3d679a101e 100644 --- a/src/ethereum/shanghai/vm/interpreter.py +++ b/src/ethereum/shanghai/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -107,7 +108,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/spurious_dragon/state.py b/src/ethereum/spurious_dragon/state.py index 1760e0b126..aa1ab626c3 100644 --- a/src/ethereum/spurious_dragon/state.py +++ b/src/ethereum/spurious_dragon/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def is_account_empty(state: State, address: Address) -> bool: """ Checks if an account has zero nonce, empty code and zero balance. diff --git a/src/ethereum/spurious_dragon/vm/instructions/system.py b/src/ethereum/spurious_dragon/vm/instructions/system.py index c80d0af986..341314d9ca 100644 --- a/src/ethereum/spurious_dragon/vm/instructions/system.py +++ b/src/ethereum/spurious_dragon/vm/instructions/system.py @@ -17,6 +17,7 @@ from ...state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, is_account_alive, @@ -92,7 +93,9 @@ def create(evm: Evm) -> None: ): push(evm.stack, U256(0)) evm.gas_left += create_message_gas - elif account_has_code_or_nonce(evm.env.state, contract_address): + elif account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) else: diff --git a/src/ethereum/spurious_dragon/vm/interpreter.py b/src/ethereum/spurious_dragon/vm/interpreter.py index 99ccccd6a7..60f9fe3920 100644 --- a/src/ethereum/spurious_dragon/vm/interpreter.py +++ b/src/ethereum/spurious_dragon/vm/interpreter.py @@ -31,6 +31,7 @@ from ..state import ( account_exists_and_is_empty, account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -104,7 +105,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), set(), AddressCollision() diff --git a/src/ethereum/tangerine_whistle/state.py b/src/ethereum/tangerine_whistle/state.py index 0ccf16b1ec..4b5ffd86fd 100644 --- a/src/ethereum/tangerine_whistle/state.py +++ b/src/ethereum/tangerine_whistle/state.py @@ -336,13 +336,32 @@ def account_has_code_or_nonce(state: State, address: Address) -> bool: Returns ------- has_code_or_nonce : `bool` - True if if an account has non zero nonce or non empty code, + True if the account has non zero nonce or non empty code, False otherwise. """ account = get_account(state, address) return account.nonce != Uint(0) or account.code != b"" +def account_has_storage(state: State, address: Address) -> bool: + """ + Checks if an account has storage. + + Parameters + ---------- + state: + The state + address: + Address of the account that needs to be checked. + + Returns + ------- + has_storage : `bool` + True if the account has storage, False otherwise. + """ + return address in state._storage_tries + + def modify_state( state: State, address: Address, f: Callable[[Account], None] ) -> None: diff --git a/src/ethereum/tangerine_whistle/vm/instructions/system.py b/src/ethereum/tangerine_whistle/vm/instructions/system.py index 2643aba00e..904d7aa9e3 100644 --- a/src/ethereum/tangerine_whistle/vm/instructions/system.py +++ b/src/ethereum/tangerine_whistle/vm/instructions/system.py @@ -17,6 +17,7 @@ from ...state import ( account_exists, account_has_code_or_nonce, + account_has_storage, get_account, increment_nonce, set_account_balance, @@ -91,7 +92,9 @@ def create(evm: Evm) -> None: ): push(evm.stack, U256(0)) evm.gas_left += create_message_gas - elif account_has_code_or_nonce(evm.env.state, contract_address): + elif account_has_code_or_nonce( + evm.env.state, contract_address + ) or account_has_storage(evm.env.state, contract_address): increment_nonce(evm.env.state, evm.message.current_target) push(evm.stack, U256(0)) else: diff --git a/src/ethereum/tangerine_whistle/vm/interpreter.py b/src/ethereum/tangerine_whistle/vm/interpreter.py index 2eefbf087f..55cba36cef 100644 --- a/src/ethereum/tangerine_whistle/vm/interpreter.py +++ b/src/ethereum/tangerine_whistle/vm/interpreter.py @@ -30,6 +30,7 @@ from ..fork_types import Address from ..state import ( account_has_code_or_nonce, + account_has_storage, begin_transaction, commit_transaction, destroy_storage, @@ -98,7 +99,7 @@ def process_message_call( if message.target == Bytes0(b""): is_collision = account_has_code_or_nonce( env.state, message.current_target - ) + ) or account_has_storage(env.state, message.current_target) if is_collision: return MessageCallOutput( Uint(0), U256(0), tuple(), set(), AddressCollision() diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py index 17339cd1d7..99b06c3e19 100644 --- a/tests/helpers/__init__.py +++ b/tests/helpers/__init__.py @@ -12,7 +12,7 @@ }, "ethereum_tests": { "url": "https://github.com/ethereum/tests.git", - "commit_hash": "52ddcbc", + "commit_hash": "9201075", "fixture_path": "tests/fixtures/ethereum_tests", }, "latest_fork_tests": {