From f75fb6a59faae7f6d7665153de4d4fbcdc2c8ccf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 11:33:36 +0100 Subject: [PATCH 1/5] Create transaction tracing test. --- ethcore/src/evm/factory.rs | 12 +++++------ ethcore/src/executive.rs | 2 ++ ethcore/src/state.rs | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/ethcore/src/evm/factory.rs b/ethcore/src/evm/factory.rs index 4a9bd38ba..65add0050 100644 --- a/ethcore/src/evm/factory.rs +++ b/ethcore/src/evm/factory.rs @@ -25,7 +25,7 @@ use evm::Evm; /// Type of EVM to use. pub enum VMType { /// JIT EVM - #[cfg(feature="jit")] + #[cfg(feature = "jit")] Jit, /// RUST EVM Interpreter @@ -52,13 +52,13 @@ impl fmt::Display for VMType { #[cfg(feature = "json-tests")] impl VMType { /// Return all possible VMs (JIT, Interpreter) - #[cfg(feature="jit")] + #[cfg(feature = "jit")] pub fn all() -> Vec { vec![VMType::Jit, VMType::Interpreter] } /// Return all possible VMs (Interpreter) - #[cfg(not(feature="jit"))] + #[cfg(not(feature = "jit"))] pub fn all() -> Vec { vec![VMType::Interpreter] } @@ -66,12 +66,12 @@ impl VMType { /// Evm factory. Creates appropriate Evm. pub struct Factory { - evm : VMType + evm: VMType } impl Factory { /// Create fresh instance of VM - #[cfg(feature="jit")] + #[cfg(feature = "jit")] pub fn create(&self) -> Box { match self.evm { VMType::Jit => { @@ -84,7 +84,7 @@ impl Factory { } /// Create fresh instance of VM - #[cfg(not(feature="jit"))] + #[cfg(not(feature = "jit"))] pub fn create(&self) -> Box { match self.evm { VMType::Interpreter => { diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 2421150e5..49cea6f23 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -310,6 +310,8 @@ impl<'a> Executive<'a> { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, output)); } } + + trace!(target: "executive", "trace_info={:?}", trace_info); self.enact_result(&res, substate, unconfirmed_substate, trace_info); res diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index cad29b678..2f64401d2 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -349,6 +349,48 @@ use util::rlp::*; use account::*; use tests::helpers::*; use devtools::*; +use evm::factory::*; +use env_info::*; +use transaction::*; +use util::log::init_log; +use trace::*; + +#[test] +fn should_apply_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("601080600c6000396000f3006000355415600957005b60203560003555").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!(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])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} #[test] fn code_from_database() { From d2d5806e9b8df01aad9336da950cb6f4102b6b4a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 12:04:31 +0100 Subject: [PATCH 2/5] Test for failed create transactions, failed actions are logged as such. --- ethcore/src/executive.rs | 13 +++++++------ ethcore/src/state.rs | 38 ++++++++++++++++++++++++++++++++++++++ ethcore/src/substate.rs | 24 ++++++++++++++++-------- 3 files changed, 61 insertions(+), 14 deletions(-) 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); } } From 5afd32dd842e682c4aa0a37013d80f2116f70da8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 12:09:55 +0100 Subject: [PATCH 3/5] Minor tweaks. --- ethcore/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index ef64ebbbe..6135528c0 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -420,7 +420,7 @@ fn should_trace_failed_create_transaction() { from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), value: x!(100), gas: x!(78792), - init: FromHex::from_hex("5b600056").unwrap(), + init: vec![91, 96, 0, 86], result: None }), subs: vec![] From 6ac350a9960a5f701dc722402e84a1ba6cf8aeb2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 16:24:19 +0100 Subject: [PATCH 4/5] Tests for lots more configurations. --- ethcore/src/executive.rs | 10 +- ethcore/src/externalities.rs | 16 +- ethcore/src/state.rs | 307 +++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 13 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 7ae43ff0a..e4d0650d0 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -260,16 +260,14 @@ 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 { - if let Some(output) = trace_output { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, output)); - } + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: qed"))); } - trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); - trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); + trace!(target: "executive", "sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); + trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); self.enact_result(&res, substate, unconfirmed_substate, trace_info); - trace!("exec: new substate={:?}\n", substate); + trace!(target: "executive", "enacted: substate={:?}\n", substate); res } else { // otherwise, nothing diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index a6f7e4f36..3f9d4ff08 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -153,13 +153,15 @@ impl<'a> Ext for Externalities<'a> { } fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - output: &mut [u8]) -> MessageCallResult { + gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, + output: &mut [u8] + ) -> MessageCallResult { + trace!(target: "externalities", "call"); let mut params = ActionParams { sender: sender_address.clone(), diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 6135528c0..b5b312076 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -429,6 +429,313 @@ fn should_trace_failed_create_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_trace_call_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::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("6000").unwrap()); + 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::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + + +#[test] +fn should_trace_failed_call_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::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("5b600056").unwrap()); + 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::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: None + }), + subs: vec![] + }); + + println!("trace: {:?}", result.trace); + + assert_eq!(result.trace, expected_trace); +} +#[test] +fn should_trace_call_with_subcall_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::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + 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::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(69), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_subcall_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::Call(x!(0xa)), + value: x!(100), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("5b600056").unwrap()); + 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::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(79000), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: None + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_call_with_subcall_with_subcall_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::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); + state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); + 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::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(135), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: Some((x!(69), vec![])) + }), + subs: vec![Trace { + depth: 2, + action: TraceAction::Call(TraceCall { + from: x!(0xb), + to: x!(0xc), + value: x!(0), + gas: x!(78868), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_subcall_with_subcall_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::Call(x!(0xa)), + value: x!(100), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); + state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); + 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::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(79000), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: None + }), + subs: vec![Trace { + depth: 2, + action: TraceAction::Call(TraceCall { + from: x!(0xb), + to: x!(0xc), + value: x!(0), + gas: x!(78868), + input: vec![], + result: Some((x!(3), vec![])), + }), + subs: vec![] + }] + }] + }); + + assert_eq!(result.trace, expected_trace); +} #[test] fn code_from_database() { From c2933e005ab4d011452c81e77a98c130ac0de323 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 17:51:22 +0100 Subject: [PATCH 5/5] Tests for not tracking builtin calls. --- ethcore/src/state.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index b5b312076..78084e6db 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -351,6 +351,7 @@ use tests::helpers::*; use devtools::*; use evm::factory::*; use env_info::*; +use spec::*; use transaction::*; use util::log::init_log; use trace::*; @@ -468,6 +469,68 @@ fn should_trace_call_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_not_trace_call_transaction_to_builtin() { + 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 = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0x1)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + assert_eq!(result.trace, None); +} + +#[test] +fn should_not_trace_subcall_transaction_to_builtin() { + 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 = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(28061), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} #[test] fn should_trace_failed_call_transaction() {