solomka_program/lib.rs
1//! The base library for all Solana on-chain Rust programs.
2//!
3//! All Solana Rust programs that run on-chain will link to this crate, which
4//! acts as a standard library for Solana programs. Solana programs also link to
5//! the [Rust standard library][std], though it is [modified][sstd] for the
6//! Solana runtime environment. While off-chain programs that interact with the
7//! Solana network _can_ link to this crate, they typically instead use the
8//! [`solana-sdk`] crate, which reexports all modules from `solana-program`.
9//!
10//! [std]: https://doc.rust-lang.org/stable/std/
11//! [sstd]: https://docs.solana.com/developing/on-chain-programs/developing-rust#restrictions
12//! [`solana-sdk`]: https://docs.rs/solana-sdk/latest/solana_sdk/
13//!
14//! This library defines
15//!
16//! - macros for declaring the [program entrypoint][pe],
17//! - [core data types][cdt],
18//! - [logging] macros,
19//! - [serialization] methods,
20//! - methods for [cross-program instruction execution][cpi],
21//! - program IDs and instruction constructors for the system program and other
22//! [native programs][np],
23//! - [sysvar] accessors.
24//!
25//! [pe]: #defining-a-solana-program
26//! [cdt]: #core-data-types
27//! [logging]: crate::log
28//! [serialization]: #serialization
29//! [np]: #native-programs
30//! [cpi]: #cross-program-instruction-execution
31//! [sysvar]: #sysvars
32//!
33//! Idiomatic examples of `solana-program` usage can be found in
34//! [the Solana Program Library][spl].
35//!
36//! [spl]: https://github.com/solana-labs/solana-program-library
37//!
38//! # Defining a solana program
39//!
40//! Solana program crates have some unique properties compared to typical Rust
41//! programs:
42//!
43//! - They are often compiled for both on-chain use and off-chain use. This is
44//! primarily because off-chain clients may need access to data types
45//! defined by the on-chain program.
46//! - They do not define a `main` function, but instead define their entrypoint
47//! with the [`entrypoint!`] macro.
48//! - They are compiled as the ["cdylib"] crate type for dynamic loading
49//! by the Solana runtime.
50//! - They run in a constrained VM environment, and while they do have access to
51//! the [Rust standard library][std], many features of the standard library,
52//! particularly related to OS services, will fail at runtime, will silently
53//! do nothing, or are not defined. See the [restrictions to the Rust standard
54//! library][sstd] in the Solana documentation for more.
55//!
56//! [std]: https://doc.rust-lang.org/std/index.html
57//! ["cdylib"]: https://doc.rust-lang.org/reference/linkage.html
58//!
59//! Because multiple crates that are linked together cannot all define
60//! program entrypoints (see the [`entrypoint!`] documentation) a common
61//! convention is to use a [Cargo feature] called `no-entrypoint` to allow
62//! the program entrypoint to be disabled.
63//!
64//! [Cargo feature]: https://doc.rust-lang.org/cargo/reference/features.html
65//!
66//! The skeleton of a Solana program typically looks like:
67//!
68//! ```
69//! #[cfg(not(feature = "no-entrypoint"))]
70//! pub mod entrypoint {
71//! use solomka_program::{
72//! account_info::AccountInfo,
73//! entrypoint,
74//! entrypoint::ProgramResult,
75//! pubkey::Pubkey,
76//! };
77//!
78//! entrypoint!(process_instruction);
79//!
80//! pub fn process_instruction(
81//! program_id: &Pubkey,
82//! accounts: &[AccountInfo],
83//! instruction_data: &[u8],
84//! ) -> ProgramResult {
85//! // Decode and dispatch instructions here.
86//! todo!()
87//! }
88//! }
89//!
90//! // Additional code goes here.
91//! ```
92//!
93//! With a `Cargo.toml` file that contains
94//!
95//! ```toml
96//! [lib]
97//! crate-type = ["cdylib", "rlib"]
98//!
99//! [features]
100//! no-entrypoint = []
101//! ```
102//!
103//! Note that a Solana program must specify its crate-type as "cdylib", and
104//! "cdylib" crates will automatically be discovered and built by the `cargo
105//! build-bpf` command. Solana programs also often have crate-type "rlib" so
106//! they can be linked to other Rust crates.
107//!
108//! # On-chain vs. off-chain compilation targets
109//!
110//! Solana programs run on the [rbpf] VM, which implements a variant of the
111//! [eBPF] instruction set. Because this crate can be compiled for both on-chain
112//! and off-chain execution, the environments of which are significantly
113//! different, it extensively uses [conditional compilation][cc] to tailor its
114//! implementation to the environment. The `cfg` predicate used for identifying
115//! compilation for on-chain programs is `target_os = "solana"`, as in this
116//! example from the `solana-program` codebase that logs a message via a
117//! syscall when run on-chain, and via a library call when offchain:
118//!
119//! [rbpf]: https://github.com/solana-labs/rbpf
120//! [eBPF]: https://ebpf.io/
121//! [cc]: https://doc.rust-lang.org/reference/conditional-compilation.html
122//!
123//! ```
124//! pub fn sol_log(message: &str) {
125//! #[cfg(target_os = "solana")]
126//! unsafe {
127//! sol_log_(message.as_ptr(), message.len() as u64);
128//! }
129//!
130//! #[cfg(not(target_os = "solana"))]
131//! program_stubs::sol_log(message);
132//! }
133//! # mod program_stubs {
134//! # pub(crate) fn sol_log(message: &str) { }
135//! # }
136//! ```
137//!
138//! This `cfg` pattern is suitable as well for user code that needs to work both
139//! on-chain and off-chain.
140//!
141//! `solana-program` and `solana-sdk` were previously a single crate. Because of
142//! this history, and because of the dual-usage of `solana-program` for two
143//! different environments, it contains some features that are not available to
144//! on-chain programs at compile-time. It also contains some on-chain features
145//! that will fail in off-chain scenarios at runtime. This distinction is not
146//! well-reflected in the documentation.
147//!
148//! For a more complete description of Solana's implementation of eBPF and its
149//! limitations, see the main Solana documentation for [on-chain programs][ocp].
150//!
151//! [ocp]: https://docs.solana.com/developing/on-chain-programs/overview
152//!
153//! # Core data types
154//!
155//! - [`Pubkey`] — The address of a [Solana account][acc]. Some account
156//! addresses are [ed25519] public keys, with corresponding secret keys that
157//! are managed off-chain. Often, though, account addresses do not have
158//! corresponding secret keys — as with [_program derived
159//! addresses_][pdas] — or the secret key is not relevant to the
160//! operation of a program, and may have even been disposed of. As running
161//! Solana programs can not safely create or manage secret keys, the full
162//! [`Keypair`] is not defined in `solana-program` but in `solana-sdk`.
163//! - [`Hash`] — A cryptographic hash. Used to uniquely identify blocks,
164//! and also for general purpose hashing.
165//! - [`AccountInfo`] — A description of a single Solana account. All accounts
166//! that might be accessed by a program invocation are provided to the program
167//! entrypoint as `AccountInfo`.
168//! - [`Instruction`] — A directive telling the runtime to execute a program,
169//! passing it a set of accounts and program-specific data.
170//! - [`ProgramError`] and [`ProgramResult`] — The error type that all programs
171//! must return, reported to the runtime as a `u64`.
172//! - [`Sol`] — The Solana native token type, with conversions to and from
173//! [_lamports_], the smallest fractional unit of SOL, in the [`native_token`]
174//! module.
175//!
176//! [acc]: https://docs.solana.com/developing/programming-model/accounts
177//! [`Pubkey`]: pubkey::Pubkey
178//! [`Hash`]: hash::Hash
179//! [`Instruction`]: instruction::Instruction
180//! [`AccountInfo`]: account_info::AccountInfo
181//! [`ProgramError`]: program_error::ProgramError
182//! [`ProgramResult`]: entrypoint::ProgramResult
183//! [ed25519]: https://ed25519.cr.yp.to/
184//! [`Keypair`]: https://docs.rs/solana-sdk/latest/solana_sdk/signer/keypair/struct.Keypair.html
185//! [SHA-256]: https://en.wikipedia.org/wiki/SHA-2
186//! [`Sol`]: native_token::Sol
187//! [_lamports_]: https://docs.solana.com/introduction#what-are-sols
188//!
189//! # Serialization
190//!
191//! Within the Solana runtime, programs, and network, at least three different
192//! serialization formats are used, and `solana-program` provides access to
193//! those needed by programs.
194//!
195//! In user-written Solana program code, serialization is primarily used for
196//! accessing [`AccountInfo`] data and [`Instruction`] data, both of which are
197//! program-specific binary data. Every program is free to decide their own
198//! serialization format, but data received from other sources —
199//! [sysvars][sysvar] for example — must be deserialized using the methods
200//! indicated by the documentation for that data or data type.
201//!
202//! [`AccountInfo`]: account_info::AccountInfo
203//! [`Instruction`]: instruction::Instruction
204//!
205//! The three serialization formats in use in Solana are:
206//!
207//! - __[Borsh]__, a compact and well-specified format developed by the [NEAR]
208//! project, suitable for use in protocol definitions and for archival storage.
209//! It has a [Rust implementation][brust] and a [JavaScript implementation][bjs]
210//! and is recommended for all purposes.
211//!
212//! Users need to import the [`borsh`] crate themselves — it is not
213//! re-exported by `solana-program`, though this crate provides several useful
214//! utilities in its [`borsh` module][borshmod] that are not available in the
215//! `borsh` library.
216//!
217//! The [`Instruction::new_with_borsh`] function creates an `Instruction` by
218//! serializing a value with borsh.
219//!
220//! [Borsh]: https://borsh.io/
221//! [NEAR]: https://near.org/
222//! [brust]: https://docs.rs/borsh
223//! [bjs]: https://github.com/near/borsh-js
224//! [`borsh`]: https://docs.rs/borsh
225//! [borshmod]: crate::borsh
226//! [`Instruction::new_with_borsh`]: instruction::Instruction::new_with_borsh
227//!
228//! - __[Bincode]__, a compact serialization format that implements the [Serde]
229//! Rust APIs. As it does not have a specification nor a JavaScript
230//! implementation, and uses more CPU than borsh, it is not recommend for new
231//! code.
232//!
233//! Many system program and native program instructions are serialized with
234//! bincode, and it is used for other purposes in the runtime. In these cases
235//! Rust programmers are generally not directly exposed to the encoding format
236//! as it is hidden behind APIs.
237//!
238//! The [`Instruction::new_with_bincode`] function creates an `Instruction` by
239//! serializing a value with bincode.
240//!
241//! [Bincode]: https://docs.rs/bincode
242//! [Serde]: https://serde.rs/
243//! [`Instruction::new_with_bincode`]: instruction::Instruction::new_with_bincode
244//!
245//! - __[`Pack`]__, a Solana-specific serialization API that is used by many
246//! older programs in the [Solana Program Library][spl] to define their
247//! account format. It is difficult to implement and does not define a
248//! language-independent serialization format. It is not generally recommended
249//! for new code.
250//!
251//! [`Pack`]: program_pack::Pack
252//!
253//! Developers should carefully consider the CPU cost of serialization, balanced
254//! against the need for correctness and ease of use: off-the-shelf
255//! serialization formats tend to be more expensive than carefully hand-written
256//! application-specific formats; but application-specific formats are more
257//! difficult to ensure the correctness of, and to provide multi-language
258//! implementations for. It is not uncommon for programs to pack and unpack
259//! their data with hand-written code.
260//!
261//! # Cross-program instruction execution
262//!
263//! Solana programs may call other programs, termed [_cross-program
264//! invocation_][cpi] (CPI), with the [`invoke`] and [`invoke_signed`]
265//! functions. When calling another program the caller must provide the
266//! [`Instruction`] to be invoked, as well as the [`AccountInfo`] for every
267//! account required by the instruction. Because the only way for a program to
268//! acquire `AccountInfo` values is by receiving them from the runtime at the
269//! [program entrypoint][entrypoint!], any account required by the callee
270//! program must transitively be required by the caller program, and provided by
271//! _its_ caller.
272//!
273//! [`invoke`]: program::invoke
274//! [`invoke_signed`]: program::invoke_signed
275//! [cpi]: https://docs.solana.com/developing/programming-model/calling-between-programs
276//!
277//! A simple example of transferring lamports via CPI:
278//!
279//! ```
280//! use solomka_program::{
281//! account_info::{next_account_info, AccountInfo},
282//! entrypoint,
283//! entrypoint::ProgramResult,
284//! program::invoke,
285//! pubkey::Pubkey,
286//! system_instruction,
287//! system_program,
288//! };
289//!
290//! entrypoint!(process_instruction);
291//!
292//! fn process_instruction(
293//! program_id: &Pubkey,
294//! accounts: &[AccountInfo],
295//! instruction_data: &[u8],
296//! ) -> ProgramResult {
297//! let account_info_iter = &mut accounts.iter();
298//!
299//! let payer = next_account_info(account_info_iter)?;
300//! let recipient = next_account_info(account_info_iter)?;
301//! // The system program is a required account to invoke a system
302//! // instruction, even though we don't use it directly.
303//! let system_account = next_account_info(account_info_iter)?;
304//!
305//! assert!(payer.is_writable);
306//! assert!(payer.is_signer);
307//! assert!(recipient.is_writable);
308//! assert!(system_program::check_id(system_account.key));
309//!
310//! let lamports = 1000000;
311//!
312//! invoke(
313//! &system_instruction::transfer(payer.key, recipient.key, lamports),
314//! &[payer.clone(), recipient.clone(), system_account.clone()],
315//! )
316//! }
317//! ```
318//!
319//! Solana also includes a mechanism to let programs control and sign for
320//! accounts without needing to protect a corresponding secret key, called
321//! [_program derived addresses_][pdas]. PDAs are derived with the
322//! [`Pubkey::find_program_address`] function. With a PDA, a program can call
323//! `invoke_signed` to call another program while virtually "signing" for the
324//! PDA.
325//!
326//! [pdas]: https://docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses
327//! [`Pubkey::find_program_address`]: pubkey::Pubkey::find_program_address
328//!
329//! A simple example of creating an account for a PDA:
330//!
331//! ```
332//! use solomka_program::{
333//! account_info::{next_account_info, AccountInfo},
334//! entrypoint,
335//! entrypoint::ProgramResult,
336//! program::invoke_signed,
337//! pubkey::Pubkey,
338//! system_instruction,
339//! system_program,
340//! };
341//!
342//! entrypoint!(process_instruction);
343//!
344//! fn process_instruction(
345//! program_id: &Pubkey,
346//! accounts: &[AccountInfo],
347//! instruction_data: &[u8],
348//! ) -> ProgramResult {
349//! let account_info_iter = &mut accounts.iter();
350//! let payer = next_account_info(account_info_iter)?;
351//! let vault_pda = next_account_info(account_info_iter)?;
352//! let system_program = next_account_info(account_info_iter)?;
353//!
354//! assert!(payer.is_writable);
355//! assert!(payer.is_signer);
356//! assert!(vault_pda.is_writable);
357//! assert_eq!(vault_pda.owner, &system_program::ID);
358//! assert!(system_program::check_id(system_program.key));
359//!
360//! let vault_bump_seed = instruction_data[0];
361//! let vault_seeds = &[b"vault", payer.key.as_ref(), &[vault_bump_seed]];
362//! let expected_vault_pda = Pubkey::create_program_address(vault_seeds, program_id)?;
363//!
364//! assert_eq!(vault_pda.key, &expected_vault_pda);
365//!
366//! let lamports = 10000000;
367//! let vault_size = 16;
368//!
369//! invoke_signed(
370//! &system_instruction::create_account(
371//! &payer.key,
372//! &vault_pda.key,
373//! lamports,
374//! vault_size,
375//! &program_id,
376//! ),
377//! &[
378//! payer.clone(),
379//! vault_pda.clone(),
380//! ],
381//! &[
382//! &[
383//! b"vault",
384//! payer.key.as_ref(),
385//! &[vault_bump_seed],
386//! ],
387//! ]
388//! )?;
389//! Ok(())
390//! }
391//! ```
392//!
393//! # Native programs
394//!
395//! Some solana programs are [_native programs_][np2], running native machine
396//! code that is distributed with the runtime, with well-known program IDs.
397//!
398//! [np2]: https://docs.solana.com/developing/runtime-facilities/programs
399//!
400//! Some native programs can be [invoked][cpi] by other programs, but some can
401//! only be executed as "top-level" instructions included by off-chain clients
402//! in a [`Transaction`].
403//!
404//! [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
405//!
406//! This crate defines the program IDs for most native programs. Even though
407//! some native programs cannot be invoked by other programs, a Solana program
408//! may need access to their program IDs. For example, a program may need to
409//! verify that an ed25519 signature verification instruction was included in
410//! the same transaction as its own instruction. For many native programs, this
411//! crate also defines enums that represent the instructions they process, and
412//! constructors for building the instructions.
413//!
414//! Locations of program IDs and instruction constructors are noted in the list
415//! below, as well as whether they are invokable by other programs.
416//!
417//! While some native programs have been active since the genesis block, others
418//! are activated dynamically after a specific [slot], and some are not yet
419//! active. This documentation does not distinguish which native programs are
420//! active on any particular network. The `solana feature status` CLI command
421//! can help in determining active features.
422//!
423//! [slot]: https://docs.solana.com/terminology#slot
424//!
425//! Native programs important to Solana program authors include:
426//!
427//! - __System Program__: Creates new accounts, allocates account data, assigns
428//! accounts to owning programs, transfers lamports from System Program owned
429//! accounts and pays transaction fees.
430//! - ID: [`solomka_program::system_program`]
431//! - Instruction: [`solomka_program::system_instruction`]
432//! - Invokable by programs? yes
433//!
434//! - __Compute Budget Program__: Requests additional CPU or memory resources
435//! for a transaction. This program does nothing when called from another
436//! program.
437//! - ID: [`solomka_sdk::compute_budget`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/index.html)
438//! - Instruction: [`solomka_sdk::compute_budget`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/index.html)
439//! - Invokable by programs? no
440//!
441//! - __ed25519 Program__: Verifies an ed25519 signature.
442//! - ID: [`solomka_program::ed25519_program`]
443//! - Instruction: [`solomka_sdk::ed25519_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/ed25519_instruction/index.html)
444//! - Invokable by programs? no
445//!
446//! - __secp256k1 Program__: Verifies secp256k1 public key recovery operations.
447//! - ID: [`solomka_program::secp256k1_program`]
448//! - Instruction: [`solomka_sdk::secp256k1_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/secp256k1_instruction/index.html)
449//! - Invokable by programs? no
450//!
451//! - __BPF Loader__: Deploys, and executes immutable programs on the chain.
452//! - ID: [`solomka_program::bpf_loader`]
453//! - Instruction: [`solomka_program::loader_instruction`]
454//! - Invokable by programs? yes
455//!
456//! - __Upgradable BPF Loader__: Deploys, upgrades, and executes upgradable
457//! programs on the chain.
458//! - ID: [`solomka_program::bpf_loader_upgradeable`]
459//! - Instruction: [`solomka_program::loader_upgradeable_instruction`]
460//! - Invokable by programs? yes
461//!
462//! - __Deprecated BPF Loader__: Deploys, and executes immutable programs on the
463//! chain.
464//! - ID: [`solomka_program::bpf_loader_deprecated`]
465//! - Instruction: [`solomka_program::loader_instruction`]
466//! - Invokable by programs? yes
467//!
468//! [lut]: https://docs.solana.com/proposals/transactions-v2
469//!
470//! # Sysvars
471//!
472//! Sysvars are special accounts that contain dynamically-updated data about
473//! the network cluster, the blockchain history, and the executing transaction.
474//!
475//! The program IDs for sysvars are defined in the [`sysvar`] module, and simple
476//! sysvars implement the [`Sysvar::get`] method, which loads a sysvar directly
477//! from the runtime, as in this example that logs the `clock` sysvar:
478//!
479//! [`Sysvar::get`]: sysvar::Sysvar::get
480//!
481//! ```
482//! use solomka_program::{
483//! account_info::AccountInfo,
484//! clock,
485//! entrypoint::ProgramResult,
486//! msg,
487//! pubkey::Pubkey,
488//! sysvar::Sysvar,
489//! };
490//!
491//! fn process_instruction(
492//! program_id: &Pubkey,
493//! accounts: &[AccountInfo],
494//! instruction_data: &[u8],
495//! ) -> ProgramResult {
496//! let clock = clock::Clock::get()?;
497//! msg!("clock: {:#?}", clock);
498//! Ok(())
499//! }
500//! ```
501//!
502//! Since Solana sysvars are accounts, if the `AccountInfo` is provided to the
503//! program, then the program can deserialize the sysvar with
504//! [`Sysvar::from_account_info`] to access its data, as in this example that
505//! again logs the [`clock`][clk] sysvar.
506//!
507//! [`Sysvar::from_account_info`]: sysvar::Sysvar::from_account_info
508//! [clk]: sysvar::clock
509//!
510//! ```
511//! use solomka_program::{
512//! account_info::{next_account_info, AccountInfo},
513//! clock,
514//! entrypoint::ProgramResult,
515//! msg,
516//! pubkey::Pubkey,
517//! sysvar::Sysvar,
518//! };
519//!
520//! fn process_instruction(
521//! program_id: &Pubkey,
522//! accounts: &[AccountInfo],
523//! instruction_data: &[u8],
524//! ) -> ProgramResult {
525//! let account_info_iter = &mut accounts.iter();
526//! let clock_account = next_account_info(account_info_iter)?;
527//! let clock = clock::Clock::from_account_info(&clock_account)?;
528//! msg!("clock: {:#?}", clock);
529//! Ok(())
530//! }
531//! ```
532//!
533//! When possible, programs should prefer to call `Sysvar::get` instead of
534//! deserializing with `Sysvar::from_account_info`, as the latter imposes extra
535//! overhead of deserialization while also requiring the sysvar account address
536//! be passed to the program, wasting the limited space available to
537//! transactions. Deserializing sysvars that can instead be retrieved with
538//! `Sysvar::get` should be only be considered for compatibility with older
539//! programs that pass around sysvar accounts.
540//!
541//! Some sysvars are too large to deserialize within a program, and
542//! `Sysvar::from_account_info` returns an error. Some sysvars are too large
543//! to deserialize within a program, and attempting to will exhaust the
544//! program's compute budget. Some sysvars do not implement `Sysvar::get` and
545//! return an error. Some sysvars have custom deserializers that do not
546//! implement the `Sysvar` trait. These cases are documented in the modules for
547//! individual sysvars.
548//!
549//! For more details see the Solana [documentation on sysvars][sysvardoc].
550//!
551//! [sysvardoc]: https://docs.solana.com/developing/runtime-facilities/sysvars
552
553#![allow(incomplete_features)]
554#![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(specialization))]
555#![cfg_attr(RUSTC_NEEDS_PROC_MACRO_HYGIENE, feature(proc_macro_hygiene))]
556
557// Allows macro expansion of `use ::solomka_program::*` to work within this crate
558extern crate self as solomka_program;
559
560pub mod account_info;
561pub mod address_lookup_table_account;
562pub(crate) mod atomic_u64;
563pub mod blake3;
564pub mod borsh;
565pub mod bpf_loader;
566pub mod bpf_loader_deprecated;
567pub mod bpf_loader_upgradeable;
568pub mod clock;
569pub mod debug_account_data;
570pub mod decode_error;
571pub mod ed25519_program;
572pub mod entrypoint;
573pub mod entrypoint_deprecated;
574pub mod epoch_schedule;
575pub mod feature;
576pub mod fee_calculator;
577pub mod hash;
578pub mod incinerator;
579pub mod instruction;
580pub mod keccak;
581pub mod lamports;
582pub mod loader_instruction;
583pub mod loader_upgradeable_instruction;
584pub mod log;
585pub mod message;
586pub mod native_token;
587pub mod nonce;
588pub mod program;
589pub mod program_error;
590pub mod program_memory;
591pub mod program_option;
592pub mod program_pack;
593pub mod program_stubs;
594pub mod program_utils;
595pub mod pubkey;
596pub mod rent;
597pub mod sanitize;
598pub mod secp256k1_program;
599pub mod secp256k1_recover;
600pub mod serde_varint;
601pub mod serialize_utils;
602pub mod short_vec;
603pub mod slot_hashes;
604pub mod slot_history;
605pub mod stake;
606pub mod stake_history;
607pub mod syscalls;
608pub mod system_instruction;
609pub mod system_program;
610pub mod sysvar;
611pub mod wasm;
612
613#[cfg(target_os = "solana")]
614pub use solomka_sdk_macro::wasm_bindgen_stub as wasm_bindgen;
615/// Re-export of [wasm-bindgen].
616///
617/// [wasm-bindgen]: https://rustwasm.github.io/docs/wasm-bindgen/
618#[cfg(not(target_os = "solana"))]
619pub use wasm_bindgen::prelude::wasm_bindgen;
620
621/// The [config native program][np].
622///
623/// [np]: https://docs.solana.com/developing/runtime-facilities/programs#config-program
624pub mod config {
625 pub mod program {
626 crate::declare_id!("Config1111111111111111111111111111111111111");
627 }
628}
629
630/// The [vote native program][np].
631///
632/// [np]: https://docs.solana.com/developing/runtime-facilities/programs#vote-program
633pub mod vote {
634 pub mod program {
635 crate::declare_id!("Vote111111111111111111111111111111111111111");
636 }
637}
638
639/// A vector of Solana SDK IDs
640pub mod sdk_ids {
641 use {
642 crate::{
643 bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, config, ed25519_program,
644 feature, incinerator, secp256k1_program, solomka_program::pubkey::Pubkey, stake,
645 system_program, sysvar, vote,
646 },
647 lazy_static::lazy_static,
648 };
649
650 lazy_static! {
651 pub static ref SDK_IDS: Vec<Pubkey> = {
652 let mut sdk_ids = vec![
653 ed25519_program::id(),
654 secp256k1_program::id(),
655 system_program::id(),
656 sysvar::id(),
657 bpf_loader::id(),
658 bpf_loader_upgradeable::id(),
659 incinerator::id(),
660 config::program::id(),
661 vote::program::id(),
662 feature::id(),
663 bpf_loader_deprecated::id(),
664 stake::config::id(),
665 ];
666 sdk_ids.extend(sysvar::ALL_IDS.iter());
667 sdk_ids
668 };
669 }
670}
671
672/// Same as [`declare_id`] except that it reports that this ID has been deprecated.
673pub use solomka_sdk_macro::program_declare_deprecated_id as declare_deprecated_id;
674/// Convenience macro to declare a static public key and functions to interact with it.
675///
676/// Input: a single literal base58 string representation of a program's ID.
677///
678/// # Example
679///
680/// ```
681/// # // wrapper is used so that the macro invocation occurs in the item position
682/// # // rather than in the statement position which isn't allowed.
683/// use std::str::FromStr;
684/// use solomka_program::{declare_id, pubkey::Pubkey};
685///
686/// # mod item_wrapper {
687/// # use solomka_program::declare_id;
688/// declare_id!("My11111111111111111111111111111111111111111");
689/// # }
690/// # use item_wrapper::id;
691///
692/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
693/// assert_eq!(id(), my_id);
694/// ```
695pub use solomka_sdk_macro::program_declare_id as declare_id;
696/// Convenience macro to define a static public key.
697///
698/// Input: a single literal base58 string representation of a Pubkey.
699///
700/// # Example
701///
702/// ```
703/// use std::str::FromStr;
704/// use solomka_program::{pubkey, pubkey::Pubkey};
705///
706/// static ID: Pubkey = pubkey!("My11111111111111111111111111111111111111111");
707///
708/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
709/// assert_eq!(ID, my_id);
710/// ```
711pub use solomka_sdk_macro::program_pubkey as pubkey;
712
713#[macro_use]
714extern crate serde_derive;
715
716#[macro_use]
717extern crate solana_frozen_abi_macro;
718
719/// Convenience macro for doing integer division where the operation's safety
720/// can be checked at compile-time.
721///
722/// Since `unchecked_div_by_const!()` is supposed to fail at compile-time, abuse
723/// doctests to cover failure modes
724///
725/// # Examples
726///
727/// Literal denominator div-by-zero fails:
728///
729/// ```compile_fail
730/// # use solomka_program::unchecked_div_by_const;
731/// # fn main() {
732/// let _ = unchecked_div_by_const!(10, 0);
733/// # }
734/// ```
735///
736/// Const denominator div-by-zero fails:
737///
738/// ```compile_fail
739/// # use solomka_program::unchecked_div_by_const;
740/// # fn main() {
741/// const D: u64 = 0;
742/// let _ = unchecked_div_by_const!(10, D);
743/// # }
744/// ```
745///
746/// Non-const denominator fails:
747///
748/// ```compile_fail
749/// # use solomka_program::unchecked_div_by_const;
750/// # fn main() {
751/// let d = 0;
752/// let _ = unchecked_div_by_const!(10, d);
753/// # }
754/// ```
755///
756/// Literal denominator div-by-zero fails:
757///
758/// ```compile_fail
759/// # use solomka_program::unchecked_div_by_const;
760/// # fn main() {
761/// const N: u64 = 10;
762/// let _ = unchecked_div_by_const!(N, 0);
763/// # }
764/// ```
765///
766/// Const denominator div-by-zero fails:
767///
768/// ```compile_fail
769/// # use solomka_program::unchecked_div_by_const;
770/// # fn main() {
771/// const N: u64 = 10;
772/// const D: u64 = 0;
773/// let _ = unchecked_div_by_const!(N, D);
774/// # }
775/// ```
776///
777/// Non-const denominator fails:
778///
779/// ```compile_fail
780/// # use solomka_program::unchecked_div_by_const;
781/// # fn main() {
782/// # const N: u64 = 10;
783/// let d = 0;
784/// let _ = unchecked_div_by_const!(N, d);
785/// # }
786/// ```
787///
788/// Literal denominator div-by-zero fails:
789///
790/// ```compile_fail
791/// # use solomka_program::unchecked_div_by_const;
792/// # fn main() {
793/// let n = 10;
794/// let _ = unchecked_div_by_const!(n, 0);
795/// # }
796/// ```
797///
798/// Const denominator div-by-zero fails:
799///
800/// ```compile_fail
801/// # use solomka_program::unchecked_div_by_const;
802/// # fn main() {
803/// let n = 10;
804/// const D: u64 = 0;
805/// let _ = unchecked_div_by_const!(n, D);
806/// # }
807/// ```
808///
809/// Non-const denominator fails:
810///
811/// ```compile_fail
812/// # use solomka_program::unchecked_div_by_const;
813/// # fn main() {
814/// let n = 10;
815/// let d = 0;
816/// let _ = unchecked_div_by_const!(n, d);
817/// # }
818/// ```
819#[macro_export]
820macro_rules! unchecked_div_by_const {
821 ($num:expr, $den:expr) => {{
822 // Ensure the denominator is compile-time constant
823 let _ = [(); ($den - $den) as usize];
824 // Compile-time constant integer div-by-zero passes for some reason
825 // when invoked from a compilation unit other than that where this
826 // macro is defined. Do an explicit zero-check for now. Sorry about the
827 // ugly error messages!
828 // https://users.rust-lang.org/t/unexpected-behavior-of-compile-time-integer-div-by-zero-check-in-declarative-macro/56718
829 let _ = [(); ($den as usize) - 1];
830 #[allow(clippy::integer_arithmetic)]
831 let quotient = $num / $den;
832 quotient
833 }};
834}
835
836use std::{mem::MaybeUninit, ptr::write_bytes};
837
838#[macro_export]
839macro_rules! copy_field {
840 ($ptr:expr, $self:ident, $field:ident) => {
841 std::ptr::addr_of_mut!((*$ptr).$field).write($self.$field)
842 };
843}
844
845pub fn clone_zeroed<T, F>(clone: F) -> T
846where
847 F: Fn(&mut MaybeUninit<T>),
848{
849 let mut value = MaybeUninit::<T>::uninit();
850 unsafe { write_bytes(&mut value, 0, 1) }
851 clone(&mut value);
852 unsafe { value.assume_init() }
853}
854
855// This module is purposefully listed after all other exports: because of an
856// interaction within rustdoc between the reexports inside this module of
857// `solomka_program`'s top-level modules, and `solomka_sdk`'s glob re-export of
858// `solomka_program`'s top-level modules, if this module is not lexically last
859// rustdoc fails to generate documentation for the re-exports within
860// `solomka_sdk`.
861#[cfg(not(target_os = "solana"))]
862pub mod example_mocks;
863
864#[cfg(test)]
865mod tests {
866 use super::unchecked_div_by_const;
867
868 #[test]
869 fn test_unchecked_div_by_const() {
870 const D: u64 = 2;
871 const N: u64 = 10;
872 let n = 10;
873 assert_eq!(unchecked_div_by_const!(10, 2), 5);
874 assert_eq!(unchecked_div_by_const!(N, 2), 5);
875 assert_eq!(unchecked_div_by_const!(n, 2), 5);
876 assert_eq!(unchecked_div_by_const!(10, D), 5);
877 assert_eq!(unchecked_div_by_const!(N, D), 5);
878 assert_eq!(unchecked_div_by_const!(n, D), 5);
879 }
880}