Remove pass-by-reference return data value from executive (#9211)

* Remove pass-by-reference return data value from executive

* Fix tests

* Fix a missing test output

* typo: wasm_activation_test

* Tracing change in output

* json_tests: fix compile

* typo: 0..32 -> ..32 to keep it consistent with other occurance

* Fix tests
This commit is contained in:
Wei Tang 2018-08-14 05:27:13 +08:00 committed by GitHub
parent 9c595aff95
commit ff716e7799
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 137 additions and 122 deletions

View File

@ -45,7 +45,7 @@ impl Finalize for Result<GasLeft> {
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> { fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> {
match self { match self {
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }), Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }),
Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, &data, apply_state).map(|gas_left| FinalizationResult { Ok(GasLeft::NeedsReturn { gas_left, data, apply_state }) => ext.ret(&gas_left, &data, apply_state).map(|gas_left| FinalizationResult {
gas_left: gas_left, gas_left: gas_left,
apply_state: apply_state, apply_state: apply_state,
return_data: data, return_data: data,

View File

@ -523,20 +523,25 @@ impl<Cost: CostType> Interpreter<Cost> {
} }
let call_result = { let call_result = {
// we need to write and read from memory in the same time let input = self.mem.read_slice(in_off, in_size);
// and we don't want to copy ext.call(&call_gas.as_u256(), sender_address, receive_address, value, input, &code_address, call_type)
let input = unsafe { ::std::mem::transmute(self.mem.read_slice(in_off, in_size)) };
let output = self.mem.writeable_slice(out_off, out_size);
ext.call(&call_gas.as_u256(), sender_address, receive_address, value, input, &code_address, output, call_type)
}; };
let output = self.mem.writeable_slice(out_off, out_size);
return match call_result { return match call_result {
MessageCallResult::Success(gas_left, data) => { MessageCallResult::Success(gas_left, data) => {
let len = cmp::min(output.len(), data.len());
(&mut output[..len]).copy_from_slice(&data[..len]);
self.stack.push(U256::one()); self.stack.push(U256::one());
self.return_data = data; self.return_data = data;
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one"))) Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one")))
}, },
MessageCallResult::Reverted(gas_left, data) => { MessageCallResult::Reverted(gas_left, data) => {
let len = cmp::min(output.len(), data.len());
(&mut output[..len]).copy_from_slice(&data[..len]);
self.stack.push(U256::zero()); self.stack.push(U256::zero());
self.return_data = data; self.return_data = data;
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one"))) Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one")))

View File

@ -19,7 +19,7 @@
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use ethereum_types::{H256, U256, H160}; use ethereum_types::{H256, U256, H160};
use {factory, journaldb, trie, kvdb_memorydb, bytes}; use {factory, journaldb, trie, kvdb_memorydb};
use kvdb::{self, KeyValueDB}; use kvdb::{self, KeyValueDB};
use {state, state_db, client, executive, trace, transaction, db, spec, pod_state, log_entry, receipt}; use {state, state_db, client, executive, trace, transaction, db, spec, pod_state, log_entry, receipt};
use factory::Factories; use factory::Factories;
@ -183,14 +183,12 @@ impl<'a> EvmTestClient<'a> {
gas_limit: *genesis.gas_limit(), gas_limit: *genesis.gas_limit(),
}; };
let mut substate = state::Substate::new(); let mut substate = state::Substate::new();
let mut output = vec![];
let machine = self.spec.engine.machine(); let machine = self.spec.engine.machine();
let schedule = machine.schedule(info.number); let schedule = machine.schedule(info.number);
let mut executive = executive::Executive::new(&mut self.state, &info, &machine, &schedule); let mut executive = executive::Executive::new(&mut self.state, &info, &machine, &schedule);
executive.call( executive.call(
params, params,
&mut substate, &mut substate,
bytes::BytesRef::Flexible(&mut output),
tracer, tracer,
vm_tracer, vm_tracer,
).map_err(EvmTestError::Evm) ).map_err(EvmTestError::Evm)

View File

@ -204,7 +204,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
&'any mut self, &'any mut self,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'any mut Substate, substate: &'any mut Substate,
output: OutputPolicy<'any, 'any>, output: OutputPolicy,
tracer: &'any mut T, tracer: &'any mut T,
vm_tracer: &'any mut V, vm_tracer: &'any mut V,
static_call: bool, static_call: bool,
@ -312,8 +312,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
call_type: CallType::None, call_type: CallType::None,
params_type: vm::ParamsType::Embedded, params_type: vm::ParamsType::Embedded,
}; };
let mut out = if output_from_create { Some(vec![]) } else { None }; let res = self.create(params, &mut substate, &mut tracer, &mut vm_tracer);
(self.create(params, &mut substate, &mut out, &mut tracer, &mut vm_tracer), out.unwrap_or_else(Vec::new)) let out = match &res {
Ok(res) if output_from_create => res.return_data.to_vec(),
_ => Vec::new(),
};
(res, out)
}, },
Action::Call(ref address) => { Action::Call(ref address) => {
let params = ActionParams { let params = ActionParams {
@ -330,8 +334,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
call_type: CallType::Call, call_type: CallType::Call,
params_type: vm::ParamsType::Separate, params_type: vm::ParamsType::Separate,
}; };
let mut out = vec![]; let res = self.call(params, &mut substate, &mut tracer, &mut vm_tracer);
(self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer, &mut vm_tracer), out) let out = match &res {
Ok(res) => res.return_data.to_vec(),
_ => Vec::new(),
};
(res, out)
} }
}; };
@ -382,7 +390,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
&mut self, &mut self,
params: ActionParams, params: ActionParams,
substate: &mut Substate, substate: &mut Substate,
mut output: BytesRef,
tracer: &mut T, tracer: &mut T,
vm_tracer: &mut V vm_tracer: &mut V
) -> vm::Result<FinalizationResult> where T: Tracer, V: VMTracer { ) -> vm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
@ -432,7 +439,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
Err(evm_err) Err(evm_err)
} else { } else {
self.state.discard_checkpoint(); self.state.discard_checkpoint();
output.write(0, &builtin_out_buffer);
// Trace only top level calls and calls with balance transfer to builtins. The reason why we don't // Trace only top level calls and calls with balance transfer to builtins. The reason why we don't
// trace all internal calls to builtin contracts is that memcpy (IDENTITY) is a heavily used // trace all internal calls to builtin contracts is that memcpy (IDENTITY) is a heavily used
@ -444,7 +450,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
if self.depth == 0 || is_transferred { if self.depth == 0 || is_transferred {
let mut trace_output = tracer.prepare_trace_output(); let mut trace_output = tracer.prepare_trace_output();
if let Some(out) = trace_output.as_mut() { if let Some(out) = trace_output.as_mut() {
*out = output.to_owned(); *out = builtin_out_buffer.clone();
} }
tracer.trace_call( tracer.trace_call(
@ -485,7 +491,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed")); let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed"));
let res = { let res = {
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return, &mut subtracer, &mut subvmtracer)
}; };
vm_tracer.done_subtrace(subvmtracer); vm_tracer.done_subtrace(subvmtracer);
@ -494,12 +500,15 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let traces = subtracer.drain(); let traces = subtracer.drain();
match res { match res {
Ok(ref res) if res.apply_state => tracer.trace_call( Ok(ref res) if res.apply_state => {
trace_output.as_mut().map(|d| *d = res.return_data.to_vec());
tracer.trace_call(
trace_info, trace_info,
gas - res.gas_left, gas - res.gas_left,
trace_output, trace_output,
traces traces
), );
},
Ok(_) => tracer.trace_failed_call(trace_info, traces, vm::Error::Reverted.into()), Ok(_) => tracer.trace_failed_call(trace_info, traces, vm::Error::Reverted.into()),
Err(ref e) => tracer.trace_failed_call(trace_info, traces, e.into()), Err(ref e) => tracer.trace_failed_call(trace_info, traces, e.into()),
}; };
@ -530,7 +539,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
&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<FinalizationResult> where T: Tracer, V: VMTracer { ) -> vm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
@ -579,7 +587,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let res = self.exec_vm( let res = self.exec_vm(
params, params,
&mut unconfirmed_substate, &mut unconfirmed_substate,
OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), OutputPolicy::InitContract,
&mut subtracer, &mut subtracer,
&mut subvmtracer &mut subvmtracer
); );
@ -587,13 +595,16 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
vm_tracer.done_subtrace(subvmtracer); vm_tracer.done_subtrace(subvmtracer);
match res { match res {
Ok(ref res) if res.apply_state => tracer.trace_create( Ok(ref res) if res.apply_state => {
trace_output.as_mut().map(|trace| *trace = res.return_data.to_vec());
tracer.trace_create(
trace_info, trace_info,
gas - res.gas_left, gas - res.gas_left,
trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)), trace_output,
created, created,
subtracer.drain() subtracer.drain()
), );
}
Ok(_) => tracer.trace_failed_create(trace_info, subtracer.drain(), vm::Error::Reverted.into()), Ok(_) => tracer.trace_failed_create(trace_info, subtracer.drain(), vm::Error::Reverted.into()),
Err(ref e) => tracer.trace_failed_create(trace_info, subtracer.drain(), e.into()) Err(ref e) => tracer.trace_failed_create(trace_info, subtracer.drain(), e.into())
}; };
@ -715,7 +726,6 @@ mod tests {
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use super::*; use super::*;
use ethereum_types::{H256, U256, U512, Address}; use ethereum_types::{H256, U256, U512, Address};
use bytes::BytesRef;
use vm::{ActionParams, ActionValue, CallType, EnvInfo, CreateContractAddress}; use vm::{ActionParams, ActionValue, CallType, EnvInfo, CreateContractAddress};
use evm::{Factory, VMType}; use evm::{Factory, VMType};
use error::ExecutionError; use error::ExecutionError;
@ -766,7 +776,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(79_975)); assert_eq!(gas_left, U256::from(79_975));
@ -824,7 +834,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(62_976)); assert_eq!(gas_left, U256::from(62_976));
@ -868,8 +878,7 @@ mod tests {
let mut vm_tracer = ExecutiveVMTracer::toplevel(); let mut vm_tracer = ExecutiveVMTracer::toplevel();
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, &mut tracer, &mut vm_tracer).unwrap();
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap();
assert_eq!(tracer.drain(), vec![FlatTrace { assert_eq!(tracer.drain(), vec![FlatTrace {
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
@ -896,7 +905,7 @@ mod tests {
call_type: CallType::Call call_type: CallType::Call
}), result: trace::Res::Call(trace::CallResult { }), result: trace::Res::Call(trace::CallResult {
gas_used: 600.into(), gas_used: 600.into(),
output: vec![] output: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 17, 133, 165, 197, 233, 252, 84, 97, 40, 8, 151, 126, 232, 245, 72, 178, 37, 141, 49]
}), }),
subtraces: 0, subtraces: 0,
trace_address: vec![0].into_iter().collect(), trace_address: vec![0].into_iter().collect(),
@ -954,8 +963,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, &mut tracer, &mut vm_tracer).unwrap()
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(44_752)); assert_eq!(gas_left, U256::from(44_752));
@ -1071,8 +1079,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, &mut tracer, &mut vm_tracer).unwrap()
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(62967)); assert_eq!(gas_left, U256::from(62967));
@ -1144,7 +1151,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap() ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(96_776)); assert_eq!(gas_left, U256::from(96_776));
@ -1230,7 +1237,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(62_976)); assert_eq!(gas_left, U256::from(62_976));
@ -1282,7 +1289,7 @@ mod tests {
{ {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap(); ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap();
} }
assert_eq!(substate.contracts_created.len(), 1); assert_eq!(substate.contracts_created.len(), 1);
@ -1343,7 +1350,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(73_237)); assert_eq!(gas_left, U256::from(73_237));
@ -1388,7 +1395,7 @@ mod tests {
let FinalizationResult { gas_left, .. } = { let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(59_870)); assert_eq!(gas_left, U256::from(59_870));
@ -1562,7 +1569,7 @@ mod tests {
let result = { let result = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer)
}; };
match result { match result {
@ -1595,10 +1602,11 @@ mod tests {
let mut substate = Substate::new(); let mut substate = Substate::new();
let mut output = [0u8; 14]; let mut output = [0u8; 14];
let FinalizationResult { gas_left: result, .. } = { let FinalizationResult { gas_left: result, return_data, .. } = {
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
(&mut output).copy_from_slice(&return_data[..(cmp::min(14, return_data.len()))]);
assert_eq!(result, U256::from(1)); assert_eq!(result, U256::from(1));
assert_eq!(output[..], returns[..]); assert_eq!(output[..], returns[..]);
@ -1638,11 +1646,12 @@ mod tests {
let machine = ::ethereum::new_kovan_wasm_test_machine(); let machine = ::ethereum::new_kovan_wasm_test_machine();
let mut output = [0u8; 20]; let mut output = [0u8; 20];
let FinalizationResult { gas_left: result, .. } = { let FinalizationResult { gas_left: result, return_data, .. } = {
let schedule = machine.schedule(info.number); let schedule = machine.schedule(info.number);
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.call(params.clone(), &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params.clone(), &mut Substate::new(), &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
(&mut output).copy_from_slice(&return_data[..(cmp::min(20, return_data.len()))]);
assert_eq!(result, U256::from(18433)); assert_eq!(result, U256::from(18433));
// Transaction successfully returned sender // Transaction successfully returned sender
@ -1652,11 +1661,12 @@ mod tests {
info.number = 1; info.number = 1;
let mut output = [0u8; 20]; let mut output = [0u8; 20];
let FinalizationResult { gas_left: result, .. } = { let FinalizationResult { gas_left: result, return_data, .. } = {
let schedule = machine.schedule(info.number); let schedule = machine.schedule(info.number);
let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let mut ex = Executive::new(&mut state, &info, &machine, &schedule);
ex.call(params, &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut Substate::new(), &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
(&mut output[..((cmp::min(20, return_data.len())))]).copy_from_slice(&return_data[..(cmp::min(20, return_data.len()))]);
assert_eq!(result, U256::from(20025)); assert_eq!(result, U256::from(20025));
// Since transaction errored due to wasm was not activated, result is just empty // Since transaction errored due to wasm was not activated, result is just empty

View File

@ -18,7 +18,7 @@
use std::cmp; use std::cmp;
use std::sync::Arc; use std::sync::Arc;
use ethereum_types::{H256, U256, Address}; use ethereum_types::{H256, U256, Address};
use bytes::{Bytes, BytesRef}; use bytes::Bytes;
use state::{Backend as StateBackend, State, Substate, CleanupMode}; use state::{Backend as StateBackend, State, Substate, CleanupMode};
use machine::EthereumMachine as Machine; use machine::EthereumMachine as Machine;
use executive::*; use executive::*;
@ -32,12 +32,12 @@ use transaction::UNSIGNED_SENDER;
use trace::{Tracer, VMTracer}; use trace::{Tracer, VMTracer};
/// Policy for handling output data on `RETURN` opcode. /// Policy for handling output data on `RETURN` opcode.
pub enum OutputPolicy<'a, 'b> { pub enum OutputPolicy {
/// Return reference to fixed sized output. /// Return reference to fixed sized output.
/// Used for message calls. /// Used for message calls.
Return(BytesRef<'a>, Option<&'b mut Bytes>), Return,
/// Init new contract as soon as `RETURN` is called. /// Init new contract as soon as `RETURN` is called.
InitContract(Option<&'b mut Bytes>), InitContract,
} }
/// Transaction properties that externalities need to know about. /// Transaction properties that externalities need to know about.
@ -71,7 +71,7 @@ pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> {
substate: &'a mut Substate, substate: &'a mut Substate,
machine: &'a Machine, machine: &'a Machine,
schedule: &'a Schedule, schedule: &'a Schedule,
output: OutputPolicy<'a, 'a>, output: OutputPolicy,
tracer: &'a mut T, tracer: &'a mut T,
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
static_flag: bool, static_flag: bool,
@ -89,7 +89,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
depth: usize, depth: usize,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
output: OutputPolicy<'a, 'a>, output: OutputPolicy,
tracer: &'a mut T, tracer: &'a mut T,
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
static_flag: bool, static_flag: bool,
@ -171,9 +171,12 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
params_type: vm::ParamsType::Separate, params_type: vm::ParamsType::Separate,
}; };
let mut output = H256::new();
let mut ex = Executive::new(self.state, self.env_info, self.machine, self.schedule); let mut ex = Executive::new(self.state, self.env_info, self.machine, self.schedule);
let r = ex.call(params, self.substate, BytesRef::Fixed(&mut output), self.tracer, self.vm_tracer); let r = ex.call(params, self.substate, self.tracer, self.vm_tracer);
let output = match &r {
Ok(ref r) => H256::from(&r.return_data[..32]),
_ => H256::new(),
};
trace!("ext: blockhash contract({}) -> {:?}({}) self.env_info.number={}\n", number, r, output, self.env_info.number); trace!("ext: blockhash contract({}) -> {:?}({}) self.env_info.number={}\n", number, r, output, self.env_info.number);
output output
} else { } else {
@ -194,7 +197,13 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
} }
} }
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address_scheme: CreateContractAddress) -> ContractCreateResult { fn create(
&mut self,
gas: &U256,
value: &U256,
code: &[u8],
address_scheme: CreateContractAddress
) -> ContractCreateResult {
// create new contract address // create new contract address
let (address, code_hash) = match self.state.nonce(&self.origin_info.address) { let (address, code_hash) = match self.state.nonce(&self.origin_info.address) {
Ok(nonce) => contract_address(address_scheme, &self.origin_info.address, &nonce, &code), Ok(nonce) => contract_address(address_scheme, &self.origin_info.address, &nonce, &code),
@ -231,7 +240,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag); let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag);
// TODO: handle internal error separately // TODO: handle internal error separately
match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) { match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
Ok(FinalizationResult{ gas_left, apply_state: true, .. }) => { Ok(FinalizationResult{ gas_left, apply_state: true, .. }) => {
self.substate.contracts_created.push(address.clone()); self.substate.contracts_created.push(address.clone());
ContractCreateResult::Created(address, gas_left) ContractCreateResult::Created(address, gas_left)
@ -243,14 +252,14 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
} }
} }
fn call(&mut self, fn call(
&mut self,
gas: &U256, gas: &U256,
sender_address: &Address, sender_address: &Address,
receive_address: &Address, receive_address: &Address,
value: Option<U256>, value: Option<U256>,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
output: &mut [u8],
call_type: CallType call_type: CallType
) -> MessageCallResult { ) -> MessageCallResult {
trace!(target: "externalities", "call"); trace!(target: "externalities", "call");
@ -284,7 +293,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag); let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag);
match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { match ex.call(params, self.substate, self.tracer, self.vm_tracer) {
Ok(FinalizationResult{ gas_left, return_data, apply_state: true }) => MessageCallResult::Success(gas_left, return_data), Ok(FinalizationResult{ gas_left, return_data, apply_state: true }) => MessageCallResult::Success(gas_left, return_data),
Ok(FinalizationResult{ gas_left, return_data, apply_state: false }) => MessageCallResult::Reverted(gas_left, return_data), Ok(FinalizationResult{ gas_left, return_data, apply_state: false }) => MessageCallResult::Reverted(gas_left, return_data),
_ => MessageCallResult::Failed _ => MessageCallResult::Failed
@ -303,27 +312,13 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
Ok(self.state.code_size(address)?) Ok(self.state.code_size(address)?)
} }
fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result<U256> fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result<U256>
where Self: Sized { where Self: Sized {
let handle_copy = |to: &mut Option<&mut Bytes>| {
to.as_mut().map(|b| **b = data.to_vec());
};
match self.output { match self.output {
OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { OutputPolicy::Return => {
handle_copy(copy);
let len = cmp::min(slice.len(), data.len());
(&mut slice[..len]).copy_from_slice(&data[..len]);
Ok(*gas) Ok(*gas)
}, },
OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { OutputPolicy::InitContract if apply_state => {
handle_copy(copy);
vec.clear();
vec.extend_from_slice(&*data);
Ok(*gas)
},
OutputPolicy::InitContract(ref mut copy) if apply_state => {
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 || data.len() > self.schedule.create_data_limit { if return_cost > *gas || data.len() > self.schedule.create_data_limit {
return match self.schedule.exceptional_failed_code_deposit { return match self.schedule.exceptional_failed_code_deposit {
@ -331,11 +326,10 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
false => Ok(*gas) false => Ok(*gas)
} }
} }
handle_copy(copy);
self.state.init_code(&self.origin_info.address, data.to_vec())?; self.state.init_code(&self.origin_info.address, data.to_vec())?;
Ok(*gas - return_cost) Ok(*gas - return_cost)
}, },
OutputPolicy::InitContract(_) => { OutputPolicy::InitContract => {
Ok(*gas) Ok(*gas)
}, },
} }
@ -479,7 +473,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
assert_eq!(ext.env_info().number, 100); assert_eq!(ext.env_info().number, 100);
} }
@ -491,7 +485,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap()); let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap());
@ -515,7 +509,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap()); let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap());
@ -530,9 +524,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
let mut output = vec![];
// this should panic because we have no balance on any account // this should panic because we have no balance on any account
ext.call( ext.call(
@ -542,7 +534,6 @@ mod tests {
Some("0000000000000000000000000000000000000000000000000000000000150000".parse::<U256>().unwrap()), Some("0000000000000000000000000000000000000000000000000000000000150000".parse::<U256>().unwrap()),
&[], &[],
&Address::new(), &Address::new(),
&mut output,
CallType::Call CallType::Call
); );
} }
@ -558,7 +549,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
{ {
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
ext.log(log_topics, &log_data).unwrap(); ext.log(log_topics, &log_data).unwrap();
} }
@ -575,7 +566,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
{ {
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
ext.suicide(refund_account).unwrap(); ext.suicide(refund_account).unwrap();
} }
@ -592,7 +583,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let address = { let address = {
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderAndNonce) { match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderAndNonce) {
ContractCreateResult::Created(address, _) => address, ContractCreateResult::Created(address, _) => address,
_ => panic!("Test create failed; expected Created, got Failed/Reverted."), _ => panic!("Test create failed; expected Created, got Failed/Reverted."),
@ -612,7 +603,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let address = { let address = {
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract, &mut tracer, &mut vm_tracer, false);
match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderSaltAndCodeHash(H256::default())) { match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderSaltAndCodeHash(H256::default())) {
ContractCreateResult::Created(address, _) => address, ContractCreateResult::Created(address, _) => address,

View File

@ -30,7 +30,7 @@ use test_helpers::get_temp_state;
use ethjson; use ethjson;
use trace::{Tracer, NoopTracer}; use trace::{Tracer, NoopTracer};
use trace::{VMTracer, NoopVMTracer}; use trace::{VMTracer, NoopVMTracer};
use bytes::{Bytes, BytesRef}; use bytes::Bytes;
use ethtrie; use ethtrie;
use rlp::RlpStream; use rlp::RlpStream;
use hash::keccak; use hash::keccak;
@ -90,7 +90,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
depth: usize, depth: usize,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
output: OutputPolicy<'a, 'a>, output: OutputPolicy,
address: Address, address: Address,
tracer: &'a mut T, tracer: &'a mut T,
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
@ -154,7 +154,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
value: Option<U256>, value: Option<U256>,
data: &[u8], data: &[u8],
_code_address: &Address, _code_address: &Address,
_output: &mut [u8],
_call_type: CallType _call_type: CallType
) -> MessageCallResult { ) -> MessageCallResult {
self.callcreates.push(CallCreate { self.callcreates.push(CallCreate {
@ -262,7 +261,6 @@ fn do_json_test_for<H: FnMut(&str, HookType)>(vm_type: &VMType, json_data: &[u8]
let mut substate = Substate::new(); let mut substate = Substate::new();
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut output = vec![];
let vm_factory = state.vm_factory(); let vm_factory = state.vm_factory();
// execute // execute
@ -276,7 +274,7 @@ fn do_json_test_for<H: FnMut(&str, HookType)>(vm_type: &VMType, json_data: &[u8]
0, 0,
OriginInfo::from(&params), OriginInfo::from(&params),
&mut substate, &mut substate,
OutputPolicy::Return(BytesRef::Flexible(&mut output), None), OutputPolicy::Return,
params.address.clone(), params.address.clone(),
&mut tracer, &mut tracer,
&mut vm_tracer, &mut vm_tracer,
@ -288,6 +286,11 @@ fn do_json_test_for<H: FnMut(&str, HookType)>(vm_type: &VMType, json_data: &[u8]
(res.finalize(ex), callcreates) (res.finalize(ex), callcreates)
}; };
let output = match &res {
Ok(res) => res.return_data.to_vec(),
Err(_) => Vec::new(),
};
let log_hash = { let log_hash = {
let mut rlp = RlpStream::new_list(substate.logs.len()); let mut rlp = RlpStream::new_list(substate.logs.len());
for l in &substate.logs { for l in &substate.logs {

View File

@ -33,7 +33,6 @@ use transaction::{self, SYSTEM_ADDRESS, UnverifiedTransaction, SignedTransaction
use tx_filter::TransactionFilter; use tx_filter::TransactionFilter;
use ethereum_types::{U256, Address}; use ethereum_types::{U256, Address};
use bytes::BytesRef;
use rlp::Rlp; use rlp::Rlp;
use vm::{CallType, ActionParams, ActionValue, ParamsType}; use vm::{CallType, ActionParams, ActionValue, ParamsType};
use vm::{EnvInfo, Schedule, CreateContractAddress}; use vm::{EnvInfo, Schedule, CreateContractAddress};
@ -148,10 +147,14 @@ impl EthereumMachine {
let schedule = self.schedule(env_info.number); let schedule = self.schedule(env_info.number);
let mut ex = Executive::new(&mut state, &env_info, self, &schedule); let mut ex = Executive::new(&mut state, &env_info, self, &schedule);
let mut substate = Substate::new(); let mut substate = Substate::new();
let mut output = Vec::new(); let res = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer);
if let Err(e) = ex.call(params, &mut substate, BytesRef::Flexible(&mut output), &mut NoopTracer, &mut NoopVMTracer) { let output = match res {
Ok(res) => res.return_data.to_vec(),
Err(e) => {
warn!("Encountered error on making system call: {}", e); warn!("Encountered error on making system call: {}", e);
Vec::new()
} }
};
Ok(output) Ok(output)
} }

View File

@ -655,7 +655,7 @@ impl Spec {
let machine = self.engine.machine(); let machine = self.engine.machine();
let schedule = machine.schedule(env_info.number); let schedule = machine.schedule(env_info.number);
let mut exec = Executive::new(&mut state, &env_info, &machine, &schedule); let mut exec = Executive::new(&mut state, &env_info, &machine, &schedule);
if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) { if let Err(e) = exec.create(params, &mut substate, &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

@ -29,7 +29,6 @@ use transaction::SYSTEM_ADDRESS;
use rustc_hex::FromHex; use rustc_hex::FromHex;
use ethereum_types::{H256, Address}; use ethereum_types::{H256, Address};
use bytes::BytesRef;
evm_test!{test_blockhash_eip210: test_blockhash_eip210_int} evm_test!{test_blockhash_eip210: test_blockhash_eip210_int}
fn test_blockhash_eip210(factory: Factory) { fn test_blockhash_eip210(factory: Factory) {
@ -65,8 +64,7 @@ fn test_blockhash_eip210(factory: Factory) {
let schedule = machine.schedule(env_info.number); let schedule = machine.schedule(env_info.number);
let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule); let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule);
let mut substate = Substate::new(); let mut substate = Substate::new();
let mut output = []; if let Err(e) = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on updating last hashes: {}", e); panic!("Encountered error on updating last hashes: {}", e);
} }
} }
@ -89,9 +87,12 @@ fn test_blockhash_eip210(factory: Factory) {
let schedule = machine.schedule(env_info.number); let schedule = machine.schedule(env_info.number);
let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule); let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule);
let mut substate = Substate::new(); let mut substate = Substate::new();
let mut output = H256::new(); let res = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer);
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) { let output = match res {
Ok(res) => H256::from(&res.return_data[..32]),
Err(e) => {
panic!("Encountered error on getting last hash: {}", e); panic!("Encountered error on getting last hash: {}", e);
} },
};
assert_eq!(output, 255.into()); assert_eq!(output, 255.into());
} }

View File

@ -101,7 +101,6 @@ pub trait Ext {
value: Option<U256>, value: Option<U256>,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
output: &mut [u8],
call_type: CallType call_type: CallType
) -> MessageCallResult; ) -> MessageCallResult;

View File

@ -155,7 +155,6 @@ impl Ext for FakeExt {
value: Option<U256>, value: Option<U256>,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
_output: &mut [u8],
_call_type: CallType _call_type: CallType
) -> MessageCallResult { ) -> MessageCallResult {

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::cmp;
use ethereum_types::{U256, H256, Address}; use ethereum_types::{U256, H256, Address};
use vm::{self, CallType}; use vm::{self, CallType};
use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap, TrapKind}; use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap, TrapKind};
@ -447,12 +448,14 @@ impl<'a> Runtime<'a> {
val, val,
&payload, &payload,
&address, &address,
&mut result[..],
call_type, call_type,
); );
match call_result { match call_result {
vm::MessageCallResult::Success(gas_left, _) => { vm::MessageCallResult::Success(gas_left, data) => {
let len = cmp::min(result.len(), data.len());
(&mut result[..len]).copy_from_slice(&data[..len]);
// cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas // cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas
self.gas_counter = self.gas_counter - self.gas_counter = self.gas_counter -
gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64 gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64
@ -461,7 +464,10 @@ impl<'a> Runtime<'a> {
self.memory.set(result_ptr, &result)?; self.memory.set(result_ptr, &result)?;
Ok(0i32.into()) Ok(0i32.into())
}, },
vm::MessageCallResult::Reverted(gas_left, _) => { vm::MessageCallResult::Reverted(gas_left, data) => {
let len = cmp::min(result.len(), data.len());
(&mut result[..len]).copy_from_slice(&data[..len]);
// cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas // cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas
self.gas_counter = self.gas_counter - self.gas_counter = self.gas_counter -
gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64 gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64