@@ -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