Skip to content

Commit 194648a

Browse files
atergamax-dfinity
andauthored
feat(nervous-system): Enable Root to upgrade canisters using chunked Wasms (#3300)
This PR enables Root to upgrade canisters using chunked Wasms. This is relevant to both the NNS and the SNSs. --------- Co-authored-by: max-dfinity <[email protected]>
1 parent fc935aa commit 194648a

File tree

15 files changed

+474
-26
lines changed

15 files changed

+474
-26
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rs/nervous_system/common/test_utils/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package_group(
88
name = "ic_nervous_system_common_test_utils_visibility",
99
packages = [
1010
"//rs/nervous_system/common/...",
11+
"//rs/nervous_system/integration_tests/...",
1112
"//rs/nns/...",
1213
"//rs/sns/...",
1314
],

rs/nervous_system/common/test_utils/src/wasm_helpers.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use ic_wasm;
22
use libflate::gzip;
3+
use std::io::Read;
34

45
/// A small, valid WASM suitable for tests.
56
pub const SMALLEST_VALID_WASM_BYTES: &[u8; 8] = &[0, 0x61, 0x73, 0x6D, 1, 0, 0, 0];
@@ -25,7 +26,7 @@ pub fn annotate_wasm_with_metadata(
2526
wasm_module.emit_wasm()
2627
}
2728

28-
// Gzips a wasm, returning the hash of its compressed representation.
29+
/// Gzips a wasm, returning the hash of its compressed representation.
2930
pub fn gzip_wasm(wasm: &[u8]) -> Vec<u8> {
3031
let mut encoder = gzip::Encoder::new(Vec::new()).expect("Failed to create gzip encoder.");
3132
std::io::copy(&mut &wasm[..], &mut encoder).expect("Failed to copy WASM bytes.");
@@ -34,3 +35,13 @@ pub fn gzip_wasm(wasm: &[u8]) -> Vec<u8> {
3435
.into_result()
3536
.expect("Failed to finish gzip encoding.")
3637
}
38+
39+
/// Decompresses a previously gzipped wasm.
40+
pub fn ungzip_wasm(gzipped_bytes: &[u8]) -> Vec<u8> {
41+
let mut decoder = gzip::Decoder::new(gzipped_bytes).expect("Failed to create gzip decoder.");
42+
let mut wasm_buf = Vec::new();
43+
decoder
44+
.read_to_end(&mut wasm_buf)
45+
.expect("Failed decoding Wasm.");
46+
wasm_buf
47+
}

rs/nervous_system/integration_tests/BUILD.bazel

+21
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ BASE_DEPENDENCIES = [
4141
"//packages/pocket-ic",
4242
"//rs/crypto/sha2",
4343
"//rs/nervous_system/common/test_keys",
44+
"//rs/nervous_system/common/test_utils",
4445
"//rs/nns/constants",
4546
"//rs/protobuf",
4647
"//rs/registry/canister",
@@ -100,6 +101,7 @@ DEV_DATA = [
100101
"//rs/sns/root:sns-root-canister",
101102
"//rs/sns/swap:sns-swap-canister",
102103
"//rs/universal_canister/impl:universal_canister.wasm.gz",
104+
"//testnet/prebuilt-canisters:image-classification",
103105
"@cycles-ledger.wasm.gz//file",
104106
"@mainnet_ic-icrc1-archive//file",
105107
"@mainnet_ic-icrc1-index-ng//file",
@@ -124,6 +126,7 @@ DEV_ENV = {
124126
"IC_ICRC1_ARCHIVE_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/archive:archive_canister)",
125127
"IC_ICRC1_INDEX_NG_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/index-ng:index_ng_canister)",
126128
"IC_ICRC1_LEDGER_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/ledger:ledger_canister)",
129+
"IMAGE_CLASSIFICATION_CANISTER_WASM_PATH": "$(rootpath //testnet/prebuilt-canisters:image-classification)",
127130
"LEDGER_CANISTER_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/ledger:ledger-canister-wasm)",
128131
"LEDGER_CANISTER_NOTIFY_METHOD_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/ledger:ledger-canister-wasm-notify-method)",
129132
"LEDGER_ARCHIVE_NODE_CANISTER_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/archive:ledger-archive-node-canister-wasm)",
@@ -178,6 +181,7 @@ rust_test_suite_with_extra_srcs(
178181
"tests/deploy_fresh_sns_test.rs",
179182
"tests/sns_release_qualification_legacy.rs",
180183
"tests/sns_upgrade_test_utils_legacy.rs",
184+
"tests/upgrade_sns_controlled_canister_with_large_wasm.rs",
181185
],
182186
),
183187
aliases = ALIASES,
@@ -279,3 +283,20 @@ rust_test(
279283
],
280284
deps = [":nervous_system_integration_tests"] + DEPENDENCIES_WITH_TEST_FEATURES + DEV_DEPENDENCIES,
281285
)
286+
287+
rust_test(
288+
name = "upgrade_sns_controlled_canister_with_large_wasm",
289+
timeout = "long",
290+
srcs = [
291+
"tests/upgrade_sns_controlled_canister_with_large_wasm.rs",
292+
],
293+
aliases = ALIASES,
294+
data = DEV_DATA,
295+
env = DEV_ENV | {"RUST_TEST_NOCAPTURE": "1"},
296+
flaky = True,
297+
proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
298+
tags = [
299+
"cpu:4",
300+
],
301+
deps = [":nervous_system_integration_tests"] + DEPENDENCIES_WITH_TEST_FEATURES + DEV_DEPENDENCIES,
302+
)

rs/nervous_system/integration_tests/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ ic-icrc1-index-ng = { path = "../../ledger_suite/icrc1/index-ng" }
4949
ic-icrc1-tokens-u64 = { path = "../../ledger_suite/icrc1/tokens_u64" }
5050
ic-management-canister-types = { path = "../../types/management_canister_types" }
5151
ic-nervous-system-common-test-keys = { path = "../common/test_keys" }
52+
ic-nervous-system-common-test-utils = { path = "../../nervous_system/common/test_utils" }
5253
ic-nervous-system-root = { path = "../root" }
5354
ic-nns-constants = { path = "../../nns/constants" }
5455
ic-nns-gtc = { path = "../../nns/gtc" }

rs/nervous_system/integration_tests/src/pocket_ic_helpers.rs

+27
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,33 @@ pub async fn install_canister_with_controllers(
185185
);
186186
}
187187

188+
pub async fn install_canister_on_subnet(
189+
pocket_ic: &PocketIc,
190+
subnet_id: Principal,
191+
arg: Vec<u8>,
192+
wasm: Option<Wasm>,
193+
controllers: Vec<PrincipalId>,
194+
) -> CanisterId {
195+
let controllers = controllers.into_iter().map(|c| c.0).collect::<Vec<_>>();
196+
let controller_principal = controllers.first().cloned();
197+
let settings = Some(CanisterSettings {
198+
controllers: Some(controllers),
199+
..Default::default()
200+
});
201+
let canister_id = pocket_ic
202+
.create_canister_on_subnet(None, settings, subnet_id)
203+
.await;
204+
pocket_ic
205+
.add_cycles(canister_id, STARTING_CYCLES_PER_CANISTER)
206+
.await;
207+
if let Some(wasm) = wasm {
208+
pocket_ic
209+
.install_canister(canister_id, wasm.bytes(), arg, controller_principal)
210+
.await;
211+
}
212+
CanisterId::unchecked_from_principal(canister_id.into())
213+
}
214+
188215
// TODO migrate this to nns::governance
189216
pub async fn add_wasm_via_nns_proposal(
190217
pocket_ic: &PocketIc,

0 commit comments

Comments
 (0)