415 lines
9.8 KiB
Rust
415 lines
9.8 KiB
Rust
// Copyright 2015-2017 Parity Technologies (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/>.
|
|
|
|
//! Tracing datatypes.
|
|
|
|
use bigint::prelude::U256;
|
|
use util::Address;
|
|
use bytes::Bytes;
|
|
use hash::keccak;
|
|
use bloomable::Bloomable;
|
|
use rlp::*;
|
|
|
|
use vm::ActionParams;
|
|
use basic_types::LogBloom;
|
|
use evm::CallType;
|
|
use super::error::Error;
|
|
|
|
/// `Call` result.
|
|
#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)]
|
|
pub struct CallResult {
|
|
/// Gas used by call.
|
|
pub gas_used: U256,
|
|
/// Call Output.
|
|
pub output: Bytes,
|
|
}
|
|
|
|
/// `Create` result.
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
pub struct CreateResult {
|
|
/// Gas used by create.
|
|
pub gas_used: U256,
|
|
/// Code of the newly created contract.
|
|
pub code: Bytes,
|
|
/// Address of the newly created contract.
|
|
pub address: Address,
|
|
}
|
|
|
|
impl CreateResult {
|
|
/// Returns bloom.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
LogBloom::from_bloomed(&keccak(&self.address))
|
|
}
|
|
}
|
|
|
|
/// Description of a _call_ action, either a `CALL` operation or a message transction.
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
pub struct Call {
|
|
/// The sending account.
|
|
pub from: Address,
|
|
/// The destination account.
|
|
pub to: Address,
|
|
/// The value transferred to the destination account.
|
|
pub value: U256,
|
|
/// The gas available for executing the call.
|
|
pub gas: U256,
|
|
/// The input data provided to the call.
|
|
pub input: Bytes,
|
|
/// The type of the call.
|
|
pub call_type: CallType,
|
|
}
|
|
|
|
impl From<ActionParams> for Call {
|
|
fn from(p: ActionParams) -> Self {
|
|
Call {
|
|
from: p.sender,
|
|
to: p.address,
|
|
value: p.value.value(),
|
|
gas: p.gas,
|
|
input: p.data.unwrap_or_else(Vec::new),
|
|
call_type: p.call_type,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Call {
|
|
/// Returns call action bloom.
|
|
/// The bloom contains from and to addresses.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
LogBloom::from_bloomed(&keccak(&self.from))
|
|
.with_bloomed(&keccak(&self.to))
|
|
}
|
|
}
|
|
|
|
/// Description of a _create_ action, either a `CREATE` operation or a create transction.
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
pub struct Create {
|
|
/// The address of the creator.
|
|
pub from: Address,
|
|
/// The value with which the new account is endowed.
|
|
pub value: U256,
|
|
/// The gas available for the creation init code.
|
|
pub gas: U256,
|
|
/// The init code.
|
|
pub init: Bytes,
|
|
}
|
|
|
|
impl From<ActionParams> for Create {
|
|
fn from(p: ActionParams) -> Self {
|
|
Create {
|
|
from: p.sender,
|
|
value: p.value.value(),
|
|
gas: p.gas,
|
|
init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Create {
|
|
/// Returns bloom create action bloom.
|
|
/// The bloom contains only from address.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
LogBloom::from_bloomed(&keccak(&self.from))
|
|
}
|
|
}
|
|
|
|
/// Reward type.
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum RewardType {
|
|
/// Block
|
|
Block,
|
|
/// Uncle
|
|
Uncle,
|
|
}
|
|
|
|
impl Encodable for RewardType {
|
|
fn rlp_append(&self, s: &mut RlpStream) {
|
|
let v = match *self {
|
|
RewardType::Block => 0u32,
|
|
RewardType::Uncle => 1,
|
|
};
|
|
Encodable::rlp_append(&v, s);
|
|
}
|
|
}
|
|
|
|
impl Decodable for RewardType {
|
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
|
rlp.as_val().and_then(|v| Ok(match v {
|
|
0u32 => RewardType::Block,
|
|
1 => RewardType::Uncle,
|
|
_ => return Err(DecoderError::Custom("Invalid value of RewardType item")),
|
|
}))
|
|
}
|
|
}
|
|
|
|
/// Reward action
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Reward {
|
|
/// Author's address.
|
|
pub author: Address,
|
|
/// Reward amount.
|
|
pub value: U256,
|
|
/// Reward type.
|
|
pub reward_type: RewardType,
|
|
}
|
|
|
|
impl Reward {
|
|
/// Return reward action bloom.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
LogBloom::from_bloomed(&keccak(&self.author))
|
|
}
|
|
}
|
|
|
|
impl Encodable for Reward {
|
|
fn rlp_append(&self, s: &mut RlpStream) {
|
|
s.begin_list(3);
|
|
s.append(&self.author);
|
|
s.append(&self.value);
|
|
s.append(&self.reward_type);
|
|
}
|
|
}
|
|
|
|
impl Decodable for Reward {
|
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
|
let res = Reward {
|
|
author: rlp.val_at(0)?,
|
|
value: rlp.val_at(1)?,
|
|
reward_type: rlp.val_at(2)?,
|
|
};
|
|
|
|
Ok(res)
|
|
}
|
|
}
|
|
|
|
|
|
/// Suicide action.
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
pub struct Suicide {
|
|
/// Suicided address.
|
|
pub address: Address,
|
|
/// Suicided contract heir.
|
|
pub refund_address: Address,
|
|
/// Balance of the contract just before suicide.
|
|
pub balance: U256,
|
|
}
|
|
|
|
impl Suicide {
|
|
/// Return suicide action bloom.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
LogBloom::from_bloomed(&keccak(self.address))
|
|
.with_bloomed(&keccak(self.refund_address))
|
|
}
|
|
}
|
|
|
|
/// Description of an action that we trace; will be either a call or a create.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum Action {
|
|
/// It's a call action.
|
|
Call(Call),
|
|
/// It's a create action.
|
|
Create(Create),
|
|
/// Suicide.
|
|
Suicide(Suicide),
|
|
/// Reward
|
|
Reward(Reward),
|
|
}
|
|
|
|
impl Encodable for Action {
|
|
fn rlp_append(&self, s: &mut RlpStream) {
|
|
s.begin_list(2);
|
|
match *self {
|
|
Action::Call(ref call) => {
|
|
s.append(&0u8);
|
|
s.append(call);
|
|
},
|
|
Action::Create(ref create) => {
|
|
s.append(&1u8);
|
|
s.append(create);
|
|
},
|
|
Action::Suicide(ref suicide) => {
|
|
s.append(&2u8);
|
|
s.append(suicide);
|
|
},
|
|
Action::Reward(ref reward) => {
|
|
s.append(&3u8);
|
|
s.append(reward);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Decodable for Action {
|
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
|
let action_type: u8 = rlp.val_at(0)?;
|
|
match action_type {
|
|
0 => rlp.val_at(1).map(Action::Call),
|
|
1 => rlp.val_at(1).map(Action::Create),
|
|
2 => rlp.val_at(1).map(Action::Suicide),
|
|
3 => rlp.val_at(1).map(Action::Reward),
|
|
_ => Err(DecoderError::Custom("Invalid action type.")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Action {
|
|
/// Returns action bloom.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
match *self {
|
|
Action::Call(ref call) => call.bloom(),
|
|
Action::Create(ref create) => create.bloom(),
|
|
Action::Suicide(ref suicide) => suicide.bloom(),
|
|
Action::Reward(ref reward) => reward.bloom(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The result of the performed action.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum Res {
|
|
/// Successful call action result.
|
|
Call(CallResult),
|
|
/// Successful create action result.
|
|
Create(CreateResult),
|
|
/// Failed call.
|
|
FailedCall(Error),
|
|
/// Failed create.
|
|
FailedCreate(Error),
|
|
/// None
|
|
None,
|
|
}
|
|
|
|
impl Encodable for Res {
|
|
fn rlp_append(&self, s: &mut RlpStream) {
|
|
match *self {
|
|
Res::Call(ref call) => {
|
|
s.begin_list(2);
|
|
s.append(&0u8);
|
|
s.append(call);
|
|
},
|
|
Res::Create(ref create) => {
|
|
s.begin_list(2);
|
|
s.append(&1u8);
|
|
s.append(create);
|
|
},
|
|
Res::FailedCall(ref err) => {
|
|
s.begin_list(2);
|
|
s.append(&2u8);
|
|
s.append(err);
|
|
},
|
|
Res::FailedCreate(ref err) => {
|
|
s.begin_list(2);
|
|
s.append(&3u8);
|
|
s.append(err);
|
|
},
|
|
Res::None => {
|
|
s.begin_list(1);
|
|
s.append(&4u8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Decodable for Res {
|
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
|
let action_type: u8 = rlp.val_at(0)?;
|
|
match action_type {
|
|
0 => rlp.val_at(1).map(Res::Call),
|
|
1 => rlp.val_at(1).map(Res::Create),
|
|
2 => rlp.val_at(1).map(Res::FailedCall),
|
|
3 => rlp.val_at(1).map(Res::FailedCreate),
|
|
4 => Ok(Res::None),
|
|
_ => Err(DecoderError::Custom("Invalid result type.")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Res {
|
|
/// Returns result bloom.
|
|
pub fn bloom(&self) -> LogBloom {
|
|
match *self {
|
|
Res::Create(ref create) => create.bloom(),
|
|
Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Did this call fail?
|
|
pub fn succeeded(&self) -> bool {
|
|
match *self {
|
|
Res::Call(_) | Res::Create(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
/// A diff of some chunk of memory.
|
|
pub struct MemoryDiff {
|
|
/// Offset into memory the change begins.
|
|
pub offset: usize,
|
|
/// The changed data.
|
|
pub data: Bytes,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
/// A diff of some storage value.
|
|
pub struct StorageDiff {
|
|
/// Which key in storage is changed.
|
|
pub location: U256,
|
|
/// What the value has been changed to.
|
|
pub value: U256,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
|
|
/// A record of an executed VM operation.
|
|
pub struct VMExecutedOperation {
|
|
/// The total gas used.
|
|
pub gas_used: U256,
|
|
/// The stack item placed, if any.
|
|
pub stack_push: Vec<U256>,
|
|
/// If altered, the memory delta.
|
|
pub mem_diff: Option<MemoryDiff>,
|
|
/// The altered storage value, if any.
|
|
pub store_diff: Option<StorageDiff>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)]
|
|
/// 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,
|
|
/// Information concerning the execution of the operation.
|
|
pub executed: Option<VMExecutedOperation>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)]
|
|
/// A record of a full VM trace for a CALL/CREATE.
|
|
pub struct VMTrace {
|
|
/// 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.
|
|
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>,
|
|
}
|