Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 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
75 changes: 38 additions & 37 deletions src/ethereum/osaka/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""

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

from ethereum_rlp import rlp
from ethereum_types.bytes import Bytes
Expand Down 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 @@ -189,7 +179,9 @@ def get_last_256_block_hashes(chain: BlockChain) -> List[Hash32]:
return recent_block_hashes


def state_transition(chain: BlockChain, block: Block) -> None:
def state_transition(
chain: BlockChain, block: Block, oracle: Optional[Any] = None
) -> None:
"""
Attempts to apply a block to an existing block chain.

Expand All @@ -210,6 +202,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 All @@ -218,9 +212,13 @@ def state_transition(chain: BlockChain, block: Block) -> None:
if block.ommers != ():
raise InvalidBlock

# Oracle must be provided
if oracle is None:
raise ValueError("Oracle parameter is required for state_transition")

block_env = vm.BlockEnvironment(
chain_id=chain.chain_id,
state=chain.state,
oracle=oracle,
block_gas_limit=block.header.gas_limit,
block_hashes=get_last_256_block_hashes(chain),
coinbase=block.header.coinbase,
Expand All @@ -237,7 +235,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.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 +459,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.oracle.get_account(sender_address)

if isinstance(
tx, (FeeMarketTransaction, BlobTransaction, SetCodeTransaction)
Expand Down Expand Up @@ -666,7 +664,7 @@ 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.oracle.get_account(target_address).code

if len(system_contract_code) == 0:
raise InvalidBlock(
Expand Down Expand Up @@ -713,7 +711,7 @@ 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.oracle.get_account(target_address).code
return process_system_transaction(
block_env,
target_address,
Expand Down Expand Up @@ -870,7 +868,7 @@ def process_transaction(
tx=tx,
)

sender_account = get_account(block_env.state, sender)
sender_account = block_env.oracle.get_account(sender)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Most changes look like this:

Before:

func(state, params)

After:

oracle.func(params)


if isinstance(tx, BlobTransaction):
blob_gas_fee = calculate_data_fee(block_env.excess_blob_gas, tx)
Expand All @@ -880,13 +878,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.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.oracle.set_account_balance(
sender, U256(sender_balance_after_gas_fee)
)

access_list_addresses = set()
Expand Down Expand Up @@ -949,26 +947,29 @@ 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.oracle.get_account(sender).balance
sender_balance_after_refund = current_sender_balance + U256(
gas_refund_amount
)
block_env.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.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.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.oracle.account_exists_and_is_empty(block_env.coinbase):
block_env.oracle.destroy_account(block_env.coinbase)

for address in tx_output.accounts_to_delete:
destroy_account(block_env.state, address)
block_env.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 +1009,10 @@ def increase_recipient_balance(recipient: Account) -> None:
rlp.encode(wd),
)

modify_state(block_env.state, wd.address, increase_recipient_balance)
block_env.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.oracle.account_exists_and_is_empty(wd.address):
block_env.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.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.oracle.get_account(tx.to).code
code_address = tx.to
else:
raise AssertionError("Target must be address or empty bytes")
Expand Down
5 changes: 3 additions & 2 deletions src/ethereum/osaka/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@

from ethereum.crypto.hash import Hash32
from ethereum.exceptions import EthereumException
from ethereum.state_oracle import MerkleOracle

from ..blocks import Log, Receipt, Withdrawal
from ..fork_types import Address, Authorization, VersionedHash
from ..state import State, TransientStorage
from ..state import TransientStorage
from ..transactions import LegacyTransaction
from ..trie import Trie

Expand All @@ -38,7 +39,7 @@ class BlockEnvironment:
"""

chain_id: U64
state: State
oracle: MerkleOracle
block_gas_limit: Uint
block_hashes: List[Hash32]
coinbase: Address
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.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.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.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.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.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.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.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