diff --git a/CHANGELOG.md b/CHANGELOG.md index d670178..c02b392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Overhauled PEM auth. PEM files are now password-protected by default, and must be used instead of seed files. Passwords can be provided interactively or with `--password-file`. Keys can be generated unencrypted with `quill generate --storage-mode plaintext`, and encrypted keys can be converted to plaintext with `quill decrypt-pem`. - Overhauled output format. All commands besides `quill sns` should have human-readable output instead of candid IDL. Candid IDL format can be forced with `--raw`. +- Added support for setting the install mode for UpgradeSnsControlledCanister proposals. + ## [0.4.4] - 2024-03-21 - Fixed `quill sns make-proposal` setting some fields to null. diff --git a/Cargo.lock b/Cargo.lock index 21e2a9e..d631526 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4899,6 +4899,7 @@ dependencies = [ "ic-base-types", "ic-ckbtc-minter", "ic-identity-hsm", + "ic-management-canister-types", "ic-nervous-system-common", "ic-nns-common", "ic-nns-constants", diff --git a/Cargo.toml b/Cargo.toml index e25bed4..27c56cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ license = "Apache-2.0" [dependencies] ic-base-types = { git = "https://github.com/dfinity/ic", rev = "479fc39a7ee082a62ec070efeed224784a83eb1b" } ic-ckbtc-minter = { git = "https://github.com/dfinity/ic", rev = "479fc39a7ee082a62ec070efeed224784a83eb1b" } +ic-management-canister-types = { git = "https://github.com/dfinity/ic", rev = "479fc39a7ee082a62ec070efeed224784a83eb1b" } ic-nervous-system-common = { git = "https://github.com/dfinity/ic", rev = "479fc39a7ee082a62ec070efeed224784a83eb1b" } ic-nns-common = { git = "https://github.com/dfinity/ic", rev = "479fc39a7ee082a62ec070efeed224784a83eb1b" } ic-nns-constants = { git = "https://github.com/dfinity/ic", rev = "479fc39a7ee082a62ec070efeed224784a83eb1b" } diff --git a/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.mdx b/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.mdx index 275163a..1669437 100644 --- a/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.mdx +++ b/docs/cli-reference/sns/quill-sns-make-upgrade-canister-proposal.mdx @@ -36,6 +36,7 @@ quill sns make-upgrade-canister-proposal --target-canister- | `--title ` | Title of the proposal. | | `--url <URL>` | URL of the proposal. | | `--wasm-path <WASM_PATH>` | Path to the WASM file to be installed into the target canister. | +| `--mode <MODE>` | The install mode ("install", "reinstall", or "upgrade"). | ## Remarks diff --git a/src/commands/sns/make_upgrade_canister_proposal.rs b/src/commands/sns/make_upgrade_canister_proposal.rs index b817a12..e4372c4 100644 --- a/src/commands/sns/make_upgrade_canister_proposal.rs +++ b/src/commands/sns/make_upgrade_canister_proposal.rs @@ -12,6 +12,7 @@ use candid::Principal; use candid::{Encode, IDLArgs}; use candid_parser::parse_idl_args; use clap::Parser; +use ic_management_canister_types::CanisterInstallMode; use ic_sns_governance::pb::v1::{ manage_neuron, proposal, ManageNeuron, Proposal, UpgradeSnsControlledCanister, }; @@ -27,8 +28,8 @@ pub struct MakeUpgradeCanisterProposalOpts { proposer_neuron_id: ParsedSnsNeuron, /// Title of the proposal. - #[arg(long, default_value_t = String::from("Upgrade Canister"))] - title: String, + #[arg(long)] + title: Option<String>, /// URL of the proposal. #[arg(long, default_value_t = String::new())] @@ -62,6 +63,10 @@ pub struct MakeUpgradeCanisterProposalOpts { /// Path to the binary file containing argument to post-upgrade method of the new canister WASM. #[arg(long, conflicts_with = "canister_upgrade_arg")] canister_upgrade_arg_path: Option<String>, + + /// The install mode. + #[arg(long, value_parser = ["install", "reinstall", "upgrade"])] + mode: String, } pub fn exec( @@ -79,7 +84,23 @@ pub fn exec( wasm_path, canister_upgrade_arg, canister_upgrade_arg_path, + mode, } = opts; + let mode = match mode.as_str() { + "install" => CanisterInstallMode::Install, + "reinstall" => CanisterInstallMode::Reinstall, + "upgrade" => CanisterInstallMode::Upgrade, + _ => return Err(Error::msg("Invalid mode.")), + }; + + let title = title.unwrap_or_else(|| { + match mode { + CanisterInstallMode::Install => "Install Canister", + CanisterInstallMode::Reinstall => "Reinstall Canister", + CanisterInstallMode::Upgrade => "Upgrade Canister", + } + .to_string() + }); let wasm = std::fs::read(wasm_path).context("Unable to read --wasm-path.")?; let canister_upgrade_arg = match (canister_upgrade_arg, canister_upgrade_arg_path) { @@ -100,7 +121,7 @@ pub fn exec( String::from_utf8(std::fs::read(path).context("Unable to read --summary-path.")?) .context("Summary must be valid UTF-8.")? } - (None, None) => summarize(target_canister_id, &wasm), + (None, None) => summarize(target_canister_id, &wasm, mode), }; let proposal = Proposal { @@ -112,7 +133,7 @@ pub fn exec( canister_id: Some(target_canister_id.into()), new_canister_wasm: wasm, canister_upgrade_arg, - mode: None, + mode: Some(mode as i32), }, )), }; @@ -137,14 +158,20 @@ pub fn exec( Ok(vec![msg]) } -fn summarize(target_canister_id: Principal, wasm: &Vec<u8>) -> String { +fn summarize(target_canister_id: Principal, wasm: &Vec<u8>, mode: CanisterInstallMode) -> String { // Fingerprint wasm. let mut hasher = Sha256::new(); hasher.update(wasm); let wasm_fingerprint = hex::encode(hasher.finalize()); + let action = match mode { + CanisterInstallMode::Install => "Install", + CanisterInstallMode::Reinstall => "Reinstall", + CanisterInstallMode::Upgrade => "Upgrade", + }; + format!( - "Upgrade canister: + "{action} canister: ID: {} diff --git a/tests/output/default/sns/make_proposal/upgrade.txt b/tests/output/default/sns/make_proposal/upgrade.txt index aef88ef..5bba120 100644 --- a/tests/output/default/sns/make_proposal/upgrade.txt +++ b/tests/output/default/sns/make_proposal/upgrade.txt @@ -10,16 +10,16 @@ Sending message with command = opt variant { MakeProposal = record { url = ""; - title = "Upgrade Canister"; + title = "Install Canister"; action = opt variant { UpgradeSnsControlledCanister = record { new_canister_wasm = blob "\00\61\73\6d\01\00\00\00"; - mode = null; + mode = opt (1 : int32); canister_id = opt principal "pycv5-3jbbb-ccccc-ddddd-cai"; canister_upgrade_arg = null; } }; - summary = "Upgrade canister:\n\n ID: pycv5-3jbbb-ccccc-ddddd-cai\n\n WASM:\n length: 8\n fingerprint: 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"; + summary = "Install canister:\n\n ID: pycv5-3jbbb-ccccc-ddddd-cai\n\n WASM:\n length: 8\n fingerprint: 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"; } }; }, diff --git a/tests/output/default/sns/make_proposal/upgrade_arg.txt b/tests/output/default/sns/make_proposal/upgrade_arg.txt index a9c1b6e..1960113 100644 --- a/tests/output/default/sns/make_proposal/upgrade_arg.txt +++ b/tests/output/default/sns/make_proposal/upgrade_arg.txt @@ -10,16 +10,16 @@ Sending message with command = opt variant { MakeProposal = record { url = ""; - title = "Upgrade Canister"; + title = "Reinstall Canister"; action = opt variant { UpgradeSnsControlledCanister = record { new_canister_wasm = blob "\00\61\73\6d\01\00\00\00"; - mode = null; + mode = opt (2 : int32); canister_id = opt principal "pycv5-3jbbb-ccccc-ddddd-cai"; canister_upgrade_arg = opt blob "\44\49\44\4c\01\6c\02\b9\fa\ee\18\79\b5\f6\a1\43\79\01\00\02\00\00\00\03\00\00\00"; } }; - summary = "Upgrade canister:\n\n ID: pycv5-3jbbb-ccccc-ddddd-cai\n\n WASM:\n length: 8\n fingerprint: 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"; + summary = "Reinstall canister:\n\n ID: pycv5-3jbbb-ccccc-ddddd-cai\n\n WASM:\n length: 8\n fingerprint: 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"; } }; }, diff --git a/tests/output/default/sns/make_proposal/upgrade_summary_path.txt b/tests/output/default/sns/make_proposal/upgrade_summary_path.txt index 43c2371..31e1d54 100644 --- a/tests/output/default/sns/make_proposal/upgrade_summary_path.txt +++ b/tests/output/default/sns/make_proposal/upgrade_summary_path.txt @@ -14,7 +14,7 @@ Sending message with action = opt variant { UpgradeSnsControlledCanister = record { new_canister_wasm = blob "\00\61\73\6d\01\00\00\00"; - mode = null; + mode = opt (3 : int32); canister_id = opt principal "pycv5-3jbbb-ccccc-ddddd-cai"; canister_upgrade_arg = null; } diff --git a/tests/output/sns.rs b/tests/output/sns.rs index 8049ad7..55b2c34 100644 --- a/tests/output/sns.rs +++ b/tests/output/sns.rs @@ -134,16 +134,16 @@ fn make_proposal() { .diff("sns/make_proposal/from_file.txt"); let canister_wasm = asset("sns_canister.wasm"); - quill_sns_send(&format!("sns make-upgrade-canister-proposal {NEURON_ID} --wasm-path '{canister_wasm}' --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai")) + quill_sns_send(&format!("sns make-upgrade-canister-proposal {NEURON_ID} --wasm-path '{canister_wasm}' --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai --mode install")) .diff("sns/make_proposal/upgrade.txt"); quill_sns_send(&format!("sns make-upgrade-canister-proposal {NEURON_ID} --wasm-path '{canister_wasm}' - --canister-upgrade-arg '(record {{major=2:nat32; minor=3:nat32;}})' --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai")) + --canister-upgrade-arg '(record {{major=2:nat32; minor=3:nat32;}})' --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai --mode reinstall")) .diff("sns/make_proposal/upgrade_arg.txt"); let upgrade_summary = asset("upgrade_summary.txt"); quill_sns_send(&format!( "sns make-upgrade-canister-proposal {NEURON_ID} --wasm-path '{canister_wasm}' - --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai --summary-path '{upgrade_summary}'" + --target-canister-id pycv5-3jbbb-ccccc-ddddd-cai --summary-path '{upgrade_summary}' --mode upgrade" )) .diff("sns/make_proposal/upgrade_summary_path.txt"); }