eth_call returns output of contract creations (#6420)

* eth_call returns output of contract creations

* Fix parameters order.

* Save outputs for light client as well.
This commit is contained in:
Tomasz Drwięga 2017-09-05 13:22:19 +02:00 committed by Gav Wood
parent c49beccadc
commit 7462a69583
5 changed files with 35 additions and 15 deletions

View File

@ -1131,7 +1131,9 @@ impl Client {
T: trace::Tracer, T: trace::Tracer,
V: trace::VMTracer, 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 original_state = if state_diff { Some(state.clone()) } else { None };
let mut ret = Executive::new(state, env_info, engine).transact_virtual(transaction, options)?; 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<Vec<u8>> { fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>> {
// pending transitions are never deleted, and do not contain // pending transitions are never deleted, and do not contain
// finality proofs by definition. // finality proofs by definition.

View File

@ -77,6 +77,8 @@ pub struct TransactOptions<T, V> {
pub vm_tracer: V, pub vm_tracer: V,
/// Check transaction nonce before execution. /// Check transaction nonce before execution.
pub check_nonce: bool, pub check_nonce: bool,
/// Records the output from init contract calls.
pub output_from_init_contract: bool,
} }
impl<T, V> TransactOptions<T, V> { impl<T, V> TransactOptions<T, V> {
@ -86,6 +88,7 @@ impl<T, V> TransactOptions<T, V> {
tracer, tracer,
vm_tracer, vm_tracer,
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
@ -94,6 +97,12 @@ impl<T, V> TransactOptions<T, V> {
self.check_nonce = false; self.check_nonce = false;
self 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<trace::ExecutiveTracer, trace::ExecutiveVMTracer> { impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
@ -103,6 +112,7 @@ impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
tracer: trace::ExecutiveTracer::default(), tracer: trace::ExecutiveTracer::default(),
vm_tracer: trace::ExecutiveVMTracer::toplevel(), vm_tracer: trace::ExecutiveVMTracer::toplevel(),
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -114,6 +124,7 @@ impl TransactOptions<trace::ExecutiveTracer, trace::NoopVMTracer> {
tracer: trace::ExecutiveTracer::default(), tracer: trace::ExecutiveTracer::default(),
vm_tracer: trace::NoopVMTracer, vm_tracer: trace::NoopVMTracer,
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -125,6 +136,7 @@ impl TransactOptions<trace::NoopTracer, trace::ExecutiveVMTracer> {
tracer: trace::NoopTracer, tracer: trace::NoopTracer,
vm_tracer: trace::ExecutiveVMTracer::toplevel(), vm_tracer: trace::ExecutiveVMTracer::toplevel(),
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -136,6 +148,7 @@ impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
tracer: trace::NoopTracer, tracer: trace::NoopTracer,
vm_tracer: trace::NoopVMTracer, vm_tracer: trace::NoopVMTracer,
check_nonce: true, 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<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>) pub fn transact<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>)
-> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer, -> Result<Executed, ExecutionError> 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. /// 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, &'a mut self,
t: &SignedTransaction, t: &SignedTransaction,
check_nonce: bool, check_nonce: bool,
output_from_create: bool,
mut tracer: T, mut tracer: T,
mut vm_tracer: V mut vm_tracer: V
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer { ) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
@ -297,7 +311,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
data: None, data: None,
call_type: CallType::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) => { Action::Call(ref address) => {
let params = ActionParams { let params = ActionParams {
@ -490,6 +505,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
&mut self, &mut self,
params: ActionParams, params: ActionParams,
substate: &mut Substate, substate: &mut Substate,
output: &mut Option<Bytes>,
tracer: &mut T, tracer: &mut T,
vm_tracer: &mut V, vm_tracer: &mut V,
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { ) -> 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 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 = { 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); 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( Ok(ref res) => tracer.trace_create(
trace_info, trace_info,
gas - res.gas_left, gas - res.gas_left,
trace_output, trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)),
created, created,
subtracer.drain() subtracer.drain()
), ),
@ -701,7 +717,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); 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)); assert_eq!(gas_left, U256::from(79_975));
@ -759,7 +775,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); 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)); assert_eq!(gas_left, U256::from(62_976));
@ -926,7 +942,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); 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)); assert_eq!(gas_left, U256::from(96_776));
@ -1011,7 +1027,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); 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)); assert_eq!(gas_left, U256::from(62_976));
@ -1062,7 +1078,7 @@ mod tests {
{ {
let mut ex = Executive::new(&mut state, &info, &engine); 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); assert_eq!(substate.contracts_created.len(), 1);
@ -1335,7 +1351,7 @@ mod tests {
let result = { let result = {
let mut ex = Executive::new(&mut state, &info, &engine); 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 { match result {

View File

@ -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); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
// TODO: handle internal error separately // 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, _)) => { Ok((gas_left, _)) => {
self.substate.contracts_created.push(address.clone()); self.substate.contracts_created.push(address.clone());
ContractCreateResult::Created(address, gas_left) ContractCreateResult::Created(address, gas_left)

View File

@ -355,7 +355,7 @@ impl Spec {
{ {
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref()); 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); warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
} }
} }

View File

@ -212,7 +212,8 @@ pub fn check_proof(
Err(_) => return ProvedExecution::BadProof, 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), Ok(executed) => ProvedExecution::Complete(executed),
Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof, Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof,
Err(e) => ProvedExecution::Failed(e), Err(e) => ProvedExecution::Failed(e),
@ -246,7 +247,7 @@ pub fn prove_transaction<H: AsHashDB + Send + Sync>(
Err(_) => return None, 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) { match state.execute(env_info, engine, transaction, options, virt) {
Err(ExecutionError::Internal(_)) => None, Err(ExecutionError::Internal(_)) => None,
Err(e) => { Err(e) => {