Skip to content
Draft
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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ packages = [
"ethereum_spec_tools.lint",
"ethereum_spec_tools.lint.lints",
"ethereum",
"ethereum.state_oracle",
"ethereum.frontier",
"ethereum.frontier.utils",
"ethereum.frontier.vm",
Expand Down
73 changes: 39 additions & 34 deletions src/ethereum/osaka/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,7 @@
compute_requests_hash,
parse_deposit_requests,
)
from .state import (
State,
TransientStorage,
account_exists_and_is_empty,
destroy_account,
get_account,
increment_nonce,
modify_state,
set_account_balance,
state_root,
)
from .state import State, TransientStorage
from .transactions import (
AccessListTransaction,
BlobTransaction,
Expand Down Expand Up @@ -210,6 +200,8 @@ def state_transition(chain: BlockChain, block: Block) -> None:
History and current state.
block :
Block to apply to `chain`.
oracle : MerkleOracle
State oracle for accessing blockchain state. Must be provided.
"""
if len(rlp.encode(block)) > MAX_RLP_BLOCK_SIZE:
raise InvalidBlock("Block rlp size exceeds MAX_RLP_BLOCK_SIZE")
Expand Down Expand Up @@ -237,7 +229,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
transactions=block.transactions,
withdrawals=block.withdrawals,
)
block_state_root = state_root(block_env.state)
block_state_root = block_env.get_oracle().state_root()
transactions_root = root(block_output.transactions_trie)
receipt_root = root(block_output.receipts_trie)
block_logs_bloom = logs_bloom(block_output.block_logs)
Expand Down Expand Up @@ -461,7 +453,7 @@ def check_transaction(
raise BlobGasLimitExceededError("blob gas limit exceeded")

sender_address = recover_sender(block_env.chain_id, tx)
sender_account = get_account(block_env.state, sender_address)
sender_account = block_env.get_oracle().get_account(sender_address)

if isinstance(
tx, (FeeMarketTransaction, BlobTransaction, SetCodeTransaction)
Expand Down Expand Up @@ -666,7 +658,9 @@ def process_checked_system_transaction(
system_tx_output : `MessageCallOutput`
Output of processing the system transaction.
"""
system_contract_code = get_account(block_env.state, target_address).code
system_contract_code = (
block_env.get_oracle().get_account(target_address).code
)

if len(system_contract_code) == 0:
raise InvalidBlock(
Expand Down Expand Up @@ -713,7 +707,9 @@ def process_unchecked_system_transaction(
system_tx_output : `MessageCallOutput`
Output of processing the system transaction.
"""
system_contract_code = get_account(block_env.state, target_address).code
system_contract_code = (
block_env.get_oracle().get_account(target_address).code
)
return process_system_transaction(
block_env,
target_address,
Expand Down Expand Up @@ -870,7 +866,7 @@ def process_transaction(
tx=tx,
)

sender_account = get_account(block_env.state, sender)
sender_account = block_env.get_oracle().get_account(sender)

if isinstance(tx, BlobTransaction):
blob_gas_fee = calculate_data_fee(block_env.excess_blob_gas, tx)
Expand All @@ -880,13 +876,13 @@ def process_transaction(
effective_gas_fee = tx.gas * effective_gas_price

gas = tx.gas - intrinsic_gas
increment_nonce(block_env.state, sender)
block_env.get_oracle().increment_nonce(sender)

sender_balance_after_gas_fee = (
Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
)
set_account_balance(
block_env.state, sender, U256(sender_balance_after_gas_fee)
block_env.get_oracle().set_account_balance(
sender, U256(sender_balance_after_gas_fee)
)

access_list_addresses = set()
Expand Down Expand Up @@ -949,26 +945,33 @@ def process_transaction(
transaction_fee = tx_gas_used_after_refund * priority_fee_per_gas

# refund gas
sender_balance_after_refund = get_account(
block_env.state, sender
).balance + U256(gas_refund_amount)
set_account_balance(block_env.state, sender, sender_balance_after_refund)
current_sender_balance = block_env.get_oracle().get_account(sender).balance
sender_balance_after_refund = current_sender_balance + U256(
gas_refund_amount
)
block_env.get_oracle().set_account_balance(
sender, sender_balance_after_refund
)

# transfer miner fees
coinbase_balance_after_mining_fee = get_account(
block_env.state, block_env.coinbase
).balance + U256(transaction_fee)
current_coinbase_balance = (
block_env.get_oracle().get_account(block_env.coinbase).balance
)
coinbase_balance_after_mining_fee = current_coinbase_balance + U256(
transaction_fee
)
if coinbase_balance_after_mining_fee != 0:
set_account_balance(
block_env.state,
block_env.get_oracle().set_account_balance(
block_env.coinbase,
coinbase_balance_after_mining_fee,
)
elif account_exists_and_is_empty(block_env.state, block_env.coinbase):
destroy_account(block_env.state, block_env.coinbase)
elif block_env.get_oracle().account_exists_and_is_empty(
block_env.coinbase
):
block_env.get_oracle().destroy_account(block_env.coinbase)

for address in tx_output.accounts_to_delete:
destroy_account(block_env.state, address)
block_env.get_oracle().destroy_account(address)

block_output.block_gas_used += tx_gas_used_after_refund
block_output.blob_gas_used += tx_blob_gas_used
Expand Down Expand Up @@ -1008,10 +1011,12 @@ def increase_recipient_balance(recipient: Account) -> None:
rlp.encode(wd),
)

modify_state(block_env.state, wd.address, increase_recipient_balance)
block_env.get_oracle().modify_state(
wd.address, increase_recipient_balance
)

if account_exists_and_is_empty(block_env.state, wd.address):
destroy_account(block_env.state, wd.address)
if block_env.get_oracle().account_exists_and_is_empty(wd.address):
block_env.get_oracle().destroy_account(wd.address)


def check_gas_limit(gas_limit: Uint, parent_gas_limit: Uint) -> bool:
Expand Down
5 changes: 2 additions & 3 deletions src/ethereum/osaka/utils/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from ethereum_types.numeric import Uint

from ..fork_types import Address
from ..state import get_account
from ..transactions import Transaction
from ..vm import BlockEnvironment, Message, TransactionEnvironment
from ..vm.precompiled_contracts.mapping import PRE_COMPILED_CONTRACTS
Expand Down Expand Up @@ -54,15 +53,15 @@ def prepare_message(
if isinstance(tx.to, Bytes0):
current_target = compute_contract_address(
tx_env.origin,
get_account(block_env.state, tx_env.origin).nonce - Uint(1),
block_env.get_oracle().get_account(tx_env.origin).nonce - Uint(1),
)
msg_data = Bytes(b"")
code = tx.data
code_address = None
elif isinstance(tx.to, Address):
current_target = tx.to
msg_data = tx.data
code = get_account(block_env.state, tx.to).code
code = block_env.get_oracle().get_account(tx.to).code
code_address = tx.to
else:
raise AssertionError("Target must be address or empty bytes")
Expand Down
13 changes: 12 additions & 1 deletion src/ethereum/osaka/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""

from dataclasses import dataclass, field
from typing import List, Optional, Set, Tuple
from typing import Any, List, Optional, Set, Tuple

from ethereum_types.bytes import Bytes, Bytes0, Bytes32
from ethereum_types.numeric import U64, U256, Uint
Expand All @@ -38,6 +38,7 @@ class BlockEnvironment:
"""

chain_id: U64
# TODO: Remove, no longer used. Kept so tests don't break for now.
state: State
block_gas_limit: Uint
block_hashes: List[Hash32]
Expand All @@ -49,6 +50,16 @@ class BlockEnvironment:
excess_blob_gas: U64
parent_beacon_block_root: Hash32

def get_oracle(self) -> Any:
"""
Get the state oracle.

Returns the global oracle (raises error if not set).
"""
from ethereum.state_oracle import get_state_oracle

return get_state_oracle()


@dataclass
class BlockOutput:
Expand Down
20 changes: 9 additions & 11 deletions src/ethereum/osaka/vm/eoa_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Set EOA account code.
"""


from typing import Optional, Tuple

from ethereum_rlp import rlp
Expand All @@ -14,7 +13,6 @@
from ethereum.exceptions import InvalidBlock, InvalidSignatureError

from ..fork_types import Address, Authorization
from ..state import account_exists, get_account, increment_nonce, set_code
from ..utils.hexadecimal import hex_to_address
from ..vm.gas import GAS_COLD_ACCOUNT_ACCESS, GAS_WARM_ACCESS
from . import Evm, Message
Expand Down Expand Up @@ -130,8 +128,8 @@ def access_delegation(
delegation : `Tuple[bool, Address, Bytes, Uint]`
The delegation address, code, and access gas cost.
"""
state = evm.message.block_env.state
code = get_account(state, address).code
oracle = evm.message.block_env.get_oracle()
code = oracle.get_account(address).code
if not is_valid_delegation(code):
return False, address, code, Uint(0)

Expand All @@ -141,7 +139,7 @@ def access_delegation(
else:
evm.accessed_addresses.add(address)
access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
code = get_account(state, address).code
code = oracle.get_account(address).code

return True, address, code, access_gas_cost

Expand All @@ -162,7 +160,7 @@ def set_delegation(message: Message) -> U256:
refund_counter: `U256`
Refund from authority which already exists in state.
"""
state = message.block_env.state
oracle = message.block_env.get_oracle()
refund_counter = U256(0)
for auth in message.tx_env.authorizations:
if auth.chain_id not in (message.block_env.chain_id, U256(0)):
Expand All @@ -178,7 +176,7 @@ def set_delegation(message: Message) -> U256:

message.accessed_addresses.add(authority)

authority_account = get_account(state, authority)
authority_account = oracle.get_account(authority)
authority_code = authority_account.code

if authority_code and not is_valid_delegation(authority_code):
Expand All @@ -188,20 +186,20 @@ def set_delegation(message: Message) -> U256:
if authority_nonce != auth.nonce:
continue

if account_exists(state, authority):
if oracle.account_exists(authority):
refund_counter += U256(PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST)

if auth.address == NULL_ADDRESS:
code_to_set = b""
else:
code_to_set = EOA_DELEGATION_MARKER + auth.address
set_code(state, authority, code_to_set)
oracle.set_code(authority, code_to_set)

increment_nonce(state, authority)
oracle.increment_nonce(authority)

if message.code_address is None:
raise InvalidBlock("Invalid type 4 transaction: no target")

message.code = get_account(state, message.code_address).code
message.code = oracle.get_account(message.code_address).code

return refund_counter
18 changes: 10 additions & 8 deletions src/ethereum/osaka/vm/instructions/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from ethereum.utils.numeric import ceil32

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blockhash was not modified, but that should also likely be a part of "state" since 2935 has been implemented

from ...fork_types import EMPTY_ACCOUNT
from ...state import get_account
from ...utils.address import to_address_masked
from ...vm.memory import buffer_read, memory_write
from .. import Evm
Expand Down Expand Up @@ -84,8 +83,9 @@ def balance(evm: Evm) -> None:
charge_gas(evm, GAS_COLD_ACCOUNT_ACCESS)

# OPERATION
oracle = evm.message.block_env.get_oracle()
# Non-existent accounts default to EMPTY_ACCOUNT, which has balance 0.
balance = get_account(evm.message.block_env.state, address).balance
balance = oracle.get_account(address).balance

push(evm.stack, balance)

Expand Down Expand Up @@ -351,7 +351,8 @@ def extcodesize(evm: Evm) -> None:
charge_gas(evm, access_gas_cost)

# OPERATION
code = get_account(evm.message.block_env.state, address).code
oracle = evm.message.block_env.get_oracle()
code = oracle.get_account(address).code

codesize = U256(len(code))
push(evm.stack, codesize)
Expand Down Expand Up @@ -393,7 +394,8 @@ def extcodecopy(evm: Evm) -> None:

# OPERATION
evm.memory += b"\x00" * extend_memory.expand_by
code = get_account(evm.message.block_env.state, address).code
oracle = evm.message.block_env.get_oracle()
code = oracle.get_account(address).code

value = buffer_read(code, code_start_index, size)
memory_write(evm.memory, memory_start_index, value)
Expand Down Expand Up @@ -479,7 +481,8 @@ def extcodehash(evm: Evm) -> None:
charge_gas(evm, access_gas_cost)

# OPERATION
account = get_account(evm.message.block_env.state, address)
oracle = evm.message.block_env.get_oracle()
account = oracle.get_account(address)

if account == EMPTY_ACCOUNT:
codehash = U256(0)
Expand Down Expand Up @@ -510,10 +513,9 @@ def self_balance(evm: Evm) -> None:
charge_gas(evm, GAS_FAST_STEP)

# OPERATION
oracle = evm.message.block_env.get_oracle()
# Non-existent accounts default to EMPTY_ACCOUNT, which has balance 0.
balance = get_account(
evm.message.block_env.state, evm.message.current_target
).balance
balance = oracle.get_account(evm.message.current_target).balance

push(evm.stack, balance)

Expand Down
1 change: 1 addition & 0 deletions src/ethereum/osaka/vm/instructions/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

Implementations of the EVM Memory instructions.
"""

from ethereum_types.bytes import Bytes
from ethereum_types.numeric import U256, Uint

Expand Down
Loading
Loading