pub struct AccountView { /* private fields */ }Expand description
Zero-copy view over a Solana account.
AccountView is the single canonical type for account access in
Hopper programs. It wraps whatever backend is active and exposes a
Hopper-owned API surface.
The #[repr(transparent)] layout guarantees that &[backend::AccountView]
can be safely reinterpreted as &[AccountView] at the entrypoint
boundary with zero conversion cost.
Implementations§
Source§impl AccountView
impl AccountView
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 set_lamports(&self, lamports: u64)
pub fn set_lamports(&self, lamports: u64)
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.
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 pre-audit
“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 [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.
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 [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 [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 [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 [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 [segment_ref_typed] for the
contract, this is the exclusive variant.
Sourcepub fn load<T: LayoutContract>(&self) -> Result<Ref<'_, T>, ProgramError>
pub fn load<T: LayoutContract>(&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 load_mut<T: LayoutContract>(&self) -> Result<RefMut<'_, T>, ProgramError>
pub fn load_mut<T: LayoutContract>(&self) -> Result<RefMut<'_, T>, ProgramError>
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().
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.
Sourcepub fn load_cross_program<T: LayoutContract>(
&self,
) -> Result<Ref<'_, T>, ProgramError>
pub fn load_cross_program<T: LayoutContract>( &self, ) -> Result<Ref<'_, T>, ProgramError>
Load a cross-program layout without ownership checks.
Validates wire format (disc + layout_id + size) 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.
The layout_id check ensures ABI compatibility: if the other program changes its layout, this will fail rather than silently misinterpret.
§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 fields<T: LayoutContract>() -> &'static [FieldInfo]
pub fn fields<T: LayoutContract>() -> &'static [FieldInfo]
Compile-time field metadata for a layout contract.
Sourcepub fn field<T: LayoutContract>(name: &str) -> Option<&'static FieldInfo>
pub fn field<T: LayoutContract>(name: &str) -> Option<&'static FieldInfo>
Find a compile-time field descriptor by name.
This is a tooling/inspection helper that delegates to
FieldMap::field_by_name. It performs a const-driven linear
scan over T::FIELDS and is not intended for hot-path use -
programs should reach for the const offsets emitted by
#[hopper::state] instead.
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 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_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 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.
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 resize(&self, new_len: usize) -> ProgramResult
pub fn resize(&self, new_len: usize) -> ProgramResult
Resize the account data.
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.
This is the Hopper Safety Audit’s recommended tightening: the pre-audit version mutated lamports and zeroed data without checking either side, relying on the runtime to reject the transaction later. The audit flagged that as “encouraging patterns that will only be rejected later”, the safe API should surface the violation at call time.
Sourcepub fn close_to_unchecked(&self, destination: &AccountView) -> ProgramResult
pub fn close_to_unchecked(&self, destination: &AccountView) -> ProgramResult
Unchecked variant of [close_to].
Retained for the rare caller that has already verified the
preconditions (e.g. inside a validated #[hopper::context]
binding). Does not check writable or owner, so only use it
when the preconditions are guaranteed by the surrounding code.
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.
Sourcepub unsafe fn close_unchecked(&self)
pub unsafe fn close_unchecked(&self)
Trait Implementations§
Source§impl Clone for AccountView
impl Clone for AccountView
Source§fn clone(&self) -> AccountView
fn clone(&self) -> AccountView
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for AccountView
impl Debug for AccountView
Source§impl<'a> From<&'a AccountView> for CpiAccount<'a>
Available on crate feature hopper-native-backend only.
impl<'a> From<&'a AccountView> for CpiAccount<'a>
hopper-native-backend only.