idl.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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, constraint = 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(zero)]
  54. pub buffer: ProgramAccount<'info, IdlAccount>,
  55. #[account(signer, constraint = authority.key != &Pubkey::new_from_array([0u8; 32]))]
  56. pub authority: AccountInfo<'info>,
  57. }
  58. // Accounts for upgrading the canonical IdlAccount with the buffer.
  59. #[derive(Accounts)]
  60. pub struct IdlSetBuffer<'info> {
  61. // The buffer with the new idl data.
  62. #[account(mut, constraint = buffer.authority == idl.authority)]
  63. pub buffer: ProgramAccount<'info, IdlAccount>,
  64. // The idl account to be updated with the buffer's data.
  65. #[account(mut, has_one = authority)]
  66. pub idl: ProgramAccount<'info, IdlAccount>,
  67. #[account(signer, constraint = authority.key != &Pubkey::new_from_array([0u8; 32]))]
  68. pub authority: AccountInfo<'info>,
  69. }
  70. // The account holding a program's IDL. This is stored on chain so that clients
  71. // can fetch it and generate a client with nothing but a program's ID.
  72. //
  73. // Note: we use the same account for the "write buffer", similar to the
  74. // bpf upgradeable loader's mechanism.
  75. #[account("internal")]
  76. #[derive(Debug)]
  77. pub struct IdlAccount {
  78. // Address that can modify the IDL.
  79. pub authority: Pubkey,
  80. // Compressed idl bytes.
  81. pub data: Vec<u8>,
  82. }
  83. impl IdlAccount {
  84. pub fn address(program_id: &Pubkey) -> Pubkey {
  85. let program_signer = Pubkey::find_program_address(&[], program_id).0;
  86. Pubkey::create_with_seed(&program_signer, IdlAccount::seed(), program_id)
  87. .expect("Seed is always valid")
  88. }
  89. pub fn seed() -> &'static str {
  90. "anchor:idl"
  91. }
  92. }