diff --git a/runtime/src/eval/system.rs b/runtime/src/eval/system.rs index a23966c2a..382109e86 100644 --- a/runtime/src/eval/system.rs +++ b/runtime/src/eval/system.rs @@ -8,6 +8,14 @@ use core::cmp::min; use primitive_types::{H256, U256}; use sha3::{Digest, Keccak256}; +pub fn u8_vec_to_hex(to_convert: &Vec) -> String { + let mut hex_string = String::new(); + for byte in to_convert { + hex_string.push_str(&format!("{:02x}", byte)); + } + hex_string +} + pub fn sha3(runtime: &mut Runtime) -> Control { pop_u256!(runtime, from, len); @@ -258,6 +266,12 @@ pub fn log(runtime: &mut Runtime, n: u8, handler: &mut H) -> Control pub fn suicide(runtime: &mut Runtime, handler: &mut H) -> Control { pop!(runtime, target); + event!(TransactSuicide { + address: runtime.context.address, + target: target.into(), + balance: handler.balance(runtime.context.address), + }); + match handler.mark_delete(runtime.context.address, target.into()) { Ok(()) => (), Err(e) => return Control::Exit(e.into()), @@ -295,9 +309,23 @@ pub fn create(runtime: &mut Runtime, is_create2: bool, handler: &mut } }; + event!(TransactCreate { + call_type: &(if is_create2 { + "CREATE2".to_string() + } else { + "CREATE".to_string() + }), + address: runtime.context.address, + target: handler.get_create_address(scheme).into(), + balance: value, + is_create2: is_create2, + input: &format!("0x{:}", u8_vec_to_hex(&code)), + }); + match handler.create(runtime.context.address, scheme, value, code, None) { Capture::Exit((reason, address, return_data)) => { runtime.return_data_buffer = return_data; + let create_address: H256 = address.map(|a| a.into()).unwrap_or_default(); match reason { @@ -399,6 +427,20 @@ pub fn call(runtime: &mut Runtime, scheme: CallScheme, handler: &mut None }; + let target = if scheme == CallScheme::CallCode { + runtime.context.address + } else { + to.into() + }; + + event!(TransactTransfer { + call_type: &format!("{:?}", scheme).to_uppercase(), + address: runtime.context.address, + target: target.into(), + balance: value, + input: &format!("0x{:}", u8_vec_to_hex(&input)), + }); + match handler.call( to.into(), transfer, diff --git a/runtime/src/handler.rs b/runtime/src/handler.rs index 75413d97e..ef1e9d481 100644 --- a/runtime/src/handler.rs +++ b/runtime/src/handler.rs @@ -88,6 +88,10 @@ pub trait Handler { init_code: Vec, target_gas: Option, ) -> Capture<(ExitReason, Option, Vec), Self::CreateInterrupt>; + + /// Calculate the create or create2 address + fn get_create_address(&mut self, scheme: CreateScheme) -> H160; + /// Feed in create feedback. fn create_feedback(&mut self, _feedback: Self::CreateFeedback) -> Result<(), ExitError> { Ok(()) diff --git a/runtime/src/tracing.rs b/runtime/src/tracing.rs index 4f17f5619..4d5ff38a8 100644 --- a/runtime/src/tracing.rs +++ b/runtime/src/tracing.rs @@ -1,7 +1,7 @@ //! Allows to listen to runtime events. use crate::{Capture, Context, ExitReason, Memory, Opcode, Stack, Trap}; -use primitive_types::{H160, H256}; +use primitive_types::{H160, H256, U256}; environmental::environmental!(listener: dyn EventListener + 'static); @@ -32,6 +32,26 @@ pub enum Event<'a> { index: H256, value: H256, }, + TransactSuicide { + address: H160, + target: H160, + balance: U256, + }, + TransactTransfer { + call_type: &'a String, + address: H160, + target: H160, + balance: U256, + input: &'a String, + }, + TransactCreate { + call_type: &'a String, + address: H160, + target: H160, + balance: U256, + is_create2: bool, + input: &'a String, + }, } // Expose `listener::with` to the crate only. diff --git a/src/executor/stack/executor.rs b/src/executor/stack/executor.rs index 1f989147e..4a60702ee 100644 --- a/src/executor/stack/executor.rs +++ b/src/executor/stack/executor.rs @@ -1150,6 +1150,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler capture } + fn get_create_address(&mut self, scheme: CreateScheme) -> H160 { + self.create_address(scheme) + } + #[cfg(not(feature = "tracing"))] fn call( &mut self,