diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 26ef11ffb..fc29b1f10 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1131,7 +1131,9 @@ impl Client { T: trace::Tracer, V: trace::VMTracer, { - let options = options.dont_check_nonce(); + let options = options + .dont_check_nonce() + .save_output_from_contract(); let original_state = if state_diff { Some(state.clone()) } else { None }; let mut ret = Executive::new(state, env_info, engine).transact_virtual(transaction, options)?; @@ -2001,6 +2003,7 @@ impl ProvingBlockChainClient for Client { ) } + fn epoch_signal(&self, hash: H256) -> Option> { // pending transitions are never deleted, and do not contain // finality proofs by definition. diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 4da8568c2..c00046e0e 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -77,6 +77,8 @@ pub struct TransactOptions { pub vm_tracer: V, /// Check transaction nonce before execution. pub check_nonce: bool, + /// Records the output from init contract calls. + pub output_from_init_contract: bool, } impl TransactOptions { @@ -86,6 +88,7 @@ impl TransactOptions { tracer, vm_tracer, check_nonce: true, + output_from_init_contract: false, } } @@ -94,6 +97,12 @@ impl TransactOptions { self.check_nonce = false; self } + + /// Saves the output from contract creation. + pub fn save_output_from_contract(mut self) -> Self { + self.output_from_init_contract = true; + self + } } impl TransactOptions { @@ -103,6 +112,7 @@ impl TransactOptions { tracer: trace::ExecutiveTracer::default(), vm_tracer: trace::ExecutiveVMTracer::toplevel(), check_nonce: true, + output_from_init_contract: false, } } } @@ -114,6 +124,7 @@ impl TransactOptions { tracer: trace::ExecutiveTracer::default(), vm_tracer: trace::NoopVMTracer, check_nonce: true, + output_from_init_contract: false, } } } @@ -125,6 +136,7 @@ impl TransactOptions { tracer: trace::NoopTracer, vm_tracer: trace::ExecutiveVMTracer::toplevel(), check_nonce: true, + output_from_init_contract: false, } } } @@ -136,6 +148,7 @@ impl TransactOptions { tracer: trace::NoopTracer, vm_tracer: trace::NoopVMTracer, check_nonce: true, + output_from_init_contract: false, } } } @@ -204,7 +217,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result where T: Tracer, V: VMTracer, { - self.transact_with_tracer(t, options.check_nonce, options.tracer, options.vm_tracer) + self.transact_with_tracer(t, options.check_nonce, options.output_from_init_contract, options.tracer, options.vm_tracer) } /// Execute a transaction in a "virtual" context. @@ -229,6 +242,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { &'a mut self, t: &SignedTransaction, check_nonce: bool, + output_from_create: bool, mut tracer: T, mut vm_tracer: V ) -> Result where T: Tracer, V: VMTracer { @@ -297,7 +311,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { data: None, call_type: CallType::None, }; - (self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![]) + let mut out = if output_from_create { Some(vec![]) } else { None }; + (self.create(params, &mut substate, &mut out, &mut tracer, &mut vm_tracer), out.unwrap_or_else(Vec::new)) }, Action::Call(ref address) => { let params = ActionParams { @@ -490,6 +505,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { &mut self, params: ActionParams, substate: &mut Substate, + output: &mut Option, tracer: &mut T, vm_tracer: &mut V, ) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { @@ -531,7 +547,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed")); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer) }; vm_tracer.done_subtrace(subvmtracer); @@ -540,7 +556,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { Ok(ref res) => tracer.trace_create( trace_info, gas - res.gas_left, - trace_output, + trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)), created, subtracer.drain() ), @@ -701,7 +717,7 @@ mod tests { let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() + ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(79_975)); @@ -759,7 +775,7 @@ mod tests { let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() + ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -926,7 +942,7 @@ mod tests { let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap() + ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap() }; assert_eq!(gas_left, U256::from(96_776)); @@ -1011,7 +1027,7 @@ mod tests { let (gas_left, _) = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() + ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -1062,7 +1078,7 @@ mod tests { { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap(); + ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap(); } assert_eq!(substate.contracts_created.len(), 1); @@ -1335,7 +1351,7 @@ mod tests { let result = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) + ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) }; match result { diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 5054d4c08..5fc613844 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -224,7 +224,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag); // TODO: handle internal error separately - match ex.create(params, self.substate, self.tracer, self.vm_tracer) { + match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) { Ok((gas_left, _)) => { self.substate.contracts_created.push(address.clone()); ContractCreateResult::Created(address, gas_left) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 727b08584..a807384be 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -355,7 +355,7 @@ impl Spec { { let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref()); - if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) { + if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) { warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e); } } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 4539708ec..eb6deac23 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -212,7 +212,8 @@ pub fn check_proof( Err(_) => return ProvedExecution::BadProof, }; - match state.execute(env_info, engine, transaction, TransactOptions::with_no_tracing(), true) { + let options = TransactOptions::with_no_tracing().save_output_from_contract(); + match state.execute(env_info, engine, transaction, options, true) { Ok(executed) => ProvedExecution::Complete(executed), Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof, Err(e) => ProvedExecution::Failed(e), @@ -246,7 +247,7 @@ pub fn prove_transaction( Err(_) => return None, }; - let options = TransactOptions::with_no_tracing().dont_check_nonce(); + let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract(); match state.execute(env_info, engine, transaction, options, virt) { Err(ExecutionError::Internal(_)) => None, Err(e) => {