@@ -129,10 +129,11 @@ use {
129129 loaded_programs:: { ProgramCacheEntry , ProgramRuntimeEnvironments } ,
130130 } ,
131131 solana_pubkey:: { Pubkey , PubkeyHasherBuilder } ,
132+ solana_rent:: Rent ,
132133 solana_runtime_transaction:: {
133134 runtime_transaction:: RuntimeTransaction , transaction_with_meta:: TransactionWithMeta ,
134135 } ,
135- solana_sdk_ids:: { bpf_loader_upgradeable, incinerator, native_loader} ,
136+ solana_sdk_ids:: { bpf_loader_upgradeable, incinerator, native_loader, system_program } ,
136137 solana_sha256_hasher:: hashv,
137138 solana_signature:: Signature ,
138139 solana_slot_hashes:: SlotHashes ,
@@ -187,7 +188,7 @@ use {
187188 AtomicBool , AtomicI64 , AtomicU64 ,
188189 Ordering :: { self , AcqRel , Acquire , Relaxed } ,
189190 } ,
190- Arc , LockResult , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard , Weak ,
191+ Arc , LazyLock , LockResult , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard , Weak ,
191192 } ,
192193 time:: { Duration , Instant } ,
193194 } ,
@@ -234,6 +235,14 @@ pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
234235/// only the top 2000 validators by stake will be present in vote account structures.
235236pub const MAX_ALPENGLOW_VOTE_ACCOUNTS : usize = 2000 ;
236237
238+ /// The off-curve account where we store the Alpenglow clock. The clock sysvar has seconds
239+ /// resolution while the Alpenglow clock has nanosecond resolution.
240+ static NANOSECOND_CLOCK_ACCOUNT : LazyLock < Pubkey > = LazyLock :: new ( || {
241+ let ( pubkey, _) =
242+ Pubkey :: find_program_address ( & [ b"alpenclock" ] , & agave_feature_set:: alpenglow:: id ( ) ) ;
243+ pubkey
244+ } ) ;
245+
237246pub type BankStatusCache = StatusCache < Result < ( ) > > ;
238247#[ cfg_attr(
239248 feature = "frozen-abi" ,
@@ -2901,6 +2910,61 @@ impl Bank {
29012910 } )
29022911 }
29032912
2913+ /// Update the clock sysvar from a block footer's nanosecond timestamp.
2914+ /// Also stores the nanosecond value for later retrieval via `get_nanosecond_clock`.
2915+ pub fn update_clock_from_footer ( & self , unix_timestamp_nanos : i64 ) {
2916+ if !self . feature_set . is_active ( & feature_set:: alpenglow:: id ( ) ) {
2917+ return ;
2918+ }
2919+
2920+ // On epoch boundaries, update epoch_start_timestamp
2921+ let unix_timestamp_s = unix_timestamp_nanos / 1_000_000_000 ;
2922+ let epoch_start_timestamp = match ( self . slot , self . parent ( ) ) {
2923+ ( 0 , _) => self . unix_timestamp_from_genesis ( ) ,
2924+ ( _, Some ( parent) ) if parent. epoch ( ) != self . epoch ( ) => unix_timestamp_s,
2925+ _ => self . clock ( ) . epoch_start_timestamp ,
2926+ } ;
2927+
2928+ // Update clock sysvar
2929+ // NOTE: block footer UNIX timestamps are in nanoseconds, but clock sysvar stores timestamps
2930+ // in seconds
2931+ let clock = sysvar:: clock:: Clock {
2932+ slot : self . slot ,
2933+ epoch_start_timestamp,
2934+ epoch : self . epoch_schedule ( ) . get_epoch ( self . slot ) ,
2935+ leader_schedule_epoch : self . epoch_schedule ( ) . get_leader_schedule_epoch ( self . slot ) ,
2936+ unix_timestamp : unix_timestamp_s,
2937+ } ;
2938+
2939+ self . update_sysvar_account ( & sysvar:: clock:: id ( ) , |account| {
2940+ create_account (
2941+ & clock,
2942+ self . inherit_specially_retained_account_fields ( account) ,
2943+ )
2944+ } ) ;
2945+
2946+ // Update Alpenglow clock
2947+ let alpenclock_size = wincode:: serialized_size ( & unix_timestamp_nanos) . unwrap ( ) ;
2948+ let lamports = Rent :: default ( ) . minimum_balance ( alpenclock_size as usize ) ;
2949+ let alpenclock_account_data =
2950+ AccountSharedData :: new_data ( lamports, & unix_timestamp_nanos, & system_program:: ID )
2951+ . unwrap ( ) ;
2952+
2953+ self . store_account_and_update_capitalization (
2954+ & NANOSECOND_CLOCK_ACCOUNT ,
2955+ & alpenclock_account_data,
2956+ ) ;
2957+ }
2958+
2959+ /// Get the nanosecond clock value. Returns `None` if the nanosecond clock has not been
2960+ /// populated (i.e., before Alpenglow migration completes).
2961+ pub fn get_nanosecond_clock ( & self ) -> Option < i64 > {
2962+ self . get_account ( & NANOSECOND_CLOCK_ACCOUNT ) . map ( |acct| {
2963+ acct. deserialize_data ( )
2964+ . expect ( "Couldn't deserialize nanosecond resolution clock" )
2965+ } )
2966+ }
2967+
29042968 pub fn confirmed_last_blockhash ( & self ) -> Hash {
29052969 const NUM_BLOCKHASH_CONFIRMATIONS : usize = 3 ;
29062970
0 commit comments