idl.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. //! Defines the instructions and account state used to store a program's
  2. //! IDL on-chain at a canonical account address, which can be derived as a
  3. //! function of nothing other than the program's ID.
  4. //!
  5. //! It can be upgraded in a way similar to a BPF upgradeable program. That is,
  6. //! one may invoke the `IdlInstruction::CreateBuffer` instruction to create
  7. //! a buffer, `IdlInstruction::Write` to write a new IDL into it, and then
  8. //! `IdlInstruction::SetBuffer` to copy the IDL into the program's canonical
  9. //! IDL account. In order to perform this upgrade, the buffer's `authority`
  10. //! must match the canonical IDL account's authority.
  11. //!
  12. //! Because the IDL can be larger than the max transaction size, the transaction
  13. //! must be broken up into several pieces and stored into the IDL account with
  14. //! multiple transactions via the `Write` instruction to continuously append to
  15. //! the account's IDL data buffer.
  16. //!
  17. //! Note that IDL account instructions are automatically inserted into all
  18. //! Anchor programs. To remove them, one can use the `no-idl` feature.
  19. use crate::prelude::*;
  20. use solana_program::pubkey::Pubkey;
  21. // The first 8 bytes of an instruction to create or modify the IDL account. This
  22. // instruction is defined outside the main program's instruction enum, so that
  23. // the enum variant tags can align with function source order.
  24. //
  25. // Sha256(anchor:idl)[..8];
  26. pub const IDL_IX_TAG: u64 = 0x0a69e9a778bcf440;
  27. #[derive(AnchorSerialize, AnchorDeserialize)]
  28. pub enum IdlInstruction {
  29. // One time initializer for creating the program's idl account.
  30. Create { data_len: u64 },
  31. // Creates a new IDL account buffer. Can be called several times.
  32. CreateBuffer,
  33. // Appends the given data to the end of the idl account buffer.
  34. Write { data: Vec<u8> },
  35. // Sets a new data buffer for the IdlAccount.
  36. SetBuffer,
  37. // Sets a new authority on the IdlAccount.
  38. SetAuthority { new_authority: Pubkey },
  39. }
  40. // Accounts for the Create instruction.
  41. pub type IdlCreateAccounts<'info> = crate::ctor::Ctor<'info>;
  42. // Accounts for Idl instructions.
  43. #[derive(Accounts)]
  44. pub struct IdlAccounts<'info> {
  45. #[account(mut, has_one = authority)]
  46. pub idl: ProgramAccount<'info, IdlAccount>,
  47. #[account(signer, "authority.key != &Pubkey::new_from_array([0u8; 32])")]
  48. pub authority: AccountInfo<'info>,
  49. }
  50. // Accounts for creating an idl buffer.
  51. #[derive(Accounts)]
  52. pub struct IdlCreateBuffer<'info> {
  53. #[account(init)]
  54. pub buffer: ProgramAccount<'info, IdlAccount>,
  55. #[account(signer, "authority.key != &Pubkey::new_from_array([0u8; 32])")]
  56. pub authority: AccountInfo<'info>,
  57. pub rent: Sysvar<'info, Rent>,
  58. }
  59. // Accounts for upgrading the canonical IdlAccount with the buffer.
  60. #[derive(Accounts)]
  61. pub struct IdlSetBuffer<'info> {
  62. // The buffer with the new idl data.
  63. #[account(mut, "buffer.authority == idl.authority")]
  64. pub buffer: ProgramAccount<'info, IdlAccount>,
  65. // The idl account to be updated with the buffer's data.
  66. #[account(mut, has_one = authority)]
  67. pub idl: ProgramAccount<'info, IdlAccount>,
  68. #[account(signer, "authority.key != &Pubkey::new_from_array([0u8; 32])")]
  69. pub authority: AccountInfo<'info>,
  70. }
  71. // The account holding a program's IDL. This is stored on chain so that clients
  72. // can fetch it and generate a client with nothing but a program's ID.
  73. //
  74. // Note: we use the same account for the "write buffer", similar to the
  75. // bpf upgradeable loader's mechanism.
  76. #[account("internal")]
  77. #[derive(Debug)]
  78. pub struct IdlAccount {
  79. // Address that can modify the IDL.
  80. pub authority: Pubkey,
  81. // Compressed idl bytes.
  82. pub data: Vec<u8>,
  83. }
  84. impl IdlAccount {
  85. pub fn address(program_id: &Pubkey) -> Pubkey {
  86. let program_signer = Pubkey::find_program_address(&[], program_id).0;
  87. Pubkey::create_with_seed(&program_signer, IdlAccount::seed(), program_id)
  88. .expect("Seed is always valid")
  89. }
  90. pub fn seed() -> &'static str {
  91. "anchor:idl"
  92. }
  93. }