Skip to content

Commit

Permalink
lang: Make discriminator type unsized (#3098)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Jul 20, 2024
1 parent f8d0f52 commit 14cec14
Show file tree
Hide file tree
Showing 17 changed files with 46 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- client: Add `tokio` support to `RequestBuilder` with `async` feature ([#3057](https://github.com/coral-xyz/anchor/pull/3057)).
- lang: Remove `EventData` trait ([#3083](https://github.com/coral-xyz/anchor/pull/3083)).
- client: Remove `async_rpc` method ([#3053](https://github.com/coral-xyz/anchor/pull/3053)).
- lang: Make discriminator type unsized ([#3098](https://github.com/coral-xyz/anchor/pull/3098)).

## [0.30.1] - 2024-06-20

Expand Down
2 changes: 1 addition & 1 deletion client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
filters: Vec<RpcFilterType>,
) -> Result<ProgramAccountsIterator<T>, ClientError> {
let account_type_filter =
RpcFilterType::Memcmp(Memcmp::new_base58_encoded(0, &T::discriminator()));
RpcFilterType::Memcmp(Memcmp::new_base58_encoded(0, T::DISCRIMINATOR));
let config = RpcProgramAccountsConfig {
filters: Some([vec![account_type_filter], filters].concat()),
account_config: RpcAccountInfoConfig {
Expand Down
4 changes: 2 additions & 2 deletions lang/attribute/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub fn account(

#[automatically_derived]
impl #impl_gen anchor_lang::Discriminator for #account_name #type_gen #where_clause {
const DISCRIMINATOR: [u8; 8] = #discriminator;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}

// This trait is useful for clients deserializing accounts.
Expand Down Expand Up @@ -239,7 +239,7 @@ pub fn account(

#[automatically_derived]
impl #impl_gen anchor_lang::Discriminator for #account_name #type_gen #where_clause {
const DISCRIMINATOR: [u8; 8] = #discriminator;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}

#owner_impl
Expand Down
8 changes: 6 additions & 2 deletions lang/attribute/event/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn event(
}

impl anchor_lang::Discriminator for #event_name {
const DISCRIMINATOR: [u8; 8] = #discriminator;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}
};

Expand Down Expand Up @@ -161,7 +161,11 @@ pub fn emit_cpi(input: proc_macro::TokenStream) -> proc_macro::TokenStream {

let disc = anchor_lang::event::EVENT_IX_TAG_LE;
let inner_data = anchor_lang::Event::data(&#event_struct);
let ix_data: Vec<u8> = disc.into_iter().chain(inner_data.into_iter()).collect();
let ix_data: Vec<u8> = disc
.into_iter()
.map(|b| *b)
.chain(inner_data.into_iter())
.collect();

let ix = anchor_lang::solana_program::instruction::Instruction::new_with_bytes(
crate::ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub fn gen_accounts_mod(idl: &Idl) -> proc_macro2::TokenStream {
#impls

impl anchor_lang::Discriminator for #name {
const DISCRIMINATOR: [u8; 8] = #discriminator;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}

impl anchor_lang::Owner for #name {
Expand Down
2 changes: 1 addition & 1 deletion lang/attribute/program/src/declare_program/mods/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub fn gen_events_mod(idl: &Idl) -> proc_macro2::TokenStream {
}

impl anchor_lang::Discriminator for #name {
const DISCRIMINATOR: [u8; 8] = #discriminator;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn gen_internal_args_mod(idl: &Idl) -> proc_macro2::TokenStream {
let discriminator = gen_discriminator(&ix.discriminator);
quote! {
impl anchor_lang::Discriminator for #ix_struct_name {
const DISCRIMINATOR: [u8; 8] = #discriminator;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}
}
} else {
Expand Down
29 changes: 16 additions & 13 deletions lang/src/accounts/account_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::{
Accounts, AccountsClose, AccountsExit, Key, Owner, Result, ToAccountInfo, ToAccountInfos,
ToAccountMetas, ZeroCopy,
};
use arrayref::array_ref;
use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::pubkey::Pubkey;
Expand Down Expand Up @@ -123,13 +122,15 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram)
.with_pubkeys((*acc_info.owner, T::owner())));
}
let data: &[u8] = &acc_info.try_borrow_data()?;
if data.len() < T::discriminator().len() {

let data = &acc_info.try_borrow_data()?;
let disc = T::DISCRIMINATOR;
if data.len() < disc.len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
// Discriminator must match.
let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {

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

Expand All @@ -152,12 +153,13 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
/// Returns a Ref to the account data structure for reading.
pub fn load(&self) -> Result<Ref<T>> {
let data = self.acc_info.try_borrow_data()?;
if data.len() < T::discriminator().len() {
let disc = T::DISCRIMINATOR;
if data.len() < disc.len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}

let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {
let given_disc = &data[..8];
if given_disc != disc {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}

Expand All @@ -175,12 +177,13 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
}

let data = self.acc_info.try_borrow_mut_data()?;
if data.len() < T::discriminator().len() {
let disc = T::DISCRIMINATOR;
if data.len() < disc.len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}

let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {
let given_disc = &data[..8];
if given_disc != disc {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}

Expand Down Expand Up @@ -241,7 +244,7 @@ impl<'info, T: ZeroCopy + Owner> AccountsExit<'info> for AccountLoader<'info, T>
let mut data = self.acc_info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut writer = BpfWriter::new(dst);
writer.write_all(&T::discriminator()).unwrap();
writer.write_all(T::DISCRIMINATOR).unwrap();
}
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion lang/src/bpf_upgradeable_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ mod idl_build {

impl crate::IdlBuild for ProgramData {}
impl crate::Discriminator for ProgramData {
const DISCRIMINATOR: [u8; 8] = [u8::MAX; 8];
const DISCRIMINATOR: &'static [u8] = &[];
}
}
2 changes: 1 addition & 1 deletion lang/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Sha256(anchor:event)[..8]
pub const EVENT_IX_TAG: u64 = 0x1d9acb512ea545e4;
pub const EVENT_IX_TAG_LE: [u8; 8] = EVENT_IX_TAG.to_le_bytes();
pub const EVENT_IX_TAG_LE: &[u8] = EVENT_IX_TAG.to_le_bytes().as_slice();
2 changes: 1 addition & 1 deletion lang/src/idl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::prelude::*;
//
// Sha256(anchor:idl)[..8];
pub const IDL_IX_TAG: u64 = 0x0a69e9a778bcf440;
pub const IDL_IX_TAG_LE: [u8; 8] = IDL_IX_TAG.to_le_bytes();
pub const IDL_IX_TAG_LE: &[u8] = IDL_IX_TAG.to_le_bytes().as_slice();

// The Pubkey that is stored as the 'authority' on the IdlAccount when the authority
// is "erased".
Expand Down
8 changes: 4 additions & 4 deletions lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ pub trait ZeroCopy: Discriminator + Copy + Clone + Zeroable + Pod {}
pub trait InstructionData: Discriminator + AnchorSerialize {
fn data(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(256);
data.extend_from_slice(&Self::discriminator());
data.extend_from_slice(Self::DISCRIMINATOR);
self.serialize(&mut data).unwrap();
data
}
Expand All @@ -290,7 +290,7 @@ pub trait InstructionData: Discriminator + AnchorSerialize {
/// necessary), and because the data field in `Instruction` expects a `Vec<u8>`.
fn write_to(&self, mut data: &mut Vec<u8>) {
data.clear();
data.extend_from_slice(&Self::DISCRIMINATOR);
data.extend_from_slice(Self::DISCRIMINATOR);
self.serialize(&mut data).unwrap()
}
}
Expand All @@ -302,8 +302,8 @@ pub trait Event: AnchorSerialize + AnchorDeserialize + Discriminator {

/// 8 byte unique identifier for a type.
pub trait Discriminator {
const DISCRIMINATOR: [u8; 8];
fn discriminator() -> [u8; 8] {
const DISCRIMINATOR: &'static [u8];
fn discriminator() -> &'static [u8] {
Self::DISCRIMINATOR
}
}
Expand Down
3 changes: 1 addition & 2 deletions lang/syn/src/codegen/program/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let ix_method_name = &ix.raw_method.sig.ident;
let ix_name_camel: proc_macro2::TokenStream = ix_method_name
.to_string()
.as_str()
.to_camel_case()
.parse()
.expect("Failed to parse ix method name in camel as `TokenStream`");
Expand Down Expand Up @@ -65,7 +64,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
sighash
};

match sighash {
match sighash.as_slice() {
#(#global_dispatch_arms)*
anchor_lang::idl::IDL_IX_TAG_LE => {
// If the method identifier is the IDL tag, then execute an IDL
Expand Down
11 changes: 5 additions & 6 deletions lang/syn/src/codegen/program/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
})
.collect();
let ix_data_trait = {
let sighash_arr = ix
let discriminator = ix
.interface_discriminator
.unwrap_or(sighash(SIGHASH_GLOBAL_NAMESPACE, name));
let sighash_tts: proc_macro2::TokenStream =
format!("{sighash_arr:?}").parse().unwrap();
.unwrap_or_else(|| sighash(SIGHASH_GLOBAL_NAMESPACE, name));
let discriminator: proc_macro2::TokenStream =
format!("{discriminator:?}").parse().unwrap();
quote! {
impl anchor_lang::Discriminator for #ix_name_camel {
const DISCRIMINATOR: [u8; 8] = #sighash_tts;
const DISCRIMINATOR: &'static [u8] = &#discriminator;
}
impl anchor_lang::InstructionData for #ix_name_camel {}
impl anchor_lang::Owner for #ix_name_camel {
Expand Down Expand Up @@ -72,7 +72,6 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
pub mod instruction {
use super::*;


#(#variants)*
}
}
Expand Down
4 changes: 2 additions & 2 deletions lang/tests/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn test_instruction_data() {
bar: String,
}
impl Discriminator for MyType {
const DISCRIMINATOR: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
const DISCRIMINATOR: &'static [u8] = &[1, 2, 3, 4, 5, 6, 7, 8];
}
impl InstructionData for MyType {}

Expand All @@ -25,7 +25,7 @@ fn test_instruction_data() {
instance.write_to(&mut write);

// Check that one is correct and that they are equal (implies other is correct)
let correct_disc = data[0..8] == MyType::DISCRIMINATOR;
let correct_disc = &data[0..8] == MyType::DISCRIMINATOR;
let correct_data = MyType::deserialize(&mut &data[8..]).is_ok_and(|result| result == instance);
let correct_serialization = correct_disc & correct_data;
assert!(correct_serialization, "serialization was not correct");
Expand Down
2 changes: 1 addition & 1 deletion spl/src/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ macro_rules! vote_weight_record {

#[cfg(feature = "idl-build")]
impl anchor_lang::Discriminator for VoterWeightRecord {
const DISCRIMINATOR: [u8; 8] = [0; 8];
const DISCRIMINATOR: &[u8] = &[];
}
};
}
2 changes: 1 addition & 1 deletion spl/src/idl_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ macro_rules! impl_idl_build {
//
// TODO: Find a better way to handle discriminators of wrapped external accounts.
impl anchor_lang::Discriminator for $ty {
const DISCRIMINATOR: [u8; 8] = [0; 8];
const DISCRIMINATOR: &[u8] = &[];
}
};
}
Expand Down

0 comments on commit 14cec14

Please sign in to comment.