4

Is it possible to set the 8-byte discriminator on an Anchor account manually?

I'm trying to initialize a new pda account in an instruction, but not all of the seeds are available in the context (can't use instruction(...) macro to get seed either). I still want to initialize the account as an Anchor #[account] though, so that I can access it in subsequent instructions.

Basic program setup:

#[account]
pub struct MyAccount {...}

#[derive(Accounts)]
pub struct InitIx<'info> {
  ...
  #[account(mut)]
  pub my_account: UncheckedAccount<'info>,
  ...
}

#[derive(Accounts)]
pub struct InitIxWrapper<'info> {
  ...
  init_ix: InitIx<'info>,
  some_pubkey: UncheckedAccount<'info>,
  ...
}

#[derive(Accounts)]
pub struct OtherIx<'info> {
  ...
  my_account: Account<'info, MyAccount>,
  ...
}

// The global instruction
pub fn init_ix_wrapper(ctx: Context<InitIxWrapper>) -> Result<()> {
  ...
  // local ix for processing
  local::inix_ix(
    Context::new(
     ...
     ctx.accounts.init_ix,
     ...
    ),
    ctx.accounts.some_pubkey.key
  )?;
  ...
}

pub fn other_ix(ctx: Context<OtherIx>) -> Result<()> {
  // access data from my_account like usual
}

I would like the local ix to do something like the following:

pub fn init_ix(ctx: Context<InitIx>, my_account_seed: &Pubkey) -> Result<()> {
  // assert derivation of my_account key using my_account_seed
  // manually initialize account (solana create_account ix)
  // manually set discriminator for MyAccount and write to my_account.data
  // write relevant remaining data to my_account.data
}

If manually setting discriminator is not possible, then can someone please direct me to a different way to accomplish what I want given my program structure?

5 Answers 5

8

if you have an account like this:

#[account]
pub struct State {}

then you can call the discriminator static method like &State::discriminator() by importing the trait manually like use anchor_lang::Discriminator;

2

Not sure if this is exactly answering your question but there is a Discriminator trait you can implement.

1
  • It seems that the #[account] attribute already implements the Discriminator trait. Do you know how to call the discriminator() function for a specific account?
    – nibbus
    Commented Jul 29, 2022 at 22:45
2

As hana said, you can get the discriminator for an account using MyAccount::discriminator(); so long as you import anchor_lang::Discriminator into your source file.

Then you can write the account data like so:

let my_account_data = MyAccount {...};
let discriminator = MyAccount::discriminator();
let write_data = (discriminator, my_account_data.clone());
write_data.serialize(&mut *ctx.accounts.my_account.try_borrow_mut_data()?)?;
1

tl;dr: No, you can't, but you can derive the discriminator if you know the function/state name, which is usually good enough.

The discriminator is the first 8 bytes of the sha256 hash of the context and the struct name in the format "namespace:name", in snake_case. Same thing for functions. You can use any sha256 generation tool or get it like so:

pub fn get_hash(namespace: &str, name: &str) -> [u8; 8] {
    let preimage = format!("{}:{}", namespace, name);
    let mut sighash = [0u8; 8];
    sighash.copy_from_slice(
        &anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()
            [..8],
    );
    sighash
}

Where the namespace for your struct is probably "state" or "global".

So you COULD try different names (or rename the context the function is in) until you get a certain discriminator, but it will take a very long time to brute force a collision for the first 8 bytes of sha256 since it's essentially completely random.

It sounds like the function above should work for you, since you can derive the discriminator.

0

You'd first have to bring the Discriminator trait into scope with use anchor_lang::Discriminator;

Then your code would be:

let discriminator = MyAccount::discriminator();
discriminator.serialize(&mut &mut my_account_info.data.borrow_mut()[..8])?;

where MyAccount is your Anchor-defined data structure

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.