Solana Account Model

On Solana, all data is stored in what are called "accounts." You can think of data on Solana as a public database with a single "Accounts" table, where each entry in this table is an "account." Every Solana account shares the same base Account type.

AccountsAccounts

Key Points

  • Accounts can store up to 10MiB of data, which contains either executable program code or program state.
  • Accounts require a rent deposit in lamports (SOL) that's proportional to the amount of data stored, and you can fully recover it when you close the account.
  • Every account has a program owner. Only the program that owns an account can change its data or deduct its lamport balance. But anyone can increase the balance.
  • Sysvar accounts are special accounts that store network cluster state.
  • Program accounts store the executable code of smart contracts.
  • Data accounts are created by programs to store and manage program state.

Account

Every account on Solana has a unique 32-byte address, often shown as a base58 encoded string (e.g. 14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5).

The relationship between the account and its address works like a key-value pair, where the address is the key to locate the corresponding on-chain data of the account. The account address acts as the "unique ID" for each entry in the "Accounts" table.

Account AddressAccount Address

Most Solana accounts use an Ed25519 public key as their address.

Generate Keypair
import { Keypair } from "@solana/web3.js";
const keypair = Keypair.generate();
console.log(`Public Key: ${keypair.publicKey}`);
console.log(`Secret Key: ${keypair.secretKey}`);

Click 'Run' to see output.
Program Logs in the Output are clickable links to Solana Explorer.
You must enable the "Enable Custom URL Param" setting on Solana Explorer.
If not enabled, links will default to localhost:8899 instead of the Mirror.ad RPC URL.

While public keys are commonly used as account addresses, Solana also supports a feature called Program Derived Addresses (PDAs). PDAs are special addresses that you can deterministically derive from a program ID and optional inputs (seeds). The details are on the Program Derived Address page.

import { PublicKey } from "@solana/web3.js";
const programAddress = new PublicKey("11111111111111111111111111111111");
const seeds = [Buffer.from("helloWorld")];
const [pda, bump] = await PublicKey.findProgramAddressSync(
seeds,
programAddress
);
console.log(`PDA: ${pda}`);
console.log(`Bump: ${bump}`);

Click 'Run' to see output.
Program Logs in the Output are clickable links to Solana Explorer.
You must enable the "Enable Custom URL Param" setting on Solana Explorer.
If not enabled, links will default to localhost:8899 instead of the Mirror.ad RPC URL.

Account Type

Accounts have a max size of 10MiB and every account on Solana shares the same base Account type.

Account TypeAccount Type

Every Account on Solana has the following fields:

  • data: A byte array that stores arbitrary data for an account. For non-executable accounts, this often stores state that's meant be read from. For program accounts (smart contracts), this contains the executable program code. The data field is commonly called "account data."
  • executable: This flag shows if an account is a program.
  • lamports: The account's balance in lamports, the smallest unit of SOL (1 SOL = 1 billion lamports).
  • owner: The program ID (public key) of the program that owns this account. Only the owner program can change the account's data or deduct its lamports balance.
  • rent_epoch: A legacy field from when Solana had a mechanism that periodically deducted lamports from accounts. While this field still exists in the Account type, it is no longer used since rent collection was deprecated.
Base Account Type
pub struct Account {
/// lamports in the account
pub lamports: u64,
/// data held in this account
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
pub data: Vec<u8>,
/// the program that owns this account. If executable, the program that loads this account.
pub owner: Pubkey,
/// this account's data contains a loaded program (and is now read-only)
pub executable: bool,
/// the epoch at which this account will next owe rent
pub rent_epoch: Epoch,
}
Fetch Account
import { Keypair, Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";
const keypair = Keypair.generate();
console.log(`Public Key: ${keypair.publicKey}`);
const connection = new Connection("http://localhost:8899", "confirmed");
// Funding an address with SOL automatically creates an account
const signature = await connection.requestAirdrop(
keypair.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(signature, "confirmed");
const accountInfo = await connection.getAccountInfo(keypair.publicKey);
console.log(accountInfo);

Click 'Run' to see output.
Program Logs in the Output are clickable links to Solana Explorer.
You must enable the "Enable Custom URL Param" setting on Solana Explorer.
If not enabled, links will default to localhost:8899 instead of the Mirror.ad RPC URL.

Rent

To store data on-chain, accounts must also keep a lamport (SOL) balance that's proportional to the amount of data stored on the account (in bytes). This balance is called "rent," but it works more like a deposit because you can recover the full amount when you close an account. You can find the calculation here using these constants.

The term "rent" comes from a deprecated mechanism that regularly deducted lamports from accounts that fell below the rent threshold. This mechanism isn't active anymore.

Program Owner

On Solana, "smart contracts" are called programs. Program ownership is a key part of the Solana Account Model. Every account has a designated program as its owner. Only the owner program can:

  • Change the account's data field
  • Deduct lamports from the account's balance

System Program

By default, all new accounts are owned to the System Program. The System Program does a few key things:

  • New Account Creation: Only the System Program can create new accounts.
  • Space Allocation: Sets the byte capacity for the data field of each account.
  • Transfer / 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.

All "wallet" accounts on Solana are just accounts owned by the System Program. The lamport balance in these accounts shows the amount of SOL owned by the wallet. Only accounts owned by the System Program can pay transaction fees.

System AccountSystem Account

Sysvar Accounts

Sysvar accounts are special accounts at predefined addresses that provide access to cluster state data. These accounts update dynamically with data about the network cluster. You can find the full list of Sysvar Accounts here.

Fetch Sysvar Clock Account
import { Connection, SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
const connection = new Connection("http://localhost:8899", "confirmed");
const accountInfo = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);
console.log(JSON.stringify(accountInfo, null, 2));

Click 'Run' to see output.
Program Logs in the Output are clickable links to Solana Explorer.
You must enable the "Enable Custom URL Param" setting on Solana Explorer.
If not enabled, links will default to localhost:8899 instead of the Mirror.ad RPC URL.

Program Account

Deploying a Solana program creates an executable program account. The program account stores the executable code of the program.

Program accounts are owned by a Loader Program.

Program AccountProgram Account

For simplicity, you can treat the program account as the program itself. When you invoke a program's instructions, you specify the program account's address (commonly called the "Program ID").

Fetch Token Program Account
import { Connection, PublicKey } from "@solana/web3.js";
const connection = new Connection("http://localhost:8899", "confirmed");
const accountInfo = await connection.getAccountInfo(
new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
);
console.log(accountInfo);

Click 'Run' to see output.
Program Logs in the Output are clickable links to Solana Explorer.
You must enable the "Enable Custom URL Param" setting on Solana Explorer.
If not enabled, links will default to localhost:8899 instead of the Mirror.ad RPC URL.

When you deploy a Solana program, it's stored in a program account. Program accounts are owned by a Loader Program. There are several versions of the loader, but all except loader-v3 store the executable code directly in the program account. Loader-v3 stores the executable code in a separate "program data account" and the program account just points to it. When you deploy a new program, the Solana CLI uses the latest loader version by default.

Buffer Account

Loader-v3 has a special account type for temporarily staging the upload of a program during deployment or redeployment/upgrades. In loader-v4, there are still buffers, but they're just normal program accounts.

Program Data Account

Loader-v3 works differently from all other BPF Loader programs. The program account only contains the address of a program data account, which stores the actual executable code: Program Data AccountProgram Data Account

Don't confuse these program data accounts with the data accounts of programs (see below).

Data Account

On Solana, the executable code of a program is stored in a different account than the program's state. This is like how operating systems typically have separate files for programs and their data.

To maintain state, programs define instructions to create separate accounts that they own. Each of these accounts has its own unique address and can store any arbitrary data defined by the program.

Data AccountData Account

Note that only the System Program can create new accounts. Once the System Program creates an account, it can then transfer or assign ownership of the new account to another program.

In other words, creating a data account for a custom program takes two steps:

  1. Invoke the System Program to create an account, then transfer ownership to the custom program
  2. Invoke the custom program, which now owns the account, to initialize the account data as defined by the program's instruction

This account creation process is often abstracted as a single step, but it's helpful to understand the underlying process.

Create Token Mint Account
import {
Connection,
Keypair,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
import {
createInitializeMintInstruction,
TOKEN_2022_PROGRAM_ID,
MINT_SIZE,
getMinimumBalanceForRentExemptMint
} from "@solana/spl-token";
// Create connection to local validator
const connection = new Connection("http://localhost:8899", "confirmed");
const recentBlockhash = await connection.getLatestBlockhash();
// Generate a new keypair for the fee payer
const feePayer = Keypair.generate();
// Airdrop 1 SOL to fee payer
const airdropSignature = await connection.requestAirdrop(
feePayer.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction({
blockhash: recentBlockhash.blockhash,
lastValidBlockHeight: recentBlockhash.lastValidBlockHeight,
signature: airdropSignature
});
// Generate keypair to use as address of mint
const mint = Keypair.generate();
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: mint.publicKey,
space: MINT_SIZE,
lamports: await getMinimumBalanceForRentExemptMint(connection),
programId: TOKEN_2022_PROGRAM_ID
});
const initializeMintInstruction = createInitializeMintInstruction(
mint.publicKey, // mint pubkey
9, // decimals
feePayer.publicKey, // mint authority
feePayer.publicKey, // freeze authority
TOKEN_2022_PROGRAM_ID
);
const transaction = new Transaction().add(
createAccountInstruction,
initializeMintInstruction
);
const transactionSignature = await sendAndConfirmTransaction(
connection,
transaction,
[feePayer, mint] // Signers
);
console.log("Mint Address: ", mint.publicKey.toBase58());
console.log("Transaction Signature: ", transactionSignature);
const accountInfo = await connection.getAccountInfo(mint.publicKey);
console.log(accountInfo);

Click 'Run' to see output.
Program Logs in the Output are clickable links to Solana Explorer.
You must enable the "Enable Custom URL Param" setting on Solana Explorer.
If not enabled, links will default to localhost:8899 instead of the Mirror.ad RPC URL.

Is this page helpful?

Spis treści

Edytuj stronę