From 925483ed1eb0f6724ece0dde50c5b576377607e4 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 17 Jul 2022 15:07:29 -0700 Subject: [PATCH 1/4] Add custom opcodes - `GET_STATE_ROOT` and `SET_STATE_ROOT` deal with the root of the state trie, and will be called from storage routines. Similarly `GET_RECEIPT_ROOT` and `SET_RECEIPT_ROOT` deal with the root of the receipt trie. - `PANIC` enables an unsatisfiable constraint, so no proof can be generated. - `GET_CONTEXT` and `SET_CONTEXT`, used when calling and returning - `CONSUME_GAS` charges the sender gas; useful for cases where gas calculations are nontrivial and best implemented in assembly. - `EXIT_KERNEL` simply clears the CPU flag indicating that we're in kernel mode; it would be used just before a jump to return to the (userspace) caller. - `MLOAD_GENERAL` and `MSTORE_GENERAL` are for reading and writing memory, but they're not limited to the main memory segment of the current context; they can access any context and any segment. I added a couple macros to show how the they would typically be used. There may be more later, but these are the ones I think we need for now. I tried to fill in smaller invalid sections of the decoder's tree, as Jacqui suggested, while keeping related opcodes together. We can fine tune it when the opcode list is more stable. These are all intended to be priviledged, i.e. they will be treated as invalid if used from userspace, for compatibility as well as (in some cases) security reasons. --- evm/src/cpu/columns.rs | 17 +++++++++----- evm/src/cpu/decode.rs | 37 ++++++++++++++++++------------- evm/src/cpu/kernel/asm/memory.asm | 27 ++++++++++++++++++++++ evm/src/cpu/kernel/interpreter.rs | 11 +++++++++ evm/src/cpu/kernel/opcodes.rs | 11 +++++++++ 5 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/memory.asm diff --git a/evm/src/cpu/columns.rs b/evm/src/cpu/columns.rs index f3a400c6..c79f9e9d 100644 --- a/evm/src/cpu/columns.rs +++ b/evm/src/cpu/columns.rs @@ -90,6 +90,10 @@ pub struct CpuColumnsView { pub is_msize: T, pub is_gas: T, pub is_jumpdest: T, + pub is_get_state_root: T, + pub is_set_state_root: T, + pub is_get_receipt_root: T, + pub is_set_receipt_root: T, pub is_push: T, pub is_dup: T, pub is_swap: T, @@ -98,13 +102,20 @@ pub struct CpuColumnsView { pub is_log2: T, pub is_log3: T, pub is_log4: T, + pub is_panic: T, pub is_create: T, pub is_call: T, pub is_callcode: T, pub is_return: T, pub is_delegatecall: T, pub is_create2: T, + pub is_get_context: T, + pub is_set_context: T, + pub is_consume_gas: T, + pub is_exit_kernel: T, pub is_staticcall: T, + pub is_mload_general: T, + pub is_mstore_general: T, pub is_revert: T, pub is_selfdestruct: T, @@ -124,12 +135,6 @@ pub struct CpuColumnsView { pub is_invalid_12: T, pub is_invalid_13: T, pub is_invalid_14: T, - pub is_invalid_15: T, - pub is_invalid_16: T, - pub is_invalid_17: T, - pub is_invalid_18: T, - pub is_invalid_19: T, - pub is_invalid_20: T, /// If CPU cycle: the opcode, broken up into bits in **big-endian** order. pub opcode_bits: [T; 8], diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index 0b091558..22a25dc6 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -15,7 +15,7 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP}; // - its start index is a multiple of its length (it is aligned) // These properties permit us to check if an opcode belongs to a block of length 2^n by checking its // top 8-n bits. -const OPCODES: [(u64, usize, usize); 102] = [ +const OPCODES: [(u64, usize, usize); 107] = [ // (start index of block, number of top bits to check (log2), flag column) (0x00, 0, COL_MAP.is_stop), (0x01, 0, COL_MAP.is_add), @@ -90,34 +90,39 @@ const OPCODES: [(u64, usize, usize); 102] = [ (0x59, 0, COL_MAP.is_msize), (0x5a, 0, COL_MAP.is_gas), (0x5b, 0, COL_MAP.is_jumpdest), - (0x5c, 2, COL_MAP.is_invalid_9), // 0x5c-0x5f - (0x60, 5, COL_MAP.is_push), // 0x60-0x7f - (0x80, 4, COL_MAP.is_dup), // 0x80-0x8f - (0x90, 4, COL_MAP.is_swap), // 0x90-0x9f + (0x5c, 0, COL_MAP.is_get_state_root), + (0x5d, 0, COL_MAP.is_set_state_root), + (0x5e, 0, COL_MAP.is_get_receipt_root), + (0x5f, 0, COL_MAP.is_set_receipt_root), + (0x60, 5, COL_MAP.is_push), // 0x60-0x7f + (0x80, 4, COL_MAP.is_dup), // 0x80-0x8f + (0x90, 4, COL_MAP.is_swap), // 0x90-0x9f (0xa0, 0, COL_MAP.is_log0), (0xa1, 0, COL_MAP.is_log1), (0xa2, 0, COL_MAP.is_log2), (0xa3, 0, COL_MAP.is_log3), (0xa4, 0, COL_MAP.is_log4), - (0xa5, 0, COL_MAP.is_invalid_10), - (0xa6, 1, COL_MAP.is_invalid_11), // 0xa6-0xa7 - (0xa8, 3, COL_MAP.is_invalid_12), // 0xa8-0xaf - (0xb0, 4, COL_MAP.is_invalid_13), // 0xb0-0xbf - (0xc0, 5, COL_MAP.is_invalid_14), // 0xc0-0xdf - (0xe0, 4, COL_MAP.is_invalid_15), // 0xe0-0xef + (0xa5, 0, COL_MAP.is_panic), + (0xa6, 1, COL_MAP.is_invalid_9), // 0xa6-0xa7 + (0xa8, 3, COL_MAP.is_invalid_10), // 0xa8-0xaf + (0xb0, 4, COL_MAP.is_invalid_11), // 0xb0-0xbf + (0xc0, 5, COL_MAP.is_invalid_12), // 0xc0-0xdf + (0xe0, 4, COL_MAP.is_invalid_13), // 0xe0-0xef (0xf0, 0, COL_MAP.is_create), (0xf1, 0, COL_MAP.is_call), (0xf2, 0, COL_MAP.is_callcode), (0xf3, 0, COL_MAP.is_return), (0xf4, 0, COL_MAP.is_delegatecall), (0xf5, 0, COL_MAP.is_create2), - (0xf6, 1, COL_MAP.is_invalid_16), // 0xf6-0xf7 - (0xf8, 1, COL_MAP.is_invalid_17), // 0xf8-0xf9 + (0xf6, 0, COL_MAP.is_get_context), + (0xf7, 0, COL_MAP.is_set_context), + (0xf8, 0, COL_MAP.is_consume_gas), + (0xf9, 0, COL_MAP.is_exit_kernel), (0xfa, 0, COL_MAP.is_staticcall), - (0xfb, 0, COL_MAP.is_invalid_18), - (0xfc, 0, COL_MAP.is_invalid_19), + (0xfb, 0, COL_MAP.is_mload_general), + (0xfc, 0, COL_MAP.is_mstore_general), (0xfd, 0, COL_MAP.is_revert), - (0xfe, 0, COL_MAP.is_invalid_20), + (0xfe, 0, COL_MAP.is_invalid_14), (0xff, 0, COL_MAP.is_selfdestruct), ]; diff --git a/evm/src/cpu/kernel/asm/memory.asm b/evm/src/cpu/kernel/asm/memory.asm new file mode 100644 index 00000000..c325ed9d --- /dev/null +++ b/evm/src/cpu/kernel/asm/memory.asm @@ -0,0 +1,27 @@ +// Load a byte from the given segment of the current context's memory space. +// Note that main memory values are one byte each, but in general memory values +// can be 256 bits. This macro deals with a single address (unlike MSTORE), so +// if it is used with main memory, it will load a single byte. +%macro mload_current(segment) + // stack: offset + PUSH $segment + // stack: segment, offset + CURRENT_CONTEXT + // stack: context, segment, offset + MLOAD_GENERAL + // stack: value +%endmacro + +// Store a byte to the given segment of the current context's memory space. +// Note that main memory values are one byte each, but in general memory values +// can be 256 bits. This macro deals with a single address (unlike MSTORE), so +// if it is used with main memory, it will store a single byte. +%macro mstore_current(segment) + // stack: offset, value + PUSH $segment + // stack: segment, offset, value + CURRENT_CONTEXT + // stack: context, segment, offset, value + MSTORE_GENERAL + // stack: (empty) +%endmacro diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 09e493b9..d18ef945 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -115,6 +115,10 @@ impl<'a> Interpreter<'a> { 0x59 => todo!(), // "MSIZE", 0x5a => todo!(), // "GAS", 0x5b => (), // "JUMPDEST", + 0x5c => todo!(), // "GET_STATE_ROOT", + 0x5d => todo!(), // "SET_STATE_ROOT", + 0x5e => todo!(), // "GET_RECEIPT_ROOT", + 0x5f => todo!(), // "SET_RECEIPT_ROOT", x if (0x60..0x80).contains(&x) => self.run_push(x - 0x5f), // "PUSH" x if (0x80..0x90).contains(&x) => self.run_dup(x - 0x7f), // "DUP" x if (0x90..0xa0).contains(&x) => self.run_swap(x - 0x8f), // "SWAP" @@ -123,13 +127,20 @@ impl<'a> Interpreter<'a> { 0xa2 => todo!(), // "LOG2", 0xa3 => todo!(), // "LOG3", 0xa4 => todo!(), // "LOG4", + 0xa5 => panic!("Executed PANIC"), // "PANIC", 0xf0 => todo!(), // "CREATE", 0xf1 => todo!(), // "CALL", 0xf2 => todo!(), // "CALLCODE", 0xf3 => todo!(), // "RETURN", 0xf4 => todo!(), // "DELEGATECALL", 0xf5 => todo!(), // "CREATE2", + 0xf6 => todo!(), // "GET_CONTEXT", + 0xf7 => todo!(), // "SET_CONTEXT", + 0xf8 => todo!(), // "CONSUME_GAS", + 0xf9 => todo!(), // "EXIT_KERNEL", 0xfa => todo!(), // "STATICCALL", + 0xfb => todo!(), // "MLOAD_GENERAL", + 0xfc => todo!(), // "MSTORE_GENERAL", 0xfd => todo!(), // "REVERT", 0xfe => todo!(), // "INVALID", 0xff => todo!(), // "SELFDESTRUCT", diff --git a/evm/src/cpu/kernel/opcodes.rs b/evm/src/cpu/kernel/opcodes.rs index b8633178..b9ef7d5e 100644 --- a/evm/src/cpu/kernel/opcodes.rs +++ b/evm/src/cpu/kernel/opcodes.rs @@ -71,6 +71,10 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 { "MSIZE" => 0x59, "GAS" => 0x5a, "JUMPDEST" => 0x5b, + "GET_STATE_ROOT" => 0x5c, + "SET_STATE_ROOT" => 0x5d, + "GET_RECEIPT_ROOT" => 0x5e, + "SET_RECEIPT_ROOT" => 0x5f, "DUP1" => 0x80, "DUP2" => 0x81, "DUP3" => 0x82, @@ -108,13 +112,20 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 { "LOG2" => 0xa2, "LOG3" => 0xa3, "LOG4" => 0xa4, + "PANIC" => 0xa5, "CREATE" => 0xf0, "CALL" => 0xf1, "CALLCODE" => 0xf2, "RETURN" => 0xf3, "DELEGATECALL" => 0xf4, "CREATE2" => 0xf5, + "GET_CONTEXT" => 0xf6, + "SET_CONTEXT" => 0xf7, + "CONSUME_GAS" => 0xf8, + "EXIT_KERNEL" => 0xf9, "STATICCALL" => 0xfa, + "MLOAD_GENERAL" => 0xfb, + "MSTORE_GENERAL" => 0xfc, "REVERT" => 0xfd, "INVALID" => 0xfe, "SELFDESTRUCT" => 0xff, From 0b7e3eca67e13dabe45351edb240a560ab8bd100 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 08:58:11 -0700 Subject: [PATCH 2/4] PANIC returns error --- evm/src/cpu/kernel/interpreter.rs | 28 +++++++----- evm/src/cpu/kernel/tests/curve_ops.rs | 62 +++++++++++++-------------- evm/src/cpu/kernel/tests/ecrecover.rs | 4 +- evm/src/cpu/kernel/tests/exp.rs | 12 +++--- 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 33bc4327..a9507fde 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -1,3 +1,4 @@ +use anyhow::bail; use ethereum_types::{U256, U512}; /// Halt interpreter execution whenever a jump to this offset is done. @@ -51,7 +52,11 @@ pub(crate) struct Interpreter<'a> { running: bool, } -pub(crate) fn run(code: &[u8], initial_offset: usize, initial_stack: Vec) -> Interpreter { +pub(crate) fn run( + code: &[u8], + initial_offset: usize, + initial_stack: Vec, +) -> anyhow::Result { let mut interpreter = Interpreter { code, jumpdests: find_jumpdests(code), @@ -65,7 +70,7 @@ pub(crate) fn run(code: &[u8], initial_offset: usize, initial_stack: Vec) interpreter.run_opcode(); } - interpreter + Ok(interpreter) } impl<'a> Interpreter<'a> { @@ -89,7 +94,7 @@ impl<'a> Interpreter<'a> { self.stack.pop().expect("Pop on empty stack.") } - fn run_opcode(&mut self) { + fn run_opcode(&mut self) -> anyhow::Result<()> { let opcode = self.code.get(self.offset).copied().unwrap_or_default(); self.incr(1); match opcode { @@ -168,7 +173,7 @@ impl<'a> Interpreter<'a> { 0xa2 => todo!(), // "LOG2", 0xa3 => todo!(), // "LOG3", 0xa4 => todo!(), // "LOG4", - 0xa5 => panic!("Executed PANIC"), // "PANIC", + 0xa5 => bail!("Executed PANIC"), // "PANIC", 0xf0 => todo!(), // "CREATE", 0xf1 => todo!(), // "CALL", 0xf2 => todo!(), // "CALLCODE", @@ -183,10 +188,11 @@ impl<'a> Interpreter<'a> { 0xfb => todo!(), // "MLOAD_GENERAL", 0xfc => todo!(), // "MSTORE_GENERAL", 0xfd => todo!(), // "REVERT", - 0xfe => todo!(), // "INVALID", + 0xfe => bail!("Executed INVALID"), // "INVALID", 0xff => todo!(), // "SELFDESTRUCT", - _ => panic!("Unrecognized opcode {}.", opcode), + _ => bail!("Unrecognized opcode {}.", opcode), }; + Ok(()) } fn run_stop(&mut self) { @@ -381,15 +387,16 @@ mod tests { use crate::cpu::kernel::interpreter::{run, Interpreter}; #[test] - fn test_run() { + fn test_run() -> anyhow::Result<()> { let code = vec![ 0x60, 0x1, 0x60, 0x2, 0x1, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56, ]; // PUSH1, 1, PUSH1, 2, ADD, PUSH4 deadbeef, JUMP - assert_eq!(run(&code, 0, vec![]).stack, vec![0x3.into()]); + assert_eq!(run(&code, 0, vec![])?.stack, vec![0x3.into()]); + Ok(()) } #[test] - fn test_run_with_memory() { + fn test_run_with_memory() -> anyhow::Result<()> { // PUSH1 0xff // PUSH1 0 // MSTORE @@ -407,9 +414,10 @@ mod tests { 0x60, 0xff, 0x60, 0x0, 0x52, 0x60, 0, 0x51, 0x60, 0x1, 0x51, 0x60, 0x42, 0x60, 0x27, 0x53, ]; - let run = run(&code, 0, vec![]); + let run = run(&code, 0, vec![])?; let Interpreter { stack, memory, .. } = run; assert_eq!(stack, vec![0xff.into(), 0xff00.into()]); assert_eq!(&memory.memory, &hex!("00000000000000000000000000000000000000000000000000000000000000ff0000000000000042000000000000000000000000000000000000000000000000")); + Ok(()) } } diff --git a/evm/src/cpu/kernel/tests/curve_ops.rs b/evm/src/cpu/kernel/tests/curve_ops.rs index 7d7f042a..6d8c6696 100644 --- a/evm/src/cpu/kernel/tests/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/curve_ops.rs @@ -43,76 +43,76 @@ mod bn { // Standard addition #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard addition #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard doubling #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #2 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_double, initial_stack).stack; + let stack = run(&kernel.code, ec_double, initial_stack)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #3 let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Addition with identity #1 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, point1.1, point1.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #3 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Addition with invalid point(s) #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, invalid.1, invalid.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Addition with invalid point(s) #2 let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Addition with invalid point(s) #3 let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Addition with invalid point(s) #4 let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, invalid.1, invalid.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); // Scalar multiplication #2 let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #3 let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([point0.1, point0.0])?); // Scalar multiplication #4 let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #5 let initial_stack = u256ify(["0xdeadbeef", s, invalid.1, invalid.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls @@ -126,7 +126,7 @@ mod bn { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) @@ -176,55 +176,55 @@ mod secp { // Standard addition #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard addition #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard doubling #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #2 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_double, initial_stack).stack; + let stack = run(&kernel.code, ec_double, initial_stack)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #3 let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Addition with identity #1 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, point1.1, point1.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #3 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); // Scalar multiplication #2 let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #3 let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([point0.1, point0.0])?); // Scalar multiplication #4 let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack).stack; + let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Multiple calls @@ -238,7 +238,7 @@ mod secp { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack).stack; + let stack = run(&kernel.code, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) diff --git a/evm/src/cpu/kernel/tests/ecrecover.rs b/evm/src/cpu/kernel/tests/ecrecover.rs index 5077d042..d6eac6f7 100644 --- a/evm/src/cpu/kernel/tests/ecrecover.rs +++ b/evm/src/cpu/kernel/tests/ecrecover.rs @@ -25,7 +25,7 @@ fn test_valid_ecrecover( ) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify([s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack).stack; + let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; let got = pubkey_to_addr(stack[1], stack[0]); assert_eq!(got, hex::decode(&expected[2..]).unwrap()); @@ -35,7 +35,7 @@ fn test_valid_ecrecover( fn test_invalid_ecrecover(hash: &str, v: &str, r: &str, s: &str, kernel: &Kernel) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack).stack; + let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX]); Ok(()) diff --git a/evm/src/cpu/kernel/tests/exp.rs b/evm/src/cpu/kernel/tests/exp.rs index b12b943e..25c88623 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -18,26 +18,26 @@ fn test_exp() -> Result<()> { // Random input let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack).stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; let initial_stack = vec![b, a]; let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP - let stack_with_opcode = run(&code, 0, initial_stack).stack; + let stack_with_opcode = run(&code, 0, initial_stack)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); // 0 base let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack).stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; let initial_stack = vec![b, U256::zero()]; let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP - let stack_with_opcode = run(&code, 0, initial_stack).stack; + let stack_with_opcode = run(&code, 0, initial_stack)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); // 0 exponent let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack).stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; let initial_stack = vec![U256::zero(), a]; let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP - let stack_with_opcode = run(&code, 0, initial_stack).stack; + let stack_with_opcode = run(&code, 0, initial_stack)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); Ok(()) From b29de2c46a78ad3c19244ee5c5506180aae43826 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 09:29:21 -0700 Subject: [PATCH 3/4] tweak --- evm/src/cpu/kernel/asm/memory.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/memory.asm b/evm/src/cpu/kernel/asm/memory.asm index c325ed9d..e3af9954 100644 --- a/evm/src/cpu/kernel/asm/memory.asm +++ b/evm/src/cpu/kernel/asm/memory.asm @@ -1,6 +1,6 @@ // Load a byte from the given segment of the current context's memory space. // Note that main memory values are one byte each, but in general memory values -// can be 256 bits. This macro deals with a single address (unlike MSTORE), so +// can be 256 bits. This macro deals with a single address (unlike MLOAD), so // if it is used with main memory, it will load a single byte. %macro mload_current(segment) // stack: offset From 799d333a903488d30c775f60eb2238c874ab2bc4 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 10:40:02 -0700 Subject: [PATCH 4/4] fix --- evm/src/cpu/kernel/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index a9507fde..452acd93 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -67,7 +67,7 @@ pub(crate) fn run( }; while interpreter.running { - interpreter.run_opcode(); + interpreter.run_opcode()?; } Ok(interpreter)