diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e9de43d2..f4c86bf4ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The minor version will be incremented upon a breaking change and the patch versi - syn: Add `IdlBuild` trait to implement IDL support for custom types ([#2629](https://github.com/coral-xyz/anchor/pull/2629)). - spl: Add `idl-build` feature. IDL build method will not work without enabling this feature when using `anchor-spl` ([#2629](https://github.com/coral-xyz/anchor/pull/2629)). - lang: Add support for type aliases in IDLs ([#2637](https://github.com/coral-xyz/anchor/pull/2637)). +- cli: Add `test.upgradeable`, `test.genesis.upgradeable` setting in anchor.toml to support testing upgradeable programs ([#2641](https://github.com/coral-xyz/anchor/pull/2642)). ### Fixes diff --git a/cli/src/config.rs b/cli/src/config.rs index e5277d9d16..e2cd48fca4 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -706,6 +706,7 @@ pub struct TestValidator { pub validator: Option, pub startup_wait: i32, pub shutdown_wait: i32, + pub upgradeable: bool, } #[derive(Default, Debug, Clone, Serialize, Deserialize)] @@ -718,6 +719,8 @@ pub struct _TestValidator { pub startup_wait: Option, #[serde(skip_serializing_if = "Option::is_none")] pub shutdown_wait: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub upgradeable: Option, } pub const STARTUP_WAIT: i32 = 5000; @@ -730,6 +733,7 @@ impl From<_TestValidator> for TestValidator { startup_wait: _test_validator.startup_wait.unwrap_or(STARTUP_WAIT), genesis: _test_validator.genesis, validator: _test_validator.validator.map(Into::into), + upgradeable: _test_validator.upgradeable.unwrap_or(false), } } } @@ -741,6 +745,7 @@ impl From for _TestValidator { startup_wait: Some(test_validator.startup_wait), genesis: test_validator.genesis, validator: test_validator.validator.map(Into::into), + upgradeable: Some(test_validator.upgradeable), } } } @@ -949,6 +954,8 @@ pub struct GenesisEntry { pub address: String, // Filepath to the compiled program to embed into the genesis. pub program: String, + // Whether the genesis program is upgradeable. + pub upgradeable: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/cli/src/lib.rs b/cli/src/lib.rs index f698cafa49..aa077ba468 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -3025,6 +3025,11 @@ fn validator_flags( ) -> Result> { let programs = cfg.programs.get(&Cluster::Localnet); + let test_upgradeable_program = test_validator + .as_ref() + .map(|test_validator| test_validator.upgradeable) + .unwrap_or(false); + let mut flags = Vec::new(); for mut program in cfg.read_all_programs()? { let binary_path = program.binary_path().display().to_string(); @@ -3036,9 +3041,16 @@ fn validator_flags( .map(|deployment| Ok(deployment.address.to_string())) .unwrap_or_else(|| program.pubkey().map(|p| p.to_string()))?; - flags.push("--bpf-program".to_string()); - flags.push(address.clone()); - flags.push(binary_path); + if test_upgradeable_program { + flags.push("--upgradeable-program".to_string()); + flags.push(address.clone()); + flags.push(binary_path); + flags.push(cfg.wallet_kp()?.pubkey().to_string()); + } else { + flags.push("--bpf-program".to_string()); + flags.push(address.clone()); + flags.push(binary_path); + } if let Some(idl) = program.idl.as_mut() { // Add program address to the IDL. @@ -3062,9 +3074,16 @@ fn validator_flags( program_path.display() )); } - flags.push("--bpf-program".to_string()); - flags.push(entry.address.clone()); - flags.push(entry.program.clone()); + if entry.upgradeable.unwrap_or(false) { + flags.push("--upgradeable-program".to_string()); + flags.push(entry.address.clone()); + flags.push(entry.program.clone()); + flags.push(cfg.wallet_kp()?.pubkey().to_string()); + } else { + flags.push("--bpf-program".to_string()); + flags.push(entry.address.clone()); + flags.push(entry.program.clone()); + } } } if let Some(validator) = &test.validator { diff --git a/docs/src/pages/docs/manifest.md b/docs/src/pages/docs/manifest.md index 7cc2547275..f64567bf50 100644 --- a/docs/src/pages/docs/manifest.md +++ b/docs/src/pages/docs/manifest.md @@ -122,6 +122,20 @@ program = "dex.so" [[test.genesis]] address = "22Y43yTVxuUkoRKdm9thyRhQ3SdgQS7c7kB6UNCiaczD" program = "swap.so" +upgradeable = true +``` + +#### upgradeable + +Deploys the program-to-test using `--upgradeable-program`. This makes it possible to test that certain instructions can only be executed by the program's upgrade authority. The initial upgrade authority will be set to `provider.wallet`. + +If unspecified or explicitly set to false, then the test program will be deployed with `--bpf-program`, disabling upgrades to it. + +Example: + +```toml +[test] +upgradeable = true ``` ## test.validator