Programs
On Solana, "smart contracts" are called programs. Programs are deployed on-chain to accounts that contain the program's compiled executable binary. Users interact with programs by sending transactions containing instructions that tell the program what to do.
Key Points
- Programs are accounts containing executable code, organized into functions called instructions.
- While programs are stateless, they can include instructions that create and update other accounts to store data.
- An upgrade authority can update programs. Once this authority is removed, the program becomes immutable.
- Users can verify an on-chain program account's data matches its public source code through verifiable builds.
Writing Solana Programs
Solana programs are predominantly written in the Rust programming language, with two common approaches for development:
-
Anchor: A framework designed for Solana program development. It provides a faster and simpler way to write programs, using Rust macros to reduce boilerplate code. For beginners, it is recommended to start with the Anchor framework.
-
Native Rust: This approach involves writing Solana programs in Rust without leveraging any frameworks. It offers more flexibility but comes with increased complexity.
Updating Solana Programs
To learn more about deploying and upgrading programs, see the deploying programs page.
Programs can be
directly modified
by an account designated as the "upgrade authority", which is typically the
account that originally deployed the program. If the
upgrade authority
is revoked and set to None
, the program becomes immutable and can no longer be
updated.
Verifiable Programs
Verifiable builds allow anyone to check if a program's on-chain code matches its public source code, making it possible to detect discrepancies between source and deployed versions.
The Solana developer community has introduced tools to support verifiable builds, enabling both developers and users to verify that on-chain programs accurately reflect their publicly shared source code.
-
Searching for Verified Programs: To quickly check for verified programs, users can search for a program address on Solana Explorer. View an example of a verified program here.
-
Verification Tools: The Solana Verifiable Build CLI by Ellipsis Labs enables users to independently verify on-chain programs against published source code.
-
Support for Verifiable Builds in Anchor: Anchor provides built-in support for verifiable builds. Details can be found in the Anchor documentation.
Berkeley Packet Filter (BPF)
Solana uses LLVM (Low Level Virtual Machine) to compile programs into ELF (Executable and Linkable Format) files. These files contain Solana's custom version of eBPF bytecode, called "Solana Bytecode Format" (sBPF). The ELF file contains the program's binary and is stored on-chain in an executable account when the program is deployed.
Built-in Programs
Loader Programs
Every program itself is owned by another program, which is its loader. Currently, five loaders programs exist:
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 | Is being phased out | Instructions |
v4 | LoaderV411111111111111111111111111111111111 | v4 is expected to become the standard loader | Instructions |
These loaders are necessary to create and manage custom programs:
- Deploy a new program or buffer
- Close a program or buffer
- Redeploy / upgrade an existing program
- Transfer the authority over a program
- Finalize a program
Loader-v3 and loader-v4 support modifications to programs after their initial deployment. Permission to do so is regulated by the authority of a program because the account ownership of each program resides with the loader.
Precompiled Programs
Ed25519 Program
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 first u8
is a count of the
number of signatures to check, which is followed by a single byte padding. After
that, the following struct is serialized, one for each signature to check.
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}
The pseudo code of the signature verification:
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}
Secp256k1 Program
Program | Program ID | Description | Instructions |
---|---|---|---|
Secp256k1 Program | KeccakSecp256k11111111111111111111111111111 | Verifies secp256k1 public key recovery operations (ecrecover). | Instructions |
The secp256k1 program processes an instruction which takes in as the first byte a count of the following struct serialized in 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}
The pseudo code of the recovery verification:
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.
Secp256r1 Program
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 first u8
is a count of the
number of signatures to check, followed by a single byte padding. After that,
the following struct is serialized, one for each signature to check:
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}
The pseudo code of the signature verification:
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}
Note: Low S values are enforced for all signatures to avoid accidental signature malleability.
Core Programs
The Solana cluster genesis includes a list of special programs that provide core functionalities for the network. Historically these were referred to as "native" programs and they used to be distributed together with the validator code.
Program | Program ID | Description | Instructions |
---|---|---|---|
System Program | 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 Program | Vote111111111111111111111111111111111111111 | Create and manage accounts that track validator voting state and rewards. | VoteInstruction |
Stake Program | Stake11111111111111111111111111111111111111 | Create and manage accounts representing stake and rewards for delegations to validators. | StakeInstruction |
Config Program | 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 to store inside of it. | ConfigInstruction |
Compute Budget Program | ComputeBudget111111111111111111111111111111 | Set compute unit limits and prices for transactions, allowing users to control compute resources and prioritization fees. | ComputeBudgetInstruction |
Address Lookup Table Program | 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 Program | ZkE1Gama1Proof11111111111111111111111111111 | Provides zero-knowledge proof verification for ElGamal-encrypted data. | — |
Is this page helpful?