798 lines
29 KiB
Rust
798 lines
29 KiB
Rust
//! The base library for all Solana on-chain Rust programs.
|
|
//!
|
|
//! All Solana Rust programs that run on-chain will link to this crate, which
|
|
//! acts as a standard library for Solana programs. Solana programs also link to
|
|
//! the [Rust standard library][std], though it is [modified][sstd] for the
|
|
//! Solana runtime environment. While off-chain programs that interact with the
|
|
//! Solana network _can_ link to this crate, they typically instead use the
|
|
//! [`solana-sdk`] crate, which reexports all modules from `solana-program`.
|
|
//!
|
|
//! [std]: https://doc.rust-lang.org/stable/std/
|
|
//! [sstd]: https://docs.solana.com/developing/on-chain-programs/developing-rust#restrictions
|
|
//! [`solana-sdk`]: https://docs.rs/solana-sdk/latest/solana_sdk/
|
|
//!
|
|
//! This library defines
|
|
//!
|
|
//! - macros for declaring the [program entrypoint][pe],
|
|
//! - [core data types][cdt],
|
|
//! - [logging] macros,
|
|
//! - [serialization] methods,
|
|
//! - methods for [cross-program instruction execution][cpi],
|
|
//! - program IDs and instruction constructors for the system program and other
|
|
//! [native programs][np],
|
|
//! - [sysvar] accessors.
|
|
//!
|
|
//! [pe]: #defining-a-solana-program
|
|
//! [cdt]: #core-data-types
|
|
//! [logging]: crate::log
|
|
//! [serialization]: #serialization
|
|
//! [np]: #native-programs
|
|
//! [cpi]: #cross-program-instruction-execution
|
|
//! [sysvar]: #sysvars
|
|
//!
|
|
//! Idiomatic examples of `solana-program` usage can be found in
|
|
//! [the Solana Program Library][spl].
|
|
//!
|
|
//! [spl]: https://github.com/solana-labs/solana-program-library
|
|
//!
|
|
//! # Defining a solana program
|
|
//!
|
|
//! Solana program crates have some unique properties compared to typical Rust
|
|
//! programs:
|
|
//!
|
|
//! - They are often compiled for both on-chain use and off-chain use. This is
|
|
//! primarily because off-chain clients may need access to data types
|
|
//! defined by the on-chain program.
|
|
//! - They do not define a `main` function, but instead define their entrypoint
|
|
//! with the [`entrypoint!`] macro.
|
|
//! - They are compiled as the ["cdylib"] crate type for dynamic loading
|
|
//! by the Solana runtime.
|
|
//! - They run in a constrained VM environment, and while they do have access to
|
|
//! the [Rust standard library][std], many features of the standard library,
|
|
//! particularly related to OS services, will fail at runtime, will silently
|
|
//! do nothing, or are not defined. See the [restrictions to the Rust standard
|
|
//! library][sstd] in the Solana documentation for more.
|
|
//!
|
|
//! [std]: https://doc.rust-lang.org/std/index.html
|
|
//! ["cdylib"]: https://doc.rust-lang.org/reference/linkage.html
|
|
//!
|
|
//! Because multiple crates that are linked together cannot all define
|
|
//! program entrypoints (see the [`entrypoint!`] documentation) a common
|
|
//! convention is to use a [Cargo feature] called `no-entrypoint` to allow
|
|
//! the program entrypoint to be disabled.
|
|
//!
|
|
//! [Cargo feature]: https://doc.rust-lang.org/cargo/reference/features.html
|
|
//!
|
|
//! The skeleton of a Solana program typically looks like:
|
|
//!
|
|
//! ```
|
|
//! #[cfg(not(feature = "no-entrypoint"))]
|
|
//! pub mod entrypoint {
|
|
//! use solana_program::{
|
|
//! account_info::AccountInfo,
|
|
//! entrypoint,
|
|
//! entrypoint::ProgramResult,
|
|
//! pubkey::Pubkey,
|
|
//! };
|
|
//!
|
|
//! entrypoint!(process_instruction);
|
|
//!
|
|
//! pub fn process_instruction(
|
|
//! program_id: &Pubkey,
|
|
//! accounts: &[AccountInfo],
|
|
//! instruction_data: &[u8],
|
|
//! ) -> ProgramResult {
|
|
//! // Decode and dispatch instructions here.
|
|
//! todo!()
|
|
//! }
|
|
//! }
|
|
//!
|
|
//! // Additional code goes here.
|
|
//! ```
|
|
//!
|
|
//! With a `Cargo.toml` file that contains
|
|
//!
|
|
//! ```toml
|
|
//! [lib]
|
|
//! crate-type = ["cdylib", "rlib"]
|
|
//!
|
|
//! [features]
|
|
//! no-entrypoint = []
|
|
//! ```
|
|
//!
|
|
//! Note that a Solana program must specify its crate-type as "cdylib", and
|
|
//! "cdylib" crates will automatically be discovered and built by the `cargo
|
|
//! build-bpf` command. Solana programs also often have crate-type "rlib" so
|
|
//! they can be linked to other Rust crates.
|
|
//!
|
|
//! # On-chain vs. off-chain compilation targets
|
|
//!
|
|
//! Solana programs run on the [rbpf] VM, which implements a variant of the
|
|
//! [eBPF] instruction set. Because this crate can be compiled for both on-chain
|
|
//! and off-chain execution, the environments of which are significantly
|
|
//! different, it extensively uses [conditional compilation][cc] to tailor its
|
|
//! implementation to the environment. The `cfg` predicate used for identifying
|
|
//! compilation for on-chain programs is `target_arch = "bpf"`, as in this
|
|
//! example from the `solana-program` codebase that logs a message via a
|
|
//! syscall when run on-chain, and via a library call when offchain:
|
|
//!
|
|
//! [rbpf]: https://github.com/solana-labs/rbpf
|
|
//! [eBPF]: https://ebpf.io/
|
|
//! [cc]: https://doc.rust-lang.org/reference/conditional-compilation.html
|
|
//!
|
|
//! ```
|
|
//! pub fn sol_log(message: &str) {
|
|
//! #[cfg(target_arch = "bpf")]
|
|
//! unsafe {
|
|
//! sol_log_(message.as_ptr(), message.len() as u64);
|
|
//! }
|
|
//!
|
|
//! #[cfg(not(target_arch = "bpf"))]
|
|
//! program_stubs::sol_log(message);
|
|
//! }
|
|
//! # mod program_stubs {
|
|
//! # pub(crate) fn sol_log(message: &str) { }
|
|
//! # }
|
|
//! ```
|
|
//!
|
|
//! This `cfg` pattern is suitable as well for user code that needs to work both
|
|
//! on-chain and off-chain.
|
|
//!
|
|
//! `solana-program` and `solana-sdk` were previously a single crate. Because of
|
|
//! this history, and because of the dual-usage of `solana-program` for two
|
|
//! different environments, it contains some features that are not available to
|
|
//! on-chain programs at compile-time. It also contains some on-chain features
|
|
//! that will fail in off-chain scenarios at runtime. This distinction is not
|
|
//! well-reflected in the documentation.
|
|
//!
|
|
//! For a more complete description of Solana's implementation of eBPF and its
|
|
//! limitations, see the main Solana documentation for [on-chain programs][ocp].
|
|
//!
|
|
//! [ocp]: https://docs.solana.com/developing/on-chain-programs/overview
|
|
//!
|
|
//! # Core data types
|
|
//!
|
|
//! - [`Pubkey`] — The address of a [Solana account][acc]. Some account
|
|
//! addresses are [ed25519] public keys, with corresponding secret keys that
|
|
//! are managed off-chain. Often though account addresses do not have
|
|
//! corresponding secret keys, as with [_program derived addresses_][pdas], or
|
|
//! the secret key is not relevant to the operation of a program, and may have
|
|
//! even been disposed of. As running Solana programs can not safely create or
|
|
//! manage secret keys, the full [`Keypair`] is not defined in
|
|
//! `solana-program` but in `solana-sdk`.
|
|
//! - [`Hash`] — A [SHA-256] hash. Used to uniquely identify blocks, and
|
|
//! also for general purpose hashing.
|
|
//! - [`AccountInfo`] — A description of a single Solana account. All accounts
|
|
//! that might be accessed by a program invocation are provided to the program
|
|
//! entrypoint as `AccountInfo`.
|
|
//! - [`Instruction`] — A directive telling the runtime to execute a program,
|
|
//! passing it a set of accounts and program-specific data.
|
|
//! - [`ProgramError`] and [`ProgramResult`] — The error type that all programs
|
|
//! must return, reported to the runtime as a `u64`.
|
|
//! - [`Sol`] — The Solana native token type, with conversions to and from
|
|
//! [_lamports_], the smallest fractional unit of SOL, in the [`native_token`]
|
|
//! module.
|
|
//!
|
|
//! [acc]: https://docs.solana.com/developing/programming-model/accounts
|
|
//! [`Pubkey`]: pubkey::Pubkey
|
|
//! [`Hash`]: hash::Hash
|
|
//! [`Instruction`]: instruction::Instruction
|
|
//! [`AccountInfo`]: account_info::AccountInfo
|
|
//! [`ProgramError`]: program_error::ProgramError
|
|
//! [`ProgramResult`]: entrypoint::ProgramResult
|
|
//! [ed25519]: https://ed25519.cr.yp.to/
|
|
//! [`Keypair`]: https://docs.rs/solana-sdk/latest/solana_sdk/signer/keypair/struct.Keypair.html
|
|
//! [SHA-256]: https://en.wikipedia.org/wiki/SHA-2
|
|
//! [`Sol`]: native_token::Sol
|
|
//! [_lamports_]: https://docs.solana.com/introduction#what-are-sols
|
|
//!
|
|
//! # Serialization
|
|
//!
|
|
//! Within the Solana runtime, programs, and network, at least three different
|
|
//! serialization formats are used, and `solana-program` provides access to
|
|
//! those needed by programs.
|
|
//!
|
|
//! In user-written Solana program code, serialization is primarily used for
|
|
//! accessing [`AccountInfo`] data and [`Instruction`] data, both of which are
|
|
//! program-specific binary data. Every program is free to decide their own
|
|
//! serialization format, but data recieved from other sources —
|
|
//! [sysvars][sysvar] for example — must be deserialized using the methods
|
|
//! indicated by the documentation for that data or data type.
|
|
//!
|
|
//! [`AccountInfo`]: account_info::AccountInfo
|
|
//! [`Instruction`]: instruction::Instruction
|
|
//!
|
|
//! The three serialization formats in use in Solana are:
|
|
//!
|
|
//! - __[Borsh]__, a compact and well-specified format developed by the [NEAR]
|
|
//! project, suitable for use in protocol definitions and for archival storage.
|
|
//! It has a [Rust implementation][brust] and a [JavaScript implementation][bjs]
|
|
//! and is recommended for all purposes.
|
|
//!
|
|
//! Users need to import the [`borsh`] crate themselves — it is not
|
|
//! re-exported by `solana-program`, though this crate provides several useful
|
|
//! utilities in its [`borsh` module][borshmod] that are not available in the
|
|
//! `borsh` library.
|
|
//!
|
|
//! The [`Instruction::new_with_borsh`] function creates an `Instruction` by
|
|
//! serializing a value with borsh.
|
|
//!
|
|
//! [Borsh]: https://borsh.io/
|
|
//! [NEAR]: https://near.org/
|
|
//! [brust]: https://docs.rs/borsh
|
|
//! [bjs]: https://github.com/near/borsh-js
|
|
//! [`borsh`]: https://docs.rs/borsh
|
|
//! [borshmod]: crate::borsh
|
|
//! [`Instruction::new_with_borsh`]: instruction::Instruction::new_with_borsh
|
|
//!
|
|
//! - __[Bincode]__, a compact serialization format that implements the [Serde]
|
|
//! Rust APIs. As it does not have a specification nor a JavaScript
|
|
//! implementation, and uses more CPU than borsh, it is not recommend for new
|
|
//! code.
|
|
//!
|
|
//! Many system program and native program instructions are serialized with
|
|
//! bincode, and it is used for other purposes in the runtime. In these cases
|
|
//! Rust programmers are generally not directly exposed to the encoding format
|
|
//! as it is hidden behind APIs.
|
|
//!
|
|
//! The [`Instruction::new_with_bincode`] function creates an `Instruction` by
|
|
//! serializing a value with bincode.
|
|
//!
|
|
//! [Bincode]: https://docs.rs/bincode
|
|
//! [Serde]: https://serde.rs/
|
|
//! [`Instruction::new_with_bincode`]: instruction::Instruction::new_with_bincode
|
|
//!
|
|
//! - __[`Pack`]__, a Solana-specific serialization API that is used by many
|
|
//! older programs in the [Solana Program Library][spl] to define their
|
|
//! account format. It is difficult to implement and does not define a
|
|
//! language-independent serialization format. It is not generally recommended
|
|
//! for new code.
|
|
//!
|
|
//! [`Pack`]: program_pack::Pack
|
|
//!
|
|
//! Developers should carefully consider the CPU cost of serialization, balanced
|
|
//! against the need for correctness and ease of use: off-the-shelf
|
|
//! serialization formats tend to be more expensive than carefully hand-written
|
|
//! application-specific formats; but application-specific formats are more
|
|
//! difficult to ensure the correctness of, and to provide multi-language
|
|
//! implementations for. It is not uncommon for programs to pack and unpack
|
|
//! their data with hand-written code.
|
|
//!
|
|
//! # Cross-program instruction execution
|
|
//!
|
|
//! Solana programs may call other programs, termed [_cross-program
|
|
//! invocation_][cpi] (CPI), with the [`invoke`] and [`invoke_signed`]
|
|
//! functions. When calling another program the caller must provide the
|
|
//! [`Instruction`] to be invoked, as well as the [`AccountInfo`] for every
|
|
//! account required by the instruction. Because the only way for a program to
|
|
//! acquire `AccountInfo` values is by receiving them from the runtime at the
|
|
//! [program entrypoint][entrypoint!], any account required by the callee
|
|
//! program must transitively be required by the caller program, and provided by
|
|
//! _its_ caller.
|
|
//!
|
|
//! [`invoke`]: program::invoke
|
|
//! [`invoke_signed`]: program::invoke_signed
|
|
//! [cpi]: https://docs.solana.com/developing/programming-model/calling-between-programs
|
|
//!
|
|
//! A simple example of transferring lamports via CPI:
|
|
//!
|
|
//! ```
|
|
//! use solana_program::{
|
|
//! account_info::{next_account_info, AccountInfo},
|
|
//! entrypoint,
|
|
//! entrypoint::ProgramResult,
|
|
//! program::invoke,
|
|
//! pubkey::Pubkey,
|
|
//! system_instruction,
|
|
//! system_program,
|
|
//! };
|
|
//!
|
|
//! entrypoint!(process_instruction);
|
|
//!
|
|
//! fn process_instruction(
|
|
//! program_id: &Pubkey,
|
|
//! accounts: &[AccountInfo],
|
|
//! instruction_data: &[u8],
|
|
//! ) -> ProgramResult {
|
|
//! let account_info_iter = &mut accounts.iter();
|
|
//!
|
|
//! let payer = next_account_info(account_info_iter)?;
|
|
//! let recipient = next_account_info(account_info_iter)?;
|
|
//! // The system program is a required account to invoke a system
|
|
//! // instruction, even though we don't use it directly.
|
|
//! let system_account = next_account_info(account_info_iter)?;
|
|
//!
|
|
//! assert!(payer.is_writable);
|
|
//! assert!(payer.is_signer);
|
|
//! assert!(recipient.is_writable);
|
|
//! assert!(system_program::check_id(system_account.key));
|
|
//!
|
|
//! let lamports = 1000000;
|
|
//!
|
|
//! invoke(
|
|
//! &system_instruction::transfer(payer.key, recipient.key, lamports),
|
|
//! &[payer.clone(), recipient.clone(), system_account.clone()],
|
|
//! )
|
|
//! }
|
|
//! ```
|
|
//!
|
|
//! Solana also includes a mechinasm to let programs control and sign for
|
|
//! accounts without needing to protect a corresponding secret key, called
|
|
//! [_program derived addresses_][pdas]. PDAs are derived with the
|
|
//! [`Pubkey::find_program_address`] function. With a PDA, a program can call
|
|
//! `invoke_signed` to call another program while virtually "signing" for the
|
|
//! PDA.
|
|
//!
|
|
//! [pdas]: https://docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses
|
|
//! [`Pubkey::find_program_address`]: pubkey::Pubkey::find_program_address
|
|
//!
|
|
//! A simple example of creating an account for a PDA:
|
|
//!
|
|
//! ```
|
|
//! use solana_program::{
|
|
//! account_info::{next_account_info, AccountInfo},
|
|
//! entrypoint,
|
|
//! entrypoint::ProgramResult,
|
|
//! program::invoke_signed,
|
|
//! pubkey::Pubkey,
|
|
//! system_instruction,
|
|
//! system_program,
|
|
//! };
|
|
//!
|
|
//! entrypoint!(process_instruction);
|
|
//!
|
|
//! fn process_instruction(
|
|
//! program_id: &Pubkey,
|
|
//! accounts: &[AccountInfo],
|
|
//! instruction_data: &[u8],
|
|
//! ) -> ProgramResult {
|
|
//! let account_info_iter = &mut accounts.iter();
|
|
//! let payer = next_account_info(account_info_iter)?;
|
|
//! let vault_pda = next_account_info(account_info_iter)?;
|
|
//! let system_program = next_account_info(account_info_iter)?;
|
|
//!
|
|
//! assert!(payer.is_writable);
|
|
//! assert!(payer.is_signer);
|
|
//! assert!(vault_pda.is_writable);
|
|
//! assert_eq!(vault_pda.owner, &system_program::ID);
|
|
//! assert!(system_program::check_id(system_program.key));
|
|
//!
|
|
//! let vault_bump_seed = instruction_data[0];
|
|
//! let vault_seeds = &[b"vault", payer.key.as_ref(), &[vault_bump_seed]];
|
|
//! let expected_vault_pda = Pubkey::create_program_address(vault_seeds, program_id)?;
|
|
//!
|
|
//! assert_eq!(vault_pda.key, &expected_vault_pda);
|
|
//!
|
|
//! let lamports = 10000000;
|
|
//! let vault_size = 16;
|
|
//!
|
|
//! invoke_signed(
|
|
//! &system_instruction::create_account(
|
|
//! &payer.key,
|
|
//! &vault_pda.key,
|
|
//! lamports,
|
|
//! vault_size,
|
|
//! &program_id,
|
|
//! ),
|
|
//! &[
|
|
//! payer.clone(),
|
|
//! vault_pda.clone(),
|
|
//! ],
|
|
//! &[
|
|
//! &[
|
|
//! b"vault",
|
|
//! payer.key.as_ref(),
|
|
//! &[vault_bump_seed],
|
|
//! ],
|
|
//! ]
|
|
//! )?;
|
|
//! Ok(())
|
|
//! }
|
|
//! ```
|
|
//!
|
|
//! # Native programs
|
|
//!
|
|
//! Some solana programs are [_native programs_][np2], running native machine
|
|
//! code that is distributed with the runtime, with well-known program IDs.
|
|
//!
|
|
//! [np2]: https://docs.solana.com/developing/runtime-facilities/programs
|
|
//!
|
|
//! Some native programs can be [invoked][cpi] by other programs, but some can
|
|
//! only be executed as "top-level" instructions included by off-chain clients
|
|
//! in a [`Transaction`].
|
|
//!
|
|
//! [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
|
|
//!
|
|
//! This crate defines the program IDs for most native programs. Even though
|
|
//! some native programs cannot be invoked by other programs, a Solana program
|
|
//! may need access to their program IDs. For example, a program may need to
|
|
//! verify that an ed25519 signature verification instruction was included in
|
|
//! the same transaction as its own instruction. For many native programs, this
|
|
//! crate also defines enums that represent the instructions they process, and
|
|
//! constructors for building the instructions.
|
|
//!
|
|
//! Locations of program IDs and instruction constructors are noted in the list
|
|
//! below, as well as whether they are invokable by other programs.
|
|
//!
|
|
//! While some native programs have been active since the genesis block, others
|
|
//! are activated dynamically after a specific [slot], and some are not yet
|
|
//! active. This documentation does not distinguish which native programs are
|
|
//! active on any particular network. The `solana feature status` CLI command
|
|
//! can help in determining active features.
|
|
//!
|
|
//! [slot]: https://docs.solana.com/terminology#slot
|
|
//!
|
|
//! Native programs important to Solana program authors include:
|
|
//!
|
|
//! - __System Program__: Creates new accounts, allocates account data, assigns
|
|
//! accounts to owning programs, transfers lamports from System Program owned
|
|
//! accounts and pays transaction fees.
|
|
//! - ID: [`solana_program::system_program`]
|
|
//! - Instruction: [`solana_program::system_instruction`]
|
|
//! - Invokable by programs? yes
|
|
//!
|
|
//! - __Compute Budget Program__: Requests additional CPU or memory resources
|
|
//! for a transaction. This program does nothing when called from another
|
|
//! program.
|
|
//! - ID: [`solana_sdk::compute_budget`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/index.html)
|
|
//! - Instruction: [`solana_sdk::compute_budget`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/index.html)
|
|
//! - Invokable by programs? no
|
|
//!
|
|
//! - __ed25519 Program__: Verifies an ed25519 signature.
|
|
//! - ID: [`solana_program::ed25519_program`]
|
|
//! - Instruction: [`solana_sdk::ed25519_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/ed25519_instruction/index.html)
|
|
//! - Invokable by programs? no
|
|
//!
|
|
//! - __secp256k1 Program__: Verifies secp256k1 public key recovery operations.
|
|
//! - ID: [`solana_program::secp256k1_program`]
|
|
//! - Instruction: [`solana_sdk::secp256k1_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/secp256k1_instruction/index.html)
|
|
//! - Invokable by programs? no
|
|
//!
|
|
//! - __BPF Loader__: Deploys, and executes immutable programs on the chain.
|
|
//! - ID: [`solana_program::bpf_loader`]
|
|
//! - Instruction: [`solana_program::loader_instruction`]
|
|
//! - Invokable by programs? yes
|
|
//!
|
|
//! - __Upgradable BPF Loader__: Deploys, upgrades, and executes upgradable
|
|
//! programs on the chain.
|
|
//! - ID: [`solana_program::bpf_loader_upgradeable`]
|
|
//! - Instruction: [`solana_program::loader_upgradeable_instruction`]
|
|
//! - Invokable by programs? yes
|
|
//!
|
|
//! - __Deprecated BPF Loader__: Deploys, and executes immutable programs on the
|
|
//! chain.
|
|
//! - ID: [`solana_program::bpf_loader_deprecated`]
|
|
//! - Instruction: [`solana_program::loader_instruction`]
|
|
//! - Invokable by programs? yes
|
|
//!
|
|
//! [lut]: https://docs.solana.com/proposals/transactions-v2
|
|
//!
|
|
//! # Sysvars
|
|
//!
|
|
//! Sysvars are special accounts that contain dynamically-updating 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))]
|
|
#![cfg_attr(RUSTC_NEEDS_PROC_MACRO_HYGIENE, feature(proc_macro_hygiene))]
|
|
|
|
// Allows macro expansion of `use ::solana_program::*` to work within this crate
|
|
extern crate self as solana_program;
|
|
|
|
pub mod account_info;
|
|
pub(crate) mod atomic_u64;
|
|
pub mod blake3;
|
|
pub mod borsh;
|
|
pub mod bpf_loader;
|
|
pub mod bpf_loader_deprecated;
|
|
pub mod bpf_loader_upgradeable;
|
|
pub mod clock;
|
|
pub mod debug_account_data;
|
|
pub mod decode_error;
|
|
pub mod ed25519_program;
|
|
pub mod entrypoint;
|
|
pub mod entrypoint_deprecated;
|
|
pub mod epoch_schedule;
|
|
pub mod example_mocks;
|
|
pub mod feature;
|
|
pub mod fee_calculator;
|
|
pub mod hash;
|
|
pub mod incinerator;
|
|
pub mod instruction;
|
|
pub mod keccak;
|
|
pub mod lamports;
|
|
pub mod loader_instruction;
|
|
pub mod loader_upgradeable_instruction;
|
|
pub mod log;
|
|
pub mod message;
|
|
pub mod native_token;
|
|
pub mod nonce;
|
|
pub mod program;
|
|
pub mod program_error;
|
|
pub mod program_memory;
|
|
pub mod program_option;
|
|
pub mod program_pack;
|
|
pub mod program_stubs;
|
|
pub mod program_utils;
|
|
pub mod pubkey;
|
|
pub mod rent;
|
|
pub mod sanitize;
|
|
pub mod secp256k1_program;
|
|
pub mod secp256k1_recover;
|
|
pub mod serialize_utils;
|
|
pub mod short_vec;
|
|
pub mod slot_hashes;
|
|
pub mod slot_history;
|
|
pub mod stake;
|
|
pub mod stake_history;
|
|
pub mod system_instruction;
|
|
pub mod system_program;
|
|
pub mod sysvar;
|
|
pub mod wasm;
|
|
|
|
#[cfg(target_arch = "bpf")]
|
|
pub use solana_sdk_macro::wasm_bindgen_stub as wasm_bindgen;
|
|
#[cfg(not(target_arch = "bpf"))]
|
|
pub use wasm_bindgen::prelude::wasm_bindgen;
|
|
|
|
pub mod config {
|
|
pub mod program {
|
|
crate::declare_id!("Config1111111111111111111111111111111111111");
|
|
}
|
|
}
|
|
|
|
pub mod vote {
|
|
pub mod program {
|
|
crate::declare_id!("Vote111111111111111111111111111111111111111");
|
|
}
|
|
}
|
|
|
|
/// Same as `declare_id` except report that this id has been deprecated
|
|
pub use solana_sdk_macro::program_declare_deprecated_id as declare_deprecated_id;
|
|
/// Convenience macro to declare a static public key and functions to interact with it
|
|
///
|
|
/// Input: a single literal base58 string representation of a program's id
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # // wrapper is used so that the macro invocation occurs in the item position
|
|
/// # // rather than in the statement position which isn't allowed.
|
|
/// use std::str::FromStr;
|
|
/// use solana_program::{declare_id, pubkey::Pubkey};
|
|
///
|
|
/// # mod item_wrapper {
|
|
/// # use solana_program::declare_id;
|
|
/// declare_id!("My11111111111111111111111111111111111111111");
|
|
/// # }
|
|
/// # use item_wrapper::id;
|
|
///
|
|
/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
|
|
/// assert_eq!(id(), my_id);
|
|
/// ```
|
|
pub use solana_sdk_macro::program_declare_id as declare_id;
|
|
/// Convenience macro to define a static public key
|
|
///
|
|
/// Input: a single literal base58 string representation of a Pubkey
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// use std::str::FromStr;
|
|
/// use solana_program::{pubkey, pubkey::Pubkey};
|
|
///
|
|
/// static ID: Pubkey = pubkey!("My11111111111111111111111111111111111111111");
|
|
///
|
|
/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
|
|
/// assert_eq!(ID, my_id);
|
|
/// ```
|
|
pub use solana_sdk_macro::program_pubkey as pubkey;
|
|
|
|
#[macro_use]
|
|
extern crate serde_derive;
|
|
|
|
#[macro_use]
|
|
extern crate solana_frozen_abi_macro;
|
|
|
|
/// Convenience macro for doing integer division where the opersation's safety
|
|
/// can be checked at compile-time
|
|
///
|
|
/// Since `unchecked_div_by_const!()` is supposed to fail at compile-time, abuse
|
|
/// doctests to cover failure modes
|
|
/// Literal denominator div-by-zero fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # let _ = unchecked_div_by_const!(10, 0);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// # Const denominator div-by-zero fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # const D: u64 = 0;
|
|
/// # let _ = unchecked_div_by_const!(10, D);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// # Non-const denominator fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # let d = 0;
|
|
/// # let _ = unchecked_div_by_const!(10, d);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// Literal denominator div-by-zero fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # const N: u64 = 10;
|
|
/// # let _ = unchecked_div_by_const!(N, 0);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// # Const denominator div-by-zero fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # const N: u64 = 10;
|
|
/// # const D: u64 = 0;
|
|
/// # let _ = unchecked_div_by_const!(N, D);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// # Non-const denominator fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # const N: u64 = 10;
|
|
/// # let d = 0;
|
|
/// # let _ = unchecked_div_by_const!(N, d);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// Literal denominator div-by-zero fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # let n = 10;
|
|
/// # let _ = unchecked_div_by_const!(n, 0);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// # Const denominator div-by-zero fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # let n = 10;
|
|
/// # const D: u64 = 0;
|
|
/// # let _ = unchecked_div_by_const!(n, D);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
/// # Non-const denominator fails
|
|
/// ```compile_fail
|
|
/// # use solana_program::unchecked_div_by_const;
|
|
/// # fn main() {
|
|
/// # let n = 10;
|
|
/// # let d = 0;
|
|
/// # let _ = unchecked_div_by_const!(n, d);
|
|
/// # }
|
|
/// ```
|
|
/// #
|
|
#[macro_export]
|
|
macro_rules! unchecked_div_by_const {
|
|
($num:expr, $den:expr) => {{
|
|
// Ensure the denominator is compile-time constant
|
|
let _ = [(); ($den - $den) as usize];
|
|
// Compile-time constant integer div-by-zero passes for some reason
|
|
// when invoked from a compilation unit other than that where this
|
|
// macro is defined. Do an explicit zero-check for now. Sorry about the
|
|
// ugly error messages!
|
|
// https://users.rust-lang.org/t/unexpected-behavior-of-compile-time-integer-div-by-zero-check-in-declarative-macro/56718
|
|
let _ = [(); ($den as usize) - 1];
|
|
#[allow(clippy::integer_arithmetic)]
|
|
let quotient = $num / $den;
|
|
quotient
|
|
}};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::unchecked_div_by_const;
|
|
|
|
#[test]
|
|
fn test_unchecked_div_by_const() {
|
|
const D: u64 = 2;
|
|
const N: u64 = 10;
|
|
let n = 10;
|
|
assert_eq!(unchecked_div_by_const!(10, 2), 5);
|
|
assert_eq!(unchecked_div_by_const!(N, 2), 5);
|
|
assert_eq!(unchecked_div_by_const!(n, 2), 5);
|
|
assert_eq!(unchecked_div_by_const!(10, D), 5);
|
|
assert_eq!(unchecked_div_by_const!(N, D), 5);
|
|
assert_eq!(unchecked_div_by_const!(n, D), 5);
|
|
}
|
|
}
|