Output stored for calls.

This commit is contained in:
Gav Wood 2016-03-19 18:37:55 +01:00
parent bd7cd68c32
commit 7d93fa2533
3 changed files with 34 additions and 22 deletions

View File

@ -104,7 +104,7 @@ impl<'a> Executive<'a> {
} }
/// Creates `Externalities` from `Executive`. /// Creates `Externalities` from `Executive`.
pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { 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) Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output)
} }
@ -249,15 +249,17 @@ impl<'a> Executive<'a> {
// part of substate that may be reverted // part of substate that may be reverted
let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some());
let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(&params), self.depth)); let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(&params), self.depth));
let mut trace_output = trace_info.as_ref().map(|_| vec![]);
let res = { let res = {
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()))
}; };
if let Some((TraceAction::Call(ref mut c), _)) = trace_info { if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, vec![])); if let Some(output) = trace_output {
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, output));
}
} }
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);

View File

@ -23,12 +23,12 @@ use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult};
use substate::*; use substate::*;
/// Policy for handling output data on `RETURN` opcode. /// Policy for handling output data on `RETURN` opcode.
pub enum OutputPolicy<'a> { pub enum OutputPolicy<'a, 'b> {
/// Return reference to fixed sized output. /// Return reference to fixed sized output.
/// Used for message calls. /// Used for message calls.
Return(BytesRef<'a>), Return(BytesRef<'a>, Option<&'b mut Bytes>),
/// Init new contract as soon as `RETURN` is called. /// Init new contract as soon as `RETURN` is called.
InitContract InitContract,
} }
/// Transaction properties that externalities need to know about. /// Transaction properties that externalities need to know about.
@ -62,18 +62,19 @@ pub struct Externalities<'a> {
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
schedule: Schedule, schedule: Schedule,
output: OutputPolicy<'a> output: OutputPolicy<'a, 'a>
} }
impl<'a> Externalities<'a> { impl<'a> Externalities<'a> {
/// Basic `Externalities` constructor. /// Basic `Externalities` constructor.
pub fn new(state: &'a mut State, pub fn new(state: &'a mut State,
env_info: &'a EnvInfo, env_info: &'a EnvInfo,
engine: &'a Engine, engine: &'a Engine,
depth: usize, depth: usize,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
output: OutputPolicy<'a>) -> Self { output: OutputPolicy<'a, 'a>
) -> Self {
Externalities { Externalities {
state: state, state: state,
env_info: env_info, env_info: env_info,
@ -190,20 +191,29 @@ impl<'a> Ext for Externalities<'a> {
#[cfg_attr(feature="dev", allow(match_ref_pats))] #[cfg_attr(feature="dev", allow(match_ref_pats))]
fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> { fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> {
match &mut self.output { let handle_copy = |to: &mut Option<&mut Bytes>| {
&mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { to.as_mut().map(|b| **b = data.to_owned());
};
match self.output {
OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => {
handle_copy(copy);
let len = cmp::min(slice.len(), data.len()); let len = cmp::min(slice.len(), data.len());
ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); unsafe {
ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len);
}
Ok(*gas) Ok(*gas)
}, },
&mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => {
handle_copy(copy);
vec.clear(); vec.clear();
vec.reserve(data.len()); vec.reserve(data.len());
ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); unsafe {
vec.set_len(data.len()); ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len());
vec.set_len(data.len());
}
Ok(*gas) Ok(*gas)
}, },
&mut OutputPolicy::InitContract => { OutputPolicy::InitContract => {
let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
if return_cost > *gas { if return_cost > *gas {
return match self.schedule.exceptional_failed_code_deposit { return match self.schedule.exceptional_failed_code_deposit {

View File

@ -239,7 +239,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
0, 0,
OriginInfo::from(&params), OriginInfo::from(&params),
&mut substate, &mut substate,
OutputPolicy::Return(BytesRef::Flexible(&mut output)), OutputPolicy::Return(&mut BytesRef::Flexible(&mut output)),
params.address.clone() params.address.clone()
); );
let evm = engine.vm_factory().create(); let evm = engine.vm_factory().create();