Skip to content

feat request: add a trait to serialize instruction data #109

Open
@publicqi

Description

@publicqi

right now all instructions are wrapped behind structs, and instruction data are mostly inside implementation inside invoke_signed.

we can add a trait to export/serialize these instructions.

there're two benefits for this:

  1. we can easily test against other libraries (e.g. solana-program, anchor, etc.) to see if our pinocchio instruction has the same results
  2. developers may have more control over the instruction data (not common but may be useful for some hacky stuff)

a draft interface:

pub trait IxSerialize {
    fn to_ix_data(&self) -> Box<[u8]>;
}

// For e.g. construction of transaction
impl IxSerialize for Transfer<'_> {
    fn to_ix_data(&self) -> Box<[u8]> {
        self.to_ix_data()
    }
}

and an example impl of token::transfer

impl Transfer<'_> {
    #[inline(always)]
    pub fn invoke(&self) -> ProgramResult {
        self.invoke_signed(&[])
    }

    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
        // account metadata
        let account_metas: [AccountMeta; 3] = [
            AccountMeta::writable(self.from.key()),
            AccountMeta::writable(self.to.key()),
            AccountMeta::readonly_signer(self.authority.key()),
        ];

        let instruction_data = self.to_ix_data();

        let instruction = Instruction {
            program_id: &crate::ID,
            accounts: &account_metas,
            data: &instruction_data,
        };

        invoke_signed(&instruction, &[self.from, self.to, self.authority], signers)
    }

    fn to_ix_data(&self) -> Box<[u8]> {
        // Instruction data layout:
        // -  [0]: instruction discriminator (1 byte, u8)
        // -  [1..9]: amount (8 bytes, u64)
        let mut instruction_data = Box::new_uninit_slice(9);

        // Set discriminator as u8 at offset [0]
        write_bytes(&mut instruction_data, &[3]);
        // Set amount as u64 at offset [1..9]
        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());

        unsafe { instruction_data.assume_init() }
    }
}

impl<'a> IxSerialize for Transfer<'a> {
    fn to_ix_data(&self) -> Box<[u8]> {
        self.to_ix_data()
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions