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 significantly 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.
On-chain 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 onchain 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 the SolanaFM Explorer and navigate to the "Verification" tab. View an example of a verified program here.
-
Verification Tools: The Solana Verifiable Build CLI by Ellipsis Labs enables users to independently verify onchain 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 to compile programs into ELF 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. There are currently five loaders:
- native loader:
- Program id:
NativeLoader1111111111111111111111111111111
- Owns the other four loaders
- loader-v1:
- Program id:
BPFLoader1111111111111111111111111111111111
- Management instructions are disabled, but programs still execute
- loader-v2:
- Program id:
BPFLoader2111111111111111111111111111111111
- Instructions
- Management instructions are disabled, but programs still execute
- loader-v3:
- Program id:
BPFLoaderUpgradeab1e11111111111111111111111
- Instructions
- Is being phased out
- loader-v4:
- Program id:
LoaderV411111111111111111111111111111111111
- Instructions
- Will become the standard loader
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.
Precompile Programs
Ed25519 Program
The program for verifying ed25519 signatures. It takes an ed25519 signature, a public key, and a message. Multiple signatures can be verified. If any of the signatures fail to verify, an error is returned.
- Program id:
Ed25519SigVerify111111111111111111111111111
- 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
Verify secp256k1 public key recovery operations (ecrecover).
- Program id:
KeccakSecp256k11111111111111111111111111111
- 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
The program for verifying secp256r1 signatures. It takes a secp256r1 signature, a public key, and a message. Up to 8 signatures can be verified. If any of the signatures fail to verify, an error is returned.
- Program id:
Secp256r1SigVerify1111111111111111111111111
- 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 various core functionalities for the network. Historically these were referred to as "native" programs and they used to be distributed together with the validator code.
- System Program
- Program id:
11111111111111111111111111111111
- Instructions
- Create new accounts, allocate account data, assign accounts to owning programs, transfer lamports from System Program owned accounts and pay transaction fees.
- Vote Program
- Program id:
Vote111111111111111111111111111111111111111
- Instructions
- Create and manage accounts that track validator voting state and rewards.
- Stake Program
- Program id:
Stake11111111111111111111111111111111111111
- Instructions
- Create and manage accounts representing stake and rewards for delegations to validators.
- Config Program
- Program id:
Config1111111111111111111111111111111111111
- Instructions
- 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.
- Compute Budget Program
- Program id:
ComputeBudget111111111111111111111111111111
- Instructions
- Address Lookup Table Program
- Program id:
AddressLookupTab1e1111111111111111111111111
- Instructions
- Zk Token Proof Program
- Program id:
ZkTokenProof1111111111111111111111111111111
- Zk Elgamal Proof Program
- Program id:
ZkE1Gama1Proof11111111111111111111111111111
Is this page helpful?