Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions p-interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ pinocchio = { workspace = true }
pinocchio-pubkey = "0.3"

[dev-dependencies]
rand = "0.8"
strum = "0.27"
strum_macros = "0.27"
2 changes: 1 addition & 1 deletion p-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod native_mint;
pub mod state;

pub mod program {
pinocchio_pubkey::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
pinocchio_pubkey::declare_id!("cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m");
}

/// A "dummy" function with a hint to the compiler that it is unlikely to be
Expand Down
1 change: 1 addition & 0 deletions p-interface/src/state/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl Account {

unsafe impl Transmutable for Account {
const LEN: usize = core::mem::size_of::<Account>();
const ACCOUNT_TYPE: u8 = super::ACCOUNT_TYPE_TOKEN_ACCOUNT;
}

impl Initializable for Account {
Expand Down
1 change: 1 addition & 0 deletions p-interface/src/state/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ impl Mint {
unsafe impl Transmutable for Mint {
/// The length of the `Mint` account data.
const LEN: usize = core::mem::size_of::<Mint>();
const ACCOUNT_TYPE: u8 = super::ACCOUNT_TYPE_MINT;
}

impl Initializable for Mint {
Expand Down
47 changes: 40 additions & 7 deletions p-interface/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ pub mod multisig;
/// Type alias for fields represented as `COption`.
pub type COption<T> = ([u8; 4], T);

/// AccountType discriminator for Mint accounts.
/// Validation checks byte 165 (ACCOUNT_TYPE_OFFSET) for all extended accounts.
pub const ACCOUNT_TYPE_MINT: u8 = 1;

/// AccountType discriminator for Token accounts.
/// Validation checks byte 165 (ACCOUNT_TYPE_OFFSET) for all extended accounts.
pub const ACCOUNT_TYPE_TOKEN_ACCOUNT: u8 = 2;

/// Marker trait for types that can be cast from a raw pointer.
///
/// # Safety
Expand All @@ -20,6 +28,10 @@ pub unsafe trait Transmutable {
///
/// This must be equal to the size of each individual field in the type.
const LEN: usize;

/// The expected AccountType discriminator value at byte offset `LEN` for extended accounts.
/// Used to validate account type when `bytes.len() > LEN`.
const ACCOUNT_TYPE: u8;
}

/// Trait to represent a type that can be initialized.
Expand All @@ -35,7 +47,7 @@ pub trait Initializable {
/// The caller must ensure that `bytes` contains a valid representation of `T`.
#[inline(always)]
pub unsafe fn load<T: Initializable + Transmutable>(bytes: &[u8]) -> Result<&T, ProgramError> {
load_unchecked(bytes).and_then(|t: &T| {
load_unchecked(&bytes).and_then(|t: &T| {
// checks if the data is initialized
if t.is_initialized()? {
Ok(t)
Expand All @@ -45,19 +57,31 @@ pub unsafe fn load<T: Initializable + Transmutable>(bytes: &[u8]) -> Result<&T,
})
}

/// Byte offset of AccountType discriminator in extended accounts.
pub const ACCOUNT_TYPE_OFFSET: usize = 165;

/// Return a `T` reference from the given bytes.
///
/// This function does not check if the data is initialized.
///
/// Accepts:
/// - Exact length match: `bytes.len() == T::LEN` (standard account)
/// - Extended account: `bytes.len() > ACCOUNT_TYPE_OFFSET` with matching AccountType at byte 165
///
/// Rejects everything else (too short, ambiguous size, wrong AccountType).
///
/// # Safety
///
/// The caller must ensure that `bytes` contains a valid representation of `T`.
#[inline(always)]
pub unsafe fn load_unchecked<T: Transmutable>(bytes: &[u8]) -> Result<&T, ProgramError> {
if bytes.len() != T::LEN {
return Err(ProgramError::InvalidAccountData);
if bytes.len() == T::LEN {
return Ok(&*(bytes[..T::LEN].as_ptr() as *const T));
}
if bytes.len() > ACCOUNT_TYPE_OFFSET && bytes[ACCOUNT_TYPE_OFFSET] == T::ACCOUNT_TYPE {
return Ok(&*(bytes[..T::LEN].as_ptr() as *const T));
}
Ok(&*(bytes.as_ptr() as *const T))
Err(ProgramError::InvalidAccountData)
}

/// Return a mutable reference for an initialized `T` from the given bytes.
Expand All @@ -83,15 +107,24 @@ pub unsafe fn load_mut<T: Initializable + Transmutable>(
///
/// This function does not check if the data is initialized.
///
/// Accepts:
/// - Exact length match: `bytes.len() == T::LEN` (standard account)
/// - Extended account: `bytes.len() > ACCOUNT_TYPE_OFFSET` with matching AccountType at byte 165
///
/// Rejects everything else (too short, ambiguous size, wrong AccountType).
///
/// # Safety
///
/// The caller must ensure that `bytes` contains a valid representation of `T`.
#[inline(always)]
pub unsafe fn load_mut_unchecked<T: Transmutable>(
bytes: &mut [u8],
) -> Result<&mut T, ProgramError> {
if bytes.len() != T::LEN {
return Err(ProgramError::InvalidAccountData);
if bytes.len() == T::LEN {
return Ok(&mut *(bytes[..T::LEN].as_mut_ptr() as *mut T));
}
if bytes.len() > ACCOUNT_TYPE_OFFSET && bytes[ACCOUNT_TYPE_OFFSET] == T::ACCOUNT_TYPE {
return Ok(&mut *(bytes[..T::LEN].as_mut_ptr() as *mut T));
}
Ok(&mut *(bytes.as_mut_ptr() as *mut T))
Err(ProgramError::InvalidAccountData)
}
2 changes: 2 additions & 0 deletions p-interface/src/state/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ impl Multisig {
unsafe impl Transmutable for Multisig {
/// The length of the `Multisig` account data.
const LEN: usize = core::mem::size_of::<Multisig>();
/// Multisig not supported for extended accounts (255 = invalid/unused type).
const ACCOUNT_TYPE: u8 = 255;
}

impl Initializable for Multisig {
Expand Down
Loading