@@ -36,15 +36,14 @@ use {
3636 solana_pubkey:: Pubkey ,
3737 solana_runtime:: { bank:: Bank , installed_scheduler_pool:: BankWithScheduler } ,
3838 solana_transaction:: versioned:: VersionedTransaction ,
39- solana_version:: version,
4039 solana_votor_messages:: migration:: MigrationStatus ,
4140 std:: {
4241 cmp,
4342 sync:: {
4443 atomic:: { AtomicBool , AtomicU64 , Ordering } ,
4544 Arc , Mutex , RwLock ,
4645 } ,
47- time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ,
46+ time:: { Duration , Instant , SystemTime } ,
4847 } ,
4948 thiserror:: Error ,
5049} ;
@@ -350,7 +349,7 @@ impl PohRecorder {
350349 self . metrics . report_metrics_us += report_metrics_us;
351350
352351 loop {
353- let ( flush_cache_res, flush_cache_us) = measure_us ! ( self . flush_cache( false , false ) ) ;
352+ let ( flush_cache_res, flush_cache_us) = measure_us ! ( self . flush_cache( false , None ) ) ;
354353 self . metrics . flush_cache_no_tick_us += flush_cache_us;
355354 flush_cache_res?;
356355
@@ -437,7 +436,7 @@ impl PohRecorder {
437436 self . tick_height ( ) ,
438437 ) ) ;
439438
440- let ( _flush_res, flush_cache_and_tick_us) = measure_us ! ( self . flush_cache( true , false ) ) ;
439+ let ( _flush_res, flush_cache_and_tick_us) = measure_us ! ( self . flush_cache( true , None ) ) ;
441440 self . metrics . flush_cache_tick_us += flush_cache_and_tick_us;
442441
443442 let ( _, sleep_us) = measure_us ! ( {
@@ -484,7 +483,7 @@ impl PohRecorder {
484483
485484 // TODO: adjust the working_bank.start time based on number of ticks
486485 // that have already elapsed based on current tick height.
487- let _ = self . flush_cache ( false , false ) ;
486+ let _ = self . flush_cache ( false , None ) ;
488487 }
489488
490489 fn clear_bank ( & mut self ) {
@@ -568,10 +567,67 @@ impl PohRecorder {
568567 self . start_tick_height = self . tick_height ( ) + 1 ;
569568 }
570569
570+ /// Waits for the bank to freeze and sends the block footer with the bank hash.
571+ /// Returns:
572+ /// - Ok(()): Footer sent successfully
573+ /// - Err(None): Bank freeze timeout (caller should break without updating send_result)
574+ /// - Err(Some(e)): Send failed (caller should update send_result and break)
575+ fn wait_for_freeze_and_send_footer (
576+ & self ,
577+ footer : & BlockFooterV1 ,
578+ working_bank : & WorkingBank ,
579+ ) -> std:: result:: Result < ( ) , Option < SendError < WorkingBankEntryMarker > > > {
580+ // Wait for the bank to be frozen with timeout
581+ // TODO: change this to use DELTA_BLOCK from votor instead.
582+ let start = Instant :: now ( ) ;
583+ while !working_bank. bank . is_frozen ( ) {
584+ if start. elapsed ( ) > Duration :: from_millis ( 400 ) {
585+ break ;
586+ }
587+ std:: hint:: spin_loop ( ) ;
588+ }
589+
590+ // If the bank still isn't frozen, we've timed out
591+ if !working_bank. bank . is_frozen ( ) {
592+ error ! (
593+ "slot = {} block production failure. bank freezing timed out." ,
594+ working_bank. bank. slot( )
595+ ) ;
596+ return Err ( None ) ;
597+ }
598+
599+ // Send out the block footer - we now have the bank hash
600+ let mut footer = footer. clone ( ) ;
601+ footer. bank_hash = working_bank. bank . hash ( ) ;
602+
603+ let footer = VersionedBlockFooter :: Current ( footer. clone ( ) ) ;
604+ let footer = BlockMarkerV1 :: BlockFooter ( footer) ;
605+ let footer = VersionedBlockMarker :: Current ( footer) ;
606+
607+ let footer_entry_marker = (
608+ EntryMarker :: Marker ( footer) ,
609+ working_bank. max_tick_height - 1 ,
610+ ) ;
611+
612+ let send_result = self
613+ . working_bank_sender
614+ . send ( ( working_bank. bank . clone ( ) , footer_entry_marker) ) ;
615+
616+ if send_result. is_err ( ) {
617+ error ! (
618+ "slot = {} block production failure. failed to broadcast footer" ,
619+ working_bank. bank. slot( )
620+ ) ;
621+ return Err ( send_result. err ( ) ) ;
622+ }
623+
624+ Ok ( ( ) )
625+ }
626+
571627 // Flush cache will delay flushing the cache for a bank until it past the WorkingBank::min_tick_height
572628 // On a record flush will flush the cache at the WorkingBank::min_tick_height, since a record
573629 // occurs after the min_tick_height was generated
574- fn flush_cache ( & mut self , tick : bool , is_alpentick : bool ) -> Result < ( ) > {
630+ fn flush_cache ( & mut self , tick : bool , footer : Option < BlockFooterV1 > ) -> Result < ( ) > {
575631 // check_tick_height is called before flush cache, so it cannot overrun the bank
576632 // so a bank that is so late that it's slot fully generated before it starts recording
577633 // will fail instead of broadcasting any ticks
@@ -605,43 +661,15 @@ impl PohRecorder {
605661 for ( entry, tick_height) in & self . tick_cache [ ..entry_count] {
606662 working_bank. bank . register_tick ( & entry. hash ) ;
607663
608- if is_alpentick {
609- // Wait for the bank to be frozen with timeout
610- // TODO: change this to use DELTA_BLOCK from votor instead.
611- let start = Instant :: now ( ) ;
612- while !working_bank. bank . is_frozen ( ) {
613- if start. elapsed ( ) > Duration :: from_millis ( 400 ) {
664+ if let Some ( footer) = footer. as_ref ( ) {
665+ match self . wait_for_freeze_and_send_footer ( footer, working_bank) {
666+ Ok ( ( ) ) => { } // Continue processing
667+ Err ( None ) => break , // Timeout - break without updating send_result
668+ Err ( Some ( e) ) => {
669+ // Send failed - update send_result and break
670+ send_result = Err ( e) ;
614671 break ;
615672 }
616- std:: hint:: spin_loop ( ) ;
617- }
618-
619- // If the bank still isn't frozen, we've timed out
620- if !working_bank. bank . is_frozen ( ) {
621- error ! (
622- "slot = {} block production failure. bank freezing timed out." ,
623- working_bank. bank. slot( )
624- ) ;
625- break ;
626- }
627-
628- // Send out the block footer
629- let footer = self . produce_block_footer ( working_bank) ;
630- let footer_entry_marker = (
631- EntryMarker :: Marker ( footer) ,
632- working_bank. max_tick_height - 1 ,
633- ) ;
634-
635- send_result = self
636- . working_bank_sender
637- . send ( ( working_bank. bank . clone ( ) , footer_entry_marker) ) ;
638-
639- if send_result. is_err ( ) {
640- error ! (
641- "slot = {} block production failure. failed to broadcast footer" ,
642- working_bank. bank. slot( )
643- ) ;
644- break ;
645673 }
646674 }
647675
@@ -977,34 +1005,7 @@ impl PohRecorder {
9771005 self . clear_bank ( ) ;
9781006 }
9791007
980- pub fn working_bank_block_producer_time_nanos ( & self ) -> u64 {
981- self . working_bank ( )
982- . unwrap ( )
983- . start
984- . duration_since ( UNIX_EPOCH )
985- . expect ( "Misconfigured system clock; couldn't measure block producer time." )
986- . as_nanos ( ) as u64
987- }
988-
989- fn produce_block_footer ( & self , working_bank : & WorkingBank ) -> VersionedBlockMarker {
990- if !working_bank. bank . is_frozen ( ) {
991- let slot = working_bank. bank . slot ( ) ;
992- error ! ( "slot = {slot} creating a block footer with a non-frozen bank! " ) ;
993- }
994-
995- let footer = BlockFooterV1 {
996- bank_hash : working_bank. bank . hash ( ) ,
997- block_producer_time_nanos : self . working_bank_block_producer_time_nanos ( ) ,
998- block_user_agent : format ! ( "agave/{}" , version!( ) ) . into_bytes ( ) ,
999- } ;
1000-
1001- let footer = VersionedBlockFooter :: Current ( footer) ;
1002- let footer = BlockMarkerV1 :: BlockFooter ( footer) ;
1003-
1004- VersionedBlockMarker :: Current ( footer)
1005- }
1006-
1007- pub fn tick_alpenglow ( & mut self , slot_max_tick_height : u64 ) {
1008+ pub fn tick_alpenglow ( & mut self , slot_max_tick_height : u64 , footer : BlockFooterV1 ) {
10081009 let ( poh_entry, tick_lock_contention_us) = measure_us ! ( {
10091010 let mut poh_l = self . poh. lock( ) . unwrap( ) ;
10101011 poh_l. tick( )
@@ -1027,7 +1028,8 @@ impl PohRecorder {
10271028 self . tick_height . load ( ) ,
10281029 ) ) ;
10291030
1030- let ( _flush_res, flush_cache_and_tick_us) = measure_us ! ( self . flush_cache( true , true ) ) ;
1031+ let ( _flush_res, flush_cache_and_tick_us) =
1032+ measure_us ! ( self . flush_cache( true , Some ( footer) ) ) ;
10311033 self . metrics . flush_cache_tick_us += flush_cache_and_tick_us;
10321034 }
10331035 }
0 commit comments