Skip to content

Commit

Permalink
EELS base types and serde
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementWalter committed Nov 11, 2024
1 parent 84e3433 commit 71307ff
Show file tree
Hide file tree
Showing 27 changed files with 1,125 additions and 175 deletions.
68 changes: 68 additions & 0 deletions cairo/ethereum/base_types.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from starkware.cairo.common.dict_access import DictAccess
from starkware.cairo.common.uint256 import Uint256

// Int types
struct bool {
value: felt,
}
struct U64 {
value: felt,
}
struct U128 {
value: felt,
}
struct Uint {
value: felt,
}
struct U256 {
value: Uint256*,
}

// Bytes types
struct Bytes0 {
value: felt,
}
struct Bytes8 {
value: felt,
}
struct Bytes20 {
value: felt,
}
struct Bytes32 {
value: Uint256*,
}
struct Bytes256 {
value: U128*,
}

// Iterables types
struct BytesStruct {
data: felt*,
len: felt,
}

struct Bytes {
value: BytesStruct*,
}
// Some parts of the exec spec use bytes, so just easier to copy/paste
using bytes = Bytes;

// In Cairo, tuples are not a first-class type, so we need to define a custom
// struct to represent a tuple of Bytes32.
struct TupleBytesStruct {
value: Bytes,
len: felt,
}

struct TupleBytes {
value: TupleBytesStruct*,
}

struct TupleBytes32Struct {
value: Bytes32,
len: felt,
}

struct TupleBytes32 {
value: TupleBytes32Struct*,
}
110 changes: 110 additions & 0 deletions cairo/ethereum/cancun/blocks.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from ethereum.base_types import (
U64,
U256,
Bytes,
Bytes8,
Bytes32,
Uint,
TupleBytes32,
bool,
TupleBytes,
)
from ethereum.cancun.fork_types import Address, Bloom, Root
from ethereum.crypto.hash import Hash32

struct WithdrawalStruct {
index: U64,
validator_index: U64,
address: Address,
amount: U256,
}

struct Withdrawal {
value: WithdrawalStruct*,
}

struct TupleWithdrawalStruct {
value: Withdrawal,
len: felt,
}

struct TupleWithdrawal {
value: TupleWithdrawalStruct*,
}

struct HeaderStruct {
parent_hash: Hash32,
ommers_hash: Hash32,
coinbase: Address,
state_root: Root,
transactions_root: Root,
receipt_root: Root,
bloom: Bloom,
difficulty: Uint,
number: Uint,
gas_limit: Uint,
gas_used: Uint,
timestamp: U256,
extra_data: Bytes,
prev_randao: Bytes32,
nonce: Bytes8,
base_fee_per_gas: Uint,
withdrawals_root: Root,
blob_gas_used: U64,
excess_blob_gas: U64,
parent_beacon_block_root: Root,
}

struct Header {
value: HeaderStruct*,
}

struct TupleHeaderStruct {
value: Header,
len: felt,
}

struct TupleHeader {
value: TupleHeaderStruct*,
}

struct BlockStruct {
header: Header,
transactions: TupleBytes,
ommers: TupleHeader,
withdrawals: TupleWithdrawal,
}

struct Block {
value: BlockStruct*,
}

struct LogStruct {
address: Address,
topics: TupleBytes32,
data: Bytes,
}

struct Log {
value: LogStruct*,
}

struct TupleLogStruct {
value: Log,
len: felt,
}

struct TupleLog {
value: TupleLogStruct*,
}

struct ReceiptStruct {
succeeded: bool,
cumulative_gas_used: Uint,
bloom: Bloom,
logs: TupleLog,
}

struct Receipt {
value: ReceiptStruct*,
}
18 changes: 18 additions & 0 deletions cairo/ethereum/cancun/fork_types.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from ethereum.crypto.hash import Hash32
from ethereum.base_types import Bytes20, Bytes256, Uint, U256, Bytes, bytes

using Address = Bytes20;
using Root = Hash32;
using VersionedHash = Hash32;

using Bloom = Bytes256;

struct AccountStruct {
nonce: Uint,
balance: U256,
code: bytes,
}

struct Account {
value: AccountStruct*,
}
6 changes: 6 additions & 0 deletions cairo/ethereum/cancun/transactions.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const TX_BASE_COST = 21000;
const TX_DATA_COST_PER_NON_ZERO = 16;
const TX_DATA_COST_PER_ZERO = 4;
const TX_CREATE_COST = 32000;
const TX_ACCESS_LIST_ADDRESS_COST = 2400;
const TX_ACCESS_LIST_STORAGE_KEY_COST = 1900;
3 changes: 3 additions & 0 deletions cairo/ethereum/crypto/hash.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from ethereum.base_types import Bytes32

using Hash32 = Bytes32;
48 changes: 48 additions & 0 deletions cairo/ethereum/utils/numeric.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from starkware.cairo.common.math_cmp import is_le

func min{range_check_ptr}(a: felt, b: felt) -> felt {
if (a == b) {
return a;
}

let res = is_le(a, b);
if (res == 1) {
return a;
}
return b;
}

// @dev Inlined version of unsigned_div_rem
// Returns q and r such that:
// 0 <= q < rc_bound, 0 <= r < div and value = q * div + r.
//
// Assumption: 0 < div <= PRIME / rc_bound.
// Prover assumption: value / div < rc_bound.
//
// The value of div is restricted to make sure there is no overflow.
// q * div + r < (q + 1) * div <= rc_bound * (PRIME / rc_bound) = PRIME.
func divmod{range_check_ptr}(value, div) -> (q: felt, r: felt) {
let r = [range_check_ptr];
let q = [range_check_ptr + 1];
let range_check_ptr = range_check_ptr + 2;
%{
from starkware.cairo.common.math_utils import assert_integer
assert_integer(ids.div)
assert 0 < ids.div <= PRIME // range_check_builtin.bound, \
f'div={hex(ids.div)} is out of the valid range.'
ids.q, ids.r = divmod(ids.value, ids.div)
%}

// equivalent to assert_le(r, div - 1);
tempvar a = div - 1 - r;
%{
from starkware.cairo.common.math_utils import assert_integer
assert_integer(ids.a)
assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'
%}
a = [range_check_ptr];
let range_check_ptr = range_check_ptr + 1;

assert value = q * div + r;
return (q, r);
}
22 changes: 22 additions & 0 deletions cairo/tests/ethereum/utils/test_numeric.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from ethereum.utils.numeric import min, divmod

func test_min{range_check_ptr}() -> felt {
tempvar a;
tempvar b;
%{
ids.a = program_input["a"]
ids.b = program_input["b"]
%}

return min(a, b);
}

func test_divmod{range_check_ptr}() -> (q: felt, r: felt) {
tempvar value;
tempvar div;
%{
ids.value = program_input["value"]
ids.div = program_input["div"]
%}
return divmod(value, div);
}
20 changes: 20 additions & 0 deletions cairo/tests/ethereum/utils/test_numeric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from hypothesis import given
from hypothesis import strategies as st
from starkware.cairo.lang.instances import PRIME

from tests.utils.strategies import uint128


class TestNumeric:
@given(a=uint128, b=uint128)
def test_min(self, cairo_run, a, b):
assert min(a, b) == cairo_run("test_min", a=a, b=b)

@given(
value=uint128,
div=st.integers(min_value=1, max_value=PRIME // (2**128 - 1) - 1),
)
def test_divmod(self, cairo_run, value, div):
assert list(divmod(value, div)) == cairo_run(
"test_divmod", value=value, div=div
)
14 changes: 1 addition & 13 deletions cairo/tests/fixtures/data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from tests.utils.models import Account, Block, State
from tests.utils.models import Block, State


@pytest.fixture
Expand Down Expand Up @@ -63,18 +63,6 @@ def block():
)


@pytest.fixture
def account():
return Account.model_validate(
{
"balance": "0x00",
"code": "0x7fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf5f527fc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf6020527fe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff60405260786040356020355f35608a565b5f515f55602051600155604051600255005b5e56",
"nonce": "0x01",
"storage": {"0x1": "0xabde1"},
}
)


@pytest.fixture
def state():
return State.model_validate(
Expand Down
20 changes: 12 additions & 8 deletions cairo/tests/fixtures/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import pytest
import starkware.cairo.lang.instances as LAYOUTS
from starkware.cairo.common.dict import DictManager
from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME
from starkware.cairo.lang.compiler.cairo_compile import compile_cairo, get_module_reader
from starkware.cairo.lang.compiler.preprocessor.default_pass_manager import (
Expand All @@ -24,9 +25,8 @@
from starkware.cairo.lang.vm.memory_segments import FIRST_MEMORY_ADDR as PROGRAM_BASE
from starkware.cairo.lang.vm.utils import RunResources

from tests.utils.constants import Opcodes
from tests.utils.coverage import VmWithCoverage
from tests.utils.hints import implement_hints
from tests.utils.hints import gen_arg, implement_hints
from tests.utils.reporting import profile_from_tracer_data
from tests.utils.serde import Serde

Expand Down Expand Up @@ -115,7 +115,7 @@ def _factory(entrypoint, **kwargs):
proof_mode=request.config.getoption("proof_mode"),
allow_missing_builtins=False,
)
serde = Serde(runner)
serde = Serde(runner.segments, cairo_program)

runner.program_base = runner.segments.add()
runner.execution_base = runner.segments.add()
Expand Down Expand Up @@ -156,11 +156,13 @@ def _factory(entrypoint, **kwargs):
)
runner.initial_fp = runner.initial_ap = runner.execution_base + len(stack)

dict_manager = DictManager()

runner.initialize_vm(
hint_locals={"program_input": kwargs},
static_locals={
"serde": serde,
"Opcodes": Opcodes,
hint_locals={
"program_input": kwargs,
"__dict_manager": dict_manager,
"gen_arg": gen_arg(dict_manager, runner.segments),
},
vm_class=VmWithCoverage,
)
Expand Down Expand Up @@ -261,7 +263,9 @@ def _factory(entrypoint, **kwargs):
final_output = None
if add_output:
final_output = serde.serialize_list(output_ptr)
function_output = serde.serialize(return_data.cairo_type)
function_output = serde.serialize(
return_data.cairo_type, runner.vm.run_context.ap
)
if final_output is not None:
function_output = (
function_output
Expand Down
Loading

0 comments on commit 71307ff

Please sign in to comment.