1

So let's imagine I have a program my_program with an instruction do_something. Given an ix:

let ix: solana_program::instruction::Instruction = ...

with ix.program_id equal to my_program::id(), how can I check if this instruction is do_something or not?

1
  • can install cargo expand and expand all the macros , u will see all the account and ixs discriminaors Commented Oct 3 at 10:51

2 Answers 2

2

As part of macros expansion Anchor generates the following code for your program's instructions:

pub mod instruction {
    /// Instruction.
    pub struct DoSomething {
        pub args: DoSomethingArgs,
    }

    // ...

    impl anchor_lang::Discriminator for DoSomething {
        const DISCRIMINATOR: [u8; 8] = [122, 77, 80, 159, 84, 88, 90, 197];
    }

    // ...

So by checking the first 8 bytes of ix.data and comparing them to the Anchor discriminator of do_something you can tell if this instruction is meant to be processed by do_something or not.

// NOTE: This line is required.
use anchor_lang::Discriminator;

// ...

let is_do_something_ix = ix.data[..8] == crate::instruction::DoSomething::DISCRIMINATOR
1

Anchor uses the sha256 of "namespace":"function_name" as a function identifier. When you are creating your instruction:

    let instruction = Instruction {
        program_id, // whatever the program key is
        accounts: vec![
            AccountMeta::new(ctx.accounts.whatever.key(), false),
        ],
        data: get_function_hash("global", "do_something").to_vec(),
    };

pub fn get_function_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
}

If the instruction also has args, you would need to serialize them and append them to the buffer for the function hash, e.g.

#[derive(AnchorSerialize, AnchorDeserialize)]
struct CpiArgs {
    bump: u8,
}

fn get_ix_data(bump: u8, amount: Amount) -> Vec<u8> {
    let hash = get_function_hash("global", "do_something");
    let mut buf: Vec<u8> = vec![];
    buf.extend_from_slice(&hash);
    let args = CpiArgs { bump };
    args.serialize(&mut buf).unwrap();
    buf
}

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