Merge pull request #838 from mir-protocol/transfer_test

Fixes to get test_simple_transfer working
This commit is contained in:
Daniel Lubarov 2022-12-08 23:47:58 -08:00 committed by GitHub
commit 4ae1d840a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 607 additions and 96 deletions

View File

@ -142,14 +142,14 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
let mut dummy_yield_constr = ConstraintConsumer::new(vec![], P::ZEROS, P::ZEROS, P::ZEROS);
bootstrap_kernel::eval_bootstrap_kernel(vars, yield_constr);
control_flow::eval_packed_generic(local_values, next_values, yield_constr);
decode::eval_packed_generic(local_values, yield_constr);
decode::eval_packed_generic(local_values, &mut dummy_yield_constr);
dup_swap::eval_packed(local_values, yield_constr);
jumps::eval_packed(local_values, next_values, &mut dummy_yield_constr);
membus::eval_packed(local_values, yield_constr);
modfp254::eval_packed(local_values, yield_constr);
shift::eval_packed(local_values, yield_constr);
simple_logic::eval_packed(local_values, yield_constr);
stack::eval_packed(local_values, yield_constr);
stack::eval_packed(local_values, &mut dummy_yield_constr);
stack_bounds::eval_packed(local_values, &mut dummy_yield_constr);
syscalls::eval_packed(local_values, next_values, yield_constr);
}
@ -168,14 +168,14 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
RecursiveConstraintConsumer::new(zero, vec![], zero, zero, zero);
bootstrap_kernel::eval_bootstrap_kernel_circuit(builder, vars, yield_constr);
control_flow::eval_ext_circuit(builder, local_values, next_values, yield_constr);
decode::eval_ext_circuit(builder, local_values, yield_constr);
decode::eval_ext_circuit(builder, local_values, &mut dummy_yield_constr);
dup_swap::eval_ext_circuit(builder, local_values, yield_constr);
jumps::eval_ext_circuit(builder, local_values, next_values, &mut dummy_yield_constr);
membus::eval_ext_circuit(builder, local_values, yield_constr);
modfp254::eval_ext_circuit(builder, local_values, yield_constr);
shift::eval_ext_circuit(builder, local_values, yield_constr);
simple_logic::eval_ext_circuit(builder, local_values, yield_constr);
stack::eval_ext_circuit(builder, local_values, yield_constr);
stack::eval_ext_circuit(builder, local_values, &mut dummy_yield_constr);
stack_bounds::eval_ext_circuit(builder, local_values, &mut dummy_yield_constr);
syscalls::eval_ext_circuit(builder, local_values, next_values, yield_constr);
}

View File

@ -44,6 +44,7 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/memory/memcpy.asm"),
include_str!("asm/memory/metadata.asm"),
include_str!("asm/memory/packing.asm"),
include_str!("asm/memory/syscalls.asm"),
include_str!("asm/memory/txn_fields.asm"),
include_str!("asm/mpt/accounts.asm"),
include_str!("asm/mpt/delete/delete.asm"),
@ -67,8 +68,9 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/ripemd/main.asm"),
include_str!("asm/ripemd/memory.asm"),
include_str!("asm/ripemd/update.asm"),
include_str!("asm/rlp/encode.asm"),
include_str!("asm/rlp/decode.asm"),
include_str!("asm/rlp/encode.asm"),
include_str!("asm/rlp/encode_rlp_string.asm"),
include_str!("asm/rlp/num_bytes.asm"),
include_str!("asm/rlp/read_to_memory.asm"),
include_str!("asm/sha2/compression.asm"),

View File

@ -4,7 +4,7 @@ global balance:
// stack: account_ptr, retdest
DUP1 ISZERO %jumpi(retzero) // If the account pointer is null, return 0.
%add_const(1)
// stack: balance_ptr
// stack: balance_ptr, retdest
%mload_trie_data
// stack: balance, retdest
SWAP1 JUMP

View File

@ -45,7 +45,9 @@ global delegate_call:
-> (0, 0, value, sender, self, address, gas)
%jump(call_common)
call_common:
// Pre stack: static, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
// Post stack: success, leftover_gas
global call_common:
// stack: static, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
%create_context
// Store the static flag in metadata.
@ -108,3 +110,4 @@ after_call:
// stack: new_ctx, ret_offset, ret_size, retdest
// TODO: Set RETURNDATA.
// TODO: Return to caller w/ EXIT_KERNEL.
// TODO: Return leftover gas

View File

@ -5,6 +5,7 @@
global get_nonce:
// stack: address, retdest
// TODO: Replace with actual implementation.
POP
JUMP
// Convenience macro to call get_nonce and return where we left off.

View File

@ -3,39 +3,58 @@
// TODO: Save checkpoints in @CTX_METADATA_STATE_TRIE_CHECKPOINT_PTR and @SEGMENT_STORAGE_TRIE_CHECKPOINT_PTRS.
// Pre stack: retdest
// Post stack: (empty)
global process_normalized_txn:
// stack: (empty)
// stack: retdest
PUSH validate
%jump(intrinsic_gas)
validate:
// stack: intrinsic_gas
// TODO: Check gas >= intrinsic_gas.
// TODO: Check sender_balance >= intrinsic_gas + value.
global validate:
// stack: intrinsic_gas, retdest
// TODO: Check signature? (Or might happen in type_0.asm etc.)
// TODO: Assert nonce is correct.
// TODO: Assert sender has no code.
POP // TODO: Assert gas_limit >= intrinsic_gas.
// stack: retdest
buy_gas:
// TODO: Deduct gas from sender (some may be refunded later).
global charge_gas:
// TODO: Deduct gas limit from sender (some gas may be refunded later).
increment_nonce:
// TODO: Increment nonce.
PUSH 0 // TODO: Push sender.
%increment_nonce
process_based_on_type:
global process_based_on_type:
%is_contract_creation
%jumpi(process_contract_creation_txn)
%jump(process_message_txn)
process_contract_creation_txn:
// stack: (empty)
global process_contract_creation_txn:
// stack: retdest
// Push the code address & length onto the stack, then call `create`.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
// stack: code_len
// stack: code_len, retdest
PUSH 0
// stack: code_offset, code_len
// stack: code_offset, code_len, retdest
PUSH @SEGMENT_TXN_DATA
// stack: code_segment, code_offset, code_len
// stack: code_segment, code_offset, code_len, retdest
PUSH 0 // context
// stack: CODE_ADDR, code_len
// stack: CODE_ADDR, code_len, retdest
%jump(create)
process_message_txn:
// TODO
global process_message_txn:
// stack: retdest
%mload_txn_field(@TXN_FIELD_VALUE)
%mload_txn_field(@TXN_FIELD_TO)
%mload_txn_field(@TXN_FIELD_ORIGIN)
// stack: from, to, amount, retdest
%transfer_eth
// stack: transfer_eth_status, retdest
%jumpi(process_message_txn_insufficient_balance)
// stack: retdest
// TODO: If code is non-empty, execute it in a new context.
JUMP
global process_message_txn_insufficient_balance:
// stack: retdest
PANIC // TODO

View File

@ -7,7 +7,6 @@ global sys_signextend:
global sys_slt:
global sys_sgt:
global sys_sar:
global sys_keccak256:
global sys_address:
global sys_balance:
global sys_origin:
@ -33,9 +32,6 @@ global sys_gaslimit:
global sys_chainid:
global sys_selfbalance:
global sys_basefee:
global sys_mload:
global sys_mstore:
global sys_mstore8:
global sys_sload:
global sys_sstore:
global sys_msize:

View File

@ -1,15 +1,20 @@
// Transfers some ETH from one address to another. The amount is given in wei.
// Pre stack: from, to, amount, retdest
// Post stack: (empty)
// Post stack: status (0 indicates success)
global transfer_eth:
// stack: from, to, amount, retdest
%stack (from, to, amount, retdest)
-> (from, amount, to, amount)
-> (from, amount, to, amount, retdest)
%deduct_eth
// TODO: Handle exception from %deduct_eth?
// stack: deduct_eth_status, to, amount, retdest
%jumpi(transfer_eth_failure)
// stack: to, amount, retdest
%add_eth
// stack: retdest
global transfer_eth_3:
%stack (retdest) -> (retdest, 0)
JUMP
global transfer_eth_failure:
%stack (to, amount, retdest) -> (retdest, 1)
JUMP
// Convenience macro to call transfer_eth and return where we left off.
@ -31,11 +36,31 @@ global transfer_eth:
%%after:
%endmacro
// Returns 0 on success, or 1 if addr has insufficient balance. Panics if addr isn't found in the trie.
// Pre stack: addr, amount, retdest
// Post stack: status (0 indicates success)
global deduct_eth:
// stack: addr, amount, retdest
%jump(mpt_read_state_trie)
deduct_eth_after_read:
PANIC // TODO
%mpt_read_state_trie
// stack: account_ptr, amount, retdest
DUP1 ISZERO %jumpi(panic) // If the account pointer is null, return 0.
%add_const(1)
// stack: balance_ptr, amount, retdest
DUP1 %mload_trie_data
// stack: balance, balance_ptr, amount, retdest
DUP1 DUP4 GT
// stack: amount > balance, balance, balance_ptr, amount, retdest
%jumpi(deduct_eth_insufficient_balance)
%stack (balance, balance_ptr, amount, retdest) -> (balance, amount, balance_ptr, retdest, 0)
SUB
SWAP1
// stack: balance_ptr, balance - amount, retdest, 0
%mstore_trie_data
// stack: retdest, 0
JUMP
global deduct_eth_insufficient_balance:
%stack (balance, balance_ptr, amount, retdest) -> (retdest, 1)
JUMP
// Convenience macro to call deduct_eth and return where we left off.
%macro deduct_eth
@ -44,8 +69,40 @@ deduct_eth_after_read:
%%after:
%endmacro
// Pre stack: addr, amount, redest
// Post stack: (empty)
global add_eth:
PANIC // TODO
// stack: addr, amount, retdest
DUP1 %mpt_read_state_trie
// stack: account_ptr, addr, amount, retdest
DUP1 ISZERO %jumpi(add_eth_new_account) // If the account pointer is null, we need to create the account.
%add_const(1)
// stack: balance_ptr, addr, amount, retdest
DUP1 %mload_trie_data
// stack: balance, balance_ptr, addr, amount, retdest
%stack (balance, balance_ptr, addr, amount) -> (amount, balance, addr, balance_ptr)
ADD
// stack: new_balance, addr, balance_ptr, retdest
SWAP1 %mstore_trie_data
// stack: addr, retdest
POP JUMP
global add_eth_new_account:
// TODO: Skip creation if amount == 0?
// stack: null_account_ptr, addr, amount, retdest
POP
%get_trie_data_size // pointer to new account we're about to create
// stack: new_account_ptr, addr, amount, retdest
SWAP2
// stack: amount, addr, new_account_ptr, retdest
PUSH 0 %append_to_trie_data // nonce
%append_to_trie_data // balance
// stack: addr, new_account_ptr, retdest
PUSH @EMPTY_NODE_HASH %append_to_trie_data // storage root
PUSH @EMPTY_STRING_HASH %append_to_trie_data // code hash
// stack: addr, new_account_ptr, retdest
%addr_to_state_key
// stack: key, new_account_ptr, retdest
%jump(mpt_insert_state_trie)
// Convenience macro to call add_eth and return where we left off.
%macro add_eth

View File

@ -11,7 +11,7 @@ hash_initial_tries:
%mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE)
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE)
txn_loop:
global txn_loop:
// If the prover has no more txns for us to process, halt.
PROVER_INPUT(end_of_txns)
%jumpi(hash_final_tries)
@ -20,7 +20,7 @@ txn_loop:
PUSH txn_loop
%jump(route_txn)
hash_final_tries:
global hash_final_tries:
%mpt_hash_state_trie %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER)
%mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_AFTER)
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER)

View File

@ -0,0 +1,82 @@
global sys_mload:
// stack: kexit_info, offset
PUSH 0 // acc = 0
// stack: acc, kexit_info, offset
DUP3 %add_const( 0) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xf8) ADD
DUP3 %add_const( 1) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xf0) ADD
DUP3 %add_const( 2) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xe8) ADD
DUP3 %add_const( 3) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xe0) ADD
DUP3 %add_const( 4) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xd8) ADD
DUP3 %add_const( 5) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xd0) ADD
DUP3 %add_const( 6) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xc8) ADD
DUP3 %add_const( 7) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xc0) ADD
DUP3 %add_const( 8) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xb8) ADD
DUP3 %add_const( 9) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xb0) ADD
DUP3 %add_const(10) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xa8) ADD
DUP3 %add_const(11) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0xa0) ADD
DUP3 %add_const(12) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x98) ADD
DUP3 %add_const(13) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x90) ADD
DUP3 %add_const(14) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x88) ADD
DUP3 %add_const(15) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x80) ADD
DUP3 %add_const(16) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x78) ADD
DUP3 %add_const(17) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x70) ADD
DUP3 %add_const(18) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x68) ADD
DUP3 %add_const(19) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x60) ADD
DUP3 %add_const(20) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x58) ADD
DUP3 %add_const(21) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x50) ADD
DUP3 %add_const(22) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x48) ADD
DUP3 %add_const(23) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x40) ADD
DUP3 %add_const(24) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x38) ADD
DUP3 %add_const(25) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x30) ADD
DUP3 %add_const(26) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x28) ADD
DUP3 %add_const(27) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x20) ADD
DUP3 %add_const(28) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x18) ADD
DUP3 %add_const(29) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x10) ADD
DUP3 %add_const(30) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x08) ADD
DUP3 %add_const(31) %mload_current(@SEGMENT_MAIN_MEMORY) %shl_const(0x00) ADD
%stack (acc, kexit_info, offset) -> (kexit_info, acc)
EXIT_KERNEL
global sys_mstore:
// stack: kexit_info, offset, value
DUP3 PUSH 0 BYTE DUP3 %add_const( 0) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 1 BYTE DUP3 %add_const( 1) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 2 BYTE DUP3 %add_const( 2) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 3 BYTE DUP3 %add_const( 3) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 4 BYTE DUP3 %add_const( 4) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 5 BYTE DUP3 %add_const( 5) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 6 BYTE DUP3 %add_const( 6) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 7 BYTE DUP3 %add_const( 7) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 8 BYTE DUP3 %add_const( 8) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 9 BYTE DUP3 %add_const( 9) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 10 BYTE DUP3 %add_const(10) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 11 BYTE DUP3 %add_const(11) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 12 BYTE DUP3 %add_const(12) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 13 BYTE DUP3 %add_const(13) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 14 BYTE DUP3 %add_const(14) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 15 BYTE DUP3 %add_const(15) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 16 BYTE DUP3 %add_const(16) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 17 BYTE DUP3 %add_const(17) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 18 BYTE DUP3 %add_const(18) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 19 BYTE DUP3 %add_const(19) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 20 BYTE DUP3 %add_const(20) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 21 BYTE DUP3 %add_const(21) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 22 BYTE DUP3 %add_const(22) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 23 BYTE DUP3 %add_const(23) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 24 BYTE DUP3 %add_const(24) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 25 BYTE DUP3 %add_const(25) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 26 BYTE DUP3 %add_const(26) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 27 BYTE DUP3 %add_const(27) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 28 BYTE DUP3 %add_const(28) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 29 BYTE DUP3 %add_const(29) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 30 BYTE DUP3 %add_const(30) %mstore_current(@SEGMENT_MAIN_MEMORY)
DUP3 PUSH 31 BYTE DUP3 %add_const(31) %mstore_current(@SEGMENT_MAIN_MEMORY)
%stack (kexit_info, offset, value) -> (kexit_info)
EXIT_KERNEL
global sys_mstore8:
// stack: kexit_info, offset, value
%stack (kexit_info, offset, value) -> (offset, value, kexit_info)
%mstore_current(@SEGMENT_MAIN_MEMORY)
// stack: kexit_info
EXIT_KERNEL

View File

@ -1,6 +1,8 @@
// Insertion logic specific to a particular trie.
// Mutate the state trie, inserting the given key-value pair.
// Pre stack: key, value_ptr, retdest
// Post stack: (empty)
global mpt_insert_state_trie:
// stack: key, value_ptr, retdest
%stack (key, value_ptr)

View File

@ -8,7 +8,20 @@ global encode_rlp_scalar:
%gt_const(0x7f)
%jumpi(encode_rlp_scalar_medium)
// This is the "small" case, where the value is its own encoding.
// Else, if scalar != 0, this is the "small" case, where the value is its own encoding.
DUP2 %jumpi(encode_rlp_scalar_small)
// scalar = 0, so BE(scalar) is the empty string, which RLP encodes as a single byte 0x80.
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, 0x80, pos)
%mstore_rlp
// stack: pos, retdest
%increment
// stack: pos', retdest
SWAP1
JUMP
encode_rlp_scalar_small:
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, scalar, pos)
// stack: pos, scalar, pos, retdest
@ -127,14 +140,8 @@ encode_rlp_multi_byte_string_prefix_large:
// stack: pos, len_of_len, str_len, retdest
%increment
// stack: pos', len_of_len, str_len, retdest
%stack (pos, len_of_len, str_len)
-> (pos, str_len, len_of_len,
encode_rlp_multi_byte_string_prefix_large_done_writing_len)
%stack (pos, len_of_len, str_len) -> (pos, str_len, len_of_len)
%jump(mstore_unpacking_rlp)
encode_rlp_multi_byte_string_prefix_large_done_writing_len:
// stack: pos'', retdest
SWAP1
JUMP
%macro encode_rlp_multi_byte_string_prefix
%stack (pos, str_len) -> (pos, str_len, %%after)

View File

@ -0,0 +1,72 @@
// Encodes an arbitrary string, given a pointer and length.
// Pre stack: pos, ADDR: 3, len, retdest
// Post stack: pos'
global encode_rlp_string:
// stack: pos, ADDR: 3, len, retdest
DUP5 %eq_const(1)
// stack: len == 1, pos, ADDR: 3, len, retdest
DUP5 DUP5 DUP5 // ADDR: 3
MLOAD_GENERAL
// stack: first_byte, len == 1, pos, ADDR: 3, len, retdest
%lt_const(128)
MUL // cheaper than AND
// stack: single_small_byte, pos, ADDR: 3, len, retdest
%jumpi(encode_rlp_string_small_single_byte)
// stack: pos, ADDR: 3, len, retdest
DUP5 %gt_const(55)
// stack: len > 55, pos, ADDR: 3, len, retdest
%jumpi(encode_rlp_string_large)
global encode_rlp_string_small:
// stack: pos, ADDR: 3, len, retdest
DUP5 // len
%add_const(0x80)
// stack: first_byte, pos, ADDR: 3, len, retdest
DUP2
// stack: pos, first_byte, pos, ADDR: 3, len, retdest
%mstore_rlp
// stack: pos, ADDR: 3, len, retdest
%increment
// stack: pos', ADDR: 3, len, retdest
DUP5 DUP2 ADD // pos'' = pos' + len
// stack: pos'', pos', ADDR: 3, len, retdest
%stack (pos2, pos1, ADDR: 3, len, retdest)
-> (0, @SEGMENT_RLP_RAW, pos1, ADDR, len, retdest, pos2)
%jump(memcpy)
global encode_rlp_string_small_single_byte:
// stack: pos, ADDR: 3, len, retdest
%stack (pos, ADDR: 3, len) -> (ADDR, pos)
MLOAD_GENERAL
// stack: byte, pos, retdest
DUP2
%mstore_rlp
// stack: pos, retdest
%increment
JUMP
global encode_rlp_string_large:
// stack: pos, ADDR: 3, len, retdest
DUP5 %num_bytes
// stack: len_of_len, pos, ADDR: 3, len, retdest
SWAP1
DUP2 // len_of_len
%add_const(0xb7)
// stack: first_byte, pos, len_of_len, ADDR: 3, len, retdest
DUP2
// stack: pos, first_byte, pos, len_of_len, ADDR: 3, len, retdest
%mstore_rlp
// stack: pos, len_of_len, ADDR: 3, len, retdest
%increment
// stack: pos', len_of_len, ADDR: 3, len, retdest
%stack (pos, len_of_len, ADDR: 3, len)
-> (pos, len, len_of_len, encode_rlp_string_large_after_writing_len, ADDR, len)
%jump(mstore_unpacking_rlp)
global encode_rlp_string_large_after_writing_len:
// stack: pos'', ADDR: 3, len, retdest
DUP5 DUP2 ADD // pos''' = pos'' + len
// stack: pos''', pos'', ADDR: 3, len, retdest
%stack (pos3, pos2, ADDR: 3, len, retdest)
-> (0, @SEGMENT_RLP_RAW, pos2, ADDR, len, retdest, pos3)
%jump(memcpy)

View File

@ -127,7 +127,92 @@ parse_r:
%mstore_txn_field(@TXN_FIELD_S)
// stack: retdest
// TODO: Write the signed txn data to memory, where it can be hashed and
// checked against the signature.
type_0_compute_signed_data:
// If a chain_id is present in v, the signed data is
// keccak256(rlp([nonce, gas_price, gas_limit, to, value, data, chain_id, 0, 0]))
// otherwise, it is
// keccak256(rlp([nonce, gas_price, gas_limit, to, value, data]))
%mload_txn_field(@TXN_FIELD_NONCE)
// stack: nonce, retdest
PUSH 9 // We start at 9 to leave room to prepend the largest possible RLP list header.
// stack: rlp_pos, nonce, retdest
%encode_rlp_scalar
// stack: rlp_pos, retdest
%mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
%mload_txn_field(@TXN_FIELD_TO)
SWAP1 %encode_rlp_160
// stack: rlp_pos, retdest
%mload_txn_field(@TXN_FIELD_VALUE)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// Encode txn data.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
PUSH 0 // ADDR.virt
PUSH @SEGMENT_TXN_DATA
PUSH 0 // ADDR.context
// stack: ADDR: 3, len, rlp_pos, retdest
PUSH after_serializing_txn_data
// stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, retdest
SWAP5
// stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, retdest
%jump(encode_rlp_string)
after_serializing_txn_data:
// stack: rlp_pos, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT)
ISZERO %jumpi(finish_rlp_list)
// stack: rlp_pos, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
PUSH 0
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
PUSH 0
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
finish_rlp_list:
%prepend_rlp_list_prefix
// stack: start_pos, rlp_len, retdest
PUSH @SEGMENT_RLP_RAW
PUSH 0 // context
// stack: ADDR: 3, rlp_len, retdest
KECCAK_GENERAL
// stack: hash, retdest
%mload_txn_field(@TXN_FIELD_S)
%mload_txn_field(@TXN_FIELD_R)
%mload_txn_field(@TXN_FIELD_Y_PARITY) %add_const(27) // ecrecover interprets v as y_parity + 27
PUSH store_origin
// stack: store_origin, v, r, s, hash, retdest
SWAP4
// stack: hash, v, r, s, store_origin, retdest
%jump(ecrecover)
store_origin:
// stack: address, retdest
// If ecrecover returned u256::MAX, that indicates failure.
DUP1
%eq_const(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
%jumpi(panic)
// stack: address, retdest
%mstore_txn_field(@TXN_FIELD_ORIGIN)
// stack: retdest
%jump(process_normalized_txn)

View File

@ -1,3 +1,14 @@
global sys_keccak256:
// stack: kexit_info, offset, len
%stack (kexit_info, offset, len) -> (offset, len, kexit_info)
PUSH @SEGMENT_MAIN_MEMORY
GET_CONTEXT
// stack: ADDR: 3, len, kexit_info
KECCAK_GENERAL
// stack: hash, kexit_info
SWAP1
EXIT_KERNEL
// Computes Keccak256(input_word). Clobbers @SEGMENT_KERNEL_GENERAL.
//
// Pre stack: input_word

View File

@ -1,7 +1,7 @@
use std::collections::HashMap;
use ethereum_types::U256;
use itertools::izip;
use itertools::{izip, Itertools};
use keccak_hash::keccak;
use log::debug;
@ -28,6 +28,7 @@ pub struct Kernel {
pub(crate) code_hash: [u32; 8],
pub(crate) global_labels: HashMap<String, usize>,
pub(crate) ordered_labels: Vec<String>,
/// Map from `PROVER_INPUT` offsets to their corresponding `ProverInputFn`.
pub(crate) prover_inputs: HashMap<usize, ProverInputFn>,
@ -43,18 +44,30 @@ impl Kernel {
let code_hash = std::array::from_fn(|i| {
u32::from_le_bytes(std::array::from_fn(|j| code_hash_bytes[i * 4 + j]))
});
let ordered_labels = global_labels
.keys()
.cloned()
.sorted_by_key(|label| global_labels[label])
.collect();
Self {
code,
code_hash,
global_labels,
ordered_labels,
prover_inputs,
}
}
/// Get a string representation of the current offset for debugging purposes.
pub(crate) fn offset_name(&self, offset: usize) -> String {
self.offset_label(offset)
.unwrap_or_else(|| offset.to_string())
match self
.ordered_labels
.binary_search_by_key(&offset, |label| self.global_labels[label])
{
Ok(idx) => self.ordered_labels[idx].clone(),
Err(0) => offset.to_string(),
Err(idx) => format!("{}, below {}", offset, self.ordered_labels[idx - 1]),
}
}
pub(crate) fn offset_label(&self, offset: usize) -> Option<String> {

View File

@ -49,7 +49,12 @@ pub fn evm_constants() -> HashMap<String, U256> {
c
}
const HASH_CONSTANTS: [(&str, [u8; 32]); 1] = [
const HASH_CONSTANTS: [(&str, [u8; 32]); 2] = [
// Hash of an empty string: keccak(b'').hex()
(
"EMPTY_STRING_HASH",
hex!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"),
),
// Hash of an empty node: keccak(rlp.encode(b'')).hex()
(
"EMPTY_NODE_HASH",

View File

@ -17,10 +17,11 @@ pub(crate) enum NormalizedTxnField {
YParity = 9,
R = 10,
S = 11,
Origin = 12,
}
impl NormalizedTxnField {
pub(crate) const COUNT: usize = 12;
pub(crate) const COUNT: usize = 13;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
@ -36,6 +37,7 @@ impl NormalizedTxnField {
Self::YParity,
Self::R,
Self::S,
Self::Origin,
]
}
@ -54,6 +56,7 @@ impl NormalizedTxnField {
NormalizedTxnField::YParity => "TXN_FIELD_Y_PARITY",
NormalizedTxnField::R => "TXN_FIELD_R",
NormalizedTxnField::S => "TXN_FIELD_S",
NormalizedTxnField::Origin => "TXN_FIELD_ORIGIN",
}
}
}

View File

@ -72,8 +72,8 @@ pub fn eval_packed<P: PackedField>(
// This memory channel is constrained in `stack.rs`.
let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value;
// Push current PC to stack
yield_constr.constraint(filter * (output[0] - lv.program_counter));
// Push current PC + 1 to stack
yield_constr.constraint(filter * (output[0] - (lv.program_counter + P::ONES)));
// Push current kernel flag to stack (share register with PC)
yield_constr.constraint(filter * (output[1] - lv.is_kernel_mode));
// Zero the rest of that register
@ -180,9 +180,10 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
// This memory channel is constrained in `stack.rs`.
let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value;
// Push current PC to stack
// Push current PC + 1 to stack
{
let diff = builder.sub_extension(output[0], lv.program_counter);
let pc_plus_1 = builder.add_const_extension(lv.program_counter, F::ONE);
let diff = builder.sub_extension(output[0], pc_plus_1);
let constr = builder.mul_extension(filter, diff);
yield_constr.constraint(builder, constr);
}

View File

@ -16,6 +16,17 @@ pub struct AccountRlp {
pub code_hash: H256,
}
impl Default for AccountRlp {
fn default() -> Self {
Self {
nonce: U256::zero(),
balance: U256::zero(),
storage_root: PartialTrie::Empty.calc_hash(),
code_hash: keccak([]),
}
}
}
pub(crate) fn all_mpt_prover_inputs_reversed(trie_inputs: &TrieInputs) -> Vec<U256> {
let mut inputs = all_mpt_prover_inputs(trie_inputs);
inputs.reverse();

View File

@ -5,6 +5,7 @@ use plonky2::field::types::Field;
use crate::cpu::columns::CpuColumnsView;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::assembler::BYTES_PER_OFFSET;
use crate::cpu::membus::NUM_GP_CHANNELS;
use crate::cpu::simple_logic::eq_iszero::generate_pinv_diff;
use crate::generation::state::GenerationState;
@ -20,9 +21,6 @@ use crate::{arithmetic, logic};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum Operation {
Push(u8),
Dup(u8),
Swap(u8),
Iszero,
Not,
Byte,
@ -39,6 +37,9 @@ pub(crate) enum Operation {
Pc,
Gas,
Jumpdest,
Push(u8),
Dup(u8),
Swap(u8),
GetContext,
SetContext,
ConsumeGas,
@ -190,6 +191,10 @@ pub(crate) fn generate_jump<F: Field>(
state.traces.push_memory(log_in0);
state.traces.push_cpu(row);
state.registers.program_counter = u256_saturating_cast_usize(dst);
log::debug!(
"Jumping to {}",
KERNEL.offset_name(state.registers.program_counter)
);
// TODO: Set other cols like input0_upper_sum_inv.
Ok(())
}
@ -206,12 +211,47 @@ pub(crate) fn generate_jumpi<F: Field>(
state.registers.program_counter = if cond.is_zero() {
state.registers.program_counter + 1
} else {
u256_saturating_cast_usize(dst)
let dst_usize = u256_saturating_cast_usize(dst);
log::debug!(
"Jumping to {}",
KERNEL.offset_name(state.registers.program_counter)
);
dst_usize
};
// TODO: Set other cols like input0_upper_sum_inv.
Ok(())
}
pub(crate) fn generate_jumpdest<F: Field>(
state: &mut GenerationState<F>,
row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
state.traces.push_cpu(row);
Ok(())
}
pub(crate) fn generate_get_context<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
let ctx = state.registers.context.into();
let write = stack_push_log_and_fill(state, &mut row, ctx)?;
state.traces.push_memory(write);
state.traces.push_cpu(row);
Ok(())
}
pub(crate) fn generate_set_context<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
let [(ctx, log_in)] = stack_pop_with_log_and_fill::<1, _>(state, &mut row)?;
state.registers.context = ctx.as_usize();
state.traces.push_memory(log_in);
state.traces.push_cpu(row);
Ok(())
}
pub(crate) fn generate_push<F: Field>(
n: u8,
state: &mut GenerationState<F>,
@ -386,7 +426,9 @@ pub(crate) fn generate_syscall<F: Field>(
mut row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
let handler_jumptable_addr = KERNEL.global_labels["syscall_jumptable"];
let handler_addr_addr = handler_jumptable_addr + (opcode as usize);
let handler_addr_addr =
handler_jumptable_addr + (opcode as usize) * (BYTES_PER_OFFSET as usize);
assert_eq!(BYTES_PER_OFFSET, 3, "Code below assumes 3 bytes per offset");
let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill(
0,
MemoryAddress::new(0, Segment::Code, handler_addr_addr),
@ -409,11 +451,12 @@ pub(crate) fn generate_syscall<F: Field>(
let handler_addr = (handler_addr0 << 16) + (handler_addr1 << 8) + handler_addr2;
let new_program_counter = handler_addr.as_usize();
let syscall_info = U256::from(state.registers.program_counter)
let syscall_info = U256::from(state.registers.program_counter + 1)
+ (U256::from(u64::from(state.registers.is_kernel)) << 32);
let log_out = stack_push_log_and_fill(state, &mut row, syscall_info)?;
state.registers.program_counter = new_program_counter;
log::debug!("Syscall to {}", KERNEL.offset_name(new_program_counter));
state.registers.is_kernel = true;
state.traces.push_memory(log_in0);
@ -448,14 +491,19 @@ pub(crate) fn generate_exit_kernel<F: Field>(
mut row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
let [(kexit_info, log_in)] = stack_pop_with_log_and_fill::<1, _>(state, &mut row)?;
let kexit_info_u64: [u64; 4] = kexit_info.0;
let program_counter = kexit_info_u64[0] as usize;
let is_kernel_mode_val = (kexit_info_u64[1] >> 32) as u32;
let kexit_info_u64 = kexit_info.0[0];
let program_counter = kexit_info_u64 as u32 as usize;
let is_kernel_mode_val = (kexit_info_u64 >> 32) as u32;
assert!(is_kernel_mode_val == 0 || is_kernel_mode_val == 1);
let is_kernel_mode = is_kernel_mode_val != 0;
state.registers.program_counter = program_counter;
state.registers.is_kernel = is_kernel_mode;
log::debug!(
"Exiting to {}, is_kernel={}",
KERNEL.offset_name(program_counter),
is_kernel_mode
);
state.traces.push_memory(log_in);
state.traces.push_cpu(row);

View File

@ -113,6 +113,10 @@ fn decode(registers: RegistersState, opcode: u8) -> Result<Operation, ProgramErr
(0xa2, _) => Ok(Operation::Syscall(opcode)),
(0xa3, _) => Ok(Operation::Syscall(opcode)),
(0xa4, _) => Ok(Operation::Syscall(opcode)),
(0xa5, _) => panic!(
"Kernel panic at {}",
KERNEL.offset_name(registers.program_counter)
),
(0xf0, _) => Ok(Operation::Syscall(opcode)),
(0xf1, _) => Ok(Operation::Syscall(opcode)),
(0xf2, _) => Ok(Operation::Syscall(opcode)),
@ -128,7 +132,10 @@ fn decode(registers: RegistersState, opcode: u8) -> Result<Operation, ProgramErr
(0xfc, true) => Ok(Operation::MstoreGeneral),
(0xfd, _) => Ok(Operation::Syscall(opcode)),
(0xff, _) => Ok(Operation::Syscall(opcode)),
_ => Err(ProgramError::InvalidOpcode),
_ => {
log::warn!("Invalid opcode: {}", opcode);
Err(ProgramError::InvalidOpcode)
}
}
}
@ -203,9 +210,9 @@ fn perform_op<F: Field>(
Operation::Jumpi => generate_jumpi(state, row)?,
Operation::Pc => todo!(),
Operation::Gas => todo!(),
Operation::Jumpdest => todo!(),
Operation::GetContext => todo!(),
Operation::SetContext => todo!(),
Operation::Jumpdest => generate_jumpdest(state, row)?,
Operation::GetContext => generate_get_context(state, row)?,
Operation::SetContext => generate_set_context(state, row)?,
Operation::ConsumeGas => todo!(),
Operation::ExitKernel => generate_exit_kernel(state, row)?,
Operation::MloadGeneral => generate_mload_general(state, row)?,
@ -219,12 +226,6 @@ fn perform_op<F: Field>(
_ => 1,
};
if let Some(label) = KERNEL.offset_label(state.registers.program_counter) {
if !label.starts_with("halt_pc") {
log::debug!("At {label}");
}
}
Ok(())
}
@ -239,19 +240,39 @@ fn try_perform_instruction<F: Field>(state: &mut GenerationState<F>) -> Result<(
let opcode = read_code_memory(state, &mut row);
let op = decode(state.registers, opcode)?;
let pc = state.registers.program_counter;
log::trace!("\nCycle {}", state.traces.clock());
log::trace!(
"Stack: {:?}",
log_instruction(state, op);
fill_op_flag(op, &mut row);
perform_op(state, op, row)
}
fn log_instruction<F: Field>(state: &mut GenerationState<F>, op: Operation) {
let pc = state.registers.program_counter;
let is_interesting_offset = KERNEL
.offset_label(pc)
.filter(|label| !label.starts_with("halt_pc"))
.is_some();
let level = if is_interesting_offset {
log::Level::Debug
} else {
log::Level::Trace
};
log::log!(
level,
"Cycle {}, pc={}, instruction={:?}, stack={:?}",
state.traces.clock(),
KERNEL.offset_name(pc),
op,
(0..state.registers.stack_len)
.map(|i| stack_peek(state, i).unwrap())
.collect_vec()
);
log::trace!("Executing {:?} at {}", op, KERNEL.offset_name(pc));
fill_op_flag(op, &mut row);
perform_op(state, op, row)
if state.registers.is_kernel && pc >= KERNEL.code.len() {
panic!("Kernel PC is out of range: {}", pc);
}
}
fn handle_error<F: Field>(_state: &mut GenerationState<F>) {
@ -270,7 +291,8 @@ pub(crate) fn transition<F: Field>(state: &mut GenerationState<F>) {
}
Err(e) => {
if state.registers.is_kernel {
panic!("exception in kernel mode: {:?}", e);
let offset_name = KERNEL.offset_name(state.registers.program_counter);
panic!("exception in kernel mode at {}: {:?}", offset_name, e);
}
state.rollback(checkpoint);
handle_error(state)

View File

@ -1,12 +1,16 @@
use std::collections::HashMap;
use eth_trie_utils::partial_trie::PartialTrie;
use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV};
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
use ethereum_types::U256;
use hex_literal::hex;
use keccak_hash::keccak;
use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::plonk::config::PoseidonGoldilocksConfig;
use plonky2::util::timing::TimingTree;
use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::generation::mpt::AccountRlp;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::prover::prove;
@ -18,28 +22,95 @@ type C = PoseidonGoldilocksConfig;
/// Test a simple token transfer to a new address.
#[test]
#[ignore] // TODO: Won't work until txn parsing, storage, etc. are implemented.
fn test_simple_transfer() -> anyhow::Result<()> {
init_logger();
let all_stark = AllStark::<F, D>::default();
let config = StarkConfig::standard_fast_config();
let block_metadata = BlockMetadata::default();
let sender = hex!("2c7536e3605d9c16a7a3d7b1898e529396a65c23");
let to = hex!("a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0");
let sender_state_key = keccak(sender);
let to_state_key = keccak(to);
let sender_nibbles = Nibbles::from(sender_state_key);
let to_nibbles = Nibbles::from(to_state_key);
let value = U256::from(100u32);
let txn = hex!("f85f050a82520894000000000000000000000000000000000000000064801ca0fa56df5d988638fad8798e5ef75a1e1125dc7fb55d2ac4bce25776a63f0c2967a02cb47a5579eb5f83a1cabe4662501c0059f1b58e60ef839a1b0da67af6b9fb38");
let sender_account_before = AccountRlp {
nonce: 5.into(),
balance: eth_to_wei(100_000.into()),
storage_root: PartialTrie::Empty.calc_hash(),
code_hash: keccak([]),
};
let state_trie_before = PartialTrie::Leaf {
nibbles: sender_nibbles,
value: rlp::encode(&sender_account_before).to_vec(),
};
let tries_before = TrieInputs {
state_trie: state_trie_before,
transactions_trie: PartialTrie::Empty,
receipts_trie: PartialTrie::Empty,
storage_tries: vec![],
};
// Generated using a little py-evm script.
let txn = hex!("f861050a8255f094a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0648242421ba02c89eb757d9deeb1f5b3859a9d4d679951ef610ac47ad4608dc142beb1b7e313a05af7e9fbab825455d36c36c7f4cfcafbeafa9a77bdff936b52afb36d4fe4bcdd");
let block_metadata = BlockMetadata::default();
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: TrieInputs {
state_trie: PartialTrie::Empty,
transactions_trie: PartialTrie::Empty,
receipts_trie: PartialTrie::Empty,
storage_tries: vec![],
},
tries: tries_before,
contract_code: HashMap::new(),
block_metadata,
};
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut TimingTree::default())?;
let mut timing = TimingTree::new("prove", log::Level::Debug);
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.print();
let expected_state_trie_after = {
let sender_account_after = AccountRlp {
balance: sender_account_before.balance - value, // TODO: Also subtract gas_used * price.
// nonce: sender_account_before.nonce + 1, // TODO
..sender_account_before
};
let to_account_after = AccountRlp {
balance: value,
..AccountRlp::default()
};
let mut children = std::array::from_fn(|_| PartialTrie::Empty.into());
children[sender_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf {
nibbles: sender_nibbles.truncate_n_nibbles_front(1),
value: rlp::encode(&sender_account_after).to_vec(),
}
.into();
children[to_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf {
nibbles: to_nibbles.truncate_n_nibbles_front(1),
value: rlp::encode(&to_account_after).to_vec(),
}
.into();
PartialTrie::Branch {
children,
value: vec![],
}
};
assert_eq!(
proof.public_values.trie_roots_after.state_root,
expected_state_trie_after.calc_hash()
);
verify_proof(all_stark, proof, &config)
}
fn eth_to_wei(eth: U256) -> U256 {
// 1 ether = 2^18 wei.
eth << 18
}
fn init_logger() {
let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "debug"));
}