From 7077ef38fac46e7d4033322ac41e33dbe599f0da Mon Sep 17 00:00:00 2001 From: gusto Date: Fri, 5 Jan 2024 11:21:59 +0200 Subject: [PATCH] Limit number of committed blocks in info requests (#552) * Limit number of committed blocks in info requests * Make carnot info limit configurable --- consensus/carnot-engine/src/lib.rs | 47 +++++++++++++++++----------- nomos-services/consensus/src/lib.rs | 4 +-- simulations/src/node/carnot/state.rs | 2 +- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/consensus/carnot-engine/src/lib.rs b/consensus/carnot-engine/src/lib.rs index 6a654351..328ce8c4 100644 --- a/consensus/carnot-engine/src/lib.rs +++ b/consensus/carnot-engine/src/lib.rs @@ -20,6 +20,7 @@ pub struct Carnot { safe_blocks: HashMap, tip: BlockId, last_view_timeout_qc: Option, + latest_committed_block: Option, overlay: O, } @@ -31,6 +32,7 @@ impl Carnot { id, highest_voted_view: View(-1), last_view_timeout_qc: None, + latest_committed_block: None, overlay, safe_blocks: [(genesis_block.id, genesis_block.clone())].into(), tip: genesis_block.id, @@ -99,6 +101,7 @@ impl Carnot { new_state.safe_blocks.insert(block.id, block.clone()); if block.view > new_state.tip().view { new_state.tip = block.id; + new_state.update_latest_committed_block(&block); } new_state.update_high_qc(block.parent_qc); } else { @@ -297,6 +300,12 @@ impl Carnot { } } + fn update_latest_committed_block(&mut self, block: &Block) { + if let Some(block) = self.can_commit_grandparent(block) { + self.latest_committed_block = Some(block.id); + } + } + pub fn blocks_in_view(&self, view: View) -> Vec { self.safe_blocks .iter() @@ -310,7 +319,7 @@ impl Carnot { } // Returns the id of the grandparent block if it can be committed or None otherwise - fn can_commit_grandparent(&self, block: Block) -> Option { + fn can_commit_grandparent(&self, block: &Block) -> Option { let parent = self.safe_blocks.get(&block.parent())?; let grandparent = self.safe_blocks.get(&parent.parent())?; @@ -324,33 +333,33 @@ impl Carnot { } pub fn latest_committed_block(&self) -> Block { - for view in (0..=self.current_view.0).rev() { - for block in self.blocks_in_view(View(view)) { - if let Some(block) = self.can_commit_grandparent(block) { - return block; - } - } - } - self.genesis_block() + self.latest_committed_block + .and_then(|id| self.safe_blocks.get(&id).cloned()) + .unwrap_or_else(|| self.genesis_block()) } pub fn latest_committed_view(&self) -> View { self.latest_committed_block().view } - pub fn latest_committed_blocks(&self) -> Vec { + pub fn latest_committed_blocks(&self, limit: Option) -> Vec { + let limit = limit.unwrap_or(self.safe_blocks.len()); let mut res = vec![]; let mut current = self.latest_committed_block(); - while current != self.genesis_block() { + + while res.len() < limit { res.push(current.id); - current = if let Some(new_current) = self.safe_blocks.get(¤t.parent()) { - new_current.clone() - } else { + + if current == self.genesis_block() { break; + } + + current = match self.safe_blocks.get(¤t.parent()) { + Some(new_current) => new_current.clone(), + None => break, }; - // current = self.safe_blocks.get(¤t.parent()).unwrap().clone(); } - res.push(self.genesis_block().id); + res } @@ -501,7 +510,7 @@ mod test { assert_eq!(engine.high_qc(), genesis.parent_qc.high_qc()); assert_eq!(engine.blocks_in_view(View(0)), vec![genesis.clone()]); assert_eq!(engine.last_view_timeout_qc(), None); - assert_eq!(engine.latest_committed_blocks(), vec![genesis.id]); + assert_eq!(engine.latest_committed_blocks(None), vec![genesis.id]); } #[test] @@ -595,7 +604,7 @@ mod test { engine = engine.receive_block(block3.clone()).unwrap(); assert_eq!(engine.latest_committed_block(), block1); assert_eq!( - engine.latest_committed_blocks(), + engine.latest_committed_blocks(None), vec![block1.id, engine.genesis_block().id] // without block2 and block3 ); engine = update_leader_selection(&engine); @@ -604,7 +613,7 @@ mod test { engine = engine.receive_block(block4).unwrap(); assert_eq!(engine.latest_committed_block(), block2); assert_eq!( - engine.latest_committed_blocks(), + engine.latest_committed_blocks(None), vec![block2.id, block1.id, engine.genesis_block().id] // without block3, block4 ); } diff --git a/nomos-services/consensus/src/lib.rs b/nomos-services/consensus/src/lib.rs index fbe2a0ea..9c51862f 100644 --- a/nomos-services/consensus/src/lib.rs +++ b/nomos-services/consensus/src/lib.rs @@ -424,9 +424,7 @@ where local_high_qc: carnot.high_qc(), tip: carnot.tip(), last_view_timeout_qc: carnot.last_view_timeout_qc(), - last_committed_block: carnot.safe_blocks() - [&carnot.latest_committed_blocks()[0]] - .clone(), + last_committed_block: carnot.latest_committed_block(), }; tx.send(info).unwrap_or_else(|e| { tracing::error!("Could not send consensus info through channel: {:?}", e) diff --git a/simulations/src/node/carnot/state.rs b/simulations/src/node/carnot/state.rs index 23ba9384..9095af86 100644 --- a/simulations/src/node/carnot/state.rs +++ b/simulations/src/node/carnot/state.rs @@ -152,7 +152,7 @@ impl From<&Carnot> for CarnotState { .map(|b| (b.id, b)) .collect(), last_view_timeout_qc: value.last_view_timeout_qc(), - committed_blocks: value.latest_committed_blocks(), + committed_blocks: value.latest_committed_blocks(None), highest_voted_view: Default::default(), step_duration: Default::default(), format: SubscriberFormat::Csv,