Developing with Rust | Solana (2024)

Solana supports writing onchain programs using theRust programming language.

Hello World: Get started with Solana development

To quickly get started with Solana development and build your first Rustprogram, take a look at these detailed quick start guides:

  • Build and deploy your first Solana program using only your browser.No installation needed.
  • Setup your local environment and use the localtest validator.

Project Layout #

Solana Rust programs follow the typicalRust project layout:

/inc//src//Cargo.toml

Solana Rust programs may depend directly on each other in order to gain accessto instruction helpers when makingcross-program invocations. When doing so it's important tonot pull in the dependent program's entrypoint symbols because they may conflictwith the program's own. To avoid this, programs should define an no-entrypointfeature in Cargo.toml and use to exclude the entrypoint.

Then when other programs include this program as a dependency, they should do sousing the no-entrypoint feature.

Project Dependencies #

At a minimum, Solana Rust programs must pull in thesolana-program crate.

Solana SBF programs have some restrictions that may prevent theinclusion of some crates as dependencies or require special handling.

For example:

  • Crates that require the architecture be a subset of the ones supported by theofficial toolchain. There is no workaround for this unless that crate isforked and SBF added to that those architecture checks.
  • Crates may depend on rand which is not supported in Solana's deterministicprogram environment. To include a rand dependent crate refer toDepending on Rand.
  • Crates may overflow the stack even if the stack overflowing code isn'tincluded in the program itself. For more information refer toStack.

How to Build #

First setup the environment:

  • Install the latest Rust stable from https://rustup.rs/
  • Install the latest Solana command-line tools

The normal cargo build is available for building programs against your hostmachine which can be used for unit testing:

cargo build

To build a specific program, such as SPL Token, for the Solana SBF target whichcan be deployed to the cluster:

cd <the program directory>cargo build-bpf

How to Test #

Solana programs can be unit tested via the traditional cargo test mechanism byexercising program functions directly.

To help facilitate testing in an environment that more closely matches a livecluster, developers can use theprogram-test crate. Theprogram-test crate starts up a local instance of the runtime and allows teststo send multiple transactions while keeping state for the duration of the test.

For more information thetest in sysvar exampleshows how an instruction containing sysvar account is sent and processed by theprogram.

Program Entrypoint #

Programs export a known entrypoint symbol which the Solana runtime looks up andcalls when invoking a program. Solana supports multiple versions of the BPFloader and the entrypoints may vary between them. Programs must be written forand deployed to the same loader. For more details see theFAQ section on Loaders.

Currently there are two supported loadersBPF LoaderandBPF loader deprecated

They both have the same raw entrypoint definition, the following is the rawsymbol that the runtime looks up and calls:

#[no_mangle]pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64;

This entrypoint takes a generic byte array which contains the serialized programparameters (program id, accounts, instruction data, etc...). To deserialize theparameters each loader contains its own wrapper macro that exports the rawentrypoint, deserializes the parameters, calls a user defined instructionprocessing function, and returns the results.

You can find the entrypoint macros here:

The program defined instruction processing function that the entrypoint macroscall must be of this form:

pub type ProcessInstruction = fn(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult;

Parameter Deserialization #

Each loader provides a helper function that deserializes the program's inputparameters into Rust types. The entrypoint macros automatically calls thedeserialization helper:

Some programs may want to perform deserialization themselves and they can byproviding their own implementation of the raw entrypoint.Take note that the provided deserialization functions retain references back tothe serialized byte array for variables that the program is allowed to modify(lamports, account data). The reason for this is that upon return the loaderwill read those modifications so they may be committed. If a program implementstheir own deserialization function they need to ensure that any modificationsthe program wishes to commit be written back into the input byte array.

Details on how the loader serializes the program inputs can be found in theInput Parameter Serializationdocs.

Data Types #

The loader's entrypoint macros call the program defined instruction processorfunction with the following parameters:

program_id: &Pubkey,accounts: &[AccountInfo],instruction_data: &[u8]

The program id is the public key of the currently executing program.

The accounts is an ordered slice of the accounts referenced by the instructionand represented as anAccountInfostructures. An account's place in the array signifies its meaning, for example,when transferring lamports an instruction may define the first account as thesource and the second as the destination.

The members of the AccountInfo structure are read-only except for lamportsand data. Both may be modified by the program in accordance with the "runtimeenforcement policy". Both of these members are protected by the Rust RefCellconstruct, so they must be borrowed to read or write to them. The reason forthis is they both point back to the original input byte array, but there may bemultiple entries in the accounts slice that point to the same account. UsingRefCell ensures that the program does not accidentally perform overlappingread/writes to the same underlying data via multiple AccountInfo structures.If a program implements their own deserialization function care should be takento handle duplicate accounts appropriately.

The instruction data is the general purpose byte array from theinstruction's instruction data beingprocessed.

Heap #

Rust programs implement the heap directly by defining a customglobal_allocator

Programs may implement their own global_allocator based on its specific needs.Refer to the custom heap example for more information.

Restrictions #

On-chain Rust programs support most of Rust's libstd, libcore, and liballoc, aswell as many 3rd party crates.

There are some limitations since these programs run in a resource-constrained,single-threaded environment, as well as being deterministic:

  • No access to
    • rand
    • std::fs
    • std::net
    • std::future
    • std::process
    • std::sync
    • std::task
    • std::thread
    • std::time
  • Limited access to:
    • std::hash
    • std::os
  • Bincode is extremely computationally expensive in both cycles and call depthand should be avoided
  • String formatting should be avoided since it is also computationallyexpensive.
  • No support for println!, print!, the Solana logging helpersshould be used instead.
  • The runtime enforces a limit on the number of instructions a program canexecute during the processing of one instruction. Seecomputation budget for more information.

Depending on Rand #

Programs are constrained to run deterministically, so random numbers are notavailable. Sometimes a program may depend on a crate that depends itself onrand even if the program does not use any of the random number functionality.If a program depends on rand, the compilation will fail because there is noget-random support for Solana. The error will typically look like this:

error: target is not supported, for more information see: https://docs.rs/getrandom/#unsupported-targets --> /Users/jack/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.1.14/src/lib.rs:257:9 |257 | / compile_error!("\258 | | target is not supported, for more information see: \259 | | https://docs.rs/getrandom/#unsupported-targets\260 | | "); | |___________^

To work around this dependency issue, add the following dependency to theprogram's Cargo.toml:

getrandom = { version = "0.1.14", features = ["dummy"] }

or if the dependency is on getrandom v0.2 add:

getrandom = { version = "0.2.2", features = ["custom"] }

Logging #

Rust's println! macro is computationally expensive and not supported. Insteadthe helper macromsg!is provided.

msg! has two forms:

msg!("A string");

or

msg!(0_64, 1_64, 2_64, 3_64, 4_64);

Both forms output the results to the program logs. If a program so wishes theycan emulate println! by using format!:

msg!("Some variable: {:?}", variable);

The debugging section has moreinformation about working with program logs the Rust examplescontains a logging example.

Panicking #

Rust's panic!, assert!, and internal panic results are printed to theprogram logs by default.

INFO solana_runtime::message_processor] Finalized account CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZINFO solana_runtime::message_processor] Call SBF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZINFO solana_runtime::message_processor] Program log: Panicked at: 'assertion failed: `(left == right)` left: `1`, right: `2`', rust/panic/src/lib.rs:22:5INFO solana_runtime::message_processor] SBF program consumed 5453 of 200000 unitsINFO solana_runtime::message_processor] SBF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ failed: BPF program panicked

Custom Panic Handler #

Programs can override the default panic handler by providing their ownimplementation.

First define the custom-panic feature in the program's Cargo.toml

[features]default = ["custom-panic"]custom-panic = []

Then provide a custom implementation of the panic handler:

#[cfg(all(feature = "custom-panic", target_os = "solana"))]#[no_mangle]fn custom_panic(info: &core::panic::PanicInfo<'_>) { solana_program::msg!("program custom panic enabled"); solana_program::msg!("{}", info);}

In the above snippit, the default implementation is shown, but developers mayreplace that with something that better suits their needs.

One of the side effects of supporting full panic messages by default is thatprograms incur the cost of pulling in more of Rust's libstd implementationinto program's shared object. Typical programs will already be pulling in a fairamount of libstd and may not notice much of an increase in the shared objectsize. But programs that explicitly attempt to be very small by avoiding libstdmay take a significant impact (~25kb). To eliminate that impact, programs canprovide their own custom panic handler with an empty implementation.

#[cfg(all(feature = "custom-panic", target_os = "solana"))]#[no_mangle]fn custom_panic(info: &core::panic::PanicInfo<'_>) { // Do nothing to save space}

Compute Budget #

Use the system call sol_remaining_compute_units() to return a u64 indicatingthe number of compute units remaining for this transaction.

Use the system callsol_log_compute_units()to log a message containing the remaining number of compute units the programmay consume before execution is halted

See the Compute Budget documentation formore information.

ELF Dump #

The SBF shared object internals can be dumped to a text file to gain moreinsight into a program's composition and what it may be doing at runtime. Thedump will contain both the ELF information as well as a list of all the symbolsand the instructions that implement them. Some of the BPF loader's error logmessages will reference specific instruction numbers where the error occurred.These references can be looked up in the ELF dump to identify the offendinginstruction and its context.

To create a dump file:

cd <program directory>cargo build-bpf --dump

Examples #

TheSolana Program Library GitHubrepo contains a collection of Rust examples.

TheSolana Developers Program Examples GitHubrepo also contains a collection of beginner to intermediate Rust programexamples.

Developing with Rust | Solana (2024)
Top Articles
U.S. states with least number of vehicle thefts 2020 | Statista
Transavia | Aéroport Rennes Bretagne
Lakers Game Summary
Dricxzyoki
Skamania Lodge Groupon
Clafi Arab
Mikayla Campino Video Twitter: Unveiling the Viral Sensation and Its Impact on Social Media
Bed Bath And Body Works Hiring
Texas (TX) Powerball - Winning Numbers & Results
Aries Auhsd
MindWare : Customer Reviews : Hocus Pocus Magic Show Kit
Shooting Games Multiplayer Unblocked
Rosemary Beach, Panama City Beach, FL Real Estate & Homes for Sale | realtor.com®
About Us | TQL Careers
The most iconic acting lineages in cinema history
Seattle Rpz
Xomissmandi
Trivago Sf
Palm Springs Ca Craigslist
Promiseb Discontinued
Tyrone Unblocked Games Bitlife
Sec Baseball Tournament Score
Regal Amc Near Me
Phantom Fireworks Of Delaware Watergap Photos
6892697335
Churchill Downs Racing Entries
No Limit Telegram Channel
3 Ways to Drive Employee Engagement with Recognition Programs | UKG
A Man Called Otto Showtimes Near Carolina Mall Cinema
Where to eat: the 50 best restaurants in Freiburg im Breisgau
Willys Pickup For Sale Craigslist
Street Fighter 6 Nexus
Frommer's Belgium, Holland and Luxembourg (Frommer's Complete Guides) - PDF Free Download
#1 | Rottweiler Puppies For Sale In New York | Uptown
8005607994
Anya Banerjee Feet
Nancy Pazelt Obituary
Review: T-Mobile's Unlimited 4G voor Thuis | Consumentenbond
Nba Props Covers
11526 Lake Ave Cleveland Oh 44102
Craigslist Antique
Satucket Lectionary
56X40X25Cm
Take Me To The Closest Ups
Hughie Francis Foley – Marinermath
17 of the best things to do in Bozeman, Montana
Greg Steube Height
Concentrix + Webhelp devient Concentrix
Wvu Workday
When Is The First Cold Front In Florida 2022
Ocean County Mugshots
Land of Samurai: One Piece’s Wano Kuni Arc Explained
Latest Posts
Article information

Author: Msgr. Refugio Daniel

Last Updated:

Views: 6833

Rating: 4.3 / 5 (74 voted)

Reviews: 89% of readers found this page helpful

Author information

Name: Msgr. Refugio Daniel

Birthday: 1999-09-15

Address: 8416 Beatty Center, Derekfort, VA 72092-0500

Phone: +6838967160603

Job: Mining Executive

Hobby: Woodworking, Knitting, Fishing, Coffee roasting, Kayaking, Horseback riding, Kite flying

Introduction: My name is Msgr. Refugio Daniel, I am a fine, precious, encouraging, calm, glamorous, vivacious, friendly person who loves writing and wants to share my knowledge and understanding with you.