@@ -192,7 +192,7 @@ use {
192192 AtomicBool , AtomicI64 , AtomicU64 ,
193193 Ordering :: { self , AcqRel , Acquire , Relaxed } ,
194194 } ,
195- Arc , LockResult , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard , Weak ,
195+ Arc , LazyLock , LockResult , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard , Weak ,
196196 } ,
197197 time:: { Duration , Instant } ,
198198 } ,
@@ -236,6 +236,14 @@ pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
236236/// only the top 2000 validators by stake will be present in vote account structures.
237237pub const MAX_ALPENGLOW_VOTE_ACCOUNTS : usize = 2000 ;
238238
239+ /// The off-curve account where we store the Alpenglow clock. The clock sysvar has seconds
240+ /// resolution while the Alpenglow clock has nanosecond resolution.
241+ static NANOSECOND_CLOCK_ACCOUNT : LazyLock < Pubkey > = LazyLock :: new ( || {
242+ let ( pubkey, _) =
243+ Pubkey :: find_program_address ( & [ b"alpenclock" ] , & agave_feature_set:: alpenglow:: id ( ) ) ;
244+ pubkey
245+ } ) ;
246+
239247pub type BankStatusCache = StatusCache < Result < ( ) > > ;
240248#[ cfg_attr(
241249 feature = "frozen-abi" ,
@@ -2911,6 +2919,61 @@ impl Bank {
29112919 self . store_account_and_update_capitalization ( & GENESIS_CERTIFICATE_ACCOUNT , & cert_acct) ;
29122920 }
29132921
2922+ /// Update the clock sysvar from a block footer's nanosecond timestamp.
2923+ /// Also stores the nanosecond value for later retrieval via `get_nanosecond_clock`.
2924+ pub fn update_clock_from_footer ( & self , unix_timestamp_nanos : i64 ) {
2925+ if !self . feature_set . is_active ( & feature_set:: alpenglow:: id ( ) ) {
2926+ return ;
2927+ }
2928+
2929+ // On epoch boundaries, update epoch_start_timestamp
2930+ let unix_timestamp_s = unix_timestamp_nanos / 1_000_000_000 ;
2931+ let epoch_start_timestamp = match ( self . slot , self . parent ( ) ) {
2932+ ( 0 , _) => self . unix_timestamp_from_genesis ( ) ,
2933+ ( _, Some ( parent) ) if parent. epoch ( ) != self . epoch ( ) => unix_timestamp_s,
2934+ _ => self . clock ( ) . epoch_start_timestamp ,
2935+ } ;
2936+
2937+ // Update clock sysvar
2938+ // NOTE: block footer UNIX timestamps are in nanoseconds, but clock sysvar stores timestamps
2939+ // in seconds
2940+ let clock = sysvar:: clock:: Clock {
2941+ slot : self . slot ,
2942+ epoch_start_timestamp,
2943+ epoch : self . epoch_schedule ( ) . get_epoch ( self . slot ) ,
2944+ leader_schedule_epoch : self . epoch_schedule ( ) . get_leader_schedule_epoch ( self . slot ) ,
2945+ unix_timestamp : unix_timestamp_s,
2946+ } ;
2947+
2948+ self . update_sysvar_account ( & sysvar:: clock:: id ( ) , |account| {
2949+ create_account (
2950+ & clock,
2951+ self . inherit_specially_retained_account_fields ( account) ,
2952+ )
2953+ } ) ;
2954+
2955+ // Update Alpenglow clock
2956+ let alpenclock_size = wincode:: serialized_size ( & unix_timestamp_nanos) . unwrap ( ) ;
2957+ let lamports = Rent :: default ( ) . minimum_balance ( alpenclock_size as usize ) ;
2958+ let alpenclock_account_data =
2959+ AccountSharedData :: new_data ( lamports, & unix_timestamp_nanos, & system_program:: ID )
2960+ . unwrap ( ) ;
2961+
2962+ self . store_account_and_update_capitalization (
2963+ & NANOSECOND_CLOCK_ACCOUNT ,
2964+ & alpenclock_account_data,
2965+ ) ;
2966+ }
2967+
2968+ /// Get the nanosecond clock value. Returns `None` if the nanosecond clock has not been
2969+ /// populated (i.e., before Alpenglow migration completes).
2970+ pub fn get_nanosecond_clock ( & self ) -> Option < i64 > {
2971+ self . get_account ( & NANOSECOND_CLOCK_ACCOUNT ) . map ( |acct| {
2972+ acct. deserialize_data ( )
2973+ . expect ( "Couldn't deserialize nanosecond resolution clock" )
2974+ } )
2975+ }
2976+
29142977 pub fn confirmed_last_blockhash ( & self ) -> Hash {
29152978 const NUM_BLOCKHASH_CONFIRMATIONS : usize = 3 ;
29162979
0 commit comments