openethereum/ethcore/src/trace/types/trace.rs

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>,
}