Skip to content

Commit

Permalink
Run txs in os (kkrt-labs#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementWalter authored Nov 27, 2024
1 parent d7d0240 commit 896f526
Show file tree
Hide file tree
Showing 50 changed files with 781 additions and 425 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/python_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ jobs:
with:
enable-cache: true
cache-dependency-glob: uv.lock

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- run: |
cd cairo
uv run compile
forge build
uv run pytest -n logical --junitxml=junit.xml -o junit_family=legacy
- uses: codecov/[email protected]
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/trunk_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ jobs:
cache: pip
- run: pip install cairo-lang==0.13.2 sympy==1.11.1

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Trunk Check
uses: trunk-io/trunk-action@v1
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ cairo/tests/ef_tests/test_data

# Ide settings
.vscode/

cache
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[submodule "solidity_contracts/lib/forge-std"]
path = solidity_contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std.git
[submodule "solidity_contracts/lib/solmate"]
path = solidity_contracts/lib/solmate
url = https://github.com/transmissions11/solmate
[submodule "solidity_contracts/lib/openzeppelin-contracts"]
path = solidity_contracts/lib/openzeppelin-contracts
url = https://github.com/Openzeppelin/openzeppelin-contracts
3 changes: 3 additions & 0 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ downloads:
- os: linux
url: https://static.rust-lang.org/dist/2024-10-31/rust-nightly-x86_64-unknown-linux-gnu.tar.gz
strip_components: 2
- os: macos
url: https://static.rust-lang.org/dist/2024-10-31/rust-nightly-x86_64-apple-darwin.tar.gz
strip_components: 2
# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
lint:
disabled:
Expand Down
95 changes: 84 additions & 11 deletions cairo/programs/os.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ from starkware.cairo.common.cairo_builtins import (
)
from starkware.cairo.common.math import assert_le, assert_nn
from starkware.cairo.common.bool import FALSE
from starkware.cairo.common.math_cmp import is_not_zero
from starkware.cairo.common.uint256 import Uint256

from src.model import model
from src.utils.transaction import Transaction
from src.state import State
from src.instructions.system_operations import CreateHelper
from src.interpreter import Interpreter

func main{
func os{
output_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
Expand All @@ -27,25 +31,22 @@ func main{
range_check96_ptr: felt*,
add_mod_ptr: ModBuiltin*,
mul_mod_ptr: ModBuiltin*,
}() {
}() -> model.State* {
alloc_locals;
%{ dict_manager %}
local block: model.Block*;
local state: model.State*;
local chain_id: felt;
local block_hashes: Uint256*;
%{ block %}
// TODO: Validate header
%{ state %}
%{ chain_id %}
// TODO: Compute initial state root hash and compare with block.parent_hash
// TODO: Loop through transactions and apply them to the initial state
%{ chain_id %}
%{ block_hashes %}

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.value;
let range_check_ptr = range_check_ptr + 3;

with header, chain_id, state {
with header, chain_id, state, block_hashes {
apply_transactions(block.transactions_len, block.transactions);
}

Expand All @@ -54,7 +55,7 @@ func main{

// TODO: Compare the final state root hash with block.state_root
end:
return ();
return state;
}

func apply_transactions{
Expand All @@ -63,6 +64,7 @@ func apply_transactions{
range_check_ptr,
keccak_ptr: KeccakBuiltin*,
header: model.BlockHeader*,
block_hashes: Uint256*,
chain_id: felt,
state: model.State*,
}(txs_len: felt, tx_encoded: model.TransactionEncoded*) {
Expand Down Expand Up @@ -114,5 +116,76 @@ func apply_transactions{
assert_le(tx.max_priority_fee_per_gas, tx.max_fee_per_gas);
}

let is_regular_tx = is_not_zero(tx.destination.is_some);

let is_deploy_tx = 1 - is_regular_tx;
let evm_contract_address = resolve_to(tx.destination, tx_encoded.sender, tx.signer_nonce);
let code_account = State.get_account(evm_contract_address);
tempvar env = new model.Environment(
origin=tx_encoded.sender,
gas_price=tx.max_fee_per_gas,
chain_id=chain_id,
prev_randao=header.mix_hash,
block_number=header.number,
block_gas_limit=header.gas_limit,
block_timestamp=header.timestamp,
coinbase=header.coinbase,
base_fee=header.base_fee_per_gas.value,
block_hashes=block_hashes,
);

Interpreter.execute(
env,
evm_contract_address,
is_deploy_tx,
code_account.code_len,
code_account.code,
tx.payload_len,
tx.payload,
&tx.amount,
tx.gas_limit,
tx.access_list_len,
tx.access_list,
);

return apply_transactions(txs_len - 1, tx_encoded + model.TransactionEncoded.SIZE);
}

// @notice Get the EVM address from the transaction
// @dev When to=None, it's a deploy tx so we first compute the target address
// @param to The transaction to parameter
// @param origin The transaction origin parameter
// @param nonce The transaction nonce parameter, used to compute the target address if it's a deploy tx
// @return the target evm address
func resolve_to{
pedersen_ptr: HashBuiltin*,
range_check_ptr,
bitwise_ptr: BitwiseBuiltin*,
keccak_ptr: KeccakBuiltin*,
}(to: model.Option, origin: felt, nonce: felt) -> felt {
alloc_locals;
if (to.is_some != 0) {
return to.value;
}
let (local evm_contract_address) = CreateHelper.get_create_address(origin, nonce);
return evm_contract_address;
}

// @notice The main function for the os program
func main{
output_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
ecdsa_ptr,
bitwise_ptr: BitwiseBuiltin*,
ec_op_ptr,
keccak_ptr: KeccakBuiltin*,
poseidon_ptr: PoseidonBuiltin*,
range_check96_ptr: felt*,
add_mod_ptr: ModBuiltin*,
mul_mod_ptr: ModBuiltin*,
}() {
os();

return ();
}
2 changes: 2 additions & 0 deletions cairo/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ dependencies = [
"ethereum",
"marshmallow-dataclass>=8.6.1",
"python-dotenv>=1.0.1",
"toml>=0.10.2",
"web3>=7.2.0",
]

[project.scripts]
Expand Down
18 changes: 5 additions & 13 deletions cairo/src/account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ from starkware.cairo.common.hash_state import (
from starkware.cairo.lang.compiler.lib.registers import get_ap
from starkware.cairo.common.find_element import find_element

from src.interfaces.interfaces import ICairo1Helpers
from src.model import model
from src.utils.dict import dict_copy, dict_squash
from src.utils.utils import Helpers
Expand Down Expand Up @@ -151,23 +150,16 @@ namespace Account {
return (self, value_ptr);
}

// @notive Read the first value of a given storage slot
// @notice Read the first value of a given storage slot
// @dev The storage needs to exists already, to this should be used only
// after a storage_read or storage_write has been done
func fetch_original_storage{pedersen_ptr: HashBuiltin*}(
self: model.Account*, key: Uint256*
) -> Uint256 {
alloc_locals;
let storage = self.storage;
let (local storage_addr) = Internals._storage_addr(key);

let (pointer) = dict_read{dict_ptr=storage}(key=storage_addr);
local value_ptr: Uint256*;
if (pointer != 0) {
assert value_ptr = cast(pointer, Uint256*);
} else {
assert value_ptr = new Uint256(0, 0);
}
// TODO: Fetch from parent account
tempvar value = Uint256(0, 0);
return value;
}

// @notice Update a storage key with the given value
Expand Down Expand Up @@ -275,7 +267,7 @@ namespace Account {
// @param code_len The len of the code
// @param code The code array
// @return The updated Account with the code and valid jumpdests set
func set_code{pedersen_ptr: HashBuiltin*, range_check_ptr}(
func set_code{range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin*}(
self: model.Account*, code_len: felt, code: felt*
) -> model.Account* {
alloc_locals;
Expand Down
1 change: 0 additions & 1 deletion cairo/src/evm.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ from src.model import model
from src.account import Account
from src.stack import Stack
from src.state import State
from src.interfaces.interfaces import IAccount

// @title EVM related functions.
// @notice This file contains functions related to the execution context.
Expand Down
41 changes: 23 additions & 18 deletions cairo/src/instructions/block_information.cairo
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from starkware.cairo.common.bool import FALSE
from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin
from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin, KeccakBuiltin
from starkware.cairo.common.math import split_felt
from starkware.cairo.common.math_cmp import is_in_range
from starkware.cairo.common.uint256 import Uint256

from src.constants import Constants
from src.evm import EVM
from src.interfaces.interfaces import ICairo1Helpers
from src.model import model
from src.stack import Stack
from src.state import State
Expand All @@ -19,6 +18,7 @@ namespace BlockInformation {
pedersen_ptr: HashBuiltin*,
range_check_ptr,
bitwise_ptr: BitwiseBuiltin*,
keccak_ptr: KeccakBuiltin*,
stack: model.Stack*,
memory: model.Memory*,
state: model.State*,
Expand All @@ -41,29 +41,31 @@ namespace BlockInformation {
jmp blobbasefee;

blockhash:
let pedersen_ptr = cast([fp - 9], HashBuiltin*);
let range_check_ptr = [fp - 8];
let range_check_ptr = [fp - 9];
let stack = cast([fp - 6], model.Stack*);
let evm = cast([fp - 3], model.EVM*);
Internals.blockhash(evm);

// Rebind unused args with fp
let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*);
let pedersen_ptr = cast([fp - 10], HashBuiltin*);
let bitwise_ptr = cast([fp - 8], BitwiseBuiltin*);
let keccak_ptr = cast([fp - 7], KeccakBuiltin*);
let memory = cast([fp - 5], model.Memory*);
let state = cast([fp - 4], model.State*);
return evm;

coinbase:
let evm = cast([fp - 3], model.EVM*);
let stack = cast([fp - 6], model.Stack*);
let range_check_ptr = [fp - 8];
let range_check_ptr = [fp - 9];
let (coinbase_high, coinbase_low) = split_felt(evm.message.env.coinbase);
tempvar coinbase_u256 = Uint256(low=coinbase_low, high=coinbase_high);
Stack.push_uint256(coinbase_u256);

// Rebind unused args with fp
let pedersen_ptr = cast([fp - 9], HashBuiltin*);
let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*);
let pedersen_ptr = cast([fp - 10], HashBuiltin*);
let bitwise_ptr = cast([fp - 8], BitwiseBuiltin*);
let keccak_ptr = cast([fp - 7], KeccakBuiltin*);
let memory = cast([fp - 5], model.Memory*);
let state = cast([fp - 4], model.State*);
return evm;
Expand Down Expand Up @@ -99,15 +101,16 @@ namespace BlockInformation {
jmp end;

selfbalance:
let pedersen_ptr = cast([fp - 9], HashBuiltin*);
let range_check_ptr = [fp - 8];
let pedersen_ptr = cast([fp - 10], HashBuiltin*);
let range_check_ptr = [fp - 9];
let stack = cast([fp - 6], model.Stack*);
let state = cast([fp - 4], model.State*);
let evm = cast([fp - 3], model.EVM*);
Internals.selfbalance(evm);

// Rebind unused args with fp
let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*);
let bitwise_ptr = cast([fp - 8], BitwiseBuiltin*);
let keccak_ptr = cast([fp - 7], KeccakBuiltin*);
let memory = cast([fp - 5], model.Memory*);
return evm;

Expand All @@ -130,9 +133,10 @@ namespace BlockInformation {

end:
// Rebind unused args with fp
let pedersen_ptr = cast([fp - 9], HashBuiltin*);
let range_check_ptr = [fp - 8];
let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*);
let pedersen_ptr = cast([fp - 10], HashBuiltin*);
let range_check_ptr = [fp - 9];
let bitwise_ptr = cast([fp - 8], BitwiseBuiltin*);
let keccak_ptr = cast([fp - 7], KeccakBuiltin*);
let memory = cast([fp - 5], model.Memory*);
let state = cast([fp - 4], model.State*);
let evm = cast([fp - 3], model.EVM*);
Expand All @@ -145,7 +149,7 @@ namespace BlockInformation {
}

namespace Internals {
func blockhash{}(evm: model.EVM*) {
func blockhash{range_check_ptr, stack: model.Stack*}(evm: model.EVM*) {
let (block_number) = Stack.pop();
if (block_number.high != 0) {
Stack.push_uint256(Uint256(0, 0));
Expand All @@ -160,9 +164,10 @@ namespace Internals {
return ();
}

let (blockhash) = ICairo1Helpers.get_block_hash(implementation, block_number.low);
let (blockhash_high, blockhash_low) = split_felt(blockhash);
Stack.push_uint256(Uint256(low=blockhash_low, high=blockhash_high));
let block_hashes = evm.message.env.block_hashes[
evm.message.env.block_number - block_number.low
];
Stack.push_uint256(block_hashes);
return ();
}

Expand Down
3 changes: 2 additions & 1 deletion cairo/src/instructions/duplication_operations.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin
from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin, KeccakBuiltin

from src.model import model
from src.stack import Stack
Expand All @@ -14,6 +14,7 @@ namespace DuplicationOperations {
pedersen_ptr: HashBuiltin*,
range_check_ptr,
bitwise_ptr: BitwiseBuiltin*,
keccak_ptr: KeccakBuiltin*,
stack: model.Stack*,
memory: model.Memory*,
state: model.State*,
Expand Down
Loading

0 comments on commit 896f526

Please sign in to comment.