Skip to main content

Module lazy

Module lazy 

Source
Expand description

Lazy account parser – on-demand account deserialization.

The standard entrypoint parses every account upfront, burning CU even for accounts the instruction never touches. The lazy parser gives you instruction data and program ID immediately, then hands back an iterator that parses accounts one at a time ON DEMAND.

Hopper’s lazy path is distinct not because Pinocchio lacks lazy parsing, but because Hopper preserves canonical duplicate-account handling and keeps instruction_data() / program_id() available at any time – even before a single account is consumed. Pinocchio’s lazy entrypoint, by contrast, errors (InvalidInstructionData) if you read instruction data before draining every account, because it locates the tail purely by where the account cursor lands. Hopper instead runs a memoized skip-walk to the instruction tail the first time instruction_data() / program_id() is requested, then caches it. If a program never asks for the tail, the walk never runs; if it consumes k accounts first, only the remaining records are walked. There is no upfront pre-scan and no zero-fill of the resolved-account array – both were pure overhead the pre-fusion shape paid on every invocation.

§CU Savings

Programs that dispatch on instruction_data[0] and only need a subset of accounts save measurable CU. A vault program that routes 8 instruction variants through a single entrypoint might only parse 2-3 of 10 accounts for a given variant.

§Usage

ⓘ
use hopper_native::lazy::LazyContext;
use hopper_native::hopper_lazy_entrypoint;

hopper_lazy_entrypoint!(process);

fn process(ctx: LazyContext) -> ProgramResult {
    let disc = ctx.instruction_data().first().copied().unwrap_or(0);
    match disc {
        0 => {
            let payer = ctx.next_account()?;
            let vault = ctx.next_account()?;
            // Remaining accounts are never parsed.
            do_deposit(payer, vault, &ctx.instruction_data()[1..])
        }
        _ => Err(ProgramError::InvalidInstructionData),
    }
}

Structs§

LazyContext
Pre-parsed header from the BPF input buffer: a cursor positioned at the first account, plus enough state to locate instruction data + program ID on demand.

Functions§

lazy_deserialize⚠
Deserialize a BPF input buffer into a LazyContext.