From 7da8003f451f93d0bbb6f9f310dbcba4a36fd44b Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Nov 2019 16:45:27 +1100 Subject: [PATCH] Add fork choice persistence --- beacon_node/beacon_chain/src/beacon_chain.rs | 1 + beacon_node/beacon_chain/src/builder.rs | 32 +++++++++++-------- beacon_node/beacon_chain/src/fork_choice.rs | 8 +++++ .../src/persisted_beacon_chain.rs | 1 + beacon_node/beacon_chain/src/test_utils.rs | 4 +-- beacon_node/client/src/builder.rs | 2 +- eth2/lmd_ghost/src/lib.rs | 2 +- eth2/lmd_ghost/src/reduced_tree.rs | 4 +-- 8 files changed, 34 insertions(+), 20 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index c83e96b6e5..1e1d7e9ebe 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -145,6 +145,7 @@ impl BeaconChain { op_pool: PersistedOperationPool::from_operation_pool(&self.op_pool), genesis_block_root: self.genesis_block_root, ssz_head_tracker: self.head_tracker.to_ssz_container(), + fork_choice_ssz_bytes: self.fork_choice.as_bytes(), }; let key = Hash256::from_slice(&BEACON_CHAIN_DB_KEY.as_bytes()); diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index fffdf8ace7..620b996f7c 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -388,9 +388,7 @@ where event_handler: self .event_handler .ok_or_else(|| "Cannot build without an event handler".to_string())?, - head_tracker: self - .head_tracker - .ok_or_else(|| "Cannot build without a head tracker".to_string())?, + head_tracker: self.head_tracker.unwrap_or_default(), log: log.clone(), }; @@ -430,21 +428,27 @@ where /// `ThreadSafeReducedTree` backend. /// /// Requires the store and state to be initialized. - pub fn empty_reduced_tree_fork_choice(self) -> Result { + pub fn reduced_tree_fork_choice(self) -> Result { let store = self .store .clone() .ok_or_else(|| "reduced_tree_fork_choice requires a store")?; - let finalized_checkpoint = &self - .finalized_checkpoint - .as_ref() - .expect("should have finalized checkpoint"); - let backend = ThreadSafeReducedTree::new( - store.clone(), - &finalized_checkpoint.beacon_block, - finalized_checkpoint.beacon_block_root, - ); + let backend = if let Some(persisted_beacon_chain) = &self.persisted_beacon_chain { + ThreadSafeReducedTree::from_bytes(&persisted_beacon_chain.fork_choice_ssz_bytes, store) + .map_err(|e| format!("Unable to decode fork choice from db: {:?}", e))? + } else { + let finalized_checkpoint = &self + .finalized_checkpoint + .as_ref() + .expect("should have finalized checkpoint"); + + ThreadSafeReducedTree::new( + store.clone(), + &finalized_checkpoint.beacon_block, + finalized_checkpoint.beacon_block_root, + ) + }; self.fork_choice_backend(backend) } @@ -623,7 +627,7 @@ mod test { .null_event_handler() .testing_slot_clock(Duration::from_secs(1)) .expect("should configure testing slot clock") - .empty_reduced_tree_fork_choice() + .reduced_tree_fork_choice() .expect("should add fork choice to builder") .build() .expect("should build"); diff --git a/beacon_node/beacon_chain/src/fork_choice.rs b/beacon_node/beacon_chain/src/fork_choice.rs index 9f9277693f..78b582828b 100644 --- a/beacon_node/beacon_chain/src/fork_choice.rs +++ b/beacon_node/beacon_chain/src/fork_choice.rs @@ -291,6 +291,14 @@ impl ForkChoice { .update_finalized_root(finalized_block, finalized_block_root) .map_err(Into::into) } + + /// Returns a byte-level representation of the present state of the fork choice cache. + /// + /// This simply calls `as_bytes()`, on the backend. To decode these bytes, decode the backend + /// directly then use `Self::new(..)`. + pub fn as_bytes(&self) -> Vec { + self.backend.as_bytes() + } } impl From for Error { diff --git a/beacon_node/beacon_chain/src/persisted_beacon_chain.rs b/beacon_node/beacon_chain/src/persisted_beacon_chain.rs index c88372bf8f..c98dbeec14 100644 --- a/beacon_node/beacon_chain/src/persisted_beacon_chain.rs +++ b/beacon_node/beacon_chain/src/persisted_beacon_chain.rs @@ -15,6 +15,7 @@ pub struct PersistedBeaconChain { pub op_pool: PersistedOperationPool, pub genesis_block_root: Hash256, pub ssz_head_tracker: SszHeadTracker, + pub fork_choice_ssz_bytes: Vec, } impl SimpleStoreItem for PersistedBeaconChain { diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 6916982e0a..c52630e4f6 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -100,7 +100,7 @@ impl BeaconChainHarness> { .null_event_handler() .testing_slot_clock(Duration::from_secs(1)) .expect("should configure testing slot clock") - .empty_reduced_tree_fork_choice() + .reduced_tree_fork_choice() .expect("should add fork choice to builder") .build() .expect("should build"); @@ -142,7 +142,7 @@ impl BeaconChainHarness> { .null_event_handler() .testing_slot_clock(Duration::from_secs(1)) .expect("should configure testing slot clock") - .empty_reduced_tree_fork_choice() + .reduced_tree_fork_choice() .expect("should add fork choice to builder") .build() .expect("should build"); diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 84e9feff00..234761e51d 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -498,7 +498,7 @@ where .clone() .ok_or_else(|| "beacon_chain requires a slot clock")?, ) - .empty_reduced_tree_fork_choice() + .reduced_tree_fork_choice() .map_err(|e| format!("Failed to init fork choice: {}", e))? .build() .map_err(|e| format!("Failed to build beacon chain: {}", e))?; diff --git a/eth2/lmd_ghost/src/lib.rs b/eth2/lmd_ghost/src/lib.rs index 0cec0a3616..c5fd95bc55 100644 --- a/eth2/lmd_ghost/src/lib.rs +++ b/eth2/lmd_ghost/src/lib.rs @@ -54,7 +54,7 @@ pub trait LmdGhost: Send + Sync + Sized { fn verify_integrity(&self) -> Result<()>; /// Encode the `LmdGhost` instance to bytes. - fn as_bytes(self) -> Vec; + fn as_bytes(&self) -> Vec; /// Create a new `LmdGhost` instance given a `store` and encoded bytes. fn from_bytes(bytes: &[u8], store: Arc) -> Result; diff --git a/eth2/lmd_ghost/src/reduced_tree.rs b/eth2/lmd_ghost/src/reduced_tree.rs index a841378363..c6cb71a334 100644 --- a/eth2/lmd_ghost/src/reduced_tree.rs +++ b/eth2/lmd_ghost/src/reduced_tree.rs @@ -121,8 +121,8 @@ where } /// Consume the `ReducedTree` object and return its ssz encoded bytes representation. - fn as_bytes(self) -> Vec { - self.core.into_inner().as_bytes() + fn as_bytes(&self) -> Vec { + self.core.read().as_bytes() } /// Create a new `ThreadSafeReducedTree` instance from a `store` and the