Skip to content

Commit

Permalink
Add more sysvar API docs (#26849)
Browse files Browse the repository at this point in the history
* Add more sysvar API docs

* Remove println from examples

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/clock.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Fix docs for ACCOUNT_STORAGE_OVERHEAD

* Update sdk/program/src/epoch_schedule.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/sysvar/slot_hashes.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/sysvar/slot_history.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/sysvar/slot_history.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Update sdk/program/src/sysvar/mod.rs

Co-authored-by: Tyera Eulberg <[email protected]>

* Fix docs for DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET

* Fix recent_blockhash short description

* Fix whitespace

Co-authored-by: Tyera Eulberg <[email protected]>
  • Loading branch information
brson and CriesofCarrots authored Aug 15, 2022
1 parent 3ad93c8 commit b6762fc
Show file tree
Hide file tree
Showing 19 changed files with 889 additions and 186 deletions.
12 changes: 6 additions & 6 deletions sdk/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ fn id_to_tokens(
tokens: &mut proc_macro2::TokenStream,
) {
tokens.extend(quote! {
/// The static program ID
/// The static program ID.
pub static ID: #pubkey_type = #id;

/// Confirms that a given pubkey is equivalent to the program ID
/// Returns `true` if given pubkey is the program ID.
pub fn check_id(id: &#pubkey_type) -> bool {
id == &ID
}

/// Returns the program ID
/// Returns the program ID.
pub fn id() -> #pubkey_type {
ID
}
Expand All @@ -71,16 +71,16 @@ fn deprecated_id_to_tokens(
tokens: &mut proc_macro2::TokenStream,
) {
tokens.extend(quote! {
/// The static program ID
/// The static program ID.
pub static ID: #pubkey_type = #id;

/// Confirms that a given pubkey is equivalent to the program ID
/// Returns `true` if given pubkey is the program ID.
#[deprecated()]
pub fn check_id(id: &#pubkey_type) -> bool {
id == &ID
}

/// Returns the program ID
/// Returns the program ID.
#[deprecated()]
pub fn id() -> #pubkey_type {
ID
Expand Down
101 changes: 70 additions & 31 deletions sdk/program/src/clock.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
//! Information about the network's clock, ticks, slots, etc.
//!
//! Time in Solana is marked primarily by _slots_, which occur approximately every
//! 400 milliseconds, and are numbered sequentially. For every slot, a leader is
//! chosen from the validator set, and that leader is expected to produce a new
//! block, though sometimes leaders may fail to do so. Blocks can be identified
//! by their slot number, and some slots do not contain a block.
//!
//! An approximation of the passage of real-world time can be calculated by
//! multiplying a number of slots by [`SLOT_MS`], which is a constant target
//! time for the network to produce slots. Note though that this method suffers
//! a variable amount of drift, as the network does not produce slots at exactly
//! the target rate, and the greater number of slots being calculated for, the
//! greater the drift. Epochs cannot be used this way as they contain variable
//! numbers of slots.
//!
//! The network's current view of the real-world time can always be accessed via
//! [`Clock::unix_timestamp`], which is produced by an [oracle derived from the
//! validator set][oracle].
//!
//! [oracle]: https://docs.solana.com/implemented-proposals/validator-timestamp-oracle
use {
crate::{clone_zeroed, copy_field},
std::mem::MaybeUninit,
};

// The default tick rate that the cluster attempts to achieve. Note that the actual tick
// rate at any given time should be expected to drift
/// The default tick rate that the cluster attempts to achieve (160 per second).
///
/// Note that the actual tick rate at any given time should be expected to drift.
pub const DEFAULT_TICKS_PER_SECOND: u64 = 160;

#[cfg(test)]
static_assertions::const_assert_eq!(MS_PER_TICK, 6);

/// The number of milliseconds per tick (6).
pub const MS_PER_TICK: u64 = 1000 / DEFAULT_TICKS_PER_SECOND;

#[cfg(test)]
static_assertions::const_assert_eq!(SLOT_MS, 400);

/// The expected duration of a slot (400 milliseconds).
pub const SLOT_MS: u64 = (DEFAULT_TICKS_PER_SLOT * 1000) / DEFAULT_TICKS_PER_SECOND;

// At 160 ticks/s, 64 ticks per slot implies that leader rotation and voting will happen
Expand All @@ -41,7 +66,10 @@ pub const TICKS_PER_DAY: u64 = DEFAULT_TICKS_PER_SECOND * SECONDS_PER_DAY;

#[cfg(test)]
static_assertions::const_assert_eq!(DEFAULT_SLOTS_PER_EPOCH, 432_000);
// 1 Epoch ~= 2 days

/// The number of slots per epoch after initial network warmup.
///
/// 1 Epoch ~= 2 days.
pub const DEFAULT_SLOTS_PER_EPOCH: u64 = 2 * TICKS_PER_DAY / DEFAULT_TICKS_PER_SLOT;

// leader schedule is governed by this
Expand All @@ -52,12 +80,14 @@ static_assertions::const_assert_eq!(DEFAULT_MS_PER_SLOT, 400);
pub const DEFAULT_MS_PER_SLOT: u64 = 1_000 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND;
pub const DEFAULT_S_PER_SLOT: f64 = DEFAULT_TICKS_PER_SLOT as f64 / DEFAULT_TICKS_PER_SECOND as f64;

/// The time window of recent block hash values that the bank will track the signatures
/// of over. Once the bank discards a block hash, it will reject any transactions that use
/// that `recent_blockhash` in a transaction. Lowering this value reduces memory consumption,
/// but requires clients to update its `recent_blockhash` more frequently. Raising the value
/// lengthens the time a client must wait to be certain a missing transaction will
/// not be processed by the network.
/// The time window of recent block hash values over which the bank will track
/// signatures.
///
/// Once the bank discards a block hash, it will reject any transactions that
/// use that `recent_blockhash` in a transaction. Lowering this value reduces
/// memory consumption, but requires a client to update its `recent_blockhash`
/// more frequently. Raising the value lengthens the time a client must wait to
/// be certain a missing transaction will not be processed by the network.
pub const MAX_HASH_AGE_IN_SECONDS: usize = 120;

#[cfg(test)]
Expand All @@ -78,52 +108,61 @@ pub const MAX_TRANSACTION_FORWARDING_DELAY_GPU: usize = 2;
/// More delay is expected if CUDA is not enabled (as signature verification takes longer)
pub const MAX_TRANSACTION_FORWARDING_DELAY: usize = 6;

/// Slot is a unit of time given to a leader for encoding,
/// is some some number of Ticks long.
/// The unit of time given to a leader for encoding a block.
///
/// It is some some number of _ticks_ long.
pub type Slot = u64;

/// Uniquely distinguishes every version of a slot, even if the
/// slot number is the same, i.e. duplicate slots
/// Uniquely distinguishes every version of a slot.
///
/// The `BankId` is unique even if the slot number of two different slots is the
/// same. This can happen in the case of e.g. duplicate slots.
pub type BankId = u64;

/// Epoch is a unit of time a given leader schedule is honored,
/// some number of Slots.
/// The unit of time a given leader schedule is honored.
///
/// It lasts for some number of [`Slot`]s.
pub type Epoch = u64;

pub const GENESIS_EPOCH: Epoch = 0;
// must be sync with Account::rent_epoch::default()
pub const INITIAL_RENT_EPOCH: Epoch = 0;

/// SlotIndex is an index to the slots of a epoch
/// An index to the slots of a epoch.
pub type SlotIndex = u64;

/// SlotCount is the number of slots in a epoch
/// The number of slots in a epoch.
pub type SlotCount = u64;

/// UnixTimestamp is an approximate measure of real-world time,
/// expressed as Unix time (ie. seconds since the Unix epoch)
/// An approximate measure of real-world time.
///
/// Expressed as Unix time (i.e. seconds since the Unix epoch).
pub type UnixTimestamp = i64;

/// Clock represents network time. Members of Clock start from 0 upon
/// network boot. The best way to map Clock to wallclock time is to use
/// current Slot, as Epochs vary in duration (they start short and grow
/// as the network progresses).
/// A representation of network time.
///
/// All members of `Clock` start from 0 upon network boot.
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
pub struct Clock {
/// the current network/bank Slot
/// The current `Slot`.
pub slot: Slot,
/// the timestamp of the first Slot in this Epoch
/// The timestamp of the first `Slot` in this `Epoch`.
pub epoch_start_timestamp: UnixTimestamp,
/// the bank Epoch
/// The current `Epoch`.
pub epoch: Epoch,
/// the future Epoch for which the leader schedule has
/// most recently been calculated
/// The future `Epoch` for which the leader schedule has
/// most recently been calculated.
pub leader_schedule_epoch: Epoch,
/// originally computed from genesis creation time and network time
/// in slots (drifty); corrected using validator timestamp oracle as of
/// timestamp_correction and timestamp_bounding features
/// The approximate real world time of the current slot.
///
/// This value was originally computed from genesis creation time and
/// network time in slots, incurring a lot of drift. Following activation of
/// the [`timestamp_correction` and `timestamp_bounding`][tsc] features it
/// is calculated using a [validator timestamp oracle][oracle].
///
/// [tsc]: https://docs.solana.com/implemented-proposals/bank-timestamp-correction
/// [oracle]: https://docs.solana.com/implemented-proposals/validator-timestamp-oracle
pub unix_timestamp: UnixTimestamp,
}

Expand Down
37 changes: 26 additions & 11 deletions sdk/program/src/epoch_schedule.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
//! Configuration for epochs and slots.
//!
//! Epochs mark a period of time composed of _slots_, for which a particular
//! [leader schedule][ls] is in effect. The epoch schedule determines the length
//! of epochs, and the timing of the next leader-schedule selection.
//!
//! [ls]: https://docs.solana.com/cluster/leader-rotation#leader-schedule-rotation
//!
//! The epoch schedule does not change during the life of a blockchain,
//! though the length of an epoch does &mdash; during the initial launch of
//! the chain there is a "warmup" period, where epochs are short, with subsequent
//! epochs increasing in slots until they last for [`DEFAULT_SLOTS_PER_EPOCH`].
/// 1 Epoch = 400 * 8192 ms ~= 55 minutes
pub use crate::clock::{Epoch, Slot, DEFAULT_SLOTS_PER_EPOCH};
use {
crate::{clone_zeroed, copy_field},
std::mem::MaybeUninit,
};

/// The number of slots before an epoch starts to calculate the leader schedule.
/// Default is an entire epoch, i.e. leader schedule for epoch X is calculated at
/// the beginning of epoch X - 1.
/// The default number of slots before an epoch starts to calculate the leader schedule.
pub const DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET: u64 = DEFAULT_SLOTS_PER_EPOCH;

/// The maximum number of slots before an epoch starts to calculate the leader schedule.
/// Default is an entire epoch, i.e. leader schedule for epoch X is calculated at
/// the beginning of epoch X - 1.
///
/// Default is an entire epoch, i.e. leader schedule for epoch X is calculated at
/// the beginning of epoch X - 1.
pub const MAX_LEADER_SCHEDULE_EPOCH_OFFSET: u64 = 3;

/// based on MAX_LOCKOUT_HISTORY from vote_program
/// The minimum number of slots per epoch during the warmup period.
///
/// Based on `MAX_LOCKOUT_HISTORY` from `vote_program`.
pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;

#[repr(C)]
Expand All @@ -28,16 +39,20 @@ pub struct EpochSchedule {
pub slots_per_epoch: u64,

/// A number of slots before beginning of an epoch to calculate
/// a leader schedule for that epoch
/// a leader schedule for that epoch.
pub leader_schedule_slot_offset: u64,

/// whether epochs start short and grow
/// Whether epochs start short and grow.
pub warmup: bool,

/// basically: log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
/// The first epoch after the warmup period.
///
/// Basically: `log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)`.
pub first_normal_epoch: Epoch,

/// basically: MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)
/// The first slot after the warmup period.
///
/// Basically: `MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)`.
pub first_normal_slot: Slot,
}

Expand Down
4 changes: 4 additions & 0 deletions sdk/program/src/example_mocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ pub mod solana_sdk {
address_lookup_table_account, hash, instruction, keccak, message, nonce,
pubkey::{self, Pubkey},
system_instruction, system_program,
sysvar::{
self,
clock::{self, Clock},
},
};

pub mod account {
Expand Down
85 changes: 1 addition & 84 deletions sdk/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
//! [serialization]: #serialization
//! [np]: #native-programs
//! [cpi]: #cross-program-instruction-execution
//! [sysvar]: #sysvars
//! [sysvar]: crate::sysvar
//!
//! Idiomatic examples of `solana-program` usage can be found in
//! [the Solana Program Library][spl].
Expand Down Expand Up @@ -466,89 +466,6 @@
//! - Invokable by programs? yes
//!
//! [lut]: https://docs.solana.com/proposals/transactions-v2
//!
//! # Sysvars
//!
//! Sysvars are special accounts that contain dynamically-updated data about
//! the network cluster, the blockchain history, and the executing transaction.
//!
//! The program IDs for sysvars are defined in the [`sysvar`] module, and simple
//! sysvars implement the [`Sysvar::get`] method, which loads a sysvar directly
//! from the runtime, as in this example that logs the `clock` sysvar:
//!
//! [`Sysvar::get`]: sysvar::Sysvar::get
//!
//! ```
//! use solana_program::{
//! account_info::AccountInfo,
//! clock,
//! entrypoint::ProgramResult,
//! msg,
//! pubkey::Pubkey,
//! sysvar::Sysvar,
//! };
//!
//! fn process_instruction(
//! program_id: &Pubkey,
//! accounts: &[AccountInfo],
//! instruction_data: &[u8],
//! ) -> ProgramResult {
//! let clock = clock::Clock::get()?;
//! msg!("clock: {:#?}", clock);
//! Ok(())
//! }
//! ```
//!
//! Since Solana sysvars are accounts, if the `AccountInfo` is provided to the
//! program, then the program can deserialize the sysvar with
//! [`Sysvar::from_account_info`] to access its data, as in this example that
//! again logs the [`clock`][clk] sysvar.
//!
//! [`Sysvar::from_account_info`]: sysvar::Sysvar::from_account_info
//! [clk]: sysvar::clock
//!
//! ```
//! use solana_program::{
//! account_info::{next_account_info, AccountInfo},
//! clock,
//! entrypoint::ProgramResult,
//! msg,
//! pubkey::Pubkey,
//! sysvar::Sysvar,
//! };
//!
//! fn process_instruction(
//! program_id: &Pubkey,
//! accounts: &[AccountInfo],
//! instruction_data: &[u8],
//! ) -> ProgramResult {
//! let account_info_iter = &mut accounts.iter();
//! let clock_account = next_account_info(account_info_iter)?;
//! let clock = clock::Clock::from_account_info(&clock_account)?;
//! msg!("clock: {:#?}", clock);
//! Ok(())
//! }
//! ```
//!
//! When possible, programs should prefer to call `Sysvar::get` instead of
//! deserializing with `Sysvar::from_account_info`, as the latter imposes extra
//! overhead of deserialization while also requiring the sysvar account address
//! be passed to the program, wasting the limited space available to
//! transactions. Deserializing sysvars that can instead be retrieved with
//! `Sysvar::get` should be only be considered for compatibility with older
//! programs that pass around sysvar accounts.
//!
//! Some sysvars are too large to deserialize within a program, and
//! `Sysvar::from_account_info` returns an error. Some sysvars are too large
//! to deserialize within a program, and attempting to will exhaust the
//! program's compute budget. Some sysvars do not implement `Sysvar::get` and
//! return an error. Some sysvars have custom deserializers that do not
//! implement the `Sysvar` trait. These cases are documented in the modules for
//! individual sysvars.
//!
//! For more details see the Solana [documentation on sysvars][sysvardoc].
//!
//! [sysvardoc]: https://docs.solana.com/developing/runtime-facilities/sysvars
#![allow(incomplete_features)]
#![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(specialization))]
Expand Down
Loading

0 comments on commit b6762fc

Please sign in to comment.