diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a53f22344..7891ff500d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ The minor version will be incremented upon a breaking change and the patch versi - idl: Fix `unexpected_cfgs` build warning ([#2992](https://github.com/coral-xyz/anchor/pull/2992)). - lang: Make tuple struct fields public in `declare_program!` ([#2994](https://github.com/coral-xyz/anchor/pull/2994)). - Remove `rust-version` from crate manifests ([#3000](https://github.com/coral-xyz/anchor/pull/3000)). +- cli: Fix upgradeable program clones ([#3010](https://github.com/coral-xyz/anchor/pull/3010)). ### Breaking diff --git a/cli/src/lib.rs b/cli/src/lib.rs index f71f14bb32..7ba367e98a 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -3361,7 +3361,7 @@ fn validator_flags( )); }; - let mut pubkeys = value + let pubkeys = value .as_array() .unwrap() .iter() @@ -3370,36 +3370,33 @@ fn validator_flags( Pubkey::from_str(address) .map_err(|_| anyhow!("Invalid pubkey {}", address)) }) - .collect::>>()?; - - let accounts_keys = pubkeys.iter().cloned().collect::>(); - let accounts = client.get_multiple_accounts(&accounts_keys)?; - - // Check if there are program accounts - for (account, acc_key) in accounts.iter().zip(accounts_keys) { - if let Some(account) = account { - if account.owner == bpf_loader_upgradeable::id() { - let upgradable: UpgradeableLoaderState = account - .deserialize_data() - .map_err(|_| anyhow!("Invalid program account {}", acc_key))?; - - if let UpgradeableLoaderState::Program { - programdata_address, - } = upgradable + .collect::>>()? + .into_iter() + .collect::>(); + let accounts = client.get_multiple_accounts(&pubkeys)?; + + for (pubkey, account) in pubkeys.into_iter().zip(accounts) { + match account { + Some(account) => { + // Use a different flag for program accounts to fix the problem + // described in https://github.com/anza-xyz/agave/issues/522 + if account.owner == bpf_loader_upgradeable::id() + // Only programs are supported with `--clone-upgradeable-program` + && matches!( + account.deserialize_data::()?, + UpgradeableLoaderState::Program { .. } + ) { - pubkeys.insert(programdata_address); + flags.push("--clone-upgradeable-program".to_string()); + flags.push(pubkey.to_string()); + } else { + flags.push("--clone".to_string()); + flags.push(pubkey.to_string()); } } - } else { - return Err(anyhow!("Account {} not found", acc_key)); + _ => return Err(anyhow!("Account {} not found", pubkey)), } } - - for pubkey in &pubkeys { - // Push the clone flag for each array entry - flags.push("--clone".to_string()); - flags.push(pubkey.to_string()); - } } else if key == "deactivate_feature" { // Verify that the feature flags are valid pubkeys let pubkeys_result: Result, _> = value