The loader's entrypoint macros call the program defined instruction processor function with the following parameters:
The program id is the public key of the currently executing program.
The accounts is an ordered slice of the accounts referenced by the instruction. An account's place in the array signifies its meaning, for example, when transferring lamports an instruction may define the first account as the source and the second as the destination.
The members of the AccountInfo structure are read-only except for lamports and data. Both of these members are protected by the Rust RefCell construct, so they must be borrowed to read or write to them. The reason for this is they both point back to the original input byte array, but there may be multiple entries in the accounts slice that point to the same account. Using RefCell ensures that the program does not accidentally perform overlapping read/writes to the same underlying data via multiple AccountInfo structures. If a program implements its own deserialization function care should be taken to handle duplicate accounts appropriately.
On-chain Rust programs support most of Rust's libstd, libcore, and liballoc, as well as many 3rd party crates.
There are some limitations since these programs run in a resource-constrained, single-threaded environment, and must be deterministic:
No access to:
○ Std::process○ Std::sync
Limited access to:
Bincode is extremely computationally expensive in both cycles and call depth and should be avoided.
String formatting should be avoided since it is also computationally expensive.
No support for println!, print!, Instead the helper macro msg! is provided.
Programs support a limited subset of Rust's float operations, if a program attempts to use a float operation that is not supported, the runtime will report an unresolved symbol error. Also, the BPF instruction set does not support signed division.
The runtime enforces a limit on the number of instructions a program can execute during the processing of one instruction.
Programs are constrained to run deterministically, so random numbers are not available. Sometimes a program may depend on a crate that depends itself on rand 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 no get random support for Solana.
Rust's panic!, assert!, and internal panic results are printed to the program logs by default.
Use the system call sol_log_compute_units() to log a message containing the remaining number of computing units the program may consume before execution is halted.