Programs
On Solana, a smart contract is called a program. A program is a stateless account that contains executable code. This code is organized into functions called instructions. Users interact with a program by sending a transaction containing one or more instructions. A transaction can include instructions from multiple programs.
When a program is deployed, Solana uses LLVM to compile it into executable and linkable format (ELF). The ELF file contains the program's binary in Solana Bytecode Format (sBPF) and is saved on-chain in an executable account.
sBPF is Solana's custom version of eBPF bytecode.
Write programs
The majority of programs are written in Rust, with two common development approaches:
- Anchor: Anchor is a framework designed for fast and easy Solana development. It uses Rust macros to reduce boilerplate code—making it great for beginners.
- Native Rust: Write programs in Rust without leveraging any frameworks. This approach offers more flexibility but comes with increased complexity.
Update programs
To modify
an existing program, an account must be designated as the upgrade authority.
(Typically the same account that originally deployed the program.)
If the upgrade authority is revoked and set to None, the program can no longer be updated.
Verify programs
Solana supports verifiable builds, which allow users to check whether a program's on-chain code matches its public source code. The Anchor framework provides built-in support for creating a verifiable build.
To check whether an existing program is verified, search for its program ID on the Solana Explorer. Alternatively, you may use the Ellipsis Labs Solana Verifiable Build CLI, to independently verify on-chain programs.
Built-in programs
The System Program
The System Program is the only account that can create new accounts. By default, all new accounts are owned by the System Program, although many are assigned a new owner upon creation. The System Program performs the following key functions:
| Function | Description |
|---|---|
| New Account Creation | Only the System Program can create new accounts. |
| Space Allocation | Sets the byte capacity for the data field of each account. |
| Assign Program Ownership | Once the System Program creates an account, it can reassign the designated program owner to a different program account. That's how custom programs take ownership of new accounts created by the System Program. |
| Transfer SOL | Transfers lamports (SOL) from System Accounts to other accounts. |
The address of the system program is 11111111111111111111111111111111.
Loader programs
Every program is owned by another—its loader. Loaders are used to deploy, redeploy, upgrade or close programs. They are also used to finalize a program and transfer program authority.
Loader programs are sometimes referred to as, 'BPF Loaders'.
There are currently five loader programs, as shown in the table below.
| Loader | Program ID | Notes | Instructions Link |
|---|---|---|---|
| native | NativeLoader1111111111111111111111111111111 | Owns the other four loaders | — |
| v1 | BPFLoader1111111111111111111111111111111111 | Management instructions are disabled, but programs still execute | — |
| v2 | BPFLoader2111111111111111111111111111111111 | Management instructions are disabled, but programs still execute | Instructions |
| v3 | BPFLoaderUpgradeab1e11111111111111111111111 | Programs can be updated after deployment. Program executable is stored in a separate program data account | Instructions |
| v4 | LoaderV411111111111111111111111111111111111 | In development (unreleased) | Instructions |
Programs deployed with loader-v3 or loader-v4 may be modifiable after deployment, as determined by its upgrade authority.
When a new program is deployed, the latest loader version will be used by default.
Precompiled programs
In addition to the loader programs, Solana provides the following precompiled programs.
Verify ed25519 signature
The ed25519 program is used to verify one or more ed25519 signatures.
| Program | Program ID | Description | Instructions |
|---|---|---|---|
| Ed25519 Program | Ed25519SigVerify111111111111111111111111111 | Verifies ed25519 signatures. If any signature fails, an error is returned. | Instructions |
The ed25519 program processes an instruction.
The instruction's first u8 contains a count of the number of signatures to be checked,
followed by a single byte padding.
After that, the following struct is serialized, one for each signature to be checked.
struct Ed25519SignatureOffsets {signature_offset: u16, // offset to ed25519 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to public key of 32 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionsinstruction_index = ed25519_signature_instruction_index != u16::MAX ? ed25519_signature_instruction_index : current_instruction;signature = instructions[instruction_index].data[ed25519_signature_offset..ed25519_signature_offset + 64]instruction_index = ed25519_pubkey_instruction_index != u16::MAX ? ed25519_pubkey_instruction_index : current_instruction;pubkey = instructions[instruction_index].data[ed25519_pubkey_offset..ed25519_pubkey_offset + 32]instruction_index = ed25519_message_instruction_index != u16::MAX ? ed25519_message_instruction_index : current_instruction;message = instructions[instruction_index].data[ed25519_message_data_offset..ed25519_message_data_offset + ed25519_message_data_size]if pubkey.verify(signature, message) != Success {return Error}}return Success}
Verify secp256k1 recovery
The secp256k1 program is used to verify secp256k1 public key recovery operations.
| Program | Program ID | Description | Instructions |
|---|---|---|---|
| Secp256k1 Program | KeccakSecp256k11111111111111111111111111111 | Verifies secp256k1 public key recovery operations (ecrecover). | Instructions |
The secp256k1 program processes an instruction. The instruction's first byte contains a count of the number of public keys to be checked. After that, the following struct is created once for each public key, then serialized and added to the instruction data.
struct Secp256k1SignatureOffsets {secp_signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytessecp_signature_instruction_index: u8, // instruction index to find signaturesecp_pubkey_offset: u16, // offset to ethereum_address pubkey of 20 bytessecp_pubkey_instruction_index: u8, // instruction index to find pubkeysecp_message_data_offset: u16, // offset to start of message datasecp_message_data_size: u16, // size of message datasecp_message_instruction_index: u8, // instruction index to find message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionssignature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64]recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64]ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 20]message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size])pubkey = ecrecover(signature, recovery_id, message_hash)eth_pubkey = keccak256(pubkey[1..])[12..]if eth_pubkey != ref_eth_pubkey {return Error}}return Success}
This allows the user to specify any instruction data in the transaction for signature and message data. By specifying a special instructions sysvar, one can also receive data from the transaction itself.
Cost of the transaction will count the number of signatures to verify multiplied by the signature cost verify multiplier.
The secp256r1 program is used to verify up to 8 secp256r1 signatures.
| Program | Program ID | Description | Instructions |
|---|---|---|---|
| Secp256r1 Program | Secp256r1SigVerify1111111111111111111111111 | Verifies up to 8 secp256r1 signatures. Takes a signature, public key, and message. Returns error if any fail. | Instructions |
The secp256r1 program processes an instruction.
The instruction's first u8 is a count of the number of signatures to be checked,
followed by a single byte padding.
After that, the following struct is created for each signature,
then serialized and added to the instruction data.
struct Secp256r1SignatureOffsets {signature_offset: u16, // offset to compact secp256r1 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to compressed public key of 33 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
Low S values are enforced for all signatures to avoid accidental signature malleability.
process_instruction() {if data.len() < SIGNATURE_OFFSETS_START {return Error}num_signatures = data[0] as usizeif num_signatures == 0 || num_signatures > 8 {return Error}expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_STARTif data.len() < expected_data_size {return Error}for i in 0..num_signatures {offsets = parse_signature_offsets(data, i)signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)if s > half_curve_order {return Error}pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)if !verify_signature(signature, pubkey, message) {return Error}}return Success}
Core programs
The programs in the list below provide the network's core functionality.
| Program | Program ID | Description | Instructions |
|---|---|---|---|
| System | 11111111111111111111111111111111 | Create new accounts, allocate account data, assign accounts to owning programs, transfer lamports from System Program-owned accounts, and pay transaction fees | SystemInstruction |
| Vote | Vote111111111111111111111111111111111111111 | Create and manage accounts that track validator voting state and rewards | VoteInstruction |
| Stake | Stake11111111111111111111111111111111111111 | Create and manage accounts representing stake and rewards for delegations to validators | StakeInstruction |
| Config | Config1111111111111111111111111111111111111 | Add configuration data to the chain, followed by the list of public keys that are allowed to modify it. Unlike the other programs, the Config program does not define any individual instructions. It has just one implicit instruction: "store". Its instruction data is a set of keys that gate access to the account and the data stored inside of it | ConfigInstruction |
| Compute Budget | ComputeBudget111111111111111111111111111111 | Set compute unit limits and prices for transactions, allowing users to control compute resources and prioritization fees | ComputeBudgetInstruction |
| Address Lookup Table | AddressLookupTab1e1111111111111111111111111 | Manage address lookup tables, which allow transactions to reference more accounts than would otherwise fit in the transaction's account list | ProgramInstruction |
| ZK ElGamal Proof | ZkE1Gama1Proof11111111111111111111111111111 | Provides zero-knowledge proof verification for ElGamal-encrypted data | — |
Is this page helpful?