2021-03-23 10:08:22 -07:00
|
|
|
//! idl.rs defines the instructions and account state used to store a program's
|
|
|
|
//! IDL on-chain at a canonical account address, which can be derived as a
|
|
|
|
//! function of nothing other than the program's ID.
|
2021-01-29 06:19:00 -08:00
|
|
|
//!
|
2021-03-23 10:08:22 -07:00
|
|
|
//! It can be upgraded in a way similar to a BPF upgradeable program. That is,
|
|
|
|
//! one may invoke the `IdlInstruction::CreateBuffer` instruction to create
|
|
|
|
//! a buffer, `IdlInstruction::Write` to write a new IDL into it, and then
|
|
|
|
//! `IdlInstruction::SetBuffer` to copy the IDL into the program's canonical
|
|
|
|
//! IDL account. In order to perform this upgrade, the buffer's `authority`
|
|
|
|
//! must match the canonical IDL account's authority.
|
2021-01-29 06:19:00 -08:00
|
|
|
//!
|
2021-03-23 10:08:22 -07:00
|
|
|
//! Because the IDL can be larger than the max transaction size, the transaction
|
|
|
|
//! must be broken up into several pieces and stored into the IDL account with
|
|
|
|
//! multiple transactions via the `Write` instruction to continuously append to
|
|
|
|
//! the account's IDL data buffer.
|
|
|
|
//!
|
|
|
|
//! Note that IDL account instructions are automatically inserted into all
|
|
|
|
//! Anchor programs. To remove them, one can use the `no-idl` feature.
|
2021-01-29 06:19:00 -08:00
|
|
|
|
|
|
|
use crate::prelude::*;
|
|
|
|
use solana_program::pubkey::Pubkey;
|
|
|
|
|
|
|
|
// The first 8 bytes of an instruction to create or modify the IDL account. This
|
|
|
|
// instruction is defined outside the main program's instruction enum, so that
|
|
|
|
// the enum variant tags can align with function source order.
|
|
|
|
//
|
|
|
|
// Sha256(anchor:idl)[..8];
|
|
|
|
pub const IDL_IX_TAG: u64 = 0x0a69e9a778bcf440;
|
|
|
|
|
|
|
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
|
pub enum IdlInstruction {
|
|
|
|
// One time initializer for creating the program's idl account.
|
|
|
|
Create { data_len: u64 },
|
2021-03-12 12:43:26 -08:00
|
|
|
// Creates a new IDL account buffer. Can be called several times.
|
|
|
|
CreateBuffer,
|
|
|
|
// Appends the given data to the end of the idl account buffer.
|
2021-01-29 06:19:00 -08:00
|
|
|
Write { data: Vec<u8> },
|
2021-03-12 12:43:26 -08:00
|
|
|
// Sets a new data buffer for the IdlAccount.
|
|
|
|
SetBuffer,
|
2021-01-29 06:19:00 -08:00
|
|
|
// Sets a new authority on the IdlAccount.
|
|
|
|
SetAuthority { new_authority: Pubkey },
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accounts for the Create instuction.
|
|
|
|
pub type IdlCreateAccounts<'info> = crate::ctor::Ctor<'info>;
|
|
|
|
|
|
|
|
// Accounts for Idl instructions.
|
|
|
|
#[derive(Accounts)]
|
|
|
|
pub struct IdlAccounts<'info> {
|
|
|
|
#[account(mut, has_one = authority)]
|
|
|
|
pub idl: ProgramAccount<'info, IdlAccount>,
|
2021-01-31 03:07:52 -08:00
|
|
|
#[account(signer, "authority.key != &Pubkey::new_from_array([0u8; 32])")]
|
2021-01-29 06:19:00 -08:00
|
|
|
pub authority: AccountInfo<'info>,
|
|
|
|
}
|
|
|
|
|
2021-03-12 12:43:26 -08:00
|
|
|
// Accounts for creating an idl buffer.
|
|
|
|
#[derive(Accounts)]
|
|
|
|
pub struct IdlCreateBuffer<'info> {
|
|
|
|
#[account(init)]
|
|
|
|
pub buffer: ProgramAccount<'info, IdlAccount>,
|
|
|
|
#[account(signer, "authority.key != &Pubkey::new_from_array([0u8; 32])")]
|
|
|
|
pub authority: AccountInfo<'info>,
|
|
|
|
pub rent: Sysvar<'info, Rent>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accounts for upgrading the canonical IdlAccount with the buffer.
|
|
|
|
#[derive(Accounts)]
|
|
|
|
pub struct IdlSetBuffer<'info> {
|
|
|
|
// The buffer with the new idl data.
|
|
|
|
#[account(mut, "buffer.authority == idl.authority")]
|
|
|
|
pub buffer: ProgramAccount<'info, IdlAccount>,
|
|
|
|
// The idl account to be updated with the buffer's data.
|
|
|
|
#[account(mut, has_one = authority)]
|
|
|
|
pub idl: ProgramAccount<'info, IdlAccount>,
|
|
|
|
#[account(signer, "authority.key != &Pubkey::new_from_array([0u8; 32])")]
|
|
|
|
pub authority: AccountInfo<'info>,
|
|
|
|
}
|
|
|
|
|
2021-01-29 06:19:00 -08:00
|
|
|
// The account holding a program's IDL. This is stored on chain so that clients
|
|
|
|
// can fetch it and generate a client with nothing but a program's ID.
|
2021-03-12 12:43:26 -08:00
|
|
|
//
|
|
|
|
// Note: we use the same account for the "write buffer", similar to the
|
|
|
|
// bpf upgradeable loader's mechanism.
|
2021-01-29 06:19:00 -08:00
|
|
|
#[account]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct IdlAccount {
|
|
|
|
// Address that can modify the IDL.
|
|
|
|
pub authority: Pubkey,
|
|
|
|
// Compressed idl bytes.
|
|
|
|
pub data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IdlAccount {
|
|
|
|
pub fn address(program_id: &Pubkey) -> Pubkey {
|
|
|
|
let program_signer = Pubkey::find_program_address(&[], program_id).0;
|
|
|
|
Pubkey::create_with_seed(&program_signer, IdlAccount::seed(), program_id)
|
|
|
|
.expect("Seed is always valid")
|
|
|
|
}
|
|
|
|
pub fn seed() -> &'static str {
|
|
|
|
"anchor:idl"
|
|
|
|
}
|
|
|
|
}
|