-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathidl.rs
105 lines (96 loc) · 4.02 KB
/
idl.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! 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.
//!
//! 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.
//!
//! 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.
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 },
// Creates a new IDL account buffer. Can be called several times.
CreateBuffer,
// Appends the given data to the end of the idl account buffer.
Write { data: Vec<u8> },
// Sets a new data buffer for the IdlAccount.
SetBuffer,
// Sets a new authority on the IdlAccount.
SetAuthority { new_authority: Pubkey },
}
// Accounts for the Create instruction.
pub type IdlCreateAccounts<'info> = crate::ctor::Ctor<'info>;
// Accounts for Idl instructions.
#[derive(Accounts)]
pub struct IdlAccounts<'info> {
#[account(mut, has_one = authority)]
#[allow(deprecated)]
pub idl: ProgramAccount<'info, IdlAccount>,
#[account(signer, constraint = authority.key != &Pubkey::new_from_array([0u8; 32]))]
pub authority: AccountInfo<'info>,
}
// Accounts for creating an idl buffer.
#[derive(Accounts)]
pub struct IdlCreateBuffer<'info> {
#[account(zero)]
#[allow(deprecated)]
pub buffer: ProgramAccount<'info, IdlAccount>,
#[account(signer, constraint = authority.key != &Pubkey::new_from_array([0u8; 32]))]
pub authority: AccountInfo<'info>,
}
// Accounts for upgrading the canonical IdlAccount with the buffer.
#[derive(Accounts)]
pub struct IdlSetBuffer<'info> {
// The buffer with the new idl data.
#[account(mut, constraint = buffer.authority == idl.authority)]
#[allow(deprecated)]
pub buffer: ProgramAccount<'info, IdlAccount>,
// The idl account to be updated with the buffer's data.
#[account(mut, has_one = authority)]
#[allow(deprecated)]
pub idl: ProgramAccount<'info, IdlAccount>,
#[account(signer, constraint = authority.key != &Pubkey::new_from_array([0u8; 32]))]
pub authority: AccountInfo<'info>,
}
// 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.
//
// Note: we use the same account for the "write buffer", similar to the
// bpf upgradeable loader's mechanism.
#[account("internal")]
#[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"
}
}