Skip to content

Commit 3adc9da

Browse files
committed
Split "on_success_quorum" into smaller and more manageable functions
1 parent 1dd4eec commit 3adc9da

1 file changed

Lines changed: 98 additions & 68 deletions

File tree

node/src/chain/fsm.rs

Lines changed: 98 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -302,79 +302,109 @@ impl<N: Network, DB: database::DB, VM: vm::VMExecution> SimpleFSM<N, DB, VM> {
302302
qmsg: &Quorum,
303303
metadata: Option<Metadata>,
304304
) {
305-
// Clean up attestation cache
306305
self.clean_att_cache();
306+
307+
let (candidate, attestation) = match qmsg.att.result {
308+
RatificationResult::Success(Vote::Valid(candidate)) => (candidate, qmsg.att),
309+
_ => {
310+
error!("Invalid Quorum message");
311+
return;
312+
}
313+
};
314+
315+
let quorum_blk = self.fetch_quorum_block(candidate, qmsg.header.round).await;
316+
317+
match quorum_blk {
318+
Some(blk) => self.handle_found_quorum_block(blk, attestation, metadata).await,
319+
None => self.handle_missing_quorum_block(candidate, attestation, qmsg.header.round).await,
320+
}
321+
}
307322

308-
if let RatificationResult::Success(Vote::Valid(candidate)) =
309-
qmsg.att.result
310-
{
311-
let db = self.acc.read().await.db.clone();
312-
let tip_header = self.acc.read().await.tip_header().await;
313-
let tip_height = tip_header.height;
314-
let quorum_height = qmsg.header.round;
315-
316-
let quorum_blk = if quorum_height > tip_height + 1 {
317-
// Quorum from future
318-
319-
// We do not check the db because we currently do not store
320-
// candidates from the future
321-
None
322-
} else if (quorum_height == tip_height + 1)
323-
|| (quorum_height == tip_height && tip_header.hash != candidate)
324-
{
325-
// If Quorum is for at height tip+1 or tip (but for a different
326-
// candidate) we try to fetch the candidate from the DB
327-
let res = db
328-
.read()
329-
.await
330-
.view(|t| t.fetch_candidate_block(&candidate));
331-
332-
match res {
333-
Ok(b) => b,
334-
Err(_) => None,
335-
}
336-
} else {
337-
// INFO: we currently ignore Quorum messages from the past
338-
None
339-
};
340-
341-
let attestation = qmsg.att;
342-
343-
if let Some(mut blk) = quorum_blk {
344-
// Candidate found. We can build the "full" block
345-
info!(
346-
event = "new block",
347-
src = "quorum_msg",
348-
blk_height = blk.header().height,
349-
blk_hash = to_str(&blk.header().hash),
350-
);
351-
352-
// Attach the Attestation to the block
353-
blk.set_attestation(attestation);
354-
355-
// Handle the new block
356-
let res = self.on_block_event(blk, metadata).await;
357-
match res {
358-
Ok(_) => {}
359-
Err(e) => {
360-
error!("Error on block handling: {e}");
361-
}
362-
}
363-
} else {
364-
// Candidate block not found
365-
debug!(
366-
event = "Candidate not found. Requesting it to the network",
367-
hash = to_str(&candidate),
368-
height = quorum_height,
369-
);
370-
371-
// Cache the attestation and request the candidate from the
372-
// network.
373-
self.flood_request_block(candidate, attestation).await;
323+
/// This function encapsulates the logic for fetching a quorum block based on the candidate hash and round number. Here's a breakdown of what it does:
324+
/// 1. It first acquires the necessary data: the database, tip header, and tip height.
325+
/// 2. It then checks the round number against the tip height:
326+
/// - If the round is from the future (greater than tip height + 1), it returns None.
327+
/// - If the round is either for the next block (tip height + 1) or for the current height but with a different hash, it attempts to fetch the candidate block from the database.
328+
/// - For any other case (i.e., quorum from the past), it returns None.
329+
/// 3. When fetching from the database, it uses the view method to access the transaction, then calls fetch_candidate_block. The ok().flatten() at the end handles both the Result from the database operation and the Option from fetch_candidate_block.
330+
async fn fetch_quorum_block(
331+
&self,
332+
candidate: [u8; 32],
333+
round: u64,
334+
) -> Option<Block> {
335+
let db = self.acc.read().await.db.clone();
336+
let tip_header = self.acc.read().await.tip_header().await;
337+
let tip_height = tip_header.height;
338+
339+
if round > tip_height + 1 {
340+
// Quorum from the future
341+
None
342+
} else if (round == tip_height + 1) || (round == tip_height && tip_header.hash != candidate) {
343+
// Quorum from height tip+1 or tip but for a different candidate
344+
345+
// We try to fetch the candidate from the DB
346+
db.read()
347+
.await
348+
.view(|t| t.fetch_candidate_block(&candidate))
349+
.ok()
350+
.flatten()
351+
} else {
352+
// Quorum from the past
353+
None
354+
}
355+
}
356+
357+
/// Handles the case where a quorum block is found in the database.
358+
/// It performs the following actions:
359+
/// 1. Logs the event
360+
/// 2. Attaches the attestation to the block
361+
/// 3. Passes the block to the on_block_event method for further processing
362+
async fn handle_found_quorum_block(
363+
&mut self,
364+
mut blk: Block,
365+
attestation: Attestation,
366+
metadata: Option<Metadata>,
367+
) {
368+
// Candidate found. We can build the "full" block
369+
info!(
370+
event = "new block",
371+
src = "quorum_msg",
372+
blk_height = blk.header().height,
373+
blk_hash = to_str(&blk.header().hash),
374+
);
375+
376+
// Attach the Attestation to the block
377+
blk.set_attestation(attestation);
378+
379+
// Handle the new block
380+
match self.on_block_event(blk, metadata).await {
381+
Ok(_) => {}
382+
Err(e) => {
383+
error!("Error on block handling: {e}");
374384
}
375385
}
386+
}
376387

377-
error!("Invalid Quorum message");
388+
/// Handles the case where a quorum block is not found in the database.
389+
/// It performs the following actions:
390+
/// 1. Logs the event
391+
/// 2. Caches the attestation
392+
/// 3. Requests the candidate block from the network
393+
async fn handle_missing_quorum_block(
394+
&mut self,
395+
candidate: [u8; 32],
396+
attestation: Attestation,
397+
quorum_height: u64,
398+
) {
399+
// Candidate block not found
400+
debug!(
401+
event = "Candidate not found. Requesting it from the network",
402+
hash = to_str(&candidate),
403+
height = quorum_height,
404+
);
405+
406+
// Cache the attestation and request the candidate from the network
407+
self.flood_request_block(candidate, attestation).await;
378408
}
379409

380410
pub(crate) async fn on_heartbeat_event(&mut self) -> anyhow::Result<()> {

0 commit comments

Comments
 (0)