Rearchitected VM tracing to reflect existing tracing.
Should more or less work now.
This commit is contained in:
parent
d4a06b27ed
commit
86fdcabd0e
@ -40,9 +40,6 @@ pub enum MessageCallResult {
|
||||
Failed
|
||||
}
|
||||
|
||||
/// The trace function callback for VM tracing (*not* transaction tracing - that's different).
|
||||
pub type VMTraceFunctionBox = Box<FnMut(usize, u8, U256, U256) + Send>;
|
||||
|
||||
/// Externalities interface for EVMs
|
||||
pub trait Ext {
|
||||
/// Returns a value for given key.
|
||||
@ -109,6 +106,7 @@ pub trait Ext {
|
||||
/// Increments sstore refunds count by 1.
|
||||
fn inc_sstore_clears(&mut self);
|
||||
|
||||
/// Provide a tracer for VM tracing if the VM implementation supports it.
|
||||
fn vm_tracer(&mut self) -> Option<&mut VMTraceFunctionBox>;
|
||||
// TODO work out a way of not having this here but go via .
|
||||
/// Prepare to trace an operation. Passthrough for the VM trace.
|
||||
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256, _stack: &[U256]) {}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
///! Rust VM implementation
|
||||
|
||||
use common::*;
|
||||
use trace::VMTracer;
|
||||
use super::instructions as instructions;
|
||||
use super::instructions::Instruction;
|
||||
use std::marker::Copy;
|
||||
@ -69,6 +70,8 @@ trait Stack<T> {
|
||||
fn push(&mut self, elem: T);
|
||||
/// Get number of elements on Stack
|
||||
fn size(&self) -> usize;
|
||||
/// Returns all data on stack.
|
||||
fn peek_all(&mut self) -> &[T];
|
||||
}
|
||||
|
||||
struct VecStack<S> {
|
||||
@ -131,6 +134,10 @@ impl<S : fmt::Display> Stack<S> for VecStack<S> {
|
||||
fn size(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
|
||||
fn peek_all(&mut self) -> &[S] {
|
||||
&self.stack
|
||||
}
|
||||
}
|
||||
|
||||
trait Memory {
|
||||
@ -297,6 +304,10 @@ impl evm::Evm for Interpreter {
|
||||
|
||||
// Calculate gas cost
|
||||
let (gas_cost, mem_size) = try!(self.get_gas_cost_mem(ext, instruction, &mut mem, &stack));
|
||||
|
||||
// TODO: make compile-time removable if too much of a performance hit.
|
||||
ext.trace_prepare_execute(reader.position, instruction, &gas_cost, stack.peek_all());
|
||||
|
||||
try!(self.verify_gas(¤t_gas, &gas_cost));
|
||||
mem.expand(mem_size);
|
||||
current_gas = current_gas - gas_cost; //TODO: use operator -=
|
||||
@ -311,12 +322,6 @@ impl evm::Evm for Interpreter {
|
||||
);
|
||||
});
|
||||
|
||||
// Call trace
|
||||
// TODO: allow to be disabled at build time for max speed
|
||||
if let Some(ref mut trace_instruction) = ext.vm_tracer() {
|
||||
(*trace_instruction.deref_mut())(reader.position, instruction, gas_cost, current_gas);
|
||||
}
|
||||
|
||||
// Execute instruction
|
||||
let result = try!(self.exec_instruction(
|
||||
current_gas, ¶ms, ext, instruction, &mut reader, &mut mem, &mut stack
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
//! Just in time compiler execution environment.
|
||||
use common::*;
|
||||
use trace::VMTracer;
|
||||
use evmjit;
|
||||
use evm;
|
||||
|
||||
|
@ -30,6 +30,6 @@ mod jit;
|
||||
mod tests;
|
||||
|
||||
pub use self::evm::{Evm, Error, Result};
|
||||
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, VMTraceFunctionBox};
|
||||
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult};
|
||||
pub use self::factory::{Factory, VMType};
|
||||
pub use self::schedule::Schedule;
|
||||
|
@ -21,7 +21,7 @@ use engine::*;
|
||||
use evm::{self, Ext, Factory};
|
||||
use externalities::*;
|
||||
use substate::*;
|
||||
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer};
|
||||
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
||||
use crossbeam;
|
||||
|
||||
pub use types::executed::{Executed, ExecutionResult};
|
||||
@ -82,21 +82,40 @@ impl<'a> Executive<'a> {
|
||||
}
|
||||
|
||||
/// Creates `Externalities` from `Executive`.
|
||||
pub fn as_externalities<'_, T>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>, tracer: &'_ mut T) -> Externalities<'_, T> where T: Tracer {
|
||||
Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer)
|
||||
pub fn as_externalities<'_, T, V>(
|
||||
&'_ mut self,
|
||||
origin_info: OriginInfo,
|
||||
substate: &'_ mut Substate,
|
||||
output: OutputPolicy<'_, '_>,
|
||||
tracer: &'_ mut T,
|
||||
vm_tracer: &'_ mut V
|
||||
) -> Externalities<'_, T, V> where T: Tracer, V: VMTracer {
|
||||
Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer)
|
||||
}
|
||||
|
||||
/// This function should be used to execute transaction.
|
||||
pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, ExecutionError> {
|
||||
let check = options.check_nonce;
|
||||
match options.tracing {
|
||||
true => self.transact_with_tracer(t, check, ExecutiveTracer::default()),
|
||||
false => self.transact_with_tracer(t, check, NoopTracer),
|
||||
true => match options.vm_tracing {
|
||||
true => self.transact_with_tracer(t, check, ExecutiveTracer::default(), ExecutiveVMTracer::default()),
|
||||
false => self.transact_with_tracer(t, check, ExecutiveTracer::default(), NoopVMTracer),
|
||||
},
|
||||
false => match options.vm_tracing {
|
||||
true => self.transact_with_tracer(t, check, NoopTracer, ExecutiveVMTracer::default()),
|
||||
false => self.transact_with_tracer(t, check, NoopTracer, NoopVMTracer),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute transaction/call with tracing enabled
|
||||
pub fn transact_with_tracer<T>(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result<Executed, ExecutionError> where T: Tracer {
|
||||
pub fn transact_with_tracer<T, V>(
|
||||
&'a mut self,
|
||||
t: &SignedTransaction,
|
||||
check_nonce: bool,
|
||||
mut tracer: T,
|
||||
mut vm_tracer: V
|
||||
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
|
||||
let sender = try!(t.sender().map_err(|e| {
|
||||
let message = format!("Transaction malformed: {:?}", e);
|
||||
ExecutionError::TransactionMalformed(message)
|
||||
@ -156,7 +175,7 @@ impl<'a> Executive<'a> {
|
||||
code: Some(t.data.clone()),
|
||||
data: None,
|
||||
};
|
||||
(self.create(params, &mut substate, &mut tracer), vec![])
|
||||
(self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![])
|
||||
},
|
||||
Action::Call(ref address) => {
|
||||
let params = ActionParams {
|
||||
@ -172,20 +191,26 @@ impl<'a> Executive<'a> {
|
||||
};
|
||||
// TODO: move output upstream
|
||||
let mut out = vec![];
|
||||
(self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer), out)
|
||||
(self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer, &mut vm_tracer), out)
|
||||
}
|
||||
};
|
||||
|
||||
// finalize here!
|
||||
Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop())))
|
||||
Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop(), vm_tracer.drain())))
|
||||
}
|
||||
|
||||
fn exec_vm<T>(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, tracer: &mut T)
|
||||
-> evm::Result where T: Tracer {
|
||||
fn exec_vm<T, V>(
|
||||
&mut self,
|
||||
params: ActionParams,
|
||||
unconfirmed_substate: &mut Substate,
|
||||
output_policy: OutputPolicy,
|
||||
tracer: &mut T,
|
||||
vm_tracer: &mut V
|
||||
) -> evm::Result where T: Tracer, V: VMTracer {
|
||||
// Ordinary execution - keep VM in same thread
|
||||
if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 {
|
||||
let vm_factory = self.vm_factory;
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer);
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer);
|
||||
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
||||
return vm_factory.create().exec(params, &mut ext);
|
||||
}
|
||||
@ -195,7 +220,7 @@ impl<'a> Executive<'a> {
|
||||
// https://github.com/aturon/crossbeam/issues/16
|
||||
crossbeam::scope(|scope| {
|
||||
let vm_factory = self.vm_factory;
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer);
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer);
|
||||
|
||||
scope.spawn(move || {
|
||||
vm_factory.create().exec(params, &mut ext)
|
||||
@ -207,8 +232,14 @@ impl<'a> Executive<'a> {
|
||||
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||
/// Modifies the substate and the output.
|
||||
/// Returns either gas_left or `evm::Error`.
|
||||
pub fn call<T>(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef, tracer: &mut T)
|
||||
-> evm::Result where T: Tracer {
|
||||
pub fn call<T, V>(
|
||||
&mut self,
|
||||
params: ActionParams,
|
||||
substate: &mut Substate,
|
||||
mut output: BytesRef,
|
||||
tracer: &mut T,
|
||||
vm_tracer: &mut V
|
||||
) -> evm::Result where T: Tracer, V: VMTracer {
|
||||
// backup used in case of running out of gas
|
||||
self.state.snapshot();
|
||||
|
||||
@ -266,16 +297,22 @@ impl<'a> Executive<'a> {
|
||||
let trace_info = tracer.prepare_trace_call(¶ms);
|
||||
let mut trace_output = tracer.prepare_trace_output();
|
||||
let mut subtracer = tracer.subtracer();
|
||||
|
||||
let gas = params.gas;
|
||||
|
||||
if params.code.is_some() {
|
||||
// part of substate that may be reverted
|
||||
let mut unconfirmed_substate = Substate::new();
|
||||
|
||||
// TODO: make ActionParams pass by ref then avoid copy altogether.
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is protected by params.code.is_some condition"));
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer)
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
|
||||
trace!(target: "executive", "res={:?}", res);
|
||||
|
||||
let traces = subtracer.traces();
|
||||
@ -309,8 +346,13 @@ impl<'a> Executive<'a> {
|
||||
/// Creates contract with given contract params.
|
||||
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||
/// Modifies the substate.
|
||||
pub fn create<T>(&mut self, params: ActionParams, substate: &mut Substate, tracer: &mut T) -> evm::Result where T:
|
||||
Tracer {
|
||||
pub fn create<T, V>(
|
||||
&mut self,
|
||||
params: ActionParams,
|
||||
substate: &mut Substate,
|
||||
tracer: &mut T,
|
||||
vm_tracer: &mut V
|
||||
) -> evm::Result where T: Tracer, V: VMTracer {
|
||||
// backup used in case of running out of gas
|
||||
self.state.snapshot();
|
||||
|
||||
@ -332,10 +374,14 @@ impl<'a> Executive<'a> {
|
||||
let gas = params.gas;
|
||||
let created = params.address.clone();
|
||||
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(¶ms.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)
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
|
||||
match res {
|
||||
Ok(gas_left) => tracer.trace_create(
|
||||
trace_info,
|
||||
@ -353,7 +399,15 @@ impl<'a> Executive<'a> {
|
||||
}
|
||||
|
||||
/// Finalizes the transaction (does refunds and suicides).
|
||||
fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes, trace: Option<Trace>) -> ExecutionResult {
|
||||
fn finalize(
|
||||
&mut self,
|
||||
t: &SignedTransaction,
|
||||
substate: Substate,
|
||||
result: evm::Result,
|
||||
output: Bytes,
|
||||
trace: Option<Trace>,
|
||||
vm_trace: Option<VMTrace>
|
||||
) -> ExecutionResult {
|
||||
let schedule = self.engine.schedule(self.info);
|
||||
|
||||
// refunds from SSTORE nonzero -> zero
|
||||
@ -396,7 +450,7 @@ impl<'a> Executive<'a> {
|
||||
contracts_created: vec![],
|
||||
output: output,
|
||||
trace: trace,
|
||||
vm_trace: None,
|
||||
vm_trace: vm_trace,
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
@ -409,7 +463,7 @@ impl<'a> Executive<'a> {
|
||||
contracts_created: substate.contracts_created,
|
||||
output: output,
|
||||
trace: trace,
|
||||
vm_trace: None,
|
||||
vm_trace: vm_trace,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ use common::*;
|
||||
use state::*;
|
||||
use engine::*;
|
||||
use executive::*;
|
||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory, VMTraceFunctionBox};
|
||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory};
|
||||
use substate::*;
|
||||
use trace::Tracer;
|
||||
use trace::{Tracer, VMTracer};
|
||||
|
||||
/// Policy for handling output data on `RETURN` opcode.
|
||||
pub enum OutputPolicy<'a, 'b> {
|
||||
@ -55,7 +55,7 @@ impl OriginInfo {
|
||||
}
|
||||
|
||||
/// Implementation of evm Externalities.
|
||||
pub struct Externalities<'a, T> where T: 'a + Tracer {
|
||||
pub struct Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer {
|
||||
state: &'a mut State,
|
||||
env_info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
@ -66,10 +66,10 @@ pub struct Externalities<'a, T> where T: 'a + Tracer {
|
||||
schedule: Schedule,
|
||||
output: OutputPolicy<'a, 'a>,
|
||||
tracer: &'a mut T,
|
||||
vm_tracer: Option<VMTraceFunctionBox>,
|
||||
vm_tracer: &'a mut V,
|
||||
}
|
||||
|
||||
impl<'a, T> Externalities<'a, T> where T: 'a + Tracer {
|
||||
impl<'a, T, V> Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer {
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
/// Basic `Externalities` constructor.
|
||||
pub fn new(state: &'a mut State,
|
||||
@ -81,6 +81,7 @@ impl<'a, T> Externalities<'a, T> where T: 'a + Tracer {
|
||||
substate: &'a mut Substate,
|
||||
output: OutputPolicy<'a, 'a>,
|
||||
tracer: &'a mut T,
|
||||
vm_tracer: &'a mut V,
|
||||
) -> Self {
|
||||
Externalities {
|
||||
state: state,
|
||||
@ -93,40 +94,12 @@ impl<'a, T> Externalities<'a, T> where T: 'a + Tracer {
|
||||
schedule: engine.schedule(env_info),
|
||||
output: output,
|
||||
tracer: tracer,
|
||||
vm_tracer: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
/// Basic `Externalities` constructor.
|
||||
pub fn with_vm_tracer(state: &'a mut State,
|
||||
env_info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
vm_factory: &'a Factory,
|
||||
depth: usize,
|
||||
origin_info: OriginInfo,
|
||||
substate: &'a mut Substate,
|
||||
output: OutputPolicy<'a, 'a>,
|
||||
tracer: &'a mut T,
|
||||
vm_tracer: VMTraceFunctionBox,
|
||||
) -> Self {
|
||||
Externalities {
|
||||
state: state,
|
||||
env_info: env_info,
|
||||
engine: engine,
|
||||
vm_factory: vm_factory,
|
||||
depth: depth,
|
||||
origin_info: origin_info,
|
||||
substate: substate,
|
||||
schedule: engine.schedule(env_info),
|
||||
output: output,
|
||||
tracer: tracer,
|
||||
vm_tracer: Some(vm_tracer),
|
||||
vm_tracer: vm_tracer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer {
|
||||
impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer {
|
||||
fn storage_at(&self, key: &H256) -> H256 {
|
||||
self.state.storage_at(&self.origin_info.address, key)
|
||||
}
|
||||
@ -181,7 +154,7 @@ impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer {
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth);
|
||||
|
||||
// TODO: handle internal error separately
|
||||
match ex.create(params, self.substate, self.tracer) {
|
||||
match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
|
||||
Ok(gas_left) => {
|
||||
self.substate.contracts_created.push(address.clone());
|
||||
ContractCreateResult::Created(address, gas_left)
|
||||
@ -219,7 +192,7 @@ impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer {
|
||||
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth);
|
||||
|
||||
match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer) {
|
||||
match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) {
|
||||
Ok(gas_left) => MessageCallResult::Success(gas_left),
|
||||
_ => MessageCallResult::Failed
|
||||
}
|
||||
@ -316,7 +289,9 @@ impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer {
|
||||
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
|
||||
}
|
||||
|
||||
fn vm_tracer(&mut self) -> Option<&mut VMTraceFunctionBox> { self.vm_tracer.as_mut() }
|
||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256, stack: &[U256]) {
|
||||
self.vm_tracer.trace_prepare_execute(pc, instruction, gas_cost, stack);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
use util::{Bytes, Address, U256};
|
||||
use action_params::ActionParams;
|
||||
use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult};
|
||||
use trace::Tracer;
|
||||
use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation};
|
||||
use trace::{Tracer, VMTracer};
|
||||
|
||||
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
|
||||
#[derive(Default)]
|
||||
pub struct ExecutiveTracer {
|
||||
traces: Vec<Trace>
|
||||
traces: Vec<Trace>,
|
||||
}
|
||||
|
||||
impl Tracer for ExecutiveTracer {
|
||||
@ -105,3 +105,35 @@ impl Tracer for ExecutiveTracer {
|
||||
self.traces
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple VM tracer. Traces all operations. Ignores delegatecalls.
|
||||
#[derive(Default)]
|
||||
pub struct ExecutiveVMTracer {
|
||||
data: VMTrace,
|
||||
}
|
||||
|
||||
impl VMTracer for ExecutiveVMTracer {
|
||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256, stack: &[U256]) {
|
||||
self.data.operations.push(VMOperation {
|
||||
pc: pc,
|
||||
instruction: instruction,
|
||||
gas_cost: gas_cost.clone(),
|
||||
stack: stack.iter().cloned().collect(),
|
||||
})
|
||||
}
|
||||
|
||||
fn prepare_subtrace(&self, code: &Bytes) -> Self {
|
||||
ExecutiveVMTracer { data: VMTrace {
|
||||
parent_step: self.data.operations.len(),
|
||||
code: code.clone(),
|
||||
operations: vec![],
|
||||
subs: vec![],
|
||||
}}
|
||||
}
|
||||
|
||||
fn done_subtrace(&mut self, sub: Self) {
|
||||
self.data.subs.push(sub.data);
|
||||
}
|
||||
|
||||
fn drain(self) -> Option<VMTrace> { Some(self.data) }
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ pub use self::config::{Config, Switch};
|
||||
pub use self::db::TraceDB;
|
||||
pub use self::error::Error;
|
||||
pub use types::trace_types::trace::{Trace, VMTrace};
|
||||
pub use self::noop_tracer::NoopTracer;
|
||||
pub use self::executive_tracer::ExecutiveTracer;
|
||||
pub use self::noop_tracer::{NoopTracer, NoopVMTracer};
|
||||
pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer};
|
||||
pub use types::trace_types::filter::{Filter, AddressesFilter};
|
||||
pub use self::import::ImportRequest;
|
||||
pub use self::localized::LocalizedTrace;
|
||||
@ -91,13 +91,16 @@ pub trait Tracer: Send {
|
||||
/// Used by executive to build VM traces.
|
||||
pub trait VMTracer: Send {
|
||||
/// Trace the preparation to execute a single instruction.
|
||||
fn trace_prepare_execute(pc: usize, instruction: u8, gas_cost: &U256, stack: &Vec<U256>);
|
||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256, stack: &[U256]);
|
||||
|
||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||
fn subtracer(&self) -> Self where Self: Sized;
|
||||
fn prepare_subtrace(&self, code: &Bytes) -> Self where Self: Sized;
|
||||
|
||||
/// Consumes self and returns all VM traces.
|
||||
fn traces(self) -> Vec<VMTrace>;
|
||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||
fn done_subtrace(&mut self, sub: Self) where Self: Sized;
|
||||
|
||||
/// Consumes self and returns the VM trace.
|
||||
fn drain(self) -> Option<VMTrace>;
|
||||
}
|
||||
|
||||
/// `DbExtras` provides an interface to query extra data which is not stored in tracesdb,
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
use util::{Bytes, Address, U256};
|
||||
use action_params::ActionParams;
|
||||
use trace::Tracer;
|
||||
use trace::trace::{Trace, Call, Create};
|
||||
use trace::{Tracer, VMTracer};
|
||||
use trace::trace::{Trace, Call, Create, VMTrace};
|
||||
|
||||
/// Nonoperative tracer. Does not trace anything.
|
||||
pub struct NoopTracer;
|
||||
@ -63,3 +63,20 @@ impl Tracer for NoopTracer {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Nonoperative VM tracer. Does not trace anything.
|
||||
pub struct NoopVMTracer;
|
||||
|
||||
impl VMTracer for NoopVMTracer {
|
||||
/// Trace the preparation to execute a single instruction.
|
||||
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256, _stack: &[U256]) {}
|
||||
|
||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||
fn prepare_subtrace(&self, _code: &Bytes) -> Self { NoopVMTracer }
|
||||
|
||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||
fn done_subtrace(&mut self, _sub: Self) {}
|
||||
|
||||
/// Consumes self and returns all VM traces.
|
||||
fn drain(self) -> Option<VMTrace> { None }
|
||||
}
|
||||
|
@ -397,12 +397,11 @@ impl Decodable for VMOperation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Binary)]
|
||||
#[derive(Debug, Clone, PartialEq, Binary, Default)]
|
||||
/// A record of a full VM trace for a CALL/CREATE.
|
||||
pub struct VMTrace {
|
||||
/// The number of EVM execution environments active when this action happened; 0 if it's
|
||||
/// the outer action of the transaction.
|
||||
pub depth: usize,
|
||||
/// The step (i.e. index into operations) at which this trace corresponds.
|
||||
pub parent_step: usize,
|
||||
/// The code to be executed.
|
||||
pub code: Bytes,
|
||||
/// The operations executed.
|
||||
@ -415,7 +414,7 @@ pub struct VMTrace {
|
||||
impl Encodable for VMTrace {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(4);
|
||||
s.append(&self.depth);
|
||||
s.append(&self.parent_step);
|
||||
s.append(&self.code);
|
||||
s.append(&self.operations);
|
||||
s.append(&self.subs);
|
||||
@ -426,7 +425,7 @@ impl Decodable for VMTrace {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = VMTrace {
|
||||
depth: try!(d.val_at(0)),
|
||||
parent_step: try!(d.val_at(0)),
|
||||
code: try!(d.val_at(1)),
|
||||
operations: try!(d.val_at(2)),
|
||||
subs: try!(d.val_at(3)),
|
||||
|
Loading…
Reference in New Issue
Block a user