Skip to content

Commit

Permalink
lang: Get discriminator length dynamically (#3101)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Jul 21, 2024
1 parent 14cec14 commit ba33d5e
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Export `Discriminator` trait from `prelude` ([#3075](https://github.com/coral-xyz/anchor/pull/3075)).
- lang: Add `Account` utility type to get accounts from bytes ([#3091](https://github.com/coral-xyz/anchor/pull/3091)).
- client: Add option to pass in mock rpc client when using anchor_client ([#3053](https://github.com/coral-xyz/anchor/pull/3053)).
- lang: Get discriminator length dynamically ([#3101](https://github.com/coral-xyz/anchor/pull/3101)).

### Fixes

Expand Down
8 changes: 4 additions & 4 deletions lang/attribute/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,15 @@ pub fn account(
if buf.len() < #discriminator.len() {
return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
}
let given_disc = &buf[..8];
let given_disc = &buf[..#discriminator.len()];
if &#discriminator != given_disc {
return Err(anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch).with_account_name(#account_name_str));
}
Self::try_deserialize_unchecked(buf)
}

fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
let data: &[u8] = &buf[8..];
let data: &[u8] = &buf[#discriminator.len()..];
// Re-interpret raw bytes into the POD data structure.
let account = anchor_lang::__private::bytemuck::from_bytes(data);
// Copy out the bytes into a new, owned data structure.
Expand Down Expand Up @@ -223,15 +223,15 @@ pub fn account(
if buf.len() < #discriminator.len() {
return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
}
let given_disc = &buf[..8];
let given_disc = &buf[..#discriminator.len()];
if &#discriminator != given_disc {
return Err(anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch).with_account_name(#account_name_str));
}
Self::try_deserialize_unchecked(buf)
}

fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
let mut data: &[u8] = &buf[8..];
let mut data: &[u8] = &buf[#discriminator.len()..];
AnchorDeserialize::deserialize(&mut data)
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into())
}
Expand Down
24 changes: 14 additions & 10 deletions lang/src/accounts/account_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}

let given_disc = &data[..8];
let given_disc = &data[..disc.len()];
if given_disc != disc {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Expand Down Expand Up @@ -158,13 +158,13 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}

let given_disc = &data[..8];
let given_disc = &data[..disc.len()];
if given_disc != disc {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}

Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[8..mem::size_of::<T>() + 8])
bytemuck::from_bytes(&data[disc.len()..mem::size_of::<T>() + disc.len()])
}))
}

Expand All @@ -182,13 +182,15 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}

let given_disc = &data[..8];
let given_disc = &data[..disc.len()];
if given_disc != disc {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}

Ok(RefMut::map(data, |data| {
bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::<T>() + 8])
bytemuck::from_bytes_mut(
&mut data.deref_mut()[disc.len()..mem::size_of::<T>() + disc.len()],
)
}))
}

Expand All @@ -204,15 +206,17 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
let data = self.acc_info.try_borrow_mut_data()?;

// The discriminator should be zero, since we're initializing.
let mut disc_bytes = [0u8; 8];
disc_bytes.copy_from_slice(&data[..8]);
let discriminator = u64::from_le_bytes(disc_bytes);
if discriminator != 0 {
let disc = T::DISCRIMINATOR;
let given_disc = &data[..disc.len()];
let has_disc = given_disc.iter().any(|b| *b != 0);
if has_disc {
return Err(ErrorCode::AccountDiscriminatorAlreadySet.into());
}

Ok(RefMut::map(data, |data| {
bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::<T>() + 8])
bytemuck::from_bytes_mut(
&mut data.deref_mut()[disc.len()..mem::size_of::<T>() + disc.len()],
)
}))
}
}
Expand Down
5 changes: 4 additions & 1 deletion lang/syn/src/codegen/program/idl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream {
let owner = accounts.program.key;
let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
// Space: account discriminator || authority pubkey || vec len || vec data
let space = std::cmp::min(8 + 32 + 4 + data_len as usize, 10_000);
let space = std::cmp::min(
IdlAccount::DISCRIMINATOR.len() + 32 + 4 + data_len as usize,
10_000
);
let rent = Rent::get()?;
let lamports = rent.minimum_balance(space);
let seeds = &[&[nonce][..]];
Expand Down

0 comments on commit ba33d5e

Please sign in to comment.