Tracing implemented.
TODO: - make it optional; - track output; - usher through to level higher than ExecutionResult.
This commit is contained in:
parent
2309e19fd9
commit
bd338a5741
@ -65,7 +65,7 @@ pub enum Error {
|
||||
|
||||
/// Evm result.
|
||||
///
|
||||
/// Returns gas_left if execution is successfull, otherwise error.
|
||||
/// Returns gas_left if execution is successful, otherwise error.
|
||||
pub type Result = result::Result<U256, Error>;
|
||||
|
||||
/// Evm interface.
|
||||
|
@ -41,26 +41,34 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
||||
pub struct Executed {
|
||||
/// Gas paid up front for execution of transaction.
|
||||
pub gas: U256,
|
||||
|
||||
/// Gas used during execution of transaction.
|
||||
pub gas_used: U256,
|
||||
|
||||
/// Gas refunded after the execution of transaction.
|
||||
/// To get gas that was required up front, add `refunded` and `gas_used`.
|
||||
pub refunded: U256,
|
||||
|
||||
/// Cumulative gas used in current block so far.
|
||||
///
|
||||
/// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)`
|
||||
///
|
||||
/// where `tn` is current transaction.
|
||||
pub cumulative_gas_used: U256,
|
||||
|
||||
/// Vector of logs generated by transaction.
|
||||
pub logs: Vec<LogEntry>,
|
||||
|
||||
/// Addresses of contracts created during execution of transaction.
|
||||
/// Ordered from earliest creation.
|
||||
///
|
||||
/// eg. sender creates contract A and A in constructor creates contract B
|
||||
///
|
||||
/// B creation ends first, and it will be the first element of the vector.
|
||||
pub contracts_created: Vec<Address>
|
||||
pub contracts_created: Vec<Address>,
|
||||
|
||||
/// The trace of this transaction.
|
||||
pub trace: Vec<TraceItem>,
|
||||
}
|
||||
|
||||
/// Transaction execution result.
|
||||
@ -71,7 +79,7 @@ pub struct Executive<'a> {
|
||||
state: &'a mut State,
|
||||
info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
depth: usize
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl<'a> Executive<'a> {
|
||||
@ -243,13 +251,20 @@ impl<'a> Executive<'a> {
|
||||
// part of substate that may be reverted
|
||||
let mut unconfirmed_substate = Substate::new();
|
||||
|
||||
let mut action = TraceAction::from_call(¶ms);
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output))
|
||||
};
|
||||
|
||||
if let TraceAction::Call(ref mut c) = action {
|
||||
c.result = res.as_ref().ok().map(|gas_left| c.gas - *gas_left);
|
||||
}
|
||||
|
||||
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
|
||||
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||
self.enact_result(&res, substate, unconfirmed_substate);
|
||||
|
||||
self.enact_result(&res, substate, unconfirmed_substate, action);
|
||||
trace!("exec: new substate={:?}\n", substate);
|
||||
res
|
||||
} else {
|
||||
@ -278,10 +293,18 @@ impl<'a> Executive<'a> {
|
||||
self.state.new_contract(¶ms.address, prev_bal);
|
||||
}
|
||||
|
||||
let mut action = TraceAction::from_create(¶ms);
|
||||
let created = params.address.clone();
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract)
|
||||
};
|
||||
self.enact_result(&res, substate, unconfirmed_substate);
|
||||
|
||||
if let TraceAction::Create(ref mut c) = action {
|
||||
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created));
|
||||
}
|
||||
|
||||
self.enact_result(&res, substate, unconfirmed_substate, action);
|
||||
res
|
||||
}
|
||||
|
||||
@ -326,7 +349,8 @@ impl<'a> Executive<'a> {
|
||||
refunded: U256::zero(),
|
||||
cumulative_gas_used: self.info.gas_used + t.gas,
|
||||
logs: vec![],
|
||||
contracts_created: vec![]
|
||||
contracts_created: vec![],
|
||||
trace: substate.trace,
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
@ -337,12 +361,13 @@ impl<'a> Executive<'a> {
|
||||
cumulative_gas_used: self.info.gas_used + gas_used,
|
||||
logs: substate.logs,
|
||||
contracts_created: substate.contracts_created,
|
||||
trace: substate.trace,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) {
|
||||
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, action: TraceAction) {
|
||||
match *result {
|
||||
Err(evm::Error::OutOfGas)
|
||||
| Err(evm::Error::BadJumpDestination {..})
|
||||
@ -353,7 +378,7 @@ impl<'a> Executive<'a> {
|
||||
},
|
||||
Ok(_) | Err(evm::Error::Internal) => {
|
||||
self.state.clear_snapshot();
|
||||
substate.accrue(un_substate)
|
||||
substate.accrue(un_substate, action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,43 +17,110 @@
|
||||
//! Execution environment substate.
|
||||
use common::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TraceCall {
|
||||
pub from: Address,
|
||||
pub to: Address,
|
||||
pub value: U256,
|
||||
pub gas: U256,
|
||||
pub input: Bytes,
|
||||
pub result: Option<U256>,
|
||||
// pub output: Bytes,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TraceCreate {
|
||||
pub from: Address,
|
||||
pub value: U256,
|
||||
pub gas: U256,
|
||||
pub init: Bytes,
|
||||
pub result: Option<(U256, Address)>,
|
||||
// pub output: Bytes,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TraceAction {
|
||||
Unknown,
|
||||
Call(TraceCall),
|
||||
Create(TraceCreate),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TraceItem {
|
||||
pub action: TraceAction,
|
||||
pub subs: Vec<TraceItem>,
|
||||
}
|
||||
|
||||
impl Default for TraceItem {
|
||||
fn default() -> TraceItem {
|
||||
TraceItem {
|
||||
action: TraceAction::Unknown,
|
||||
subs: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// State changes which should be applied in finalize,
|
||||
/// after transaction is fully executed.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Substate {
|
||||
/// Any accounts that have suicided.
|
||||
pub suicides: HashSet<Address>,
|
||||
|
||||
/// Any logs.
|
||||
pub logs: Vec<LogEntry>,
|
||||
|
||||
/// Refund counter of SSTORE nonzero -> zero.
|
||||
pub sstore_clears_count: U256,
|
||||
/// Created contracts.
|
||||
pub contracts_created: Vec<Address>
|
||||
}
|
||||
|
||||
impl Default for Substate {
|
||||
fn default() -> Self {
|
||||
Substate::new()
|
||||
}
|
||||
/// Created contracts.
|
||||
pub contracts_created: Vec<Address>,
|
||||
|
||||
/// The trace during this execution.
|
||||
pub trace: Vec<TraceItem>,
|
||||
}
|
||||
|
||||
impl Substate {
|
||||
/// Creates new substate.
|
||||
pub fn new() -> Self {
|
||||
Substate {
|
||||
suicides: HashSet::new(),
|
||||
logs: vec![],
|
||||
sstore_clears_count: U256::zero(),
|
||||
contracts_created: vec![]
|
||||
}
|
||||
Substate::default()
|
||||
}
|
||||
|
||||
/// Merge secondary substate `s` into self, accruing each element correspondingly.
|
||||
pub fn accrue(&mut self, s: Substate) {
|
||||
pub fn accrue(&mut self, s: Substate, action: TraceAction) {
|
||||
self.suicides.extend(s.suicides.into_iter());
|
||||
self.logs.extend(s.logs.into_iter());
|
||||
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
|
||||
self.contracts_created.extend(s.contracts_created.into_iter());
|
||||
self.trace.push(TraceItem {
|
||||
action: action,
|
||||
subs: s.trace,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl TraceAction {
|
||||
pub fn from_call(p: &ActionParams) -> TraceAction {
|
||||
TraceAction::Call(TraceCall {
|
||||
from: p.sender.clone(),
|
||||
to: p.address.clone(),
|
||||
value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() },
|
||||
gas: p.gas.clone(),
|
||||
input: p.data.clone().unwrap_or(vec![]),
|
||||
result: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_create(p: &ActionParams) -> TraceAction {
|
||||
TraceAction::Create(TraceCreate {
|
||||
from: p.sender.clone(),
|
||||
value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() },
|
||||
gas: p.gas.clone(),
|
||||
init: p.data.clone().unwrap_or(vec![]),
|
||||
result: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user