Skip to content

Commit

Permalink
Idl: Add IdlClose instruction and "anchor idl close" cli
Browse files Browse the repository at this point in the history
  • Loading branch information
microwavedcola1 authored and ckamm committed Dec 21, 2022
1 parent f8dc68c commit 16a346a
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 0 deletions.
53 changes: 53 additions & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ pub enum IdlCommand {
#[clap(short, long)]
filepath: String,
},
Close {
program_id: Pubkey,
},
/// Writes an IDL into a buffer account. This can be used with SetBuffer
/// to perform an upgrade.
WriteBuffer {
Expand Down Expand Up @@ -1548,6 +1551,7 @@ fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> {
program_id,
filepath,
} => idl_init(cfg_override, program_id, filepath),
IdlCommand::Close { program_id } => idl_close(cfg_override, program_id),
IdlCommand::WriteBuffer {
program_id,
filepath,
Expand Down Expand Up @@ -1590,6 +1594,17 @@ fn idl_init(cfg_override: &ConfigOverride, program_id: Pubkey, idl_filepath: Str
})
}

fn idl_close(cfg_override: &ConfigOverride, program_id: Pubkey) -> Result<()> {
with_workspace(cfg_override, |cfg| {
let idl_address = IdlAccount::address(&program_id);
idl_close_account(&cfg, &program_id, idl_address)?;

println!("Idl account closed: {:?}", idl_address);

Ok(())
})
}

fn idl_write_buffer(
cfg_override: &ConfigOverride,
program_id: Pubkey,
Expand Down Expand Up @@ -1763,6 +1778,44 @@ fn idl_erase_authority(cfg_override: &ConfigOverride, program_id: Pubkey) -> Res
Ok(())
}

fn idl_close_account(cfg: &Config, program_id: &Pubkey, idl_address: Pubkey) -> Result<()> {
let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string())
.map_err(|_| anyhow!("Unable to read keypair file"))?;
let url = cluster_url(cfg, &cfg.test_validator);
let client = RpcClient::new(url);

// Instruction accounts.
let accounts = vec![
AccountMeta::new(idl_address, false),
AccountMeta::new_readonly(keypair.pubkey(), true),
AccountMeta::new(keypair.pubkey(), true),
];
// Instruction.
let ix = Instruction {
program_id: *program_id,
accounts,
data: { serialize_idl_ix(anchor_lang::idl::IdlInstruction::Close {})? },
};
// Send transaction.
let latest_hash = client.get_latest_blockhash()?;
let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&keypair.pubkey()),
&[&keypair],
latest_hash,
);
client.send_and_confirm_transaction_with_spinner_and_config(
&tx,
CommitmentConfig::confirmed(),
RpcSendTransactionConfig {
skip_preflight: true,
..RpcSendTransactionConfig::default()
},
)?;

Ok(())
}

// Write the idl to the account buffer, chopping up the IDL into pieces
// and sending multiple transactions in the event the IDL doesn't fit into
// a single transaction.
Expand Down
13 changes: 13 additions & 0 deletions lang/src/idl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub enum IdlInstruction {
SetBuffer,
// Sets a new authority on the IdlAccount.
SetAuthority { new_authority: Pubkey },
Close,
}

// Accounts for the Create instruction.
Expand Down Expand Up @@ -85,6 +86,18 @@ pub struct IdlSetBuffer<'info> {
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>,
}

// 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.
//
Expand Down
19 changes: 19 additions & 0 deletions lang/syn/src/codegen/program/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
__idl_create_account(program_id, &mut accounts, data_len)?;
accounts.exit(program_id)?;
},
anchor_lang::idl::IdlInstruction::Close => {
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)?;
__idl_close_account(program_id, &mut accounts)?;
accounts.exit(program_id)?;
},
anchor_lang::idl::IdlInstruction::CreateBuffer => {
let mut bumps = std::collections::BTreeMap::new();
let mut reallocs = std::collections::BTreeSet::new();
Expand Down Expand Up @@ -140,6 +148,17 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
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,
Expand Down

0 comments on commit 16a346a

Please sign in to comment.