diff --git a/client/consensus/common/src/level_monitor.rs b/client/consensus/common/src/level_monitor.rs index 294527f1f9f..4f344b505a7 100644 --- a/client/consensus/common/src/level_monitor.rs +++ b/client/consensus/common/src/level_monitor.rs @@ -15,7 +15,7 @@ // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. use sc_client_api::{blockchain::Backend as _, Backend, HeaderBackend as _}; -use sp_blockchain::{HashAndNumber, TreeRoute}; +use sp_blockchain::{HashAndNumber, HeaderMetadata, TreeRoute}; use sp_runtime::traits::{Block as BlockT, NumberFor, One, Saturating, UniqueSaturatedInto, Zero}; use std::{ collections::{HashMap, HashSet}, @@ -48,17 +48,17 @@ pub enum LevelLimit { /// Support structure to constrain the number of leaves at each level. pub struct LevelMonitor<Block: BlockT, BE> { - // Max number of leaves for each level. + /// Max number of leaves for each level. level_limit: usize, - // Monotonic counter used to keep track of block freshness. + /// Monotonic counter used to keep track of block freshness. pub(crate) import_counter: NumberFor<Block>, - // Map between blocks hashes and freshness. + /// Map between blocks hashes and freshness. pub(crate) freshness: HashMap<Block::Hash, NumberFor<Block>>, - // Blockchain levels cache. + /// Blockchain levels cache. pub(crate) levels: HashMap<NumberFor<Block>, HashSet<Block::Hash>>, - // Lower level number stored by the levels map. + /// Lower level number stored by the levels map. lowest_level: NumberFor<Block>, - // Backend reference to remove blocks on level saturation. + /// Backend reference to remove blocks on level saturation. backend: Arc<BE>, } @@ -96,7 +96,9 @@ where /// /// Level limits are not enforced during this phase. fn restore(&mut self) { + const ERR_MSG: &str = "route from finalized to leaf should be available; qed"; let info = self.backend.blockchain().info(); + log::debug!( target: "parachain", "Restoring chain level monitor from last finalized block: {} {}", @@ -105,30 +107,24 @@ where self.lowest_level = info.finalized_number; self.import_counter = info.finalized_number; - self.block_imported(info.finalized_number, info.finalized_hash); - - let mut counter_max = info.finalized_number; for leaf in self.backend.blockchain().leaves().unwrap_or_default() { - let route = - sp_blockchain::tree_route(self.backend.blockchain(), info.finalized_hash, leaf) - .expect("Route from finalized to leaf should be available; qed"); - if !route.retracted().is_empty() { - continue - } - route.enacted().iter().for_each(|elem| { - if !self.freshness.contains_key(&elem.hash) { - // Use the block height value as the freshness. - self.import_counter = elem.number; - self.block_imported(elem.number, elem.hash); + let mut meta = self.backend.blockchain().header_metadata(leaf).expect(ERR_MSG); + + self.import_counter = self.import_counter.max(meta.number); + + // Populate the monitor until we don't hit an already imported branch + while !self.freshness.contains_key(&meta.hash) { + self.freshness.insert(meta.hash, meta.number); + self.levels.entry(meta.number).or_default().insert(meta.hash); + if meta.number <= self.lowest_level { + break } - }); - counter_max = std::cmp::max(self.import_counter, counter_max); + meta = self.backend.blockchain().header_metadata(meta.parent).expect(ERR_MSG); + } } - log::debug!(target: "parachain", "Restored chain level monitor up to height {}", counter_max); - - self.import_counter = counter_max; + log::debug!(target: "parachain", "Restored chain level monitor up to height {}", self.import_counter); } /// Check and enforce the limit bound at the given height. @@ -355,9 +351,9 @@ where /// Add a new imported block information to the monitor. pub fn block_imported(&mut self, number: NumberFor<Block>, hash: Block::Hash) { + self.import_counter += One::one(); self.freshness.insert(hash, self.import_counter); self.levels.entry(number).or_default().insert(hash); - self.import_counter += One::one(); // Do cleanup once in a while, we are allowed to have some obsolete information. let finalized_num = self.backend.blockchain().info().finalized_number; diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index e44c26e85d1..23516d96388 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -765,6 +765,12 @@ fn restore_limit_monitor() { LevelLimit::Some(LEVEL_LIMIT), ); + let monitor_sd = para_import.monitor.clone().unwrap(); + + let monitor = monitor_sd.shared_data(); + assert_eq!(monitor.import_counter, 3); + std::mem::drop(monitor); + let block13 = build_and_import_block_ext( &*client, BlockOrigin::Own, @@ -783,14 +789,13 @@ fn restore_limit_monitor() { let expected = vec![blocks1[1].header.hash(), block13.header.hash()]; assert_eq!(leaves, expected); - let monitor = para_import.monitor.unwrap(); - let monitor = monitor.shared_data(); - assert_eq!(monitor.import_counter, 5); + let monitor = monitor_sd.shared_data(); + assert_eq!(monitor.import_counter, 4); assert!(monitor.levels.iter().all(|(number, hashes)| { hashes .iter() .filter(|hash| **hash != block13.header.hash()) .all(|hash| *number == *monitor.freshness.get(hash).unwrap()) })); - assert_eq!(*monitor.freshness.get(&block13.header.hash()).unwrap(), monitor.import_counter - 1); + assert_eq!(*monitor.freshness.get(&block13.header.hash()).unwrap(), monitor.import_counter); }