pub struct Program<'info, P: ProgramId> { /* private fields */ }Expand description
Account that must be a named program. P: ProgramId identifies
which program the account’s address must equal.
pub system_program: Program<'info, SystemId>,Implementations§
Source§impl<'info, P: ProgramId> Program<'info, P>
impl<'info, P: ProgramId> Program<'info, P>
Sourcepub fn try_new(view: &'info AccountView<'info>) -> Result<Self, ProgramError>
pub fn try_new(view: &'info AccountView<'info>) -> Result<Self, ProgramError>
Wrap with address-pin and executable-flag verification.
pub fn as_account(&self) -> &'info AccountView<'info>
Methods from Deref<Target = AccountView<'info>>§
Sourcepub unsafe fn owner(&self) -> &Address
pub unsafe fn owner(&self) -> &Address
The owning program’s address.
§Safety
The returned reference is invalidated if the account is assigned to a new owner. The caller must ensure no concurrent mutation.
Sourcepub fn read_owner(&self) -> Address
pub fn read_owner(&self) -> Address
Read the owner address as a copy (safe, no aliasing hazard).
Sourcepub fn owned_by(&self, program: &Address) -> bool
pub fn owned_by(&self, program: &Address) -> bool
Whether this account is owned by the given program.
Sourcepub fn is_writable(&self) -> bool
pub fn is_writable(&self) -> bool
Whether this account is writable in the transaction.
Sourcepub fn executable(&self) -> bool
pub fn executable(&self) -> bool
Whether this account contains an executable program.
Sourcepub fn is_data_empty(&self) -> bool
pub fn is_data_empty(&self) -> bool
Whether the account data is empty.
Sourcepub fn try_set_lamports(&self, lamports: u64) -> ProgramResult
pub fn try_set_lamports(&self, lamports: u64) -> ProgramResult
Try to set the lamport balance.
Backends such as solana-program enforce lamport borrow rules at
runtime. Use this in framework code so borrow conflicts return a
ProgramError instead of panicking.
Sourcepub fn set_lamports(&self, lamports: u64) -> ProgramResult
pub fn set_lamports(&self, lamports: u64) -> ProgramResult
Set the lamport balance.
Sourcepub fn try_borrow(&self) -> Result<Ref<'_, [u8]>, ProgramError>
pub fn try_borrow(&self) -> Result<Ref<'_, [u8]>, ProgramError>
Try to obtain a shared borrow of the account data.
Sourcepub fn try_borrow_mut(&self) -> Result<RefMut<'_, [u8]>, ProgramError>
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, [u8]>, ProgramError>
Try to obtain an exclusive (mutable) borrow of the account data.
Touch-map note: this RAW byte surface does not stamp the touch
log, segment leases route their exclusive borrows through here
and would smear every narrow lease into a whole-account record,
destroying the map’s field precision. The TYPED whole-account
surfaces (load_mut /
load_compact_mut) record instead.
Ambient-gate note: under a bound strict_writes context this raw
whole-account write borrow is governed, the instruction-ambient
gate refuses it unless the declared policy covers the full data
range, closing the historical “raw borrow bypasses the write
policy” surface. With no gate installed the check is one load and
branch. Segment leases use the crate-internal ungated variant
because they gate the exact range themselves; the migration crank
uses it under its own check_migratable authorization (a
whole-layout transform, distinct from the byte-range gate; see the
crate-private try_borrow_mut_ungated helper.
Sourcepub fn segment_ref<'a, T: Pod>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
abs_offset: u32,
size: u32,
) -> Result<SegRef<'a, T>, ProgramError>
pub fn segment_ref<'a, T: Pod>( &'a self, borrows: &'a mut SegmentBorrowRegistry, abs_offset: u32, size: u32, ) -> Result<SegRef<'a, T>, ProgramError>
Project a typed segment from this account with segment-level borrow tracking.
The runtime validates the requested byte range, registers a
leased read borrow in the provided instruction-scoped
registry, and returns a SegRef<T> that
releases the lease on drop. This replaces the earlier
“instruction-sticky” behaviour: the registry entry is now tied
to the returned guard’s lifetime, so sequential patterns like
let x = segment_ref…; drop(x); let y = segment_ref…; work
exactly the way Rust callers expect.
On the native backend (Solana), the inner Ref<T> uses the
flat {ptr, state} representation, no dummy slice guard,
no intermediate Ref<[u8]>.
The explicit 'a lifetime binds the returned SegRef<'a, T>
to the shorter of &self (the account) and &mut borrows
(the registry). Either outliving the other would let the guard
dangle.
Sourcepub fn segment_mut<'a, T: Pod>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
abs_offset: u32,
size: u32,
) -> Result<SegRefMut<'a, T>, ProgramError>
pub fn segment_mut<'a, T: Pod>( &'a self, borrows: &'a mut SegmentBorrowRegistry, abs_offset: u32, size: u32, ) -> Result<SegRefMut<'a, T>, ProgramError>
Project a mutable typed segment. Mirror of Self::segment_ref; the
returned SegRefMut<T> carries both the
account-level exclusive borrow guard and the segment-registry
lease, so dropping it is a full release, no lingering entries.
Under a bound strict_writes context the instruction-ambient gate
checks this EXACT byte range against the declared write policy, so
direct segment access outside a Context is governed too (the
Context methods enforce the same installed policy before
delegating to the ungated internal variant, paying the check once).
Sourcepub fn split_segments_mut<'a, T: Pod, const N: usize>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
ranges: [(u32, u32); N],
) -> Result<SegmentsMut<'a, T, N>, ProgramError>
pub fn split_segments_mut<'a, T: Pod, const N: usize>( &'a self, borrows: &'a mut SegmentBorrowRegistry, ranges: [(u32, u32); N], ) -> Result<SegmentsMut<'a, T, N>, ProgramError>
Borrow several disjoint byte ranges of one account as
independent typed &mut guards at the same time.
This is the ergonomic answer to “I need mutable access to two
fields of the same account simultaneously”. A single
segment_mut call exclusively borrows the registry for the
returned guard’s lifetime, so two segment_mut calls cannot
coexist. split_segments_mut registers all N ranges up
front, proving pairwise disjointness once through the borrow
registry, and returns an array of N guards that live together
and each release their lease on drop.
Every range is (abs_offset, size) where size == size_of::<T>().
Overlapping ranges are rejected with AccountBorrowFailed; an
out-of-bounds or wrong-size range is rejected with
InvalidArgument / AccountDataTooSmall, and any already-claimed
leases from the batch are rolled back before returning.
// Mutate balance and nonce of the same vault at once.
let [mut bal, mut nonce] =
vault.split_segments_mut::<WireU64, 2>(ctx.borrows_mut(),
[(BALANCE_OFF, 8), (NONCE_OFF, 8)])?;
bal.set(bal.get() + amount);
nonce.set(nonce.get() + 1);Sourcepub fn segment_ref_const<'a, T: Pod>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
segment: Segment,
) -> Result<SegRef<'a, T>, ProgramError>
pub fn segment_ref_const<'a, T: Pod>( &'a self, borrows: &'a mut SegmentBorrowRegistry, segment: Segment, ) -> Result<SegRef<'a, T>, ProgramError>
Project a typed segment described by a compile-time crate::Segment.
This is the “const-driven” access form the Hopper design demands:
the offset and size come from a const SEG: Segment = ...;
declaration generated by #[hopper::state] or written by hand,
so the call collapses to a single ptr + const_offset add on
Solana SBF. No runtime string lookup, no dynamic map, no search.
segment.offset is the absolute offset from the start of
account data (i.e. past the Hopper header already folded in).
Construct it via Segment::new(offset, size) or
Segment::body(body_offset, size), the latter adds
HopperHeader::SIZE for you.
const BALANCE: Segment = Segment::body(0, 8);
let mut balance = vault.segment_ref_const::<u64>(&mut borrows, BALANCE)?;Sourcepub fn segment_mut_const<'a, T: Pod>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
segment: Segment,
) -> Result<SegRefMut<'a, T>, ProgramError>
pub fn segment_mut_const<'a, T: Pod>( &'a self, borrows: &'a mut SegmentBorrowRegistry, segment: Segment, ) -> Result<SegRefMut<'a, T>, ProgramError>
Mutable const-Segment access. See Self::segment_ref_const for the
contract, this is the exclusive variant.
Sourcepub fn segment_ref_typed<'a, T: Pod, const OFFSET: u32>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
_segment: TypedSegment<T, OFFSET>,
) -> Result<SegRef<'a, T>, ProgramError>
pub fn segment_ref_typed<'a, T: Pod, const OFFSET: u32>( &'a self, borrows: &'a mut SegmentBorrowRegistry, _segment: TypedSegment<T, OFFSET>, ) -> Result<SegRef<'a, T>, ProgramError>
Project a typed segment described by a crate::TypedSegment.
This is the tightest form of segment access Hopper exposes: both
the type T and the offset are compile-time constants baked
into the crate::TypedSegment marker, so the call collapses to a
single ptr + literal_offset add with a literal size in the
bounds check. The marker argument is a zero-sized token, free
to pass around.
const BALANCE: TypedSegment<WireU64, { HopperHeader::SIZE as u32 }>
= TypedSegment::new();
let bal = vault.segment_ref_typed(&mut borrows, BALANCE)?;Sourcepub fn segment_mut_typed<'a, T: Pod, const OFFSET: u32>(
&'a self,
borrows: &'a mut SegmentBorrowRegistry,
_segment: TypedSegment<T, OFFSET>,
) -> Result<SegRefMut<'a, T>, ProgramError>
pub fn segment_mut_typed<'a, T: Pod, const OFFSET: u32>( &'a self, borrows: &'a mut SegmentBorrowRegistry, _segment: TypedSegment<T, OFFSET>, ) -> Result<SegRefMut<'a, T>, ProgramError>
Mutable typed-segment access. See Self::segment_ref_typed for the
contract, this is the exclusive variant.
Sourcepub fn load<T: LayoutContract + Pod>(&self) -> Result<Ref<'_, T>, ProgramError>
pub fn load<T: LayoutContract + Pod>(&self) -> Result<Ref<'_, T>, ProgramError>
Load a typed layout after validating the account header.
This is the canonical “validate then project” path:
- Check disc, version, and layout_id match
T - Verify data length >=
T::SIZE - Return zero-copy reference into account data
The returned reference begins at T::TYPE_OFFSET. Body-only layouts
project past the Hopper header; header-inclusive layouts project the
full account struct from byte 0.
§Example
let vault = account.load::<Vault>()?;Sourcepub fn with<T, R, F>(&self, f: F) -> Result<R, ProgramError>
pub fn with<T, R, F>(&self, f: F) -> Result<R, ProgramError>
Borrow a typed layout for the duration of a closure.
This is the ergonomic safe path for read-only handlers: Hopper still
validates the header and holds the data borrow guard, while user code
gets a plain &T inside the closure.
Sourcepub fn load_mut<T: LayoutContract + Pod>(
&self,
) -> Result<RefMut<'_, T>, ProgramError>
pub fn load_mut<T: LayoutContract + Pod>( &self, ) -> Result<RefMut<'_, T>, ProgramError>
Sourcepub fn with_mut<T, R, F>(&self, f: F) -> Result<R, ProgramError>
pub fn with_mut<T, R, F>(&self, f: F) -> Result<R, ProgramError>
Mutably borrow a typed layout for the duration of a closure.
This keeps the zero-copy borrow guard scoped to the closure while making common updates read like direct state mutation.
Sourcepub fn load_compact<T: CompactLayout>(&self) -> Result<Ref<'_, T>, ProgramError>
pub fn load_compact<T: CompactLayout>(&self) -> Result<Ref<'_, T>, ProgramError>
Load a Tier-1 compact layout: [disc:u8][zero-copy body].
The hot path is check_len_exact + check_disc + project-body-at-byte-1.
Unlike load there is no 16-byte header, no
layout_id read, and no schema-epoch comparison. Layout identity is
a program-level fact (the Tier-2 registry), not a per-account one.
§Example
let vault = account.load_compact::<Vault>()?;Sourcepub fn load_compact_mut<T: CompactLayout>(
&self,
) -> Result<RefMut<'_, T>, ProgramError>
pub fn load_compact_mut<T: CompactLayout>( &self, ) -> Result<RefMut<'_, T>, ProgramError>
Mutable Tier-1 compact load. See load_compact.
Sourcepub fn with_compact<T, R, F>(&self, f: F) -> Result<R, ProgramError>
pub fn with_compact<T, R, F>(&self, f: F) -> Result<R, ProgramError>
Borrow a compact layout for the duration of a closure (read-only).
Sourcepub fn with_compact_mut<T, R, F>(&self, f: F) -> Result<R, ProgramError>
pub fn with_compact_mut<T, R, F>(&self, f: F) -> Result<R, ProgramError>
Mutably borrow a compact layout for the duration of a closure.
Sourcepub fn init_compact<T: CompactLayout>(&self) -> ProgramResult
pub fn init_compact<T: CompactLayout>(&self) -> ProgramResult
Initialise a compact account by stamping the discriminator byte.
Writes T::DISC at byte 0; the body is left as-is (callers
typically follow with load_compact_mut
to populate it). Requires the account to be writable and exactly
T::COMPACT_LEN bytes long.
Sourcepub fn load_compact_dynamic<T: CompactDynamicLayout>(
&self,
) -> Result<Ref<'_, T>, ProgramError>
pub fn load_compact_dynamic<T: CompactDynamicLayout>( &self, ) -> Result<Ref<'_, T>, ProgramError>
Tier-1 compact dynamic load: validate the discriminator and the
minimum length, then project the fixed head at
COMPACT_BODY_OFFSET.
Unlike load_compact, the account may be longer
than the fixed head: the trailing bytes are the dynamic tail, left
untouched here and accessed through the generated tail_* helpers.
This is the [disc:u8][fixed_head][tail] analogue of
load’s tolerance of a headered dynamic tail.
§Example
let head = account.load_compact_dynamic::<Market>()?; // fixed head
let data = account.try_borrow()?;
let tail = Market::tail_read(&data)?; // dynamic tailSourcepub fn load_compact_dynamic_mut<T: CompactDynamicLayout>(
&self,
) -> Result<RefMut<'_, T>, ProgramError>
pub fn load_compact_dynamic_mut<T: CompactDynamicLayout>( &self, ) -> Result<RefMut<'_, T>, ProgramError>
Mutable Tier-1 compact-dynamic load of the fixed head.
See load_compact_dynamic.
Sourcepub fn with_compact_dynamic<T, R, F>(&self, f: F) -> Result<R, ProgramError>
pub fn with_compact_dynamic<T, R, F>(&self, f: F) -> Result<R, ProgramError>
Borrow a compact-dynamic fixed head for the duration of a closure.
Sourcepub fn with_compact_dynamic_mut<T, R, F>(&self, f: F) -> Result<R, ProgramError>
pub fn with_compact_dynamic_mut<T, R, F>(&self, f: F) -> Result<R, ProgramError>
Mutably borrow a compact-dynamic fixed head for the duration of a closure.
Sourcepub fn init_compact_dynamic<T: CompactDynamicLayout>(&self) -> ProgramResult
pub fn init_compact_dynamic<T: CompactDynamicLayout>(&self) -> ProgramResult
Initialise a compact-dynamic account: stamp T::DISC at byte 0 and, if
the account was allocated with room for a tail, zero the tail’s u32
length prefix so a fresh account reads as an empty tail rather than
uninitialized bytes (fail-closed init).
Requires the account to be writable and at least T::MIN_LEN bytes
(discriminator + fixed head). The tail region may be larger to reserve
growth headroom.
Sourcepub unsafe fn raw_ref<T: Pod>(&self) -> Result<Ref<'_, T>, ProgramError>
pub unsafe fn raw_ref<T: Pod>(&self) -> Result<Ref<'_, T>, ProgramError>
Explicit raw typed read of the account buffer.
This bypasses Hopper layout validation and segment tracking, but it still
respects the account-level borrow rules enforced by try_borrow().
§Safety
Caller must uphold the invariants documented for this unsafe API before invoking it.
Sourcepub unsafe fn raw_mut<T: Pod>(&self) -> Result<RefMut<'_, T>, ProgramError>
pub unsafe fn raw_mut<T: Pod>(&self) -> Result<RefMut<'_, T>, ProgramError>
Explicit raw typed write of the account buffer.
This bypasses Hopper layout validation and segment tracking, but it still enforces writability and the account-level exclusive borrow rules.
§Safety
Caller must uphold the invariants documented for this unsafe API before invoking it.
Sourcepub fn load_cross_program<T: LayoutContract + Pod>(
&self,
) -> Result<Ref<'_, T>, ProgramError>
pub fn load_cross_program<T: LayoutContract + Pod>( &self, ) -> Result<Ref<'_, T>, ProgramError>
Load a cross-program layout without ownership checks.
Validates the layout contract but does not check that the account is owned by this program. Use for cross-program reads where the account is owned by another program and you need a typed, zero-copy view of its data.
Full contract validation ensures ABI compatibility: if the other program changes its layout identity or schema epoch, this fails rather than silently misinterpreting bytes.
§Example
let other_vault = foreign_account.load_cross_program::<OtherVault>()?;Sourcepub fn layout_info(&self) -> Option<LayoutInfo>
pub fn layout_info(&self) -> Option<LayoutInfo>
Read runtime layout metadata from this account’s header.
Returns None if the account data is too short for a Hopper header.
This is useful for runtime inspection, manager tooling, and schema
checking when the concrete layout type is not known at compile time.
Sourcepub fn extension_range<T: LayoutContract>(
&self,
) -> Result<Range<usize>, ProgramError>
pub fn extension_range<T: LayoutContract>( &self, ) -> Result<Range<usize>, ProgramError>
Return the extension-region byte range for a layout that declares one.
Callers can apply the returned range to a borrowed data slice when they want to inspect or mutate extension bytes explicitly.
Sourcepub fn extension_bytes<T: LayoutContract>(
&self,
) -> Result<Ref<'_, [u8]>, ProgramError>
pub fn extension_bytes<T: LayoutContract>( &self, ) -> Result<Ref<'_, [u8]>, ProgramError>
Borrow the extension/tail region declared by a layout contract.
Sourcepub fn extension_bytes_mut<T: LayoutContract>(
&self,
) -> Result<RefMut<'_, [u8]>, ProgramError>
pub fn extension_bytes_mut<T: LayoutContract>( &self, ) -> Result<RefMut<'_, [u8]>, ProgramError>
Mutably borrow the extension/tail region declared by a layout contract.
Sourcepub fn zero_range(&self, start: usize, len: usize) -> ProgramResult
pub fn zero_range(&self, start: usize, len: usize) -> ProgramResult
Zero the byte range [start, start + len), checked against the
instruction-ambient write policy over exactly that range.
This is the precise-authority spelling of “clear these bytes.” The
naive alternative, take a whole-account try_borrow_mut and slice,
demands authority over every byte of the account, so a narrow but
entirely legitimate declaration (a tail(seq) grant zero-filling
the tail it just grew) would be refused by its own policy. Gating
the exact range keeps the refusal honest: it fires when the bytes
being cleared are outside the declaration, and not before.
An empty range is a no-op and requires no authority.
Sourcepub fn zero_appended(&self, previous_len: usize) -> ProgramResult
pub fn zero_appended(&self, previous_len: usize) -> ProgramResult
Zero the bytes a grow just appended: [previous_len, data_len).
Authorized by the transition dimension, not the byte-range one,
deliberately, and this is the whole reason it is a separate
method from zero_range:
- The bytes did not exist when the policy was declared. Clearing
them cannot destroy, reveal, or corrupt any state a byte-range
declaration protects, so requiring a declared range over them
would refuse the framework’s own
realloc_zerolifecycle on every narrow declaration (mut(seg)+realloc) while protecting nothing. - The authority to create them was already checked:
resizeconsultscheck_account_transition, and an account carrying no declared data authority cannot resize in the first place. Same check here, so this method can never reach an account the instruction has no data authority over. - It is strictly narrower than the pre-existing body: a caller cannot name an offset, only “whatever the grow added.”
Writes into the PRE-EXISTING body remain governed by the byte-range policy through every other surface.
Sourcepub fn init_layout<T: LayoutContract>(&self) -> ProgramResult
pub fn init_layout<T: LayoutContract>(&self) -> ProgramResult
Initialize an account with the given layout contract header.
Writes the disc, version, layout_id, and zeroes flags/reserved. Call this when creating a new account before writing field data.
Sourcepub fn require_signer(&self) -> ProgramResult
pub fn require_signer(&self) -> ProgramResult
Validate that this account is a signer.
Sourcepub fn require_writable(&self) -> ProgramResult
pub fn require_writable(&self) -> ProgramResult
Validate that this account is writable.
Sourcepub fn require_owned_by(&self, program: &Address) -> ProgramResult
pub fn require_owned_by(&self, program: &Address) -> ProgramResult
Validate that this account is owned by the given program.
Sourcepub fn require_payer(&self) -> ProgramResult
pub fn require_payer(&self) -> ProgramResult
Validate signer + writable (common “payer” pattern).
Sourcepub fn check_signer(&self) -> Result<&Self, ProgramError>
pub fn check_signer(&self) -> Result<&Self, ProgramError>
Chainable signer check.
Sourcepub fn check_writable(&self) -> Result<&Self, ProgramError>
pub fn check_writable(&self) -> Result<&Self, ProgramError>
Chainable writable check.
Sourcepub fn check_owned_by(&self, program: &Address) -> Result<&Self, ProgramError>
pub fn check_owned_by(&self, program: &Address) -> Result<&Self, ProgramError>
Chainable ownership check.
Sourcepub fn check_owned_by_any(
&self,
programs: &[&Address],
) -> Result<&Self, ProgramError>
pub fn check_owned_by_any( &self, programs: &[&Address], ) -> Result<&Self, ProgramError>
Chainable check that this account’s owner is one of programs.
Accepts an account from any of several programs, most commonly an SPL
Token or Token-2022 mint / token account, and rejects every other
owner. This is check_owned_by generalized to a
set; an empty programs slice always rejects.
Sourcepub fn check_disc(&self, expected: u8) -> Result<&Self, ProgramError>
pub fn check_disc(&self, expected: u8) -> Result<&Self, ProgramError>
Chainable discriminator check.
Sourcepub fn check_has_data(&self) -> Result<&Self, ProgramError>
pub fn check_has_data(&self) -> Result<&Self, ProgramError>
Chainable non-empty data check.
Sourcepub fn check_executable(&self) -> Result<&Self, ProgramError>
pub fn check_executable(&self) -> Result<&Self, ProgramError>
Chainable executable check.
Sourcepub fn check_address(&self, expected: &Address) -> Result<&Self, ProgramError>
pub fn check_address(&self, expected: &Address) -> Result<&Self, ProgramError>
Chainable address check.
Sourcepub fn check_data_len(&self, min_len: usize) -> Result<&Self, ProgramError>
pub fn check_data_len(&self, min_len: usize) -> Result<&Self, ProgramError>
Chainable minimum data length check.
Sourcepub fn check_version(&self, expected: u8) -> Result<&Self, ProgramError>
pub fn check_version(&self, expected: u8) -> Result<&Self, ProgramError>
Chainable version check.
Sourcepub fn check_layout<T: LayoutContract>(&self) -> Result<&Self, ProgramError>
pub fn check_layout<T: LayoutContract>(&self) -> Result<&Self, ProgramError>
Chainable full layout contract check (disc + version + layout_id + size).
Sourcepub fn proof(&self) -> AccountProof<'_>
pub fn proof(&self) -> AccountProof<'_>
Start a proof-carrying validation chain for this account.
Sourcepub fn layout_id(&self) -> Option<&[u8; 8]>
pub fn layout_id(&self) -> Option<&[u8; 8]>
Read the 8-byte layout_id from the Hopper account header (bytes 4..12).
Sourcepub fn require_disc(&self, expected: u8) -> ProgramResult
pub fn require_disc(&self, expected: u8) -> ProgramResult
Verify that this account has the given discriminator.
Sourcepub fn flags(&self) -> u8
pub fn flags(&self) -> u8
Pack the account’s boolean flags into a single byte.
Bit layout: bit 0 = signer, bit 1 = writable, bit 2 = executable, bit 3 = has data.
Delegates to the native backend, which extracts signer/writable/ executable from one packed-u32 header read instead of three separate byte loads.
Sourcepub fn expect_flags(&self, required: u8) -> ProgramResult
pub fn expect_flags(&self, required: u8) -> ProgramResult
Check that the account’s flags contain all required bits.
Sourcepub fn expect_signer_writable(
&self,
need_signer: bool,
need_writable: bool,
) -> ProgramResult
pub fn expect_signer_writable( &self, need_signer: bool, need_writable: bool, ) -> ProgramResult
Fused signer/writable validation (the generated-context hot path).
Validates both requirements with a single packed-flags read and
one masked compare, the same shape a hand-rolled
header & MASK == MASK check compiles to, since need_signer /
need_writable are compile-time literals at every macro call site
and this function is #[inline(always)]. On mismatch it falls back
to the individual checks so the error stays precise
(MissingRequiredSignature vs Immutable); the fallback runs only
on the failure path, where compute cost is irrelevant.
Sourcepub fn resize(&self, new_len: usize) -> ProgramResult
pub fn resize(&self, new_len: usize) -> ProgramResult
Resize the account data, zeroing any newly exposed region on growth.
See hopper_native::AccountView::resize for why zero-on-growth
is the safe default. Use resize_raw for the
hot path when the caller overwrites the grown region in full.
Sourcepub fn resize_raw(&self, new_len: usize) -> ProgramResult
pub fn resize_raw(&self, new_len: usize) -> ProgramResult
Resize the account data without zero-filling the grown region.
Sourcepub unsafe fn assign(&self, new_owner: &Address)
pub unsafe fn assign(&self, new_owner: &Address)
Assign a new owner.
§Safety
The caller must ensure the account is writable and that ownership transfer is authorized.
Sourcepub fn close(&self) -> ProgramResult
pub fn close(&self) -> ProgramResult
Close the account: zero lamports and data.
Sourcepub fn close_to(
&self,
destination: &AccountView<'_>,
program_id: &Address,
) -> ProgramResult
pub fn close_to( &self, destination: &AccountView<'_>, program_id: &Address, ) -> ProgramResult
Close the account, transferring remaining lamports to destination.
Idiomatic Solana close pattern: move all lamports to the destination account, then zero this account’s data so the runtime garbage-collects it at the end of the transaction.
§Preconditions (enforced)
Per Solana’s account modification rules (only the owning program can debit lamports or mutate data on a writable account), this method requires:
selfmust be writable, otherwise the runtime will reject the commit anyway, but we fail fast here rather than let the transaction progress through an invalid state.selfmust be owned byprogram_id, the program that is executing this instruction. Without this check the safe API would silently encourage patterns that only Solana’s post-instruction verifier catches.destinationmust be writable, receiving lamports requires write permission on the credit side.
A same-address recipient is rejected. Borrow conflicts, both lamport policies, and credit overflow are checked before data or balances change, including when the caller catches a returned error.
Sourcepub fn close_to_unchecked(&self, destination: &AccountView<'_>) -> ProgramResult
pub fn close_to_unchecked(&self, destination: &AccountView<'_>) -> ProgramResult
Unchecked variant of Self::close_to.
Retained for the rare caller that has already verified the
preconditions (e.g. inside a validated #[hopper::context]
binding). It omits the owner and destination-writable checks; callers
must establish both. Source writability, active data borrows, distinct
addresses, checked credit arithmetic, and installed policies still apply.
“Unchecked” waives only those two preconditions. The ambient
write gate is not a precondition a caller can pre-verify; it is
the instruction’s installed policy, and closing an account both
zeroes its data and ends its presence, so the same transition
rule as close / close_to
applies here (the lamport moves are separately governed by the
gated try_set_lamports funnel below).
Sourcepub fn check_borrow(&self) -> Result<(), ProgramError>
pub fn check_borrow(&self) -> Result<(), ProgramError>
Check that the account can be shared-borrowed.
Sourcepub fn check_borrow_mut(&self) -> Result<(), ProgramError>
pub fn check_borrow_mut(&self) -> Result<(), ProgramError>
Check that the account can be exclusively borrowed.
Sourcepub unsafe fn borrow_unchecked(&self) -> &[u8]
pub unsafe fn borrow_unchecked(&self) -> &[u8]
Sourcepub unsafe fn borrow_unchecked_mut(&self) -> &mut [u8] ⓘ
pub unsafe fn borrow_unchecked_mut(&self) -> &mut [u8] ⓘ
Mutably borrow account data without tracking.
§Safety
The caller must ensure no other borrows are active.
Sourcepub unsafe fn resize_unchecked(&self, new_len: usize)
pub unsafe fn resize_unchecked(&self, new_len: usize)
Resize without bounds checking.
§Safety
The caller must guarantee the new length is within the permitted increase.