Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Tracing implemented. #772

Merged
merged 15 commits into from
Mar 19, 2016
58 changes: 36 additions & 22 deletions ethcore/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use state::*;
use verification::PreverifiedBlock;

/// A block, encoded as it is on the block chain.
// TODO: rename to Block
#[derive(Default, Debug, Clone)]
pub struct Block {
/// The header of this block.
Expand Down Expand Up @@ -76,15 +75,14 @@ impl Decodable for Block {
}

/// Internal type for a block's common elements.
// TODO: rename to ExecutedBlock
// TODO: use BareBlock
#[derive(Debug)]
pub struct ExecutedBlock {
base: Block,

receipts: Vec<Receipt>,
transactions_set: HashSet<H256>,
state: State,
traces: Option<Vec<Trace>>,
}

/// A set of references to `ExecutedBlock` fields that are publicly accessible.
Expand All @@ -99,11 +97,21 @@ pub struct BlockRefMut<'a> {
pub receipts: &'a Vec<Receipt>,
/// State.
pub state: &'a mut State,
/// Traces.
pub traces: &'a Option<Vec<Trace>>,
}

impl ExecutedBlock {
/// Create a new block from the given `state`.
fn new(state: State) -> ExecutedBlock { ExecutedBlock { base: Default::default(), receipts: Default::default(), transactions_set: Default::default(), state: state } }
fn new(state: State, tracing: bool) -> ExecutedBlock {
ExecutedBlock {
base: Default::default(),
receipts: Default::default(),
transactions_set: Default::default(),
state: state,
traces: if tracing {Some(Vec::new())} else {None},
}
}

/// Get a structure containing individual references to all public fields.
pub fn fields(&mut self) -> BlockRefMut {
Expand All @@ -113,6 +121,7 @@ impl ExecutedBlock {
uncles: &self.base.uncles,
state: &mut self.state,
receipts: &self.receipts,
traces: &self.traces,
}
}
}
Expand All @@ -134,6 +143,9 @@ pub trait IsBlock {
/// Get all information on receipts in this block.
fn receipts(&self) -> &Vec<Receipt> { &self.block().receipts }

/// Get all information concerning transaction tracing in this block.
fn traces(&self) -> &Option<Vec<Trace>> { &self.block().traces }

/// Get all uncles in this block.
fn uncles(&self) -> &Vec<Header> { &self.block().base.uncles }
}
Expand Down Expand Up @@ -171,9 +183,9 @@ pub struct SealedBlock {

impl<'x> OpenBlock<'x> {
/// Create a new OpenBlock ready for transaction pushing.
pub fn new(engine: &'x Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
pub fn new(engine: &'x Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
let mut r = OpenBlock {
block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())),
block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing),
engine: engine,
last_hashes: last_hashes,
};
Expand Down Expand Up @@ -249,11 +261,13 @@ impl<'x> OpenBlock<'x> {
pub fn push_transaction(&mut self, t: SignedTransaction, h: Option<H256>) -> Result<&Receipt, Error> {
let env_info = self.env_info();
// info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine, &t) {
Ok(receipt) => {
match self.block.state.apply(&env_info, self.engine, &t, self.block.traces.is_some()) {
Ok(outcome) => {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.base.transactions.push(t);
self.block.receipts.push(receipt);
let t = outcome.trace;
self.block.traces.as_mut().map(|traces| traces.push(t.expect("self.block.traces.is_some(): so we must be tracing: qed")));
self.block.receipts.push(outcome.receipt);
Ok(&self.block.receipts.last().unwrap())
}
Err(x) => Err(From::from(x))
Expand Down Expand Up @@ -339,15 +353,15 @@ impl IsBlock for SealedBlock {
}

/// Enact the block given by block header, transactions and uncles
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce());
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
}

let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone());
let mut b = OpenBlock::new(engine, tracing, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone());
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
Expand All @@ -357,22 +371,22 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head
}

/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes)
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes)
}

/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes)
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes)
}

/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<SealedBlock, Error> {
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal())))
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes)).seal(engine, header.seal())))
}

#[cfg(test)]
Expand All @@ -391,7 +405,7 @@ mod tests {
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let b = b.close();
let _ = b.seal(engine.deref(), vec![]);
}
Expand All @@ -405,14 +419,14 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();

let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()]).unwrap();

assert_eq!(e.rlp_bytes(), orig_bytes);

Expand All @@ -430,7 +444,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let mut open_block = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]);
let mut open_block = OpenBlock::new(engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]);
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
Expand All @@ -445,7 +459,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()]).unwrap();

let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);
Expand Down
6 changes: 6 additions & 0 deletions ethcore/src/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ impl Default for BlockChainConfig {

/// Interface for querying blocks by hash and by number.
pub trait BlockProvider {
/// True if we store full tracing information for transactions.
fn have_tracing(&self) -> bool;

/// Returns true if the given block is known
/// (though not necessarily a part of the canon chain).
fn is_known(&self, hash: &H256) -> bool;
Expand Down Expand Up @@ -177,6 +180,9 @@ impl BlockProvider for BlockChain {
self.query_extras_exist(hash, &self.block_details)
}

// We do not store tracing information.
fn have_tracing(&self) -> bool { false }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a stub for now - next PR for this feature will introduce processing logic into the Blockchain struct.


/// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes> {
{
Expand Down
3 changes: 2 additions & 1 deletion ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ impl<V> Client<V> where V: Verifier {
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().unwrap().spawn();

let enact_result = enact_verified(&block, engine, db, &parent, last_hashes);
let enact_result = enact_verified(&block, engine, self.chain.have_tracing(), db, &parent, last_hashes);
if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
Expand Down Expand Up @@ -398,6 +398,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {

let mut b = OpenBlock::new(
engine,
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().unwrap().spawn(),
match self.chain.block_header(&h) { Some(ref x) => x, None => {return None} },
self.build_last_hashes(h.clone()),
Expand Down
3 changes: 2 additions & 1 deletion ethcore/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ pub use account::*;
pub use transaction::*;
pub use log_entry::*;
pub use receipt::*;
pub use action_params::*;
pub use action_params::*;
pub use trace::*;
4 changes: 2 additions & 2 deletions ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ mod tests {
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
Expand All @@ -312,7 +312,7 @@ mod tests {
let mut db = db_result.take();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let mut b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/evm/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down