@@ -186,7 +186,7 @@ use {
186186 AtomicBool , AtomicI64 , AtomicU64 ,
187187 Ordering :: { self , AcqRel , Acquire , Relaxed } ,
188188 } ,
189- Arc , LockResult , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard , Weak ,
189+ Arc , LazyLock , LockResult , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard , Weak ,
190190 } ,
191191 time:: { Duration , Instant } ,
192192 } ,
@@ -230,6 +230,14 @@ pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
230230/// only the top 2000 validators by stake will be present in vote account structures.
231231pub const MAX_ALPENGLOW_VOTE_ACCOUNTS : usize = 2000 ;
232232
233+ /// The off-curve account where we store the Alpenglow clock. The clock sysvar has seconds
234+ /// resolution while the Alpenglow clock has nanosecond resolution.
235+ static NANOSECOND_CLOCK_ACCOUNT : LazyLock < Pubkey > = LazyLock :: new ( || {
236+ let ( pubkey, _) =
237+ Pubkey :: find_program_address ( & [ b"alpenclock" ] , & agave_feature_set:: alpenglow:: id ( ) ) ;
238+ pubkey
239+ } ) ;
240+
233241pub type BankStatusCache = StatusCache < Result < ( ) > > ;
234242#[ cfg_attr(
235243 feature = "frozen-abi" ,
@@ -2849,6 +2857,59 @@ impl Bank {
28492857 } )
28502858 }
28512859
2860+ /// Update the clock sysvar from a block footer's nanosecond timestamp.
2861+ /// Also stores the nanosecond value for later retrieval via `get_nanosecond_clock`.
2862+ pub fn update_clock_from_footer ( & self , time_nanos : i64 ) {
2863+ if !self . feature_set . is_active ( & feature_set:: alpenglow:: id ( ) ) {
2864+ return ;
2865+ }
2866+
2867+ let time_secs = time_nanos / 1_000_000_000 ;
2868+
2869+ let parent_epoch = self . parent ( ) . map ( |p| p. epoch ( ) ) ;
2870+ let epoch_start_timestamp =
2871+ if parent_epoch. is_some ( ) && parent_epoch. unwrap ( ) != self . epoch ( ) {
2872+ time_secs
2873+ } else {
2874+ self . clock ( ) . epoch_start_timestamp
2875+ } ;
2876+
2877+ let clock = sysvar:: clock:: Clock {
2878+ slot : self . slot ,
2879+ epoch_start_timestamp,
2880+ epoch : self . epoch_schedule ( ) . get_epoch ( self . slot ) ,
2881+ leader_schedule_epoch : self . epoch_schedule ( ) . get_leader_schedule_epoch ( self . slot ) ,
2882+ unix_timestamp : time_secs,
2883+ } ;
2884+ self . update_sysvar_account ( & sysvar:: clock:: id ( ) , |account| {
2885+ create_account (
2886+ & clock,
2887+ self . inherit_specially_retained_account_fields ( account) ,
2888+ )
2889+ } ) ;
2890+
2891+ // Store nanosecond clock value in account for later retrieval
2892+ let data = time_nanos. to_le_bytes ( ) ;
2893+ let lamports = self . get_minimum_balance_for_rent_exemption ( data. len ( ) ) ;
2894+ let mut account = AccountSharedData :: new ( lamports, data. len ( ) , & Pubkey :: default ( ) ) ;
2895+ account. set_data_from_slice ( & data) ;
2896+ self . store_account ( & NANOSECOND_CLOCK_ACCOUNT , & account) ;
2897+ }
2898+
2899+ /// Get the nanosecond clock value. Returns `None` if the nanosecond clock has not been
2900+ /// populated (i.e., before Alpenglow migration completes).
2901+ pub fn get_nanosecond_clock ( & self ) -> Option < i64 > {
2902+ self . get_account ( & NANOSECOND_CLOCK_ACCOUNT )
2903+ . and_then ( |acct| {
2904+ let data = acct. data ( ) ;
2905+ if data. len ( ) == 8 {
2906+ Some ( i64:: from_le_bytes ( data. try_into ( ) . unwrap ( ) ) )
2907+ } else {
2908+ None
2909+ }
2910+ } )
2911+ }
2912+
28522913 pub fn confirmed_last_blockhash ( & self ) -> Hash {
28532914 const NUM_BLOCKHASH_CONFIRMATIONS : usize = 3 ;
28542915
0 commit comments