Add more sysvar API docs (#26849)
* Add more sysvar API docs * Remove println from examples * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/clock.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Fix docs for ACCOUNT_STORAGE_OVERHEAD * Update sdk/program/src/epoch_schedule.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/sysvar/slot_hashes.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/sysvar/slot_history.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/sysvar/slot_history.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Update sdk/program/src/sysvar/mod.rs Co-authored-by: Tyera Eulberg <teulberg@gmail.com> * Fix docs for DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET * Fix recent_blockhash short description * Fix whitespace Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
This commit is contained in:
parent
3ad93c84b6
commit
b6762fc2f9
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
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)]
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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].
|
||||
|
@ -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))]
|
||||
|
|
|
@ -3,40 +3,53 @@
|
|||
//! [rent]: https://docs.solana.com/implemented-proposals/rent
|
||||
|
||||
#![allow(clippy::integer_arithmetic)]
|
||||
//! configuration for network rent
|
||||
|
||||
use {
|
||||
crate::{clock::DEFAULT_SLOTS_PER_EPOCH, clone_zeroed, copy_field},
|
||||
std::mem::MaybeUninit,
|
||||
};
|
||||
|
||||
/// Configuration of network rent.
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Copy, Debug, AbiExample)]
|
||||
pub struct Rent {
|
||||
/// Rental rate
|
||||
/// Rental rate in lamports/byte-year.
|
||||
pub lamports_per_byte_year: u64,
|
||||
|
||||
/// exemption threshold, in years
|
||||
/// Amount of time (in years) a balance must include rent for the account to
|
||||
/// be rent exempt.
|
||||
pub exemption_threshold: f64,
|
||||
|
||||
// What portion of collected rent are to be destroyed, percentage-wise
|
||||
/// The percentage of collected rent that is burned.
|
||||
///
|
||||
/// Valid values are in the range [0, 100]. The remaining percentage is
|
||||
/// distributed to validators.
|
||||
pub burn_percent: u8,
|
||||
}
|
||||
|
||||
/// default rental rate in lamports/byte-year, based on:
|
||||
/// 10^9 lamports per SOL
|
||||
/// $1 per SOL
|
||||
/// $0.01 per megabyte day
|
||||
/// $3.65 per megabyte year
|
||||
/// Default rental rate in lamports/byte-year.
|
||||
///
|
||||
/// This calculation is based on:
|
||||
/// - 10^9 lamports per SOL
|
||||
/// - $1 per SOL
|
||||
/// - $0.01 per megabyte day
|
||||
/// - $3.65 per megabyte year
|
||||
pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 1_000_000_000 / 100 * 365 / (1024 * 1024);
|
||||
|
||||
/// default amount of time (in years) the balance has to include rent for
|
||||
/// Default amount of time (in years) the balance has to include rent for the
|
||||
/// account to be rent exempt.
|
||||
pub const DEFAULT_EXEMPTION_THRESHOLD: f64 = 2.0;
|
||||
|
||||
/// default percentage of rent to burn (Valid values are 0 to 100)
|
||||
/// Default percentage of collected rent that is burned.
|
||||
///
|
||||
/// Valid values are in the range [0, 100]. The remaining percentage is
|
||||
/// distributed to validators.
|
||||
pub const DEFAULT_BURN_PERCENT: u8 = 50;
|
||||
|
||||
/// account storage overhead for calculation of base rent
|
||||
/// Account storage overhead for calculation of base rent.
|
||||
///
|
||||
/// This is the number of bytes required to store an account with no data. It is
|
||||
/// added to an accounts data length when calculating [`Rent::minimum_balance`].
|
||||
pub const ACCOUNT_STORAGE_OVERHEAD: u64 = 128;
|
||||
|
||||
impl Default for Rent {
|
||||
|
@ -63,28 +76,33 @@ impl Clone for Rent {
|
|||
}
|
||||
|
||||
impl Rent {
|
||||
/// calculate how much rent to burn from the collected rent
|
||||
/// Calculate how much rent to burn from the collected rent.
|
||||
///
|
||||
/// The first value returned is the amount burned. The second is the amount
|
||||
/// to distribute to validators.
|
||||
pub fn calculate_burn(&self, rent_collected: u64) -> (u64, u64) {
|
||||
let burned_portion = (rent_collected * u64::from(self.burn_percent)) / 100;
|
||||
(burned_portion, rent_collected - burned_portion)
|
||||
}
|
||||
/// minimum balance due for rent-exemption of a given size Account::data.len()
|
||||
|
||||
/// Minimum balance due for rent-exemption of a given account data size.
|
||||
///
|
||||
/// Note: a stripped-down version of this calculation is used in
|
||||
/// calculate_split_rent_exempt_reserve in the stake program. When this function is updated, --
|
||||
/// eg. when making rent variable -- the stake program will need to be refactored
|
||||
/// `calculate_split_rent_exempt_reserve` in the stake program. When this
|
||||
/// function is updated, eg. when making rent variable, the stake program
|
||||
/// will need to be refactored.
|
||||
pub fn minimum_balance(&self, data_len: usize) -> u64 {
|
||||
let bytes = data_len as u64;
|
||||
(((ACCOUNT_STORAGE_OVERHEAD + bytes) * self.lamports_per_byte_year) as f64
|
||||
* self.exemption_threshold) as u64
|
||||
}
|
||||
|
||||
/// whether a given balance and data_len would be exempt
|
||||
/// Whether a given balance and data length would be exempt.
|
||||
pub fn is_exempt(&self, balance: u64, data_len: usize) -> bool {
|
||||
balance >= self.minimum_balance(data_len)
|
||||
}
|
||||
|
||||
/// rent due on account's data_len with balance
|
||||
/// Rent due on account's data length with balance.
|
||||
pub fn due(&self, balance: u64, data_len: usize, years_elapsed: f64) -> RentDue {
|
||||
if self.is_exempt(balance, data_len) {
|
||||
RentDue::Exempt
|
||||
|
@ -93,13 +111,16 @@ impl Rent {
|
|||
}
|
||||
}
|
||||
|
||||
/// rent due for account that is known to be not exempt
|
||||
/// Rent due for account that is known to be not exempt.
|
||||
pub fn due_amount(&self, data_len: usize, years_elapsed: f64) -> u64 {
|
||||
let actual_data_len = data_len as u64 + ACCOUNT_STORAGE_OVERHEAD;
|
||||
let lamports_per_year = self.lamports_per_byte_year * actual_data_len;
|
||||
(lamports_per_year as f64 * years_elapsed) as u64
|
||||
}
|
||||
|
||||
/// Creates a `Rent` that charges no lamports.
|
||||
///
|
||||
/// This is used for testing.
|
||||
pub fn free() -> Self {
|
||||
Self {
|
||||
lamports_per_byte_year: 0,
|
||||
|
@ -107,6 +128,9 @@ impl Rent {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a `Rent` that is scaled based on the number of slots in an epoch.
|
||||
///
|
||||
/// This is used for testing.
|
||||
pub fn with_slots_per_epoch(slots_per_epoch: u64) -> Self {
|
||||
let ratio = slots_per_epoch as f64 / DEFAULT_SLOTS_PER_EPOCH as f64;
|
||||
let exemption_threshold = DEFAULT_EXEMPTION_THRESHOLD as f64 * ratio;
|
||||
|
@ -119,17 +143,17 @@ impl Rent {
|
|||
}
|
||||
}
|
||||
|
||||
/// Enumerate return values from `Rent::due()`
|
||||
/// The return value of [`Rent::due`].
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum RentDue {
|
||||
/// Used to indicate the account is rent exempt
|
||||
/// Used to indicate the account is rent exempt.
|
||||
Exempt,
|
||||
/// The account owes rent, and the amount is the field
|
||||
/// The account owes this much rent.
|
||||
Paying(u64),
|
||||
}
|
||||
|
||||
impl RentDue {
|
||||
/// Return the lamports due for rent
|
||||
/// Return the lamports due for rent.
|
||||
pub fn lamports(&self) -> u64 {
|
||||
match self {
|
||||
RentDue::Exempt => 0,
|
||||
|
@ -137,7 +161,7 @@ impl RentDue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return 'true' if rent exempt
|
||||
/// Return 'true' if rent exempt.
|
||||
pub fn is_exempt(&self) -> bool {
|
||||
match self {
|
||||
RentDue::Exempt => true,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! The sysvar ID is declared in [`sysvar::slot_hashes`].
|
||||
//!
|
||||
//! [`sysvar::slot_hashes`]: crate::slot_hashes
|
||||
//! [`sysvar::slot_hashes`]: crate::sysvar::slot_hashes
|
||||
|
||||
pub use crate::clock::Slot;
|
||||
use {
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
//!
|
||||
//! The sysvar ID is declared in [`sysvar::slot_history`].
|
||||
//!
|
||||
//! [`sysvar::slot_history`]: crate::slot_history
|
||||
//! [`sysvar::slot_history`]: crate::sysvar::slot_history
|
||||
|
||||
#![allow(clippy::integer_arithmetic)]
|
||||
pub use crate::clock::Slot;
|
||||
use bv::{BitVec, BitsMut};
|
||||
|
||||
/// A bitvector indicating which slots are present in the past epoch.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct SlotHistory {
|
||||
|
|
|
@ -1,5 +1,131 @@
|
|||
//! This account contains the clock slot, epoch, and leader_schedule_epoch
|
||||
//! Information about the network’s clock, ticks, slots, etc.
|
||||
//!
|
||||
//! The _clock sysvar_ provides access to the [`Clock`] type, which includes the
|
||||
//! current slot, the current epoch, and the approximate real-world time of the
|
||||
//! slot.
|
||||
//!
|
||||
//! [`Clock`] implements [`Sysvar::get`] and can be loaded efficiently without
|
||||
//! passing the sysvar account ID to the program.
|
||||
//!
|
||||
//! See also the Solana [documentation on the clock sysvar][sdoc].
|
||||
//!
|
||||
//! [sdoc]: https://docs.solana.com/developing/runtime-facilities/sysvars#clock
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Accessing via on-chain program directly:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::clock::{self, Clock},
|
||||
//! # sysvar::Sysvar,
|
||||
//! # };
|
||||
//! # use solana_program::program_error::ProgramError;
|
||||
//! #
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//!
|
||||
//! let clock = Clock::get()?;
|
||||
//! msg!("clock: {:#?}", clock);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # use solana_program::sysvar::SysvarId;
|
||||
//! # let p = Clock::id();
|
||||
//! # let l = &mut 1169280;
|
||||
//! # let d = &mut vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0];
|
||||
//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0);
|
||||
//! # let accounts = &[a.clone(), a];
|
||||
//! # process_instruction(
|
||||
//! # &Pubkey::new_unique(),
|
||||
//! # accounts,
|
||||
//! # &[],
|
||||
//! # )?;
|
||||
//! # Ok::<(), ProgramError>(())
|
||||
//! ```
|
||||
//!
|
||||
//! Accessing via on-chain program's account parameters:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::clock::{self, Clock},
|
||||
//! # sysvar::Sysvar,
|
||||
//! # };
|
||||
//! # use solana_program::program_error::ProgramError;
|
||||
//! #
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//! let account_info_iter = &mut accounts.iter();
|
||||
//! let clock_account_info = next_account_info(account_info_iter)?;
|
||||
//!
|
||||
//! assert!(clock::check_id(clock_account_info.key));
|
||||
//!
|
||||
//! let clock = Clock::from_account_info(clock_account_info)?;
|
||||
//! msg!("clock: {:#?}", clock);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # use solana_program::sysvar::SysvarId;
|
||||
//! # let p = Clock::id();
|
||||
//! # let l = &mut 1169280;
|
||||
//! # let d = &mut vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0];
|
||||
//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0);
|
||||
//! # let accounts = &[a.clone(), a];
|
||||
//! # process_instruction(
|
||||
//! # &Pubkey::new_unique(),
|
||||
//! # accounts,
|
||||
//! # &[],
|
||||
//! # )?;
|
||||
//! # Ok::<(), ProgramError>(())
|
||||
//! ```
|
||||
//!
|
||||
//! Accessing via the RPC client:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::example_mocks::solana_sdk;
|
||||
//! # use solana_program::example_mocks::solana_client;
|
||||
//! # use solana_sdk::account::Account;
|
||||
//! # use solana_client::rpc_client::RpcClient;
|
||||
//! # use solana_sdk::sysvar::clock::{self, Clock};
|
||||
//! # use anyhow::Result;
|
||||
//! #
|
||||
//! fn print_sysvar_clock(client: &RpcClient) -> Result<()> {
|
||||
//! # client.set_get_account_response(clock::ID, Account {
|
||||
//! # lamports: 1169280,
|
||||
//! # data: vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0],
|
||||
//! # owner: solana_sdk::system_program::ID,
|
||||
//! # executable: false,
|
||||
//! # rent_epoch: 307,
|
||||
//! # });
|
||||
//! #
|
||||
//! let clock = client.get_account(&clock::ID)?;
|
||||
//! let data: Clock = bincode::deserialize(&clock.data)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # let client = RpcClient::new(String::new());
|
||||
//! # print_sysvar_clock(&client)?;
|
||||
//! #
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! ```
|
||||
|
||||
pub use crate::clock::Clock;
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
|
|
|
@ -1,5 +1,130 @@
|
|||
//! This account contains the current cluster rent
|
||||
//! Information about epoch duration.
|
||||
//!
|
||||
//! The _epoch schedule_ sysvar provides access to the [`EpochSchedule`] type,
|
||||
//! which includes the number of slots per epoch, timing of leader schedule
|
||||
//! selection, and information about epoch warm-up time.
|
||||
//!
|
||||
//! [`EpochSchedule`] implements [`Sysvar::get`] and can be loaded efficiently without
|
||||
//! passing the sysvar account ID to the program.
|
||||
//!
|
||||
//! See also the Solana [documentation on the epoch schedule sysvar][sdoc].
|
||||
//!
|
||||
//! [sdoc]: https://docs.solana.com/developing/runtime-facilities/sysvars#epochschedule
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Accessing via on-chain program directly:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::epoch_schedule::{self, EpochSchedule},
|
||||
//! # sysvar::Sysvar,
|
||||
//! # };
|
||||
//! # use solana_program::program_error::ProgramError;
|
||||
//! #
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//!
|
||||
//! let epoch_schedule = EpochSchedule::get()?;
|
||||
//! msg!("epoch_schedule: {:#?}", epoch_schedule);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # use solana_program::sysvar::SysvarId;
|
||||
//! # let p = EpochSchedule::id();
|
||||
//! # let l = &mut 1120560;
|
||||
//! # let d = &mut vec![0, 32, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0);
|
||||
//! # let accounts = &[a.clone(), a];
|
||||
//! # process_instruction(
|
||||
//! # &Pubkey::new_unique(),
|
||||
//! # accounts,
|
||||
//! # &[],
|
||||
//! # )?;
|
||||
//! # Ok::<(), ProgramError>(())
|
||||
//! ```
|
||||
//!
|
||||
//! Accessing via on-chain program's account parameters:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::epoch_schedule::{self, EpochSchedule},
|
||||
//! # sysvar::Sysvar,
|
||||
//! # };
|
||||
//! # use solana_program::program_error::ProgramError;
|
||||
//! #
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//! let account_info_iter = &mut accounts.iter();
|
||||
//! let epoch_schedule_account_info = next_account_info(account_info_iter)?;
|
||||
//!
|
||||
//! assert!(epoch_schedule::check_id(epoch_schedule_account_info.key));
|
||||
//!
|
||||
//! let epoch_schedule = EpochSchedule::from_account_info(epoch_schedule_account_info)?;
|
||||
//! msg!("epoch_schedule: {:#?}", epoch_schedule);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # use solana_program::sysvar::SysvarId;
|
||||
//! # let p = EpochSchedule::id();
|
||||
//! # let l = &mut 1120560;
|
||||
//! # let d = &mut vec![0, 32, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0);
|
||||
//! # let accounts = &[a.clone(), a];
|
||||
//! # process_instruction(
|
||||
//! # &Pubkey::new_unique(),
|
||||
//! # accounts,
|
||||
//! # &[],
|
||||
//! # )?;
|
||||
//! # Ok::<(), ProgramError>(())
|
||||
//! ```
|
||||
//!
|
||||
//! Accessing via the RPC client:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::example_mocks::solana_sdk;
|
||||
//! # use solana_program::example_mocks::solana_client;
|
||||
//! # use solana_sdk::account::Account;
|
||||
//! # use solana_client::rpc_client::RpcClient;
|
||||
//! # use solana_sdk::sysvar::epoch_schedule::{self, EpochSchedule};
|
||||
//! # use anyhow::Result;
|
||||
//! #
|
||||
//! fn print_sysvar_epoch_schedule(client: &RpcClient) -> Result<()> {
|
||||
//! # client.set_get_account_response(epoch_schedule::ID, Account {
|
||||
//! # lamports: 1120560,
|
||||
//! # data: vec![0, 32, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
//! # owner: solana_sdk::system_program::ID,
|
||||
//! # executable: false,
|
||||
//! # rent_epoch: 307,
|
||||
//! # });
|
||||
//! #
|
||||
//! let epoch_schedule = client.get_account(&epoch_schedule::ID)?;
|
||||
//! let data: EpochSchedule = bincode::deserialize(&epoch_schedule.data)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # let client = RpcClient::new(String::new());
|
||||
//! # print_sysvar_epoch_schedule(&client)?;
|
||||
//! #
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! ```
|
||||
pub use crate::epoch_schedule::EpochSchedule;
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
//! This account contains the current cluster fees
|
||||
//! Current cluster fees.
|
||||
//!
|
||||
//! The _fees sysvar_ provides access to the [`Fees`] type, which contains the
|
||||
//! current [`FeeCalculator`].
|
||||
//!
|
||||
//! [`Fees`] implements [`Sysvar::get`] and can be loaded efficiently without
|
||||
//! passing the sysvar account ID to the program.
|
||||
//!
|
||||
//! This sysvar is deprecated and will not be available in the future.
|
||||
//! Transaction fees should be determined with the [`getFeeForMessage`] RPC
|
||||
//! method. For additional context see the [Comprehensive Compute Fees
|
||||
//! proposal][ccf].
|
||||
//!
|
||||
//! [`getFeeForMessage`]: https://docs.solana.com/developing/clients/jsonrpc-api#getfeeformessage
|
||||
//! [ccf]: https://docs.solana.com/proposals/comprehensive-compute-fees
|
||||
//!
|
||||
//! See also the Solana [documentation on the fees sysvar][sdoc].
|
||||
//!
|
||||
//! [sdoc]: https://docs.solana.com/developing/runtime-facilities/sysvars#fees
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use {
|
||||
|
@ -12,6 +30,7 @@ use {
|
|||
|
||||
crate::declare_deprecated_sysvar_id!("SysvarFees111111111111111111111111111111111", Fees);
|
||||
|
||||
/// Transaction fees.
|
||||
#[deprecated(
|
||||
since = "1.9.0",
|
||||
note = "Please do not use, will no longer be available in the future"
|
||||
|
|
|
@ -1,5 +1,34 @@
|
|||
//! The serialized instructions of the current transaction.
|
||||
//!
|
||||
//! The _instructions sysvar_ provides access to the serialized instruction data
|
||||
//! for the currently-running transaction. This allows for [instruction
|
||||
//! introspection][in], which is required for correctly interoperating with
|
||||
//! native programs like the [secp256k1] and [ed25519] programs.
|
||||
//!
|
||||
//! [in]: https://docs.solana.com/implemented-proposals/instruction_introspection
|
||||
//! [secp256k1]: crate::secp256k1_program
|
||||
//! [ed25519]: crate::ed25519_program
|
||||
//!
|
||||
//! Unlike other sysvars, the data in the instructions sysvar is not accessed
|
||||
//! through a type that implements the [`Sysvar`] trait. Instead, the
|
||||
//! instruction sysvar is accessed through several free functions within this
|
||||
//! module.
|
||||
//!
|
||||
//! [`Sysvar`]: crate::sysvar::Sysvar
|
||||
//!
|
||||
//! See also the Solana [documentation on the instructions sysvar][sdoc].
|
||||
//!
|
||||
//! [sdoc]: https://docs.solana.com/developing/runtime-facilities/sysvars#instructions
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! For a complete example of how the instructions sysvar is used see the
|
||||
//! documentation for [`secp256k1_instruction`] in the `solana-sdk` crate.
|
||||
//!
|
||||
//! [`secp256k1_instruction`]: https://docs.rs/solana-sdk/latest/solana_sdk/secp256k1_instruction/index.html
|
||||
|
||||
#![allow(clippy::integer_arithmetic)]
|
||||
//! This account contains the serialized transaction instructions
|
||||
|
||||
use crate::{
|
||||
account_info::AccountInfo,
|
||||
instruction::{AccountMeta, Instruction},
|
||||
|
@ -14,12 +43,23 @@ use {
|
|||
bitflags::bitflags,
|
||||
};
|
||||
|
||||
// Instructions Sysvar, dummy type, use the associated helpers instead of the Sysvar trait
|
||||
/// Instructions sysvar, dummy type.
|
||||
///
|
||||
/// This type exists for consistency with other sysvar modules, but is a dummy
|
||||
/// type that does not contain sysvar data. It implements the [`SysvarId`] trait
|
||||
/// but does not implement the [`Sysvar`] trait.
|
||||
///
|
||||
/// [`SysvarId`]: crate::sysvar::SysvarId
|
||||
/// [`Sysvar`]: crate::sysvar::Sysvar
|
||||
///
|
||||
/// Use the free functions in this module to access the instructions sysvar.
|
||||
pub struct Instructions();
|
||||
|
||||
crate::declare_sysvar_id!("Sysvar1nstructions1111111111111111111111111", Instructions);
|
||||
|
||||
// Construct the account data for the Instructions Sysvar
|
||||
/// Construct the account data for the instructions sysvar.
|
||||
///
|
||||
/// This function is used by the runtime and not available to Solana programs.
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
pub fn construct_instructions_data(instructions: &[BorrowedInstruction]) -> Vec<u8> {
|
||||
let mut data = serialize_instructions(instructions);
|
||||
|
@ -29,14 +69,20 @@ pub fn construct_instructions_data(instructions: &[BorrowedInstruction]) -> Vec<
|
|||
data
|
||||
}
|
||||
|
||||
/// Borrowed version of AccountMeta
|
||||
/// Borrowed version of `AccountMeta`.
|
||||
///
|
||||
/// This struct is used by the runtime when constructing the sysvar. It is not
|
||||
/// useful to Solana programs.
|
||||
pub struct BorrowedAccountMeta<'a> {
|
||||
pub pubkey: &'a Pubkey,
|
||||
pub is_signer: bool,
|
||||
pub is_writable: bool,
|
||||
}
|
||||
|
||||
/// Borrowed version of Instruction
|
||||
/// Borrowed version of `Instruction`.
|
||||
///
|
||||
/// This struct is used by the runtime when constructing the sysvar. It is not
|
||||
/// useful to Solana programs.
|
||||
pub struct BorrowedInstruction<'a> {
|
||||
pub program_id: &'a Pubkey,
|
||||
pub accounts: Vec<BorrowedAccountMeta<'a>>,
|
||||
|
@ -99,7 +145,9 @@ fn serialize_instructions(instructions: &[BorrowedInstruction]) -> Vec<u8> {
|
|||
}
|
||||
|
||||
/// Load the current `Instruction`'s index in the currently executing
|
||||
/// `Transaction` from the Instructions Sysvar data
|
||||
/// `Transaction`.
|
||||
///
|
||||
/// `data` is the instructions sysvar account data.
|
||||
#[deprecated(
|
||||
since = "1.8.0",
|
||||
note = "Unsafe because the sysvar accounts address is not checked, please use `load_current_index_checked` instead"
|
||||
|
@ -112,7 +160,11 @@ pub fn load_current_index(data: &[u8]) -> u16 {
|
|||
}
|
||||
|
||||
/// Load the current `Instruction`'s index in the currently executing
|
||||
/// `Transaction`
|
||||
/// `Transaction`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`ProgramError::UnsupportedSysvar`] if the given account's ID is not equal to [`ID`].
|
||||
pub fn load_current_index_checked(
|
||||
instruction_sysvar_account_info: &AccountInfo,
|
||||
) -> Result<u16, ProgramError> {
|
||||
|
@ -127,7 +179,7 @@ pub fn load_current_index_checked(
|
|||
Ok(u16::from_le_bytes(instr_fixed_data))
|
||||
}
|
||||
|
||||
/// Store the current `Instruction`'s index in the Instructions Sysvar data
|
||||
/// Store the current `Instruction`'s index in the instructions sysvar data.
|
||||
pub fn store_current_index(data: &mut [u8], instruction_index: u16) {
|
||||
let last_index = data.len() - 2;
|
||||
data[last_index..last_index + 2].copy_from_slice(&instruction_index.to_le_bytes());
|
||||
|
@ -178,7 +230,9 @@ fn deserialize_instruction(index: usize, data: &[u8]) -> Result<Instruction, San
|
|||
}
|
||||
|
||||
/// Load an `Instruction` in the currently executing `Transaction` at the
|
||||
/// specified index
|
||||
/// specified index.
|
||||
///
|
||||
/// `data` is the instructions sysvar account data.
|
||||
#[deprecated(
|
||||
since = "1.8.0",
|
||||
note = "Unsafe because the sysvar accounts address is not checked, please use `load_instruction_at_checked` instead"
|
||||
|
@ -188,7 +242,11 @@ pub fn load_instruction_at(index: usize, data: &[u8]) -> Result<Instruction, San
|
|||
}
|
||||
|
||||
/// Load an `Instruction` in the currently executing `Transaction` at the
|
||||
/// specified index
|
||||
/// specified index.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`ProgramError::UnsupportedSysvar`] if the given account's ID is not equal to [`ID`].
|
||||
pub fn load_instruction_at_checked(
|
||||
index: usize,
|
||||
instruction_sysvar_account_info: &AccountInfo,
|
||||
|
@ -205,7 +263,11 @@ pub fn load_instruction_at_checked(
|
|||
}
|
||||
|
||||
/// Returns the `Instruction` relative to the current `Instruction` in the
|
||||
/// currently executing `Transaction`
|
||||
/// currently executing `Transaction`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`ProgramError::UnsupportedSysvar`] if the given account's ID is not equal to [`ID`].
|
||||
pub fn get_instruction_relative(
|
||||
index_relative_to_current: i64,
|
||||
instruction_sysvar_account_info: &AccountInfo,
|
||||
|
|
|
@ -1,5 +1,82 @@
|
|||
//! Access to special accounts with dynamically-updated data.
|
||||
//!
|
||||
//! Sysvars are special accounts that contain dynamically-updated data about the
|
||||
//! network cluster, the blockchain history, and the executing transaction. Each
|
||||
//! sysvar is defined in its own submodule within this module. The [`clock`],
|
||||
//! [`epoch_schedule`], [`instructions`], and [`rent`] sysvars are most useful
|
||||
//! to on-chain programs.
|
||||
//!
|
||||
//! Simple sysvars implement the [`Sysvar::get`] method, which loads a sysvar
|
||||
//! directly from the runtime, as in this example that logs the `clock` sysvar:
|
||||
//!
|
||||
//! ```
|
||||
//! 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`] sysvar.
|
||||
//!
|
||||
//! ```
|
||||
//! 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, or the serialization attempt
|
||||
//! 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.
|
||||
//!
|
||||
//! All sysvar accounts are owned by the account identified by [`sysvar::ID`].
|
||||
//!
|
||||
//! [`sysvar::ID`]: crate::sysvar::ID
|
||||
//!
|
||||
//! For more details see the Solana [documentation on sysvars][sysvardoc].
|
||||
//!
|
||||
//! [sysvardoc]: https://docs.solana.com/developing/runtime-facilities/sysvars
|
||||
|
@ -37,6 +114,7 @@ lazy_static! {
|
|||
];
|
||||
}
|
||||
|
||||
/// Returns `true` of the given `Pubkey` is a sysvar account.
|
||||
pub fn is_sysvar_id(id: &Pubkey) -> bool {
|
||||
ALL_IDS.iter().any(|key| key == id)
|
||||
}
|
||||
|
@ -94,35 +172,54 @@ macro_rules! declare_deprecated_sysvar_id(
|
|||
// Owner pubkey for sysvar accounts
|
||||
crate::declare_id!("Sysvar1111111111111111111111111111111111111");
|
||||
|
||||
/// A type that holds sysvar data and has an associated sysvar `Pubkey`.
|
||||
pub trait SysvarId {
|
||||
/// The `Pubkey` of the sysvar.
|
||||
fn id() -> Pubkey;
|
||||
|
||||
/// Returns `true` if the given pubkey is the program ID.
|
||||
fn check_id(pubkey: &Pubkey) -> bool;
|
||||
}
|
||||
|
||||
// Sysvar utilities
|
||||
/// A type that holds sysvar data.
|
||||
pub trait Sysvar:
|
||||
SysvarId + Default + Sized + serde::Serialize + serde::de::DeserializeOwned
|
||||
{
|
||||
/// The size in bytes of the sysvar as serialized account data.
|
||||
fn size_of() -> usize {
|
||||
bincode::serialized_size(&Self::default()).unwrap() as usize
|
||||
}
|
||||
|
||||
/// Deserializes a sysvar from its `AccountInfo`.
|
||||
/// Deserializes the sysvar from its `AccountInfo`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If `account_info` does not have the same ID as the sysvar
|
||||
/// this function returns [`ProgramError::InvalidArgument`].
|
||||
/// If `account_info` does not have the same ID as the sysvar this function
|
||||
/// returns [`ProgramError::InvalidArgument`].
|
||||
fn from_account_info(account_info: &AccountInfo) -> Result<Self, ProgramError> {
|
||||
if !Self::check_id(account_info.unsigned_key()) {
|
||||
return Err(ProgramError::InvalidArgument);
|
||||
}
|
||||
bincode::deserialize(&account_info.data.borrow()).map_err(|_| ProgramError::InvalidArgument)
|
||||
}
|
||||
|
||||
/// Serializes the sysvar to `AccountInfo`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if serialization failed.
|
||||
fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> {
|
||||
bincode::serialize_into(&mut account_info.data.borrow_mut()[..], self).ok()
|
||||
}
|
||||
|
||||
/// Load the sysvar directly from the runtime.
|
||||
///
|
||||
/// This is the preferred way to load a sysvar. Calling this method does not
|
||||
/// incur any deserialization overhead, and does not require the sysvar
|
||||
/// account to be passed to the program.
|
||||
///
|
||||
/// Not all sysvars support this method. If not, it returns
|
||||
/// [`ProgramError::UnsupportedSysvar`].
|
||||
fn get() -> Result<Self, ProgramError> {
|
||||
Err(ProgramError::UnsupportedSysvar)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
//! Information about recent blocks and their fee calculators.
|
||||
//!
|
||||
//! The _recent blockhashes sysvar_ provides access to the [`RecentBlockhashes`],
|
||||
//! which contains recent blockhahes and their [`FeeCalculator`]s.
|
||||
//!
|
||||
//! [`RecentBlockhashes`] does not implement [`Sysvar::get`].
|
||||
//!
|
||||
//! This sysvar is deprecated and should not be used. Transaction fees should be
|
||||
//! determined with the [`getFeeForMessage`] RPC method. For additional context
|
||||
//! see the [Comprehensive Compute Fees proposal][ccf].
|
||||
//!
|
||||
//! [`getFeeForMessage`]: https://docs.solana.com/developing/clients/jsonrpc-api#getfeeformessage
|
||||
//! [ccf]: https://docs.solana.com/proposals/comprehensive-compute-fees
|
||||
//!
|
||||
//! See also the Solana [documentation on the recent blockhashes sysvar][sdoc].
|
||||
//!
|
||||
//! [sdoc]: https://docs.solana.com/developing/runtime-facilities/sysvars#recentblockhashes
|
||||
|
||||
#![allow(deprecated)]
|
||||
#![allow(clippy::integer_arithmetic)]
|
||||
use {
|
||||
|
|
|
@ -1,5 +1,131 @@
|
|||
//! This account contains the current cluster rent
|
||||
//! Configuration for network [rent].
|
||||
//!
|
||||
//! [rent]: https://docs.solana.com/implemented-proposals/rent
|
||||
//!
|
||||
//! The _rent sysvar_ provides access to the [`Rent`] type, which defines
|
||||
//! storage rent fees.
|
||||
//!
|
||||
//! [`Rent`] implements [`Sysvar::get`] and can be loaded efficiently without
|
||||
//! passing the sysvar account ID to the program.
|
||||
//!
|
||||
//! See also the Solana [documentation on the rent sysvar][sdoc].
|
||||
//!
|
||||
//! [sdoc]: https://docs.solana.com/developing/runtime-facilities/sysvars#rent
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Accessing via on-chain program directly:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::rent::{self, Rent},
|
||||
//! # sysvar::Sysvar,
|
||||
//! # };
|
||||
//! # use solana_program::program_error::ProgramError;
|
||||
//! #
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//!
|
||||
//! let rent = Rent::get()?;
|
||||
//! msg!("rent: {:#?}", rent);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # use solana_program::sysvar::SysvarId;
|
||||
//! # let p = Rent::id();
|
||||
//! # let l = &mut 1009200;
|
||||
//! # let d = &mut vec![152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 100];
|
||||
//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0);
|
||||
//! # let accounts = &[a.clone(), a];
|
||||
//! # process_instruction(
|
||||
//! # &Pubkey::new_unique(),
|
||||
//! # accounts,
|
||||
//! # &[],
|
||||
//! # )?;
|
||||
//! # Ok::<(), ProgramError>(())
|
||||
//! ```
|
||||
//!
|
||||
//! Accessing via on-chain program's parameters:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::rent::{self, Rent},
|
||||
//! # sysvar::Sysvar,
|
||||
//! # };
|
||||
//! # use solana_program::program_error::ProgramError;
|
||||
//! #
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//! let account_info_iter = &mut accounts.iter();
|
||||
//! let rent_account_info = next_account_info(account_info_iter)?;
|
||||
//!
|
||||
//! assert!(rent::check_id(rent_account_info.key));
|
||||
//!
|
||||
//! let rent = Rent::from_account_info(rent_account_info)?;
|
||||
//! msg!("rent: {:#?}", rent);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # use solana_program::sysvar::SysvarId;
|
||||
//! # let p = Rent::id();
|
||||
//! # let l = &mut 1009200;
|
||||
//! # let d = &mut vec![152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 100];
|
||||
//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0);
|
||||
//! # let accounts = &[a.clone(), a];
|
||||
//! # process_instruction(
|
||||
//! # &Pubkey::new_unique(),
|
||||
//! # accounts,
|
||||
//! # &[],
|
||||
//! # )?;
|
||||
//! # Ok::<(), ProgramError>(())
|
||||
//! ```
|
||||
//!
|
||||
//! Accessing via the RPC client:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::example_mocks::solana_sdk;
|
||||
//! # use solana_program::example_mocks::solana_client;
|
||||
//! # use solana_sdk::account::Account;
|
||||
//! # use solana_client::rpc_client::RpcClient;
|
||||
//! # use solana_sdk::sysvar::rent::{self, Rent};
|
||||
//! # use anyhow::Result;
|
||||
//! #
|
||||
//! fn print_sysvar_rent(client: &RpcClient) -> Result<()> {
|
||||
//! # client.set_get_account_response(rent::ID, Account {
|
||||
//! # lamports: 1009200,
|
||||
//! # data: vec![152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 100],
|
||||
//! # owner: solana_sdk::system_program::ID,
|
||||
//! # executable: false,
|
||||
//! # rent_epoch: 307,
|
||||
//! # });
|
||||
//! #
|
||||
//! let rent = client.get_account(&rent::ID)?;
|
||||
//! let data: Rent = bincode::deserialize(&rent.data)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # let client = RpcClient::new(String::new());
|
||||
//! # print_sysvar_rent(&client)?;
|
||||
//! #
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! ```
|
||||
pub use crate::rent::Rent;
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! DEPRECATED: This sysvar can be removed once the pico-inflation feature is enabled
|
||||
//!
|
||||
//! This sysvar is deprecated and unused.
|
||||
|
||||
use crate::sysvar::Sysvar;
|
||||
|
||||
crate::declare_sysvar_id!("SysvarRewards111111111111111111111111111111", Rewards);
|
||||
|
|
|
@ -1,7 +1,50 @@
|
|||
//! named accounts for synthesized data accounts for bank state, etc.
|
||||
//! The most recent hashes of a slot's parent banks.
|
||||
//!
|
||||
//! this account carries the Bank's most recent bank hashes for some N parents
|
||||
//! The _slot hashes sysvar_ provides access to the [`SlotHashes`] type.
|
||||
//!
|
||||
//! The [`Sysvar::from_account_info`] and [`Sysvar::get`] methods always return
|
||||
//! [`ProgramError::UnsupportedSysvar`] because this sysvar account is too large
|
||||
//! to process on-chain. Thus this sysvar cannot be accessed on chain, though
|
||||
//! one can still use the [`SysvarId::id`], [`SysvarId::check_id`] and
|
||||
//! [`Sysvar::size_of`] methods in an on-chain program, and it can be accessed
|
||||
//! off-chain through RPC.
|
||||
//!
|
||||
//! [`SysvarId::id`]: crate::sysvar::SysvarId::id
|
||||
//! [`SysvarId::check_id`]: crate::sysvar::SysvarId::check_id
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Calling via the RPC client:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::example_mocks::solana_sdk;
|
||||
//! # use solana_program::example_mocks::solana_client;
|
||||
//! # use solana_sdk::account::Account;
|
||||
//! # use solana_client::rpc_client::RpcClient;
|
||||
//! # use solana_sdk::sysvar::slot_hashes::{self, SlotHashes};
|
||||
//! # use anyhow::Result;
|
||||
//! #
|
||||
//! fn print_sysvar_slot_hashes(client: &RpcClient) -> Result<()> {
|
||||
//! # client.set_get_account_response(slot_hashes::ID, Account {
|
||||
//! # lamports: 1009200,
|
||||
//! # data: vec![1, 0, 0, 0, 0, 0, 0, 0, 86, 190, 235, 7, 0, 0, 0, 0, 133, 242, 94, 158, 223, 253, 207, 184, 227, 194, 235, 27, 176, 98, 73, 3, 175, 201, 224, 111, 21, 65, 73, 27, 137, 73, 229, 19, 255, 192, 193, 126],
|
||||
//! # owner: solana_sdk::system_program::ID,
|
||||
//! # executable: false,
|
||||
//! # rent_epoch: 307,
|
||||
//! # });
|
||||
//! #
|
||||
//! let slot_hashes = client.get_account(&slot_hashes::ID)?;
|
||||
//! let data: SlotHashes = bincode::deserialize(&slot_hashes.data)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # let client = RpcClient::new(String::new());
|
||||
//! # print_sysvar_slot_hashes(&client)?;
|
||||
//! #
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! ```
|
||||
|
||||
pub use crate::slot_hashes::SlotHashes;
|
||||
use crate::{account_info::AccountInfo, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
|
|
|
@ -1,8 +1,52 @@
|
|||
//! named accounts for synthesized data accounts for bank state, etc.
|
||||
//! A bitvector of slots present over the last epoch.
|
||||
//!
|
||||
//! this account carries a bitvector of slots present over the past
|
||||
//! epoch
|
||||
//! The _slot history sysvar_ provides access to the [`SlotHistory`] type.
|
||||
//!
|
||||
//! The [`Sysvar::from_account_info`] and [`Sysvar::get`] methods always return
|
||||
//! [`ProgramError::UnsupportedSysvar`] because this sysvar account is too large
|
||||
//! to process on-chain. Thus this sysvar cannot be accessed on chain, though
|
||||
//! one can still use the [`SysvarId::id`], [`SysvarId::check_id`] and
|
||||
//! [`Sysvar::size_of`] methods in an on-chain program, and it can be accessed
|
||||
//! off-chain through RPC.
|
||||
//!
|
||||
//! [`SysvarId::id`]: crate::sysvar::SysvarId::id
|
||||
//! [`SysvarId::check_id`]: crate::sysvar::SysvarId::check_id
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Calling via the RPC client:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::example_mocks::solana_sdk;
|
||||
//! # use solana_program::example_mocks::solana_client;
|
||||
//! # use solana_sdk::account::Account;
|
||||
//! # use solana_client::rpc_client::RpcClient;
|
||||
//! # use solana_sdk::sysvar::slot_history::{self, SlotHistory};
|
||||
//! # use anyhow::Result;
|
||||
//! #
|
||||
//! fn print_sysvar_slot_history(client: &RpcClient) -> Result<()> {
|
||||
//! # let slot_history = SlotHistory::default();
|
||||
//! # let data: Vec<u8> = bincode::serialize(&slot_history)?;
|
||||
//! # client.set_get_account_response(slot_history::ID, Account {
|
||||
//! # lamports: 913326000,
|
||||
//! # data,
|
||||
//! # owner: solana_sdk::system_program::ID,
|
||||
//! # executable: false,
|
||||
//! # rent_epoch: 307,
|
||||
//! # });
|
||||
//! #
|
||||
//! let slot_history = client.get_account(&slot_history::ID)?;
|
||||
//! let data: SlotHistory = bincode::deserialize(&slot_history.data)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # let client = RpcClient::new(String::new());
|
||||
//! # print_sysvar_slot_history(&client)?;
|
||||
//! #
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! ```
|
||||
|
||||
use crate::sysvar::Sysvar;
|
||||
pub use crate::{
|
||||
account_info::AccountInfo, program_error::ProgramError, slot_history::SlotHistory,
|
||||
|
|
|
@ -1,7 +1,50 @@
|
|||
//! named accounts for synthesized data accounts for bank state, etc.
|
||||
//! History of stake activations and de-activations.
|
||||
//!
|
||||
//! this account carries history about stake activations and de-activations
|
||||
//! The _stake history sysvar_ provides access to the [`StakeHistory`] type.
|
||||
//!
|
||||
//! The [`Sysvar::get`] method always returns
|
||||
//! [`ProgramError::UnsupportedSysvar`], and in practice the data size of this
|
||||
//! sysvar is too large to process on chain. One can still use the
|
||||
//! [`SysvarId::id`], [`SysvarId::check_id`] and [`Sysvar::size_of`] methods in
|
||||
//! an on-chain program, and it can be accessed off-chain through RPC.
|
||||
//!
|
||||
//! [`ProgramError::UnsupportedSysvar`]: crate::program_error::ProgramError::UnsupportedSysvar
|
||||
//! [`SysvarId::id`]: crate::sysvar::SysvarId::id
|
||||
//! [`SysvarId::check_id`]: crate::sysvar::SysvarId::check_id
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Calling via the RPC client:
|
||||
//!
|
||||
//! ```
|
||||
//! # use solana_program::example_mocks::solana_sdk;
|
||||
//! # use solana_program::example_mocks::solana_client;
|
||||
//! # use solana_sdk::account::Account;
|
||||
//! # use solana_client::rpc_client::RpcClient;
|
||||
//! # use solana_sdk::sysvar::stake_history::{self, StakeHistory};
|
||||
//! # use anyhow::Result;
|
||||
//! #
|
||||
//! fn print_sysvar_stake_history(client: &RpcClient) -> Result<()> {
|
||||
//! # client.set_get_account_response(stake_history::ID, Account {
|
||||
//! # lamports: 114979200,
|
||||
//! # data: vec![0, 0, 0, 0, 0, 0, 0, 0],
|
||||
//! # owner: solana_sdk::system_program::ID,
|
||||
//! # executable: false,
|
||||
//! # rent_epoch: 307,
|
||||
//! # });
|
||||
//! #
|
||||
//! let stake_history = client.get_account(&stake_history::ID)?;
|
||||
//! let data: StakeHistory = bincode::deserialize(&stake_history.data)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! #
|
||||
//! # let client = RpcClient::new(String::new());
|
||||
//! # print_sysvar_stake_history(&client)?;
|
||||
//! #
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! ```
|
||||
|
||||
pub use crate::stake_history::StakeHistory;
|
||||
use crate::sysvar::Sysvar;
|
||||
|
||||
|
|
Loading…
Reference in New Issue