diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index 1cc68596b..945de14d7 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -104,7 +104,7 @@ impl EvmTestClient { let mut tracer = trace::NoopTracer; let mut output = vec![]; let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine); - let gas_left = executive.call( + let (gas_left, _) = executive.call( params, &mut substate, util::BytesRef::Flexible(&mut output), diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 523f98d18..46457c35f 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -97,10 +97,45 @@ impl fmt::Display for Error { /// A specialized version of Result over EVM errors. pub type Result = ::std::result::Result; + +/// Return data buffer. Holds memory from a previous call and a slice into that memory. +#[derive(Debug)] +pub struct ReturnData { + mem: Vec, + offset: usize, + size: usize, +} + +impl ::std::ops::Deref for ReturnData { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.mem[self.offset..self.offset + self.size] + } +} + +impl ReturnData { + /// Create empty `ReturnData`. + pub fn empty() -> Self { + ReturnData { + mem: Vec::new(), + offset: 0, + size: 0, + } + } + /// Create `ReturnData` from give buffer and slice. + pub fn new(mem: Vec, offset: usize, size: usize) -> Self { + ReturnData { + mem: mem, + offset: offset, + size: size, + } + } +} + /// Gas Left: either it is a known value, or it needs to be computed by processing /// a return instruction. -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum GasLeft<'a> { +#[derive(Debug)] +pub enum GasLeft { /// Known gas left Known(U256), /// Return or Revert instruction must be processed. @@ -108,7 +143,7 @@ pub enum GasLeft<'a> { /// Amount of gas left. gas_left: U256, /// Return data buffer. - data: &'a [u8], + data: ReturnData, /// Apply or revert state changes on revert. apply_state: bool }, @@ -122,6 +157,8 @@ pub struct FinalizationResult { pub gas_left: U256, /// Apply execution state changes or revert them. pub apply_state: bool, + /// Return data buffer. + pub return_data: ReturnData, } /// Types that can be "finalized" using an EVM. @@ -133,13 +170,14 @@ pub trait Finalize { fn finalize(self, ext: E) -> Result; } -impl<'a> Finalize for Result> { +impl Finalize for Result { fn finalize(self, ext: E) -> Result { match self { - Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true }), - Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, data).map(|gas_left| FinalizationResult { + Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }), + Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, &data).map(|gas_left| FinalizationResult { gas_left: gas_left, apply_state: apply_state, + return_data: data, }), Err(err) => Err(err), } diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index fbdc3cec4..cc294dbd4 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -17,7 +17,7 @@ //! Interface for Evm externalities. use util::*; -use evm::{self, Schedule}; +use evm::{self, Schedule, ReturnData}; use env_info::*; use types::executed::CallType; @@ -34,8 +34,8 @@ pub enum ContractCreateResult { /// Result of externalities call function. pub enum MessageCallResult { /// Returned when message call was successfull. - /// Contains gas left. - Success(U256), + /// Contains gas left and output data. + Success(U256, ReturnData), /// Returned when message call failed. /// VM doesn't have to know the reason. Failed @@ -109,7 +109,7 @@ pub trait Ext { /// Should be called when transaction calls `RETURN` opcode. /// Returns gas_left if cost of returning the data is not too high. - fn ret(self, gas: &U256, data: &[u8]) -> evm::Result where Self: Sized; + fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result; /// Should be called when contract commits suicide. /// Address to which funds should be refunded. diff --git a/ethcore/src/evm/instructions.rs b/ethcore/src/evm/instructions.rs index 2fb6cfd66..f726c9166 100644 --- a/ethcore/src/evm/instructions.rs +++ b/ethcore/src/evm/instructions.rs @@ -178,6 +178,8 @@ lazy_static! { arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 0, 3, 1, false, GasPriceTier::Mid); arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 0, 3, 1, false, GasPriceTier::Mid); arr[SIGNEXTEND as usize] = InstructionInfo::new("SIGNEXTEND", 0, 2, 1, false, GasPriceTier::Low); + arr[RETURNDATASIZE as usize] = InstructionInfo::new("RETURNDATASIZE", 0, 0, 1, false, GasPriceTier::Base); + arr[RETURNDATACOPY as usize] = InstructionInfo::new("RETURNDATACOPY", 0, 3, 0, true, GasPriceTier::VeryLow); arr[SHA3 as usize] = InstructionInfo::new("SHA3", 0, 2, 1, false, GasPriceTier::Special); arr[ADDRESS as usize] = InstructionInfo::new("ADDRESS", 0, 0, 1, false, GasPriceTier::Base); arr[BALANCE as usize] = InstructionInfo::new("BALANCE", 0, 1, 1, false, GasPriceTier::Special); @@ -369,6 +371,10 @@ pub const GASPRICE: Instruction = 0x3a; pub const EXTCODESIZE: Instruction = 0x3b; /// copy external code (from another contract) pub const EXTCODECOPY: Instruction = 0x3c; +/// get the size of the return data buffer for the last call +pub const RETURNDATASIZE: Instruction = 0x3d; +/// copy return data buffer to memory +pub const RETURNDATACOPY: Instruction = 0x3e; /// get hash of most recent complete block pub const BLOCKHASH: Instruction = 0x40; diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index 4d8350e91..e76a5971e 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -173,7 +173,7 @@ impl Gasometer { let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?) }, - instructions::CALLDATACOPY | instructions::CODECOPY => { + instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => { Request::GasMemCopy(default_gas, mem_needed(stack.peek(0), stack.peek(2))?, Gas::from_u256(*stack.peek(2))?) }, instructions::EXTCODECOPY => { diff --git a/ethcore/src/evm/interpreter/memory.rs b/ethcore/src/evm/interpreter/memory.rs index 39c0d8025..555e4bc30 100644 --- a/ethcore/src/evm/interpreter/memory.rs +++ b/ethcore/src/evm/interpreter/memory.rs @@ -15,6 +15,9 @@ // along with Parity. If not, see . use util::U256; +use evm::ReturnData; + +const MAX_RETURN_WASTE_BYTES: usize = 16384; pub trait Memory { /// Retrieve current size of the memory @@ -36,6 +39,8 @@ pub trait Memory { /// Retrieve writeable part of memory fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut[u8]; fn dump(&self); + /// Convert memory into return data. + fn into_return_data(self, offset: U256, size: U256) -> ReturnData; } /// Checks whether offset and size is valid memory range @@ -109,6 +114,21 @@ impl Memory for Vec { Memory::resize(self, size) } } + + fn into_return_data(mut self, offset: U256, size: U256) -> ReturnData { + let mut offset = offset.low_u64() as usize; + let size = size.low_u64() as usize; + if !is_valid_range(offset, size) { + return ReturnData::empty() + } + if self.len() - size > MAX_RETURN_WASTE_BYTES { + { let _ = self.drain(..offset); } + self.truncate(size); + self.shrink_to_fit(); + offset = 0; + } + ReturnData::new(self, offset, size) + } } #[cfg(test)] @@ -164,4 +184,4 @@ mod tests { assert_eq!(mem.read_slice(U256::from(0), U256::from(7)), "a67890g".as_bytes()); } } -} \ No newline at end of file +} diff --git a/ethcore/src/evm/interpreter/mod.rs b/ethcore/src/evm/interpreter/mod.rs index fe3f34013..8b8b739e0 100644 --- a/ethcore/src/evm/interpreter/mod.rs +++ b/ethcore/src/evm/interpreter/mod.rs @@ -32,7 +32,7 @@ use std::marker::PhantomData; use action_params::{ActionParams, ActionValue}; use types::executed::CallType; use evm::instructions::{self, Instruction, InstructionInfo}; -use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress}; +use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress, ReturnData}; use bit_set::BitSet; use util::*; @@ -102,6 +102,7 @@ enum InstructionResult { pub struct Interpreter { mem: Vec, cache: Arc, + return_data: ReturnData, _type: PhantomData, } @@ -166,9 +167,10 @@ impl evm::Evm for Interpreter { }, InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { informant.done(); + let mem = mem::replace(&mut self.mem, Vec::new()); return Ok(GasLeft::NeedsReturn { gas_left: gas.as_u256(), - data: self.mem.read_slice(init_off, init_size), + data: mem.into_return_data(init_off, init_size), apply_state: apply }); }, @@ -187,6 +189,7 @@ impl Interpreter { Interpreter { mem: Vec::new(), cache: cache, + return_data: ReturnData::empty(), _type: PhantomData::default(), } } @@ -233,7 +236,7 @@ impl Interpreter { match instruction { instructions::MSTORE | instructions::MLOAD => Some((stack.peek(0).low_u64() as usize, 32)), instructions::MSTORE8 => Some((stack.peek(0).low_u64() as usize, 1)), - instructions::CALLDATACOPY | instructions::CODECOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)), + instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)), instructions::EXTCODECOPY => Some((stack.peek(1).low_u64() as usize, stack.peek(3).low_u64() as usize)), instructions::CALL | instructions::CALLCODE => Some((stack.peek(5).low_u64() as usize, stack.peek(6).low_u64() as usize)), instructions::DELEGATECALL => Some((stack.peek(4).low_u64() as usize, stack.peek(5).low_u64() as usize)), @@ -362,8 +365,9 @@ impl Interpreter { }; return match call_result { - MessageCallResult::Success(gas_left) => { + MessageCallResult::Success(gas_left, data) => { stack.push(U256::one()); + self.return_data = data; Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater then current one"))) }, MessageCallResult::Failed => { @@ -495,21 +499,27 @@ impl Interpreter { instructions::CODESIZE => { stack.push(U256::from(code.len())); }, + instructions::RETURNDATASIZE => { + stack.push(U256::from(self.return_data.len())) + }, instructions::EXTCODESIZE => { let address = u256_to_address(&stack.pop_back()); let len = ext.extcodesize(&address)?; stack.push(U256::from(len)); }, instructions::CALLDATACOPY => { - self.copy_data_to_memory(stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); + Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); + }, + instructions::RETURNDATACOPY => { + Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data); }, instructions::CODECOPY => { - self.copy_data_to_memory(stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8])); + Self::copy_data_to_memory(&mut self.mem, stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8])); }, instructions::EXTCODECOPY => { let address = u256_to_address(&stack.pop_back()); let code = ext.extcode(&address)?; - self.copy_data_to_memory(stack, &code); + Self::copy_data_to_memory(&mut self.mem, stack, &code); }, instructions::GASPRICE => { stack.push(params.gas_price.clone()); @@ -541,7 +551,7 @@ impl Interpreter { Ok(InstructionResult::Ok) } - fn copy_data_to_memory(&mut self, stack: &mut Stack, source: &[u8]) { + fn copy_data_to_memory(mem: &mut Vec, stack: &mut Stack, source: &[u8]) { let dest_offset = stack.pop_back(); let source_offset = stack.pop_back(); let size = stack.pop_back(); @@ -550,9 +560,9 @@ impl Interpreter { let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size { true => { let zero_slice = if source_offset > source_size { - self.mem.writeable_slice(dest_offset, size) + mem.writeable_slice(dest_offset, size) } else { - self.mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size) + mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size) }; for i in zero_slice.iter_mut() { *i = 0; @@ -564,7 +574,7 @@ impl Interpreter { if source_offset < source_size { let output_begin = source_offset.low_u64() as usize; - self.mem.write_slice(dest_offset, &source[output_begin..output_end]); + mem.write_slice(dest_offset, &source[output_begin..output_end]); } } diff --git a/ethcore/src/evm/mod.rs b/ethcore/src/evm/mod.rs index 3b27c1f31..1ac05ce61 100644 --- a/ethcore/src/evm/mod.rs +++ b/ethcore/src/evm/mod.rs @@ -33,7 +33,7 @@ mod tests; #[cfg(all(feature="benches", test))] mod benches; -pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType}; +pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData}; pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; pub use self::vmtype::VMType; pub use self::factory::Factory; diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index b6e783c91..462a632b4 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -18,7 +18,7 @@ use util::*; use action_params::{ActionParams, ActionValue}; use env_info::EnvInfo; use types::executed::CallType; -use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; +use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; use std::fmt::Debug; use tests::helpers::*; use types::transaction::SYSTEM_ADDRESS; @@ -149,7 +149,7 @@ impl Ext for FakeExt { data: data.to_vec(), code_address: Some(code_address.clone()) }); - MessageCallResult::Success(*gas) + MessageCallResult::Success(*gas, ReturnData::empty()) } fn extcode(&self, address: &Address) -> trie::Result> { @@ -167,7 +167,7 @@ impl Ext for FakeExt { }); } - fn ret(self, _gas: &U256, _data: &[u8]) -> evm::Result { + fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result { unimplemented!(); } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 36efdd2e7..b5b5fb959 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -22,7 +22,7 @@ use engines::Engine; use types::executed::CallType; use env_info::EnvInfo; use error::ExecutionError; -use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult}; +use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData}; use externalities::*; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; use transaction::{Action, SignedTransaction}; @@ -194,7 +194,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { let mut substate = Substate::new(); - let (gas_left, output) = match t.action { + let (result, output) = match t.action { Action::Create => { let code_hash = t.data.sha3(); let new_address = contract_address(self.engine.create_address_scheme(self.info.number), &sender, &nonce, &code_hash); @@ -233,7 +233,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { }; // finalize here! - Ok(self.finalize(t, substate, gas_left, output, tracer.traces(), vm_tracer.drain())?) + Ok(self.finalize(t, substate, result, output, tracer.traces(), vm_tracer.drain())?) } fn exec_vm( @@ -279,7 +279,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { mut output: BytesRef, tracer: &mut T, vm_tracer: &mut V - ) -> evm::Result where T: Tracer, V: VMTracer { + ) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { // backup used in case of running out of gas self.state.checkpoint(); @@ -329,7 +329,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { ); } - Ok(params.gas - cost) + Ok((params.gas - cost, ReturnData::empty())) } } else { // just drain the whole gas @@ -376,13 +376,13 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { self.enact_result(&res, substate, unconfirmed_substate); trace!(target: "executive", "enacted: substate={:?}\n", substate); - res.map(|r| r.gas_left) + res.map(|r| (r.gas_left, r.return_data)) } else { // otherwise it's just a basic transaction, only do tracing, if necessary. self.state.discard_checkpoint(); tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]); - Ok(params.gas) + Ok((params.gas, ReturnData::empty())) } } } @@ -396,7 +396,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { substate: &mut Substate, tracer: &mut T, vm_tracer: &mut V, - ) -> evm::Result where T: Tracer, V: VMTracer { + ) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { let scheme = self.engine.create_address_scheme(self.info.number); if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? { @@ -446,7 +446,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { }; self.enact_result(&res, substate, unconfirmed_substate); - res.map(|r| r.gas_left) + res.map(|r| (r.gas_left, r.return_data)) } /// Finalizes the transaction (does refunds and suicides). @@ -454,7 +454,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { &mut self, t: &SignedTransaction, mut substate: Substate, - result: evm::Result, + result: evm::Result<(U256, ReturnData)>, output: Bytes, trace: Vec, vm_trace: Option @@ -468,7 +468,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { let refunds_bound = sstore_refunds + suicide_refunds; // real ammount to refund - let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() }; + let gas_left_prerefund = match result { Ok((x, _)) => x, _ => 0.into() }; let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1); let gas_left = gas_left_prerefund + refunded; @@ -597,7 +597,7 @@ mod tests { let engine = TestEngine::new(0); let mut substate = Substate::new(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -655,7 +655,7 @@ mod tests { let engine = TestEngine::new(0); let mut substate = Substate::new(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -713,7 +713,7 @@ mod tests { let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() @@ -822,7 +822,7 @@ mod tests { let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap() }; @@ -907,7 +907,7 @@ mod tests { let engine = TestEngine::new(0); let mut substate = Substate::new(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1018,7 +1018,7 @@ mod tests { let engine = TestEngine::new(0); let mut substate = Substate::new(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1062,7 +1062,7 @@ mod tests { let engine = TestEngine::new(0); let mut substate = Substate::new(); - let gas_left = { + let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1267,7 +1267,7 @@ mod tests { let mut substate = Substate::new(); let mut output = [0u8; 14]; - let result = { + let (result, _) = { let mut ex = Executive::new(&mut state, &info, &engine); ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 25ed0d042..22a80a3ba 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -21,7 +21,7 @@ use state::{Backend as StateBackend, State, Substate}; use engines::Engine; use env_info::EnvInfo; use executive::*; -use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; +use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; use types::executed::CallType; use types::transaction::UNSIGNED_SENDER; use trace::{Tracer, VMTracer}; @@ -212,7 +212,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> // TODO: handle internal error separately match ex.create(params, self.substate, self.tracer, self.vm_tracer) { - Ok(gas_left) => { + Ok((gas_left, _)) => { self.substate.contracts_created.push(address.clone()); ContractCreateResult::Created(address, gas_left) }, @@ -261,7 +261,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { - Ok(gas_left) => MessageCallResult::Success(gas_left), + Ok((gas_left, return_data)) => MessageCallResult::Success(gas_left, return_data), _ => MessageCallResult::Failed } } @@ -275,10 +275,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> } #[cfg_attr(feature="dev", allow(match_ref_pats))] - fn ret(mut self, gas: &U256, data: &[u8]) -> evm::Result + fn ret(mut self, gas: &U256, data: &ReturnData) -> evm::Result where Self: Sized { let handle_copy = |to: &mut Option<&mut Bytes>| { - to.as_mut().map(|b| **b = data.to_owned()); + to.as_mut().map(|b| **b = data.to_vec()); }; match self.output { OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { @@ -292,7 +292,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> handle_copy(copy); vec.clear(); - vec.extend_from_slice(data); + vec.extend_from_slice(&*data); Ok(*gas) }, OutputPolicy::InitContract(ref mut copy) => { diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 86442179b..b21259090 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -21,7 +21,7 @@ use executive::*; use engines::Engine; use env_info::EnvInfo; use evm; -use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; +use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; use externalities::*; use types::executed::CallType; use tests::helpers::*; @@ -142,7 +142,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> gas_limit: *gas, value: value.unwrap() }); - MessageCallResult::Success(*gas) + MessageCallResult::Success(*gas, ReturnData::empty()) } fn extcode(&self, address: &Address) -> trie::Result> { @@ -157,7 +157,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> self.ext.log(topics, data) } - fn ret(self, gas: &U256, data: &[u8]) -> Result { + fn ret(self, gas: &U256, data: &ReturnData) -> Result { self.ext.ret(gas, data) } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 915ff91b0..819964aef 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -72,6 +72,8 @@ pub struct CommonParams { pub eip210_contract_code: Bytes, /// Gas allocated for EIP-210 blockhash update. pub eip210_contract_gas: U256, + /// Number of first block where EIP-211 (Metropolis: RETURNDATASIZE/RETURNDATACOPY) rules begin. + pub eip211_transition: BlockNumber, } impl From for CommonParams { @@ -94,6 +96,7 @@ impl From for CommonParams { || DEFAULT_BLOCKHASH_CONTRACT.from_hex().expect("Default BLOCKHASH contract is valid"), Into::into), eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into), + eip211_transition: p.eip211_transition.map_or(BlockNumber::max_value(), Into::into), } } } diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index e5029f4f2..fc69435c9 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -75,6 +75,9 @@ pub struct Params { /// See `CommonParams` docs. #[serde(rename="eip210ContractGas")] pub eip210_contract_gas: Option, + /// See `CommonParams` docs. + #[serde(rename="eip211Transition")] + pub eip211_transition: Option, } #[cfg(test)]