[docs] updating the "writing programs" section (#29197)
* docs: added limitations page * fix: updated deprecated cargo test-bpf * docs: moved content off of overview * fix: added compute budget description * fix: updated compute buddget * fix: rearranged sections * fix: update code snippet * docs: overview page and links
This commit is contained in:
parent
1e0d3931fd
commit
5918d6f09d
|
@ -240,6 +240,11 @@ module.exports = {
|
|||
id: "developing/on-chain-programs/examples",
|
||||
label: "Program Examples",
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "developing/on-chain-programs/limitations",
|
||||
label: "Limitations",
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "developing/on-chain-programs/faq",
|
||||
|
|
|
@ -56,10 +56,9 @@ information on how to write a test case.
|
|||
## Program Entrypoint
|
||||
|
||||
Programs export a known entrypoint symbol which the Solana runtime looks up and
|
||||
calls when invoking a program. Solana supports multiple [versions of the SBF
|
||||
loader](overview.md#versions) and the entrypoints may vary between them.
|
||||
calls when invoking a program. Solana supports multiple versions of the SBF loader and the entrypoints may vary between them.
|
||||
Programs must be written for and deployed to the same loader. For more details
|
||||
see the [overview](overview#loaders).
|
||||
see the [FAQ section on Loaders](./faq.md#loaders).
|
||||
|
||||
Currently there are two supported loaders [SBF
|
||||
Loader](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17)
|
||||
|
@ -104,7 +103,7 @@ their own deserialization function they need to ensure that any modifications
|
|||
the program wishes to commit must be written back into the input byte array.
|
||||
|
||||
Details on how the loader serializes the program inputs can be found in the
|
||||
[Input Parameter Serialization](overview.md#input-parameter-serialization) docs.
|
||||
[Input Parameter Serialization](./faq.md#input-parameter-serialization) docs.
|
||||
|
||||
## Data Types
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ For example:
|
|||
on Rand](#depending-on-rand).
|
||||
- Crates may overflow the stack even if the stack overflowing code isn't
|
||||
included in the program itself. For more information refer to
|
||||
[Stack](overview.md#stack).
|
||||
[Stack](./faq.md#stack).
|
||||
|
||||
## How to Build
|
||||
|
||||
|
@ -95,10 +95,10 @@ program.
|
|||
## Program Entrypoint
|
||||
|
||||
Programs export a known entrypoint symbol which the Solana runtime looks up and
|
||||
calls when invoking a program. Solana supports multiple [versions of the BPF
|
||||
loader](overview.md#versions) and the entrypoints may vary between them.
|
||||
calls when invoking a program. Solana supports multiple versions of the BPF
|
||||
loader and the entrypoints may vary between them.
|
||||
Programs must be written for and deployed to the same loader. For more details
|
||||
see the [overview](overview#loaders).
|
||||
see the [FAQ section on Loaders](./faq.md#loaders).
|
||||
|
||||
Currently there are two supported loaders [BPF
|
||||
Loader](https://github.com/solana-labs/solana/blob/d9b0fc0e3eec67dfe4a97d9298b15969b2804fab/sdk/program/src/bpf_loader.rs#L17)
|
||||
|
@ -159,7 +159,7 @@ their own deserialization function they need to ensure that any modifications
|
|||
the 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 the
|
||||
[Input Parameter Serialization](overview.md#input-parameter-serialization) docs.
|
||||
[Input Parameter Serialization](./faq.md#input-parameter-serialization) docs.
|
||||
|
||||
### Data Types
|
||||
|
||||
|
@ -211,7 +211,7 @@ 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:
|
||||
single-threaded environment, as well as being deterministic:
|
||||
|
||||
- No access to
|
||||
- `rand`
|
||||
|
|
|
@ -8,32 +8,36 @@ questions.
|
|||
|
||||
If not addressed here, ask on [StackOverflow](https://stackoverflow.com/questions/tagged/solana) with the `solana` tag or check out the Solana [#developer-support](https://discord.gg/RxeGBH)
|
||||
|
||||
## `CallDepth` error
|
||||
## Limitations
|
||||
|
||||
This error means that that cross-program invocation exceeded the allowed
|
||||
invocation call depth.
|
||||
Developing programs on the Solana blockchain have some inherent limitation associated with them. Below is a list of common limitation that you may run into.
|
||||
|
||||
See [cross-program invocation Call
|
||||
Depth](developing/programming-model/calling-between-programs.md#call-depth)
|
||||
See [Limitations of developing programs](./limitations.md) for more details
|
||||
|
||||
## `CallDepthExceeded` error
|
||||
## Berkeley Packet Filter (BPF)
|
||||
|
||||
This error means the SBF stack depth was exceeded.
|
||||
Solana on-chain programs are compiled via the [LLVM compiler infrastructure](https://llvm.org/) to an [Executable and Linkable Format (ELF)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) containing
|
||||
a variation of the [Berkeley Packet Filter (BPF)](https://en.wikipedia.org/wiki/Berkeley_Packet_Filter) bytecode.
|
||||
|
||||
See [call depth](overview.md#call-depth)
|
||||
Because Solana uses the LLVM compiler infrastructure, a program may be written in any programming language that can target the LLVM's BPF backend.
|
||||
|
||||
## Computational constraints
|
||||
BPF provides an efficient [instruction set](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md) that can be executed in an interpreted virtual machine or as efficient just-in-time compiled native instructions.
|
||||
|
||||
See [computational
|
||||
constraints](developing/programming-model/runtime.md#compute-budget)
|
||||
## Memory map
|
||||
|
||||
## Float Rust types
|
||||
The virtual address memory map used by Solana SBF programs is fixed and laid out
|
||||
as follows
|
||||
|
||||
See [float support](overview.md#float-support)
|
||||
- Program code starts at 0x100000000
|
||||
- Stack data starts at 0x200000000
|
||||
- Heap data starts at 0x300000000
|
||||
- Program input parameters start at 0x400000000
|
||||
|
||||
## Heap size
|
||||
|
||||
See [heap](overview.md#heap)
|
||||
The above virtual addresses are start addresses but programs are given access to
|
||||
a subset of the memory map. The program will panic if it attempts to read or
|
||||
write to a virtual address that it was not granted access to, and an
|
||||
`AccessViolation` error will be returned that contains the address and size of
|
||||
the attempted violation.
|
||||
|
||||
## InvalidAccountData
|
||||
|
||||
|
@ -75,6 +79,137 @@ See [Rust Project Dependencies](developing-rust.md#project-dependencies)
|
|||
|
||||
See [Rust restrictions](developing-rust.md#restrictions)
|
||||
|
||||
## Stack size
|
||||
## Stack
|
||||
|
||||
See [stack](overview.md#stack)
|
||||
SBF uses stack frames instead of a variable stack pointer. Each stack frame is
|
||||
4KB in size.
|
||||
|
||||
If a program violates that stack frame size, the compiler will report the
|
||||
overrun as a warning.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
Error: Function _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E Stack offset of -30728 exceeded max offset of -4096 by 26632 bytes, please minimize large stack variables
|
||||
```
|
||||
|
||||
The message identifies which symbol is exceeding its stack frame, but the name
|
||||
might be mangled if it is a Rust or C++ symbol.
|
||||
|
||||
> To demangle a Rust symbol use [rustfilt](https://github.com/luser/rustfilt).
|
||||
|
||||
The above warning came from a Rust program, so the demangled symbol name is:
|
||||
|
||||
```bash
|
||||
rustfilt _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E
|
||||
curve25519_dalek::edwards::EdwardsBasepointTable::create
|
||||
```
|
||||
|
||||
To demangle a C++ symbol use `c++filt` from binutils.
|
||||
|
||||
The reason a warning is reported rather than an error is because some dependent
|
||||
crates may include functionality that violates the stack frame restrictions even
|
||||
if the program doesn't use that functionality. If the program violates the stack
|
||||
size at runtime, an `AccessViolation` error will be reported.
|
||||
|
||||
SBF stack frames occupy a virtual address range starting at `0x200000000`.
|
||||
|
||||
## Heap size
|
||||
|
||||
Programs have access to a runtime heap either directly in C or via the Rust
|
||||
`alloc` APIs. To facilitate fast allocations, a simple 32KB bump heap is
|
||||
utilized. The heap does not support `free` or `realloc` so use it wisely.
|
||||
|
||||
Internally, programs have access to the 32KB memory region starting at virtual
|
||||
address 0x300000000 and may implement a custom heap based on the program's
|
||||
specific needs.
|
||||
|
||||
- [Rust program heap usage](developing-rust.md#heap)
|
||||
- [C program heap usage](developing-c.md#heap)
|
||||
|
||||
## Loaders
|
||||
|
||||
Programs are deployed with and executed by runtime loaders, currently there are
|
||||
two supported loaders [BPF
|
||||
Loader](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17)
|
||||
and [BPF loader
|
||||
deprecated](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader_deprecated.rs#L14)
|
||||
|
||||
Loaders may support different application binary interfaces so developers must
|
||||
write their programs for and deploy them to the same loader. If a program
|
||||
written for one loader is deployed to a different one the result is usually a
|
||||
`AccessViolation` error due to mismatched deserialization of the program's input
|
||||
parameters.
|
||||
|
||||
For all practical purposes program should always be written to target the latest
|
||||
BPF loader and the latest loader is the default for the command-line interface
|
||||
and the javascript APIs.
|
||||
|
||||
For language specific information about implementing a program for a particular
|
||||
loader see:
|
||||
|
||||
- [Rust program entrypoints](developing-rust.md#program-entrypoint)
|
||||
- [C program entrypoints](developing-c.md#program-entrypoint)
|
||||
|
||||
### Deployment
|
||||
|
||||
SBF program deployment is the process of uploading a BPF shared object into a
|
||||
program account's data and marking the account executable. A client breaks the
|
||||
SBF shared object into smaller pieces and sends them as the instruction data of
|
||||
[`Write`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L13)
|
||||
instructions to the loader where loader writes that data into the program's
|
||||
account data. Once all the pieces are received the client sends a
|
||||
[`Finalize`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L30)
|
||||
instruction to the loader, the loader then validates that the SBF data is valid
|
||||
and marks the program account as _executable_. Once the program account is
|
||||
marked executable, subsequent transactions may issue instructions for that
|
||||
program to process.
|
||||
|
||||
When an instruction is directed at an executable SBF program the loader
|
||||
configures the program's execution environment, serializes the program's input
|
||||
parameters, calls the program's entrypoint, and reports any errors encountered.
|
||||
|
||||
For further information see [deploying](deploying.md)
|
||||
|
||||
### Input Parameter Serialization
|
||||
|
||||
SBF loaders serialize the program input parameters into a byte array that is
|
||||
then passed to the program's entrypoint, where the program is responsible for
|
||||
deserializing it on-chain. One of the changes between the deprecated loader and
|
||||
the current loader is that the input parameters are serialized in a way that
|
||||
results in various parameters falling on aligned offsets within the aligned byte
|
||||
array. This allows deserialization implementations to directly reference the
|
||||
byte array and provide aligned pointers to the program.
|
||||
|
||||
For language specific information about serialization see:
|
||||
|
||||
- [Rust program parameter
|
||||
deserialization](developing-rust.md#parameter-deserialization)
|
||||
- [C program parameter
|
||||
deserialization](developing-c.md#parameter-deserialization)
|
||||
|
||||
The latest loader serializes the program input parameters as follows (all
|
||||
encoding is little endian):
|
||||
|
||||
- 8 bytes unsigned number of accounts
|
||||
- For each account
|
||||
- 1 byte indicating if this is a duplicate account, if not a duplicate then
|
||||
the value is 0xff, otherwise the value is the index of the account it is a
|
||||
duplicate of.
|
||||
- If duplicate: 7 bytes of padding
|
||||
- If not duplicate:
|
||||
- 1 byte boolean, true if account is a signer
|
||||
- 1 byte boolean, true if account is writable
|
||||
- 1 byte boolean, true if account is executable
|
||||
- 4 bytes of padding
|
||||
- 32 bytes of the account public key
|
||||
- 32 bytes of the account's owner public key
|
||||
- 8 bytes unsigned number of lamports owned by the account
|
||||
- 8 bytes unsigned number of bytes of account data
|
||||
- x bytes of account data
|
||||
- 10k bytes of padding, used for realloc
|
||||
- enough padding to align the offset to 8 bytes.
|
||||
- 8 bytes rent epoch
|
||||
- 8 bytes of unsigned number of instruction data
|
||||
- x bytes of instruction data
|
||||
- 32 bytes of the program id
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
title: "Limitations"
|
||||
---
|
||||
|
||||
Developing programs on the Solana blockchain have some inherent limitation associated with them. Below is a list of common limitation that you may run into.
|
||||
|
||||
## Rust libraries
|
||||
|
||||
Since Rust based on-chain programs must run be deterministic while running in a resource-constrained, single-threaded environment, they have some limitations on various libraries.
|
||||
|
||||
See [Developing with Rust - Restrictions](./developing-rust.md#restrictions) for a detailed breakdown these restrictions and limitations.
|
||||
|
||||
## Compute budget
|
||||
|
||||
To prevent abuse of the blockchain's computational resources, each transaction is allocated a [compute budget](./../../terminology.md#compute-budget). Exceeding this compute budget will result in the transaction failing.
|
||||
|
||||
See [computational constraints](../programming-model/runtime.md#compute-budget) in the Runtime for more specific details.
|
||||
|
||||
## Call stack depth - `CallDepthExceeded` error
|
||||
|
||||
Solana programs are constrained to run quickly, and to facilitate this, the program's call stack is limited to a max depth of **64 frames**.
|
||||
|
||||
When a program exceeds the allowed call stack depth limit, it will receive the `CallDepthExceeded` error.
|
||||
|
||||
## CPI call depth - `CallDepth` error
|
||||
|
||||
Cross-program invocations allow programs to invoke other programs directly, but the depth is constrained currently to `4`.
|
||||
|
||||
When a program exceeds the allowed [cross-program invocation call depth](../programming-model/calling-between-programs.md#call-depth), it will receive a `CallDepth` error
|
||||
|
||||
## Float Rust types support
|
||||
|
||||
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.
|
||||
|
||||
Float operations are performed via software libraries, specifically LLVM's float
|
||||
built-ins. Due to the software emulated, they consume more compute units than
|
||||
integer operations. In general, fixed point operations are recommended where
|
||||
possible.
|
||||
|
||||
The Solana Program Library math tests will report the performance of some math
|
||||
operations: https://github.com/solana-labs/solana-program-library/tree/master/libraries/math
|
||||
|
||||
To run the test: sync the repo and run:
|
||||
|
||||
```sh
|
||||
cargo test-sbf -- --nocapture --test-threads=1
|
||||
```
|
||||
|
||||
Recent results show the float operations take more instructions compared to
|
||||
integers equivalents. Fixed point implementations may vary but will also be
|
||||
less than the float equivalents:
|
||||
|
||||
```
|
||||
u64 f32
|
||||
Multiply 8 176
|
||||
Divide 9 219
|
||||
```
|
||||
|
||||
## Static writable data
|
||||
|
||||
Program shared objects do not support writable shared data. Programs are shared
|
||||
between multiple parallel executions using the same shared read-only code and
|
||||
data. This means that developers should not include any static writable or
|
||||
global variables in programs. In the future a copy-on-write mechanism could be
|
||||
added to support writable data.
|
||||
|
||||
## Signed division
|
||||
|
||||
The SBF instruction set does not support
|
||||
[signed division](https://www.kernel.org/doc/html/latest/bpf/bpf_design_QA.Html#q-why-there-is-no-bpf-sdiv-for-signed-divide-operation). Adding a signed division instruction is a consideration.
|
|
@ -1,218 +1,64 @@
|
|||
---
|
||||
title: "Overview"
|
||||
title: "Overview of Writing Programs"
|
||||
sidebar_label: "Overview"
|
||||
---
|
||||
|
||||
Developers can write and deploy their own programs to the Solana blockchain.
|
||||
Developers can write and deploy their own programs to the Solana blockchain. While developing these "on-chain" programs can seem cumbersome, the entire process can be broadly summarized into a few key steps.
|
||||
|
||||
The [Helloworld example](examples.md#helloworld) is a good starting place to see
|
||||
how a program is written, built, deployed, and interacted with on-chain.
|
||||
## Solana Development Lifecycle
|
||||
|
||||
## Berkeley Packet Filter (BPF)
|
||||
1. Setup your development environment
|
||||
2. Write your program
|
||||
3. Compile the program
|
||||
4. Generate the program's public address
|
||||
5. Deploy the program
|
||||
|
||||
Solana on-chain programs are compiled via the [LLVM compiler
|
||||
infrastructure](https://llvm.org/) to an [Executable and Linkable Format
|
||||
(ELF)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) containing
|
||||
a variation of the [Berkeley Packet Filter
|
||||
(BPF)](https://en.wikipedia.org/wiki/Berkeley_Packet_Filter) bytecode.
|
||||
### 1. Setup your development environment
|
||||
|
||||
Because Solana uses the LLVM compiler infrastructure, a program may be written
|
||||
in any programming language that can target the LLVM's BPF backend. Solana
|
||||
currently supports writing programs in Rust and C/C++.
|
||||
The most robust way of getting started with Solana development, is [installing the Solana CLI](./../../cli/install-solana-cli-tools.md) tools on your local computer. This will allow you to have the most powerful development environment.
|
||||
|
||||
BPF provides an efficient [instruction
|
||||
set](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md) that can be
|
||||
executed in an interpreted virtual machine or as efficient just-in-time compiled
|
||||
native instructions.
|
||||
Some developers may also opt for using [Solana Playground](https://beta.solpg.io/), a browser based IDE. It will let you write, build, and deploy on-chain programs. All from your browser. No installation needed.
|
||||
|
||||
## Memory map
|
||||
### 2. Write your program
|
||||
|
||||
The virtual address memory map used by Solana SBF programs is fixed and laid out
|
||||
as follows
|
||||
Writing Solana programs is most commonly done so using the Rust language. These Rust programs are effectively the same as creating a traditional [Rust library](https://doc.rust-lang.org/rust-by-example/crates/lib.html).
|
||||
|
||||
- Program code starts at 0x100000000
|
||||
- Stack data starts at 0x200000000
|
||||
- Heap data starts at 0x300000000
|
||||
- Program input parameters start at 0x400000000
|
||||
> You can read more about other [supported languages](#support-languages) below.
|
||||
|
||||
The above virtual addresses are start addresses but programs are given access to
|
||||
a subset of the memory map. The program will panic if it attempts to read or
|
||||
write to a virtual address that it was not granted access to, and an
|
||||
`AccessViolation` error will be returned that contains the address and size of
|
||||
the attempted violation.
|
||||
### 3. Compile the program
|
||||
|
||||
## Stack
|
||||
Once the program is written, it must be complied down to [Berkley Packet Filter](./faq.md#berkeley-packet-filter-bpf) byte-code that will then be deployed to the blockchain.
|
||||
|
||||
SBF uses stack frames instead of a variable stack pointer. Each stack frame is
|
||||
4KB in size.
|
||||
### 4. Generate the program's public address
|
||||
|
||||
If a program violates that stack frame size, the compiler will report the
|
||||
overrun as a warning.
|
||||
Using the [Solana CLI](./../../cli/install-solana-cli-tools.md), the developer will generate a new unique [Keypair](./../../terminology.md#keypair) for the new program. The public address (aka [Pubkey](./../../terminology.md#public-key-pubkey)) from this Keypair will be used on-chain as the program's public address (aka [`programId`](./../../terminology.md#program-id)).
|
||||
|
||||
For example: `Error: Function _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E Stack offset of -30728 exceeded max offset of -4096 by 26632 bytes, please minimize large stack variables`
|
||||
### 5. Deploying the program
|
||||
|
||||
The message identifies which symbol is exceeding its stack frame but the name
|
||||
might be mangled if it is a Rust or C++ symbol. To demangle a Rust symbol use
|
||||
[rustfilt](https://github.com/luser/rustfilt). The above warning came from a
|
||||
Rust program, so the demangled symbol name is:
|
||||
Then again using the CLI, the compiled program can be deployed to the selected blockchain cluster by creating many transactions containing the program's byte-code. Due to the transaction memory size limitations, each transaction effectively sends small chunks of the program to the blockchain in a rapid-fire manner.
|
||||
|
||||
```bash
|
||||
$ rustfilt _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E
|
||||
curve25519_dalek::edwards::EdwardsBasepointTable::create
|
||||
```
|
||||
Once the entire program has been sent to the blockchain, a final transaction is sent to write all of the buffered byte-code to the program's data account. This either mark the new program as [`executable`](./../programming-model/accounts.md#executable), or complete the process to upgrade an existing program (if it already existed).
|
||||
|
||||
To demangle a C++ symbol use `c++filt` from binutils.
|
||||
## Support languages
|
||||
|
||||
The reason a warning is reported rather than an error is because some dependent
|
||||
crates may include functionality that violates the stack frame restrictions even
|
||||
if the program doesn't use that functionality. If the program violates the stack
|
||||
size at runtime, an `AccessViolation` error will be reported.
|
||||
Solana programs are typically written in the [Rust language](./developing-rust.md), but [C/C++](./developing-c.md) are also supported.
|
||||
|
||||
SBF stack frames occupy a virtual address range starting at 0x200000000.
|
||||
There are also various community driven efforts to enable writing on-chain programs using other languages, including:
|
||||
|
||||
## Call Depth
|
||||
- Python via [Seahorse](https://seahorse-lang.org/) (that acts as a wrapper the Rust based Anchor framework)
|
||||
|
||||
Programs are constrained to run quickly, and to facilitate this, the program's
|
||||
call stack is limited to a max depth of 64 frames.
|
||||
## Example programs
|
||||
|
||||
## Heap
|
||||
The [Hello world example](examples.md#helloworld) is a good starting place to see how a program is written, built, deployed, and interacted with on-chain.
|
||||
|
||||
Programs have access to a runtime heap either directly in C or via the Rust
|
||||
`alloc` APIs. To facilitate fast allocations, a simple 32KB bump heap is
|
||||
utilized. The heap does not support `free` or `realloc` so use it wisely.
|
||||
You can also explore the [Program Examples](./examples.md) for other examples of on-chain programs.
|
||||
|
||||
Internally, programs have access to the 32KB memory region starting at virtual
|
||||
address 0x300000000 and may implement a custom heap based on the program's
|
||||
specific needs.
|
||||
## Limitations
|
||||
|
||||
- [Rust program heap usage](developing-rust.md#heap)
|
||||
- [C program heap usage](developing-c.md#heap)
|
||||
As you dive deeper into program development, it is important to understand some of the important limitations associated with on-chain programs.
|
||||
|
||||
## Float Support
|
||||
Read more details on the [Limitations](./limitations.md) page
|
||||
|
||||
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.
|
||||
## Frequently asked questions
|
||||
|
||||
Float operations are performed via software libraries, specifically LLVM's float
|
||||
builtins. Due to the software emulated they consume more compute units than
|
||||
integer operations. In general, fixed point operations are recommended where
|
||||
possible.
|
||||
|
||||
The Solana Program Library math tests will report the performance of some math
|
||||
operations:
|
||||
https://github.com/solana-labs/solana-program-library/tree/master/libraries/math
|
||||
|
||||
To run the test, sync the repo, and run:
|
||||
|
||||
`$ cargo test-bpf -- --nocapture --test-threads=1`
|
||||
|
||||
Recent results show the float operations take more instructions compared to
|
||||
integers equivalents. Fixed point implementations may vary but will also be
|
||||
less than the float equivalents:
|
||||
|
||||
```
|
||||
u64 f32
|
||||
Multipy 8 176
|
||||
Divide 9 219
|
||||
```
|
||||
|
||||
## Static Writable Data
|
||||
|
||||
Program shared objects do not support writable shared data. Programs are shared
|
||||
between multiple parallel executions using the same shared read-only code and
|
||||
data. This means that developers should not include any static writable or
|
||||
global variables in programs. In the future a copy-on-write mechanism could be
|
||||
added to support writable data.
|
||||
|
||||
## Signed division
|
||||
|
||||
The SBF instruction set does not support [signed
|
||||
division](https://www.kernel.org/doc/html/latest/bpf/bpf_design_QA.html#q-why-there-is-no-bpf-sdiv-for-signed-divide-operation).
|
||||
Adding a signed division instruction is a consideration.
|
||||
|
||||
## Loaders
|
||||
|
||||
Programs are deployed with and executed by runtime loaders, currently there are
|
||||
two supported loaders [BPF
|
||||
Loader](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17)
|
||||
and [BPF loader
|
||||
deprecated](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader_deprecated.rs#L14)
|
||||
|
||||
Loaders may support different application binary interfaces so developers must
|
||||
write their programs for and deploy them to the same loader. If a program
|
||||
written for one loader is deployed to a different one the result is usually a
|
||||
`AccessViolation` error due to mismatched deserialization of the program's input
|
||||
parameters.
|
||||
|
||||
For all practical purposes program should always be written to target the latest
|
||||
BPF loader and the latest loader is the default for the command-line interface
|
||||
and the javascript APIs.
|
||||
|
||||
For language specific information about implementing a program for a particular
|
||||
loader see:
|
||||
|
||||
- [Rust program entrypoints](developing-rust.md#program-entrypoint)
|
||||
- [C program entrypoints](developing-c.md#program-entrypoint)
|
||||
|
||||
### Deployment
|
||||
|
||||
SBF program deployment is the process of uploading a BPF shared object into a
|
||||
program account's data and marking the account executable. A client breaks the
|
||||
SBF shared object into smaller pieces and sends them as the instruction data of
|
||||
[`Write`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L13)
|
||||
instructions to the loader where loader writes that data into the program's
|
||||
account data. Once all the pieces are received the client sends a
|
||||
[`Finalize`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L30)
|
||||
instruction to the loader, the loader then validates that the SBF data is valid
|
||||
and marks the program account as _executable_. Once the program account is
|
||||
marked executable, subsequent transactions may issue instructions for that
|
||||
program to process.
|
||||
|
||||
When an instruction is directed at an executable SBF program the loader
|
||||
configures the program's execution environment, serializes the program's input
|
||||
parameters, calls the program's entrypoint, and reports any errors encountered.
|
||||
|
||||
For further information see [deploying](deploying.md)
|
||||
|
||||
### Input Parameter Serialization
|
||||
|
||||
SBF loaders serialize the program input parameters into a byte array that is
|
||||
then passed to the program's entrypoint, where the program is responsible for
|
||||
deserializing it on-chain. One of the changes between the deprecated loader and
|
||||
the current loader is that the input parameters are serialized in a way that
|
||||
results in various parameters falling on aligned offsets within the aligned byte
|
||||
array. This allows deserialization implementations to directly reference the
|
||||
byte array and provide aligned pointers to the program.
|
||||
|
||||
For language specific information about serialization see:
|
||||
|
||||
- [Rust program parameter
|
||||
deserialization](developing-rust.md#parameter-deserialization)
|
||||
- [C program parameter
|
||||
deserialization](developing-c.md#parameter-deserialization)
|
||||
|
||||
The latest loader serializes the program input parameters as follows (all
|
||||
encoding is little endian):
|
||||
|
||||
- 8 bytes unsigned number of accounts
|
||||
- For each account
|
||||
- 1 byte indicating if this is a duplicate account, if not a duplicate then
|
||||
the value is 0xff, otherwise the value is the index of the account it is a
|
||||
duplicate of.
|
||||
- If duplicate: 7 bytes of padding
|
||||
- If not duplicate:
|
||||
- 1 byte boolean, true if account is a signer
|
||||
- 1 byte boolean, true if account is writable
|
||||
- 1 byte boolean, true if account is executable
|
||||
- 4 bytes of padding
|
||||
- 32 bytes of the account public key
|
||||
- 32 bytes of the account's owner public key
|
||||
- 8 bytes unsigned number of lamports owned by the account
|
||||
- 8 bytes unsigned number of bytes of account data
|
||||
- x bytes of account data
|
||||
- 10k bytes of padding, used for realloc
|
||||
- enough padding to align the offset to 8 bytes.
|
||||
- 8 bytes rent epoch
|
||||
- 8 bytes of unsigned number of instruction data
|
||||
- x bytes of instruction data
|
||||
- 32 bytes of the program id
|
||||
Discover many of the [frequently asked questions](./faq.md) other developers have about writing/understanding Solana programs.
|
||||
|
|
|
@ -43,7 +43,7 @@ solana config set --url localhost
|
|||
|
||||
## Create a new Rust library with Cargo
|
||||
|
||||
Solana programs written in Rust are _libraries_ which are compiled to [BPF bytecode](../developing/on-chain-programs/overview#berkeley-packet-filter-bpf) and saved in the `.so` format.
|
||||
Solana programs written in Rust are _libraries_ which are compiled to [BPF bytecode](../developing/on-chain-programs/faq.md#berkeley-packet-filter-bpf) and saved in the `.so` format.
|
||||
|
||||
Initialize a new Rust library named `hello_world` via the Cargo command line:
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ The [validator](#validator) that produces the genesis (first) [block](#block) of
|
|||
|
||||
## BPF loader
|
||||
|
||||
The Solana program that owns and loads [BPF](developing/on-chain-programs/overview#berkeley-packet-filter-bpf) smart contract programs, allowing the program to interface with the runtime.
|
||||
The Solana program that owns and loads [BPF](developing/on-chain-programs/faq#berkeley-packet-filter-bpf) smart contract programs, allowing the program to interface with the runtime.
|
||||
|
||||
## client
|
||||
|
||||
|
@ -259,7 +259,7 @@ See also [rent exempt](#rent-exempt) below. Learn more about rent here: [What is
|
|||
|
||||
## rent exempt
|
||||
|
||||
Accounts that maintain more than 2 years with of rent payments in their account are considered "*rent exempt*" and will not incur the [collection of rent](../src/developing/intro/rent.md#collecting-rent).
|
||||
Accounts that maintain more than 2 years with of rent payments in their account are considered "_rent exempt_" and will not incur the [collection of rent](../src/developing/intro/rent.md#collecting-rent).
|
||||
|
||||
## root
|
||||
|
||||
|
|
Loading…
Reference in New Issue