|
@@ -308,6 +308,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 {
|
|
@@ -1565,7 +1568,9 @@ fn fetch_idl(cfg_override: &ConfigOverride, idl_addr: Pubkey) -> Result<Idl> {
|
|
|
let mut d: &[u8] = &account.data[8..];
|
|
|
let idl_account: IdlAccount = AnchorDeserialize::deserialize(&mut d)?;
|
|
|
|
|
|
- let mut z = ZlibDecoder::new(&idl_account.data[..]);
|
|
|
+ let compressed_len: usize = idl_account.data_len.try_into().unwrap();
|
|
|
+ let compressed_bytes = &account.data[44..44 + compressed_len];
|
|
|
+ let mut z = ZlibDecoder::new(compressed_bytes);
|
|
|
let mut s = Vec::new();
|
|
|
z.read_to_end(&mut s)?;
|
|
|
serde_json::from_slice(&s[..]).map_err(Into::into)
|
|
@@ -1596,6 +1601,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,
|
|
@@ -1638,6 +1644,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,
|
|
@@ -1811,6 +1828,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.
|
|
@@ -2834,9 +2889,22 @@ fn create_idl_account(
|
|
|
|
|
|
// Run `Create instruction.
|
|
|
{
|
|
|
- let data = serialize_idl_ix(anchor_lang::idl::IdlInstruction::Create {
|
|
|
- data_len: (idl_data.len() as u64) * 2, // Double for future growth.
|
|
|
- })?;
|
|
|
+ let pda_max_growth = 60_000;
|
|
|
+ let idl_header_size = 44;
|
|
|
+ let idl_data_len = idl_data.len() as u64;
|
|
|
+ // We're only going to support up to 6 instructions in one transaction
|
|
|
+ // because will anyone really have a >60kb IDL?
|
|
|
+ if idl_data_len > pda_max_growth {
|
|
|
+ return Err(anyhow!(
|
|
|
+ "Your IDL is over 60kb and this isn't supported right now"
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ // Double for future growth.
|
|
|
+ let data_len = (idl_data_len * 2).min(pda_max_growth - idl_header_size);
|
|
|
+
|
|
|
+ let num_additional_instructions = data_len / 10000;
|
|
|
+ let mut instructions = Vec::new();
|
|
|
+ let data = serialize_idl_ix(anchor_lang::idl::IdlInstruction::Create { data_len })?;
|
|
|
let program_signer = Pubkey::find_program_address(&[], program_id).0;
|
|
|
let accounts = vec![
|
|
|
AccountMeta::new_readonly(keypair.pubkey(), true),
|
|
@@ -2846,14 +2914,27 @@ fn create_idl_account(
|
|
|
AccountMeta::new_readonly(*program_id, false),
|
|
|
AccountMeta::new_readonly(solana_program::sysvar::rent::ID, false),
|
|
|
];
|
|
|
- let ix = Instruction {
|
|
|
+ instructions.push(Instruction {
|
|
|
program_id: *program_id,
|
|
|
accounts,
|
|
|
data,
|
|
|
- };
|
|
|
+ });
|
|
|
+
|
|
|
+ for _ in 0..num_additional_instructions {
|
|
|
+ let data = serialize_idl_ix(anchor_lang::idl::IdlInstruction::Resize { data_len })?;
|
|
|
+ instructions.push(Instruction {
|
|
|
+ program_id: *program_id,
|
|
|
+ accounts: vec![
|
|
|
+ AccountMeta::new(idl_address, false),
|
|
|
+ AccountMeta::new_readonly(keypair.pubkey(), true),
|
|
|
+ AccountMeta::new_readonly(solana_program::system_program::ID, false),
|
|
|
+ ],
|
|
|
+ data,
|
|
|
+ });
|
|
|
+ }
|
|
|
let latest_hash = client.get_latest_blockhash()?;
|
|
|
let tx = Transaction::new_signed_with_payer(
|
|
|
- &[ix],
|
|
|
+ &instructions,
|
|
|
Some(&keypair.pubkey()),
|
|
|
&[&keypair],
|
|
|
latest_hash,
|