-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Various improvements to tracing & diagnostics. #1707
Changes from 2 commits
c097786
b59eb60
6ce475c
388269d
121836d
8c64692
904679c
909b044
3232e58
f0e418e
d7f76d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,8 +28,8 @@ pub struct PodAccount { | |
pub balance: U256, | ||
/// The nonce of the account. | ||
pub nonce: U256, | ||
/// The code of the account. | ||
pub code: Bytes, | ||
/// The code of the account or `None` in the special case that it is unknown. | ||
pub code: Option<Bytes>, | ||
/// The storage of the account. | ||
pub storage: BTreeMap<H256, H256>, | ||
} | ||
|
@@ -38,7 +38,7 @@ impl PodAccount { | |
/// Construct new object. | ||
#[cfg(test)] | ||
pub fn new(balance: U256, nonce: U256, code: Bytes, storage: BTreeMap<H256, H256>) -> PodAccount { | ||
PodAccount { balance: balance, nonce: nonce, code: code, storage: storage } | ||
PodAccount { balance: balance, nonce: nonce, code: Some(code), storage: storage } | ||
} | ||
|
||
/// Convert Account to a PodAccount. | ||
|
@@ -48,7 +48,7 @@ impl PodAccount { | |
balance: *acc.balance(), | ||
nonce: *acc.nonce(), | ||
storage: acc.storage_overlay().iter().fold(BTreeMap::new(), |mut m, (k, &(_, ref v))| {m.insert(k.clone(), v.clone()); m}), | ||
code: acc.code().unwrap().to_vec(), | ||
code: acc.code().map(|x| x.to_vec()), | ||
} | ||
} | ||
|
||
|
@@ -58,14 +58,15 @@ impl PodAccount { | |
stream.append(&self.nonce); | ||
stream.append(&self.balance); | ||
stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k.to_vec(), encode(&U256::from(v.as_slice())).to_vec())).collect())); | ||
stream.append(&self.code.sha3()); | ||
stream.append(&self.code.as_ref().unwrap_or(&vec![]).sha3()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
edit: or should, but the |
||
stream.out() | ||
} | ||
|
||
/// Place additional data into given hash DB. | ||
pub fn insert_additional(&self, db: &mut AccountDBMut) { | ||
if !self.code.is_empty() { | ||
db.insert(&self.code); | ||
match &self.code { | ||
&Some(ref c) if !c.is_empty() => { db.insert(c); } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. match self.code {
Some(ref c) ...
} should work. |
||
_ => {} | ||
} | ||
let mut r = H256::new(); | ||
let mut t = SecTrieDBMut::new(db, &mut r); | ||
|
@@ -80,7 +81,7 @@ impl From<ethjson::blockchain::Account> for PodAccount { | |
PodAccount { | ||
balance: a.balance.into(), | ||
nonce: a.nonce.into(), | ||
code: a.code.into(), | ||
code: Some(a.code.into()), | ||
storage: a.storage.into_iter().map(|(key, value)| { | ||
let key: U256 = key.into(); | ||
let value: U256 = value.into(); | ||
|
@@ -95,15 +96,15 @@ impl From<ethjson::spec::Account> for PodAccount { | |
PodAccount { | ||
balance: a.balance.map_or_else(U256::zero, Into::into), | ||
nonce: a.nonce.map_or_else(U256::zero, Into::into), | ||
code: vec![], | ||
code: Some(vec![]), | ||
storage: BTreeMap::new() | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for PodAccount { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len()) | ||
write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.as_ref().map_or(0, |c| c.len()), self.code.as_ref().map_or(H256::new(), |c| c.sha3()), self.storage.len()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
} | ||
|
||
|
@@ -114,13 +115,13 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A | |
(None, Some(x)) => Some(AccountDiff { | ||
balance: Diff::Born(x.balance), | ||
nonce: Diff::Born(x.nonce), | ||
code: Diff::Born(x.code.clone()), | ||
code: Diff::Born(x.code.as_ref().expect("account is newly created; newly created accounts must be given code; all caches should remain in place; qed").clone()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Born(v.clone()))).collect(), | ||
}), | ||
(Some(x), None) => Some(AccountDiff { | ||
balance: Diff::Died(x.balance), | ||
nonce: Diff::Died(x.nonce), | ||
code: Diff::Died(x.code.clone()), | ||
code: Diff::Died(x.code.as_ref().expect("account is deleted; only way to delete account is running SUICIDE; account must have had own code cached to make operation; all caches should remain in place; qed").clone()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Died(v.clone()))).collect(), | ||
}), | ||
(Some(pre), Some(post)) => { | ||
|
@@ -130,7 +131,10 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A | |
let r = AccountDiff { | ||
balance: Diff::new(pre.balance, post.balance), | ||
nonce: Diff::new(pre.nonce, post.nonce), | ||
code: Diff::new(pre.code.clone(), post.code.clone()), | ||
code: match (pre.code.clone(), post.code.clone()) { | ||
(Some(pre_code), Some(post_code)) => Diff::new(pre_code, post_code), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. match (pre.code, post.code) {
(Some(ref pre_code), Some(ref post_code)) => Diff::new(pre_code.clone(), post_code.clone()),
_ => Diff::Same,
} should work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nope - |
||
_ => Diff::Same, | ||
}, | ||
storage: storage.into_iter().map(|k| | ||
(k.clone(), Diff::new( | ||
pre.storage.get(&k).cloned().unwrap_or_else(H256::new), | ||
|
@@ -156,7 +160,7 @@ mod test { | |
|
||
#[test] | ||
fn existence() { | ||
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]}; | ||
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: Some(vec![]), storage: map![]}; | ||
assert_eq!(diff_pod(Some(&a), Some(&a)), None); | ||
assert_eq!(diff_pod(None, Some(&a)), Some(AccountDiff{ | ||
balance: Diff::Born(69.into()), | ||
|
@@ -168,8 +172,8 @@ mod test { | |
|
||
#[test] | ||
fn basic() { | ||
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]}; | ||
let b = PodAccount{balance: 42.into(), nonce: 1.into(), code: vec![], storage: map![]}; | ||
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: Some(vec![]), storage: map![]}; | ||
let b = PodAccount{balance: 42.into(), nonce: 1.into(), code: Some(vec![]), storage: map![]}; | ||
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff { | ||
balance: Diff::Changed(69.into(), 42.into()), | ||
nonce: Diff::Changed(0.into(), 1.into()), | ||
|
@@ -180,8 +184,8 @@ mod test { | |
|
||
#[test] | ||
fn code() { | ||
let a = PodAccount{balance: 0.into(), nonce: 0.into(), code: vec![], storage: map![]}; | ||
let b = PodAccount{balance: 0.into(), nonce: 1.into(), code: vec![0], storage: map![]}; | ||
let a = PodAccount{balance: 0.into(), nonce: 0.into(), code: Some(vec![]), storage: map![]}; | ||
let b = PodAccount{balance: 0.into(), nonce: 1.into(), code: Some(vec![0]), storage: map![]}; | ||
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff { | ||
balance: Diff::Same, | ||
nonce: Diff::Changed(0.into(), 1.into()), | ||
|
@@ -195,13 +199,13 @@ mod test { | |
let a = PodAccount { | ||
balance: 0.into(), | ||
nonce: 0.into(), | ||
code: vec![], | ||
code: Some(vec![]), | ||
storage: map_into![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0] | ||
}; | ||
let b = PodAccount { | ||
balance: 0.into(), | ||
nonce: 0.into(), | ||
code: vec![], | ||
code: Some(vec![]), | ||
storage: map_into![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9] | ||
}; | ||
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ use std::sync::{Weak, Arc}; | |
use jsonrpc_core::*; | ||
use std::collections::BTreeMap; | ||
//use util::H256; | ||
use util::rlp::{UntrustedRlp, View}; | ||
use ethcore::client::{BlockChainClient, CallAnalytics, TransactionID, TraceId}; | ||
use ethcore::miner::MinerService; | ||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; | ||
|
@@ -144,4 +145,40 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M: | |
Ok(Value::Null) | ||
}) | ||
} | ||
|
||
fn send_raw_transaction(&self, params: Params) -> Result<Value, Error> { | ||
try!(self.active()); | ||
trace!(target: "jsonrpc", "call: {:?}", params); | ||
from_params::<(Bytes, _)>(params) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Putting |
||
.and_then(|(raw_transaction, flags)| { | ||
let raw_transaction = raw_transaction.to_vec(); | ||
let flags: Vec<String> = flags; | ||
let analytics = CallAnalytics { | ||
transaction_tracing: flags.contains(&("trace".to_owned())), | ||
vm_tracing: flags.contains(&("vmTrace".to_owned())), | ||
state_diffing: flags.contains(&("stateDiff".to_owned())), | ||
}; | ||
match UntrustedRlp::new(&raw_transaction).as_val() { | ||
Ok(signed) => { | ||
let r = take_weak!(self.client).call(&signed, analytics); | ||
if let Ok(executed) = r { | ||
// TODO maybe add other stuff to this? | ||
let mut ret = map!["output".to_owned() => to_value(&Bytes(executed.output)).unwrap()]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a serializable struct instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if this code were to be refactored, it should be done in concert with prior trace function, and therefore is outside of this PR's scope. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with Tomek here. It should be a serializable struct. Imo it's a scope of this PR. |
||
if let Some(trace) = executed.trace { | ||
ret.insert("trace".to_owned(), to_value(&Trace::from(trace)).unwrap()); | ||
} | ||
if let Some(vm_trace) = executed.vm_trace { | ||
ret.insert("vmTrace".to_owned(), to_value(&VMTrace::from(vm_trace)).unwrap()); | ||
} | ||
if let Some(state_diff) = executed.state_diff { | ||
ret.insert("stateDiff".to_owned(), to_value(&StateDiff::from(state_diff)).unwrap()); | ||
} | ||
return Ok(Value::Object(ret)) | ||
} | ||
Ok(Value::Null) | ||
} | ||
Err(_) => Err(Error::invalid_params()), | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,9 @@ pub trait Traces: Sized + Send + Sync + 'static { | |
/// Executes the given call and returns a number of possible traces for it. | ||
fn call(&self, _: Params) -> Result<Value, Error>; | ||
|
||
/// Executes the given raw transaction and returns a number of possible traces for it. | ||
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does not actually send the transaction, does it? Perhaps |
||
|
||
/// Should be used to convert object to io delegate. | ||
fn to_delegate(self) -> IoDelegate<Self> { | ||
let mut delegate = IoDelegate::new(Arc::new(self)); | ||
|
@@ -43,6 +46,7 @@ pub trait Traces: Sized + Send + Sync + 'static { | |
delegate.add_method("trace_transaction", Traces::transaction_traces); | ||
delegate.add_method("trace_block", Traces::block_traces); | ||
delegate.add_method("trace_call", Traces::call); | ||
delegate.add_method("trace_sendRawTransaction", Traces::send_raw_transaction); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. name it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a transaction != a call. the naming follows conventions of the equivalent that said, i'm quite ambivalent; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
delegate | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will always display both warnings, maybe worth extracting the warnings somewhere above?