Skip to content

Commit 7dbdf6d

Browse files
committed
feat(alpenglow): introduce alpenclock primitives to bank
1 parent 391ebd1 commit 7dbdf6d

File tree

5 files changed

+70
-2
lines changed

5 files changed

+70
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev-bins/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

programs/sbf/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ strum_macros = { workspace = true }
190190
symlink = { workspace = true }
191191
tempfile = { workspace = true }
192192
thiserror = { workspace = true }
193+
wincode = { workspace = true }
193194

194195
[dev-dependencies]
195196
agave-logger = { workspace = true }

runtime/src/bank.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
235236
pub 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+
237246
pub 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

Comments
 (0)