Skip to content

Commit

Permalink
Fix header fields
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementWalter committed Oct 3, 2024
1 parent cb51078 commit 03ff3fa
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 68 deletions.
4 changes: 2 additions & 2 deletions cairo/programs/os.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func main{
let header = block.block_header;
assert [range_check_ptr] = header.gas_limit;
assert [range_check_ptr + 1] = header.gas_used;
assert [range_check_ptr + 2] = header.base_fee_per_gas;
assert [range_check_ptr + 2] = header.base_fee_per_gas.value;
let range_check_ptr = range_check_ptr + 3;

with header, chain_id, state {
Expand Down Expand Up @@ -105,7 +105,7 @@ func apply_transactions{
}

with_attr error_message("Max fee per gas too low") {
assert_nn(tx.max_fee_per_gas - header.base_fee_per_gas);
assert_nn(tx.max_fee_per_gas - header.base_fee_per_gas.value);
}

with_attr error_message("Max priority fee greater than max fee per gas") {
Expand Down
35 changes: 17 additions & 18 deletions cairo/src/model.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -213,29 +213,28 @@ namespace model {

// @notice A struct representing the header of an Eth block.
struct BlockHeader {
base_fee_per_gas: felt,
blob_gas_used: felt,
bloom_len: felt,
bloom: felt*,
parent_hash: Uint256,
ommers_hash: Uint256,
coinbase: felt,
difficulty: felt,
excess_blob_gas: felt,
extra_data_len: felt,
extra_data: felt*,
state_root: Uint256,
transactions_root: Uint256,
receipt_root: Uint256,
withdrawals_root: Uint256,
bloom: felt*,
difficulty: Uint256,
number: felt,
gas_limit: felt,
gas_used: felt,
hash: Uint256,
timestamp: felt,
mix_hash: Uint256,
nonce: felt,
number: felt,
parent_beacon_block_root: Uint256,
parent_hash: Uint256,
receipt_trie: Uint256,
state_root: Uint256,
timestamp: felt,
transactions_trie: Uint256,
uncle_hash: Uint256,
withdrawals_root: Uint256,
base_fee_per_gas: Option,
blob_gas_used: Option,
excess_blob_gas: Option,
parent_beacon_block_root: Option,
requests_root: Option,
extra_data_len: felt,
extra_data: felt*,
}

// @notice A struct representing an encoded Ethereum transaction.
Expand Down
5 changes: 2 additions & 3 deletions cairo/tests/test_serde.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from src.utils.uint256 import int_to_uint256
from tests.utils.models import Account, Block, to_int
from tests.utils.models import Account, to_int


class TestSerde:

def test_block(self, cairo_run, block):
result = cairo_run("test_block", block=block)
assert Block.model_validate(result) == block
cairo_run("test_block", block=block)

def test_account(self, cairo_run, account):
result = cairo_run("test_account", account=account)
Expand Down
111 changes: 69 additions & 42 deletions cairo/tests/utils/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections import defaultdict
from itertools import chain
from textwrap import wrap
from typing import Annotated, DefaultDict, Tuple, Union

from eth_utils import keccak
Expand All @@ -13,7 +14,7 @@
field_validator,
model_validator,
)
from pydantic.alias_generators import to_camel
from pydantic.alias_generators import to_camel, to_snake
from starkware.cairo.lang.vm.crypto import pedersen_hash

from src.utils.uint256 import int_to_uint256
Expand Down Expand Up @@ -41,38 +42,29 @@ def __iter__(self):

class BlockHeader(BaseModelIterValuesOnly):
@field_validator(
"base_fee_per_gas",
"blob_gas_used",
"coinbase",
"difficulty",
"excess_blob_gas",
"number",
"gas_limit",
"gas_used",
"nonce",
"number",
"timestamp",
"nonce",
mode="before",
)
def parse_hex_to_int(cls, v):
return to_int(v)

@field_validator("extra_data", "bloom", mode="before")
def parse_hex_to_bytes(cls, v):
return to_bytes(v)

@model_validator(mode="before")
def split_uint256(cls, values):
values = values.copy()
for key in [
"hash",
"mix_hash",
"parent_beacon_block_root",
"parent_hash",
"receipt_trie",
"uncle_hash",
"state_root",
"transactions_trie",
"uncle_hash",
"receipt_trie",
"withdrawals_root",
"difficulty",
"mix_hash",
]:
if key not in values:
key = to_camel(key)
Expand All @@ -85,51 +77,86 @@ def split_uint256(cls, values):
return values

@model_validator(mode="before")
def add_len_to_bytes(cls, values):
def split_option(cls, values):
values = values.copy()
for key in ["bloom", "extra_data"]:
for key in [
"base_fee_per_gas",
"blob_gas_used",
"excess_blob_gas",
"parent_beacon_block_root",
"requests_root",
]:
if key not in values:
key = to_camel(key)
is_some = key in values
value = to_int(values.get(key, 0))
values[to_camel(key) + "IsSome"] = is_some
value_type = cls.model_fields[to_snake(key) + "_value"].annotation
values[to_camel(key) + "Value"] = (
int_to_uint256(value) if value_type == Tuple[int, int] else value
)
return values

@model_validator(mode="before")
def add_len_to_extra_data(cls, values):
values = values.copy()
for key in ["extra_data"]:
if key not in values:
key = to_camel(key)
if key not in values:
continue

value = to_bytes(values[key])
if value is None:
continue
values[key] = value
values[to_camel(key) + "Len"] = len(value)
return values

base_fee_per_gas: int
blob_gas_used: int
bloom_len: int
bloom: bytes
coinbase: int
difficulty: int
excess_blob_gas: int
extra_data_len: int
extra_data: bytes
gas_limit: int
gas_used: int
hash_low: int
hash_high: int
mix_hash_low: int
mix_hash_high: int
nonce: int
number: int
parent_beacon_block_root_low: int
parent_beacon_block_root_high: int
@field_validator("bloom", mode="before")
def parse_bloom(cls, v):
bloom = to_bytes(v)
if bloom is None:
raise ValueError("Bloom cannot be empty")
if len(bloom) != 256:
raise ValueError("Bloom must be 256 bytes")
return tuple(int(chunk) for chunk in wrap(bloom.hex(), 32))

parent_hash_low: int
parent_hash_high: int
receipt_trie_low: int
receipt_trie_high: int
uncle_hash_low: int
uncle_hash_high: int
coinbase: int
state_root_low: int
state_root_high: int
timestamp: int
transactions_trie_low: int
transactions_trie_high: int
uncle_hash_low: int
uncle_hash_high: int
receipt_trie_low: int
receipt_trie_high: int
withdrawals_root_low: int
withdrawals_root_high: int
bloom: Tuple[int, ...]
difficulty_low: int
difficulty_high: int
number: int
gas_limit: int
gas_used: int
timestamp: int
mix_hash_low: int
mix_hash_high: int
nonce: int
base_fee_per_gas_is_some: bool
base_fee_per_gas_value: int
blob_gas_used_is_some: bool
blob_gas_used_value: int
excess_blob_gas_is_some: bool
excess_blob_gas_value: int
parent_beacon_block_root_is_some: bool
parent_beacon_block_root_value: Tuple[int, int]
requests_root_is_some: bool
requests_root_value: Tuple[int, int]
extra_data_len: int
extra_data: bytes


class TransactionEncoded(BaseModelIterValuesOnly):
Expand Down
10 changes: 7 additions & 3 deletions cairo/tests/utils/parsers.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
from typing import Union
from typing import Optional, Union


def to_int(v: Union[str, int]) -> int:
def to_int(v: Optional[Union[str, int]]) -> Optional[int]:
if v is None:
return v
if isinstance(v, str):
if v.startswith("0x"):
return int(v, 16)
return int(v)
return v


def to_bytes(v: Union[str, bytes, list[int]]) -> bytes:
def to_bytes(v: Optional[Union[str, bytes, list[int]]]) -> Optional[bytes]:
if v is None:
return v
if isinstance(v, bytes):
return v
elif isinstance(v, str):
Expand Down

0 comments on commit 03ff3fa

Please sign in to comment.