diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 817420f3c..452255383 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -19,13 +19,12 @@ use std::sync::{Weak, Arc}; use jsonrpc_core::*; use std::collections::BTreeMap; -use util::{H256, U256, FixedHash, Uint}; +use util::{H256, FixedHash}; use ethcore::client::{BlockChainClient, CallAnalytics, TransactionID, TraceId}; -use ethcore::trace::VMTrace; use ethcore::miner::MinerService; use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use v1::traits::Traces; -use v1::types::{TraceFilter, LocalizedTrace, Trace, BlockNumber, Index, CallRequest, Bytes, StateDiff}; +use v1::types::{TraceFilter, LocalizedTrace, Trace, BlockNumber, Index, CallRequest, Bytes, StateDiff, VMTrace}; /// Traces api implementation. pub struct TracesClient where C: BlockChainClient, M: MinerService { @@ -58,95 +57,6 @@ impl TracesClient where C: BlockChainClient, M: MinerService { } } -fn vm_trace_to_object(t: &VMTrace) -> Value { - let mut ret = BTreeMap::new(); - ret.insert("code".to_owned(), to_value(&t.code).unwrap()); - - let mut subs = t.subs.iter(); - let mut next_sub = subs.next(); - - let ops = t.operations - .iter() - .enumerate() - .map(|(i, op)| { - let mut m = map![ - "pc".to_owned() => to_value(&op.pc).unwrap(), - "cost".to_owned() => match op.gas_cost <= U256::from(!0u64) { - true => to_value(&op.gas_cost.low_u64()), - false => to_value(&op.gas_cost), - }.unwrap() - ]; - if let Some(ref ex) = op.executed { - let mut em = map![ - "used".to_owned() => to_value(&ex.gas_used.low_u64()).unwrap(), - "push".to_owned() => to_value(&ex.stack_push).unwrap() - ]; - if let Some(ref md) = ex.mem_diff { - em.insert("mem".to_owned(), Value::Object(map![ - "off".to_owned() => to_value(&md.offset).unwrap(), - "data".to_owned() => to_value(&md.data).unwrap() - ])); - } - if let Some(ref sd) = ex.store_diff { - em.insert("store".to_owned(), Value::Object(map![ - "key".to_owned() => to_value(&sd.location).unwrap(), - "val".to_owned() => to_value(&sd.value).unwrap() - ])); - } - m.insert("ex".to_owned(), Value::Object(em)); - } - if next_sub.is_some() && next_sub.unwrap().parent_step == i { - m.insert("sub".to_owned(), vm_trace_to_object(next_sub.unwrap())); - next_sub = subs.next(); - } - Value::Object(m) - }) - .collect::>(); - ret.insert("ops".to_owned(), Value::Array(ops)); - Value::Object(ret) -} -/* -fn diff_to_object(d: &Diff) -> Value where T: serde::Serialize + Eq { - let mut ret = BTreeMap::new(); - match *d { - Diff::Same => { - ret.insert("diff".to_owned(), Value::String("=".to_owned())); - } - Diff::Born(ref x) => { - ret.insert("diff".to_owned(), Value::String("+".to_owned())); - ret.insert("+".to_owned(), to_value(x).unwrap()); - } - Diff::Died(ref x) => { - ret.insert("diff".to_owned(), Value::String("-".to_owned())); - ret.insert("-".to_owned(), to_value(x).unwrap()); - } - Diff::Changed(ref from, ref to) => { - ret.insert("diff".to_owned(), Value::String("*".to_owned())); - ret.insert("-".to_owned(), to_value(from).unwrap()); - ret.insert("+".to_owned(), to_value(to).unwrap()); - } - }; - Value::Object(ret) -} - -fn state_diff_to_object(t: &StateDiff) -> Value { - Value::Object(t.iter().map(|(address, account)| { - (address.hex(), Value::Object(map![ - "existance".to_owned() => Value::String(match account.existance() { - Existance::Born => "+", - Existance::Alive => ".", - Existance::Died => "-", - }.to_owned()), - "balance".to_owned() => diff_to_object(&account.balance), - "nonce".to_owned() => diff_to_object(&account.nonce), - "code".to_owned() => diff_to_object(&account.code), - "storage".to_owned() => Value::Object(account.storage.iter().map(|(key, val)| { - (key.hex(), diff_to_object(&val)) - }).collect::>()) - ])) - }).collect::>()) -} -*/ impl Traces for TracesClient where C: BlockChainClient + 'static, M: MinerService + 'static { fn filter(&self, params: Params) -> Result { from_params::<(TraceFilter,)>(params) @@ -211,7 +121,7 @@ impl Traces for TracesClient where C: BlockChainClient + 'static, M: ret.insert("trace".to_owned(), to_value(&Trace::from(trace)).unwrap()); } if let Some(vm_trace) = executed.vm_trace { - ret.insert("vmTrace".to_owned(), vm_trace_to_object(&vm_trace)); + ret.insert("vmTrace".to_owned(), to_value(&VMTrace::from(vm_trace)).unwrap()); } if let Some(state_diff) = executed.state_diff { ret.insert("stateDiff".to_owned(), to_value(&StateDiff::from(state_diff)).unwrap()); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index fc2a19987..3f07bfb31 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -41,5 +41,5 @@ pub use self::transaction::Transaction; pub use self::transaction_request::{TransactionRequest, TransactionConfirmation, TransactionModification}; pub use self::call_request::CallRequest; pub use self::receipt::Receipt; -pub use self::trace::{Trace, LocalizedTrace, StateDiff}; +pub use self::trace::{Trace, LocalizedTrace, StateDiff, VMTrace}; pub use self::trace_filter::TraceFilter; diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index ede99b448..5b4192886 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -15,14 +15,133 @@ // along with Parity. If not, see . use std::collections::BTreeMap; -use util::{Address, U256, H256}; +use util::{Address, U256, H256, Uint}; use serde::{Serialize, Serializer}; use ethcore::trace::trace; use ethcore::trace::{Trace as EthTrace, LocalizedTrace as EthLocalizedTrace}; +use ethcore::trace as et; use ethcore::state_diff; use ethcore::account_diff; use v1::types::Bytes; +#[derive(Debug, Serialize)] +/// A diff of some chunk of memory. +pub struct MemoryDiff { + /// Offset into memory the change begins. + pub off: usize, + /// The changed data. + pub data: Vec, +} + +impl From for MemoryDiff { + fn from(c: et::MemoryDiff) -> Self { + MemoryDiff { + off: c.offset, + data: c.data, + } + } +} + +#[derive(Debug, Serialize)] +/// A diff of some storage value. +pub struct StorageDiff { + /// Which key in storage is changed. + pub key: U256, + /// What the value has been changed to. + pub val: U256, +} + +impl From for StorageDiff { + fn from(c: et::StorageDiff) -> Self { + StorageDiff { + key: c.location, + val: c.value, + } + } +} + +#[derive(Debug, Serialize)] +/// A record of an executed VM operation. +pub struct VMExecutedOperation { + /// The total gas used. + #[serde(rename="used")] + pub used: u64, + /// The stack item placed, if any. + pub push: Vec, + /// If altered, the memory delta. + #[serde(rename="mem")] + pub mem: Option, + /// The altered storage value, if any. + #[serde(rename="store")] + pub store: Option, +} + +impl From for VMExecutedOperation { + fn from(c: et::VMExecutedOperation) -> Self { + VMExecutedOperation { + used: c.gas_used.low_u64(), + push: c.stack_push, + mem: c.mem_diff.map(From::from), + store: c.store_diff.map(From::from), + } + } +} + +#[derive(Debug, Serialize)] +/// A record of the execution of a single VM operation. +pub struct VMOperation { + /// The program counter. + pub pc: usize, + /// The gas cost for this instruction. + pub cost: u64, + /// Information concerning the execution of the operation. + pub ex: Option, + /// Subordinate trace of the CALL/CREATE if applicable. + pub sub: Option, +} + +impl From<(et::VMOperation, Option)> for VMOperation { + fn from(c: (et::VMOperation, Option)) -> Self { + VMOperation { + pc: c.0.pc, + cost: c.0.gas_cost.low_u64(), + ex: c.0.executed.map(From::from), + sub: c.1.map(From::from), + } + } +} + +#[derive(Debug, Serialize)] +/// A record of a full VM trace for a CALL/CREATE. +pub struct VMTrace { + /// The code to be executed. + pub code: Vec, + /// The operations executed. + pub ops: Vec, +} + +impl From for VMTrace { + fn from(c: et::VMTrace) -> Self { + let mut subs = c.subs.into_iter(); + let mut next_sub = subs.next(); + VMTrace { + code: c.code, + ops: c.operations + .into_iter() + .enumerate() + .map(|(i, op)| (op, { + let have_sub = next_sub.is_some() && next_sub.as_ref().unwrap().parent_step == i; + if have_sub { + let r = next_sub.clone(); + next_sub = subs.next(); + r + } else { None } + }).into()) + .collect(), + } + } +} + #[derive(Debug, Serialize)] /// Aux type for Diff::Changed. pub struct ChangedType where T: Serialize {