mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 00:03:10 +00:00
Merge pull request #838 from mir-protocol/transfer_test
Fixes to get test_simple_transfer working
This commit is contained in:
commit
4ae1d840a9
@ -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);
|
let mut dummy_yield_constr = ConstraintConsumer::new(vec![], P::ZEROS, P::ZEROS, P::ZEROS);
|
||||||
bootstrap_kernel::eval_bootstrap_kernel(vars, yield_constr);
|
bootstrap_kernel::eval_bootstrap_kernel(vars, yield_constr);
|
||||||
control_flow::eval_packed_generic(local_values, next_values, 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);
|
dup_swap::eval_packed(local_values, yield_constr);
|
||||||
jumps::eval_packed(local_values, next_values, &mut dummy_yield_constr);
|
jumps::eval_packed(local_values, next_values, &mut dummy_yield_constr);
|
||||||
membus::eval_packed(local_values, yield_constr);
|
membus::eval_packed(local_values, yield_constr);
|
||||||
modfp254::eval_packed(local_values, yield_constr);
|
modfp254::eval_packed(local_values, yield_constr);
|
||||||
shift::eval_packed(local_values, yield_constr);
|
shift::eval_packed(local_values, yield_constr);
|
||||||
simple_logic::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);
|
stack_bounds::eval_packed(local_values, &mut dummy_yield_constr);
|
||||||
syscalls::eval_packed(local_values, next_values, 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);
|
RecursiveConstraintConsumer::new(zero, vec![], zero, zero, zero);
|
||||||
bootstrap_kernel::eval_bootstrap_kernel_circuit(builder, vars, yield_constr);
|
bootstrap_kernel::eval_bootstrap_kernel_circuit(builder, vars, yield_constr);
|
||||||
control_flow::eval_ext_circuit(builder, local_values, next_values, 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);
|
dup_swap::eval_ext_circuit(builder, local_values, yield_constr);
|
||||||
jumps::eval_ext_circuit(builder, local_values, next_values, &mut dummy_yield_constr);
|
jumps::eval_ext_circuit(builder, local_values, next_values, &mut dummy_yield_constr);
|
||||||
membus::eval_ext_circuit(builder, local_values, yield_constr);
|
membus::eval_ext_circuit(builder, local_values, yield_constr);
|
||||||
modfp254::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);
|
shift::eval_ext_circuit(builder, local_values, yield_constr);
|
||||||
simple_logic::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);
|
stack_bounds::eval_ext_circuit(builder, local_values, &mut dummy_yield_constr);
|
||||||
syscalls::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
syscalls::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
|||||||
include_str!("asm/memory/memcpy.asm"),
|
include_str!("asm/memory/memcpy.asm"),
|
||||||
include_str!("asm/memory/metadata.asm"),
|
include_str!("asm/memory/metadata.asm"),
|
||||||
include_str!("asm/memory/packing.asm"),
|
include_str!("asm/memory/packing.asm"),
|
||||||
|
include_str!("asm/memory/syscalls.asm"),
|
||||||
include_str!("asm/memory/txn_fields.asm"),
|
include_str!("asm/memory/txn_fields.asm"),
|
||||||
include_str!("asm/mpt/accounts.asm"),
|
include_str!("asm/mpt/accounts.asm"),
|
||||||
include_str!("asm/mpt/delete/delete.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/main.asm"),
|
||||||
include_str!("asm/ripemd/memory.asm"),
|
include_str!("asm/ripemd/memory.asm"),
|
||||||
include_str!("asm/ripemd/update.asm"),
|
include_str!("asm/ripemd/update.asm"),
|
||||||
include_str!("asm/rlp/encode.asm"),
|
|
||||||
include_str!("asm/rlp/decode.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/num_bytes.asm"),
|
||||||
include_str!("asm/rlp/read_to_memory.asm"),
|
include_str!("asm/rlp/read_to_memory.asm"),
|
||||||
include_str!("asm/sha2/compression.asm"),
|
include_str!("asm/sha2/compression.asm"),
|
||||||
|
|||||||
@ -4,7 +4,7 @@ global balance:
|
|||||||
// stack: account_ptr, retdest
|
// stack: account_ptr, retdest
|
||||||
DUP1 ISZERO %jumpi(retzero) // If the account pointer is null, return 0.
|
DUP1 ISZERO %jumpi(retzero) // If the account pointer is null, return 0.
|
||||||
%add_const(1)
|
%add_const(1)
|
||||||
// stack: balance_ptr
|
// stack: balance_ptr, retdest
|
||||||
%mload_trie_data
|
%mload_trie_data
|
||||||
// stack: balance, retdest
|
// stack: balance, retdest
|
||||||
SWAP1 JUMP
|
SWAP1 JUMP
|
||||||
|
|||||||
@ -45,7 +45,9 @@ global delegate_call:
|
|||||||
-> (0, 0, value, sender, self, address, gas)
|
-> (0, 0, value, sender, self, address, gas)
|
||||||
%jump(call_common)
|
%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
|
// stack: static, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||||
%create_context
|
%create_context
|
||||||
// Store the static flag in metadata.
|
// Store the static flag in metadata.
|
||||||
@ -108,3 +110,4 @@ after_call:
|
|||||||
// stack: new_ctx, ret_offset, ret_size, retdest
|
// stack: new_ctx, ret_offset, ret_size, retdest
|
||||||
// TODO: Set RETURNDATA.
|
// TODO: Set RETURNDATA.
|
||||||
// TODO: Return to caller w/ EXIT_KERNEL.
|
// TODO: Return to caller w/ EXIT_KERNEL.
|
||||||
|
// TODO: Return leftover gas
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
global get_nonce:
|
global get_nonce:
|
||||||
// stack: address, retdest
|
// stack: address, retdest
|
||||||
// TODO: Replace with actual implementation.
|
// TODO: Replace with actual implementation.
|
||||||
|
POP
|
||||||
JUMP
|
JUMP
|
||||||
|
|
||||||
// Convenience macro to call get_nonce and return where we left off.
|
// Convenience macro to call get_nonce and return where we left off.
|
||||||
|
|||||||
@ -3,39 +3,58 @@
|
|||||||
|
|
||||||
// TODO: Save checkpoints in @CTX_METADATA_STATE_TRIE_CHECKPOINT_PTR and @SEGMENT_STORAGE_TRIE_CHECKPOINT_PTRS.
|
// 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:
|
global process_normalized_txn:
|
||||||
// stack: (empty)
|
// stack: retdest
|
||||||
PUSH validate
|
PUSH validate
|
||||||
%jump(intrinsic_gas)
|
%jump(intrinsic_gas)
|
||||||
|
|
||||||
validate:
|
global validate:
|
||||||
// stack: intrinsic_gas
|
// stack: intrinsic_gas, retdest
|
||||||
// TODO: Check gas >= intrinsic_gas.
|
// TODO: Check signature? (Or might happen in type_0.asm etc.)
|
||||||
// TODO: Check sender_balance >= intrinsic_gas + value.
|
// TODO: Assert nonce is correct.
|
||||||
|
// TODO: Assert sender has no code.
|
||||||
|
POP // TODO: Assert gas_limit >= intrinsic_gas.
|
||||||
|
// stack: retdest
|
||||||
|
|
||||||
buy_gas:
|
global charge_gas:
|
||||||
// TODO: Deduct gas from sender (some may be refunded later).
|
// TODO: Deduct gas limit from sender (some gas may be refunded later).
|
||||||
|
|
||||||
increment_nonce:
|
PUSH 0 // TODO: Push sender.
|
||||||
// TODO: Increment nonce.
|
%increment_nonce
|
||||||
|
|
||||||
process_based_on_type:
|
global process_based_on_type:
|
||||||
%is_contract_creation
|
%is_contract_creation
|
||||||
%jumpi(process_contract_creation_txn)
|
%jumpi(process_contract_creation_txn)
|
||||||
%jump(process_message_txn)
|
%jump(process_message_txn)
|
||||||
|
|
||||||
process_contract_creation_txn:
|
global process_contract_creation_txn:
|
||||||
// stack: (empty)
|
// stack: retdest
|
||||||
// Push the code address & length onto the stack, then call `create`.
|
// Push the code address & length onto the stack, then call `create`.
|
||||||
%mload_txn_field(@TXN_FIELD_DATA_LEN)
|
%mload_txn_field(@TXN_FIELD_DATA_LEN)
|
||||||
// stack: code_len
|
// stack: code_len, retdest
|
||||||
PUSH 0
|
PUSH 0
|
||||||
// stack: code_offset, code_len
|
// stack: code_offset, code_len, retdest
|
||||||
PUSH @SEGMENT_TXN_DATA
|
PUSH @SEGMENT_TXN_DATA
|
||||||
// stack: code_segment, code_offset, code_len
|
// stack: code_segment, code_offset, code_len, retdest
|
||||||
PUSH 0 // context
|
PUSH 0 // context
|
||||||
// stack: CODE_ADDR, code_len
|
// stack: CODE_ADDR, code_len, retdest
|
||||||
%jump(create)
|
%jump(create)
|
||||||
|
|
||||||
process_message_txn:
|
global process_message_txn:
|
||||||
// TODO
|
// 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
|
||||||
|
|||||||
@ -7,7 +7,6 @@ global sys_signextend:
|
|||||||
global sys_slt:
|
global sys_slt:
|
||||||
global sys_sgt:
|
global sys_sgt:
|
||||||
global sys_sar:
|
global sys_sar:
|
||||||
global sys_keccak256:
|
|
||||||
global sys_address:
|
global sys_address:
|
||||||
global sys_balance:
|
global sys_balance:
|
||||||
global sys_origin:
|
global sys_origin:
|
||||||
@ -33,9 +32,6 @@ global sys_gaslimit:
|
|||||||
global sys_chainid:
|
global sys_chainid:
|
||||||
global sys_selfbalance:
|
global sys_selfbalance:
|
||||||
global sys_basefee:
|
global sys_basefee:
|
||||||
global sys_mload:
|
|
||||||
global sys_mstore:
|
|
||||||
global sys_mstore8:
|
|
||||||
global sys_sload:
|
global sys_sload:
|
||||||
global sys_sstore:
|
global sys_sstore:
|
||||||
global sys_msize:
|
global sys_msize:
|
||||||
|
|||||||
@ -1,15 +1,20 @@
|
|||||||
// Transfers some ETH from one address to another. The amount is given in wei.
|
// Transfers some ETH from one address to another. The amount is given in wei.
|
||||||
// Pre stack: from, to, amount, retdest
|
// Pre stack: from, to, amount, retdest
|
||||||
// Post stack: (empty)
|
// Post stack: status (0 indicates success)
|
||||||
global transfer_eth:
|
global transfer_eth:
|
||||||
// stack: from, to, amount, retdest
|
// stack: from, to, amount, retdest
|
||||||
%stack (from, to, amount, retdest)
|
%stack (from, to, amount, retdest)
|
||||||
-> (from, amount, to, amount)
|
-> (from, amount, to, amount, retdest)
|
||||||
%deduct_eth
|
%deduct_eth
|
||||||
// TODO: Handle exception from %deduct_eth?
|
// stack: deduct_eth_status, to, amount, retdest
|
||||||
|
%jumpi(transfer_eth_failure)
|
||||||
// stack: to, amount, retdest
|
// stack: to, amount, retdest
|
||||||
%add_eth
|
%add_eth
|
||||||
// stack: retdest
|
global transfer_eth_3:
|
||||||
|
%stack (retdest) -> (retdest, 0)
|
||||||
|
JUMP
|
||||||
|
global transfer_eth_failure:
|
||||||
|
%stack (to, amount, retdest) -> (retdest, 1)
|
||||||
JUMP
|
JUMP
|
||||||
|
|
||||||
// Convenience macro to call transfer_eth and return where we left off.
|
// Convenience macro to call transfer_eth and return where we left off.
|
||||||
@ -31,11 +36,31 @@ global transfer_eth:
|
|||||||
%%after:
|
%%after:
|
||||||
%endmacro
|
%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:
|
global deduct_eth:
|
||||||
// stack: addr, amount, retdest
|
// stack: addr, amount, retdest
|
||||||
%jump(mpt_read_state_trie)
|
%mpt_read_state_trie
|
||||||
deduct_eth_after_read:
|
// stack: account_ptr, amount, retdest
|
||||||
PANIC // TODO
|
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.
|
// Convenience macro to call deduct_eth and return where we left off.
|
||||||
%macro deduct_eth
|
%macro deduct_eth
|
||||||
@ -44,8 +69,40 @@ deduct_eth_after_read:
|
|||||||
%%after:
|
%%after:
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
|
// Pre stack: addr, amount, redest
|
||||||
|
// Post stack: (empty)
|
||||||
global add_eth:
|
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.
|
// Convenience macro to call add_eth and return where we left off.
|
||||||
%macro add_eth
|
%macro add_eth
|
||||||
|
|||||||
@ -11,7 +11,7 @@ hash_initial_tries:
|
|||||||
%mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE)
|
%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)
|
%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.
|
// If the prover has no more txns for us to process, halt.
|
||||||
PROVER_INPUT(end_of_txns)
|
PROVER_INPUT(end_of_txns)
|
||||||
%jumpi(hash_final_tries)
|
%jumpi(hash_final_tries)
|
||||||
@ -20,7 +20,7 @@ txn_loop:
|
|||||||
PUSH txn_loop
|
PUSH txn_loop
|
||||||
%jump(route_txn)
|
%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_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_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_AFTER)
|
||||||
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER)
|
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER)
|
||||||
|
|||||||
82
evm/src/cpu/kernel/asm/memory/syscalls.asm
Normal file
82
evm/src/cpu/kernel/asm/memory/syscalls.asm
Normal 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
|
||||||
@ -1,6 +1,8 @@
|
|||||||
// Insertion logic specific to a particular trie.
|
// Insertion logic specific to a particular trie.
|
||||||
|
|
||||||
// Mutate the state trie, inserting the given key-value pair.
|
// Mutate the state trie, inserting the given key-value pair.
|
||||||
|
// Pre stack: key, value_ptr, retdest
|
||||||
|
// Post stack: (empty)
|
||||||
global mpt_insert_state_trie:
|
global mpt_insert_state_trie:
|
||||||
// stack: key, value_ptr, retdest
|
// stack: key, value_ptr, retdest
|
||||||
%stack (key, value_ptr)
|
%stack (key, value_ptr)
|
||||||
|
|||||||
@ -8,7 +8,20 @@ global encode_rlp_scalar:
|
|||||||
%gt_const(0x7f)
|
%gt_const(0x7f)
|
||||||
%jumpi(encode_rlp_scalar_medium)
|
%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, retdest
|
||||||
%stack (pos, scalar) -> (pos, scalar, pos)
|
%stack (pos, scalar) -> (pos, scalar, pos)
|
||||||
// stack: pos, scalar, pos, retdest
|
// stack: pos, scalar, pos, retdest
|
||||||
@ -127,14 +140,8 @@ encode_rlp_multi_byte_string_prefix_large:
|
|||||||
// stack: pos, len_of_len, str_len, retdest
|
// stack: pos, len_of_len, str_len, retdest
|
||||||
%increment
|
%increment
|
||||||
// stack: pos', len_of_len, str_len, retdest
|
// stack: pos', len_of_len, str_len, retdest
|
||||||
%stack (pos, len_of_len, str_len)
|
%stack (pos, len_of_len, str_len) -> (pos, str_len, len_of_len)
|
||||||
-> (pos, str_len, len_of_len,
|
|
||||||
encode_rlp_multi_byte_string_prefix_large_done_writing_len)
|
|
||||||
%jump(mstore_unpacking_rlp)
|
%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
|
%macro encode_rlp_multi_byte_string_prefix
|
||||||
%stack (pos, str_len) -> (pos, str_len, %%after)
|
%stack (pos, str_len) -> (pos, str_len, %%after)
|
||||||
|
|||||||
72
evm/src/cpu/kernel/asm/rlp/encode_rlp_string.asm
Normal file
72
evm/src/cpu/kernel/asm/rlp/encode_rlp_string.asm
Normal 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)
|
||||||
@ -127,7 +127,92 @@ parse_r:
|
|||||||
%mstore_txn_field(@TXN_FIELD_S)
|
%mstore_txn_field(@TXN_FIELD_S)
|
||||||
// stack: retdest
|
// stack: retdest
|
||||||
|
|
||||||
// TODO: Write the signed txn data to memory, where it can be hashed and
|
type_0_compute_signed_data:
|
||||||
// checked against the signature.
|
// 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)
|
%jump(process_normalized_txn)
|
||||||
|
|||||||
@ -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.
|
// Computes Keccak256(input_word). Clobbers @SEGMENT_KERNEL_GENERAL.
|
||||||
//
|
//
|
||||||
// Pre stack: input_word
|
// Pre stack: input_word
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ethereum_types::U256;
|
use ethereum_types::U256;
|
||||||
use itertools::izip;
|
use itertools::{izip, Itertools};
|
||||||
use keccak_hash::keccak;
|
use keccak_hash::keccak;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ pub struct Kernel {
|
|||||||
pub(crate) code_hash: [u32; 8],
|
pub(crate) code_hash: [u32; 8],
|
||||||
|
|
||||||
pub(crate) global_labels: HashMap<String, usize>,
|
pub(crate) global_labels: HashMap<String, usize>,
|
||||||
|
pub(crate) ordered_labels: Vec<String>,
|
||||||
|
|
||||||
/// Map from `PROVER_INPUT` offsets to their corresponding `ProverInputFn`.
|
/// Map from `PROVER_INPUT` offsets to their corresponding `ProverInputFn`.
|
||||||
pub(crate) prover_inputs: HashMap<usize, ProverInputFn>,
|
pub(crate) prover_inputs: HashMap<usize, ProverInputFn>,
|
||||||
@ -43,18 +44,30 @@ impl Kernel {
|
|||||||
let code_hash = std::array::from_fn(|i| {
|
let code_hash = std::array::from_fn(|i| {
|
||||||
u32::from_le_bytes(std::array::from_fn(|j| code_hash_bytes[i * 4 + j]))
|
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 {
|
Self {
|
||||||
code,
|
code,
|
||||||
code_hash,
|
code_hash,
|
||||||
global_labels,
|
global_labels,
|
||||||
|
ordered_labels,
|
||||||
prover_inputs,
|
prover_inputs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a string representation of the current offset for debugging purposes.
|
/// Get a string representation of the current offset for debugging purposes.
|
||||||
pub(crate) fn offset_name(&self, offset: usize) -> String {
|
pub(crate) fn offset_name(&self, offset: usize) -> String {
|
||||||
self.offset_label(offset)
|
match self
|
||||||
.unwrap_or_else(|| offset.to_string())
|
.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> {
|
pub(crate) fn offset_label(&self, offset: usize) -> Option<String> {
|
||||||
|
|||||||
@ -49,7 +49,12 @@ pub fn evm_constants() -> HashMap<String, U256> {
|
|||||||
c
|
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()
|
// Hash of an empty node: keccak(rlp.encode(b'')).hex()
|
||||||
(
|
(
|
||||||
"EMPTY_NODE_HASH",
|
"EMPTY_NODE_HASH",
|
||||||
|
|||||||
@ -17,10 +17,11 @@ pub(crate) enum NormalizedTxnField {
|
|||||||
YParity = 9,
|
YParity = 9,
|
||||||
R = 10,
|
R = 10,
|
||||||
S = 11,
|
S = 11,
|
||||||
|
Origin = 12,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NormalizedTxnField {
|
impl NormalizedTxnField {
|
||||||
pub(crate) const COUNT: usize = 12;
|
pub(crate) const COUNT: usize = 13;
|
||||||
|
|
||||||
pub(crate) fn all() -> [Self; Self::COUNT] {
|
pub(crate) fn all() -> [Self; Self::COUNT] {
|
||||||
[
|
[
|
||||||
@ -36,6 +37,7 @@ impl NormalizedTxnField {
|
|||||||
Self::YParity,
|
Self::YParity,
|
||||||
Self::R,
|
Self::R,
|
||||||
Self::S,
|
Self::S,
|
||||||
|
Self::Origin,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +56,7 @@ impl NormalizedTxnField {
|
|||||||
NormalizedTxnField::YParity => "TXN_FIELD_Y_PARITY",
|
NormalizedTxnField::YParity => "TXN_FIELD_Y_PARITY",
|
||||||
NormalizedTxnField::R => "TXN_FIELD_R",
|
NormalizedTxnField::R => "TXN_FIELD_R",
|
||||||
NormalizedTxnField::S => "TXN_FIELD_S",
|
NormalizedTxnField::S => "TXN_FIELD_S",
|
||||||
|
NormalizedTxnField::Origin => "TXN_FIELD_ORIGIN",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,8 +72,8 @@ pub fn eval_packed<P: PackedField>(
|
|||||||
|
|
||||||
// This memory channel is constrained in `stack.rs`.
|
// This memory channel is constrained in `stack.rs`.
|
||||||
let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value;
|
let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value;
|
||||||
// Push current PC to stack
|
// Push current PC + 1 to stack
|
||||||
yield_constr.constraint(filter * (output[0] - lv.program_counter));
|
yield_constr.constraint(filter * (output[0] - (lv.program_counter + P::ONES)));
|
||||||
// Push current kernel flag to stack (share register with PC)
|
// Push current kernel flag to stack (share register with PC)
|
||||||
yield_constr.constraint(filter * (output[1] - lv.is_kernel_mode));
|
yield_constr.constraint(filter * (output[1] - lv.is_kernel_mode));
|
||||||
// Zero the rest of that register
|
// 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`.
|
// This memory channel is constrained in `stack.rs`.
|
||||||
let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value;
|
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);
|
let constr = builder.mul_extension(filter, diff);
|
||||||
yield_constr.constraint(builder, constr);
|
yield_constr.constraint(builder, constr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,17 @@ pub struct AccountRlp {
|
|||||||
pub code_hash: H256,
|
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> {
|
pub(crate) fn all_mpt_prover_inputs_reversed(trie_inputs: &TrieInputs) -> Vec<U256> {
|
||||||
let mut inputs = all_mpt_prover_inputs(trie_inputs);
|
let mut inputs = all_mpt_prover_inputs(trie_inputs);
|
||||||
inputs.reverse();
|
inputs.reverse();
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use plonky2::field::types::Field;
|
|||||||
|
|
||||||
use crate::cpu::columns::CpuColumnsView;
|
use crate::cpu::columns::CpuColumnsView;
|
||||||
use crate::cpu::kernel::aggregator::KERNEL;
|
use crate::cpu::kernel::aggregator::KERNEL;
|
||||||
|
use crate::cpu::kernel::assembler::BYTES_PER_OFFSET;
|
||||||
use crate::cpu::membus::NUM_GP_CHANNELS;
|
use crate::cpu::membus::NUM_GP_CHANNELS;
|
||||||
use crate::cpu::simple_logic::eq_iszero::generate_pinv_diff;
|
use crate::cpu::simple_logic::eq_iszero::generate_pinv_diff;
|
||||||
use crate::generation::state::GenerationState;
|
use crate::generation::state::GenerationState;
|
||||||
@ -20,9 +21,6 @@ use crate::{arithmetic, logic};
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum Operation {
|
pub(crate) enum Operation {
|
||||||
Push(u8),
|
|
||||||
Dup(u8),
|
|
||||||
Swap(u8),
|
|
||||||
Iszero,
|
Iszero,
|
||||||
Not,
|
Not,
|
||||||
Byte,
|
Byte,
|
||||||
@ -39,6 +37,9 @@ pub(crate) enum Operation {
|
|||||||
Pc,
|
Pc,
|
||||||
Gas,
|
Gas,
|
||||||
Jumpdest,
|
Jumpdest,
|
||||||
|
Push(u8),
|
||||||
|
Dup(u8),
|
||||||
|
Swap(u8),
|
||||||
GetContext,
|
GetContext,
|
||||||
SetContext,
|
SetContext,
|
||||||
ConsumeGas,
|
ConsumeGas,
|
||||||
@ -190,6 +191,10 @@ pub(crate) fn generate_jump<F: Field>(
|
|||||||
state.traces.push_memory(log_in0);
|
state.traces.push_memory(log_in0);
|
||||||
state.traces.push_cpu(row);
|
state.traces.push_cpu(row);
|
||||||
state.registers.program_counter = u256_saturating_cast_usize(dst);
|
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.
|
// TODO: Set other cols like input0_upper_sum_inv.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -206,12 +211,47 @@ pub(crate) fn generate_jumpi<F: Field>(
|
|||||||
state.registers.program_counter = if cond.is_zero() {
|
state.registers.program_counter = if cond.is_zero() {
|
||||||
state.registers.program_counter + 1
|
state.registers.program_counter + 1
|
||||||
} else {
|
} 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.
|
// TODO: Set other cols like input0_upper_sum_inv.
|
||||||
Ok(())
|
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>(
|
pub(crate) fn generate_push<F: Field>(
|
||||||
n: u8,
|
n: u8,
|
||||||
state: &mut GenerationState<F>,
|
state: &mut GenerationState<F>,
|
||||||
@ -386,7 +426,9 @@ pub(crate) fn generate_syscall<F: Field>(
|
|||||||
mut row: CpuColumnsView<F>,
|
mut row: CpuColumnsView<F>,
|
||||||
) -> Result<(), ProgramError> {
|
) -> Result<(), ProgramError> {
|
||||||
let handler_jumptable_addr = KERNEL.global_labels["syscall_jumptable"];
|
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(
|
let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill(
|
||||||
0,
|
0,
|
||||||
MemoryAddress::new(0, Segment::Code, handler_addr_addr),
|
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 handler_addr = (handler_addr0 << 16) + (handler_addr1 << 8) + handler_addr2;
|
||||||
let new_program_counter = handler_addr.as_usize();
|
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);
|
+ (U256::from(u64::from(state.registers.is_kernel)) << 32);
|
||||||
let log_out = stack_push_log_and_fill(state, &mut row, syscall_info)?;
|
let log_out = stack_push_log_and_fill(state, &mut row, syscall_info)?;
|
||||||
|
|
||||||
state.registers.program_counter = new_program_counter;
|
state.registers.program_counter = new_program_counter;
|
||||||
|
log::debug!("Syscall to {}", KERNEL.offset_name(new_program_counter));
|
||||||
state.registers.is_kernel = true;
|
state.registers.is_kernel = true;
|
||||||
|
|
||||||
state.traces.push_memory(log_in0);
|
state.traces.push_memory(log_in0);
|
||||||
@ -448,14 +491,19 @@ pub(crate) fn generate_exit_kernel<F: Field>(
|
|||||||
mut row: CpuColumnsView<F>,
|
mut row: CpuColumnsView<F>,
|
||||||
) -> Result<(), ProgramError> {
|
) -> Result<(), ProgramError> {
|
||||||
let [(kexit_info, log_in)] = stack_pop_with_log_and_fill::<1, _>(state, &mut row)?;
|
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 kexit_info_u64 = kexit_info.0[0];
|
||||||
let program_counter = kexit_info_u64[0] as usize;
|
let program_counter = kexit_info_u64 as u32 as usize;
|
||||||
let is_kernel_mode_val = (kexit_info_u64[1] >> 32) as u32;
|
let is_kernel_mode_val = (kexit_info_u64 >> 32) as u32;
|
||||||
assert!(is_kernel_mode_val == 0 || is_kernel_mode_val == 1);
|
assert!(is_kernel_mode_val == 0 || is_kernel_mode_val == 1);
|
||||||
let is_kernel_mode = is_kernel_mode_val != 0;
|
let is_kernel_mode = is_kernel_mode_val != 0;
|
||||||
|
|
||||||
state.registers.program_counter = program_counter;
|
state.registers.program_counter = program_counter;
|
||||||
state.registers.is_kernel = is_kernel_mode;
|
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_memory(log_in);
|
||||||
state.traces.push_cpu(row);
|
state.traces.push_cpu(row);
|
||||||
|
|||||||
@ -113,6 +113,10 @@ fn decode(registers: RegistersState, opcode: u8) -> Result<Operation, ProgramErr
|
|||||||
(0xa2, _) => Ok(Operation::Syscall(opcode)),
|
(0xa2, _) => Ok(Operation::Syscall(opcode)),
|
||||||
(0xa3, _) => Ok(Operation::Syscall(opcode)),
|
(0xa3, _) => Ok(Operation::Syscall(opcode)),
|
||||||
(0xa4, _) => 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)),
|
(0xf0, _) => Ok(Operation::Syscall(opcode)),
|
||||||
(0xf1, _) => Ok(Operation::Syscall(opcode)),
|
(0xf1, _) => Ok(Operation::Syscall(opcode)),
|
||||||
(0xf2, _) => 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),
|
(0xfc, true) => Ok(Operation::MstoreGeneral),
|
||||||
(0xfd, _) => Ok(Operation::Syscall(opcode)),
|
(0xfd, _) => Ok(Operation::Syscall(opcode)),
|
||||||
(0xff, _) => 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::Jumpi => generate_jumpi(state, row)?,
|
||||||
Operation::Pc => todo!(),
|
Operation::Pc => todo!(),
|
||||||
Operation::Gas => todo!(),
|
Operation::Gas => todo!(),
|
||||||
Operation::Jumpdest => todo!(),
|
Operation::Jumpdest => generate_jumpdest(state, row)?,
|
||||||
Operation::GetContext => todo!(),
|
Operation::GetContext => generate_get_context(state, row)?,
|
||||||
Operation::SetContext => todo!(),
|
Operation::SetContext => generate_set_context(state, row)?,
|
||||||
Operation::ConsumeGas => todo!(),
|
Operation::ConsumeGas => todo!(),
|
||||||
Operation::ExitKernel => generate_exit_kernel(state, row)?,
|
Operation::ExitKernel => generate_exit_kernel(state, row)?,
|
||||||
Operation::MloadGeneral => generate_mload_general(state, row)?,
|
Operation::MloadGeneral => generate_mload_general(state, row)?,
|
||||||
@ -219,12 +226,6 @@ fn perform_op<F: Field>(
|
|||||||
_ => 1,
|
_ => 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(label) = KERNEL.offset_label(state.registers.program_counter) {
|
|
||||||
if !label.starts_with("halt_pc") {
|
|
||||||
log::debug!("At {label}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
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 opcode = read_code_memory(state, &mut row);
|
||||||
let op = decode(state.registers, opcode)?;
|
let op = decode(state.registers, opcode)?;
|
||||||
let pc = state.registers.program_counter;
|
|
||||||
|
|
||||||
log::trace!("\nCycle {}", state.traces.clock());
|
log_instruction(state, op);
|
||||||
log::trace!(
|
|
||||||
"Stack: {:?}",
|
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)
|
(0..state.registers.stack_len)
|
||||||
.map(|i| stack_peek(state, i).unwrap())
|
.map(|i| stack_peek(state, i).unwrap())
|
||||||
.collect_vec()
|
.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>) {
|
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) => {
|
Err(e) => {
|
||||||
if state.registers.is_kernel {
|
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);
|
state.rollback(checkpoint);
|
||||||
handle_error(state)
|
handle_error(state)
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
use std::collections::HashMap;
|
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 hex_literal::hex;
|
||||||
|
use keccak_hash::keccak;
|
||||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||||
use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
||||||
use plonky2::util::timing::TimingTree;
|
use plonky2::util::timing::TimingTree;
|
||||||
use plonky2_evm::all_stark::AllStark;
|
use plonky2_evm::all_stark::AllStark;
|
||||||
use plonky2_evm::config::StarkConfig;
|
use plonky2_evm::config::StarkConfig;
|
||||||
|
use plonky2_evm::generation::mpt::AccountRlp;
|
||||||
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
|
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
|
||||||
use plonky2_evm::proof::BlockMetadata;
|
use plonky2_evm::proof::BlockMetadata;
|
||||||
use plonky2_evm::prover::prove;
|
use plonky2_evm::prover::prove;
|
||||||
@ -18,28 +22,95 @@ type C = PoseidonGoldilocksConfig;
|
|||||||
|
|
||||||
/// Test a simple token transfer to a new address.
|
/// Test a simple token transfer to a new address.
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore] // TODO: Won't work until txn parsing, storage, etc. are implemented.
|
|
||||||
fn test_simple_transfer() -> anyhow::Result<()> {
|
fn test_simple_transfer() -> anyhow::Result<()> {
|
||||||
|
init_logger();
|
||||||
|
|
||||||
let all_stark = AllStark::<F, D>::default();
|
let all_stark = AllStark::<F, D>::default();
|
||||||
let config = StarkConfig::standard_fast_config();
|
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 {
|
let inputs = GenerationInputs {
|
||||||
signed_txns: vec![txn.to_vec()],
|
signed_txns: vec![txn.to_vec()],
|
||||||
tries: TrieInputs {
|
tries: tries_before,
|
||||||
state_trie: PartialTrie::Empty,
|
|
||||||
transactions_trie: PartialTrie::Empty,
|
|
||||||
receipts_trie: PartialTrie::Empty,
|
|
||||||
storage_tries: vec![],
|
|
||||||
},
|
|
||||||
contract_code: HashMap::new(),
|
contract_code: HashMap::new(),
|
||||||
block_metadata,
|
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)
|
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"));
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user