From c558eedd65c24547c163769e79b51094fb4ce81a Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sat, 25 Feb 2023 07:59:51 -0800 Subject: [PATCH] Misc EVM fixes --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/account_code.asm | 31 +++- evm/src/cpu/kernel/asm/core/call.asm | 4 +- evm/src/cpu/kernel/asm/core/process_txn.asm | 14 +- evm/src/cpu/kernel/asm/core/syscall_stubs.asm | 25 +++- evm/src/cpu/kernel/asm/core/terminate.asm | 27 +++- .../kernel/asm/mpt/storage/storage_write.asm | 6 + .../asm/transactions/common_decoding.asm | 139 ++++++++++++++++++ .../cpu/kernel/asm/transactions/type_0.asm | 73 ++------- .../cpu/kernel/asm/transactions/type_1.asm | 27 +++- .../cpu/kernel/asm/transactions/type_2.asm | 29 +++- .../cpu/kernel/constants/context_metadata.rs | 6 +- evm/src/generation/mod.rs | 14 +- evm/src/generation/state.rs | 9 ++ evm/src/prover.rs | 2 +- evm/src/witness/errors.rs | 1 + evm/src/witness/transition.rs | 21 ++- 17 files changed, 331 insertions(+), 98 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/transactions/common_decoding.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index a6436f5d..6738e1e6 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -93,6 +93,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/rlp/num_bytes.asm"), include_str!("asm/rlp/read_to_memory.asm"), include_str!("asm/shift.asm"), + include_str!("asm/transactions/common_decoding.asm"), include_str!("asm/transactions/router.asm"), include_str!("asm/transactions/type_0.asm"), include_str!("asm/transactions/type_1.asm"), diff --git a/evm/src/cpu/kernel/asm/account_code.asm b/evm/src/cpu/kernel/asm/account_code.asm index ebe1a5c9..7e1ece6d 100644 --- a/evm/src/cpu/kernel/asm/account_code.asm +++ b/evm/src/cpu/kernel/asm/account_code.asm @@ -36,20 +36,43 @@ global extcodehash: %%after: %endmacro +global sys_extcodesize: + // stack: kexit_info, address + SWAP1 + // stack: address, kexit_info + %extcodesize + // stack: code_size, kexit_info + SWAP1 + EXIT_KERNEL + global extcodesize: // stack: address, retdest %extcodesize // stack: extcodesize(address), retdest SWAP1 JUMP - %macro codecopy - // stack: dest_offset, offset, size, retdest + // stack: dest_offset, offset, size %address - // stack: address, dest_offset, offset, size, retdest - %jump(extcodecopy) + %extcodecopy %endmacro +%macro extcodecopy + // stack: address, dest_offset, offset, size + %stack (dest_offset, offset, size) -> (dest_offset, offset, size, %%after) + %jump(extcodecopy) +%%after: +%endmacro + +// Pre stack: kexit_info, address, dest_offset, offset, size +// Post stack: (empty) +global sys_extcodecopy: + %stack (kexit_info, address, dest_offset, offset, size) + -> (address, dest_offset, offset, size, kexit_info) + %extcodecopy + // stack: kexit_info + EXIT_KERNEL + // Pre stack: address, dest_offset, offset, size, retdest // Post stack: (empty) global extcodecopy: diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index 761ffc7d..cc1f5218 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -1,8 +1,10 @@ // Handlers for call-like operations, namely CALL, CALLCODE, STATICCALL and DELEGATECALL. +// TODO: Take kexit_info + // Creates a new sub context and executes the code of the given account. global call: - // stack: gas, address, value, args_offset, args_size, ret_offset, ret_size, retdest + // stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size %address %stack (self, gas, address, value) // These are (static, should_transfer_value, value, sender, address, code_addr, gas) diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index 6adc0831..1796b7a5 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -29,6 +29,7 @@ global validate: // TODO: Assert nonce is correct. // TODO: Assert sender has no code. // TODO: Assert sender balance >= gas_limit * gas_price + value. + // TODO: Assert chain ID matches block metadata? // stack: retdest global buy_gas: @@ -109,7 +110,7 @@ global process_message_txn_insufficient_balance: PANIC // TODO global process_message_txn_return: - // TODO: Return leftover gas? + // TODO: Since there was no code to execute, do we still return leftover gas? JUMP global process_message_txn_code_loaded: @@ -159,9 +160,15 @@ global process_message_txn_code_loaded: MSTORE_GENERAL // stack: new_ctx, retdest - // TODO: Populate CALLDATA + // Set the new context's gas limit. + %mload_txn_field(@TXN_FIELD_GAS_LIMIT) + PUSH @CTX_METADATA_GAS_LIMIT + PUSH @SEGMENT_CONTEXT_METADATA + DUP4 // new_ctx + MSTORE_GENERAL + // stack: new_ctx, retdest - // TODO: Save parent gas and set child gas + // TODO: Copy TXN_DATA to CALLDATA // Now, switch to the new context and go to usermode with PC=0. SET_CONTEXT @@ -171,6 +178,5 @@ global process_message_txn_code_loaded: global process_message_txn_after_call: // stack: success, retdest - // TODO: Return leftover gas? Or handled by termination instructions? POP // Pop success for now. Will go into the receipt when we support that. JUMP diff --git a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm index d7f5b912..2ae89586 100644 --- a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm +++ b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm @@ -34,11 +34,11 @@ global sys_codesize: global sys_codecopy: PANIC global sys_gasprice: - PANIC -global sys_extcodesize: - PANIC -global sys_extcodecopy: - PANIC + // stack: kexit_info + %mload_txn_field(@TXN_FIELD_COMPUTED_FEE_PER_GAS) + // stack: gas_price, kexit_info + SWAP1 + EXIT_KERNEL global sys_returndatasize: PANIC global sys_returndatacopy: @@ -54,17 +54,28 @@ global sys_timestamp: global sys_number: PANIC global sys_prevrandao: + // TODO: What semantics will this have for Edge? PANIC global sys_gaslimit: + // TODO: Return the block's gas limit. PANIC global sys_chainid: - PANIC + // TODO: Return the block's chain ID instead of the txn's, even though they should match. + // stack: kexit_info + %mload_txn_field(@TXN_FIELD_CHAIN_ID) + // stack: chain_id, kexit_info + SWAP1 + EXIT_KERNEL global sys_selfbalance: PANIC global sys_basefee: PANIC global sys_msize: - PANIC + // stack: kexit_info + %mload_context_metadata(@CTX_METADATA_MSIZE) + // stack: msize, kexit_info + SWAP1 + EXIT_KERNEL global sys_gas: PANIC global sys_log0: diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index e3b88d3d..b75ed987 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -2,28 +2,36 @@ // RETURN, SELFDESTRUCT, REVERT, and exceptions such as stack underflow. global sys_stop: + // stack: kexit_info + %refund_leftover_gas + // stack: (empty) // TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE to 0. - // TODO: Refund unused gas to parent. PUSH 1 // success %jump(terminate_common) global sys_return: + // stack: kexit_info + %refund_leftover_gas + // stack: (empty) // TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE. // TODO: Copy returned memory to parent context's RETURNDATA (but not if we're returning from a constructor?) // TODO: Copy returned memory to parent context's memory (as specified in their call instruction) - // TODO: Refund unused gas to parent. PUSH 1 // success %jump(terminate_common) global sys_selfdestruct: + // stack: kexit_info %consume_gas_const(@GAS_SELFDESTRUCT) + %refund_leftover_gas + // stack: (empty) // TODO: Destroy account. - // TODO: Refund unused gas to parent. PUSH 1 // success %jump(terminate_common) global sys_revert: - // TODO: Refund unused gas to parent. + // stack: kexit_info + %refund_leftover_gas + // stack: (empty) // TODO: Revert state changes. PUSH 0 // success %jump(terminate_common) @@ -68,3 +76,14 @@ terminate_common: // stack: parent_pc, success JUMP + +%macro refund_leftover_gas + // stack: kexit_info + %shr_const(192) + // stack: gas_used + %mload_context_metadata(@CTX_METADATA_GAS_LIMIT) + SUB + // stack: leftover_gas + POP // TODO: Refund to caller. + // stack: (empty) +%endmacro diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm index a56117a7..f56a5fdf 100644 --- a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -4,6 +4,12 @@ // Post stack: (empty) global sys_sstore: + // TODO: Assuming a cold zero -> nonzero write for now. + PUSH @GAS_COLDSLOAD + PUSH @GAS_SSET + ADD + %charge_gas + %stack (kexit_info, slot, value) -> (slot, value, kexit_info) // TODO: If value = 0, delete the key instead of inserting 0. // stack: slot, value, kexit_info diff --git a/evm/src/cpu/kernel/asm/transactions/common_decoding.asm b/evm/src/cpu/kernel/asm/transactions/common_decoding.asm new file mode 100644 index 00000000..71440d1c --- /dev/null +++ b/evm/src/cpu/kernel/asm/transactions/common_decoding.asm @@ -0,0 +1,139 @@ +// Store chain ID = 1. Used for non-legacy txns which always have a chain ID. +%macro store_chain_id_present_true + PUSH 1 + %mstore_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT) +%endmacro + +// Decode the chain ID and store it. +%macro decode_and_store_chain_id + // stack: pos + %decode_rlp_scalar + %stack (pos, chain_id) -> (chain_id, pos) + %mstore_txn_field(@TXN_FIELD_CHAIN_ID) + // stack: pos +%endmacro + +// Decode the nonce and store it. +%macro decode_and_store_nonce + // stack: pos + %decode_rlp_scalar + %stack (pos, nonce) -> (nonce, pos) + %mstore_txn_field(@TXN_FIELD_NONCE) + // stack: pos +%endmacro + +// Decode the gas price and, since this is for legacy txns, store it as both +// TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS and TXN_FIELD_MAX_FEE_PER_GAS. +%macro decode_and_store_gas_price_legacy + // stack: pos + %decode_rlp_scalar + %stack (pos, gas_price) -> (gas_price, gas_price, pos) + %mstore_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS) + %mstore_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) + // stack: pos +%endmacro + +// Decode the max priority fee and store it. +%macro decode_and_store_max_priority_fee + // stack: pos + %decode_rlp_scalar + %stack (pos, gas_price) -> (gas_price, pos) + %mstore_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS) + // stack: pos +%endmacro + +// Decode the max fee and store it. +%macro decode_and_store_max_fee + // stack: pos + %decode_rlp_scalar + %stack (pos, gas_price) -> (gas_price, pos) + %mstore_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) + // stack: pos +%endmacro + +// Decode the gas limit and store it. +%macro decode_and_store_gas_limit + // stack: pos + %decode_rlp_scalar + %stack (pos, gas_limit) -> (gas_limit, pos) + %mstore_txn_field(@TXN_FIELD_GAS_LIMIT) + // stack: pos +%endmacro + +// Decode the "to" field and store it. +%macro decode_and_store_to + // stack: pos + %decode_rlp_scalar + %stack (pos, to) -> (to, pos) + %mstore_txn_field(@TXN_FIELD_TO) + // stack: pos +%endmacro + +// Decode the "value" field and store it. +%macro decode_and_store_value + // stack: pos + %decode_rlp_scalar + %stack (pos, value) -> (value, pos) + %mstore_txn_field(@TXN_FIELD_VALUE) + // stack: pos +%endmacro + +// Decode the calldata field, store its length in @TXN_FIELD_DATA_LEN, and copy it to @SEGMENT_TXN_DATA. +%macro decode_and_store_data + // stack: pos + // Decode the data length, store it, and compute new_pos after any data. + %decode_rlp_string_len + %stack (pos, data_len) -> (data_len, pos, data_len, pos, data_len) + %mstore_txn_field(@TXN_FIELD_DATA_LEN) + // stack: pos, data_len, pos, data_len + ADD + // stack: new_pos, old_pos, data_len + + // Memcpy the txn data from @SEGMENT_RLP_RAW to @SEGMENT_TXN_DATA. + %stack (new_pos, old_pos, data_len) -> (old_pos, data_len, %%after, new_pos) + PUSH @SEGMENT_RLP_RAW + GET_CONTEXT + PUSH 0 + PUSH @SEGMENT_TXN_DATA + GET_CONTEXT + // stack: DST, SRC, data_len, %%after, new_pos + %jump(memcpy) + +%%after: + // stack: new_pos +%endmacro + +%macro decode_and_store_access_list + // stack: pos + %decode_rlp_list_len + %stack (pos, len) -> (len, pos) + %jumpi(todo_access_lists_not_supported_yet) + // stack: pos +%endmacro + +%macro decode_and_store_y_parity + // stack: pos + %decode_rlp_scalar + %stack (pos, y_parity) -> (y_parity, pos) + %mstore_txn_field(@TXN_FIELD_Y_PARITY) + // stack: pos +%endmacro + +%macro decode_and_store_r + // stack: pos + %decode_rlp_scalar + %stack (pos, r) -> (r, pos) + %mstore_txn_field(@TXN_FIELD_R) + // stack: pos +%endmacro + +%macro decode_and_store_s + // stack: pos + %decode_rlp_scalar + %stack (pos, s) -> (s, pos) + %mstore_txn_field(@TXN_FIELD_S) + // stack: pos +%endmacro + +global todo_access_lists_not_supported_yet: + PANIC diff --git a/evm/src/cpu/kernel/asm/transactions/type_0.asm b/evm/src/cpu/kernel/asm/transactions/type_0.asm index d1f00ed9..e9aedca0 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_0.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_0.asm @@ -19,61 +19,16 @@ global process_type_0_txn: // We don't actually need the length. %stack (pos, len) -> (pos) - // Decode the nonce and store it. // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, nonce) -> (nonce, pos) - %mstore_txn_field(@TXN_FIELD_NONCE) - - // Decode the gas price and store it. - // For legacy transactions, we set both the - // TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS and TXN_FIELD_MAX_FEE_PER_GAS - // fields to gas_price. + %decode_and_store_nonce + %decode_and_store_gas_price_legacy + %decode_and_store_gas_limit + %decode_and_store_to + %decode_and_store_value + %decode_and_store_data // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, gas_price) -> (gas_price, gas_price, pos) - %mstore_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS) - %mstore_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) - // Decode the gas limit and store it. - // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, gas_limit) -> (gas_limit, pos) - %mstore_txn_field(@TXN_FIELD_GAS_LIMIT) - - // Decode the "to" field and store it. - // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, to) -> (to, pos) - %mstore_txn_field(@TXN_FIELD_TO) - - // Decode the value field and store it. - // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, value) -> (value, pos) - %mstore_txn_field(@TXN_FIELD_VALUE) - - // Decode the data length, store it, and compute new_pos after any data. - // stack: pos, retdest - %decode_rlp_string_len - %stack (pos, data_len) -> (data_len, pos, data_len, pos, data_len) - %mstore_txn_field(@TXN_FIELD_DATA_LEN) - // stack: pos, data_len, pos, data_len, retdest - ADD - // stack: new_pos, pos, data_len, retdest - - // Memcpy the txn data from @SEGMENT_RLP_RAW to @SEGMENT_TXN_DATA. - PUSH parse_v - %stack (parse_v, new_pos, old_pos, data_len) -> (old_pos, data_len, parse_v, new_pos) - PUSH @SEGMENT_RLP_RAW - GET_CONTEXT - PUSH 0 - PUSH @SEGMENT_TXN_DATA - GET_CONTEXT - // stack: DST, SRC, data_len, parse_v, new_pos, retdest - %jump(memcpy) - -parse_v: + // Parse the "v" field. // stack: pos, retdest %decode_rlp_scalar // stack: pos, v, retdest @@ -93,7 +48,7 @@ parse_v: %mstore_txn_field(@TXN_FIELD_Y_PARITY) // stack: pos, retdest - %jump(parse_r) + %jump(decode_r_and_s) process_v_new_style: // stack: v, pos, retdest @@ -115,16 +70,12 @@ process_v_new_style: // stack: y_parity, pos, retdest %mstore_txn_field(@TXN_FIELD_Y_PARITY) -parse_r: +decode_r_and_s: // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, r) -> (r, pos) - %mstore_txn_field(@TXN_FIELD_R) - + %decode_and_store_r + %decode_and_store_s // stack: pos, retdest - %decode_rlp_scalar - %stack (pos, s) -> (s) - %mstore_txn_field(@TXN_FIELD_S) + POP // stack: retdest type_0_compute_signed_data: diff --git a/evm/src/cpu/kernel/asm/transactions/type_1.asm b/evm/src/cpu/kernel/asm/transactions/type_1.asm index 8c7fcaae..fbd934d9 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_1.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_1.asm @@ -8,4 +8,29 @@ global process_type_1_txn: // stack: retdest - PANIC // TODO: Unfinished + PUSH 1 // initial pos, skipping over the 0x01 byte + // stack: pos, retdest + %decode_rlp_list_len + // We don't actually need the length. + %stack (pos, len) -> (pos) + + %store_chain_id_present_true + %decode_and_store_chain_id + %decode_and_store_nonce + %decode_and_store_gas_price_legacy + %decode_and_store_gas_limit + %decode_and_store_to + %decode_and_store_value + %decode_and_store_data + %decode_and_store_access_list + %decode_and_store_y_parity + %decode_and_store_r + %decode_and_store_s + + // stack: pos, retdest + POP + // stack: retdest + + // TODO: Check signature. + + %jump(process_normalized_txn) diff --git a/evm/src/cpu/kernel/asm/transactions/type_2.asm b/evm/src/cpu/kernel/asm/transactions/type_2.asm index f1ff18d8..d9586c21 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_2.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_2.asm @@ -9,4 +9,31 @@ global process_type_2_txn: // stack: retdest - PANIC // TODO: Unfinished + PUSH 1 // initial pos, skipping over the 0x02 byte + // stack: pos, retdest + %decode_rlp_list_len + // We don't actually need the length. + %stack (pos, len) -> (pos) + + // stack: pos, retdest + %store_chain_id_present_true + %decode_and_store_chain_id + %decode_and_store_nonce + %decode_and_store_max_priority_fee + %decode_and_store_max_fee + %decode_and_store_gas_limit + %decode_and_store_to + %decode_and_store_value + %decode_and_store_data + %decode_and_store_access_list + %decode_and_store_y_parity + %decode_and_store_r + %decode_and_store_s + + // stack: pos, retdest + POP + // stack: retdest + + // TODO: Check signature. + + %jump(process_normalized_txn) diff --git a/evm/src/cpu/kernel/constants/context_metadata.rs b/evm/src/cpu/kernel/constants/context_metadata.rs index 27bec078..4e869661 100644 --- a/evm/src/cpu/kernel/constants/context_metadata.rs +++ b/evm/src/cpu/kernel/constants/context_metadata.rs @@ -26,10 +26,12 @@ pub(crate) enum ContextMetadata { /// Size of the active main memory. MSize = 10, StackSize = 11, + /// The gas limit for this call (not the entire transaction). + GasLimit = 12, } impl ContextMetadata { - pub(crate) const COUNT: usize = 12; + pub(crate) const COUNT: usize = 13; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -45,6 +47,7 @@ impl ContextMetadata { Self::StateTrieCheckpointPointer, Self::MSize, Self::StackSize, + Self::GasLimit, ] } @@ -63,6 +66,7 @@ impl ContextMetadata { ContextMetadata::StateTrieCheckpointPointer => "CTX_METADATA_STATE_TRIE_CHECKPOINT_PTR", ContextMetadata::MSize => "CTX_METADATA_MSIZE", ContextMetadata::StackSize => "CTX_METADATA_STACK_SIZE", + ContextMetadata::GasLimit => "CTX_METADATA_GAS_LIMIT", } } } diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 858bb111..d36e2a66 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -67,12 +67,12 @@ pub(crate) fn generate_traces, const D: usize>( inputs: GenerationInputs, config: &StarkConfig, timing: &mut TimingTree, -) -> ([Vec>; NUM_TABLES], PublicValues) { +) -> anyhow::Result<([Vec>; NUM_TABLES], PublicValues)> { let mut state = GenerationState::::new(inputs.clone(), &KERNEL.code); generate_bootstrap_kernel::(&mut state); - timed!(timing, "simulate CPU", simulate_cpu(&mut state)); + timed!(timing, "simulate CPU", simulate_cpu(&mut state)?); log::info!( "Trace lengths (before padding): {:?}", @@ -109,10 +109,12 @@ pub(crate) fn generate_traces, const D: usize>( "convert trace data to tables", state.traces.into_tables(all_stark, config, timing) ); - (tables, public_values) + Ok((tables, public_values)) } -fn simulate_cpu, const D: usize>(state: &mut GenerationState) { +fn simulate_cpu, const D: usize>( + state: &mut GenerationState, +) -> anyhow::Result<()> { let halt_pc0 = KERNEL.global_labels["halt_pc0"]; let halt_pc1 = KERNEL.global_labels["halt_pc1"]; @@ -126,11 +128,13 @@ fn simulate_cpu, const D: usize>(state: &mut Genera } already_in_halt_loop |= in_halt_loop; - transition(state); + transition(state)?; if already_in_halt_loop && state.traces.clock().is_power_of_two() { log::info!("CPU trace padded to {} cycles", state.traces.clock()); break; } } + + Ok(()) } diff --git a/evm/src/generation/state.rs b/evm/src/generation/state.rs index bf1fbd74..88f17ade 100644 --- a/evm/src/generation/state.rs +++ b/evm/src/generation/state.rs @@ -33,6 +33,15 @@ pub(crate) struct GenerationState { impl GenerationState { pub(crate) fn new(inputs: GenerationInputs, kernel_code: &[u8]) -> Self { + log::debug!("Input signed_txns: {:?}", &inputs.signed_txns); + log::debug!("Input state_trie: {:?}", &inputs.tries.state_trie); + log::debug!( + "Input transactions_trie: {:?}", + &inputs.tries.transactions_trie + ); + log::debug!("Input receipts_trie: {:?}", &inputs.tries.receipts_trie); + log::debug!("Input storage_tries: {:?}", &inputs.tries.storage_tries); + log::debug!("Input contract_code: {:?}", &inputs.contract_code); let mpt_prover_inputs = all_mpt_prover_inputs_reversed(&inputs.tries); let rlp_prover_inputs = all_rlp_prover_inputs_reversed(&inputs.signed_txns); diff --git a/evm/src/prover.rs b/evm/src/prover.rs index c801950a..9e26218a 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -60,7 +60,7 @@ where let (traces, public_values) = timed!( timing, "generate all traces", - generate_traces(all_stark, inputs, config, timing) + generate_traces(all_stark, inputs, config, timing)? ); prove_with_traces(all_stark, config, traces, public_values, timing) } diff --git a/evm/src/witness/errors.rs b/evm/src/witness/errors.rs index bd4b03c9..53263675 100644 --- a/evm/src/witness/errors.rs +++ b/evm/src/witness/errors.rs @@ -7,4 +7,5 @@ pub enum ProgramError { InvalidJumpDestination, InvalidJumpiDestination, StackOverflow, + KernelPanic, } diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index d233655c..ff10b08b 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -1,3 +1,4 @@ +use anyhow::bail; use itertools::Itertools; use log::log_enabled; use plonky2::field::types::Field; @@ -117,10 +118,13 @@ fn decode(registers: RegistersState, opcode: u8) -> Result 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) - ), + (0xa5, _) => { + log::warn!( + "Kernel panic at {}", + KERNEL.offset_name(registers.program_counter) + ); + Err(ProgramError::KernelPanic) + } (0xf0, _) => Ok(Operation::Syscall(opcode)), (0xf1, _) => Ok(Operation::Syscall(opcode)), (0xf2, _) => Ok(Operation::Syscall(opcode)), @@ -288,11 +292,11 @@ fn log_kernel_instruction(state: &mut GenerationState, op: Operatio assert!(pc < KERNEL.code.len(), "Kernel PC is out of range: {}", pc); } -fn handle_error(_state: &mut GenerationState) { - todo!("generation for exception handling is not implemented"); +fn handle_error(_state: &mut GenerationState) -> anyhow::Result<()> { + bail!("TODO: generation for exception handling is not implemented"); } -pub(crate) fn transition(state: &mut GenerationState) { +pub(crate) fn transition(state: &mut GenerationState) -> anyhow::Result<()> { let checkpoint = state.checkpoint(); let result = try_perform_instruction(state); @@ -301,11 +305,12 @@ pub(crate) fn transition(state: &mut GenerationState) { state .memory .apply_ops(state.traces.mem_ops_since(checkpoint.traces)); + Ok(()) } Err(e) => { if state.registers.is_kernel { let offset_name = KERNEL.offset_name(state.registers.program_counter); - panic!("exception in kernel mode at {}: {:?}", offset_name, e); + bail!("exception in kernel mode at {}: {:?}", offset_name, e); } state.rollback(checkpoint); handle_error(state)