From 09beeaba8e7fee4cd3725c417e5b3ec7fd998860 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 6 Apr 2016 21:23:52 +0200 Subject: [PATCH 1/9] trace result is a structure; --- ethcore/src/executive.rs | 32 +++++++++--- ethcore/src/state.rs | 85 +++++++++++++++++++++++++------- ethcore/src/trace/mod.rs | 21 ++++++++ ethcore/src/{ => trace}/trace.rs | 37 ++++++++------ 4 files changed, 136 insertions(+), 39 deletions(-) create mode 100644 ethcore/src/trace/mod.rs rename ethcore/src/{ => trace}/trace.rs (86%) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 3e74895bd..63dea1e76 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -258,7 +258,7 @@ impl<'a> Executive<'a> { } } else { // if destination is a contract, do normal message call - + // don't trace if it's DELEGATECALL or CALLCODE. let should_trace = if let ActionValue::Transfer(_) = params.value { params.code_address == params.address && substate.subtraces.is_some() @@ -281,7 +281,10 @@ impl<'a> Executive<'a> { // if there's tracing, make up trace_info's result with trace_output and some arithmetic. if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: so should_trace: qed"))); + c.result = res.as_ref().ok().map(|gas_left| TraceCallResult { + gas_used: c.gas - *gas_left, + output: trace_output.expect("trace_info is Some: qed") + }); } trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); @@ -294,7 +297,7 @@ impl<'a> Executive<'a> { trace!(target: "executive", "Basic message (send funds) should_trace={}", should_trace); self.state.clear_snapshot(); if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = Some((x!(0), vec![])); + c.result = Some(TraceCallResult::default());// Some((x!(0), vec![])); } substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info); Ok(params.gas) @@ -330,7 +333,11 @@ impl<'a> Executive<'a> { }; if let Some((TraceAction::Create(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, trace_output.expect("trace_info is Some: qed"))); + c.result = res.as_ref().ok().map(|gas_left| TraceCreateResult { + gas_used: c.gas - *gas_left, + address: created, + code: trace_output.expect("trace_info is Some: qed") + }); } trace!(target: "executive", "trace_info={:?}", trace_info); @@ -583,7 +590,10 @@ mod tests { value: x!(100), gas: x!(100000), input: vec![], - result: Some((x!(55248), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(55_248), + output: vec![], + }) }), subs: vec![Trace { depth: 1, @@ -592,7 +602,11 @@ mod tests { value: x!(23), gas: x!(67979), init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - result: Some((x!(3224), x!("c6d80f262ae5e0f164e5fde365044d7ada2bfa34"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])), + result: Some(TraceCreateResult { + gas_used: U256::from(3224), + address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(), + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] + }) }), subs: vec![] }] @@ -646,7 +660,11 @@ mod tests { value: x!(100), gas: params.gas, init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - result: Some((x!(3224), params.address, vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])), + result: Some(TraceCreateResult { + gas_used: U256::from(3224), + address: params.address, + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] + }) }), subs: vec![] } ]); diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index fca578a09..4c997e097 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -398,7 +398,11 @@ fn should_apply_create_transaction() { value: x!(100), gas: x!(77412), init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - result: Some((x!(3224), x!("8988167e088c87cd314df6d3c2b83da5acb93ace"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])) + result: Some(TraceCreateResult { + gas_used: U256::from(3224), + address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] + }) }), subs: vec![] }); @@ -493,7 +497,10 @@ fn should_trace_call_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(3), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(3), + output: vec![] + }) }), subs: vec![] }); @@ -531,7 +538,10 @@ fn should_trace_basic_call_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(0), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(0), + output: vec![] + }) }), subs: vec![] }); @@ -595,7 +605,10 @@ fn should_not_trace_subcall_transaction_to_builtin() { value: x!(0), gas: x!(79000), input: vec![], - result: Some((x!(28061), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(28_061), + output: vec![] + }) }), subs: vec![] }); @@ -634,7 +647,10 @@ fn should_not_trace_callcode() { value: x!(0), gas: x!(79000), input: vec![], - result: Some((x!(64), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(64), + output: vec![] + }) }), subs: vec![] }); @@ -676,7 +692,10 @@ fn should_not_trace_delegatecall() { value: x!(0), gas: x!(79000), input: vec![], - result: Some((x!(61), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(61), + output: vec![] + }) }), subs: vec![] }); @@ -756,7 +775,10 @@ fn should_trace_call_with_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(69), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(69), + output: vec![] + }) }), subs: vec![Trace { depth: 1, @@ -766,7 +788,10 @@ fn should_trace_call_with_subcall_transaction() { value: x!(0), gas: x!(78934), input: vec![], - result: Some((x!(3), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(3), + output: vec![] + }) }), subs: vec![] }] @@ -806,7 +831,10 @@ fn should_trace_call_with_basic_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(31761), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(31761), + output: vec![] + }) }), subs: vec![Trace { depth: 1, @@ -816,7 +844,7 @@ fn should_trace_call_with_basic_subcall_transaction() { value: x!(69), gas: x!(2300), input: vec![], - result: Some((x!(0), vec![])) + result: Some(TraceCallResult::default()) }), subs: vec![] }] @@ -856,7 +884,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(31761), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(31761), + output: vec![] + }) }), subs: vec![] }); @@ -896,7 +927,12 @@ fn should_trace_failed_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(79000), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(79_000), + output: vec![] + }) + + // Some((x!(79000), vec![])) }), subs: vec![Trace { depth: 1, @@ -948,7 +984,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(135), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(135), + output: vec![] + }) }), subs: vec![Trace { depth: 1, @@ -958,7 +997,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78934), input: vec![], - result: Some((x!(69), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(69), + output: vec![] + }) }), subs: vec![Trace { depth: 2, @@ -968,7 +1010,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78868), input: vec![], - result: Some((x!(3), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(3), + output: vec![] + }) }), subs: vec![] }] @@ -1011,7 +1056,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(79000), vec![])) + result: Some(TraceCallResult { + gas_used: U256::from(79_000), + output: vec![] + }) }), subs: vec![Trace { depth: 1, @@ -1031,7 +1079,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78868), input: vec![], - result: Some((x!(3), vec![])), + result: Some(TraceCallResult { + gas_used: U256::from(3), + output: vec![] + }) }), subs: vec![] }] diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs new file mode 100644 index 000000000..39120c810 --- /dev/null +++ b/ethcore/src/trace/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Tracing + +mod trace; + +pub use self::trace::*; diff --git a/ethcore/src/trace.rs b/ethcore/src/trace/trace.rs similarity index 86% rename from ethcore/src/trace.rs rename to ethcore/src/trace/trace.rs index 1ea26b07e..9c97b62da 100644 --- a/ethcore/src/trace.rs +++ b/ethcore/src/trace/trace.rs @@ -17,6 +17,26 @@ //! Tracing datatypes. use common::*; +/// TraceCall result. +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TraceCallResult { + /// Gas used by call. + pub gas_used: U256, + /// Call Output. + pub output: Bytes, +} + +/// TraceCreate result. +#[derive(Debug, Clone, PartialEq)] +pub struct TraceCreateResult { + /// Gas used by create. + pub gas_used: U256, + /// Code of the newly created contract. + pub code: Bytes, + /// Address of the newly created contract. + pub address: Address, +} + /// Description of a _call_ action, either a `CALL` operation or a message transction. #[derive(Debug, Clone, PartialEq)] pub struct TraceCall { @@ -31,7 +51,7 @@ pub struct TraceCall { /// The input data provided to the call. pub input: Bytes, /// The result of the operation; the gas used and the output data of the call. - pub result: Option<(U256, Bytes)>, + pub result: Option, } /// Description of a _create_ action, either a `CREATE` operation or a create transction. @@ -47,15 +67,12 @@ pub struct TraceCreate { pub init: Bytes, /// The result of the operation; tuple of the gas used, the address of the newly created account and its code. /// NOTE: Presently failed operations are not reported so this will always be `Some`. - pub result: Option<(U256, Address, Bytes)>, -// pub output: Bytes, + pub result: Option, } /// Description of an action that we trace; will be either a call or a create. #[derive(Debug, Clone, PartialEq)] pub enum TraceAction { - /// Action isn't yet known. - Unknown, /// It's a call action. Call(TraceCall), /// It's a create action. @@ -74,16 +91,6 @@ pub struct Trace { pub subs: Vec, } -impl Default for Trace { - fn default() -> Trace { - Trace { - depth: 0, - action: TraceAction::Unknown, - subs: vec![], - } - } -} - impl TraceAction { /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call. pub fn from_call(p: &ActionParams) -> TraceAction { From 64294853cc3020eaf20dc567c89714805b46aee8 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 8 Apr 2016 01:50:55 +0200 Subject: [PATCH 2/9] separated tracing logic to its own trait --- ethcore/src/executive.rs | 209 ++++++++++++++++++----------------- ethcore/src/externalities.rs | 46 +++++--- ethcore/src/state.rs | 142 ++++++++++++------------ ethcore/src/substate.rs | 33 ++---- ethcore/src/trace/mod.rs | 178 +++++++++++++++++++++++++++++ ethcore/src/trace/trace.rs | 69 ++++++------ 6 files changed, 431 insertions(+), 246 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 63dea1e76..4c063168a 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -113,12 +113,20 @@ impl<'a> Executive<'a> { } /// Creates `Externalities` from `Executive`. - 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) + pub fn as_externalities<'_, T>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>, tracer: &'_ mut T) -> Externalities<'_, T> where T: Tracer { + Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output, tracer) } /// This funtion should be used to execute transaction. pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { + let check = options.check_nonce; + match options.tracing { + true => self.transact_with_tracer(t, check, ExecutiveTracer::default()), + false => self.transact_with_tracer(t, check, NoopTracer), + } + } + + pub fn transact_with_tracer(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result where T: Tracer { let sender = try!(t.sender()); let nonce = self.state.nonce(&sender); @@ -132,7 +140,7 @@ impl<'a> Executive<'a> { let init_gas = t.gas - base_gas_required; // validate transaction nonce - if options.check_nonce { + if check_nonce { if t.nonce != nonce { return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); } @@ -161,7 +169,7 @@ impl<'a> Executive<'a> { self.state.inc_nonce(&sender); self.state.sub_balance(&sender, &U256::from(gas_cost)); - let mut substate = Substate::new(options.tracing); + let mut substate = Substate::new(); let (gas_left, output) = match t.action { Action::Create => { @@ -177,7 +185,7 @@ impl<'a> Executive<'a> { code: Some(t.data.clone()), data: None, }; - (self.create(params, &mut substate), vec![]) + (self.create(params, &mut substate, &mut tracer), vec![]) }, Action::Call(ref address) => { let params = ActionParams { @@ -193,18 +201,19 @@ impl<'a> Executive<'a> { }; // TODO: move output upstream let mut out = vec![]; - (self.call(params, &mut substate, BytesRef::Flexible(&mut out)), out) + (self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer), out) } }; // finalize here! - Ok(try!(self.finalize(t, substate, gas_left, output))) + Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop()))) } - fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy) -> evm::Result { + fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, tracer: &mut T) + -> evm::Result where T: Tracer { // Ordinary execution - keep VM in same thread if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 { - let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy); + let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer); let vm_factory = self.engine.vm_factory(); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); return vm_factory.create().exec(params, &mut ext); @@ -214,7 +223,7 @@ impl<'a> Executive<'a> { // TODO [todr] No thread builder yet, so we need to reset once for a while // https://github.com/aturon/crossbeam/issues/16 crossbeam::scope(|scope| { - let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy); + let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer); let vm_factory = self.engine.vm_factory(); scope.spawn(move || { @@ -227,7 +236,8 @@ impl<'a> Executive<'a> { /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. - pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { + pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef, tracer: &mut T) + -> evm::Result where T: Tracer { // backup used in case of running out of gas self.state.snapshot(); @@ -257,49 +267,45 @@ impl<'a> Executive<'a> { } } } else { - // if destination is a contract, do normal message call - - // don't trace if it's DELEGATECALL or CALLCODE. - let should_trace = if let ActionValue::Transfer(_) = params.value { - params.code_address == params.address && substate.subtraces.is_some() - } else { false }; - - // transaction tracing stuff. None if there's no tracing. - let (mut trace_info, mut trace_output) = if should_trace { - (Some((TraceAction::from_call(¶ms), self.depth)), Some(vec![])) - } else { (None, None) }; + let trace_info = tracer.prepare_trace_call(¶ms); + let mut trace_output = tracer.prepare_trace_output(); + let mut subtracer = tracer.subtracer(); + let delegate_call = params.code_address != params.address; + let gas = params.gas; if params.code.is_some() { // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(should_trace); + let mut unconfirmed_substate = Substate::new(); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer) }; trace!(target: "executive", "res={:?}", res); - // if there's tracing, make up trace_info's result with trace_output and some arithmetic. - if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| TraceCallResult { - gas_used: c.gas - *gas_left, - output: trace_output.expect("trace_info is Some: qed") - }); - } + let traces = subtracer.traces(); + match res { + Ok(gas_left) => tracer.trace_call( + trace_info, + gas - gas_left, + trace_output, + self.depth, + traces, + delegate_call + ), + _ => tracer.trace_failed_call(trace_info, self.depth, traces, delegate_call), + }; trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - self.enact_result(&res, substate, unconfirmed_substate, trace_info); + self.enact_result(&res, substate, unconfirmed_substate); trace!(target: "executive", "enacted: substate={:?}\n", substate); res } else { // otherwise it's just a basic transaction, only do tracing, if necessary. - trace!(target: "executive", "Basic message (send funds) should_trace={}", should_trace); self.state.clear_snapshot(); - if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = Some(TraceCallResult::default());// Some((x!(0), vec![])); - } - substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info); + + tracer.trace_call(trace_info, U256::zero(), Some(vec![]), self.depth, vec![], delegate_call); Ok(params.gas) } } @@ -308,12 +314,13 @@ impl<'a> Executive<'a> { /// Creates contract with given contract params. /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate. - pub fn create(&mut self, params: ActionParams, substate: &mut Substate) -> evm::Result { + pub fn create(&mut self, params: ActionParams, substate: &mut Substate, tracer: &mut T) -> evm::Result where T: + Tracer { // backup used in case of running out of gas self.state.snapshot(); // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); + let mut unconfirmed_substate = Substate::new(); // create contract and transfer value to it if necessary let prev_bal = self.state.balance(¶ms.address); @@ -324,30 +331,34 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address, prev_bal); } - let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_create(¶ms), self.depth)); - let mut trace_output = trace_info.as_ref().map(|_| vec![]); + let trace_info = tracer.prepare_trace_create(¶ms); + let mut trace_output = tracer.prepare_trace_output(); + let mut subtracer = tracer.subtracer(); + let gas = params.gas; let created = params.address.clone(); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut())) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer) }; - if let Some((TraceAction::Create(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| TraceCreateResult { - gas_used: c.gas - *gas_left, - address: created, - code: trace_output.expect("trace_info is Some: qed") - }); - } + match res { + Ok(gas_left) => tracer.trace_create( + trace_info, + gas - gas_left, + trace_output, + created, + self.depth, + subtracer.traces() + ), + _ => tracer.trace_failed_create(trace_info, self.depth, subtracer.traces()) + }; - trace!(target: "executive", "trace_info={:?}", trace_info); - - self.enact_result(&res, substate, unconfirmed_substate, trace_info); + self.enact_result(&res, substate, unconfirmed_substate); res } /// Finalizes the transaction (does refunds and suicides). - fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes) -> ExecutionResult { + fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes, trace: Option) -> ExecutionResult { let schedule = self.engine.schedule(self.info); // refunds from SSTORE nonzero -> zero @@ -378,8 +389,6 @@ impl<'a> Executive<'a> { self.state.kill_account(address); } - let trace = substate.subtraces.and_then(|mut v| v.pop()); - match result { Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(_) => { @@ -409,19 +418,18 @@ impl<'a> Executive<'a> { } } - fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, maybe_info: Option<(TraceAction, usize)>) { + fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) { match *result { Err(evm::Error::OutOfGas) | Err(evm::Error::BadJumpDestination {..}) | Err(evm::Error::BadInstruction {.. }) | Err(evm::Error::StackUnderflow {..}) | Err(evm::Error::OutOfStack {..}) => { - self.state.revert_snapshot(); - substate.accrue_trace(un_substate.subtraces, maybe_info) + self.state.revert_snapshot(); }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); - substate.accrue(un_substate, maybe_info) + substate.accrue(un_substate); } } } @@ -459,11 +467,11 @@ mod tests { state.add_balance(&sender, &U256::from(0x100u64)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate).unwrap() + ex.create(params, &mut substate, &mut NoopTracer).unwrap() }; assert_eq!(gas_left, U256::from(79_975)); @@ -518,11 +526,11 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate).unwrap() + ex.create(params, &mut substate, &mut NoopTracer).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -573,16 +581,16 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(5, factory); - let mut substate = Substate::new(true); + let mut substate = Substate::new(); + let mut tracer = ExecutiveTracer::default(); 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).unwrap() + ex.call(params, &mut substate, output, &mut tracer).unwrap() }; - println!("trace: {:?}", substate.subtraces); - let expected_trace = Some(vec![ Trace { + let expected_trace = vec![ Trace { depth: 0, action: TraceAction::Call(TraceCall { from: x!("cd1722f3947def4cf144679da39c4c32bdc35681"), @@ -590,10 +598,10 @@ mod tests { value: x!(100), gas: x!(100000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(55_248), - output: vec![], - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(55_248), + output: vec![], }), subs: vec![Trace { depth: 1, @@ -601,17 +609,17 @@ mod tests { from: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), value: x!(23), gas: x!(67979), - init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - result: Some(TraceCreateResult { - gas_used: U256::from(3224), - address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(), - code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] - }) + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85] + }), + result: TraceResult::Create(TraceCreateResult { + gas_used: U256::from(3224), + address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(), + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), subs: vec![] }] - } ]); - assert_eq!(substate.subtraces, expected_trace); + }]; + assert_eq!(tracer.traces(), expected_trace); assert_eq!(gas_left, U256::from(44_752)); } @@ -645,30 +653,31 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(5, factory); - let mut substate = Substate::new(true); + let mut substate = Substate::new(); + let mut tracer = ExecutiveTracer::default(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params.clone(), &mut substate).unwrap() + ex.create(params.clone(), &mut substate, &mut tracer).unwrap() }; - println!("trace: {:?}", substate.subtraces); - let expected_trace = Some(vec![Trace { + let expected_trace = vec![Trace { depth: 0, action: TraceAction::Create(TraceCreate { from: params.sender, value: x!(100), gas: params.gas, init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - result: Some(TraceCreateResult { - gas_used: U256::from(3224), - address: params.address, - code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] - }) + }), + result: TraceResult::Create(TraceCreateResult { + gas_used: U256::from(3224), + address: params.address, + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), subs: vec![] - } ]); - assert_eq!(substate.subtraces, expected_trace); + }]; + + assert_eq!(tracer.traces(), expected_trace); assert_eq!(gas_left, U256::from(96_776)); } @@ -714,11 +723,11 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate).unwrap() + ex.create(params, &mut substate, &mut NoopTracer).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -766,11 +775,11 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(1024, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate).unwrap(); + ex.create(params, &mut substate, &mut NoopTracer).unwrap(); } assert_eq!(substate.contracts_created.len(), 1); @@ -827,11 +836,11 @@ mod tests { let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap() + ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer).unwrap() }; assert_eq!(gas_left, U256::from(73_237)); @@ -872,11 +881,11 @@ mod tests { state.init_code(&address, code.clone()); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap() + ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer).unwrap() }; assert_eq!(gas_left, U256::from(59_870)); @@ -1074,11 +1083,11 @@ mod tests { state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); let result = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate) + ex.create(params, &mut substate, &mut NoopTracer) }; match result { diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 3f9d4ff08..7d9e11d58 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -54,7 +54,7 @@ impl OriginInfo { } /// Implementation of evm Externalities. -pub struct Externalities<'a> { +pub struct Externalities<'a, T> where T: 'a + Tracer { state: &'a mut State, env_info: &'a EnvInfo, engine: &'a Engine, @@ -62,10 +62,11 @@ pub struct Externalities<'a> { origin_info: OriginInfo, substate: &'a mut Substate, schedule: Schedule, - output: OutputPolicy<'a, 'a> + output: OutputPolicy<'a, 'a>, + tracer: &'a mut T, } -impl<'a> Externalities<'a> { +impl<'a, T> Externalities<'a, T> where T: 'a + Tracer { /// Basic `Externalities` constructor. pub fn new(state: &'a mut State, env_info: &'a EnvInfo, @@ -73,7 +74,8 @@ impl<'a> Externalities<'a> { depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, - output: OutputPolicy<'a, 'a> + output: OutputPolicy<'a, 'a>, + tracer: &'a mut T, ) -> Self { Externalities { state: state, @@ -83,12 +85,13 @@ impl<'a> Externalities<'a> { origin_info: origin_info, substate: substate, schedule: engine.schedule(env_info), - output: output + output: output, + tracer: tracer, } } } -impl<'a> Ext for Externalities<'a> { +impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer { fn storage_at(&self, key: &H256) -> H256 { self.state.storage_at(&self.origin_info.address, key) } @@ -143,7 +146,7 @@ impl<'a> Ext for Externalities<'a> { let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); // TODO: handle internal error separately - match ex.create(params, self.substate) { + match ex.create(params, self.substate, self.tracer) { Ok(gas_left) => { self.substate.contracts_created.push(address.clone()); ContractCreateResult::Created(address, gas_left) @@ -181,7 +184,7 @@ impl<'a> Ext for Externalities<'a> { let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); - match ex.call(params, self.substate, BytesRef::Fixed(output)) { + match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer) { Ok(gas_left) => MessageCallResult::Success(gas_left), _ => MessageCallResult::Failed } @@ -208,7 +211,7 @@ impl<'a> Ext for Externalities<'a> { }, OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { handle_copy(copy); - + vec.clear(); vec.reserve(data.len()); unsafe { @@ -225,7 +228,7 @@ impl<'a> Ext for Externalities<'a> { false => Ok(*gas) } } - + handle_copy(copy); let mut code = vec![]; @@ -328,7 +331,7 @@ mod tests { TestSetup { state: get_temp_state(), engine: get_test_spec().to_engine().unwrap(), - sub_state: Substate::new(false), + sub_state: Substate::new(), env_info: get_test_env_info() } } @@ -338,8 +341,9 @@ mod tests { fn can_be_created() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); + let mut tracer = NoopTracer; - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); assert_eq!(ext.env_info().number, 100); } @@ -348,7 +352,9 @@ mod tests { fn can_return_block_hash_no_env() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); + let mut tracer = NoopTracer; + + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -367,7 +373,9 @@ mod tests { env_info.last_hashes.push(test_hash.clone()); } let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); + let mut tracer = NoopTracer; + + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -379,7 +387,9 @@ mod tests { fn can_call_fail_empty() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); + let mut tracer = NoopTracer; + + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); let mut output = vec![]; @@ -401,9 +411,10 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); + let mut tracer = NoopTracer; { - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); ext.log(log_topics, &log_data); } @@ -416,9 +427,10 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); + let mut tracer = NoopTracer; { - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); ext.suicide(&refund_account); } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 4c997e097..44b62def0 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -398,11 +398,11 @@ fn should_apply_create_transaction() { value: x!(100), gas: x!(77412), init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - result: Some(TraceCreateResult { - gas_used: U256::from(3224), - address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), - code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] - }) + }), + result: TraceResult::Create(TraceCreateResult { + gas_used: U256::from(3224), + address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), subs: vec![] }); @@ -458,8 +458,8 @@ fn should_trace_failed_create_transaction() { value: x!(100), gas: x!(78792), init: vec![91, 96, 0, 86], - result: None }), + result: TraceResult::FailedCreate, subs: vec![] }); @@ -497,10 +497,10 @@ fn should_trace_call_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(3), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(3), + output: vec![] }), subs: vec![] }); @@ -538,10 +538,10 @@ fn should_trace_basic_call_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(0), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(0), + output: vec![] }), subs: vec![] }); @@ -605,10 +605,10 @@ fn should_not_trace_subcall_transaction_to_builtin() { value: x!(0), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(28_061), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(28_061), + output: vec![] }), subs: vec![] }); @@ -647,10 +647,10 @@ fn should_not_trace_callcode() { value: x!(0), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(64), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(64), + output: vec![] }), subs: vec![] }); @@ -692,10 +692,10 @@ fn should_not_trace_delegatecall() { value: x!(0), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(61), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(61), + output: vec![] }), subs: vec![] }); @@ -733,8 +733,8 @@ fn should_trace_failed_call_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: None }), + result: TraceResult::FailedCall, subs: vec![] }); @@ -775,10 +775,10 @@ fn should_trace_call_with_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(69), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(69), + output: vec![] }), subs: vec![Trace { depth: 1, @@ -788,10 +788,10 @@ fn should_trace_call_with_subcall_transaction() { value: x!(0), gas: x!(78934), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(3), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(3), + output: vec![] }), subs: vec![] }] @@ -831,10 +831,10 @@ fn should_trace_call_with_basic_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(31761), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(31761), + output: vec![] }), subs: vec![Trace { depth: 1, @@ -844,8 +844,8 @@ fn should_trace_call_with_basic_subcall_transaction() { value: x!(69), gas: x!(2300), input: vec![], - result: Some(TraceCallResult::default()) }), + result: TraceResult::Call(TraceCallResult::default()), subs: vec![] }] }); @@ -884,10 +884,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(31761), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(31761), + output: vec![] }), subs: vec![] }); @@ -927,12 +927,10 @@ fn should_trace_failed_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(79_000), - output: vec![] - }) - - // Some((x!(79000), vec![])) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(79_000), + output: vec![] }), subs: vec![Trace { depth: 1, @@ -942,8 +940,8 @@ fn should_trace_failed_subcall_transaction() { value: x!(0), gas: x!(78934), input: vec![], - result: None }), + result: TraceResult::FailedCall, subs: vec![] }] }); @@ -984,10 +982,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(135), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(135), + output: vec![] }), subs: vec![Trace { depth: 1, @@ -997,10 +995,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78934), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(69), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(69), + output: vec![] }), subs: vec![Trace { depth: 2, @@ -1010,10 +1008,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78868), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(3), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(3), + output: vec![] }), subs: vec![] }] @@ -1056,10 +1054,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(79_000), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(79_000), + output: vec![] }), subs: vec![Trace { depth: 1, @@ -1069,8 +1067,8 @@ fn should_trace_failed_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78934), input: vec![], - result: None }), + result: TraceResult::FailedCall, subs: vec![Trace { depth: 2, action: TraceAction::Call(TraceCall { @@ -1079,10 +1077,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() { value: x!(0), gas: x!(78868), input: vec![], - result: Some(TraceCallResult { - gas_used: U256::from(3), - output: vec![] - }) + }), + result: TraceResult::Call(TraceCallResult { + gas_used: U256::from(3), + output: vec![] }), subs: vec![] }] diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 9d81badb9..f643fea07 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -32,44 +32,25 @@ pub struct Substate { /// Created contracts. pub contracts_created: Vec
, - - /// The trace during this execution or `None` if we're not tracing. - pub subtraces: Option>, } impl Substate { /// Creates new substate. - pub fn new(tracing: bool) -> Self { + pub fn new() -> Self { Substate { suicides: Default::default(), logs: Default::default(), sstore_clears_count: Default::default(), contracts_created: Default::default(), - subtraces: if tracing {Some(vec![])} else {None}, } } - /// Merge tracing information from substate `s` if enabled. - pub fn accrue_trace(&mut self, subs: Option>, maybe_info: Option<(TraceAction, usize)>) { - // it failed, so we don't bother accrueing any protocol-level stuff, only the - // trace info. - if let Some(info) = maybe_info { - self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace { - action: info.0, - depth: info.1, - subs: subs.expect("maybe_action is Some: so we must be tracing: qed"), - }); - } - } - - /// Merge secondary substate `s` into self, accruing each element correspondingly; will merge - /// tracing information too, if enabled. - pub fn accrue(&mut self, s: Substate, maybe_info: Option<(TraceAction, usize)>) { + /// Merge secondary substate `s` into self, accruing each element correspondingly. + pub fn accrue(&mut self, s: Substate) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); - self.accrue_trace(s.subtraces, maybe_info); } } @@ -80,13 +61,13 @@ mod tests { #[test] fn created() { - let sub_state = Substate::new(false); + let sub_state = Substate::new(); assert_eq!(sub_state.suicides.len(), 0); } #[test] fn accrue() { - let mut sub_state = Substate::new(false); + let mut sub_state = Substate::new(); sub_state.contracts_created.push(address_from_u64(1u64)); sub_state.logs.push(LogEntry { address: address_from_u64(1u64), @@ -96,7 +77,7 @@ mod tests { sub_state.sstore_clears_count = x!(5); sub_state.suicides.insert(address_from_u64(10u64)); - let mut sub_state_2 = Substate::new(false); + let mut sub_state_2 = Substate::new(); sub_state_2.contracts_created.push(address_from_u64(2u64)); sub_state_2.logs.push(LogEntry { address: address_from_u64(1u64), @@ -105,7 +86,7 @@ mod tests { }); sub_state_2.sstore_clears_count = x!(7); - sub_state.accrue(sub_state_2, None); + sub_state.accrue(sub_state_2); assert_eq!(sub_state.contracts_created.len(), 2); assert_eq!(sub_state.sstore_clears_count, x!(12)); assert_eq!(sub_state.suicides.len(), 1); diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 39120c810..c63f43f23 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -19,3 +19,181 @@ mod trace; pub use self::trace::*; +use util::bytes::Bytes; +use util::hash::Address; +use util::numbers::U256; +use action_params::ActionParams; + +/// This trait is used by executive to build traces. +pub trait Tracer: Send { + /// Prepares call trace for given params. Noop tracer should return None. + fn prepare_trace_call(&self, params: &ActionParams) -> Option; + + /// Prepares create trace for given params. Noop tracer should return None. + fn prepare_trace_create(&self, params: &ActionParams) -> Option; + + /// Prepare trace output. Noop tracer should return None. + fn prepare_trace_output(&self) -> Option; + + /// Stores trace call info. + fn trace_call( + &mut self, + call: Option, + gas_used: U256, + output: Option, + depth: usize, + subs: Vec, + delegate_call: bool + ); + + /// Stores trace create info. + fn trace_create( + &mut self, + create: Option, + gas_used: U256, + code: Option, + address: Address, + depth: usize, + subs: Vec + ); + + /// Stores failed call trace. + fn trace_failed_call(&mut self, call: Option, depth: usize, subs: Vec, delegate_call: bool); + + /// Stores failed create trace. + fn trace_failed_create(&mut self, create: Option, depth: usize, subs: Vec); + + /// Spawn subracer which will be used to trace deeper levels of execution. + fn subtracer(&self) -> Self where Self: Sized; + + /// Consumes self and returns all traces. + fn traces(self) -> Vec; +} + +/// Nonoperative tracer. Does not trace anything. +pub struct NoopTracer; + +impl Tracer for NoopTracer { + fn prepare_trace_call(&self, _: &ActionParams) -> Option { + None + } + + fn prepare_trace_create(&self, _: &ActionParams) -> Option { + None + } + + fn prepare_trace_output(&self) -> Option { + None + } + + fn trace_call(&mut self, call: Option, _: U256, output: Option, _: usize, _: Vec, + _: bool) { + assert!(call.is_none()); + assert!(output.is_none()); + } + + fn trace_create(&mut self, create: Option, _: U256, code: Option, _: Address, _: usize, _: Vec) { + assert!(create.is_none()); + assert!(code.is_none()); + } + + fn trace_failed_call(&mut self, call: Option, _: usize, _: Vec, _: bool) { + assert!(call.is_none()); + } + + fn trace_failed_create(&mut self, create: Option, _: usize, _: Vec) { + assert!(create.is_none()); + } + + fn subtracer(&self) -> Self { + NoopTracer + } + + fn traces(self) -> Vec { + vec![] + } +} + +/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls. +#[derive(Default)] +pub struct ExecutiveTracer { + traces: Vec +} + +impl Tracer for ExecutiveTracer { + fn prepare_trace_call(&self, params: &ActionParams) -> Option { + Some(TraceCall::from(params.clone())) + } + + fn prepare_trace_create(&self, params: &ActionParams) -> Option { + Some(TraceCreate::from(params.clone())) + } + + fn prepare_trace_output(&self) -> Option { + Some(vec![]) + } + + fn trace_call(&mut self, call: Option, gas_used: U256, output: Option, depth: usize, subs: + Vec, delegate_call: bool) { + if delegate_call { + return; + } + + let trace = Trace { + depth: depth, + subs: subs, + action: TraceAction::Call(call.expect("Trace call expected to be Some.")), + result: TraceResult::Call(TraceCallResult { + gas_used: gas_used, + output: output.expect("Trace call output expected to be Some.") + }) + }; + self.traces.push(trace); + } + + fn trace_create(&mut self, create: Option, gas_used: U256, code: Option, address: Address, depth: usize, subs: Vec) { + let trace = Trace { + depth: depth, + subs: subs, + action: TraceAction::Create(create.expect("Trace create expected to be Some.")), + result: TraceResult::Create(TraceCreateResult { + gas_used: gas_used, + code: code.expect("Trace create code expected to be Some."), + address: address + }) + }; + self.traces.push(trace); + } + + fn trace_failed_call(&mut self, call: Option, depth: usize, subs: Vec, delegate_call: bool) { + if delegate_call { + return; + } + + let trace = Trace { + depth: depth, + subs: subs, + action: TraceAction::Call(call.expect("Trace call expected to be Some.")), + result: TraceResult::FailedCall, + }; + self.traces.push(trace); + } + + fn trace_failed_create(&mut self, create: Option, depth: usize, subs: Vec) { + let trace = Trace { + depth: depth, + subs: subs, + action: TraceAction::Create(create.expect("Trace create expected to be Some.")), + result: TraceResult::FailedCreate, + }; + self.traces.push(trace); + } + + fn subtracer(&self) -> Self { + ExecutiveTracer::default() + } + + fn traces(self) -> Vec { + self.traces + } +} diff --git a/ethcore/src/trace/trace.rs b/ethcore/src/trace/trace.rs index 9c97b62da..b0e2e75f5 100644 --- a/ethcore/src/trace/trace.rs +++ b/ethcore/src/trace/trace.rs @@ -50,8 +50,18 @@ pub struct TraceCall { pub gas: U256, /// The input data provided to the call. pub input: Bytes, - /// The result of the operation; the gas used and the output data of the call. - pub result: Option, +} + +impl From for TraceCall { + fn from(p: ActionParams) -> Self { + TraceCall { + from: p.sender, + to: p.address, + value: p.value.value(), + gas: p.gas, + input: p.data.unwrap_or_else(Vec::new), + } + } } /// Description of a _create_ action, either a `CREATE` operation or a create transction. @@ -65,9 +75,17 @@ pub struct TraceCreate { pub gas: U256, /// The init code. pub init: Bytes, - /// The result of the operation; tuple of the gas used, the address of the newly created account and its code. - /// NOTE: Presently failed operations are not reported so this will always be `Some`. - pub result: Option, +} + +impl From for TraceCreate { + fn from(p: ActionParams) -> Self { + TraceCreate { + from: p.sender, + value: p.value.value(), + gas: p.gas, + init: p.code.unwrap_or_else(Vec::new), + } + } } /// Description of an action that we trace; will be either a call or a create. @@ -79,6 +97,19 @@ pub enum TraceAction { Create(TraceCreate), } +/// The result of the performed action. +#[derive(Debug, Clone, PartialEq)] +pub enum TraceResult { + /// Successful call action result. + Call(TraceCallResult), + /// Successful create action result. + Create(TraceCreateResult), + /// Failed call. + FailedCall, + /// Failed create. + FailedCreate, +} + #[derive(Debug, Clone, PartialEq)] /// A trace; includes a description of the action being traced and sub traces of each interior action. pub struct Trace { @@ -89,30 +120,6 @@ pub struct Trace { pub action: TraceAction, /// The sub traces for each interior action performed as part of this call. pub subs: Vec, + /// The result of the performed action. + pub result: TraceResult, } - -impl TraceAction { - /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call. - pub fn from_call(p: &ActionParams) -> TraceAction { - TraceAction::Call(TraceCall { - from: p.sender.clone(), - to: p.address.clone(), - value: p.value.value(), - gas: p.gas, - input: p.data.clone().unwrap_or_else(Vec::new), - result: None, - }) - } - - /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a create. - pub fn from_create(p: &ActionParams) -> TraceAction { - TraceAction::Create(TraceCreate { - from: p.sender.clone(), - value: p.value.value(), - gas: p.gas, - init: p.code.clone().unwrap_or_else(Vec::new), - result: None, - }) - } -} - From fcf7f392f010ef3798fa2a2489925b38fb7d8bf7 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 8 Apr 2016 11:48:37 +0200 Subject: [PATCH 3/9] fixed failing tests --- ethcore/src/executive.rs | 2 +- ethcore/src/json_tests/executive.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 4c063168a..fc2f837ef 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -305,7 +305,7 @@ impl<'a> Executive<'a> { // otherwise it's just a basic transaction, only do tracing, if necessary. self.state.clear_snapshot(); - tracer.trace_call(trace_info, U256::zero(), Some(vec![]), self.depth, vec![], delegate_call); + tracer.trace_call(trace_info, U256::zero(), trace_output, self.depth, vec![], delegate_call); Ok(params.gas) } } diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 283394204..c714f6ef6 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -76,13 +76,13 @@ impl From for CallCreate { /// Tiny wrapper around executive externalities. /// Stores callcreates. -struct TestExt<'a> { - ext: Externalities<'a>, +struct TestExt<'a, T> where T: 'a + Tracer { + ext: Externalities<'a, T>, callcreates: Vec, contract_address: Address } -impl<'a> TestExt<'a> { +impl<'a, T> TestExt<'a, T> where T: 'a + Tracer { fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, @@ -90,16 +90,17 @@ impl<'a> TestExt<'a> { origin_info: OriginInfo, substate: &'a mut Substate, output: OutputPolicy<'a, 'a>, - address: Address) -> Self { + address: Address, + tracer: &'a mut T) -> Self { TestExt { contract_address: contract_address(&address, &state.nonce(&address)), - ext: Externalities::new(state, info, engine, depth, origin_info, substate, output), + ext: Externalities::new(state, info, engine, depth, origin_info, substate, output, tracer), callcreates: vec![] } } } -impl<'a> Ext for TestExt<'a> { +impl<'a, T> Ext for TestExt<'a, T> where T: Tracer { fn storage_at(&self, key: &H256) -> H256 { self.ext.storage_at(key) } @@ -209,7 +210,8 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { let engine = TestEngineFrontier::new(1, vm_type.clone()); let params = ActionParams::from(vm.transaction); - let mut substate = Substate::new(false); + let mut substate = Substate::new(); + let mut tracer = NoopTracer; let mut output = vec![]; // execute @@ -222,7 +224,8 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { OriginInfo::from(¶ms), &mut substate, OutputPolicy::Return(BytesRef::Flexible(&mut output), None), - params.address.clone() + params.address.clone(), + &mut tracer, ); let evm = engine.vm_factory().create(); let res = evm.exec(params, &mut ex); From 69add611742962eefce4372f056c2289ac4416bf Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 10 Apr 2016 16:12:20 +0300 Subject: [PATCH 4/9] basic upgrade scenario --- Cargo.lock | 1 + Cargo.toml | 2 +- parity/main.rs | 2 ++ parity/upgrade.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 parity/upgrade.rs diff --git a/Cargo.lock b/Cargo.lock index f0f64af94..4a8e6002b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,6 +22,7 @@ dependencies = [ "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 3fe923db7..2f0d0789c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } ethcore-webapp = { path = "webapp", optional = true } - +semver = "0.2" [dependencies.hyper] version = "0.8" diff --git a/parity/main.rs b/parity/main.rs index 8ee9c6f63..b605a9dd4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -36,6 +36,7 @@ extern crate daemonize; extern crate time; extern crate number_prefix; extern crate rpassword; +extern crate semver; // for price_info.rs #[macro_use] extern crate hyper; @@ -71,6 +72,7 @@ use rpc::Server as RpcServer; use webapp::Listening as WebappServer; mod price_info; +mod upgrade; fn die_with_message(msg: &str) -> ! { println!("ERROR: {}", msg); diff --git a/parity/upgrade.rs b/parity/upgrade.rs new file mode 100644 index 000000000..22ef4a571 --- /dev/null +++ b/parity/upgrade.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Parity upgrade logic + +use semver::Version; +use std::collections::*; +use std::path::*; + +struct Error; + +const CURRENT_VERSION: &'static str = env!("CARGO_PKG_VERSION"); + +#[derive(Hash, PartialEq, Eq)] +struct UpgradeKey { + pub old_version: Version, + pub new_version: Version, +} + +type UpgradeList = HashMap Result<(), Error>>; + +impl UpgradeKey { + // given the following config exist + // ver.lock 1.1 (`previous_version`) + // + // current_version 1.4 (`current_version`) + // + // + //upgrades (set of `UpgradeKey`) + // 1.0 -> 1.1 (u1) + // 1.1 -> 1.2 (u2) + // 1.2 -> 1.3 (u3) + // 1.3 -> 1.4 (u4) + // 1.4 -> 1.5 (u5) + // + // then the following upgrades should be applied: + // u2, u3, u4 + fn is_applicable(&self, previous_version: &Version, current_version: &Version) -> bool { + self.old_version >= *previous_version && self.new_version <= *current_version + } +} + +// dummy upgrade (remove when the first one is in) +fn dummy_upgrade() -> Result<(), Error> { + Ok(()) +} + +fn push_updrades(upgrades: &mut UpgradeList) +{ + // dummy upgrade (remove when the first one is in) + upgrades.insert( + UpgradeKey { old_version: Version::parse("1.0.0").unwrap(), new_version: Version::parse("99.99.0").unwrap() }, + dummy_upgrade); +} + +fn upgrade_from_version(previous_version: &Version) -> Result { + let mut upgrades = HashMap::new(); + push_updrades(&mut upgrades); + + let current_version = Version::parse(CURRENT_VERSION).unwrap(); + + let mut count = 0; + for upgrade_key in upgrades.keys() { + if upgrade_key.is_applicable(previous_version, ¤t_version) { + let upgrade_script = upgrades[upgrade_key]; + try!(upgrade_script()); + count = count + 1; + } + } + Ok(count) +} From d3411a50a4ed056e33361d5f66c1476523f8b67d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 10 Apr 2016 16:42:33 +0300 Subject: [PATCH 5/9] locked ver.lock upgrade --- parity/upgrade.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/parity/upgrade.rs b/parity/upgrade.rs index 22ef4a571..50861fa91 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -19,8 +19,14 @@ use semver::Version; use std::collections::*; use std::path::*; +use std::fs::File; +use std::env; +use std::io::{Read, Write}; -struct Error; +pub enum Error { + CannotLockVersionFile, + CannotUpdateVersionFile, +} const CURRENT_VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -82,3 +88,42 @@ fn upgrade_from_version(previous_version: &Version) -> Result { } Ok(count) } + +fn with_locked_version(script: F) -> Result + where F: Fn(&Version) -> Result +{ + let mut path = env::home_dir().expect("Applications should have a home dir"); + path.push(".parity"); + path.push("ver.lock"); + + let version: Option = { + match File::open(&path) { + Ok(mut file) => { + let mut version_string = String::new(); + match file.read_to_string(&mut version_string) { + Ok(_) => Some(Version::parse(&version_string).unwrap()), + Err(_) => None + } + }, + Err(_) => None + } + }; + let effective_version = version.unwrap_or_else(|| Version::parse("0.9.0").unwrap()); + + let script_result = { + let mut lock = try!(File::create(&path).map_err(|_| Error::CannotLockVersionFile)); + let result = script(&effective_version); + + let written_version = Version::parse(CURRENT_VERSION).unwrap(); + try!(lock.write_all(written_version.to_string().as_bytes()).map_err(|_| Error::CannotUpdateVersionFile)); + result + }; + + script_result +} + +pub fn upgrade() -> Result { + with_locked_version(|ver| { + upgrade_from_version(ver) + }) +} From 26e23da4c017c67fa836a2faa9c99ef7d505fd15 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 10 Apr 2016 17:15:40 +0300 Subject: [PATCH 6/9] some newver/oldver logics --- parity/main.rs | 11 +++++++++++ parity/upgrade.rs | 5 +++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index b605a9dd4..d625b9ef7 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -780,6 +780,17 @@ fn die_with_io_error(e: std::io::Error) -> ! { } fn main() { + match ::upgrade::upgrade() { + Ok(upgrades_applied) => { + if upgrades_applied > 0 { + println!("Executed {} upgrade scripts - ok", upgrades_applied); + } + }, + Err(e) => { + die!("Error upgrading parity data: {:?}", e); + } + } + Configuration::parse().execute(); } diff --git a/parity/upgrade.rs b/parity/upgrade.rs index 50861fa91..0b41b5892 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -18,11 +18,11 @@ use semver::Version; use std::collections::*; -use std::path::*; use std::fs::File; use std::env; use std::io::{Read, Write}; +#[derive(Debug)] pub enum Error { CannotLockVersionFile, CannotUpdateVersionFile, @@ -61,6 +61,7 @@ impl UpgradeKey { // dummy upgrade (remove when the first one is in) fn dummy_upgrade() -> Result<(), Error> { + println!("Adding ver.lock"); Ok(()) } @@ -68,7 +69,7 @@ fn push_updrades(upgrades: &mut UpgradeList) { // dummy upgrade (remove when the first one is in) upgrades.insert( - UpgradeKey { old_version: Version::parse("1.0.0").unwrap(), new_version: Version::parse("99.99.0").unwrap() }, + UpgradeKey { old_version: Version::parse("0.9.0").unwrap(), new_version: Version::parse("1.0.0").unwrap() }, dummy_upgrade); } From 4bfbb56701b48115bdb1cf797b974fbe73a777f8 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 11 Apr 2016 11:36:39 +0200 Subject: [PATCH 7/9] added explanatory comments --- ethcore/src/trace/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index c63f43f23..2a5bda6c5 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -135,6 +135,7 @@ impl Tracer for ExecutiveTracer { fn trace_call(&mut self, call: Option, gas_used: U256, output: Option, depth: usize, subs: Vec, delegate_call: bool) { + // don't trace if it's DELEGATECALL or CALLCODE. if delegate_call { return; } @@ -166,6 +167,7 @@ impl Tracer for ExecutiveTracer { } fn trace_failed_call(&mut self, call: Option, depth: usize, subs: Vec, delegate_call: bool) { + // don't trace if it's DELEGATECALL or CALLCODE. if delegate_call { return; } From 8ecbb53e99133d89c7046efd0ab6c309278744d4 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 12 Apr 2016 06:19:15 +0300 Subject: [PATCH 8/9] reducing code --- parity/upgrade.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/parity/upgrade.rs b/parity/upgrade.rs index 0b41b5892..c9c98e174 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -97,23 +97,19 @@ fn with_locked_version(script: F) -> Result path.push(".parity"); path.push("ver.lock"); - let version: Option = { - match File::open(&path) { - Ok(mut file) => { + let version = + File::open(&path).ok().and_then(|ref mut file| + { let mut version_string = String::new(); - match file.read_to_string(&mut version_string) { - Ok(_) => Some(Version::parse(&version_string).unwrap()), - Err(_) => None - } - }, - Err(_) => None - } - }; - let effective_version = version.unwrap_or_else(|| Version::parse("0.9.0").unwrap()); + file.read_to_string(&mut version_string) + .ok() + .and_then(|_| Version::parse(&version_string).ok()) + }) + .unwrap_or_else(|| Version::parse("0.9.0").unwrap()); let script_result = { let mut lock = try!(File::create(&path).map_err(|_| Error::CannotLockVersionFile)); - let result = script(&effective_version); + let result = script(&version); let written_version = Version::parse(CURRENT_VERSION).unwrap(); try!(lock.write_all(written_version.to_string().as_bytes()).map_err(|_| Error::CannotUpdateVersionFile)); From 14241c8d14f8b0af1ca45ee8456a8146a5b9000e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 12 Apr 2016 13:05:13 +0300 Subject: [PATCH 9/9] line breaks --- ipc/rpc/src/interface.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ipc/rpc/src/interface.rs b/ipc/rpc/src/interface.rs index 247b5339b..dd52ce319 100644 --- a/ipc/rpc/src/interface.rs +++ b/ipc/rpc/src/interface.rs @@ -30,9 +30,11 @@ pub trait IpcConfig { fn api_version() -> Version { Version::parse("1.0.0").unwrap() } + fn protocol_version() -> Version { Version::parse("1.0.0").unwrap() } + fn handshake(handshake: &Handshake) -> bool { handshake.protocol_version == Self::protocol_version() && handshake.api_version == Self::api_version()