From 7d93fa25336678b6569f119aecaa5efd7bc3095f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 18:37:55 +0100 Subject: [PATCH] Output stored for calls. --- ethcore/src/executive.rs | 10 ++++--- ethcore/src/externalities.rs | 44 ++++++++++++++++++----------- ethcore/src/json_tests/executive.rs | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index d7c0ced0a..a45577322 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -104,7 +104,7 @@ impl<'a> Executive<'a> { } /// Creates `Externalities` from `Executive`. - pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { + pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>) -> Externalities { Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output) } @@ -249,15 +249,17 @@ impl<'a> Executive<'a> { // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); - let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)); + let mut trace_output = trace_info.as_ref().map(|_| vec![]); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) }; if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, vec![])); + if let Some(output) = trace_output { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, output)); + } } trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 6f44bb51c..b0ba67602 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -23,12 +23,12 @@ use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult}; use substate::*; /// Policy for handling output data on `RETURN` opcode. -pub enum OutputPolicy<'a> { +pub enum OutputPolicy<'a, 'b> { /// Return reference to fixed sized output. /// Used for message calls. - Return(BytesRef<'a>), + Return(BytesRef<'a>, Option<&'b mut Bytes>), /// Init new contract as soon as `RETURN` is called. - InitContract + InitContract, } /// Transaction properties that externalities need to know about. @@ -62,18 +62,19 @@ pub struct Externalities<'a> { origin_info: OriginInfo, substate: &'a mut Substate, schedule: Schedule, - output: OutputPolicy<'a> + output: OutputPolicy<'a, 'a> } impl<'a> Externalities<'a> { /// Basic `Externalities` constructor. pub fn new(state: &'a mut State, - env_info: &'a EnvInfo, - engine: &'a Engine, - depth: usize, - origin_info: OriginInfo, - substate: &'a mut Substate, - output: OutputPolicy<'a>) -> Self { + env_info: &'a EnvInfo, + engine: &'a Engine, + depth: usize, + origin_info: OriginInfo, + substate: &'a mut Substate, + output: OutputPolicy<'a, 'a> + ) -> Self { Externalities { state: state, env_info: env_info, @@ -190,20 +191,29 @@ impl<'a> Ext for Externalities<'a> { #[cfg_attr(feature="dev", allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { - match &mut self.output { - &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { + let handle_copy = |to: &mut Option<&mut Bytes>| { + to.as_mut().map(|b| **b = data.to_owned()); + }; + match self.output { + OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { + handle_copy(copy); let len = cmp::min(slice.len(), data.len()); - ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); + unsafe { + ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); + } Ok(*gas) }, - &mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { + OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { + handle_copy(copy); vec.clear(); vec.reserve(data.len()); - ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); - vec.set_len(data.len()); + unsafe { + ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); + vec.set_len(data.len()); + } Ok(*gas) }, - &mut OutputPolicy::InitContract => { + OutputPolicy::InitContract => { let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); if return_cost > *gas { return match self.schedule.exceptional_failed_code_deposit { diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index c0c8b3077..7a9426ad3 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -239,7 +239,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { 0, OriginInfo::from(¶ms), &mut substate, - OutputPolicy::Return(BytesRef::Flexible(&mut output)), + OutputPolicy::Return(&mut BytesRef::Flexible(&mut output)), params.address.clone() ); let evm = engine.vm_factory().create();