diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 49cea6f23..7ae43ff0a 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -306,11 +306,9 @@ impl<'a> Executive<'a> { }; if let Some((TraceAction::Create(ref mut c), _)) = trace_info { - if let Some(output) = trace_output { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, output)); - } + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, trace_output.expect("trace_info is Some: qed"))); } - + trace!(target: "executive", "trace_info={:?}", trace_info); self.enact_result(&res, substate, unconfirmed_substate, trace_info); @@ -349,6 +347,8 @@ 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(_) => { @@ -359,7 +359,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], contracts_created: vec![], - trace: None, + trace: trace, }) }, _ => { @@ -370,7 +370,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, - trace: substate.subtraces.and_then(|mut v| v.pop()), + trace: trace, }) }, } @@ -384,6 +384,7 @@ impl<'a> Executive<'a> { | Err(evm::Error::StackUnderflow {..}) | Err(evm::Error::OutOfStack {..}) => { self.state.revert_snapshot(); + substate.accrue_trace(un_substate.subtraces, maybe_info) }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 2f64401d2..ef64ebbbe 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -392,6 +392,44 @@ fn should_apply_create_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_trace_failed_create_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Create, + value: x!(100), + data: FromHex::from_hex("5b600056").unwrap(), + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + value: x!(100), + gas: x!(78792), + init: FromHex::from_hex("5b600056").unwrap(), + result: None + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + + #[test] fn code_from_database() { let a = Address::zero(); diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 0610bffb8..9d81badb9 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -49,19 +49,27 @@ impl Substate { } } - /// Merge secondary substate `s` into self, accruing each element correspondingly. + /// 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)>) { 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()); - 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: s.subtraces.expect("maybe_action is Some: so we must be tracing: qed"), - }); - } + self.accrue_trace(s.subtraces, maybe_info); } }