From 360947fcc3571d9d11b5841f9252575787162be4 Mon Sep 17 00:00:00 2001 From: henrye Date: Fri, 20 Jan 2023 10:33:51 +0000 Subject: [PATCH 01/13] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80460fff17..fc47c2d740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The minor version will be incremented upon a breaking change and the patch versi - cli: Don't regenerate idl in read_all_programs(). ([#2332](https://github.com/coral-xyz/anchor/pull/2332)). - ts: `provider.simulate` will send the transaction with `sigVerify: false` if no `signers` are present ([#2331](https://github.com/coral-xyz/anchor/pull/2331)). +- idl: Update the IDL program to use non-deprecated account types ([#2365](https://github.com/coral-xyz/anchor/pull/2365)). ### Breaking From f928549dc51be6d0f742cadcd3418c8f3397ff2d Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 10:36:23 +0000 Subject: [PATCH 02/13] move idl into match statment; move error that was never reached --- lang/syn/src/codegen/program/dispatch.rs | 24 +++++++++++++----------- lang/syn/src/codegen/program/handlers.rs | 6 ------ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/lang/syn/src/codegen/program/dispatch.rs b/lang/syn/src/codegen/program/dispatch.rs index c0bf87b627..9ecfbaaabd 100644 --- a/lang/syn/src/codegen/program/dispatch.rs +++ b/lang/syn/src/codegen/program/dispatch.rs @@ -61,21 +61,23 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { sighash }; - // If the method identifier is the IDL tag, then execute an IDL - // instruction, injected into all Anchor programs. - if cfg!(not(feature = "no-idl")) { - if sighash == anchor_lang::idl::IDL_IX_TAG.to_le_bytes() { - return __private::__idl::__idl_dispatch( - program_id, - accounts, - &ix_data, - ); - } - } use anchor_lang::Discriminator; match sighash { #(#global_dispatch_arms)* + anchor_lang::idl::IDL_IX_TAG.to_le_bytes() => { + // If the method identifier is the IDL tag, then execute an IDL + // instruction, injected into all Anchor programs. + if cfg!(not(feature = "no-idl")) { + __private::__idl::__idl_dispatch( + program_id, + accounts, + &ix_data, + ) + } else { + Err(anchor_lang::error::ErrorCode::IdlInstructionStub.into()) + } + } _ => { #fallback_fn } diff --git a/lang/syn/src/codegen/program/handlers.rs b/lang/syn/src/codegen/program/handlers.rs index 990a617611..eadda5d532 100644 --- a/lang/syn/src/codegen/program/handlers.rs +++ b/lang/syn/src/codegen/program/handlers.rs @@ -84,12 +84,6 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { Ok(()) } - #[inline(never)] - #[cfg(feature = "no-idl")] - pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> anchor_lang::Result<()> { - Err(anchor_lang::error::ErrorCode::IdlInstructionStub.into()) - } - // One time IDL account initializer. Will faill on subsequent // invocations. #[inline(never)] From d90e4a0318eb932bd542ab2b9f26f605caae543b Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 10:57:20 +0000 Subject: [PATCH 03/13] fix compile issue --- lang/src/idl.rs | 1 + lang/syn/src/codegen/program/dispatch.rs | 2 +- lang/syn/src/codegen/program/handlers.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lang/src/idl.rs b/lang/src/idl.rs index bcb3d521a4..b1e3492c3e 100644 --- a/lang/src/idl.rs +++ b/lang/src/idl.rs @@ -28,6 +28,7 @@ use solana_program::pubkey::Pubkey; // // Sha256(anchor:idl)[..8]; pub const IDL_IX_TAG: u64 = 0x0a69e9a778bcf440; +pub const IDL_IX_TAG_LE: [u8; 8] = IDL_IX_TAG.to_le_bytes(); // The Pubkey that is stored as the 'authority' on the IdlAccount when the authority // is "erased". diff --git a/lang/syn/src/codegen/program/dispatch.rs b/lang/syn/src/codegen/program/dispatch.rs index 9ecfbaaabd..dac9015082 100644 --- a/lang/syn/src/codegen/program/dispatch.rs +++ b/lang/syn/src/codegen/program/dispatch.rs @@ -65,7 +65,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { use anchor_lang::Discriminator; match sighash { #(#global_dispatch_arms)* - anchor_lang::idl::IDL_IX_TAG.to_le_bytes() => { + anchor_lang::idl::IDL_IX_TAG_LE => { // If the method identifier is the IDL tag, then execute an IDL // instruction, injected into all Anchor programs. if cfg!(not(feature = "no-idl")) { diff --git a/lang/syn/src/codegen/program/handlers.rs b/lang/syn/src/codegen/program/handlers.rs index eadda5d532..c161c7294b 100644 --- a/lang/syn/src/codegen/program/handlers.rs +++ b/lang/syn/src/codegen/program/handlers.rs @@ -84,7 +84,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { Ok(()) } - // One time IDL account initializer. Will faill on subsequent + // One time IDL account initializer. Will fail on subsequent // invocations. #[inline(never)] pub fn __idl_create_account( From d7f0b241a179b4b41ef3962869dc6f53cbf7b1db Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 12:08:35 +0000 Subject: [PATCH 04/13] move over accounts and functions to new file --- lang/src/idl.rs | 114 ++------- lang/syn/src/codegen/program/handlers.rs | 197 +-------------- lang/syn/src/codegen/program/idl.rs | 300 +++++++++++++++++++++++ lang/syn/src/codegen/program/mod.rs | 1 + 4 files changed, 322 insertions(+), 290 deletions(-) create mode 100644 lang/syn/src/codegen/program/idl.rs diff --git a/lang/src/idl.rs b/lang/src/idl.rs index b1e3492c3e..73a221eb7f 100644 --- a/lang/src/idl.rs +++ b/lang/src/idl.rs @@ -17,8 +17,6 @@ //! Note that IDL account instructions are automatically inserted into all //! Anchor programs. To remove them, one can use the `no-idl` feature. -#[allow(deprecated)] -use crate::accounts::program_account::ProgramAccount; use crate::prelude::*; use solana_program::pubkey::Pubkey; @@ -35,82 +33,21 @@ pub const IDL_IX_TAG_LE: [u8; 8] = IDL_IX_TAG.to_le_bytes(); pub const ERASED_AUTHORITY: Pubkey = Pubkey::new_from_array([0u8; 32]); #[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 }, - // Sets a new data buffer for the IdlAccount. - SetBuffer, - // Sets a new authority on the IdlAccount. - SetAuthority { new_authority: Pubkey }, - Close, - // Increases account size for accounts that need over 10kb. - Resize { data_len: u64 }, -} - -// 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(constraint = authority.key != &ERASED_AUTHORITY)] - pub authority: Signer<'info>, -} - -// Accounts for resize account instruction -#[derive(Accounts)] -pub struct IdlResizeAccount<'info> { - #[account(mut, has_one = authority)] - #[allow(deprecated)] - pub idl: ProgramAccount<'info, IdlAccount>, - #[account(mut, constraint = authority.key != &ERASED_AUTHORITY)] - pub authority: Signer<'info>, - pub system_program: Program<'info, System>, -} - -// Accounts for creating an idl buffer. -#[derive(Accounts)] -pub struct IdlCreateBuffer<'info> { - #[account(zero)] - #[allow(deprecated)] - pub buffer: ProgramAccount<'info, IdlAccount>, - #[account(constraint = authority.key != &ERASED_AUTHORITY)] - pub authority: Signer<'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(constraint = authority.key != &ERASED_AUTHORITY)] - pub authority: Signer<'info>, -} - -// Accounts for closing the canonical Idl buffer. -#[derive(Accounts)] -pub struct IdlCloseAccount<'info> { - #[account(mut, has_one = authority, close = sol_destination)] - #[allow(deprecated)] - pub account: ProgramAccount<'info, IdlAccount>, - #[account(constraint = authority.key != &ERASED_AUTHORITY)] - pub authority: Signer<'info>, - #[account(mut)] - pub sol_destination: AccountInfo<'info>, -} + 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 }, + // Sets a new data buffer for the IdlAccount. + SetBuffer, + // Sets a new authority on the IdlAccount. + SetAuthority { new_authority: Pubkey }, + Close, + // Increases account size for accounts that need over 10kb. + Resize { data_len: u64 }, + } // 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. @@ -136,23 +73,4 @@ impl IdlAccount { pub fn seed() -> &'static str { "anchor:idl" } -} - -use std::cell::{Ref, RefMut}; - -pub trait IdlTrailingData<'info> { - fn trailing_data(self) -> Ref<'info, [u8]>; - fn trailing_data_mut(self) -> RefMut<'info, [u8]>; -} - -#[allow(deprecated)] -impl<'a, 'info: 'a> IdlTrailingData<'a> for &'a ProgramAccount<'info, IdlAccount> { - fn trailing_data(self) -> Ref<'a, [u8]> { - let info = self.as_ref(); - Ref::map(info.try_borrow_data().unwrap(), |d| &d[44..]) - } - fn trailing_data_mut(self) -> RefMut<'a, [u8]> { - let info = self.as_ref(); - RefMut::map(info.try_borrow_mut_data().unwrap(), |d| &mut d[44..]) - } -} +} \ No newline at end of file diff --git a/lang/syn/src/codegen/program/handlers.rs b/lang/syn/src/codegen/program/handlers.rs index c161c7294b..6356d8762d 100644 --- a/lang/syn/src/codegen/program/handlers.rs +++ b/lang/syn/src/codegen/program/handlers.rs @@ -2,12 +2,16 @@ use crate::codegen::program::common::*; use crate::Program; use heck::CamelCase; use quote::{quote, ToTokens}; +use crate::program_codegen::idl::idl_accounts_and_functions; // Generate non-inlined wrappers for each instruction handler, since Solana's // BPF max stack size can't handle reasonable sized dispatch trees without doing // so. pub fn generate(program: &Program) -> proc_macro2::TokenStream { let program_name = &program.name; + // A constant token stream that stores the accounts and functions, required to live + // inside the target program in order to get the program ID. + let idl_accounts_and_functions = idl_accounts_and_functions(); let non_inlined_idl: proc_macro2::TokenStream = { quote! { // Entry for all IDL related instructions. Use the "no-idl" feature @@ -84,198 +88,6 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { Ok(()) } - // One time IDL account initializer. Will fail on subsequent - // invocations. - #[inline(never)] - pub fn __idl_create_account( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlCreateAccounts, - data_len: u64, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlCreateAccount"); - - if program_id != accounts.program.key { - return Err(anchor_lang::error::ErrorCode::IdlInstructionInvalidProgram.into()); - } - // Create the IDL's account. - let from = accounts.from.key; - let (base, nonce) = Pubkey::find_program_address(&[], program_id); - let seed = anchor_lang::idl::IdlAccount::seed(); - let owner = accounts.program.key; - let to = Pubkey::create_with_seed(&base, seed, owner).unwrap(); - // Space: account discriminator || authority pubkey || vec len || vec data - let space = std::cmp::min(8 + 32 + 4 + data_len as usize, 10_000); - let rent = Rent::get()?; - let lamports = rent.minimum_balance(space); - let seeds = &[&[nonce][..]]; - let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed( - from, - &to, - &base, - seed, - lamports, - space as u64, - owner, - ); - anchor_lang::solana_program::program::invoke_signed( - &ix, - &[ - accounts.from.clone(), - accounts.to.clone(), - accounts.base.clone(), - accounts.system_program.clone(), - ], - &[seeds], - )?; - - // Deserialize the newly created account. - let mut idl_account = { - let mut account_data = accounts.to.try_borrow_data()?; - let mut account_data_slice: &[u8] = &account_data; - anchor_lang::idl::IdlAccount::try_deserialize_unchecked( - &mut account_data_slice, - )? - }; - - // Set the authority. - idl_account.authority = *accounts.from.key; - - // Store the new account data. - let mut data = accounts.to.try_borrow_mut_data()?; - let dst: &mut [u8] = &mut data; - let mut cursor = std::io::Cursor::new(dst); - idl_account.try_serialize(&mut cursor)?; - - Ok(()) - } - - #[inline(never)] - pub fn __idl_resize_account( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlResizeAccount, - data_len: u64, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlResizeAccount"); - - let data_len: usize = data_len as usize; - - // We're not going to support increasing the size of accounts that already contain data - // because that would be messy and possibly dangerous - if accounts.idl.data_len != 0 { - return Err(anchor_lang::error::ErrorCode::IdlAccountNotEmpty.into()); - } - - let new_account_space = accounts.idl.to_account_info().data_len().checked_add(std::cmp::min( - data_len - .checked_sub(accounts.idl.to_account_info().data_len()) - .expect("data_len should always be >= the current account space"), - 10_000, - )) - .unwrap(); - - if new_account_space > accounts.idl.to_account_info().data_len() { - let sysvar_rent = Rent::get()?; - let new_rent_minimum = sysvar_rent.minimum_balance(new_account_space); - anchor_lang::system_program::transfer( - anchor_lang::context::CpiContext::new( - accounts.system_program.to_account_info(), - anchor_lang::system_program::Transfer { - from: accounts.authority.to_account_info(), - to: accounts.idl.to_account_info().clone(), - }, - ), - new_rent_minimum - .checked_sub(accounts.idl.to_account_info().lamports()) - .unwrap(), - )?; - accounts.idl.to_account_info().realloc(new_account_space, false)?; - } - - Ok(()) - - } - - #[inline(never)] - pub fn __idl_close_account( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlCloseAccount, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlCloseAccount"); - - Ok(()) - } - - #[inline(never)] - pub fn __idl_create_buffer( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlCreateBuffer, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlCreateBuffer"); - - let mut buffer = &mut accounts.buffer; - buffer.authority = *accounts.authority.key; - Ok(()) - } - - #[inline(never)] - pub fn __idl_write( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlAccounts, - idl_data: Vec, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlWrite"); - - let prev_len: usize = ::std::convert::TryInto::::try_into(accounts.idl.data_len).unwrap(); - let new_len: usize = prev_len + idl_data.len(); - accounts.idl.data_len = accounts.idl.data_len.checked_add(::std::convert::TryInto::::try_into(idl_data.len()).unwrap()).unwrap(); - - use anchor_lang::idl::IdlTrailingData; - let mut idl_bytes = accounts.idl.trailing_data_mut(); - let idl_expansion = &mut idl_bytes[prev_len..new_len]; - require_eq!(idl_expansion.len(), idl_data.len()); - idl_expansion.copy_from_slice(&idl_data[..]); - - Ok(()) - } - - #[inline(never)] - pub fn __idl_set_authority( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlAccounts, - new_authority: Pubkey, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlSetAuthority"); - - accounts.idl.authority = new_authority; - Ok(()) - } - - #[inline(never)] - pub fn __idl_set_buffer( - program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlSetBuffer, - ) -> anchor_lang::Result<()> { - #[cfg(not(feature = "no-log-ix-name"))] - anchor_lang::prelude::msg!("Instruction: IdlSetBuffer"); - - accounts.idl.data_len = accounts.buffer.data_len; - - use anchor_lang::idl::IdlTrailingData; - let buffer_len = ::std::convert::TryInto::::try_into(accounts.buffer.data_len).unwrap(); - let mut target = accounts.idl.trailing_data_mut(); - let source = &accounts.buffer.trailing_data()[..buffer_len]; - require_gte!(target.len(), buffer_len); - target[..buffer_len].copy_from_slice(source); - // zero the remainder of target? - - Ok(()) - } } }; @@ -358,6 +170,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { use super::*; #non_inlined_idl + #idl_accounts_and_functions } diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs new file mode 100644 index 0000000000..ac51ba1e34 --- /dev/null +++ b/lang/syn/src/codegen/program/idl.rs @@ -0,0 +1,300 @@ +use quote::quote; + +pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { + quote!{ + use anchor_lang::idl::ERASED_AUTHORITY; + + // Accounts for the Create instruction. + #[derive(Accounts)] + pub struct IdlCreateAccounts<'info> { + // Payer of the transaction. + pub from: Signer<'info>, + // The deterministically defined "state" account being created via + // `create_account_with_seed`. + #[account(mut)] + pub to: SystemAccount<'info>, + // The program-derived-address signing off on the account creation. + // Seeds = &[] + bump seed. + #[account(seeds = [])] + pub base: SystemAccount<'info>, + // The system program. + pub system_program: Program<'info, System>, + // The program whose state is being constructed. + #[account(executable)] + pub program: AccountInfo<'info>, + } + + + // Accounts for Idl instructions. + #[derive(Accounts)] + pub struct IdlAccounts<'info> { + #[account(mut, has_one = authority)] + #[allow(deprecated)] + pub idl: ProgramAccount<'info, IdlAccount>, + #[account(constraint = authority.key != &ERASED_AUTHORITY)] + pub authority: Signer<'info>, + } + + // Accounts for resize account instruction + #[derive(Accounts)] + pub struct IdlResizeAccount<'info> { + #[account(mut, has_one = authority)] + #[allow(deprecated)] + pub idl: ProgramAccount<'info, IdlAccount>, + #[account(mut, constraint = authority.key != &ERASED_AUTHORITY)] + pub authority: Signer<'info>, + pub system_program: Program<'info, System>, + } + + // Accounts for creating an idl buffer. + #[derive(Accounts)] + pub struct IdlCreateBuffer<'info> { + #[account(zero)] + #[allow(deprecated)] + pub buffer: ProgramAccount<'info, IdlAccount>, + #[account(constraint = authority.key != &ERASED_AUTHORITY)] + pub authority: Signer<'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(constraint = authority.key != &ERASED_AUTHORITY)] + pub authority: Signer<'info>, + } + + // Accounts for closing the canonical Idl buffer. + #[derive(Accounts)] + pub struct IdlCloseAccount<'info> { + #[account(mut, has_one = authority, close = sol_destination)] + #[allow(deprecated)] + pub account: ProgramAccount<'info, IdlAccount>, + #[account(constraint = authority.key != &ERASED_AUTHORITY)] + pub authority: Signer<'info>, + #[account(mut)] + pub sol_destination: AccountInfo<'info>, + } + + + use std::cell::{Ref, RefMut}; + + pub trait IdlTrailingData<'info> { + fn trailing_data(self) -> Ref<'info, [u8]>; + fn trailing_data_mut(self) -> RefMut<'info, [u8]>; + } + + #[allow(deprecated)] + impl<'a, 'info: 'a> IdlTrailingData<'a> for &'a ProgramAccount<'info, IdlAccount> { + fn trailing_data(self) -> Ref<'a, [u8]> { + let info = self.as_ref(); + Ref::map(info.try_borrow_data().unwrap(), |d| &d[44..]) + } + fn trailing_data_mut(self) -> RefMut<'a, [u8]> { + let info = self.as_ref(); + RefMut::map(info.try_borrow_mut_data().unwrap(), |d| &mut d[44..]) + } + } + + + // One time IDL account initializer. Will fail on subsequent + // invocations. + #[inline(never)] + pub fn __idl_create_account( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlCreateAccounts, + data_len: u64, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlCreateAccount"); + + if program_id != accounts.program.key { + return Err(anchor_lang::error::ErrorCode::IdlInstructionInvalidProgram.into()); + } + // Create the IDL's account. + let from = accounts.from.key; + let (base, nonce) = Pubkey::find_program_address(&[], program_id); + let seed = anchor_lang::idl::IdlAccount::seed(); + let owner = accounts.program.key; + let to = Pubkey::create_with_seed(&base, seed, owner).unwrap(); + // Space: account discriminator || authority pubkey || vec len || vec data + let space = std::cmp::min(8 + 32 + 4 + data_len as usize, 10_000); + let rent = Rent::get()?; + let lamports = rent.minimum_balance(space); + let seeds = &[&[nonce][..]]; + let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed( + from, + &to, + &base, + seed, + lamports, + space as u64, + owner, + ); + anchor_lang::solana_program::program::invoke_signed( + &ix, + &[ + accounts.from.clone(), + accounts.to.clone(), + accounts.base.clone(), + accounts.system_program.clone(), + ], + &[seeds], + )?; + + // Deserialize the newly created account. + let mut idl_account = { + let mut account_data = accounts.to.try_borrow_data()?; + let mut account_data_slice: &[u8] = &account_data; + anchor_lang::idl::IdlAccount::try_deserialize_unchecked( + &mut account_data_slice, + )? + }; + + // Set the authority. + idl_account.authority = *accounts.from.key; + + // Store the new account data. + let mut data = accounts.to.try_borrow_mut_data()?; + let dst: &mut [u8] = &mut data; + let mut cursor = std::io::Cursor::new(dst); + idl_account.try_serialize(&mut cursor)?; + + Ok(()) + } + + #[inline(never)] + pub fn __idl_resize_account( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlResizeAccount, + data_len: u64, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlResizeAccount"); + + let data_len: usize = data_len as usize; + + // We're not going to support increasing the size of accounts that already contain data + // because that would be messy and possibly dangerous + if accounts.idl.data_len != 0 { + return Err(anchor_lang::error::ErrorCode::IdlAccountNotEmpty.into()); + } + + let new_account_space = accounts.idl.to_account_info().data_len().checked_add(std::cmp::min( + data_len + .checked_sub(accounts.idl.to_account_info().data_len()) + .expect("data_len should always be >= the current account space"), + 10_000, + )) + .unwrap(); + + if new_account_space > accounts.idl.to_account_info().data_len() { + let sysvar_rent = Rent::get()?; + let new_rent_minimum = sysvar_rent.minimum_balance(new_account_space); + anchor_lang::system_program::transfer( + anchor_lang::context::CpiContext::new( + accounts.system_program.to_account_info(), + anchor_lang::system_program::Transfer { + from: accounts.authority.to_account_info(), + to: accounts.idl.to_account_info().clone(), + }, + ), + new_rent_minimum + .checked_sub(accounts.idl.to_account_info().lamports()) + .unwrap(), + )?; + accounts.idl.to_account_info().realloc(new_account_space, false)?; + } + + Ok(()) + + } + + #[inline(never)] + pub fn __idl_close_account( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlCloseAccount, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlCloseAccount"); + + Ok(()) + } + + #[inline(never)] + pub fn __idl_create_buffer( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlCreateBuffer, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlCreateBuffer"); + + let mut buffer = &mut accounts.buffer; + buffer.authority = *accounts.authority.key; + Ok(()) + } + + #[inline(never)] + pub fn __idl_write( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlAccounts, + idl_data: Vec, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlWrite"); + + let prev_len: usize = ::std::convert::TryInto::::try_into(accounts.idl.data_len).unwrap(); + let new_len: usize = prev_len + idl_data.len(); + accounts.idl.data_len = accounts.idl.data_len.checked_add(::std::convert::TryInto::::try_into(idl_data.len()).unwrap()).unwrap(); + + use anchor_lang::idl::IdlTrailingData; + let mut idl_bytes = accounts.idl.trailing_data_mut(); + let idl_expansion = &mut idl_bytes[prev_len..new_len]; + require_eq!(idl_expansion.len(), idl_data.len()); + idl_expansion.copy_from_slice(&idl_data[..]); + + Ok(()) + } + + #[inline(never)] + pub fn __idl_set_authority( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlAccounts, + new_authority: Pubkey, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlSetAuthority"); + + accounts.idl.authority = new_authority; + Ok(()) + } + + #[inline(never)] + pub fn __idl_set_buffer( + program_id: &Pubkey, + accounts: &mut anchor_lang::idl::IdlSetBuffer, + ) -> anchor_lang::Result<()> { + #[cfg(not(feature = "no-log-ix-name"))] + anchor_lang::prelude::msg!("Instruction: IdlSetBuffer"); + + accounts.idl.data_len = accounts.buffer.data_len; + + use anchor_lang::idl::IdlTrailingData; + let buffer_len = ::std::convert::TryInto::::try_into(accounts.buffer.data_len).unwrap(); + let mut target = accounts.idl.trailing_data_mut(); + let source = &accounts.buffer.trailing_data()[..buffer_len]; + require_gte!(target.len(), buffer_len); + target[..buffer_len].copy_from_slice(source); + // zero the remainder of target? + + Ok(()) + } + } +} \ No newline at end of file diff --git a/lang/syn/src/codegen/program/mod.rs b/lang/syn/src/codegen/program/mod.rs index ea5aff0c1b..eb09b42f96 100644 --- a/lang/syn/src/codegen/program/mod.rs +++ b/lang/syn/src/codegen/program/mod.rs @@ -8,6 +8,7 @@ mod dispatch; mod entry; mod handlers; mod instruction; +mod idl; pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mod_name = &program.name; From 9906712b0db7fa2e1928205dcc516e3b54b9731c Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 12:10:47 +0000 Subject: [PATCH 05/13] get rid of ctor --- lang/src/ctor.rs | 27 --------------------------- lang/src/lib.rs | 3 --- 2 files changed, 30 deletions(-) delete mode 100644 lang/src/ctor.rs diff --git a/lang/src/ctor.rs b/lang/src/ctor.rs deleted file mode 100644 index c24d392e9f..0000000000 --- a/lang/src/ctor.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{Accounts, ToAccountInfo}; -use solana_program::account_info::AccountInfo; - -/// The Ctor accounts that can be used to create any account within the program -/// itself (instead of creating the account on the client). -/// -/// This is used to create accounts at deterministic addresses, as a function of -/// nothing but a program ID--for example, to create state global program -/// structs and program IDL accounts. It's currently used **internally** within -/// the Anchor `#[program]` codegen. -#[derive(Accounts)] -pub struct Ctor<'info> { - // Payer of the transaction. - #[account(signer)] - pub from: AccountInfo<'info>, - // The deterministically defined "state" account being created via - // `create_account_with_seed`. - #[account(mut)] - pub to: AccountInfo<'info>, - // The program-derived-address signing off on the account creation. - // Seeds = &[] + bump seed. - pub base: AccountInfo<'info>, - // The system program. - pub system_program: AccountInfo<'info>, - // The program whose state is being constructed. - pub program: AccountInfo<'info>, -} diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 68fd7d36c2..9bba6382ee 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -36,7 +36,6 @@ mod bpf_upgradeable_state; mod bpf_writer; mod common; pub mod context; -mod ctor; pub mod error; #[doc(hidden)] pub mod idl; @@ -276,8 +275,6 @@ pub mod __private { /// The discriminator anchor uses to mark an account as closed. pub const CLOSED_ACCOUNT_DISCRIMINATOR: [u8; 8] = [255, 255, 255, 255, 255, 255, 255, 255]; - pub use crate::ctor::Ctor; - pub use anchor_attribute_account::ZeroCopyAccessor; pub use anchor_attribute_event::EventIndex; From c6b3d6d2d82487385b7fda1eb6ac6052912d4e5d Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 12:14:34 +0000 Subject: [PATCH 06/13] only use local references --- lang/syn/src/codegen/program/idl.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index ac51ba1e34..436c9d6351 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -2,7 +2,7 @@ use quote::quote; pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { quote!{ - use anchor_lang::idl::ERASED_AUTHORITY; + use anchor_lang::idl::{ERASED_AUTHORITY, IdlAccount}; // Accounts for the Create instruction. #[derive(Accounts)] @@ -109,7 +109,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_create_account( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlCreateAccounts, + accounts: &mut IdlCreateAccounts, data_len: u64, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] @@ -121,7 +121,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { // Create the IDL's account. let from = accounts.from.key; let (base, nonce) = Pubkey::find_program_address(&[], program_id); - let seed = anchor_lang::idl::IdlAccount::seed(); + let seed = IdlAccount::seed(); let owner = accounts.program.key; let to = Pubkey::create_with_seed(&base, seed, owner).unwrap(); // Space: account discriminator || authority pubkey || vec len || vec data @@ -153,7 +153,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { let mut idl_account = { let mut account_data = accounts.to.try_borrow_data()?; let mut account_data_slice: &[u8] = &account_data; - anchor_lang::idl::IdlAccount::try_deserialize_unchecked( + IdlAccount::try_deserialize_unchecked( &mut account_data_slice, )? }; @@ -173,7 +173,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_resize_account( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlResizeAccount, + accounts: &mut IdlResizeAccount, data_len: u64, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] @@ -220,7 +220,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_close_account( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlCloseAccount, + accounts: &mut IdlCloseAccount, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] anchor_lang::prelude::msg!("Instruction: IdlCloseAccount"); @@ -231,7 +231,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_create_buffer( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlCreateBuffer, + accounts: &mut IdlCreateBuffer, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] anchor_lang::prelude::msg!("Instruction: IdlCreateBuffer"); @@ -244,7 +244,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_write( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlAccounts, + accounts: &mut IdlAccounts, idl_data: Vec, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] @@ -254,7 +254,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { let new_len: usize = prev_len + idl_data.len(); accounts.idl.data_len = accounts.idl.data_len.checked_add(::std::convert::TryInto::::try_into(idl_data.len()).unwrap()).unwrap(); - use anchor_lang::idl::IdlTrailingData; + use IdlTrailingData; let mut idl_bytes = accounts.idl.trailing_data_mut(); let idl_expansion = &mut idl_bytes[prev_len..new_len]; require_eq!(idl_expansion.len(), idl_data.len()); @@ -266,7 +266,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_set_authority( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlAccounts, + accounts: &mut IdlAccounts, new_authority: Pubkey, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] @@ -279,14 +279,14 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[inline(never)] pub fn __idl_set_buffer( program_id: &Pubkey, - accounts: &mut anchor_lang::idl::IdlSetBuffer, + accounts: &mut IdlSetBuffer, ) -> anchor_lang::Result<()> { #[cfg(not(feature = "no-log-ix-name"))] anchor_lang::prelude::msg!("Instruction: IdlSetBuffer"); accounts.idl.data_len = accounts.buffer.data_len; - use anchor_lang::idl::IdlTrailingData; + use IdlTrailingData; let buffer_len = ::std::convert::TryInto::::try_into(accounts.buffer.data_len).unwrap(); let mut target = accounts.idl.trailing_data_mut(); let source = &accounts.buffer.trailing_data()[..buffer_len]; From 5adbf16ffc8b5daf04f7d195df8b8ff01a010dc7 Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 12:17:50 +0000 Subject: [PATCH 07/13] get rid of deprecated ProgramAccount usage --- lang/syn/src/codegen/program/idl.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index 436c9d6351..68dc36022d 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -21,7 +21,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { pub system_program: Program<'info, System>, // The program whose state is being constructed. #[account(executable)] - pub program: AccountInfo<'info>, + pub program: UncheckedAccount<'info>, } @@ -29,8 +29,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[derive(Accounts)] pub struct IdlAccounts<'info> { #[account(mut, has_one = authority)] - #[allow(deprecated)] - pub idl: ProgramAccount<'info, IdlAccount>, + pub idl: Account<'info, IdlAccount>, #[account(constraint = authority.key != &ERASED_AUTHORITY)] pub authority: Signer<'info>, } @@ -39,8 +38,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[derive(Accounts)] pub struct IdlResizeAccount<'info> { #[account(mut, has_one = authority)] - #[allow(deprecated)] - pub idl: ProgramAccount<'info, IdlAccount>, + pub idl: Account<'info, IdlAccount>, #[account(mut, constraint = authority.key != &ERASED_AUTHORITY)] pub authority: Signer<'info>, pub system_program: Program<'info, System>, @@ -50,8 +48,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[derive(Accounts)] pub struct IdlCreateBuffer<'info> { #[account(zero)] - #[allow(deprecated)] - pub buffer: ProgramAccount<'info, IdlAccount>, + pub buffer: Account<'info, IdlAccount>, #[account(constraint = authority.key != &ERASED_AUTHORITY)] pub authority: Signer<'info>, } @@ -61,12 +58,10 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { 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>, + pub buffer: Account<'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>, + pub idl: Account<'info, IdlAccount>, #[account(constraint = authority.key != &ERASED_AUTHORITY)] pub authority: Signer<'info>, } @@ -75,8 +70,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[derive(Accounts)] pub struct IdlCloseAccount<'info> { #[account(mut, has_one = authority, close = sol_destination)] - #[allow(deprecated)] - pub account: ProgramAccount<'info, IdlAccount>, + pub account: Account<'info, IdlAccount>, #[account(constraint = authority.key != &ERASED_AUTHORITY)] pub authority: Signer<'info>, #[account(mut)] @@ -91,8 +85,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { fn trailing_data_mut(self) -> RefMut<'info, [u8]>; } - #[allow(deprecated)] - impl<'a, 'info: 'a> IdlTrailingData<'a> for &'a ProgramAccount<'info, IdlAccount> { + impl<'a, 'info: 'a> IdlTrailingData<'a> for &'a Account<'info, IdlAccount> { fn trailing_data(self) -> Ref<'a, [u8]> { let info = self.as_ref(); Ref::map(info.try_borrow_data().unwrap(), |d| &d[44..]) From 3db8518aa971cd16734130877ea47e93302e7a79 Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 12:19:06 +0000 Subject: [PATCH 08/13] cargo fmt --- lang/src/idl.rs | 32 ++++++++++++------------ lang/syn/src/codegen/program/handlers.rs | 2 +- lang/syn/src/codegen/program/idl.rs | 6 ++--- lang/syn/src/codegen/program/mod.rs | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lang/src/idl.rs b/lang/src/idl.rs index 73a221eb7f..c74c111af5 100644 --- a/lang/src/idl.rs +++ b/lang/src/idl.rs @@ -33,21 +33,21 @@ pub const IDL_IX_TAG_LE: [u8; 8] = IDL_IX_TAG.to_le_bytes(); pub const ERASED_AUTHORITY: Pubkey = Pubkey::new_from_array([0u8; 32]); #[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 }, - // Sets a new data buffer for the IdlAccount. - SetBuffer, - // Sets a new authority on the IdlAccount. - SetAuthority { new_authority: Pubkey }, - Close, - // Increases account size for accounts that need over 10kb. - Resize { data_len: u64 }, - } +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 }, + // Sets a new data buffer for the IdlAccount. + SetBuffer, + // Sets a new authority on the IdlAccount. + SetAuthority { new_authority: Pubkey }, + Close, + // Increases account size for accounts that need over 10kb. + Resize { data_len: u64 }, +} // 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. @@ -73,4 +73,4 @@ impl IdlAccount { pub fn seed() -> &'static str { "anchor:idl" } -} \ No newline at end of file +} diff --git a/lang/syn/src/codegen/program/handlers.rs b/lang/syn/src/codegen/program/handlers.rs index 6356d8762d..e3e409dce3 100644 --- a/lang/syn/src/codegen/program/handlers.rs +++ b/lang/syn/src/codegen/program/handlers.rs @@ -1,8 +1,8 @@ use crate::codegen::program::common::*; +use crate::program_codegen::idl::idl_accounts_and_functions; use crate::Program; use heck::CamelCase; use quote::{quote, ToTokens}; -use crate::program_codegen::idl::idl_accounts_and_functions; // Generate non-inlined wrappers for each instruction handler, since Solana's // BPF max stack size can't handle reasonable sized dispatch trees without doing diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index 68dc36022d..c17c4ef78a 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -1,9 +1,9 @@ use quote::quote; pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { - quote!{ + quote! { use anchor_lang::idl::{ERASED_AUTHORITY, IdlAccount}; - + // Accounts for the Create instruction. #[derive(Accounts)] pub struct IdlCreateAccounts<'info> { @@ -290,4 +290,4 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { Ok(()) } } -} \ No newline at end of file +} diff --git a/lang/syn/src/codegen/program/mod.rs b/lang/syn/src/codegen/program/mod.rs index eb09b42f96..22bec8adcf 100644 --- a/lang/syn/src/codegen/program/mod.rs +++ b/lang/syn/src/codegen/program/mod.rs @@ -7,8 +7,8 @@ mod cpi; mod dispatch; mod entry; mod handlers; -mod instruction; mod idl; +mod instruction; pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mod_name = &program.name; From b4717ab6a240453d5c58b0ed08d06c805443807b Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 13:19:34 +0000 Subject: [PATCH 09/13] fix compile issues, move idlAccount --- lang/src/idl.rs | 5 ++++ lang/syn/src/codegen/program/handlers.rs | 14 +++++----- lang/syn/src/codegen/program/idl.rs | 34 +++++++++++++++++++++--- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lang/src/idl.rs b/lang/src/idl.rs index c74c111af5..0e7b9a2081 100644 --- a/lang/src/idl.rs +++ b/lang/src/idl.rs @@ -54,6 +54,11 @@ pub enum IdlInstruction { // // Note: we use the same account for the "write buffer", similar to the // bpf upgradeable loader's mechanism. +// +// TODO: IdlAccount exists here only because it's needed by the CLI, the IDL +// itself uses an IdlAccount defined inside the program itself, see program/idl.rs. +// Ideally it would be deleted and a better solution for sharing the type with CLI +// could be found. #[account("internal")] #[derive(Debug)] pub struct IdlAccount { diff --git a/lang/syn/src/codegen/program/handlers.rs b/lang/syn/src/codegen/program/handlers.rs index e3e409dce3..26b94858b2 100644 --- a/lang/syn/src/codegen/program/handlers.rs +++ b/lang/syn/src/codegen/program/handlers.rs @@ -32,7 +32,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlCreateAccounts::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlCreateAccounts::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_create_account(program_id, &mut accounts, data_len)?; accounts.exit(program_id)?; }, @@ -40,7 +40,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlResizeAccount::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlResizeAccount::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_resize_account(program_id, &mut accounts, data_len)?; accounts.exit(program_id)?; }, @@ -48,7 +48,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlCloseAccount::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlCloseAccount::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_close_account(program_id, &mut accounts)?; accounts.exit(program_id)?; }, @@ -56,7 +56,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlCreateBuffer::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlCreateBuffer::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_create_buffer(program_id, &mut accounts)?; accounts.exit(program_id)?; }, @@ -64,7 +64,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlAccounts::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlAccounts::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_write(program_id, &mut accounts, data)?; accounts.exit(program_id)?; }, @@ -72,7 +72,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlAccounts::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlAccounts::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_set_authority(program_id, &mut accounts, new_authority)?; accounts.exit(program_id)?; }, @@ -80,7 +80,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { let mut bumps = std::collections::BTreeMap::new(); let mut reallocs = std::collections::BTreeSet::new(); let mut accounts = - anchor_lang::idl::IdlSetBuffer::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; + IdlSetBuffer::try_accounts(program_id, &mut accounts, &[], &mut bumps, &mut reallocs)?; __idl_set_buffer(program_id, &mut accounts)?; accounts.exit(program_id)?; }, diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index c17c4ef78a..08a89186b7 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -2,7 +2,36 @@ use quote::quote; pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { quote! { - use anchor_lang::idl::{ERASED_AUTHORITY, IdlAccount}; + use anchor_lang::idl::{ERASED_AUTHORITY}; + + #[account("internal")] + #[derive(Debug)] + pub struct IdlAccount { + // Address that can modify the IDL. + pub authority: Pubkey, + // Length of compressed idl bytes. + pub data_len: u32, + // Followed by compressed idl bytes. + } + + 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" + } + } + + // Hacky workaround because of some internals to how account attribute + // works. Namespaces are the root of most of the problem. + impl anchor_lang::Owner for IdlAccount { + fn owner() -> Pubkey { + crate::ID + } + } // Accounts for the Create instruction. #[derive(Accounts)] @@ -15,7 +44,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { pub to: SystemAccount<'info>, // The program-derived-address signing off on the account creation. // Seeds = &[] + bump seed. - #[account(seeds = [])] + #[account(seeds = [], bump)] pub base: SystemAccount<'info>, // The system program. pub system_program: Program<'info, System>, @@ -24,7 +53,6 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { pub program: UncheckedAccount<'info>, } - // Accounts for Idl instructions. #[derive(Accounts)] pub struct IdlAccounts<'info> { From e371f17609c12e8306cab7f6cccdc4e55904128f Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 13:26:07 +0000 Subject: [PATCH 10/13] cargo fmt --- lang/src/idl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/src/idl.rs b/lang/src/idl.rs index 0e7b9a2081..24544bd482 100644 --- a/lang/src/idl.rs +++ b/lang/src/idl.rs @@ -54,7 +54,7 @@ pub enum IdlInstruction { // // Note: we use the same account for the "write buffer", similar to the // bpf upgradeable loader's mechanism. -// +// // TODO: IdlAccount exists here only because it's needed by the CLI, the IDL // itself uses an IdlAccount defined inside the program itself, see program/idl.rs. // Ideally it would be deleted and a better solution for sharing the type with CLI From f4f11617fa40ff7691a926ab49471a6b89c1608d Mon Sep 17 00:00:00 2001 From: henrye Date: Tue, 24 Jan 2023 13:38:21 +0000 Subject: [PATCH 11/13] fixed some compile issue but not others --- lang/syn/src/codegen/program/idl.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index 08a89186b7..f4fc2b81ee 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -37,20 +37,21 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { #[derive(Accounts)] pub struct IdlCreateAccounts<'info> { // Payer of the transaction. - pub from: Signer<'info>, + #[account(signer)] + pub from: AccountInfo<'info>, // The deterministically defined "state" account being created via // `create_account_with_seed`. #[account(mut)] - pub to: SystemAccount<'info>, + pub to: AccountInfo<'info>, // The program-derived-address signing off on the account creation. // Seeds = &[] + bump seed. #[account(seeds = [], bump)] - pub base: SystemAccount<'info>, + pub base: AccountInfo<'info>, // The system program. - pub system_program: Program<'info, System>, + pub system_program: AccountInfo<'info>, // The program whose state is being constructed. #[account(executable)] - pub program: UncheckedAccount<'info>, + pub program: AccountInfo<'info>, } // Accounts for Idl instructions. From 9be5cafa2fa1c8e3f5df9289d0eb114b1fb9c729 Mon Sep 17 00:00:00 2001 From: henrye Date: Wed, 25 Jan 2023 16:32:36 +0000 Subject: [PATCH 12/13] fix compile errors --- lang/syn/src/codegen/program/idl.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index f4fc2b81ee..b8aac94269 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -2,7 +2,7 @@ use quote::quote; pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { quote! { - use anchor_lang::idl::{ERASED_AUTHORITY}; + use anchor_lang::idl::ERASED_AUTHORITY; #[account("internal")] #[derive(Debug)] @@ -45,12 +45,12 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { pub to: AccountInfo<'info>, // The program-derived-address signing off on the account creation. // Seeds = &[] + bump seed. - #[account(seeds = [], bump)] + // #[account(seeds = [], bump)] pub base: AccountInfo<'info>, // The system program. pub system_program: AccountInfo<'info>, // The program whose state is being constructed. - #[account(executable)] + // #[account(executable)] pub program: AccountInfo<'info>, } @@ -116,11 +116,11 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { impl<'a, 'info: 'a> IdlTrailingData<'a> for &'a Account<'info, IdlAccount> { fn trailing_data(self) -> Ref<'a, [u8]> { - let info = self.as_ref(); + let info: &AccountInfo<'info> = self.as_ref(); Ref::map(info.try_borrow_data().unwrap(), |d| &d[44..]) } fn trailing_data_mut(self) -> RefMut<'a, [u8]> { - let info = self.as_ref(); + let info: &AccountInfo<'info> = self.as_ref(); RefMut::map(info.try_borrow_mut_data().unwrap(), |d| &mut d[44..]) } } From a4c3ffd12b0c3fffc365eba6718543dddff86208 Mon Sep 17 00:00:00 2001 From: henrye Date: Thu, 26 Jan 2023 11:15:11 +0000 Subject: [PATCH 13/13] add some minor constraints just for the sake of it --- lang/syn/src/codegen/program/idl.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs index b8aac94269..a1ef7f4d7f 100644 --- a/lang/syn/src/codegen/program/idl.rs +++ b/lang/syn/src/codegen/program/idl.rs @@ -45,12 +45,12 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { pub to: AccountInfo<'info>, // The program-derived-address signing off on the account creation. // Seeds = &[] + bump seed. - // #[account(seeds = [], bump)] + #[account(seeds = [], bump)] pub base: AccountInfo<'info>, // The system program. - pub system_program: AccountInfo<'info>, + pub system_program: Program<'info, System>, // The program whose state is being constructed. - // #[account(executable)] + #[account(executable)] pub program: AccountInfo<'info>, } @@ -166,7 +166,7 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream { accounts.from.clone(), accounts.to.clone(), accounts.base.clone(), - accounts.system_program.clone(), + accounts.system_program.to_account_info().clone(), ], &[seeds], )?;