Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more sysvar API docs #26849

Merged
merged 19 commits into from
Aug 15, 2022
Merged
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
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 — 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.
brson marked this conversation as resolved.
Show resolved Hide resolved
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