-
Notifications
You must be signed in to change notification settings - Fork 511
feat(amsterdam): defer EIP-7702 delegate warming until entry checks pass #2900
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -298,15 +298,10 @@ def generic_call( | |
| """ | ||
| Perform the core logic of the `CALL*` family of opcodes. | ||
| """ | ||
| from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message | ||
| from ...vm.interpreter import process_message | ||
|
|
||
| evm.return_data = b"" | ||
|
|
||
| if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT: | ||
| evm.gas_left += gas | ||
| push(evm.stack, U256(0)) | ||
| return | ||
|
|
||
| tx_state = evm.message.tx_env.state | ||
| code_hash = get_account(tx_state, code_address).code_hash | ||
| code = get_code(tx_state, code_hash) | ||
|
|
@@ -386,37 +381,45 @@ def call(evm: Evm) -> None: | |
| ) | ||
|
|
||
| is_cold_access = to not in evm.accessed_addresses | ||
| if is_cold_access: | ||
| access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS | ||
| else: | ||
| access_gas_cost = GasCosts.WARM_ACCESS | ||
|
|
||
| transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE | ||
|
|
||
| # check static gas before state access | ||
| check_gas( | ||
| evm, | ||
| access_gas_cost + transfer_gas_cost + extend_memory.cost, | ||
| ) | ||
| # Pre-state extra gas (warm-equivalent access cost only; cold surcharge | ||
| # is deferred to post-state). | ||
| extra_gas = GasCosts.WARM_ACCESS + transfer_gas_cost | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
|
|
||
| # Pre-state preconditions: stack depth and (if value > 0) sender balance. | ||
| from ...vm.interpreter import STACK_DEPTH_LIMIT | ||
|
|
||
| # STATE ACCESS | ||
| tx_state = evm.message.tx_env.state | ||
| sender_balance = get_account(tx_state, evm.message.current_target).balance | ||
| if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT or ( | ||
| value > U256(0) and sender_balance < value | ||
| ): | ||
| charge_gas(evm, extra_gas + extend_memory.cost) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A call that does not have enough balance to send value, ends up paying only the warm cost to access the target account, even if it is cold.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah right now it looks like we won't go for this change anyway
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nerolation Is there consensus on a final shape for this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the default was not changing and clients now had 2-3 weeks to chime in. I'll let clients take the shot on this with the default closing this PR. |
||
| evm.memory += b"\x00" * extend_memory.expand_by | ||
| push(evm.stack, U256(0)) | ||
| evm.return_data = b"" | ||
| evm.pc += Uint(1) | ||
| return | ||
|
|
||
| # Post-state: cold surcharge paired with warming and BAL insertion. | ||
| if is_cold_access: | ||
| extra_gas += GasCosts.COLD_ACCOUNT_ACCESS - GasCosts.WARM_ACCESS | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.accessed_addresses.add(to) | ||
|
|
||
| create_gas_cost = GasCosts.NEW_ACCOUNT | ||
| if value == 0 or is_account_alive(tx_state, to): | ||
| create_gas_cost = Uint(0) | ||
| if value > U256(0) and not is_account_alive(tx_state, to): | ||
| extra_gas += GasCosts.NEW_ACCOUNT | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
|
|
||
| extra_gas = access_gas_cost + transfer_gas_cost + create_gas_cost | ||
| ( | ||
| is_delegated, | ||
| code_address, | ||
| delegation_access_cost, | ||
| ) = calculate_delegation_cost(evm, to) | ||
|
|
||
| if is_delegated: | ||
| # check enough gas for delegation access | ||
| extra_gas += delegation_access_cost | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| if code_address not in evm.accessed_addresses: | ||
|
|
@@ -433,27 +436,21 @@ def call(evm: Evm) -> None: | |
|
|
||
| # OPERATION | ||
| evm.memory += b"\x00" * extend_memory.expand_by | ||
| sender_balance = get_account(tx_state, evm.message.current_target).balance | ||
| if sender_balance < value: | ||
| push(evm.stack, U256(0)) | ||
| evm.return_data = b"" | ||
| evm.gas_left += message_call_gas.sub_call | ||
| else: | ||
| generic_call( | ||
| evm, | ||
| message_call_gas.sub_call, | ||
| value, | ||
| evm.message.current_target, | ||
| to, | ||
| code_address, | ||
| True, | ||
| False, | ||
| memory_input_start_position, | ||
| memory_input_size, | ||
| memory_output_start_position, | ||
| memory_output_size, | ||
| is_delegated, | ||
| ) | ||
| generic_call( | ||
| evm, | ||
| message_call_gas.sub_call, | ||
| value, | ||
| evm.message.current_target, | ||
| to, | ||
| code_address, | ||
| True, | ||
| False, | ||
| memory_input_start_position, | ||
| memory_input_size, | ||
| memory_output_start_position, | ||
| memory_output_size, | ||
| is_delegated, | ||
| ) | ||
|
|
||
| # PROGRAM COUNTER | ||
| evm.pc += Uint(1) | ||
|
|
@@ -490,33 +487,41 @@ def callcode(evm: Evm) -> None: | |
| ) | ||
|
|
||
| is_cold_access = code_address not in evm.accessed_addresses | ||
| if is_cold_access: | ||
| access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS | ||
| else: | ||
| access_gas_cost = GasCosts.WARM_ACCESS | ||
|
|
||
| transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE | ||
|
|
||
| # check static gas before state access | ||
| check_gas( | ||
| evm, | ||
| access_gas_cost + extend_memory.cost + transfer_gas_cost, | ||
| ) | ||
| # Pre-state extra gas (warm-equivalent access cost only; cold surcharge | ||
| # is deferred to post-state). | ||
| extra_gas = GasCosts.WARM_ACCESS + transfer_gas_cost | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
|
|
||
| # Pre-state preconditions: stack depth and (if value > 0) sender balance. | ||
| from ...vm.interpreter import STACK_DEPTH_LIMIT | ||
|
|
||
| # STATE ACCESS | ||
| tx_state = evm.message.tx_env.state | ||
| sender_balance = get_account(tx_state, evm.message.current_target).balance | ||
| if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT or ( | ||
| value > U256(0) and sender_balance < value | ||
| ): | ||
| charge_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.memory += b"\x00" * extend_memory.expand_by | ||
| push(evm.stack, U256(0)) | ||
| evm.return_data = b"" | ||
| evm.pc += Uint(1) | ||
| return | ||
|
|
||
| # Post-state: cold surcharge paired with warming and BAL insertion. | ||
| if is_cold_access: | ||
| extra_gas += GasCosts.COLD_ACCOUNT_ACCESS - GasCosts.WARM_ACCESS | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.accessed_addresses.add(code_address) | ||
|
|
||
| extra_gas = access_gas_cost + transfer_gas_cost | ||
| ( | ||
| is_delegated, | ||
| code_address, | ||
| delegation_access_cost, | ||
| ) = calculate_delegation_cost(evm, code_address) | ||
|
|
||
| if is_delegated: | ||
| # check enough gas for delegation access | ||
| extra_gas += delegation_access_cost | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| if code_address not in evm.accessed_addresses: | ||
|
|
@@ -533,28 +538,21 @@ def callcode(evm: Evm) -> None: | |
|
|
||
| # OPERATION | ||
| evm.memory += b"\x00" * extend_memory.expand_by | ||
| sender_balance = get_account(tx_state, evm.message.current_target).balance | ||
|
|
||
| if sender_balance < value: | ||
| push(evm.stack, U256(0)) | ||
| evm.return_data = b"" | ||
| evm.gas_left += message_call_gas.sub_call | ||
| else: | ||
| generic_call( | ||
| evm, | ||
| message_call_gas.sub_call, | ||
| value, | ||
| evm.message.current_target, | ||
| to, | ||
| code_address, | ||
| True, | ||
| False, | ||
| memory_input_start_position, | ||
| memory_input_size, | ||
| memory_output_start_position, | ||
| memory_output_size, | ||
| is_delegated, | ||
| ) | ||
| generic_call( | ||
| evm, | ||
| message_call_gas.sub_call, | ||
| value, | ||
| evm.message.current_target, | ||
| to, | ||
| code_address, | ||
| True, | ||
| False, | ||
| memory_input_start_position, | ||
| memory_input_size, | ||
| memory_output_start_position, | ||
| memory_output_size, | ||
| is_delegated, | ||
| ) | ||
|
|
||
| # PROGRAM COUNTER | ||
| evm.pc += Uint(1) | ||
|
|
@@ -652,27 +650,36 @@ def delegatecall(evm: Evm) -> None: | |
| ) | ||
|
|
||
| is_cold_access = code_address not in evm.accessed_addresses | ||
| if is_cold_access: | ||
| access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS | ||
| else: | ||
| access_gas_cost = GasCosts.WARM_ACCESS | ||
|
|
||
| # check static gas before state access | ||
| check_gas(evm, access_gas_cost + extend_memory.cost) | ||
| # Pre-state extra gas (warm-equivalent access cost only; cold surcharge | ||
| # is deferred to post-state). | ||
| extra_gas = GasCosts.WARM_ACCESS | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
|
|
||
| # STATE ACCESS | ||
| # Pre-state precondition: stack depth. | ||
| from ...vm.interpreter import STACK_DEPTH_LIMIT | ||
|
|
||
| if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT: | ||
| charge_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.memory += b"\x00" * extend_memory.expand_by | ||
| push(evm.stack, U256(0)) | ||
| evm.return_data = b"" | ||
| evm.pc += Uint(1) | ||
| return | ||
|
|
||
| # Post-state: cold surcharge paired with warming and BAL insertion. | ||
| if is_cold_access: | ||
| extra_gas += GasCosts.COLD_ACCOUNT_ACCESS - GasCosts.WARM_ACCESS | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.accessed_addresses.add(code_address) | ||
|
|
||
| extra_gas = access_gas_cost | ||
| ( | ||
| is_delegated, | ||
| code_address, | ||
| delegation_access_cost, | ||
| ) = calculate_delegation_cost(evm, code_address) | ||
|
|
||
| if is_delegated: | ||
| # check enough gas for delegation access | ||
| extra_gas += delegation_access_cost | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| if code_address not in evm.accessed_addresses: | ||
|
|
@@ -737,27 +744,36 @@ def staticcall(evm: Evm) -> None: | |
| ) | ||
|
|
||
| is_cold_access = to not in evm.accessed_addresses | ||
| if is_cold_access: | ||
| access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS | ||
| else: | ||
| access_gas_cost = GasCosts.WARM_ACCESS | ||
|
|
||
| # check static gas before state access | ||
| check_gas(evm, access_gas_cost + extend_memory.cost) | ||
| # Pre-state extra gas (warm-equivalent access cost only; cold surcharge | ||
| # is deferred to post-state). | ||
| extra_gas = GasCosts.WARM_ACCESS | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
|
|
||
| # STATE ACCESS | ||
| # Pre-state precondition: stack depth. | ||
| from ...vm.interpreter import STACK_DEPTH_LIMIT | ||
|
|
||
| if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT: | ||
| charge_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.memory += b"\x00" * extend_memory.expand_by | ||
| push(evm.stack, U256(0)) | ||
| evm.return_data = b"" | ||
| evm.pc += Uint(1) | ||
| return | ||
|
|
||
| # Post-state: cold surcharge paired with warming and BAL insertion. | ||
| if is_cold_access: | ||
| extra_gas += GasCosts.COLD_ACCOUNT_ACCESS - GasCosts.WARM_ACCESS | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| evm.accessed_addresses.add(to) | ||
|
|
||
| extra_gas = access_gas_cost | ||
| ( | ||
| is_delegated, | ||
| code_address, | ||
| delegation_access_cost, | ||
| ) = calculate_delegation_cost(evm, to) | ||
|
|
||
| if is_delegated: | ||
| # check enough gas for delegation access | ||
| extra_gas += delegation_access_cost | ||
| check_gas(evm, extra_gas + extend_memory.cost) | ||
| if code_address not in evm.accessed_addresses: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm missing something but I don't quite understand this charge. Couldn't we just
check_gas(evm, extend_memory.cost)and immediatelyif evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT or (value > U256(0) and sender_balance < value), and charge no warm access?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answering my own comment: With bare
check_gas(evm, extend_memory.cost),CALLwith insufficient balance would be cheaper to expand the memory (full of zeros) thanMSTORE.