Skip to content
Merged
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
109 changes: 52 additions & 57 deletions src/ethereum/prague/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover
from ethereum.crypto.hash import Hash32, keccak256
from ethereum.exceptions import InvalidBlock
from ethereum.utils.ensure import ensure

from .. import rlp
from ..base_types import U64, U256, Bytes, Uint
Expand Down Expand Up @@ -178,10 +177,12 @@ def state_transition(chain: BlockChain, block: Block) -> None:
"""
parent_header = chain.blocks[-1].header
excess_blob_gas = calculate_excess_blob_gas(parent_header)
ensure(block.header.excess_blob_gas == excess_blob_gas, InvalidBlock)
if block.header.excess_blob_gas != excess_blob_gas:
raise InvalidBlock

validate_header(block.header, parent_header)
ensure(block.ommers == (), InvalidBlock)
if block.ommers != ():
raise InvalidBlock
apply_body_output = apply_body(
chain.state,
get_last_256_block_hashes(chain),
Expand All @@ -197,31 +198,20 @@ def state_transition(chain: BlockChain, block: Block) -> None:
block.header.parent_beacon_block_root,
excess_blob_gas,
)
ensure(
apply_body_output.block_gas_used == block.header.gas_used, InvalidBlock
)
ensure(
apply_body_output.transactions_root == block.header.transactions_root,
InvalidBlock,
)
ensure(
apply_body_output.state_root == block.header.state_root, InvalidBlock
)
ensure(
apply_body_output.receipt_root == block.header.receipt_root,
InvalidBlock,
)
ensure(
apply_body_output.block_logs_bloom == block.header.bloom, InvalidBlock
)
ensure(
apply_body_output.withdrawals_root == block.header.withdrawals_root,
InvalidBlock,
)
ensure(
apply_body_output.blob_gas_used == block.header.blob_gas_used,
InvalidBlock,
)
if apply_body_output.block_gas_used != block.header.gas_used:
raise InvalidBlock
if apply_body_output.transactions_root != block.header.transactions_root:
raise InvalidBlock
if apply_body_output.state_root != block.header.state_root:
raise InvalidBlock
if apply_body_output.receipt_root != block.header.receipt_root:
raise InvalidBlock
if apply_body_output.block_logs_bloom != block.header.bloom:
raise InvalidBlock
if apply_body_output.withdrawals_root != block.header.withdrawals_root:
raise InvalidBlock
if apply_body_output.blob_gas_used != block.header.blob_gas_used:
raise InvalidBlock

chain.blocks.append(block)
if len(chain.blocks) > 255:
Expand Down Expand Up @@ -256,11 +246,8 @@ def calculate_base_fee_per_gas(
Base fee per gas for the block.
"""
parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER

ensure(
check_gas_limit(block_gas_limit, parent_gas_limit),
InvalidBlock,
)
if not check_gas_limit(block_gas_limit, parent_gas_limit):
raise InvalidBlock

if parent_gas_used == parent_gas_target:
expected_base_fee_per_gas = parent_base_fee_per_gas
Expand Down Expand Up @@ -313,27 +300,33 @@ def validate_header(header: Header, parent_header: Header) -> None:
parent_header :
Parent Header of the header to check for correctness
"""
ensure(header.gas_used <= header.gas_limit, InvalidBlock)
if header.gas_used > header.gas_limit:
raise InvalidBlock

expected_base_fee_per_gas = calculate_base_fee_per_gas(
header.gas_limit,
parent_header.gas_limit,
parent_header.gas_used,
parent_header.base_fee_per_gas,
)

ensure(expected_base_fee_per_gas == header.base_fee_per_gas, InvalidBlock)

ensure(header.timestamp > parent_header.timestamp, InvalidBlock)
ensure(header.number == parent_header.number + 1, InvalidBlock)
ensure(len(header.extra_data) <= 32, InvalidBlock)

ensure(header.difficulty == 0, InvalidBlock)
ensure(header.nonce == b"\x00\x00\x00\x00\x00\x00\x00\x00", InvalidBlock)
ensure(header.ommers_hash == EMPTY_OMMER_HASH, InvalidBlock)
if expected_base_fee_per_gas != header.base_fee_per_gas:
raise InvalidBlock
if header.timestamp <= parent_header.timestamp:
raise InvalidBlock
if header.number != parent_header.number + 1:
raise InvalidBlock
if len(header.extra_data) > 32:
raise InvalidBlock
if header.difficulty != 0:
raise InvalidBlock
if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
raise InvalidBlock
if header.ommers_hash != EMPTY_OMMER_HASH:
raise InvalidBlock

block_parent_hash = keccak256(rlp.encode(parent_header))
ensure(header.parent_hash == block_parent_hash, InvalidBlock)
if header.parent_hash != block_parent_hash:
raise InvalidBlock


def check_transaction(
Expand Down Expand Up @@ -423,10 +416,12 @@ def check_transaction(
blob_versioned_hashes = tx.blob_versioned_hashes
else:
blob_versioned_hashes = ()

ensure(sender_account.nonce == tx.nonce, InvalidBlock)
ensure(sender_account.balance >= max_gas_fee + tx.value, InvalidBlock)
ensure(sender_account.code == bytearray(), InvalidBlock)
if sender_account.nonce != tx.nonce:
raise InvalidBlock
if sender_account.balance < max_gas_fee + tx.value:
raise InvalidBlock
if sender_account.code != bytearray():
raise InvalidBlock

return sender, effective_gas_price, blob_versioned_hashes

Expand Down Expand Up @@ -681,8 +676,8 @@ def apply_body(

block_logs += logs
blob_gas_used += calculate_total_blob_gas(tx)

ensure(blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK, InvalidBlock)
if blob_gas_used > MAX_BLOB_GAS_PER_BLOCK:
raise InvalidBlock
block_gas_used = block_gas_limit - gas_available

block_logs_bloom = logs_bloom(block_logs)
Expand Down Expand Up @@ -884,9 +879,10 @@ def recover_sender(chain_id: U64, tx: Transaction) -> Address:
The address of the account that signed the transaction.
"""
r, s = tx.r, tx.s

ensure(0 < r and r < SECP256K1N, InvalidBlock)
ensure(0 < s and s <= SECP256K1N // 2, InvalidBlock)
if 0 >= r or r >= SECP256K1N:
raise InvalidBlock
if 0 >= s or s > SECP256K1N // 2:
raise InvalidBlock

if isinstance(tx, LegacyTransaction):
v = tx.v
Expand All @@ -895,9 +891,8 @@ def recover_sender(chain_id: U64, tx: Transaction) -> Address:
r, s, v - 27, signing_hash_pre155(tx)
)
else:
ensure(
v == 35 + chain_id * 2 or v == 36 + chain_id * 2, InvalidBlock
)
if v != 35 + chain_id * 2 and v != 36 + chain_id * 2:
raise InvalidBlock
public_key = secp256k1_recover(
r, s, v - 35 - chain_id * 2, signing_hash_155(tx, chain_id)
)
Expand Down
4 changes: 2 additions & 2 deletions src/ethereum/prague/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from typing import Callable, Dict, Iterable, List, Optional, Set, Tuple

from ethereum.base_types import U256, Bytes, Uint, modify
from ethereum.utils.ensure import ensure

from .blocks import Withdrawal
from .fork_types import EMPTY_ACCOUNT, Account, Address, Root
Expand Down Expand Up @@ -502,7 +501,8 @@ def move_ether(
"""

def reduce_sender_balance(sender: Account) -> None:
ensure(sender.balance >= amount, AssertionError)
if sender.balance < amount:
raise AssertionError
sender.balance -= amount

def increase_recipient_balance(recipient: Account) -> None:
Expand Down
5 changes: 2 additions & 3 deletions src/ethereum/prague/trie.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

from ethereum.cancun import trie as previous_trie
from ethereum.crypto.hash import keccak256
from ethereum.utils.ensure import ensure
from ethereum.utils.hexadecimal import hex_to_bytes

from .. import rlp
Expand Down Expand Up @@ -349,8 +348,8 @@ def _prepare_trie(
encoded_value = encode_node(value, get_storage_root(address))
else:
encoded_value = encode_node(value)
# Empty values are represented by their absence
ensure(encoded_value != b"", AssertionError)
if encoded_value == b"":
raise AssertionError
key: Bytes
if trie.secured:
# "secure" tries hash keys once before construction
Expand Down
9 changes: 2 additions & 7 deletions src/ethereum/prague/vm/instructions/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from ethereum.base_types import U256, Bytes32, Uint
from ethereum.crypto.hash import keccak256
from ethereum.utils.ensure import ensure
from ethereum.utils.numeric import ceil32

from ...fork_types import EMPTY_ACCOUNT
Expand Down Expand Up @@ -441,12 +440,8 @@ def returndatacopy(evm: Evm) -> None:
evm.memory, [(memory_start_index, size)]
)
charge_gas(evm, GAS_VERY_LOW + copy_gas_cost + extend_memory.cost)

# OPERATION
ensure(
Uint(return_data_start_position) + Uint(size) <= len(evm.return_data),
OutOfBoundsRead,
)
if Uint(return_data_start_position) + Uint(size) > len(evm.return_data):
raise OutOfBoundsRead

evm.memory += b"\x00" * extend_memory.expand_by
value = evm.return_data[
Expand Down
4 changes: 2 additions & 2 deletions src/ethereum/prague/vm/instructions/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from functools import partial

from ethereum.base_types import U256
from ethereum.utils.ensure import ensure

from ...blocks import Log
from .. import Evm
Expand Down Expand Up @@ -68,7 +67,8 @@ def log_n(evm: Evm, num_topics: U256) -> None:

# OPERATION
evm.memory += b"\x00" * extend_memory.expand_by
ensure(not evm.message.is_static, WriteInStaticContext)
if evm.message.is_static:
raise WriteInStaticContext
log_entry = Log(
address=evm.message.current_target,
topics=tuple(topics),
Expand Down
11 changes: 4 additions & 7 deletions src/ethereum/prague/vm/instructions/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from functools import partial

from ethereum.base_types import U256
from ethereum.utils.ensure import ensure

from .. import Evm, stack
from ..exceptions import StackUnderflowError
Expand Down Expand Up @@ -98,9 +97,8 @@ def dup_n(evm: Evm, item_number: int) -> None:

# GAS
charge_gas(evm, GAS_VERY_LOW)

# OPERATION
ensure(item_number < len(evm.stack), StackUnderflowError)
if item_number >= len(evm.stack):
raise StackUnderflowError
data_to_duplicate = evm.stack[len(evm.stack) - 1 - item_number]
stack.push(evm.stack, data_to_duplicate)

Expand Down Expand Up @@ -131,9 +129,8 @@ def swap_n(evm: Evm, item_number: int) -> None:

# GAS
charge_gas(evm, GAS_VERY_LOW)

# OPERATION
ensure(item_number < len(evm.stack), StackUnderflowError)
if item_number >= len(evm.stack):
raise StackUnderflowError
evm.stack[-1], evm.stack[-1 - item_number] = (
evm.stack[-1 - item_number],
evm.stack[-1],
Expand Down
16 changes: 6 additions & 10 deletions src/ethereum/prague/vm/instructions/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
Implementations of the EVM storage related instructions.
"""
from ethereum.base_types import Uint
from ethereum.utils.ensure import ensure

from ...state import (
get_storage,
Expand Down Expand Up @@ -78,9 +77,8 @@ def sstore(evm: Evm) -> None:
# STACK
key = pop(evm.stack).to_be_bytes32()
new_value = pop(evm.stack)

# GAS
ensure(evm.gas_left > GAS_CALL_STIPEND, OutOfGasError)
if evm.gas_left <= GAS_CALL_STIPEND:
raise OutOfGasError

original_value = get_storage_original(
evm.env.state, evm.message.current_target, key
Expand Down Expand Up @@ -123,9 +121,8 @@ def sstore(evm: Evm) -> None:
)

charge_gas(evm, gas_cost)

# OPERATION
ensure(not evm.message.is_static, WriteInStaticContext)
if evm.message.is_static:
raise WriteInStaticContext
set_storage(evm.env.state, evm.message.current_target, key, new_value)

# PROGRAM COUNTER
Expand Down Expand Up @@ -171,9 +168,8 @@ def tstore(evm: Evm) -> None:

# GAS
charge_gas(evm, GAS_WARM_ACCESS)

# OPERATION
ensure(not evm.message.is_static, WriteInStaticContext)
if evm.message.is_static:
raise WriteInStaticContext
set_transient_storage(
evm.env.transient_storage, evm.message.current_target, key, new_value
)
Expand Down
19 changes: 8 additions & 11 deletions src/ethereum/prague/vm/instructions/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
Implementations of the EVM system related instructions.
"""
from ethereum.base_types import U256, Bytes0, Uint
from ethereum.utils.ensure import ensure
from ethereum.utils.numeric import ceil32

from ...fork_types import Address
Expand Down Expand Up @@ -79,15 +78,15 @@ def generic_create(
call_data = memory_read_bytes(
evm.memory, memory_start_position, memory_size
)

ensure(len(call_data) <= 2 * MAX_CODE_SIZE, OutOfGasError)
if len(call_data) > 2 * MAX_CODE_SIZE:
raise OutOfGasError

evm.accessed_addresses.add(contract_address)

create_message_gas = max_message_call_gas(Uint(evm.gas_left))
evm.gas_left -= create_message_gas

ensure(not evm.message.is_static, WriteInStaticContext)
if evm.message.is_static:
raise WriteInStaticContext
evm.return_data = b""

sender_address = evm.message.current_target
Expand Down Expand Up @@ -376,9 +375,8 @@ def call(evm: Evm) -> None:
access_gas_cost + create_gas_cost + transfer_gas_cost,
)
charge_gas(evm, message_call_gas.cost + extend_memory.cost)

# OPERATION
ensure(not evm.message.is_static or value == U256(0), WriteInStaticContext)
if evm.message.is_static and value != U256(0):
raise WriteInStaticContext
evm.memory += b"\x00" * extend_memory.expand_by
sender_balance = get_account(
evm.env.state, evm.message.current_target
Expand Down Expand Up @@ -506,9 +504,8 @@ def selfdestruct(evm: Evm) -> None:
gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT

charge_gas(evm, gas_cost)

# OPERATION
ensure(not evm.message.is_static, WriteInStaticContext)
if evm.message.is_static:
raise WriteInStaticContext

originator = evm.message.current_target
originator_balance = get_account(evm.env.state, originator).balance
Expand Down
Loading