diff --git a/src/evm/instructions.rs b/src/evm/instructions.rs index 7a7ef6e56..976c3c603 100644 --- a/src/evm/instructions.rs +++ b/src/evm/instructions.rs @@ -516,6 +516,8 @@ pub const LOG2: Instruction = 0xa2; pub const LOG3: Instruction = 0xa3; /// Makes a log entry; 4 topics. pub const LOG4: Instruction = 0xa4; +/// Maximal number of topics for log instructions +pub const MAX_NO_OF_TOPICS : usize = 4; /// create a new account with associated code pub const CREATE: Instruction = 0xf0; diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index c583b054d..687bdeec5 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -5,6 +5,7 @@ use evm; use super::instructions as instructions; use super::instructions::Instruction; use std::num::wrapping::OverflowingOps; +use std::marker::Copy; #[cfg(feature = "evm_debug")] macro_rules! evm_debug { @@ -39,30 +40,44 @@ trait Stack { fn has(&self, no_of_elems: usize) -> bool; /// Get element from top and remove it from Stack. Panics if stack is empty. fn pop_back(&mut self) -> T; - /// Get elements from top and remove them from Stack. Panics if stack is empty. - fn pop_n(&mut self, no_of_elems: usize) -> Vec; + /// Get (up to `instructions::MAX_NO_OF_TOPICS`) elements from top and remove them from Stack. Panics if stack is empty. + fn pop_n(&mut self, no_of_elems: usize) -> &[T]; /// Add element on top of the Stack fn push(&mut self, elem: T); /// Get number of elements on Stack fn size(&self) -> usize; } -impl Stack for Vec { +struct VecStack { + stack: Vec, + logs: [S; instructions::MAX_NO_OF_TOPICS] +} + +impl VecStack { + fn with_capacity(capacity: usize, zero: S) -> Self { + VecStack { + stack: Vec::with_capacity(capacity), + logs: [zero; instructions::MAX_NO_OF_TOPICS] + } + } +} + +impl Stack for VecStack { fn peek(&self, no_from_top: usize) -> &S { - return &self[self.len() - no_from_top - 1]; + return &self.stack[self.stack.len() - no_from_top - 1]; } fn swap_with_top(&mut self, no_from_top: usize) { - let len = self.len(); - self.swap(len - no_from_top - 1, len - 1); + let len = self.stack.len(); + self.stack.swap(len - no_from_top - 1, len - 1); } fn has(&self, no_of_elems: usize) -> bool { - self.len() >= no_of_elems + self.stack.len() >= no_of_elems } fn pop_back(&mut self) -> S { - let val = self.pop(); + let val = self.stack.pop(); match val { Some(x) => { evm_debug!({ @@ -74,24 +89,24 @@ impl Stack for Vec { } } - fn pop_n(&mut self, no_of_elems: usize) -> Vec { - let mut vec = Vec::new(); + fn pop_n(&mut self, no_of_elems: usize) -> &[S] { + assert!(no_of_elems <= instructions::MAX_NO_OF_TOPICS); - for _i in 1..no_of_elems+1 { - vec.push(self.pop_back()); + for i in 0..no_of_elems { + self.logs[i] = self.pop_back(); } - vec + &self.logs[0..no_of_elems] } fn push(&mut self, elem: S) { evm_debug!({ format!(" PUSH: {}", elem) }); - self.push(elem); + self.stack.push(elem); } fn size(&self) -> usize { - self.len() + self.stack.len() } } @@ -246,7 +261,7 @@ impl evm::Evm for Interpreter { let valid_jump_destinations = self.find_jump_destinations(&code); let mut current_gas = params.gas.clone(); - let mut stack = Vec::with_capacity(ext.schedule().stack_limit); + let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); let mut mem = vec![]; let mut reader = CodeReader { position: 0,