Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
aterga committed Jan 8, 2025
1 parent 194648a commit 49f5888
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 18 deletions.
28 changes: 28 additions & 0 deletions rs/sns/governance/api/src/ic_sns_governance.pb.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,30 @@ pub struct Motion {
#[prost(string, tag = "1")]
pub motion_text: ::prost::alloc::string::String,
}

/// Represents a WASM chunked into potentially multiple smaller chunks, each of which can safely
/// be sent around the ICP.
#[derive(
candid::CandidType,
candid::Deserialize,
comparable::Comparable,
Clone,
PartialEq,
::prost::Message,
)]
pub struct ChunkedCanisterWasm {
/// Obligatory check sum of the overall WASM to be reassembled from chunks.
#[prost(bytes = "vec", optional, tag = "1")]
pub wasm_module_hash: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
/// Obligatory; indicates which canister stores the WASM chunks.
#[prost(message, optional, tag = "2")]
pub store_canister_id: ::core::option::Option<::ic_base_types::PrincipalId>,
/// Specifies a list of hash values for the chunks that comprise this WASM. Must contain at least
/// one chink.
#[prost(bytes = "vec", repeated, tag = "3")]
pub chunk_hashes_list: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
}

/// A proposal function that upgrades a canister that is controlled by the
/// SNS governance canister.
#[derive(
Expand Down Expand Up @@ -395,6 +419,10 @@ pub struct UpgradeSnsControlledCanister {
tag = "4"
)]
pub mode: ::core::option::Option<i32>,
/// If the entire WASM does not into the 2 MiB ingress limit, then `new_canister_wasm` should be
/// an empty, and this field should be set instead.
#[prost(message, optional, tag = "5")]
pub chunked_canister_wasm: ::core::option::Option<ChunkedCanisterWasm>,
}
/// A proposal to transfer SNS treasury funds to (optionally a Subaccount of) the
/// target principal.
Expand Down
15 changes: 15 additions & 0 deletions rs/sns/governance/proto/ic_sns_governance/pb/v1/governance.proto
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,18 @@ message Motion {
string motion_text = 1;
}

// Represents a WASM chunked into potentially multiple smaller chunks, each of which can safely
// be sent around the ICP.
message ChunkedCanisterWasm {
// Obligatory check sum of the overall WASM to be reassembled from chunks.
optional bytes wasm_module_hash = 1;
// Obligatory; indicates which canister stores the WASM chunks.
optional ic_base_types.pb.v1.PrincipalId store_canister_id = 2;
// Specifies a list of hash values for the chunks that comprise this WASM. Must contain at least
// one chink.
repeated bytes chunk_hashes_list = 3;
}

// A proposal function that upgrades a canister that is controlled by the
// SNS governance canister.
message UpgradeSnsControlledCanister {
Expand All @@ -323,6 +335,9 @@ message UpgradeSnsControlledCanister {
optional bytes canister_upgrade_arg = 3;
// Canister install_code mode.
optional types.v1.CanisterInstallMode mode = 4;
// If the entire WASM does not into the 2 MiB ingress limit, then `new_canister_wasm` should be
// an empty, and this field should be set instead.
optional ChunkedCanisterWasm chunked_canister_wasm = 5;
}

// A proposal to transfer SNS treasury funds to (optionally a Subaccount of) the
Expand Down
26 changes: 26 additions & 0 deletions rs/sns/governance/src/gen/ic_sns_governance.pb.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,28 @@ pub struct Motion {
#[prost(string, tag = "1")]
pub motion_text: ::prost::alloc::string::String,
}
/// Represents a WASM chunked into potentially multiple smaller chunks, each of which can safely
/// be sent around the ICP.
#[derive(
candid::CandidType,
candid::Deserialize,
comparable::Comparable,
Clone,
PartialEq,
::prost::Message,
)]
pub struct ChunkedCanisterWasm {
/// Obligatory check sum of the overall WASM to be reassembled from chunks.
#[prost(bytes = "vec", optional, tag = "1")]
pub wasm_module_hash: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
/// Obligatory; indicates which canister stores the WASM chunks.
#[prost(message, optional, tag = "2")]
pub store_canister_id: ::core::option::Option<::ic_base_types::PrincipalId>,
/// Specifies a list of hash values for the chunks that comprise this WASM. Must contain at least
/// one chink.
#[prost(bytes = "vec", repeated, tag = "3")]
pub chunk_hashes_list: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
}
/// A proposal function that upgrades a canister that is controlled by the
/// SNS governance canister.
#[derive(
Expand Down Expand Up @@ -395,6 +417,10 @@ pub struct UpgradeSnsControlledCanister {
tag = "4"
)]
pub mode: ::core::option::Option<i32>,
/// If the entire WASM does not into the 2 MiB ingress limit, then `new_canister_wasm` should be
/// an empty, and this field should be set instead.
#[prost(message, optional, tag = "5")]
pub chunked_canister_wasm: ::core::option::Option<ChunkedCanisterWasm>,
}
/// A proposal to transfer SNS treasury funds to (optionally a Subaccount of) the
/// target principal.
Expand Down
8 changes: 7 additions & 1 deletion rs/sns/governance/src/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2517,9 +2517,15 @@ impl Governance {

let mode = upgrade.mode_or_upgrade() as i32;

let new_canister_wasm = if let Some(chunked_canister_wasm) = upgrade.chunked_canister_wasm {
todo!()
} else {
upgrade.new_canister_wasm
};

self.upgrade_non_root_canister(
target_canister_id,
upgrade.new_canister_wasm,
new_canister_wasm,
upgrade
.canister_upgrade_arg
.unwrap_or_else(|| Encode!().unwrap()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2914,6 +2914,7 @@ fn test_sns_controlled_canister_upgrade_only_upgrades_dapp_canisters() {
new_canister_wasm: vec![0, 0x61, 0x73, 0x6D, 2, 0, 0, 0],
canister_upgrade_arg: None,
mode: Some(CanisterInstallModeProto::Upgrade.into()),
chunked_canister_wasm: None,
});

// Upgrade Proposal
Expand Down
23 changes: 23 additions & 0 deletions rs/sns/governance/src/pb/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,16 +291,39 @@ impl From<pb::UpgradeSnsControlledCanister> for pb_api::UpgradeSnsControlledCani
new_canister_wasm: item.new_canister_wasm,
canister_upgrade_arg: item.canister_upgrade_arg,
mode: item.mode,
chunked_canister_wasm: item.chunked_canister_wasm.map(pb_api::ChunkedCanisterWasm::from),
}
}
}

impl From<pb_api::ChunkedCanisterWasm> for pb::ChunkedCanisterWasm {
fn from(item: pb_api::ChunkedCanisterWasm) -> Self {
Self {
wasm_module_hash: item.wasm_module_hash,
store_canister_id: item.store_canister_id,
chunk_hashes_list: item.chunk_hashes_list,
}
}
}

impl From<pb::ChunkedCanisterWasm> for pb_api::ChunkedCanisterWasm {
fn from(item: pb::ChunkedCanisterWasm) -> Self {
Self {
wasm_module_hash: item.wasm_module_hash,
store_canister_id: item.store_canister_id,
chunk_hashes_list: item.chunk_hashes_list,
}
}
}

impl From<pb_api::UpgradeSnsControlledCanister> for pb::UpgradeSnsControlledCanister {
fn from(item: pb_api::UpgradeSnsControlledCanister) -> Self {
Self {
canister_id: item.canister_id,
new_canister_wasm: item.new_canister_wasm,
canister_upgrade_arg: item.canister_upgrade_arg,
mode: item.mode,
chunked_canister_wasm: item.chunked_canister_wasm.map(pb::ChunkedCanisterWasm::from),
}
}
}
Expand Down
54 changes: 37 additions & 17 deletions rs/sns/governance/src/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,7 @@ fn validate_and_render_upgrade_sns_controlled_canister(
new_canister_wasm,
canister_upgrade_arg,
mode,
chunked_canister_wasm,
} = upgrade;
// Make sure `mode` is not None, and not an invalid/unknown value.
if let Some(mode) = mode {
Expand All @@ -1073,25 +1074,38 @@ fn validate_and_render_upgrade_sns_controlled_canister(
// see https://ic-interface-spec.netlify.app/#canister-module-format
const GZIPPED_WASM_HEADER: [u8; 3] = [0x1f, 0x8b, 0x08];

if new_canister_wasm.len() < 4
|| new_canister_wasm[..4] != RAW_WASM_HEADER[..]
&& new_canister_wasm[..3] != GZIPPED_WASM_HEADER[..]
{
defects.push("new_canister_wasm lacks the magic value in its header.".into());
match (new_canister_wasm.is_empty(), chunked_canister_wasm) {
(true, Some(_)) => {
defects.push("Cannot specify both new_canister_wasm and chunked_canister_wasm.".into());
}
(false, None) => {
defects.push("Either new_canister_wasm or chunked_canister_wasm must be specified.".into());
}
_ => (),
}

if new_canister_wasm.len().saturating_add(
canister_upgrade_arg
.as_ref()
.map(|arg| arg.len())
.unwrap_or_default(),
) >= MAX_INSTALL_CODE_WASM_AND_ARG_SIZE
{
defects.push(format!(
"the maximum canister WASM and argument size \
for UpgradeSnsControlledCanister is {} bytes.",
MAX_INSTALL_CODE_WASM_AND_ARG_SIZE
));
// TODO: Add validation for `chunked_canister_wasm`.
if chunked_canister_wasm.is_none() {
if new_canister_wasm.len() < 4
|| new_canister_wasm[..4] != RAW_WASM_HEADER[..]
&& new_canister_wasm[..3] != GZIPPED_WASM_HEADER[..]
{
defects.push("new_canister_wasm lacks the magic value in its header.".into());
}

if new_canister_wasm.len().saturating_add(
canister_upgrade_arg
.as_ref()
.map(|arg| arg.len())
.unwrap_or_default(),
) >= MAX_INSTALL_CODE_WASM_AND_ARG_SIZE
{
defects.push(format!(
"the maximum canister WASM and argument size \
for UpgradeSnsControlledCanister is {} bytes.",
MAX_INSTALL_CODE_WASM_AND_ARG_SIZE
));
}
}

// Generate final report.
Expand Down Expand Up @@ -2777,6 +2791,7 @@ mod tests {
new_canister_wasm: vec![0, 0x61, 0x73, 0x6D, 1, 0, 0, 0],
canister_upgrade_arg: None,
mode: Some(CanisterInstallModeProto::Upgrade.into()),
chunked_canister_wasm: None,
};
let text = validate_and_render_upgrade_sns_controlled_canister(&upgrade).unwrap();

Expand All @@ -2802,6 +2817,7 @@ mod tests {
new_canister_wasm: vec![0, 0x61, 0x73, 0x6D, 1, 0, 0, 0],
canister_upgrade_arg: Some(vec![10, 20, 30, 40, 50, 60, 70, 80]),
mode: Some(CanisterInstallModeProto::Upgrade.into()),
chunked_canister_wasm: None,
};
let text = validate_and_render_upgrade_sns_controlled_canister(&upgrade).unwrap();

Expand All @@ -2827,6 +2843,7 @@ mod tests {
new_canister_wasm: vec![0, 0x61, 0x73, 0x6D, 1, 0, 0, 0],
canister_upgrade_arg: None,
mode: Some(100), // 100 is not a valid mode
chunked_canister_wasm: None,
};
let text = validate_and_render_upgrade_sns_controlled_canister(&upgrade).unwrap_err();
assert!(text.contains("Invalid mode"));
Expand All @@ -2838,6 +2855,7 @@ mod tests {
new_canister_wasm: vec![0, 0x61, 0x73, 0x6D, 1, 0, 0, 0],
canister_upgrade_arg: None,
mode: Some(CanisterInstallModeProto::Upgrade.into()),
chunked_canister_wasm: None,
};
assert_is_ok(validate_and_render_upgrade_sns_controlled_canister(
&upgrade,
Expand Down Expand Up @@ -4835,6 +4853,7 @@ Payload rendering here"#
new_canister_wasm: vec![0, 1, 2, 3],
canister_upgrade_arg: Some(vec![4, 5, 6, 7]),
mode: Some(1),
chunked_canister_wasm: None,
},
)),
..Default::default()
Expand All @@ -4855,6 +4874,7 @@ Payload rendering here"#
new_canister_wasm: vec![],
canister_upgrade_arg: Some(vec![4, 5, 6, 7]),
mode: Some(1),
chunked_canister_wasm: None,
},
)),
..Default::default()
Expand Down
2 changes: 2 additions & 0 deletions rs/sns/governance/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,7 @@ impl UpgradeSnsControlledCanister {
.as_ref()
.map(|blob| summarize_blob_field(blob)),
mode: self.mode,
chunked_canister_wasm: self.chunked_canister_wasm.clone(),
}
}

Expand All @@ -1754,6 +1755,7 @@ impl UpgradeSnsControlledCanister {
canister_upgrade_arg: self.canister_upgrade_arg.clone(),
mode: self.mode,
new_canister_wasm: Vec::new(),
chunked_canister_wasm: None,
}
}
}
Expand Down

0 comments on commit 49f5888

Please sign in to comment.