
Solana Account Data Mapping in Program Execution
When developing Solana programs, you might notice something interesting: you only provide account addresses in your instructions, yet inside your program, you magically have access to all the account data. Let’s dive deep into how this works.
Step 1: Transaction Submission
When you create a transaction, you include two pieces of information:
- The addresses of all accounts your instruction will interact with
- Metadata about these accounts (is it writable? signable?)
Here’s what a typical client-side instruction looks like:
const instruction = new TransactionInstruction({
keys: [
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: accountToRead.publicKey, isSigner: false, isWritable: false },
],
programId: YOUR_PROGRAM_ID,
data: Buffer.from([/* your instruction data */]),
});
Step 2: Pre-execution Account Loading
Before your program’s code starts executing, the SVM performs a preprocessing step. During this phase:
- The runtime identifies all accounts specified in the transaction
- It loads the current state of these accounts from the blockchain
- The account data is cached in memory for quick access
- Necessary runtime checks are performed (ownership, permissions, etc.)
This preprocessing ensures that when your program starts executing, all required data is readily available.
Step 3: Runtime Data Mapping
Once preprocessing is complete, your program receives the account data through its entrypoint. In Rust, this looks like:
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo], // Your account data is available here
instruction_data: &[u8],
) -> ProgramResult {
}
The accounts
parameter contains all the account information, mapped in the same order as specified in your transaction. Each AccountInfo
structure provides:
- Account data
- Owner
- Lamport balance
- Various account flags and metadata
Working with Mapped Accounts Inside your program, you can access the mapped account data easily:
fn process_instruction(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
// Get an iterator for the accounts
let account_iter = &mut accounts.iter();
// Access specific accounts in order
let account_a = next_account_info(account_iter)?;
let account_b = next_account_info(account_iter)?;
// Access account data
let data = account_a.data.borrow();
// Do something with the data...
}