pub struct Context<'a> {
pub program_id: &'a Address,
pub instruction_data: &'a [u8],
/* private fields */
}Expand description
Execution context for a Hopper instruction handler.
Wraps the program_id, account slice, and instruction data into a single object with structured access patterns.
§Authored flow
pub fn deposit(ctx: &Context, amount: u64) -> ProgramResult {
let authority = ctx.account(0)?;
let vault = ctx.account(1)?;
authority.require_signer()?;
vault.require_writable()?;
vault.check_disc(1)?;
let mut state = vault.load_mut::<VaultState>()?;
state.balance = state.balance.checked_add(amount).ok_or(ProgramError::ArithmeticOverflow)?;
Ok(())
}Fields§
§program_id: &'a AddressThe program’s own address.
instruction_data: &'a [u8]Raw instruction data (past the discriminator byte, if applicable).
Implementations§
Source§impl<'a> Context<'a>
impl<'a> Context<'a>
Sourcepub fn new(
program_id: &'a Address,
accounts: &'a [AccountView],
instruction_data: &'a [u8],
) -> Self
pub fn new( program_id: &'a Address, accounts: &'a [AccountView], instruction_data: &'a [u8], ) -> Self
Create a new context from the entrypoint parameters.
Sourcepub fn program_id(&self) -> &Address
pub fn program_id(&self) -> &Address
Program ID.
Sourcepub fn instruction_data(&self) -> &'a [u8]
pub fn instruction_data(&self) -> &'a [u8]
Raw instruction data.
Sourcepub fn account(&self, index: usize) -> Result<&AccountView, ProgramError>
pub fn account(&self, index: usize) -> Result<&AccountView, ProgramError>
Get an account by index.
Sourcepub fn account_mut(&self, index: usize) -> Result<&AccountView, ProgramError>
pub fn account_mut(&self, index: usize) -> Result<&AccountView, ProgramError>
Get an account by index (mutation-intent variant).
Functionally identical to account() since AccountView uses
interior mutability for data access (overlay_mut, load_mut,
try_borrow_mut). The distinct name signals that the caller
intends to write through the returned reference.
Sourcepub fn num_accounts(&self) -> usize
pub fn num_accounts(&self) -> usize
Get the total number of accounts.
Sourcepub fn accounts(&self) -> &[AccountView]
pub fn accounts(&self) -> &[AccountView]
Get all accounts as a slice.
Sourcepub fn borrows(&self) -> &SegmentBorrowRegistry
pub fn borrows(&self) -> &SegmentBorrowRegistry
Access the instruction-scoped segment borrow registry.
Sourcepub fn borrows_mut(&mut self) -> &mut SegmentBorrowRegistry
pub fn borrows_mut(&mut self) -> &mut SegmentBorrowRegistry
Mutably access the instruction-scoped segment borrow registry.
Sourcepub fn audit_accounts(&self) -> AccountAudit<'a>
pub fn audit_accounts(&self) -> AccountAudit<'a>
Inspect the instruction account slice for duplicate aliases.
Sourcepub fn remaining_accounts(&self, from: usize) -> &[AccountView]
pub fn remaining_accounts(&self, from: usize) -> &[AccountView]
Get the remaining accounts starting at from.
Sourcepub fn require_accounts(&self, n: usize) -> ProgramResult
pub fn require_accounts(&self, n: usize) -> ProgramResult
Require at least n accounts are present.
Sourcepub fn require_unique_accounts(&self) -> ProgramResult
pub fn require_unique_accounts(&self) -> ProgramResult
Require all account addresses to be unique.
Sourcepub fn require_unique_writable_accounts(&self) -> ProgramResult
pub fn require_unique_writable_accounts(&self) -> ProgramResult
Require that no duplicated account is writable in this instruction.
Sourcepub fn require_unique_signer_accounts(&self) -> ProgramResult
pub fn require_unique_signer_accounts(&self) -> ProgramResult
Require that no duplicated account is used as a signer role.
Sourcepub fn require_data_len(&self, n: usize) -> ProgramResult
pub fn require_data_len(&self, n: usize) -> ProgramResult
Require at least n bytes of instruction data.
Sourcepub fn load<T: LayoutContract>(
&self,
index: usize,
) -> Result<Ref<'_, T>, ProgramError>
pub fn load<T: LayoutContract>( &self, index: usize, ) -> Result<Ref<'_, T>, ProgramError>
Validate-and-load the full typed layout for an account.
This is the indexed shortcut for ctx.account(idx)?.load::<T>().
It’s the canonical “Tier A” access path: the runtime checks the
Hopper header, validates the data length, and projects the typed
view in one inlined call. no extra cost over the spelled-out form.
Sourcepub fn load_mut<T: LayoutContract>(
&self,
index: usize,
) -> Result<RefMut<'_, T>, ProgramError>
pub fn load_mut<T: LayoutContract>( &self, index: usize, ) -> Result<RefMut<'_, T>, ProgramError>
Validate-and-load a mutable typed layout for an account.
Indexed shortcut for ctx.account(idx)?.load_mut::<T>(). The
returned guard holds the account-level exclusive borrow until
it drops.
Sourcepub fn load_cross_program<T: LayoutContract>(
&self,
index: usize,
) -> Result<Ref<'_, T>, ProgramError>
pub fn load_cross_program<T: LayoutContract>( &self, index: usize, ) -> Result<Ref<'_, T>, ProgramError>
Cross-program load: validate ABI fingerprint without ownership check.
Use this when reading an account whose owner is another program but whose layout is published as a Hopper layout contract.
Sourcepub fn segment_ref<'b, T: Pod>(
&'b mut self,
index: usize,
abs_offset: u32,
) -> Result<SegRef<'b, T>, ProgramError>
pub fn segment_ref<'b, T: Pod>( &'b mut self, index: usize, abs_offset: u32, ) -> Result<SegRef<'b, T>, ProgramError>
Register a read borrow for a segment of an account and return a
SegRef<T> that releases both the account-level
byte guard and the segment registry lease on drop.
index is the account index. abs_offset is the absolute byte
offset within the account data (including header bytes).
§Type Safety
T must implement Pod (substrate-level “safe to overlay on
raw bytes” contract: every bit pattern valid, align-1, no
padding, no interior pointers). Segment borrow tracking
prevents conflicting write access to the same byte range for
the guard’s lifetime.
§Canonical path (audit ST1 / winning-architecture spec)
Three variants exist for different offset sources:
| Variant | Use when |
|---|---|
segment_ref_typed (canonical) | Offset is a compile-time constant (the common case). The const OFFSET: u32 generic becomes an immediate in the pointer arithmetic. |
segment_ref_const | Offset comes from a runtime [Segment] value (dispatching dynamically between named fields). |
segment_ref (this method) | Offset is fully dynamic (iterating segments in a loop, for example). |
#[hopper::context]-generated accessors default to the canonical
typed path; reach for the others only when the use case
genuinely needs a runtime offset.
Sourcepub fn segment_mut<'b, T: Pod>(
&'b mut self,
index: usize,
abs_offset: u32,
) -> Result<SegRefMut<'b, T>, ProgramError>
pub fn segment_mut<'b, T: Pod>( &'b mut self, index: usize, abs_offset: u32, ) -> Result<SegRefMut<'b, T>, ProgramError>
Register a write borrow for a segment of an account.
Validates bounds, checks writable, and registers a leased
exclusive borrow, then returns a SegRefMut<T>
that releases on drop.
This is the primitive that enables safe concurrent mutation of non-overlapping account regions. Hopper’s core innovation . and the lease model (added post-audit) makes sequential same-region borrows inside one instruction work correctly.
Sourcepub fn segment_ref_const<'b, T: Pod>(
&'b mut self,
index: usize,
segment: Segment,
) -> Result<SegRef<'b, T>, ProgramError>
pub fn segment_ref_const<'b, T: Pod>( &'b mut self, index: usize, segment: Segment, ) -> Result<SegRef<'b, T>, ProgramError>
Const-driven segment read: pass a compile-time [Segment] and the
account index. Lowers to the same pointer-plus-const-offset shape
as segment_ref but without the caller hand-rolling the offset +
size arguments.
Sourcepub fn segment_mut_const<'b, T: Pod>(
&'b mut self,
index: usize,
segment: Segment,
) -> Result<SegRefMut<'b, T>, ProgramError>
pub fn segment_mut_const<'b, T: Pod>( &'b mut self, index: usize, segment: Segment, ) -> Result<SegRefMut<'b, T>, ProgramError>
Const-driven exclusive segment access. Pair with
#[hopper::state] constants for zero-overhead field writes.
Sourcepub fn segment_ref_typed<'b, T: Pod, const OFFSET: u32>(
&'b mut self,
index: usize,
segment: TypedSegment<T, OFFSET>,
) -> Result<SegRef<'b, T>, ProgramError>
pub fn segment_ref_typed<'b, T: Pod, const OFFSET: u32>( &'b mut self, index: usize, segment: TypedSegment<T, OFFSET>, ) -> Result<SegRef<'b, T>, ProgramError>
Typed-segment read: the type and offset are both compile-time
constants, baked into a [TypedSegment] zero-sized marker.
Sourcepub fn segment_mut_typed<'b, T: Pod, const OFFSET: u32>(
&'b mut self,
index: usize,
segment: TypedSegment<T, OFFSET>,
) -> Result<SegRefMut<'b, T>, ProgramError>
pub fn segment_mut_typed<'b, T: Pod, const OFFSET: u32>( &'b mut self, index: usize, segment: TypedSegment<T, OFFSET>, ) -> Result<SegRefMut<'b, T>, ProgramError>
Typed-segment write. Mirrors [segment_ref_typed] for the
exclusive path.
Sourcepub unsafe fn raw_ref<T: Pod>(
&self,
index: usize,
) -> Result<Ref<'_, T>, ProgramError>
pub unsafe fn raw_ref<T: Pod>( &self, index: usize, ) -> Result<Ref<'_, T>, ProgramError>
Explicit unsafe whole-account typed read.
Sourcepub unsafe fn raw_mut<T: Pod>(
&self,
index: usize,
) -> Result<RefMut<'_, T>, ProgramError>
pub unsafe fn raw_mut<T: Pod>( &self, index: usize, ) -> Result<RefMut<'_, T>, ProgramError>
Explicit unsafe whole-account typed write.
Sourcepub unsafe fn raw_unchecked<T: Pod>(
&self,
index: usize,
) -> Result<RefMut<'_, T>, ProgramError>
pub unsafe fn raw_unchecked<T: Pod>( &self, index: usize, ) -> Result<RefMut<'_, T>, ProgramError>
Explicit unsafe escape hatch for whole-account typed projection.
This bypasses segment borrow tracking. The caller is responsible for alias safety and for using a type that matches the account bytes.
Sourcepub unsafe fn as_mut_ptr(&self, index: usize) -> Result<*mut u8, ProgramError>
pub unsafe fn as_mut_ptr(&self, index: usize) -> Result<*mut u8, ProgramError>
Canonical raw-pointer escape hatch to an account’s data buffer.
Returns a pointer to the first byte of accounts[index]’s data
region (after the runtime account header, before any Hopper
16-byte layout header). The pointer is valid for reads and
writes for the lifetime of the account view and carries no
borrow-tracking obligations. Dereferencing it is unsafe
because the caller takes over alias-safety responsibility
that the segment registry normally upholds.
This is the explicit power-user primitive the audit asks for:
safe code reaches for segment_ref_typed / segment_mut_typed
/ the generated ctx.<field>_segment_mut(...) accessors; raw
code drops to unsafe { ctx.as_mut_ptr(0)?.add(offset) as *mut T }.
§Safety
The caller must guarantee no aliasing mutable borrow is held
on the same account for the duration of any write through the
returned pointer. The returned pointer must be dereferenced
within the 'info lifetime of the account view; reading past
AccountView::data_len() is undefined behaviour.
Sourcepub fn as_ptr(&self, index: usize) -> Result<*const u8, ProgramError>
pub fn as_ptr(&self, index: usize) -> Result<*const u8, ProgramError>
Immutable sibling of as_mut_ptr. Returns a *const u8.
Shared-borrow checking still runs, so calling this while an
exclusive borrow is live on the same account fails with
AccountBorrowFailed. The return value is safe to obtain; the
caller only needs unsafe to dereference it.
Sourcepub fn read_data<T: Pod>(&self, offset: usize) -> Result<T, ProgramError>
pub fn read_data<T: Pod>(&self, offset: usize) -> Result<T, ProgramError>
Read instruction data as a typed value (unaligned, little-endian safe).
Reads size_of::<T>() bytes starting at offset via read_unaligned.
Caller must ensure T is a plain-old-data type where all bit patterns
are valid.
Sourcepub fn data_slice(
&self,
offset: usize,
len: usize,
) -> Result<&[u8], ProgramError>
pub fn data_slice( &self, offset: usize, len: usize, ) -> Result<&[u8], ProgramError>
Get a byte slice from instruction data.
Sourcepub fn instruction_tag(&self) -> Result<u8, ProgramError>
pub fn instruction_tag(&self) -> Result<u8, ProgramError>
Read the first byte of instruction data as an instruction tag.
Common pattern for byte-tag dispatch.