[Trace] Distinguish between create and create2 (#11311)

* adding a CreateType to ActionParams

* rename calltype to action type

* comments & line lengths

* rebame ActionParams.call_type

* Making call/create type optional

* Moving strict create/call type into trace package instead of storing loosely typed action type

* fix build

* Deriving ActionType from address_scheme in ext.create

* trigger build

* more detailed comments

* Change actions_type to call in vmtests

* skipping serialization for Option::None and using TryFrom instead of maybe_new

* retrigger build

* trigger build
This commit is contained in:
Felix Leupold
2020-01-13 11:10:24 +01:00
committed by Andronik Ordian
parent e95bbe36cb
commit 87e1080581
23 changed files with 290 additions and 148 deletions

View File

@@ -374,13 +374,12 @@ mod tests {
use ethcore::test_helpers::new_db;
use ethereum_types::{H256, U256, Address};
use evm::CallType;
use kvdb::DBTransaction;
use crate::{
BlockNumber, Config, TraceDB, Database as TraceDatabase, ImportRequest, DatabaseExtras,
Filter, LocalizedTrace, AddressesFilter, TraceError,
trace::{Call, Action, Res},
trace::{Call, CallType, Action, Res},
flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces}
};
@@ -465,7 +464,7 @@ mod tests {
value: 3.into(),
gas: 4.into(),
input: vec![],
call_type: CallType::Call,
call_type: Some(CallType::Call),
}),
result: Res::FailedCall(TraceError::OutOfGas),
}])]),
@@ -487,7 +486,7 @@ mod tests {
value: 3.into(),
gas: 4.into(),
input: vec![],
call_type: CallType::Call,
call_type: Some(CallType::Call),
}),
result: Res::FailedCall(TraceError::OutOfGas),
}])]),
@@ -506,7 +505,7 @@ mod tests {
value: U256::from(3),
gas: U256::from(4),
input: vec![],
call_type: CallType::Call,
call_type: Some(CallType::Call),
}),
result: Res::FailedCall(TraceError::OutOfGas),
trace_address: vec![],

View File

@@ -125,10 +125,9 @@ impl Filter {
#[cfg(test)]
mod tests {
use ethereum_types::{Address, Bloom, BloomInput};
use evm::CallType;
use crate::{
Filter, AddressesFilter, TraceError, RewardType,
trace::{Action, Call, Res, Create, CreateResult, Suicide, Reward},
trace::{Action, Call, CallType, Res, Create, CreationMethod, CreateResult, Suicide, Reward},
flat::FlatTrace,
};
@@ -273,7 +272,7 @@ mod tests {
value: 3.into(),
gas: 4.into(),
input: vec![0x5],
call_type: CallType::Call,
call_type: Some(CallType::Call),
}),
result: Res::FailedCall(TraceError::OutOfGas),
trace_address: vec![0].into_iter().collect(),
@@ -294,6 +293,7 @@ mod tests {
value: 3.into(),
gas: 4.into(),
init: vec![0x5],
creation_method: Some(CreationMethod::Create),
}),
result: Res::Create(CreateResult {
gas_used: 10.into(),
@@ -413,6 +413,7 @@ mod tests {
gas: 4.into(),
init: vec![0x5],
value: 3.into(),
creation_method: Some(CreationMethod::Create),
}),
result: Res::FailedCall(TraceError::BadInstruction),
trace_address: vec![].into_iter().collect(),

View File

@@ -123,9 +123,8 @@ mod tests {
use rlp::*;
use crate::{
FlatBlockTraces, FlatTransactionTraces, FlatTrace,
trace::{Action, Res, CallResult, Call, Suicide, Reward, RewardType}
trace::{Action, Res, CallResult, Call, CallType, Suicide, Reward, RewardType}
};
use evm::CallType;
#[test]
fn encode_flat_transaction_traces() {
@@ -162,7 +161,7 @@ mod tests {
value: "3627e8f712373c0000".parse().unwrap(),
gas: 0x03e8.into(),
input: vec![],
call_type: CallType::Call,
call_type: Some(CallType::Call),
}),
result: Res::Call(CallResult {
gas_used: 0.into(),
@@ -179,7 +178,7 @@ mod tests {
value: 0.into(),
gas: 0x010c78.into(),
input: vec![0x41, 0xc0, 0xe1, 0xb5],
call_type: CallType::Call,
call_type: Some(CallType::Call),
}),
result: Res::Call(CallResult {
gas_used: 0x0127.into(),

View File

@@ -16,12 +16,13 @@
//! Tracing data types.
use std::convert::TryFrom;
use ethereum_types::{U256, Address, Bloom, BloomInput};
use parity_bytes::Bytes;
use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable};
use rlp_derive::{RlpEncodable, RlpDecodable};
use vm::ActionParams;
use evm::CallType;
use evm::ActionType;
use super::error::Error;
/// `Call` result.
@@ -33,6 +34,57 @@ pub struct CallResult {
pub output: Bytes,
}
/// `Call` type. Distinguish between different types of contract interactions.
#[derive(Debug, Clone, PartialEq)]
pub enum CallType {
/// Call
Call,
/// Call code
CallCode,
/// Delegate call
DelegateCall,
/// Static call
StaticCall,
}
impl TryFrom<ActionType> for CallType {
type Error = &'static str;
fn try_from(action_type: ActionType) -> Result<Self, Self::Error> {
match action_type {
ActionType::Call => Ok(CallType::Call),
ActionType::CallCode => Ok(CallType::CallCode),
ActionType::DelegateCall => Ok(CallType::DelegateCall),
ActionType::StaticCall => Ok(CallType::StaticCall),
ActionType::Create => Err("Create cannot be converted to CallType"),
ActionType::Create2 => Err("Create2 cannot be converted to CallType"),
}
}
}
impl Encodable for CallType {
fn rlp_append(&self, s: &mut RlpStream) {
let v = match *self {
CallType::Call => 0u32,
CallType::CallCode => 1,
CallType::DelegateCall => 2,
CallType::StaticCall => 3,
};
Encodable::rlp_append(&v, s);
}
}
impl Decodable for CallType {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
rlp.as_val().and_then(|v| Ok(match v {
0u32 => CallType::Call,
1 => CallType::CallCode,
2 => CallType::DelegateCall,
3 => CallType::StaticCall,
_ => return Err(DecoderError::Custom("Invalid value of RewardType item")),
}))
}
}
/// `Create` result.
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
pub struct CreateResult {
@@ -51,6 +103,49 @@ impl CreateResult {
}
}
/// `Create` method. Distinguish between use of `CREATE` and `CREATE2` opcodes in an action.
#[derive(Debug, Clone, PartialEq)]
pub enum CreationMethod {
/// Create
Create,
/// Create2
Create2,
}
impl TryFrom<ActionType> for CreationMethod {
type Error = &'static str;
fn try_from(action_type: ActionType) -> Result<Self, Self::Error> {
match action_type {
ActionType::Call => Err("Call cannot be converted to CreationMethod"),
ActionType::CallCode => Err("CallCode cannot be converted to CreationMethod"),
ActionType::DelegateCall => Err("DelegateCall cannot be converted to CreationMethod"),
ActionType::StaticCall => Err("StaticCall cannot be converted to CreationMethod"),
ActionType::Create => Ok(CreationMethod::Create),
ActionType::Create2 => Ok(CreationMethod::Create2),
}
}
}
impl Encodable for CreationMethod {
fn rlp_append(&self, s: &mut RlpStream) {
let v = match *self {
CreationMethod::Create => 0u32,
CreationMethod::Create2 => 1,
};
Encodable::rlp_append(&v, s);
}
}
impl Decodable for CreationMethod {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
rlp.as_val().and_then(|v| Ok(match v {
0u32 => CreationMethod::Create,
1 => CreationMethod::Create2,
_ => return Err(DecoderError::Custom("Invalid value of RewardType item")),
}))
}
}
/// Description of a _call_ action, either a `CALL` operation or a message transaction.
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
pub struct Call {
@@ -65,19 +160,19 @@ pub struct Call {
/// The input data provided to the call.
pub input: Bytes,
/// The type of the call.
pub call_type: CallType,
pub call_type: Option<CallType>,
}
impl From<ActionParams> for Call {
fn from(p: ActionParams) -> Self {
match p.call_type {
CallType::DelegateCall | CallType::CallCode => Call {
match p.action_type {
ActionType::DelegateCall | ActionType::CallCode => Call {
from: p.address,
to: p.code_address,
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
call_type: CallType::try_from(p.action_type).ok(),
},
_ => Call {
from: p.sender,
@@ -85,7 +180,7 @@ impl From<ActionParams> for Call {
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
call_type: CallType::try_from(p.action_type).ok(),
},
}
}
@@ -113,6 +208,8 @@ pub struct Create {
pub gas: U256,
/// The init code.
pub init: Bytes,
/// Creation method (CREATE vs CREATE2).
pub creation_method: Option<CreationMethod>,
}
impl From<ActionParams> for Create {
@@ -122,6 +219,7 @@ impl From<ActionParams> for Create {
value: p.value.value(),
gas: p.gas,
init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
creation_method: CreationMethod::try_from(p.action_type).ok(),
}
}
}