diff --git a/evm/src/cpu/kernel/asm/mpt/load.asm b/evm/src/cpu/kernel/asm/mpt/load.asm index 208b7221..57c84ddb 100644 --- a/evm/src/cpu/kernel/asm/mpt/load.asm +++ b/evm/src/cpu/kernel/asm/mpt/load.asm @@ -110,10 +110,16 @@ load_mpt_extension: %append_to_trie_data // stack: retdest - %load_mpt_and_return_root_ptr - // stack: child_ptr, retdest + // Let i be the current trie data size. We still need to expand this node by + // one element, appending our child pointer. Thus our child node will start + // at i + 1. So we will set our child pointer to i + 1. + %get_trie_data_size + %add_const(1) %append_to_trie_data // stack: retdest + + %load_mpt + // stack: retdest JUMP load_mpt_leaf: diff --git a/evm/src/cpu/kernel/asm/mpt/read.asm b/evm/src/cpu/kernel/asm/mpt/read.asm index aaf39fcc..934b6bbf 100644 --- a/evm/src/cpu/kernel/asm/mpt/read.asm +++ b/evm/src/cpu/kernel/asm/mpt/read.asm @@ -63,27 +63,59 @@ mpt_read_branch_end_of_key: mpt_read_extension: // stack: node_type, node_payload_ptr, num_nibbles, key, retdest - POP - // stack: node_payload_ptr, num_nibbles, key, retdest - // TODO + %stack (node_type, node_payload_ptr, num_nibbles, key) + -> (num_nibbles, key, node_payload_ptr) + // stack: num_nibbles, key, node_payload_ptr, retdest + DUP3 %mload_trie_data + // stack: node_num_nibbles, num_nibbles, key, node_payload_ptr, retdest + SWAP1 + SUB + // stack: future_nibbles, key, node_payload_ptr, retdest + DUP2 DUP2 + // stack: future_nibbles, key, future_nibbles, key, node_payload_ptr, retdest + %mul_const(4) SHR // key_part = key >> (future_nibbles * 4) + DUP1 + // stack: key_part, key_part, future_nibbles, key, node_payload_ptr, retdest + DUP5 %add_const(1) %mload_trie_data + // stack: node_key, key_part, key_part, future_nibbles, key, node_payload_ptr, retdest + EQ // does the first part of our key match the node's key? + %jumpi(mpt_read_extension_found) + // Not found; return 0. + %stack (key_part, future_nibbles, node_payload_ptr, retdest) -> (retdest, 0) + JUMP +mpt_read_extension_found: + // stack: key_part, future_nibbles, key, node_payload_ptr, retdest + DUP2 %mul_const(4) SHL // key_part_shifted = (key_part << (future_nibbles * 4)) + // stack: key_part_shifted, future_nibbles, key, node_payload_ptr, retdest + %stack (key_part_shifted, future_nibbles, key) + -> (key, key_part_shifted, future_nibbles) + SUB // key -= key_part_shifted + // stack: key, future_nibbles, node_payload_ptr, retdest + SWAP2 + // stack: node_payload_ptr, future_nibbles, key, retdest + %add_const(2) // child pointer is third field of extension node + %mload_trie_data + // stack: child_ptr, future_nibbles, key, retdest + %jump(mpt_read) // recurse mpt_read_leaf: - // stack: node_type, node_payload_ptr, key, num_nibbles, retdest + // stack: node_type, node_payload_ptr, num_nibbles, key, retdest POP - // stack: node_payload_ptr, key, num_nibbles, retdest + // stack: node_payload_ptr, num_nibbles, key, retdest DUP1 %mload_trie_data - // stack: node_num_nibbles, node_payload_ptr, key, num_nibbles, retdest + // stack: node_num_nibbles, node_payload_ptr, num_nibbles, key, retdest DUP2 %add_const(1) %mload_trie_data - // stack: node_key, node_num_nibbles, node_payload_ptr, key, num_nibbles, retdest - SWAP4 - // stack: num_nibbles, node_num_nibbles, node_payload_ptr, key, node_key, retdest + // stack: node_key, node_num_nibbles, node_payload_ptr, num_nibbles, key, retdest + SWAP3 + // stack: num_nibbles, node_num_nibbles, node_payload_ptr, node_key, key, retdest EQ - %stack (num_nibbles_match, node_payload_ptr, key, node_key) + %stack (num_nibbles_match, node_payload_ptr, node_key, key) -> (key, node_key, num_nibbles_match, node_payload_ptr) EQ AND // stack: keys_match && num_nibbles_match, node_payload_ptr, retdest %jumpi(mpt_read_leaf_found) + // Not found; return 0. %stack (node_payload_ptr, retdest) -> (retdest, 0) JUMP mpt_read_leaf_found: diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 20d0d1f4..7577b974 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -226,7 +226,7 @@ impl<'a> Interpreter<'a> { 0x19 => self.run_not(), // "NOT", 0x1a => self.run_byte(), // "BYTE", 0x1b => self.run_shl(), // "SHL", - 0x1c => todo!(), // "SHR", + 0x1c => self.run_shr(), // "SHR", 0x1d => todo!(), // "SAR", 0x20 => self.run_keccak256(), // "KECCAK256", 0x30 => todo!(), // "ADDRESS", @@ -427,6 +427,12 @@ impl<'a> Interpreter<'a> { self.push(x << shift); } + fn run_shr(&mut self) { + let shift = self.pop(); + let x = self.pop(); + self.push(x >> shift); + } + fn run_keccak256(&mut self) { let offset = self.pop().as_usize(); let size = self.pop().as_usize(); diff --git a/evm/src/cpu/kernel/tests/mpt/load.rs b/evm/src/cpu/kernel/tests/mpt/load.rs index 01bd35a8..fbbc690a 100644 --- a/evm/src/cpu/kernel/tests/mpt/load.rs +++ b/evm/src/cpu/kernel/tests/mpt/load.rs @@ -1,11 +1,11 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::trie_type::PartialTrieType; use crate::cpu::kernel::global_metadata::GlobalMetadata; use crate::cpu::kernel::interpreter::Interpreter; +use crate::cpu::kernel::tests::mpt::state_trie_ext_to_account_leaf; use crate::generation::mpt::all_mpt_prover_inputs_reversed; use crate::generation::TrieInputs; @@ -19,13 +19,7 @@ fn load_all_mpts() -> Result<()> { let account_rlp = rlp::encode_list(&[nonce, balance, storage_root, code_hash]); let trie_inputs = TrieInputs { - state_trie: PartialTrie::Leaf { - nibbles: Nibbles { - count: 2, - packed: 123.into(), - }, - value: account_rlp.to_vec(), - }, + state_trie: state_trie_ext_to_account_leaf(account_rlp.to_vec()), transactions_trie: Default::default(), receipts_trie: Default::default(), storage_tries: vec![], @@ -40,14 +34,19 @@ fn load_all_mpts() -> Result<()> { assert_eq!(interpreter.stack(), vec![]); let type_empty = U256::from(PartialTrieType::Empty as u32); + let type_extension = U256::from(PartialTrieType::Extension as u32); let type_leaf = U256::from(PartialTrieType::Leaf as u32); assert_eq!( interpreter.get_trie_data(), vec![ - 0.into(), // First address is unused, so 0 can be treated as a null pointer. + 0.into(), // First address is unused, so that 0 can be treated as a null pointer. + type_extension, + 3.into(), // 3 nibbles + 0xABC.into(), // key part + 5.into(), // Pointer to the leaf node immediately below. type_leaf, - 2.into(), - 123.into(), + 3.into(), // 3 nibbles + 0xDEF.into(), // key part nonce, balance, storage_root, diff --git a/evm/src/cpu/kernel/tests/mpt/mod.rs b/evm/src/cpu/kernel/tests/mpt/mod.rs index febfb73f..2d14c89a 100644 --- a/evm/src/cpu/kernel/tests/mpt/mod.rs +++ b/evm/src/cpu/kernel/tests/mpt/mod.rs @@ -1,2 +1,21 @@ +use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; + mod load; mod read; + +/// A `PartialTrie` where an extension node leads to a leaf node containing an account. +pub(crate) fn state_trie_ext_to_account_leaf(value: Vec) -> PartialTrie { + PartialTrie::Extension { + nibbles: Nibbles { + count: 3, + packed: 0xABC.into(), + }, + child: Box::new(PartialTrie::Leaf { + nibbles: Nibbles { + count: 3, + packed: 0xDEF.into(), + }, + value, + }), + } +} diff --git a/evm/src/cpu/kernel/tests/mpt/read.rs b/evm/src/cpu/kernel/tests/mpt/read.rs index 3a716e33..e26ee4ab 100644 --- a/evm/src/cpu/kernel/tests/mpt/read.rs +++ b/evm/src/cpu/kernel/tests/mpt/read.rs @@ -1,10 +1,10 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::global_metadata::GlobalMetadata; use crate::cpu::kernel::interpreter::Interpreter; +use crate::cpu::kernel::tests::mpt::state_trie_ext_to_account_leaf; use crate::generation::mpt::all_mpt_prover_inputs_reversed; use crate::generation::TrieInputs; @@ -19,13 +19,7 @@ fn mpt_read() -> Result<()> { let account_rlp = rlp::encode_list(account); let trie_inputs = TrieInputs { - state_trie: PartialTrie::Leaf { - nibbles: Nibbles { - count: 2, - packed: 123.into(), - }, - value: account_rlp.to_vec(), - }, + state_trie: state_trie_ext_to_account_leaf(account_rlp.to_vec()), transactions_trie: Default::default(), receipts_trie: Default::default(), storage_tries: vec![], @@ -43,14 +37,16 @@ fn mpt_read() -> Result<()> { // Now, execute mpt_read on the state trie. interpreter.offset = mpt_read; interpreter.push(0xdeadbeefu32.into()); - interpreter.push(2.into()); - interpreter.push(123.into()); + interpreter.push(0xABCDEFu64.into()); + interpreter.push(6.into()); interpreter.push(interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot)); interpreter.run()?; + dbg!(interpreter.stack()); assert_eq!(interpreter.stack().len(), 1); let result_ptr = interpreter.stack()[0].as_usize(); - let result = &interpreter.get_trie_data()[result_ptr..result_ptr + 4]; + dbg!(result_ptr); + let result = &interpreter.get_trie_data()[result_ptr..][..account.len()]; assert_eq!(result, account); Ok(())