Skip to content

Commit b3359dd

Browse files
committed
feat(alpenglow): introduce alpenclock primitives to bank
1 parent 54fcf2e commit b3359dd

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

runtime/src/bank.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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.
237237
pub 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+
239247
pub 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

Comments
 (0)