Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/ethereum/cancun/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
from ethereum_types.bytes import Bytes, Bytes0, Bytes32
from ethereum_types.numeric import U64, U256, Uint

from ethereum.crypto.hash import Hash32
from ethereum.crypto.hash import Hash32, keccak256
from ethereum.exceptions import EthereumException
from ethereum.utils.byte import left_pad_zero_bytes

from ..blocks import Log
from ..fork_types import Address, VersionedHash
Expand Down Expand Up @@ -150,3 +151,32 @@ def incorporate_child_on_error(evm: Evm, child_evm: Evm) -> None:
):
evm.touched_accounts.add(RIPEMD160_ADDRESS)
evm.gas_left += child_evm.gas_left

def eth_transfer_log(sender: Address, recipient: Address, amount: U256) -> Log:
"""
EIP-7708 style logs for all kinds of ETH transfers

Parameters
----------
sender :
The address of the sender
recipient :
The address of the recipient
amount :
The amount transferred
Returns
-------
log_entry:
A log entry that can be appended to the current evm context
"""
magic_signature = "MAGIC_00"
topic1 = keccak256(magic_signature.encode()) # Magic Signature
topic2 = Hash32(left_pad_zero_bytes(sender, 32))
topic3 = Hash32(left_pad_zero_bytes(recipient, 32))
amount_bytes = amount.to_bytes(32, byteorder='big')

return Log(
address=sender,
topics=(topic1, topic2, topic3),
data=amount_bytes,
)
9 changes: 8 additions & 1 deletion src/ethereum/cancun/vm/instructions/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
Message,
incorporate_child_on_error,
incorporate_child_on_success,
eth_transfer_log
)
from ..exceptions import OutOfGasError, Revert, WriteInStaticContext
from ..gas import (
Expand Down Expand Up @@ -321,6 +322,7 @@ def generic_call(
evm.return_data = child_evm.output
push(evm.stack, U256(0))
else:
# child CALL logs would be appended to parent logs
incorporate_child_on_success(evm, child_evm)
evm.return_data = child_evm.output
push(evm.stack, U256(1))
Expand Down Expand Up @@ -384,7 +386,7 @@ def call(evm: Evm) -> None:
raise WriteInStaticContext
evm.memory += b"\x00" * extend_memory.expand_by
sender_balance = get_account(
evm.env.state, evm.message.current_target
evm.env.state, evm.message.current_target # current_target is the contract that is calling the call opcode
).balance
if sender_balance < value:
push(evm.stack, U256(0))
Expand Down Expand Up @@ -522,6 +524,11 @@ def selfdestruct(evm: Evm) -> None:
originator_balance,
)

# check if amount was non zero, then update evm logs with the new log
if originator_balance > 0:
log_entry = eth_transfer_log(originator, beneficiary, originator_balance)
evm.logs = evm.logs + (log_entry,)

# register account for deletion only if it was created
# in the same transaction
if originator in evm.env.state.created_accounts:
Expand Down
17 changes: 13 additions & 4 deletions src/ethereum/cancun/vm/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
from ..vm import Message
from ..vm.gas import GAS_CODE_DEPOSIT, charge_gas
from ..vm.precompiled_contracts.mapping import PRE_COMPILED_CONTRACTS
from . import Environment, Evm
from . import Environment, Evm, eth_transfer_log
from .exceptions import (
AddressCollision,
ExceptionalHalt,
Expand Down Expand Up @@ -89,6 +89,7 @@ class MessageCallOutput:
error: Optional[EthereumException]


## This is where a general transfer tx would start from
def process_message_call(
message: Message, env: Environment
) -> MessageCallOutput:
Expand Down Expand Up @@ -121,6 +122,7 @@ def process_message_call(
evm = process_create_message(message, env)
else:
evm = process_message(message, env)
## can append to logs here
if account_exists_and_is_empty(env.state, Address(message.target)):
evm.touched_accounts.add(Address(message.target))

Expand Down Expand Up @@ -232,12 +234,18 @@ def process_message(message: Message, env: Environment) -> Evm:

touch_account(env.state, message.current_target)

log_entry = ()
if message.should_transfer_value and message.value != 0:
move_ether(
env.state, message.caller, message.current_target, message.value
)
## add log here for transfer CALL (child evm calls) and normal ETH value transfers
log_entry = eth_transfer_log(message.caller, message.current_target, message.value)

# this ensures value transfer tx logs are before the child evm logs
# both eth value transfers and CALL opcode invocations reach this execution phase
evm = execute_code(message, env, log_entry)

evm = execute_code(message, env)
if evm.error:
# revert state to the last saved checkpoint
# since the message call resulted in an error
Expand All @@ -247,7 +255,7 @@ def process_message(message: Message, env: Environment) -> Evm:
return evm


def execute_code(message: Message, env: Environment) -> Evm:
def execute_code(message: Message, env: Environment, log_entry: Log) -> Evm:
"""
Executes bytecode present in the `message`.

Expand All @@ -274,7 +282,7 @@ def execute_code(message: Message, env: Environment) -> Evm:
gas_left=message.gas,
env=env,
valid_jump_destinations=valid_jump_destinations,
logs=(),
logs=(log_entry,) if log_entry != () else (),
refund_counter=0,
running=True,
message=message,
Expand All @@ -286,6 +294,7 @@ def execute_code(message: Message, env: Environment) -> Evm:
accessed_addresses=message.accessed_addresses,
accessed_storage_keys=message.accessed_storage_keys,
)

try:
if evm.message.code_address in PRE_COMPILED_CONTRACTS:
evm_trace(evm, PrecompileStart(evm.message.code_address))
Expand Down