Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dev-bins/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions programs/sbf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ strum_macros = { workspace = true }
symlink = { workspace = true }
tempfile = { workspace = true }
thiserror = { workspace = true }
wincode = { workspace = true }

[dev-dependencies]
agave-logger = { workspace = true }
Expand Down
60 changes: 58 additions & 2 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,11 @@ use {
loaded_programs::{ProgramCacheEntry, ProgramRuntimeEnvironments},
},
solana_pubkey::{Pubkey, PubkeyHasherBuilder},
solana_rent::Rent,
solana_runtime_transaction::{
runtime_transaction::RuntimeTransaction, transaction_with_meta::TransactionWithMeta,
},
solana_sdk_ids::{bpf_loader_upgradeable, incinerator, native_loader},
solana_sdk_ids::{bpf_loader_upgradeable, incinerator, native_loader, system_program},
solana_sha256_hasher::hashv,
solana_signature::Signature,
solana_slot_hashes::SlotHashes,
Expand Down Expand Up @@ -190,10 +191,11 @@ use {
AtomicBool, AtomicI64, AtomicU64,
Ordering::{self, AcqRel, Acquire, Relaxed},
},
Arc, LockResult, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak,
Arc, LazyLock, LockResult, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak,
},
time::{Duration, Instant},
},
wincode,
};
#[cfg(feature = "dev-context-only-utils")]
use {
Expand Down Expand Up @@ -234,6 +236,14 @@ pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
/// only the top 2000 validators by stake will be present in vote account structures.
pub const MAX_ALPENGLOW_VOTE_ACCOUNTS: usize = 2000;

/// The off-curve account where we store the Alpenglow clock. The clock sysvar has seconds
/// resolution while the Alpenglow clock has nanosecond resolution.
static NANOSECOND_CLOCK_ACCOUNT: LazyLock<Pubkey> = LazyLock::new(|| {
let (pubkey, _) =
Pubkey::find_program_address(&[b"alpenclock"], &agave_feature_set::alpenglow::id());
pubkey
});

pub type BankStatusCache = StatusCache<Result<()>>;
#[cfg_attr(
feature = "frozen-abi",
Expand Down Expand Up @@ -2150,6 +2160,52 @@ impl Bank {
.unwrap_or_default()
}

pub fn update_clock_from_footer(&self, unix_timestamp_nanos: i64) {
// On epoch boundaries, update epoch_start_timestamp
let epoch_start_timestamp = match (self.slot, self.parent()) {
(0, _) => self.unix_timestamp_from_genesis(),
(_, Some(parent)) if parent.epoch() != self.epoch() => {
unix_timestamp_nanos / 1_000_000_000
}
_ => self.clock().epoch_start_timestamp,
};

// Update clock sysvar
// NOTE: block footer UNIX timestamps are in nanoseconds, but clock sysvar stores timestamps
// in seconds
let clock = sysvar::clock::Clock {
slot: self.slot,
epoch_start_timestamp,
epoch: self.epoch_schedule().get_epoch(self.slot),
leader_schedule_epoch: self.epoch_schedule().get_leader_schedule_epoch(self.slot),
unix_timestamp: unix_timestamp_nanos / 1_000_000_000,
};
self.update_sysvar_account(&sysvar::clock::id(), |account| {
create_account(
&clock,
self.inherit_specially_retained_account_fields(account),
)
});

// Update Alpenglow clock
let alpenclock_size = wincode::serialized_size(&unix_timestamp_nanos).unwrap();
let lamports = Rent::default().minimum_balance(alpenclock_size as usize);
let alpenclock_account_data =
AccountSharedData::new_data(lamports, &unix_timestamp_nanos, &system_program::ID)
.unwrap();
self.store_account_and_update_capitalization(
&NANOSECOND_CLOCK_ACCOUNT,
&alpenclock_account_data,
);
}

pub fn get_nanosecond_clock(&self) -> Option<i64> {
self.get_account(&NANOSECOND_CLOCK_ACCOUNT).map(|acct| {
acct.deserialize_data()
.expect("Couldn't deserialize nanosecond resolution clock")
})
}

fn update_clock(&self, parent_epoch: Option<Epoch>) {
let mut unix_timestamp = self.clock().unix_timestamp;
// set epoch_start_timestamp to None to warp timestamp
Expand Down
Loading