diff --git a/beacon_node/beacon_chain/src/dump.rs b/beacon_node/beacon_chain/src/dump.rs new file mode 100644 index 0000000000..e4cb0844a8 --- /dev/null +++ b/beacon_node/beacon_chain/src/dump.rs @@ -0,0 +1,72 @@ +use super::{BeaconChain, ClientDB, DBError, SlotClock}; +use types::{BeaconBlock, BeaconState, Hash256}; + +#[derive(Debug, Clone)] +pub struct SlotDump { + pub beacon_block: BeaconBlock, + pub beacon_block_root: Hash256, + pub beacon_state: BeaconState, + pub beacon_state_root: Hash256, +} + +#[derive(Debug, Clone)] +pub enum Error { + DBError(String), + MissingBlock(Hash256), +} + +impl BeaconChain +where + T: ClientDB, + U: SlotClock, +{ + pub fn chain_dump(&self) -> Result, Error> { + let mut dump = vec![]; + + let mut last_slot = SlotDump { + beacon_block: self.canonical_head().beacon_block.clone(), + beacon_block_root: self.canonical_head().beacon_block_root, + beacon_state: self.canonical_head().beacon_state.clone(), + beacon_state_root: self.canonical_head().beacon_state_root, + }; + + dump.push(last_slot.clone()); + + loop { + let beacon_block_root = last_slot.beacon_block.parent_root; + + if beacon_block_root == self.spec.zero_hash { + // Genesis has been reached. + break; + } + + let beacon_block = self + .block_store + .get_deserialized(&beacon_block_root)? + .ok_or_else(|| Error::MissingBlock(beacon_block_root))?; + let beacon_state_root = beacon_block.state_root; + let beacon_state = self + .state_store + .get_deserialized(&beacon_state_root)? + .ok_or_else(|| Error::MissingBlock(beacon_state_root))?; + + let slot = SlotDump { + beacon_block, + beacon_block_root, + beacon_state, + beacon_state_root, + }; + + dump.push(slot.clone()); + last_slot = slot; + } + + Ok(dump) + } +} + +impl From for Error { + fn from(e: DBError) -> Error { + Error::DBError(e.message) + } +} diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index e820c4b208..d6058eab76 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -3,6 +3,7 @@ mod block_graph; pub mod block_processing; pub mod block_production; mod canonical_head; +pub mod dump; mod finalized_head; mod info; mod lmd_ghost; diff --git a/beacon_node/beacon_chain/tests/chain.rs b/beacon_node/beacon_chain/tests/chain.rs index af1310cd6c..c4d8062656 100644 --- a/beacon_node/beacon_chain/tests/chain.rs +++ b/beacon_node/beacon_chain/tests/chain.rs @@ -12,4 +12,7 @@ fn it_can_produce_blocks() { for _ in 0..blocks { rig.produce_next_slot(); } + let dump = rig.chain_dump().expect("Chain dump failed."); + + assert_eq!(dump.len(), blocks + 1); // + 1 for genesis block. } diff --git a/beacon_node/beacon_chain/tests/utils/test_rig.rs b/beacon_node/beacon_chain/tests/utils/test_rig.rs index b6aef32901..a3a6417159 100644 --- a/beacon_node/beacon_chain/tests/utils/test_rig.rs +++ b/beacon_node/beacon_chain/tests/utils/test_rig.rs @@ -1,4 +1,5 @@ use super::TestValidator; +pub use beacon_chain::dump::{Error as DumpError, SlotDump}; use beacon_chain::BeaconChain; #[cfg(test)] use db::{ @@ -82,4 +83,8 @@ impl TestRig { self.validators[proposer].set_slot(slot); self.validators[proposer].produce_block().unwrap(); } + + pub fn chain_dump(&self) -> Result, DumpError> { + self.beacon_chain.chain_dump() + } }