RPC endpoint for VM tracing and ser/de types ready.

This commit is contained in:
Gav Wood
2016-05-28 16:52:33 +02:00
parent 42e4c2d51c
commit c1ed520de0
17 changed files with 167 additions and 30 deletions

View File

@@ -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)
}

View File

@@ -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;

View File

@@ -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())
}

View File

@@ -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)
};

View File

@@ -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.

View File

@@ -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};

View File

@@ -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.

View File

@@ -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};