Skip to content

Commit e26b9d3

Browse files
committed
feat(alpenglow): introduce alpenclock primitives to bank
1 parent da92715 commit e26b9d3

File tree

1 file changed

+62
-1
lines changed

1 file changed

+62
-1
lines changed

runtime/src/bank.rs

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

Comments
 (0)