From d6b5193c9b706f64f8670dac5799de9e72da1ed8 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Fri, 29 Jul 2022 13:50:16 -0700 Subject: [PATCH 01/13] RLP decoding tests --- evm/src/cpu/kernel/asm/rlp/decode.asm | 2 + evm/src/cpu/kernel/interpreter.rs | 63 +++++++++---- evm/src/cpu/kernel/tests/mod.rs | 1 + evm/src/cpu/kernel/tests/rlp.rs | 129 ++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 evm/src/cpu/kernel/tests/rlp.rs diff --git a/evm/src/cpu/kernel/asm/rlp/decode.asm b/evm/src/cpu/kernel/asm/rlp/decode.asm index 76daec1a..24d8d5a7 100644 --- a/evm/src/cpu/kernel/asm/rlp/decode.asm +++ b/evm/src/cpu/kernel/asm/rlp/decode.asm @@ -32,6 +32,7 @@ global decode_rlp_string_len: JUMP decode_rlp_string_len_medium: + JUMPDEST // String is 0-55 bytes long. First byte contains the len. // stack: first_byte, pos, retdest %sub_const(0x80) @@ -43,6 +44,7 @@ decode_rlp_string_len_medium: JUMP decode_rlp_string_len_large: + JUMPDEST // String is >55 bytes long. First byte contains the len of the len. // stack: first_byte, pos, retdest %sub_const(0xb7) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 5c2f6514..6a9d31fa 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, bail}; use ethereum_types::{BigEndianHash, U256, U512}; use keccak_hash::keccak; +use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::assembler::Kernel; use crate::cpu::kernel::prover_input::ProverInputFn; use crate::generation::memory::{MemoryContextState, MemorySegmentState}; @@ -14,7 +15,7 @@ const HALT_OFFSET: usize = 0xdeadbeef; #[derive(Debug)] pub(crate) struct InterpreterMemory { - context_memory: Vec, + pub(crate) context_memory: Vec, } impl Default for InterpreterMemory { @@ -51,13 +52,14 @@ pub struct Interpreter<'a> { jumpdests: Vec, offset: usize, context: usize, - memory: InterpreterMemory, + pub(crate) memory: InterpreterMemory, prover_inputs_map: &'a HashMap, prover_inputs: Vec, running: bool, } pub fn run_with_kernel( + // TODO: Remove param and just use KERNEL. kernel: &Kernel, initial_offset: usize, initial_stack: Vec, @@ -76,24 +78,45 @@ pub fn run<'a>( initial_stack: Vec, prover_inputs: &'a HashMap, ) -> anyhow::Result> { - let mut interpreter = Interpreter { - jumpdests: find_jumpdests(code), - offset: initial_offset, - memory: InterpreterMemory::with_code_and_stack(code, initial_stack), - prover_inputs_map: prover_inputs, - prover_inputs: Vec::new(), - context: 0, - running: true, - }; - - while interpreter.running { - interpreter.run_opcode()?; - } - + let mut interpreter = Interpreter::new(code, initial_offset, initial_stack, prover_inputs); + interpreter.run()?; Ok(interpreter) } impl<'a> Interpreter<'a> { + pub(crate) fn new_with_kernel(initial_offset: usize, initial_stack: Vec) -> Self { + Self::new( + &KERNEL.code, + initial_offset, + initial_stack, + &KERNEL.prover_inputs, + ) + } + + pub(crate) fn new( + code: &'a [u8], + initial_offset: usize, + initial_stack: Vec, + prover_inputs: &'a HashMap, + ) -> Self { + Self { + jumpdests: find_jumpdests(code), + offset: initial_offset, + memory: InterpreterMemory::with_code_and_stack(code, initial_stack), + prover_inputs_map: prover_inputs, + prover_inputs: Vec::new(), + context: 0, + running: true, + } + } + + pub(crate) fn run(&mut self) -> anyhow::Result<()> { + while self.running { + self.run_opcode()?; + } + Ok(()) + } + fn code(&self) -> &MemorySegmentState { &self.memory.context_memory[self.context].segments[Segment::Code as usize] } @@ -156,7 +179,7 @@ impl<'a> Interpreter<'a> { 0x18 => self.run_xor(), // "XOR", 0x19 => self.run_not(), // "NOT", 0x1a => todo!(), // "BYTE", - 0x1b => todo!(), // "SHL", + 0x1b => self.run_shl(), // "SHL", 0x1c => todo!(), // "SHR", 0x1d => todo!(), // "SAR", 0x20 => self.run_keccak256(), // "KECCAK256", @@ -339,6 +362,12 @@ impl<'a> Interpreter<'a> { self.push(!x); } + fn run_shl(&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/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index 100ef377..73eb3ada 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -1,6 +1,7 @@ mod curve_ops; mod ecrecover; mod exp; +mod rlp; use std::str::FromStr; diff --git a/evm/src/cpu/kernel/tests/rlp.rs b/evm/src/cpu/kernel/tests/rlp.rs new file mode 100644 index 00000000..e74213da --- /dev/null +++ b/evm/src/cpu/kernel/tests/rlp.rs @@ -0,0 +1,129 @@ +use std::str::FromStr; + +use anyhow::Result; +use ethereum_types::U256; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::interpreter::Interpreter; +use crate::memory::segments::Segment; + +#[test] +fn test_decode_rlp_string_len_short() -> Result<()> { + let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; + + let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); + + // A couple dummy bytes, followed by "0x70" which is its own encoding. + set_rlp_memory(&mut interpreter, vec![123, 234, 0x70]); + + interpreter.run()?; + let expected_stack = vec![1.into(), 2.into()]; // len, pos + assert_eq!(interpreter.stack(), expected_stack); + + Ok(()) +} + +#[test] +fn test_decode_rlp_string_len_medium() -> Result<()> { + let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; + + let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); + + // A couple dummy bytes, followed by the RLP encoding of "1 2 3 4 5". + set_rlp_memory(&mut interpreter, vec![123, 234, 0x85, 1, 2, 3, 4, 5]); + + interpreter.run()?; + let expected_stack = vec![5.into(), 3.into()]; // len, pos + assert_eq!(interpreter.stack(), expected_stack); + + Ok(()) +} + +#[test] +fn test_decode_rlp_string_len_long() -> Result<()> { + let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; + + let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); + + // The RLP encoding of the string "1 2 3 ... 56". + set_rlp_memory( + &mut interpreter, + vec![ + 123, 234, 0xb8, 56, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + ], + ); + + interpreter.run()?; + let expected_stack = vec![56.into(), 4.into()]; // len, pos + assert_eq!(interpreter.stack(), expected_stack); + + Ok(()) +} + +#[test] +fn test_decode_rlp_list_len_short() -> Result<()> { + let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; + + let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); + + // The RLP encoding of [1, 2, [3, 4]]. + set_rlp_memory(&mut interpreter, vec![0xc5, 1, 2, 0xc2, 3, 4]); + + interpreter.run()?; + let expected_stack = vec![5.into(), 1.into()]; // len, pos + assert_eq!(interpreter.stack(), expected_stack); + + Ok(()) +} + +#[test] +fn test_decode_rlp_list_len_long() -> Result<()> { + let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; + + let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); + + // The RLP encoding of [1, ..., 56]. + set_rlp_memory( + &mut interpreter, + vec![ + 0xf8, 56, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + ], + ); + + interpreter.run()?; + let expected_stack = vec![56.into(), 2.into()]; // len, pos + assert_eq!(interpreter.stack(), expected_stack); + + Ok(()) +} + +#[test] +fn test_decode_rlp_scalar() -> Result<()> { + let decode_rlp_scalar = KERNEL.global_labels["decode_rlp_scalar"]; + + let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let mut interpreter = Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); + + // The RLP encoding of "12 34 56". + set_rlp_memory(&mut interpreter, vec![0x83, 0x12, 0x34, 0x56]); + + interpreter.run()?; + let expected_stack = vec![0x123456.into(), 4.into()]; // scalar, pos + assert_eq!(interpreter.stack(), expected_stack); + + Ok(()) +} + +fn set_rlp_memory(interpreter: &mut Interpreter, rlp: Vec) { + interpreter.memory.context_memory[0].segments[Segment::RlpRaw as usize].content = + rlp.into_iter().map(U256::from).collect(); +} From 36187937060d467eb27d0b37876d21e10c8e1e22 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 11:00:12 -0700 Subject: [PATCH 02/13] Test for parsing type 0 transactions I made a couple related changes to `Interpreter`: - Only enforce the `JUMPDEST` rule if we're in kernel mode. - Convenience methods for dealing with the RLP and txn field segments of memory. --- evm/src/cpu/kernel/interpreter.rs | 43 ++++++++++++------ evm/src/cpu/kernel/tests/mod.rs | 1 + evm/src/cpu/kernel/tests/rlp.rs | 39 ++++++---------- evm/src/cpu/kernel/tests/type_0_txn.rs | 63 ++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 38 deletions(-) create mode 100644 evm/src/cpu/kernel/tests/type_0_txn.rs diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 6a9d31fa..3b753f0a 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -7,11 +7,12 @@ use keccak_hash::keccak; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::assembler::Kernel; use crate::cpu::kernel::prover_input::ProverInputFn; +use crate::cpu::kernel::txn_fields::NormalizedTxnField; use crate::generation::memory::{MemoryContextState, MemorySegmentState}; use crate::memory::segments::Segment; /// Halt interpreter execution whenever a jump to this offset is done. -const HALT_OFFSET: usize = 0xdeadbeef; +const DEFAULT_HALT_OFFSET: usize = 0xdeadbeef; #[derive(Debug)] pub(crate) struct InterpreterMemory { @@ -49,12 +50,14 @@ impl InterpreterMemory { } pub struct Interpreter<'a> { + kernel_mode: bool, jumpdests: Vec, offset: usize, context: usize, pub(crate) memory: InterpreterMemory, prover_inputs_map: &'a HashMap, prover_inputs: Vec, + pub(crate) halt_offsets: Vec, running: bool, } @@ -100,12 +103,14 @@ impl<'a> Interpreter<'a> { prover_inputs: &'a HashMap, ) -> Self { Self { + kernel_mode: true, jumpdests: find_jumpdests(code), offset: initial_offset, memory: InterpreterMemory::with_code_and_stack(code, initial_stack), prover_inputs_map: prover_inputs, prover_inputs: Vec::new(), context: 0, + halt_offsets: vec![DEFAULT_HALT_OFFSET], running: true, } } @@ -128,6 +133,15 @@ impl<'a> Interpreter<'a> { .collect::>() } + pub(crate) fn get_txn_field(&self, field: NormalizedTxnField) -> U256 { + self.memory.context_memory[0].segments[Segment::TxnFields as usize].content[field as usize] + } + + pub(crate) fn set_rlp_memory(&mut self, rlp: Vec) { + self.memory.context_memory[0].segments[Segment::RlpRaw as usize].content = + rlp.into_iter().map(U256::from).collect(); + } + fn incr(&mut self, n: usize) { self.offset += n; } @@ -435,24 +449,27 @@ impl<'a> Interpreter<'a> { fn run_jump(&mut self) { let x = self.pop().as_usize(); - self.offset = x; - if self.offset == HALT_OFFSET { - self.running = false; - } else if self.jumpdests.binary_search(&self.offset).is_err() { - panic!("Destination is not a JUMPDEST."); - } + self.jump_to(x); } fn run_jumpi(&mut self) { let x = self.pop().as_usize(); let b = self.pop(); if !b.is_zero() { - self.offset = x; - if self.offset == HALT_OFFSET { - self.running = false; - } else if self.jumpdests.binary_search(&self.offset).is_err() { - panic!("Destination is not a JUMPDEST."); - } + self.jump_to(x); + } + } + + fn jump_to(&mut self, offset: usize) { + // The JUMPDEST rule is not enforced in kernel mode. + if !self.kernel_mode && self.jumpdests.binary_search(&offset).is_err() { + panic!("Destination is not a JUMPDEST."); + } + + self.offset = offset; + + if self.halt_offsets.contains(&offset) { + self.running = false; } } diff --git a/evm/src/cpu/kernel/tests/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index 73eb3ada..e912388b 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -2,6 +2,7 @@ mod curve_ops; mod ecrecover; mod exp; mod rlp; +mod type_0_txn; use std::str::FromStr; diff --git a/evm/src/cpu/kernel/tests/rlp.rs b/evm/src/cpu/kernel/tests/rlp.rs index e74213da..fd790dcb 100644 --- a/evm/src/cpu/kernel/tests/rlp.rs +++ b/evm/src/cpu/kernel/tests/rlp.rs @@ -15,7 +15,7 @@ fn test_decode_rlp_string_len_short() -> Result<()> { let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by "0x70" which is its own encoding. - set_rlp_memory(&mut interpreter, vec![123, 234, 0x70]); + interpreter.set_rlp_memory(vec![123, 234, 0x70]); interpreter.run()?; let expected_stack = vec![1.into(), 2.into()]; // len, pos @@ -32,7 +32,7 @@ fn test_decode_rlp_string_len_medium() -> Result<()> { let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by the RLP encoding of "1 2 3 4 5". - set_rlp_memory(&mut interpreter, vec![123, 234, 0x85, 1, 2, 3, 4, 5]); + interpreter.set_rlp_memory(vec![123, 234, 0x85, 1, 2, 3, 4, 5]); interpreter.run()?; let expected_stack = vec![5.into(), 3.into()]; // len, pos @@ -49,14 +49,11 @@ fn test_decode_rlp_string_len_long() -> Result<()> { let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // The RLP encoding of the string "1 2 3 ... 56". - set_rlp_memory( - &mut interpreter, - vec![ - 123, 234, 0xb8, 56, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - ], - ); + interpreter.set_rlp_memory(vec![ + 123, 234, 0xb8, 56, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + ]); interpreter.run()?; let expected_stack = vec![56.into(), 4.into()]; // len, pos @@ -73,7 +70,7 @@ fn test_decode_rlp_list_len_short() -> Result<()> { let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, 2, [3, 4]]. - set_rlp_memory(&mut interpreter, vec![0xc5, 1, 2, 0xc2, 3, 4]); + interpreter.set_rlp_memory(vec![0xc5, 1, 2, 0xc2, 3, 4]); interpreter.run()?; let expected_stack = vec![5.into(), 1.into()]; // len, pos @@ -90,14 +87,11 @@ fn test_decode_rlp_list_len_long() -> Result<()> { let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, ..., 56]. - set_rlp_memory( - &mut interpreter, - vec![ - 0xf8, 56, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - ], - ); + interpreter.set_rlp_memory(vec![ + 0xf8, 56, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + ]); interpreter.run()?; let expected_stack = vec![56.into(), 2.into()]; // len, pos @@ -114,7 +108,7 @@ fn test_decode_rlp_scalar() -> Result<()> { let mut interpreter = Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); // The RLP encoding of "12 34 56". - set_rlp_memory(&mut interpreter, vec![0x83, 0x12, 0x34, 0x56]); + interpreter.set_rlp_memory(vec![0x83, 0x12, 0x34, 0x56]); interpreter.run()?; let expected_stack = vec![0x123456.into(), 4.into()]; // scalar, pos @@ -122,8 +116,3 @@ fn test_decode_rlp_scalar() -> Result<()> { Ok(()) } - -fn set_rlp_memory(interpreter: &mut Interpreter, rlp: Vec) { - interpreter.memory.context_memory[0].segments[Segment::RlpRaw as usize].content = - rlp.into_iter().map(U256::from).collect(); -} diff --git a/evm/src/cpu/kernel/tests/type_0_txn.rs b/evm/src/cpu/kernel/tests/type_0_txn.rs new file mode 100644 index 00000000..437795e9 --- /dev/null +++ b/evm/src/cpu/kernel/tests/type_0_txn.rs @@ -0,0 +1,63 @@ +use std::str::FromStr; + +use anyhow::Result; +use ethereum_types::U256; +use hex_literal::hex; +use NormalizedTxnField::*; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::interpreter::Interpreter; +use crate::cpu::kernel::tests::rlp::set_rlp_memory; +use crate::cpu::kernel::txn_fields::NormalizedTxnField; + +#[test] +fn process_type_0_txn() -> Result<()> { + let process_type_0_txn = KERNEL.global_labels["process_type_0_txn"]; + let process_normalized_txn = KERNEL.global_labels["process_normalized_txn"]; + + let mut interpreter = Interpreter::new_with_kernel(process_type_0_txn, vec![]); + + // When we reach process_normalized_txn, we're done with parsing and normalizing. + // Processing normalized transactions is outside the scope of this test. + interpreter.halt_offsets.push(process_normalized_txn); + + // Generated with py-evm: + // unsigned_txn = chain.create_unsigned_transaction( + // nonce=5, + // gas_price=10, + // gas=22_000, + // to=constants.ZERO_ADDRESS, + // value=100, + // data=b'\x42\x42', + // ) + // my_txn = unsigned_txn.as_signed_transaction(my_sk) + // rlp.encode(my_txn) + interpreter.set_rlp_memory(hex!("f861050a8255f0940000000000000000000000000000000000000000648242421ca07c5c61ed975ebd286f6b027b8c504842e50a47d318e1e801719dd744fe93e6c6a01e7b5119b57dd54e175ff2f055c91f3ab1b53eba0b2c184f347cdff0e745aca2").to_vec()); + + interpreter.run()?; + + assert_eq!(interpreter.get_txn_field(ChainIdPresent), 0.into()); + assert_eq!(interpreter.get_txn_field(ChainId), 0.into()); + assert_eq!(interpreter.get_txn_field(Nonce), 5.into()); + assert_eq!(interpreter.get_txn_field(MaxPriorityFeePerGas), 10.into()); + assert_eq!(interpreter.get_txn_field(MaxPriorityFeePerGas), 10.into()); + assert_eq!(interpreter.get_txn_field(MaxFeePerGas), 10.into()); + assert_eq!(interpreter.get_txn_field(To), 0.into()); + assert_eq!(interpreter.get_txn_field(Value), 100.into()); + assert_eq!(interpreter.get_txn_field(DataLen), 2.into()); + assert_eq!(interpreter.get_txn_field(YParity), 1.into()); + assert_eq!( + interpreter.get_txn_field(R), + U256::from_big_endian(&hex!( + "7c5c61ed975ebd286f6b027b8c504842e50a47d318e1e801719dd744fe93e6c6" + )) + ); + assert_eq!( + interpreter.get_txn_field(S), + U256::from_big_endian(&hex!( + "1e7b5119b57dd54e175ff2f055c91f3ab1b53eba0b2c184f347cdff0e745aca2" + )) + ); + + Ok(()) +} From b737aeaf0325e161f81acd46d321ae5d4cc0e448 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 11:13:33 -0700 Subject: [PATCH 03/13] Tweak py-evm code --- evm/src/cpu/kernel/tests/type_0_txn.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/tests/type_0_txn.rs b/evm/src/cpu/kernel/tests/type_0_txn.rs index 437795e9..01e26423 100644 --- a/evm/src/cpu/kernel/tests/type_0_txn.rs +++ b/evm/src/cpu/kernel/tests/type_0_txn.rs @@ -22,16 +22,20 @@ fn process_type_0_txn() -> Result<()> { interpreter.halt_offsets.push(process_normalized_txn); // Generated with py-evm: + // import eth, eth_keys, eth_utils, rlp + // genesis_params = { 'difficulty': eth.constants.GENESIS_DIFFICULTY } + // chain = eth.chains.mainnet.MainnetChain.from_genesis(eth.db.atomic.AtomicDB(), genesis_params, {}) // unsigned_txn = chain.create_unsigned_transaction( // nonce=5, // gas_price=10, // gas=22_000, - // to=constants.ZERO_ADDRESS, + // to=eth.constants.ZERO_ADDRESS, // value=100, // data=b'\x42\x42', // ) - // my_txn = unsigned_txn.as_signed_transaction(my_sk) - // rlp.encode(my_txn) + // sk = eth_keys.keys.PrivateKey(eth_utils.decode_hex('4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318')) + // signed_txn = unsigned_txn.as_signed_transaction(sk) + // rlp.encode(signed_txn).hex() interpreter.set_rlp_memory(hex!("f861050a8255f0940000000000000000000000000000000000000000648242421ca07c5c61ed975ebd286f6b027b8c504842e50a47d318e1e801719dd744fe93e6c6a01e7b5119b57dd54e175ff2f055c91f3ab1b53eba0b2c184f347cdff0e745aca2").to_vec()); interpreter.run()?; From 94c9b1b09c1c5f3d02ac4d8f7ed42f63892268c2 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 11:20:56 -0700 Subject: [PATCH 04/13] Misc --- evm/src/cpu/kernel/tests/mod.rs | 2 +- evm/src/cpu/kernel/tests/rlp.rs | 1 - evm/src/cpu/kernel/tests/transaction_parsing/mod.rs | 1 + .../{type_0_txn.rs => transaction_parsing/parse_type_0_txn.rs} | 3 --- 4 files changed, 2 insertions(+), 5 deletions(-) create mode 100644 evm/src/cpu/kernel/tests/transaction_parsing/mod.rs rename evm/src/cpu/kernel/tests/{type_0_txn.rs => transaction_parsing/parse_type_0_txn.rs} (97%) diff --git a/evm/src/cpu/kernel/tests/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index e912388b..ab92c5a0 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -2,7 +2,7 @@ mod curve_ops; mod ecrecover; mod exp; mod rlp; -mod type_0_txn; +mod transaction_parsing; use std::str::FromStr; diff --git a/evm/src/cpu/kernel/tests/rlp.rs b/evm/src/cpu/kernel/tests/rlp.rs index fd790dcb..55dfc7e8 100644 --- a/evm/src/cpu/kernel/tests/rlp.rs +++ b/evm/src/cpu/kernel/tests/rlp.rs @@ -5,7 +5,6 @@ use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; -use crate::memory::segments::Segment; #[test] fn test_decode_rlp_string_len_short() -> Result<()> { diff --git a/evm/src/cpu/kernel/tests/transaction_parsing/mod.rs b/evm/src/cpu/kernel/tests/transaction_parsing/mod.rs new file mode 100644 index 00000000..fb50625f --- /dev/null +++ b/evm/src/cpu/kernel/tests/transaction_parsing/mod.rs @@ -0,0 +1 @@ +mod parse_type_0_txn; diff --git a/evm/src/cpu/kernel/tests/type_0_txn.rs b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs similarity index 97% rename from evm/src/cpu/kernel/tests/type_0_txn.rs rename to evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs index 01e26423..8b725479 100644 --- a/evm/src/cpu/kernel/tests/type_0_txn.rs +++ b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow::Result; use ethereum_types::U256; use hex_literal::hex; @@ -7,7 +5,6 @@ use NormalizedTxnField::*; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; -use crate::cpu::kernel::tests::rlp::set_rlp_memory; use crate::cpu::kernel::txn_fields::NormalizedTxnField; #[test] From b34ace4c9017927b92e20ff4170aa678ee95e66d Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 17:40:16 -0700 Subject: [PATCH 05/13] More succinct deadbeef --- evm/src/cpu/kernel/tests/exp.rs | 8 +++----- evm/src/cpu/kernel/tests/rlp.rs | 14 ++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/evm/src/cpu/kernel/tests/exp.rs b/evm/src/cpu/kernel/tests/exp.rs index 388a1ac3..25bc5ad3 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow::Result; use ethereum_types::U256; use rand::{thread_rng, Rng}; @@ -17,7 +15,7 @@ fn test_exp() -> Result<()> { let b = U256([0; 4].map(|_| rng.gen())); // Random input - let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a]; + let initial_stack = vec![0xDEADBEEFu32.into(), b, a]; let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)? .stack() .to_vec(); @@ -29,7 +27,7 @@ fn test_exp() -> Result<()> { assert_eq!(stack_with_kernel, stack_with_opcode); // 0 base - let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()]; + let initial_stack = vec![0xDEADBEEFu32.into(), b, U256::zero()]; let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)? .stack() .to_vec(); @@ -41,7 +39,7 @@ fn test_exp() -> Result<()> { assert_eq!(stack_with_kernel, stack_with_opcode); // 0 exponent - let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a]; + let initial_stack = vec![0xDEADBEEFu32.into(), U256::zero(), a]; let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)? .stack() .to_vec(); diff --git a/evm/src/cpu/kernel/tests/rlp.rs b/evm/src/cpu/kernel/tests/rlp.rs index e74213da..79407f1b 100644 --- a/evm/src/cpu/kernel/tests/rlp.rs +++ b/evm/src/cpu/kernel/tests/rlp.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow::Result; use ethereum_types::U256; @@ -11,7 +9,7 @@ use crate::memory::segments::Segment; fn test_decode_rlp_string_len_short() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by "0x70" which is its own encoding. @@ -28,7 +26,7 @@ fn test_decode_rlp_string_len_short() -> Result<()> { fn test_decode_rlp_string_len_medium() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by the RLP encoding of "1 2 3 4 5". @@ -45,7 +43,7 @@ fn test_decode_rlp_string_len_medium() -> Result<()> { fn test_decode_rlp_string_len_long() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // The RLP encoding of the string "1 2 3 ... 56". @@ -69,7 +67,7 @@ fn test_decode_rlp_string_len_long() -> Result<()> { fn test_decode_rlp_list_len_short() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, 2, [3, 4]]. @@ -86,7 +84,7 @@ fn test_decode_rlp_list_len_short() -> Result<()> { fn test_decode_rlp_list_len_long() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, ..., 56]. @@ -110,7 +108,7 @@ fn test_decode_rlp_list_len_long() -> Result<()> { fn test_decode_rlp_scalar() -> Result<()> { let decode_rlp_scalar = KERNEL.global_labels["decode_rlp_scalar"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); // The RLP encoding of "12 34 56". From 3f08cca1164d422dce8959cc27747e40de118172 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 14:49:28 -0700 Subject: [PATCH 06/13] More constants for kernel ASM - `GlobalMetadata` - offsets for global kernel variables in memory - `ContextMetadata` - offsets for context-specific kernel variables in memory - `GAS_CONSTANTS`, based on the yellowpaper Also move constants to a separate module since `aggregator` was getting long. --- evm/src/cpu/kernel/aggregator.rs | 37 +---------- evm/src/cpu/kernel/constants.rs | 87 ++++++++++++++++++++++++++ evm/src/cpu/kernel/context_metadata.rs | 33 ++++++++++ evm/src/cpu/kernel/global_metadata.rs | 23 +++++++ evm/src/cpu/kernel/mod.rs | 5 +- evm/src/memory/segments.rs | 22 ++++--- 6 files changed, 161 insertions(+), 46 deletions(-) create mode 100644 evm/src/cpu/kernel/constants.rs create mode 100644 evm/src/cpu/kernel/context_metadata.rs create mode 100644 evm/src/cpu/kernel/global_metadata.rs diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index e5e1f29f..8d45a9a2 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -1,49 +1,14 @@ //! Loads each kernel assembly file and concatenates them. -use std::collections::HashMap; - -use ethereum_types::U256; -use hex_literal::hex; use itertools::Itertools; use once_cell::sync::Lazy; use super::assembler::{assemble, Kernel}; +use crate::cpu::kernel::constants::evm_constants; use crate::cpu::kernel::parser::parse; -use crate::cpu::kernel::txn_fields::NormalizedTxnField; -use crate::memory::segments::Segment; pub static KERNEL: Lazy = Lazy::new(combined_kernel); -const EC_CONSTANTS: [(&str, [u8; 32]); 3] = [ - ( - "BN_BASE", - hex!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"), - ), - ( - "SECP_BASE", - hex!("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), - ), - ( - "SECP_SCALAR", - hex!("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), - ), -]; - -pub fn evm_constants() -> HashMap { - let mut c = HashMap::new(); - for (name, value) in EC_CONSTANTS { - c.insert(name.into(), U256::from_big_endian(&value)); - } - for segment in Segment::all() { - c.insert(segment.var_name().into(), (segment as u32).into()); - } - for txn_field in NormalizedTxnField::all() { - c.insert(txn_field.var_name().into(), (txn_field as u32).into()); - } - c -} - -#[allow(dead_code)] // TODO: Should be used once witness generation is done. pub(crate) fn combined_kernel() -> Kernel { let files = vec![ include_str!("asm/curve/bn254/curve_add.asm"), diff --git a/evm/src/cpu/kernel/constants.rs b/evm/src/cpu/kernel/constants.rs new file mode 100644 index 00000000..5bc5908e --- /dev/null +++ b/evm/src/cpu/kernel/constants.rs @@ -0,0 +1,87 @@ +use std::collections::HashMap; + +use ethereum_types::U256; +use hex_literal::hex; + +use crate::cpu::kernel::context_metadata::ContextMetadata; +use crate::cpu::kernel::global_metadata::GlobalMetadata; +use crate::cpu::kernel::txn_fields::NormalizedTxnField; +use crate::memory::segments::Segment; + +/// Constants that are accessible to our kernel assembly code. +pub fn evm_constants() -> HashMap { + let mut c = HashMap::new(); + for (name, value) in EC_CONSTANTS { + c.insert(name.into(), U256::from_big_endian(&value)); + } + for (name, value) in GAS_CONSTANTS { + c.insert(name.into(), U256::from(value)); + } + for segment in Segment::all() { + c.insert(segment.var_name().into(), (segment as u32).into()); + } + for txn_field in NormalizedTxnField::all() { + c.insert(txn_field.var_name().into(), (txn_field as u32).into()); + } + for txn_field in GlobalMetadata::all() { + c.insert(txn_field.var_name().into(), (txn_field as u32).into()); + } + for txn_field in ContextMetadata::all() { + c.insert(txn_field.var_name().into(), (txn_field as u32).into()); + } + c +} + +const EC_CONSTANTS: [(&str, [u8; 32]); 3] = [ + ( + "BN_BASE", + hex!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"), + ), + ( + "SECP_BASE", + hex!("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), + ), + ( + "SECP_SCALAR", + hex!("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + ), +]; + +const GAS_CONSTANTS: [(&str, u16); 36] = [ + ("GAS_ZERO", 0), + ("GAS_JUMPDEST", 1), + ("GAS_BASE", 2), + ("GAS_VERYLOW", 3), + ("GAS_LOW", 5), + ("GAS_MID", 8), + ("GAS_HIGH", 10), + ("GAS_WARMACCESS", 100), + ("GAS_ACCESSLISTADDRESS", 2_400), + ("GAS_ACCESSLISTSTORAGE", 1_900), + ("GAS_COLDACCOUNTACCESS", 2_600), + ("GAS_COLDSLOAD", 2_100), + ("GAS_SSET", 20_000), + ("GAS_SRESET", 2_900), + ("REFUND_SCLEAR", 15_000), + ("REFUND_SELFDESTRUCT", 24_000), + ("GAS_SELFDESTRUCT", 5_000), + ("GAS_CREATE", 32_000), + ("GAS_CODEDEPOSIT", 200), + ("GAS_CALLVALUE", 9_000), + ("GAS_CALLSTIPEND", 2_300), + ("GAS_NEWACCOUNT", 25_000), + ("GAS_EXP", 10), + ("GAS_EXPBYTE", 50), + ("GAS_MEMORY", 3), + ("GAS_TXCREATE", 32_000), + ("GAS_TXDATAZERO", 4), + ("GAS_TXDATANONZERO", 16), + ("GAS_TRANSACTION", 21_000), + ("GAS_LOG", 375), + ("GAS_LOGDATA", 8), + ("GAS_LOGTOPIC", 375), + ("GAS_KECCAK256", 30), + ("GAS_KECCAK256WORD", 6), + ("GAS_COPY", 3), + ("GAS_BLOCKHASH", 20), +]; diff --git a/evm/src/cpu/kernel/context_metadata.rs b/evm/src/cpu/kernel/context_metadata.rs new file mode 100644 index 00000000..cf0bfc23 --- /dev/null +++ b/evm/src/cpu/kernel/context_metadata.rs @@ -0,0 +1,33 @@ +/// These metadata fields contain VM state specific to a particular context. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] +pub(crate) enum ContextMetadata { + /// The ID of the context which created this one. + ParentContext = 0, + /// The program counter to return to when we return to the parent context. + ParentProgramCounter = 1, + CalldataSize = 2, + ReturndataSize = 3, +} + +impl ContextMetadata { + pub(crate) const COUNT: usize = 4; + + pub(crate) fn all() -> [Self; Self::COUNT] { + [ + Self::ParentContext, + Self::ParentProgramCounter, + Self::CalldataSize, + Self::ReturndataSize, + ] + } + + /// The variable name that gets passed into kernel assembly code. + pub(crate) fn var_name(&self) -> &'static str { + match self { + ContextMetadata::ParentContext => "CTX_METADATA_PARENT_CONTEXT", + ContextMetadata::ParentProgramCounter => "CTX_METADATA_PARENT_PC", + ContextMetadata::CalldataSize => "CTX_METADATA_CALLDATA_SIZE", + ContextMetadata::ReturndataSize => "CTX_METADATA_RETURNDATA_SIZE", + } + } +} diff --git a/evm/src/cpu/kernel/global_metadata.rs b/evm/src/cpu/kernel/global_metadata.rs new file mode 100644 index 00000000..50b54ec3 --- /dev/null +++ b/evm/src/cpu/kernel/global_metadata.rs @@ -0,0 +1,23 @@ +/// These metadata fields contain global VM state, stored in the `Segment::Metadata` segment of the +/// kernel's context (which is zero). +#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] +pub(crate) enum GlobalMetadata { + /// The larger context ID that has been used so far in this execution. Tracking this allows us + /// give each new context a unique ID, so that its memory will be zero-initialized. + LargestContext = 0, +} + +impl GlobalMetadata { + pub(crate) const COUNT: usize = 1; + + pub(crate) fn all() -> [Self; Self::COUNT] { + [Self::LargestContext] + } + + /// The variable name that gets passed into kernel assembly code. + pub(crate) fn var_name(&self) -> &'static str { + match self { + GlobalMetadata::LargestContext => "GLOBAL_METADATA_LARGEST_CONTEXT", + } + } +} diff --git a/evm/src/cpu/kernel/mod.rs b/evm/src/cpu/kernel/mod.rs index f0247f93..641ee529 100644 --- a/evm/src/cpu/kernel/mod.rs +++ b/evm/src/cpu/kernel/mod.rs @@ -1,6 +1,9 @@ pub mod aggregator; pub mod assembler; mod ast; +mod constants; +mod context_metadata; +mod global_metadata; pub(crate) mod keccak_util; mod opcodes; mod parser; @@ -17,7 +20,7 @@ mod tests; use assembler::assemble; use parser::parse; -use crate::cpu::kernel::aggregator::evm_constants; +use crate::cpu::kernel::constants::evm_constants; /// Assemble files, outputting bytes. /// This is for debugging the kernel only. diff --git a/evm/src/memory/segments.rs b/evm/src/memory/segments.rs index 15545ea0..712db644 100644 --- a/evm/src/memory/segments.rs +++ b/evm/src/memory/segments.rs @@ -13,20 +13,21 @@ pub(crate) enum Segment { Returndata = 4, /// A segment which contains a few fixed-size metadata fields, such as the caller's context, or the /// size of `CALLDATA` and `RETURNDATA`. - Metadata = 5, + GlobalMetadata = 5, + ContextMetadata = 6, /// General purpose kernel memory, used by various kernel functions. /// In general, calling a helper function can result in this memory being clobbered. - KernelGeneral = 6, + KernelGeneral = 7, /// Contains normalized transaction fields; see `TxnField`. - TxnFields = 7, + TxnFields = 8, /// Contains the data field of a transaction. - TxnData = 8, + TxnData = 9, /// Raw RLP data. - RlpRaw = 9, + RlpRaw = 10, } impl Segment { - pub(crate) const COUNT: usize = 10; + pub(crate) const COUNT: usize = 11; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -35,7 +36,8 @@ impl Segment { Self::MainMemory, Self::Calldata, Self::Returndata, - Self::Metadata, + Self::GlobalMetadata, + Self::ContextMetadata, Self::KernelGeneral, Self::TxnFields, Self::TxnData, @@ -51,7 +53,8 @@ impl Segment { Segment::MainMemory => "SEGMENT_MAIN_MEMORY", Segment::Calldata => "SEGMENT_CALLDATA", Segment::Returndata => "SEGMENT_RETURNDATA", - Segment::Metadata => "SEGMENT_METADATA", + Segment::GlobalMetadata => "SEGMENT_GLOBAL_METADATA", + Segment::ContextMetadata => "SEGMENT_CONTEXT_METADATA", Segment::KernelGeneral => "SEGMENT_KERNEL_GENERAL", Segment::TxnFields => "SEGMENT_NORMALIZED_TXN", Segment::TxnData => "SEGMENT_TXN_DATA", @@ -67,7 +70,8 @@ impl Segment { Segment::MainMemory => 8, Segment::Calldata => 8, Segment::Returndata => 8, - Segment::Metadata => 256, + Segment::GlobalMetadata => 256, + Segment::ContextMetadata => 256, Segment::KernelGeneral => 256, Segment::TxnFields => 256, Segment::TxnData => 256, From be0a5269ab2f5ea4e8d8f659902491916aae127c Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 21:21:35 -0700 Subject: [PATCH 07/13] UserspaceProgramCounter --- evm/src/cpu/kernel/context_metadata.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/context_metadata.rs b/evm/src/cpu/kernel/context_metadata.rs index cf0bfc23..ff075814 100644 --- a/evm/src/cpu/kernel/context_metadata.rs +++ b/evm/src/cpu/kernel/context_metadata.rs @@ -5,17 +5,20 @@ pub(crate) enum ContextMetadata { ParentContext = 0, /// The program counter to return to when we return to the parent context. ParentProgramCounter = 1, - CalldataSize = 2, - ReturndataSize = 3, + /// If we're in a system call, this holds the userspace program counter to return to. + UserspaceProgramCounter = 2, + CalldataSize = 3, + ReturndataSize = 4, } impl ContextMetadata { - pub(crate) const COUNT: usize = 4; + pub(crate) const COUNT: usize = 5; pub(crate) fn all() -> [Self; Self::COUNT] { [ Self::ParentContext, Self::ParentProgramCounter, + Self::UserspaceProgramCounter, Self::CalldataSize, Self::ReturndataSize, ] @@ -26,6 +29,7 @@ impl ContextMetadata { match self { ContextMetadata::ParentContext => "CTX_METADATA_PARENT_CONTEXT", ContextMetadata::ParentProgramCounter => "CTX_METADATA_PARENT_PC", + ContextMetadata::UserspaceProgramCounter => "CTX_METADATA_USERSPACE_PC", ContextMetadata::CalldataSize => "CTX_METADATA_CALLDATA_SIZE", ContextMetadata::ReturndataSize => "CTX_METADATA_RETURNDATA_SIZE", } From 215be25cf8e1364092ea35d285c9bea1188a21ed Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 2 Aug 2022 09:08:24 -0700 Subject: [PATCH 08/13] Feedback --- evm/src/cpu/kernel/interpreter.rs | 4 ++++ .../cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 3b753f0a..6a5b794f 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -137,6 +137,10 @@ impl<'a> Interpreter<'a> { self.memory.context_memory[0].segments[Segment::TxnFields as usize].content[field as usize] } + pub(crate) fn get_txn_data(&self) -> &[U256] { + &self.memory.context_memory[0].segments[Segment::TxnData as usize].content + } + pub(crate) fn set_rlp_memory(&mut self, rlp: Vec) { self.memory.context_memory[0].segments[Segment::RlpRaw as usize].content = rlp.into_iter().map(U256::from).collect(); diff --git a/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs index 8b725479..c01474ce 100644 --- a/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs +++ b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs @@ -46,6 +46,7 @@ fn process_type_0_txn() -> Result<()> { assert_eq!(interpreter.get_txn_field(To), 0.into()); assert_eq!(interpreter.get_txn_field(Value), 100.into()); assert_eq!(interpreter.get_txn_field(DataLen), 2.into()); + assert_eq!(interpreter.get_txn_data(), &[0x42.into(), 0x42.into()]); assert_eq!(interpreter.get_txn_field(YParity), 1.into()); assert_eq!( interpreter.get_txn_field(R), From f95134555621288cb4e003b4adcd6cd1bc31b7ae Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 2 Aug 2022 09:09:48 -0700 Subject: [PATCH 09/13] Update evm/src/cpu/kernel/global_metadata.rs Co-authored-by: Jacqueline Nabaglo --- evm/src/cpu/kernel/global_metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/global_metadata.rs b/evm/src/cpu/kernel/global_metadata.rs index 50b54ec3..23c5a4c7 100644 --- a/evm/src/cpu/kernel/global_metadata.rs +++ b/evm/src/cpu/kernel/global_metadata.rs @@ -2,7 +2,7 @@ /// kernel's context (which is zero). #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] pub(crate) enum GlobalMetadata { - /// The larger context ID that has been used so far in this execution. Tracking this allows us + /// The largest context ID that has been used so far in this execution. Tracking this allows us /// give each new context a unique ID, so that its memory will be zero-initialized. LargestContext = 0, } From 8bb45203f9dfe90047f866cd5729e02edb19e35e Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 1 Aug 2022 17:40:16 -0700 Subject: [PATCH 10/13] More succinct deadbeef --- evm/src/cpu/kernel/tests/exp.rs | 8 +++----- evm/src/cpu/kernel/tests/rlp.rs | 14 ++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/evm/src/cpu/kernel/tests/exp.rs b/evm/src/cpu/kernel/tests/exp.rs index 388a1ac3..25bc5ad3 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow::Result; use ethereum_types::U256; use rand::{thread_rng, Rng}; @@ -17,7 +15,7 @@ fn test_exp() -> Result<()> { let b = U256([0; 4].map(|_| rng.gen())); // Random input - let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a]; + let initial_stack = vec![0xDEADBEEFu32.into(), b, a]; let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)? .stack() .to_vec(); @@ -29,7 +27,7 @@ fn test_exp() -> Result<()> { assert_eq!(stack_with_kernel, stack_with_opcode); // 0 base - let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()]; + let initial_stack = vec![0xDEADBEEFu32.into(), b, U256::zero()]; let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)? .stack() .to_vec(); @@ -41,7 +39,7 @@ fn test_exp() -> Result<()> { assert_eq!(stack_with_kernel, stack_with_opcode); // 0 exponent - let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a]; + let initial_stack = vec![0xDEADBEEFu32.into(), U256::zero(), a]; let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)? .stack() .to_vec(); diff --git a/evm/src/cpu/kernel/tests/rlp.rs b/evm/src/cpu/kernel/tests/rlp.rs index 55dfc7e8..cc311b4f 100644 --- a/evm/src/cpu/kernel/tests/rlp.rs +++ b/evm/src/cpu/kernel/tests/rlp.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow::Result; use ethereum_types::U256; @@ -10,7 +8,7 @@ use crate::cpu::kernel::interpreter::Interpreter; fn test_decode_rlp_string_len_short() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by "0x70" which is its own encoding. @@ -27,7 +25,7 @@ fn test_decode_rlp_string_len_short() -> Result<()> { fn test_decode_rlp_string_len_medium() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by the RLP encoding of "1 2 3 4 5". @@ -44,7 +42,7 @@ fn test_decode_rlp_string_len_medium() -> Result<()> { fn test_decode_rlp_string_len_long() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 2.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // The RLP encoding of the string "1 2 3 ... 56". @@ -65,7 +63,7 @@ fn test_decode_rlp_string_len_long() -> Result<()> { fn test_decode_rlp_list_len_short() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, 2, [3, 4]]. @@ -82,7 +80,7 @@ fn test_decode_rlp_list_len_short() -> Result<()> { fn test_decode_rlp_list_len_long() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, ..., 56]. @@ -103,7 +101,7 @@ fn test_decode_rlp_list_len_long() -> Result<()> { fn test_decode_rlp_scalar() -> Result<()> { let decode_rlp_scalar = KERNEL.global_labels["decode_rlp_scalar"]; - let initial_stack = vec![U256::from_str("0xdeadbeef")?, 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); // The RLP encoding of "12 34 56". From 3b54ec398618ed891e5474afcfc52288b35dec0d Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 2 Aug 2022 09:08:24 -0700 Subject: [PATCH 11/13] Feedback --- evm/src/cpu/kernel/interpreter.rs | 4 ++++ .../cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 3b753f0a..6a5b794f 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -137,6 +137,10 @@ impl<'a> Interpreter<'a> { self.memory.context_memory[0].segments[Segment::TxnFields as usize].content[field as usize] } + pub(crate) fn get_txn_data(&self) -> &[U256] { + &self.memory.context_memory[0].segments[Segment::TxnData as usize].content + } + pub(crate) fn set_rlp_memory(&mut self, rlp: Vec) { self.memory.context_memory[0].segments[Segment::RlpRaw as usize].content = rlp.into_iter().map(U256::from).collect(); diff --git a/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs index 8b725479..c01474ce 100644 --- a/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs +++ b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs @@ -46,6 +46,7 @@ fn process_type_0_txn() -> Result<()> { assert_eq!(interpreter.get_txn_field(To), 0.into()); assert_eq!(interpreter.get_txn_field(Value), 100.into()); assert_eq!(interpreter.get_txn_field(DataLen), 2.into()); + assert_eq!(interpreter.get_txn_data(), &[0x42.into(), 0x42.into()]); assert_eq!(interpreter.get_txn_field(YParity), 1.into()); assert_eq!( interpreter.get_txn_field(R), From c167da8cbea201f6b219db73119126e87b6e2f1c Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 2 Aug 2022 09:10:21 -0700 Subject: [PATCH 12/13] Revert "UserspaceProgramCounter" This reverts commit 05beaab661a8aaa2f84b6f121b5ac2f29f2ed836. --- evm/src/cpu/kernel/context_metadata.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/evm/src/cpu/kernel/context_metadata.rs b/evm/src/cpu/kernel/context_metadata.rs index ff075814..cf0bfc23 100644 --- a/evm/src/cpu/kernel/context_metadata.rs +++ b/evm/src/cpu/kernel/context_metadata.rs @@ -5,20 +5,17 @@ pub(crate) enum ContextMetadata { ParentContext = 0, /// The program counter to return to when we return to the parent context. ParentProgramCounter = 1, - /// If we're in a system call, this holds the userspace program counter to return to. - UserspaceProgramCounter = 2, - CalldataSize = 3, - ReturndataSize = 4, + CalldataSize = 2, + ReturndataSize = 3, } impl ContextMetadata { - pub(crate) const COUNT: usize = 5; + pub(crate) const COUNT: usize = 4; pub(crate) fn all() -> [Self; Self::COUNT] { [ Self::ParentContext, Self::ParentProgramCounter, - Self::UserspaceProgramCounter, Self::CalldataSize, Self::ReturndataSize, ] @@ -29,7 +26,6 @@ impl ContextMetadata { match self { ContextMetadata::ParentContext => "CTX_METADATA_PARENT_CONTEXT", ContextMetadata::ParentProgramCounter => "CTX_METADATA_PARENT_PC", - ContextMetadata::UserspaceProgramCounter => "CTX_METADATA_USERSPACE_PC", ContextMetadata::CalldataSize => "CTX_METADATA_CALLDATA_SIZE", ContextMetadata::ReturndataSize => "CTX_METADATA_RETURNDATA_SIZE", } From 002b568a12654d6d1b7804f1308bc0825dfce91d Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 2 Aug 2022 10:17:34 -0700 Subject: [PATCH 13/13] fix --- evm/src/cpu/kernel/tests/rlp.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/rlp.rs b/evm/src/cpu/kernel/tests/rlp.rs index cc311b4f..a1ca3609 100644 --- a/evm/src/cpu/kernel/tests/rlp.rs +++ b/evm/src/cpu/kernel/tests/rlp.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter;