Solana Internals Part 1
What Are the Native On-Chain Programs and Why Do They Matter?
December 31, 2021

Solana has a few built-in (native on-chain) programs (e.g., system_program, spl_token, stake, vote, ed25519, etc) that provide essential instructions and are generally trusted.

In this article, we introduce the internals of these programs, and highlight some of the intricacies.

A List of Native Solana Programs

Every Solana program (including both native and user-deployed smart contracts) has a unique program_id, which corresponds to the program’s pubkey.

Following is a list of native Solana programs with their corresponding program_ids

Native Solana Program Program ID
system_program 11111111111111111111111111111111
stake Stake11111111111111111111111111111111111111
vote Vote111111111111111111111111111111111111111
config Config1111111111111111111111111111111111111
BPFLoaderUpgradeab1e BPFLoaderUpgradeab1e11111111111111111111111
Ed25519 Ed25519SigVerify111111111111111111111111111
Secp256k1 KeccakSecp256k11111111111111111111111111111

In addition, spl_token and spl_associated_token_account are official Solana programs that are also frequently used, so we consider them as well:

Official Solana Program Program ID
spl_token TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
spl_associated_token_account ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL

Cross Program Invocation

When a program invokes another program, the callee’s program_id will be supplied to the call, typically through one of the following two functions:

  • solana_program::program::invoke
  • solana_program::program::invoke_signed

Note: internally, invoke calls invoke_signed without signer_seeds.

The program_id is the first parameter of instruction, as defined below:

Inside invoke and invoke_signed , RefCell checking is performed first to ensure that the account RefCells are consistent with the request:

The RefCell checking can be compute unit expensive due to nested loops.

To avoid that expense, dapps may choose to use invoke_unchecked and invoke_signed_unchecked, the unchecked version of invoke and invoke_signed respectively, which do not check RefCells. However, use invoke_unchecked and invoke_signed_unchecked at your own risk: only when you are certain that the accounts used in instruction are consistent with those in the account_infos.

The Solana Native Loader and BPF Loaders

In Solana, every account including Solana programs has an owner. When a Solana program is invoked in a cross program invocation, its owner is used to process the instruction (invoke or invoke_signed). For Solana programs, their owners are either the native loader or a BPF loader.

The native loader (NativeLoader1111111111111111111111111111111) is a special program that is the owner of most native Solana programs (those program_ids ended with 111111111111111111111111111).

When a native Solana program is invoked in a cross program invocation, the native loader is used to load the native program into the Solana runtime and process the instruction.

The native loader is also the owner of three BPF loaders:

  • BPFLoaderUpgradeab1e (the upgradeable Solana BPF loader. The upgradeable BPF loader is responsible for deploying, upgrading, and executing BPF programs.)
  • BPFLoader2 (The latest Solana BPF loader. The BPF loader is responsible for loading, finalizing, and executing BPF programs.)
  • BPFLoader (The original and now deprecated Solana BPF loader)

Most Solana smart contracts use Upgradeable BPF Loader to deploy the program, so their owner is BPFLoaderUpgradeab1e and they can be upgraded (by an upgrade authority set at the program deployment time).

Some Solana programs are immutable, as they are loaded by BPFLoader2 or BPFLoader.

For example, the SPL Token spl_token and the Associated Token spl_associated_token_account programs are loaded by BPFLoader2, and they are immutable.

The system_program Program

The System Program is probably the most frequently invoked program, often called with the following two instructions:

  • system_instruction::create_account
  • system_instruction::transfer

The System Program provides several important functionalities:

  1. create new accounts
  2. allocate account data
  3. assign accounts to owning programs
  4. transfer lamports from System Program owned accounts
  5. pay transaction fees.

The System Program is the owner of all wallet accounts.

Note: only the owner of an account has write access to the account. If an account is not owned by a program, the program is only permitted to read its data and credit the account (but not debit the account).

The System Program is also the default owner of an account when the account is created by create_account. It is then allowed to transfer lamports and importantly assign account ownership, i.e., changing owner to a different program id.

The spl_token Program

The SPL Token Program provides functions for creating and managing tokens (including both fungible and non-fungible tokens, i.e. NFTs).

spl_token is commonly used to create new tokens, mint, burn, and distribute to users. The following instructions are frequently used in Solana smart contracts:

  • Create a token account: spl_token::instruction::initialize_account
  • Create a token mint: spl_token::instruction::initialize_mint
  • Mint new tokens to an account: spl_token::instruction::mint_to
  • Transfers tokens from one account to another: spl_token::instruction::transfer
  • Burns tokens by removing them from an account: spl_token::instruction::burn
  • Approves a delegate: spl_token::instruction::approve

The spl_associated_token_account Program

The Associated Token Program allows a user to create a main token account for each token they own. Internally, it maps the user’s wallet address to a unique associated token account for each token mint.

Specifically, to create an associated token account for the given wallet address and token mint: create_associated_token_account

The stake Program

The Stake Program is used to create and manage accounts representing stake and rewards for validators or their delegators.

The following instructions are often used:

  • Initialize a stake with lockup and authorization information: stake::instruction::initialize
  • Authorize a key to manage stake or withdrawal: stake::instruction::authorize
  • Withdraw unstaked lamports from the stake account: stake::instruction::withdraw
  • Set stake lockup: stake::instruction::set_lockup
  • Deactivates the stake in the account: stake::instruction::deactivate_stake
  • Merge two stake accounts: stake::instruction::merge
  • Split stake off a stake account into another stake account: stake::instruction::split
  • Delegate a stake to a particular vote account: stake::instruction::delegate_stake

The vote Program

The Vote Program is used to create and manage accounts that track validator voting state and rewards.

The config Program

The Config Program is used to add configuration data to the chain including the list of public keys that are permitted to modify the data.

vote and config are primarily used by Solana validators, so we omit details here.

The ed25519 Signature Verify Program

The Ed25519 Signature Verify Program takes an ed25519 signature, public key, and message, and is used to verify if the message is signed by the (corresponding secret) private key.

By default, signatures are verified in parallel using all available CPU cores. When perf-libs are available signature verification is offloaded to the GPU.

Multiple signatures can be verified. If any of the signatures fail to verify, an error is returned.

The secp256k1 Recover Program

The Secp256k1 Recover Program is used to recover Secp256k1 public key from a signed message (ecrecover). It is added to support Ethereum / Solana bridge.

Secp256k1 is the name of the elliptic curve used by popular blockchains (e.g., Bitcoin, Ethereum) to implement public key cryptography. All points on this curve are valid public keys.

Both Ed25519 and Secp256k1 programs are precompiled in Solana to maximize performance.

From A Security Perspective

It should be noted that although these native programs are generally trustworthy and (mostly) stable, to ensure security it is important to understand their assumptions and use instructions in their expected way.

We use a security case of the SPL Token program to illustrate this point.

Before spl-token v3.1.1 (released on 2021–05–18), there was a vulnerability in the token instruction code that allows invoking an arbitrary program (instead of the real spl-token program). The fixes are in this commit.

The fixes add check_program_account in all the token instruction functions to ensure the user-provided token_program_id is the same as the spl-token program_id TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.

The check_program_account function is shown below:

The root cause of this vulnerability lies in an inconsistent assumption between the expected usages of the spl-token program and its potential usages.

Therefore, to avoid such vulnerabilities (thus attacks) in general, it is important to

  • check the expected usages of these native programs
  • add necessary user checks, and
  • always use the bug-fixed versions (e.g., spl-token v3.1.1 and above).

About sec3 (Formerly Soteria)

sec3 is a security research firm that prepares Solana projects for millions of users. sec3’s Launch Audit is a rigorous, researcher-led code examination that investigates and certifies mainnet-grade smart contracts; sec3’s continuous auditing software platform, X-ray, integrates with GitHub to progressively scan pull requests, helping projects fortify code before deployment; and sec3’s post-deployment security solution, WatchTower, ensures funds stay safe. sec3 is building technology-based scalable solutions for Web3 projects to ensure protocols stay safe as they scale.

To learn more about sec3, please visit https://www.sec3.dev