2016-05-02 12:17:30 +02:00
|
|
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
|
|
|
// This file is part of Parity.
|
|
|
|
|
|
|
|
// Parity is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// Parity is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2016-06-06 00:24:21 +02:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use serde::{Serialize, Serializer};
|
2016-05-02 12:17:30 +02:00
|
|
|
use ethcore::trace::trace;
|
2016-06-02 13:50:50 +02:00
|
|
|
use ethcore::trace::{Trace as EthTrace, LocalizedTrace as EthLocalizedTrace};
|
2016-06-07 00:18:38 +02:00
|
|
|
use ethcore::trace as et;
|
2016-06-06 00:24:21 +02:00
|
|
|
use ethcore::state_diff;
|
|
|
|
use ethcore::account_diff;
|
2016-07-27 17:41:21 +02:00
|
|
|
use ethcore::executed;
|
2016-07-26 16:48:50 +02:00
|
|
|
use ethcore::client::Executed;
|
2016-07-06 11:23:29 +02:00
|
|
|
use util::Uint;
|
|
|
|
use v1::types::{Bytes, H160, H256, U256};
|
2016-05-02 12:17:30 +02:00
|
|
|
|
2016-06-07 00:18:38 +02:00
|
|
|
#[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<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<et::MemoryDiff> 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<et::StorageDiff> for StorageDiff {
|
|
|
|
fn from(c: et::StorageDiff) -> Self {
|
|
|
|
StorageDiff {
|
2016-07-06 11:23:29 +02:00
|
|
|
key: c.location.into(),
|
|
|
|
val: c.value.into(),
|
2016-06-07 00:18:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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<U256>,
|
|
|
|
/// If altered, the memory delta.
|
|
|
|
#[serde(rename="mem")]
|
|
|
|
pub mem: Option<MemoryDiff>,
|
|
|
|
/// The altered storage value, if any.
|
|
|
|
#[serde(rename="store")]
|
|
|
|
pub store: Option<StorageDiff>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<et::VMExecutedOperation> for VMExecutedOperation {
|
|
|
|
fn from(c: et::VMExecutedOperation) -> Self {
|
|
|
|
VMExecutedOperation {
|
|
|
|
used: c.gas_used.low_u64(),
|
2016-07-06 11:23:29 +02:00
|
|
|
push: c.stack_push.into_iter().map(Into::into).collect(),
|
|
|
|
mem: c.mem_diff.map(Into::into),
|
|
|
|
store: c.store_diff.map(Into::into),
|
2016-06-07 00:18:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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<VMExecutedOperation>,
|
|
|
|
/// Subordinate trace of the CALL/CREATE if applicable.
|
|
|
|
pub sub: Option<VMTrace>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<(et::VMOperation, Option<et::VMTrace>)> for VMOperation {
|
|
|
|
fn from(c: (et::VMOperation, Option<et::VMTrace>)) -> Self {
|
|
|
|
VMOperation {
|
|
|
|
pc: c.0.pc,
|
|
|
|
cost: c.0.gas_cost.low_u64(),
|
2016-07-06 11:23:29 +02:00
|
|
|
ex: c.0.executed.map(Into::into),
|
|
|
|
sub: c.1.map(Into::into),
|
2016-06-07 00:18:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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<u8>,
|
|
|
|
/// The operations executed.
|
|
|
|
pub ops: Vec<VMOperation>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<et::VMTrace> 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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-06 00:24:21 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
/// Aux type for Diff::Changed.
|
|
|
|
pub struct ChangedType<T> where T: Serialize {
|
|
|
|
from: T,
|
|
|
|
to: T,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
/// Serde-friendly `Diff` shadow.
|
|
|
|
pub enum Diff<T> where T: Serialize {
|
|
|
|
#[serde(rename="=")]
|
|
|
|
Same,
|
|
|
|
#[serde(rename="+")]
|
|
|
|
Born(T),
|
|
|
|
#[serde(rename="-")]
|
|
|
|
Died(T),
|
|
|
|
#[serde(rename="*")]
|
|
|
|
Changed(ChangedType<T>),
|
|
|
|
}
|
|
|
|
|
2016-07-07 09:39:32 +02:00
|
|
|
impl<T, U> From<account_diff::Diff<T>> for Diff<U> where T: Eq + ::ethcore_ipc::BinaryConvertable, U: Serialize + From<T> {
|
2016-06-06 00:24:21 +02:00
|
|
|
fn from(c: account_diff::Diff<T>) -> Self {
|
|
|
|
match c {
|
|
|
|
account_diff::Diff::Same => Diff::Same,
|
|
|
|
account_diff::Diff::Born(t) => Diff::Born(t.into()),
|
|
|
|
account_diff::Diff::Died(t) => Diff::Died(t.into()),
|
|
|
|
account_diff::Diff::Changed(t, u) => Diff::Changed(ChangedType{from: t.into(), to: u.into()}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
/// Serde-friendly `AccountDiff` shadow.
|
|
|
|
pub struct AccountDiff {
|
|
|
|
pub balance: Diff<U256>,
|
|
|
|
pub nonce: Diff<U256>,
|
|
|
|
pub code: Diff<Bytes>,
|
|
|
|
pub storage: BTreeMap<H256, Diff<H256>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<account_diff::AccountDiff> for AccountDiff {
|
|
|
|
fn from(c: account_diff::AccountDiff) -> Self {
|
|
|
|
AccountDiff {
|
|
|
|
balance: c.balance.into(),
|
|
|
|
nonce: c.nonce.into(),
|
|
|
|
code: c.code.into(),
|
2016-07-06 11:23:29 +02:00
|
|
|
storage: c.storage.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),
|
2016-06-06 00:24:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 16:48:50 +02:00
|
|
|
#[derive(Debug)]
|
2016-06-06 00:24:21 +02:00
|
|
|
/// Serde-friendly `StateDiff` shadow.
|
2016-07-06 11:23:29 +02:00
|
|
|
pub struct StateDiff(BTreeMap<H160, AccountDiff>);
|
2016-06-06 00:24:21 +02:00
|
|
|
|
|
|
|
impl Serialize for StateDiff {
|
|
|
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
|
|
|
where S: Serializer {
|
|
|
|
Serialize::serialize(&self.0, serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<state_diff::StateDiff> for StateDiff {
|
|
|
|
fn from(c: state_diff::StateDiff) -> Self {
|
2016-07-07 09:39:32 +02:00
|
|
|
StateDiff(c.raw.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
|
2016-06-06 00:24:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Create response
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct Create {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Sender
|
2016-07-06 11:23:29 +02:00
|
|
|
from: H160,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Value
|
2016-05-02 12:17:30 +02:00
|
|
|
value: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Gas
|
2016-05-02 12:17:30 +02:00
|
|
|
gas: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Initialization code
|
2016-05-02 12:17:30 +02:00
|
|
|
init: Bytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::Create> for Create {
|
|
|
|
fn from(c: trace::Create) -> Self {
|
|
|
|
Create {
|
2016-07-06 11:23:29 +02:00
|
|
|
from: c.from.into(),
|
|
|
|
value: c.value.into(),
|
|
|
|
gas: c.gas.into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
init: Bytes::new(c.init),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 17:41:21 +02:00
|
|
|
/// Call type.
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub enum CallType {
|
|
|
|
/// None
|
|
|
|
#[serde(rename="none")]
|
|
|
|
None,
|
|
|
|
/// Call
|
|
|
|
#[serde(rename="call")]
|
|
|
|
Call,
|
|
|
|
/// Call code
|
|
|
|
#[serde(rename="callcode")]
|
|
|
|
CallCode,
|
|
|
|
/// Delegate call
|
|
|
|
#[serde(rename="delegatecall")]
|
|
|
|
DelegateCall,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<executed::CallType> for CallType {
|
|
|
|
fn from(c: executed::CallType) -> Self {
|
|
|
|
match c {
|
|
|
|
executed::CallType::None => CallType::None,
|
|
|
|
executed::CallType::Call => CallType::Call,
|
|
|
|
executed::CallType::CallCode => CallType::CallCode,
|
|
|
|
executed::CallType::DelegateCall => CallType::DelegateCall,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Call response
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct Call {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Sender
|
2016-07-06 11:23:29 +02:00
|
|
|
from: H160,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Recipient
|
2016-07-06 11:23:29 +02:00
|
|
|
to: H160,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Transfered Value
|
2016-05-02 12:17:30 +02:00
|
|
|
value: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Gas
|
2016-05-02 12:17:30 +02:00
|
|
|
gas: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Input data
|
2016-05-02 12:17:30 +02:00
|
|
|
input: Bytes,
|
2016-07-27 17:41:21 +02:00
|
|
|
/// The type of the call.
|
|
|
|
#[serde(rename="callType")]
|
|
|
|
call_type: CallType,
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::Call> for Call {
|
|
|
|
fn from(c: trace::Call) -> Self {
|
|
|
|
Call {
|
2016-07-06 11:23:29 +02:00
|
|
|
from: c.from.into(),
|
|
|
|
to: c.to.into(),
|
|
|
|
value: c.value.into(),
|
|
|
|
gas: c.gas.into(),
|
|
|
|
input: c.input.into(),
|
2016-07-27 17:41:21 +02:00
|
|
|
call_type: c.call_type.into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-22 14:47:23 +02:00
|
|
|
/// Suicide
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct Suicide {
|
|
|
|
/// Address.
|
|
|
|
pub address: H160,
|
|
|
|
/// Refund address.
|
|
|
|
#[serde(rename="refundAddress")]
|
|
|
|
pub refund_address: H160,
|
|
|
|
/// Balance.
|
|
|
|
pub balance: U256,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::Suicide> for Suicide {
|
|
|
|
fn from(s: trace::Suicide) -> Self {
|
|
|
|
Suicide {
|
|
|
|
address: s.address.into(),
|
|
|
|
refund_address: s.refund_address.into(),
|
|
|
|
balance: s.balance.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Action
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub enum Action {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Call
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="call")]
|
|
|
|
Call(Call),
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Create
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="create")]
|
|
|
|
Create(Create),
|
2016-07-22 14:47:23 +02:00
|
|
|
/// Suicide
|
|
|
|
#[serde(rename="suicide")]
|
|
|
|
Suicide(Suicide),
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::Action> for Action {
|
|
|
|
fn from(c: trace::Action) -> Self {
|
|
|
|
match c {
|
2016-07-22 14:47:23 +02:00
|
|
|
trace::Action::Call(call) => Action::Call(call.into()),
|
|
|
|
trace::Action::Create(create) => Action::Create(create.into()),
|
|
|
|
trace::Action::Suicide(suicide) => Action::Suicide(suicide.into()),
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Call Result
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct CallResult {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Gas used
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="gasUsed")]
|
|
|
|
gas_used: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Output bytes
|
2016-05-02 12:17:30 +02:00
|
|
|
output: Bytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::CallResult> for CallResult {
|
|
|
|
fn from(c: trace::CallResult) -> Self {
|
|
|
|
CallResult {
|
2016-07-06 11:23:29 +02:00
|
|
|
gas_used: c.gas_used.into(),
|
|
|
|
output: c.output.into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Craete Result
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct CreateResult {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Gas used
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="gasUsed")]
|
|
|
|
gas_used: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Code
|
2016-05-02 12:17:30 +02:00
|
|
|
code: Bytes,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Assigned address
|
2016-07-06 11:23:29 +02:00
|
|
|
address: H160,
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::CreateResult> for CreateResult {
|
|
|
|
fn from(c: trace::CreateResult) -> Self {
|
|
|
|
CreateResult {
|
2016-07-06 11:23:29 +02:00
|
|
|
gas_used: c.gas_used.into(),
|
|
|
|
code: c.code.into(),
|
|
|
|
address: c.address.into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Response
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub enum Res {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Call
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="call")]
|
|
|
|
Call(CallResult),
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Create
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="create")]
|
|
|
|
Create(CreateResult),
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Call failure
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="failedCall")]
|
|
|
|
FailedCall,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Creation failure
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="failedCreate")]
|
|
|
|
FailedCreate,
|
2016-07-22 14:47:23 +02:00
|
|
|
/// None
|
|
|
|
#[serde(rename="none")]
|
|
|
|
None,
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<trace::Res> for Res {
|
|
|
|
fn from(t: trace::Res) -> Self {
|
|
|
|
match t {
|
|
|
|
trace::Res::Call(call) => Res::Call(CallResult::from(call)),
|
|
|
|
trace::Res::Create(create) => Res::Create(CreateResult::from(create)),
|
|
|
|
trace::Res::FailedCall => Res::FailedCall,
|
|
|
|
trace::Res::FailedCreate => Res::FailedCreate,
|
2016-07-22 14:47:23 +02:00
|
|
|
trace::Res::None => Res::None,
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Trace
|
2016-05-02 12:17:30 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
2016-06-02 13:50:50 +02:00
|
|
|
pub struct LocalizedTrace {
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Action
|
2016-05-02 12:17:30 +02:00
|
|
|
action: Action,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Result
|
2016-05-02 12:17:30 +02:00
|
|
|
result: Res,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Trace address
|
2016-07-13 21:10:20 +02:00
|
|
|
#[serde(rename="traceAddress")]
|
2016-05-02 12:17:30 +02:00
|
|
|
trace_address: Vec<U256>,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Subtraces
|
2016-05-02 12:17:30 +02:00
|
|
|
subtraces: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Transaction position
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="transactionPosition")]
|
|
|
|
transaction_position: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Transaction hash
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="transactionHash")]
|
|
|
|
transaction_hash: H256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Block Number
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="blockNumber")]
|
|
|
|
block_number: U256,
|
2016-05-28 19:30:31 +02:00
|
|
|
/// Block Hash
|
2016-05-02 12:17:30 +02:00
|
|
|
#[serde(rename="blockHash")]
|
|
|
|
block_hash: H256,
|
|
|
|
}
|
|
|
|
|
2016-06-02 13:50:50 +02:00
|
|
|
impl From<EthLocalizedTrace> for LocalizedTrace {
|
|
|
|
fn from(t: EthLocalizedTrace) -> Self {
|
|
|
|
LocalizedTrace {
|
2016-07-06 11:23:29 +02:00
|
|
|
action: t.action.into(),
|
|
|
|
result: t.result.into(),
|
|
|
|
trace_address: t.trace_address.into_iter().map(Into::into).collect(),
|
|
|
|
subtraces: t.subtraces.into(),
|
|
|
|
transaction_position: t.transaction_number.into(),
|
|
|
|
transaction_hash: t.transaction_hash.into(),
|
|
|
|
block_number: t.block_number.into(),
|
|
|
|
block_hash: t.block_hash.into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 13:50:50 +02:00
|
|
|
/// Trace
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct Trace {
|
|
|
|
/// Depth within the call trace tree.
|
|
|
|
depth: usize,
|
|
|
|
/// Action
|
|
|
|
action: Action,
|
|
|
|
/// Result
|
|
|
|
result: Res,
|
|
|
|
/// Subtraces
|
|
|
|
subtraces: Vec<Trace>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<EthTrace> for Trace {
|
|
|
|
fn from(t: EthTrace) -> Self {
|
|
|
|
Trace {
|
|
|
|
depth: t.depth.into(),
|
|
|
|
action: t.action.into(),
|
|
|
|
result: t.result.into(),
|
2016-07-06 11:23:29 +02:00
|
|
|
subtraces: t.subs.into_iter().map(Into::into).collect(),
|
2016-06-02 13:50:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 16:48:50 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
/// A diff of some chunk of memory.
|
|
|
|
pub struct TraceResults {
|
|
|
|
/// The output of the call/create
|
|
|
|
pub output: Vec<u8>,
|
|
|
|
/// The transaction trace.
|
|
|
|
pub trace: Option<Trace>,
|
|
|
|
/// The transaction trace.
|
|
|
|
#[serde(rename="vmTrace")]
|
|
|
|
pub vm_trace: Option<VMTrace>,
|
|
|
|
/// The transaction trace.
|
|
|
|
#[serde(rename="stateDiff")]
|
|
|
|
pub state_diff: Option<StateDiff>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Executed> for TraceResults {
|
|
|
|
fn from(t: Executed) -> Self {
|
|
|
|
TraceResults {
|
|
|
|
output: t.output.into(),
|
|
|
|
trace: t.trace.map(Into::into),
|
|
|
|
vm_trace: t.vm_trace.map(Into::into),
|
|
|
|
state_diff: t.state_diff.map(Into::into),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-02 12:17:30 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use serde_json;
|
2016-06-07 21:44:57 +02:00
|
|
|
use std::collections::BTreeMap;
|
2016-07-06 11:23:29 +02:00
|
|
|
use v1::types::{Bytes, U256, H256, H160};
|
2016-05-02 12:17:30 +02:00
|
|
|
use super::*;
|
|
|
|
|
2016-07-26 16:48:50 +02:00
|
|
|
#[test]
|
|
|
|
fn should_serialize_trace_results() {
|
|
|
|
let r = TraceResults {
|
|
|
|
output: vec![0x60],
|
|
|
|
trace: None,
|
|
|
|
vm_trace: None,
|
|
|
|
state_diff: None,
|
|
|
|
};
|
|
|
|
let serialized = serde_json::to_string(&r).unwrap();
|
|
|
|
assert_eq!(serialized, r#"{"output":[96],"trace":null,"vmTrace":null,"stateDiff":null}"#);
|
|
|
|
}
|
|
|
|
|
2016-05-02 12:17:30 +02:00
|
|
|
#[test]
|
|
|
|
fn test_trace_serialize() {
|
2016-06-02 13:50:50 +02:00
|
|
|
let t = LocalizedTrace {
|
2016-05-02 12:17:30 +02:00
|
|
|
action: Action::Call(Call {
|
2016-07-06 11:23:29 +02:00
|
|
|
from: H160::from(4),
|
|
|
|
to: H160::from(5),
|
2016-05-02 12:17:30 +02:00
|
|
|
value: U256::from(6),
|
|
|
|
gas: U256::from(7),
|
|
|
|
input: Bytes::new(vec![0x12, 0x34]),
|
2016-07-27 17:41:21 +02:00
|
|
|
call_type: CallType::Call,
|
2016-05-02 12:17:30 +02:00
|
|
|
}),
|
|
|
|
result: Res::Call(CallResult {
|
|
|
|
gas_used: U256::from(8),
|
2016-07-06 11:23:29 +02:00
|
|
|
output: vec![0x56, 0x78].into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
}),
|
|
|
|
trace_address: vec![U256::from(10)],
|
|
|
|
subtraces: U256::from(1),
|
|
|
|
transaction_position: U256::from(11),
|
|
|
|
transaction_hash: H256::from(12),
|
|
|
|
block_number: U256::from(13),
|
|
|
|
block_hash: H256::from(14),
|
|
|
|
};
|
|
|
|
let serialized = serde_json::to_string(&t).unwrap();
|
2016-07-27 17:41:21 +02:00
|
|
|
assert_eq!(serialized, r#"{"action":{"call":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","input":"0x1234","callType":{"call":[]}}},"result":{"call":{"gasUsed":"0x08","output":"0x5678"}},"traceAddress":["0x0a"],"subtraces":"0x01","transactionPosition":"0x0b","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0x0d","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
2016-06-07 21:30:44 +02:00
|
|
|
#[test]
|
|
|
|
fn test_vmtrace_serialize() {
|
|
|
|
let t = VMTrace {
|
|
|
|
code: vec![0, 1, 2, 3],
|
|
|
|
ops: vec![
|
|
|
|
VMOperation {
|
|
|
|
pc: 0,
|
|
|
|
cost: 10,
|
|
|
|
ex: None,
|
|
|
|
sub: None,
|
|
|
|
},
|
|
|
|
VMOperation {
|
|
|
|
pc: 1,
|
|
|
|
cost: 11,
|
|
|
|
ex: Some(VMExecutedOperation {
|
|
|
|
used: 10,
|
|
|
|
push: vec![69.into()],
|
|
|
|
mem: None,
|
|
|
|
store: None,
|
|
|
|
}),
|
|
|
|
sub: Some(VMTrace {
|
|
|
|
code: vec![0],
|
|
|
|
ops: vec![
|
|
|
|
VMOperation {
|
|
|
|
pc: 0,
|
|
|
|
cost: 0,
|
|
|
|
ex: Some(VMExecutedOperation {
|
|
|
|
used: 10,
|
|
|
|
push: vec![42.into()],
|
|
|
|
mem: Some(MemoryDiff {off: 42, data: vec![1, 2, 3]}),
|
|
|
|
store: Some(StorageDiff {key: 69.into(), val: 42.into()}),
|
|
|
|
}),
|
|
|
|
sub: None,
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
let serialized = serde_json::to_string(&t).unwrap();
|
2016-06-08 21:41:29 +02:00
|
|
|
assert_eq!(serialized, r#"{"code":[0,1,2,3],"ops":[{"pc":0,"cost":10,"ex":null,"sub":null},{"pc":1,"cost":11,"ex":{"used":10,"push":["0x45"],"mem":null,"store":null},"sub":{"code":[0],"ops":[{"pc":0,"cost":0,"ex":{"used":10,"push":["0x2a"],"mem":{"off":42,"data":[1,2,3]},"store":{"key":"0x45","val":"0x2a"}},"sub":null}]}}]}"#);
|
2016-06-07 21:30:44 +02:00
|
|
|
}
|
|
|
|
|
2016-06-07 21:44:57 +02:00
|
|
|
#[test]
|
|
|
|
fn test_statediff_serialize() {
|
|
|
|
let t = StateDiff(map![
|
|
|
|
42.into() => AccountDiff {
|
|
|
|
balance: Diff::Same,
|
|
|
|
nonce: Diff::Born(1.into()),
|
|
|
|
code: Diff::Same,
|
|
|
|
storage: map![
|
|
|
|
42.into() => Diff::Same
|
|
|
|
]
|
|
|
|
},
|
|
|
|
69.into() => AccountDiff {
|
|
|
|
balance: Diff::Same,
|
|
|
|
nonce: Diff::Changed(ChangedType { from: 1.into(), to: 0.into() }),
|
|
|
|
code: Diff::Died(vec![96].into()),
|
|
|
|
storage: map![],
|
|
|
|
}
|
|
|
|
]);
|
|
|
|
let serialized = serde_json::to_string(&t).unwrap();
|
2016-06-08 21:41:29 +02:00
|
|
|
assert_eq!(serialized, r#"{"0x000000000000000000000000000000000000002a":{"balance":{"=":[]},"nonce":{"+":"0x01"},"code":{"=":[]},"storage":{"0x000000000000000000000000000000000000000000000000000000000000002a":{"=":[]}}},"0x0000000000000000000000000000000000000045":{"balance":{"=":[]},"nonce":{"*":{"from":"0x01","to":"0x00"}},"code":{"-":"0x60"},"storage":{}}}"#);
|
2016-06-07 21:44:57 +02:00
|
|
|
}
|
|
|
|
|
2016-05-02 12:17:30 +02:00
|
|
|
#[test]
|
|
|
|
fn test_action_serialize() {
|
|
|
|
let actions = vec![Action::Call(Call {
|
2016-07-06 11:23:29 +02:00
|
|
|
from: H160::from(1),
|
|
|
|
to: H160::from(2),
|
2016-05-02 12:17:30 +02:00
|
|
|
value: U256::from(3),
|
|
|
|
gas: U256::from(4),
|
2016-07-06 11:23:29 +02:00
|
|
|
input: vec![0x12, 0x34].into(),
|
2016-07-27 17:41:21 +02:00
|
|
|
call_type: CallType::Call,
|
2016-05-02 12:17:30 +02:00
|
|
|
}), Action::Create(Create {
|
2016-07-06 11:23:29 +02:00
|
|
|
from: H160::from(5),
|
2016-05-02 12:17:30 +02:00
|
|
|
value: U256::from(6),
|
|
|
|
gas: U256::from(7),
|
2016-07-06 11:23:29 +02:00
|
|
|
init: vec![0x56, 0x78].into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
})];
|
|
|
|
|
|
|
|
let serialized = serde_json::to_string(&actions).unwrap();
|
2016-07-27 17:41:21 +02:00
|
|
|
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x03","gas":"0x04","input":"0x1234","callType":{"call":[]}}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","init":"0x5678"}}]"#);
|
2016-05-02 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_result_serialize() {
|
|
|
|
let results = vec![
|
|
|
|
Res::Call(CallResult {
|
|
|
|
gas_used: U256::from(1),
|
2016-07-06 11:23:29 +02:00
|
|
|
output: vec![0x12, 0x34].into(),
|
2016-05-02 12:17:30 +02:00
|
|
|
}),
|
|
|
|
Res::Create(CreateResult {
|
|
|
|
gas_used: U256::from(2),
|
2016-07-06 11:23:29 +02:00
|
|
|
code: vec![0x45, 0x56].into(),
|
|
|
|
address: H160::from(3),
|
2016-05-02 12:17:30 +02:00
|
|
|
}),
|
|
|
|
Res::FailedCall,
|
|
|
|
Res::FailedCreate,
|
|
|
|
];
|
|
|
|
|
|
|
|
let serialized = serde_json::to_string(&results).unwrap();
|
|
|
|
assert_eq!(serialized, r#"[{"call":{"gasUsed":"0x01","output":"0x1234"}},{"create":{"gasUsed":"0x02","code":"0x4556","address":"0x0000000000000000000000000000000000000003"}},{"failedCall":[]},{"failedCreate":[]}]"#);
|
|
|
|
}
|
|
|
|
}
|