RPC endpoint for VM tracing and ser/de types ready.
This commit is contained in:
@@ -421,7 +421,7 @@ impl<V> Client<V> where V: Verifier {
|
||||
}
|
||||
|
||||
impl<V> BlockChainClient for Client<V> where V: Verifier {
|
||||
fn call(&self, t: &SignedTransaction) -> Result<Executed, ExecutionError> {
|
||||
fn call(&self, t: &SignedTransaction, vm_tracing: bool) -> Result<Executed, ExecutionError> {
|
||||
let header = self.block_header(BlockID::Latest).unwrap();
|
||||
let view = HeaderView::new(&header);
|
||||
let last_hashes = self.build_last_hashes(view.hash());
|
||||
@@ -444,7 +444,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
||||
// give the sender max balance
|
||||
state.sub_balance(&sender, &balance);
|
||||
state.add_balance(&sender, &U256::max_value());
|
||||
let options = TransactOptions { tracing: false, check_nonce: false };
|
||||
let options = TransactOptions { tracing: false, vm_tracing: vm_tracing, check_nonce: false };
|
||||
Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options)
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,8 @@ pub trait BlockChainClient : Sync + Send {
|
||||
fn try_seal(&self, block: LockedBlock, seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock>;
|
||||
|
||||
/// Makes a non-persistent transaction call.
|
||||
fn call(&self, t: &SignedTransaction) -> Result<Executed, ExecutionError>;
|
||||
// TODO: should be able to accept blockchain location for call.
|
||||
fn call(&self, t: &SignedTransaction, vm_tracing: bool) -> Result<Executed, ExecutionError>;
|
||||
|
||||
/// Returns EvmFactory.
|
||||
fn vm_factory(&self) -> &EvmFactory;
|
||||
|
||||
@@ -233,7 +233,7 @@ impl TestBlockChainClient {
|
||||
}
|
||||
|
||||
impl BlockChainClient for TestBlockChainClient {
|
||||
fn call(&self, _t: &SignedTransaction) -> Result<Executed, ExecutionError> {
|
||||
fn call(&self, _t: &SignedTransaction, _vm_tracing: bool) -> Result<Executed, ExecutionError> {
|
||||
Ok(self.execution_result.read().unwrap().clone().unwrap())
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
||||
pub struct TransactOptions {
|
||||
/// Enable call tracing.
|
||||
pub tracing: bool,
|
||||
/// Enable VM tracing.
|
||||
pub vm_tracing: bool,
|
||||
/// Check transaction nonce before execution.
|
||||
pub check_nonce: bool,
|
||||
}
|
||||
@@ -394,6 +396,7 @@ impl<'a> Executive<'a> {
|
||||
contracts_created: vec![],
|
||||
output: output,
|
||||
trace: trace,
|
||||
vm_trace: None,
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
@@ -406,6 +409,7 @@ impl<'a> Executive<'a> {
|
||||
contracts_created: substate.contracts_created,
|
||||
output: output,
|
||||
trace: trace,
|
||||
vm_trace: None,
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -913,7 +917,7 @@ mod tests {
|
||||
|
||||
let executed = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts).unwrap()
|
||||
};
|
||||
|
||||
@@ -947,7 +951,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@@ -979,7 +983,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@@ -1013,7 +1017,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@@ -1047,7 +1051,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ impl State {
|
||||
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, vm_factory: &EvmFactory, t: &SignedTransaction, tracing: bool) -> ApplyResult {
|
||||
// let old = self.to_pod();
|
||||
|
||||
let options = TransactOptions { tracing: tracing, check_nonce: true };
|
||||
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
|
||||
let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
|
||||
|
||||
// TODO uncomment once to_pod() works correctly.
|
||||
|
||||
@@ -31,7 +31,7 @@ pub use self::block::BlockTraces;
|
||||
pub use self::config::{Config, Switch};
|
||||
pub use self::db::TraceDB;
|
||||
pub use self::error::Error;
|
||||
pub use types::trace_types::trace::Trace;
|
||||
pub use types::trace_types::trace::{Trace, VMTrace};
|
||||
pub use self::noop_tracer::NoopTracer;
|
||||
pub use self::executive_tracer::ExecutiveTracer;
|
||||
pub use types::trace_types::filter::{Filter, AddressesFilter};
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use util::numbers::*;
|
||||
use util::Bytes;
|
||||
use trace::Trace;
|
||||
use trace::{Trace, VMTrace};
|
||||
use types::log_entry::LogEntry;
|
||||
use ipc::binary::BinaryConvertError;
|
||||
use std::fmt;
|
||||
@@ -59,6 +59,8 @@ pub struct Executed {
|
||||
pub output: Bytes,
|
||||
/// The trace of this transaction.
|
||||
pub trace: Option<Trace>,
|
||||
/// The VM trace of this transaction.
|
||||
pub vm_trace: Option<VMTrace>,
|
||||
}
|
||||
|
||||
/// Result of executing the transaction.
|
||||
|
||||
@@ -349,6 +349,94 @@ impl Trace {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Binary)]
|
||||
/// A record of the execution of a single VM operation.
|
||||
pub struct VMOperation {
|
||||
/// The program counter.
|
||||
pub pc: usize,
|
||||
/// The instruction executed.
|
||||
pub instruction: u8,
|
||||
/// The gas cost for this instruction.
|
||||
pub gas_cost: U256,
|
||||
/// The total gas used.
|
||||
pub gas_used: U256,
|
||||
/// The stack.
|
||||
pub stack: Vec<U256>,
|
||||
/// Altered storage value. TODO: should be option.
|
||||
// pub storage_diff: Option<(U256, U256)>,
|
||||
/// If altered, the new memory image.
|
||||
pub new_memory: Bytes,
|
||||
}
|
||||
|
||||
impl Encodable for VMOperation {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(6);
|
||||
s.append(&self.pc);
|
||||
s.append(&self.instruction);
|
||||
s.append(&self.gas_cost);
|
||||
s.append(&self.gas_used);
|
||||
s.append(&self.stack);
|
||||
// s.append(&self.storage_diff);
|
||||
s.append(&self.new_memory);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for VMOperation {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = VMOperation {
|
||||
pc: try!(d.val_at(0)),
|
||||
instruction: try!(d.val_at(1)),
|
||||
gas_cost: try!(d.val_at(2)),
|
||||
gas_used: try!(d.val_at(3)),
|
||||
stack: try!(d.val_at(4)),
|
||||
// storage_diff: try!(d.val_at(5)),
|
||||
new_memory: try!(d.val_at(6)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Binary)]
|
||||
/// 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 code to be executed.
|
||||
pub code: Bytes,
|
||||
/// The operations executed.
|
||||
pub operations: Vec<VMOperation>,
|
||||
/// The sub traces for each interior action performed as part of this call/create.
|
||||
/// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction.
|
||||
pub subs: Vec<VMTrace>,
|
||||
}
|
||||
|
||||
impl Encodable for VMTrace {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(4);
|
||||
s.append(&self.depth);
|
||||
s.append(&self.code);
|
||||
s.append(&self.operations);
|
||||
s.append(&self.subs);
|
||||
}
|
||||
}
|
||||
|
||||
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)),
|
||||
code: try!(d.val_at(1)),
|
||||
operations: try!(d.val_at(2)),
|
||||
subs: try!(d.val_at(3)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use util::{Address, U256, FixedHash};
|
||||
|
||||
Reference in New Issue
Block a user