Add crate docs for solana-program (#23363)

* Add crate docs for solana-program

* Rework solana-program docs for pr feedback

* Clarify log module docs

* Remove address lookup table program from solana-program docs
This commit is contained in:
Brian Anderson 2022-03-18 10:27:51 -05:00 committed by GitHub
parent f54e746fc5
commit c9b8977226
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 625 additions and 23 deletions

View File

@ -1,3 +1,555 @@
//! 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))]

View File

@ -1,4 +1,37 @@
//! Solana Rust-based BPF program logging
//! Logging utilities for Rust-based Solana programs.
//!
//! Logging is the main mechanism for getting debugging information out of
//! running Solana programs, and there are several functions available for doing
//! so efficiently, depending on the type of data being logged.
//!
//! The most common way to emit logs is through the [`msg!`] macro, which logs
//! simple strings, as well as [formatted strings][fs].
//!
//! [`msg!`]: msg
//! [fs]: https://doc.rust-lang.org/std/fmt/
//!
//! Logs can be viewed in multiple ways:
//!
//! - The `solana logs` command displays logs for all transactions executed on a
//! network. Note though that transactions that fail during pre-flight
//! simulation are not displayed here.
//! - When submitting transactions via [`RpcClient`], if Rust's own logging is
//! active then the `solana_client` crate logs at the "debug" level any logs
//! for transactions that failed during simulation. If using [`env_logger`]
//! these logs can be activated by setting `RUST_LOG=solana_client=debug`.
//! - Logs can be retrieved from a finalized transaction by calling
//! [`RpcClient::get_transaction`].
//! - Block explorers may display logs.
//!
//! [`RpcClient`]: https://docs.rs/solana-client/latest/solana_client/rpc_client/struct.RpcClient.html
//! [`env_logger`]: https://docs.rs/env_logger
//! [`RpcClient::get_transaction`]: https://docs.rs/solana-client/latest/solana_client/rpc_client/struct.RpcClient.html#method.get_transaction
//!
//! While most logging functions are defined in this module, [`Pubkey`]s can
//! also be efficiently logged with the [`Pubkey::log`] function.
//!
//! [`Pubkey`]: crate::pubkey::Pubkey
//! [`Pubkey::log`]: crate::pubkey::Pubkey::log
use crate::account_info::AccountInfo;
@ -19,14 +52,33 @@ macro_rules! info {
};
}
/// Print a message to the log
/// Print a message to the log.
///
/// Fast form:
/// 1. Single string: `msg!("hi")`
/// Supports simple strings as well as Rust [format strings][fs]. When passed a
/// single expression it will be passed directly to [`sol_log`]. The expression
/// must have type `&str`, and is typically used for logging static strings.
/// When passed something other than an expression, particularly
/// a sequence of expressions, the tokens will be passed through the
/// [`format!`] macro before being logged with `sol_log`.
///
/// The generic form incurs a very large runtime overhead so it should be used with care:
/// 3. Generalized format string: `msg!("Hello {}: 1, 2, {}", "World", 3)`
/// [fs]: https://doc.rust-lang.org/std/fmt/
/// [`format!`]: https://doc.rust-lang.org/std/fmt/fn.format.html
///
/// Note that Rust's formatting machinery is relatively CPU-intensive
/// for constrained environments like the Solana VM.
///
/// # Examples
///
/// ```
/// use solana_program::msg;
///
/// // The fast form
/// msg!("verifying multisig");
///
/// // With formatting
/// let err = "not enough signers";
/// msg!("multisig failed: {}", err);
/// ```
#[macro_export]
macro_rules! msg {
($msg:expr) => {
@ -35,9 +87,7 @@ macro_rules! msg {
($($arg:tt)*) => ($crate::log::sol_log(&format!($($arg)*)));
}
/// Print a string to the log
///
/// @param message - Message to print
/// Print a string to the log.
#[inline]
pub fn sol_log(message: &str) {
#[cfg(target_arch = "bpf")]
@ -54,10 +104,7 @@ extern "C" {
fn sol_log_(message: *const u8, len: u64);
}
/// Print 64-bit values represented as hexadecimal to the log
///
/// @param argx - integer arguments to print
/// Print 64-bit values represented as hexadecimal to the log.
#[inline]
pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
#[cfg(target_arch = "bpf")]
@ -74,9 +121,7 @@ extern "C" {
fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64);
}
/// Print some slices as base64
///
/// @param data - The slices to print
/// Print some slices as base64.
pub fn sol_log_data(data: &[&[u8]]) {
#[cfg(target_arch = "bpf")]
{
@ -91,9 +136,7 @@ pub fn sol_log_data(data: &[&[u8]]) {
crate::program_stubs::sol_log_data(data);
}
/// Print the hexadecimal representation of a slice
///
/// @param slice - The array to print
/// Print the hexadecimal representation of a slice.
#[allow(dead_code)]
pub fn sol_log_slice(slice: &[u8]) {
for (i, s) in slice.iter().enumerate() {
@ -101,10 +144,10 @@ pub fn sol_log_slice(slice: &[u8]) {
}
}
/// Print the hexadecimal representation of the program's input parameters
/// Print the hexadecimal representation of the program's input parameters.
///
/// @param ka - A pointer to an array of `AccountInfo` to print
/// @param data - A pointer to the instruction data to print
/// - `accounts` - A slice of [`AccountInfo`].
/// - `data` - The instruction data.
#[allow(dead_code)]
pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
for (i, account) in accounts.iter().enumerate() {
@ -125,7 +168,7 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
sol_log_slice(data);
}
/// Print the remaining compute units the program may consume
/// Print the remaining compute units available to the program.
#[inline]
pub fn sol_log_compute_units() {
#[cfg(target_arch = "bpf")]

View File

@ -101,6 +101,13 @@ pub trait Sysvar:
fn size_of() -> usize {
bincode::serialized_size(&Self::default()).unwrap() as usize
}
/// Deserializes a sysvar from its `AccountInfo`.
///
/// # Errors
///
/// 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);