diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 3852bd16e5544..89b64359a542b 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -18,7 +18,7 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] -// Make the WASM binary available. +// Make the WASM binaries available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); diff --git a/cumulus/zombienet/zombienet-sdk-helpers/src/lib.rs b/cumulus/zombienet/zombienet-sdk-helpers/src/lib.rs index 87efc802782e6..0d9555dd4aa76 100644 --- a/cumulus/zombienet/zombienet-sdk-helpers/src/lib.rs +++ b/cumulus/zombienet/zombienet-sdk-helpers/src/lib.rs @@ -19,6 +19,7 @@ use zombienet_sdk::subxt::{ dynamic::Value, events::Events, ext::scale_value::value, + metadata::Metadata, tx::{signer::Signer, DynamicPayload, TxStatus}, utils::H256, OnlineClient, PolkadotConfig, @@ -28,6 +29,25 @@ use zombienet_sdk::subxt::{ // If it does not arrive for whatever reason, we should not wait forever. const WAIT_MAX_BLOCKS_FOR_SESSION: u32 = 50; +/// Format a `sp_runtime::DispatchError` using runtime metadata for human-readable output. +/// +/// For module errors this resolves the pallet index and error index to their names +/// (e.g. `ParachainSystem::TooBig`) instead of showing raw bytes. +fn format_dispatch_error(err: &sp_runtime::DispatchError, metadata: &Metadata) -> String { + match err { + sp_runtime::DispatchError::Module(module_err) => { + let pallet = metadata.pallet_by_index(module_err.index); + let pallet_name = pallet.as_ref().map(|p| p.name()).unwrap_or("UnknownPallet"); + let error_name = pallet + .and_then(|p| p.error_variant_by_index(module_err.error[0])) + .map(|v| v.name.as_str()) + .unwrap_or("UnknownError"); + format!("{pallet_name}::{error_name}") + }, + other => format!("{other:?}"), + } +} + /// Find an event in subxt `Events` and attempt to decode the fields of the event. fn find_event_and_decode_fields( events: &Events, @@ -569,6 +589,45 @@ pub fn create_runtime_upgrade_call(wasm: &[u8]) -> DynamicPayload { ) } +/// Submit a runtime upgrade via sudo and verify it was scheduled. +/// +/// This submits a `Sudo::sudo_unchecked_weight(System::set_code(wasm))` extrinsic, +/// waits for finalization, then checks the `Sudid` event to verify the inner dispatch +/// succeeded. Returns the hash of the finalized block containing the upgrade extrinsic. +pub async fn submit_sudo_runtime_upgrade>( + client: &OnlineClient, + wasm: &[u8], + signer: &S, +) -> Result { + log::info!("Submitting sudo runtime upgrade, wasm size: {} bytes", wasm.len()); + let call = create_runtime_upgrade_call(wasm); + let block_hash = + submit_extrinsic_and_wait_for_finalization_success(client, &call, signer).await?; + + // Verify the inner sudo dispatch succeeded by checking the Sudid event. + // sudo_unchecked_weight always returns Ok at the extrinsic level, even if the + // inner call fails — the actual result is only in the Sudid event. + let block = client.blocks().at(block_hash).await?; + let events = block.events().await?; + let sudid_results: Vec> = + find_event_and_decode_fields(&events, "Sudo", "Sudid")?; + + match sudid_results.first() { + Some(Ok(())) => { + log::info!("Sudo runtime upgrade dispatched successfully in block {block_hash:?}") + }, + Some(Err(e)) => { + return Err(anyhow!( + "Sudo runtime upgrade inner dispatch failed in block {block_hash:?}: {}", + format_dispatch_error(e, &client.metadata()), + )) + }, + None => return Err(anyhow!("Sudid event not found in block {block_hash:?}")), + } + + Ok(block_hash) +} + /// Wait until a runtime upgrade has happened. /// /// This checks all finalized blocks until it finds a block that sets the diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/elastic_scaling/upgrade_to_3_cores.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/elastic_scaling/upgrade_to_3_cores.rs index e7cc473f924ac..8f7ab38dab99e 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/elastic_scaling/upgrade_to_3_cores.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/elastic_scaling/upgrade_to_3_cores.rs @@ -7,12 +7,11 @@ use serde_json::json; use crate::utils::initialize_network; use cumulus_test_runtime::{ - elastic_scaling::WASM_BINARY_BLOATY as WASM_ELASTIC_SCALING, - elastic_scaling_12s_slot::WASM_BINARY_BLOATY as WASM_ELASTIC_SCALING_12S_SLOT, + elastic_scaling::WASM_BINARY as WASM_ELASTIC_SCALING, + elastic_scaling_12s_slot::WASM_BINARY as WASM_ELASTIC_SCALING_12S_SLOT, }; use cumulus_zombienet_sdk_helpers::{ - assert_para_throughput, assign_cores, create_runtime_upgrade_call, - submit_extrinsic_and_wait_for_finalization_success, wait_for_runtime_upgrade, + assert_para_throughput, assign_cores, submit_sudo_runtime_upgrade, wait_for_runtime_upgrade, }; use polkadot_primitives::Id as ParaId; use rstest::rstest; @@ -71,9 +70,7 @@ async fn elastic_scaling_upgrade_to_3_cores( }; log::info!("Performing runtime upgrade"); - let call = create_runtime_upgrade_call(wasm); - submit_extrinsic_and_wait_for_finalization_success(&collator0_client, &call, &dev::alice()) - .await?; + submit_sudo_runtime_upgrade(&collator0_client, wasm, &dev::alice()).await?; let collator1 = network.get_node("collator1")?; let collator1_client: OnlineClient = collator1.wait_client().await?; diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/parachain_runtime_upgrade_slot_duration_18s.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/parachain_runtime_upgrade_slot_duration_18s.rs index 673a204a0417c..079e8fffbdf62 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/parachain_runtime_upgrade_slot_duration_18s.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/parachain_runtime_upgrade_slot_duration_18s.rs @@ -8,10 +8,10 @@ use crate::utils::initialize_network; use anyhow::anyhow; -use cumulus_test_runtime::slot_duration_18s::WASM_BINARY_BLOATY as WASM_WITH_SLOT_DURATION_18S; +use cumulus_test_runtime::slot_duration_18s::WASM_BINARY as WASM_WITH_SLOT_DURATION_18S; use cumulus_zombienet_sdk_helpers::{ - assert_blocks_are_being_finalized, assert_para_throughput, create_runtime_upgrade_call, - submit_extrinsic_and_wait_for_finalization_success, wait_for_runtime_upgrade, + assert_blocks_are_being_finalized, assert_para_throughput, submit_sudo_runtime_upgrade, + wait_for_runtime_upgrade, }; use futures::StreamExt; use polkadot_primitives::Id as ParaId; @@ -45,9 +45,7 @@ async fn parachain_runtime_upgrade_slot_duration_18s() -> Result<(), anyhow::Err let initial_slot_duration = get_slot_duration(&collator_client).await?; log::info!("Performing runtime upgrade for parachain {}", PARA_ID); - let call = create_runtime_upgrade_call(wasm); - submit_extrinsic_and_wait_for_finalization_success(&collator_client, &call, &dev::alice()) - .await?; + submit_sudo_runtime_upgrade(&collator_client, wasm, &dev::alice()).await?; let block_hash_of_upgrade = wait_for_runtime_upgrade(&collator_client).await?; diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/runtime_upgrade.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/runtime_upgrade.rs index 14c0703e457d1..d206fd9beb01c 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/runtime_upgrade.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/runtime_upgrade.rs @@ -3,11 +3,8 @@ use crate::utils::initialize_network; use anyhow::anyhow; -use cumulus_test_runtime::wasm_spec_version_incremented::WASM_BINARY_BLOATY as WASM_RUNTIME_UPGRADE; -use cumulus_zombienet_sdk_helpers::{ - create_runtime_upgrade_call, submit_extrinsic_and_wait_for_finalization_success, - wait_for_runtime_upgrade, -}; +use cumulus_test_runtime::wasm_spec_version_incremented::WASM_BINARY as WASM_RUNTIME_UPGRADE; +use cumulus_zombienet_sdk_helpers::{submit_sudo_runtime_upgrade, wait_for_runtime_upgrade}; use zombienet_sdk::{ subxt::{OnlineClient, PolkadotConfig}, subxt_signer::sr25519::dev, @@ -36,10 +33,12 @@ async fn runtime_upgrade() -> Result<(), anyhow::Error> { log::info!("Current runtime spec version {current_spec_version}"); log::info!("Performing runtime upgrade"); - - let call = create_runtime_upgrade_call(WASM_RUNTIME_UPGRADE.expect("Wasm runtime not build")); - submit_extrinsic_and_wait_for_finalization_success(&charlie_client, &call, &dev::alice()) - .await?; + submit_sudo_runtime_upgrade( + &charlie_client, + WASM_RUNTIME_UPGRADE.expect("Wasm runtime not built"), + &dev::alice(), + ) + .await?; let dave = network.get_node("dave")?; let dave_client: OnlineClient = dave.wait_client().await?; diff --git a/prdoc/pr_11641.prdoc b/prdoc/pr_11641.prdoc new file mode 100644 index 0000000000000..9ea8d40b8025a --- /dev/null +++ b/prdoc/pr_11641.prdoc @@ -0,0 +1,23 @@ +title: 'Fix runtime upgrade zombienet tests exceeding max_code_size' +doc: +- audience: Runtime Dev + description: |- + The wasm-builder's compaction and compression decision now uses the actual + blob build profile rather than the outer cargo profile. Since debug builds + already compile WASM blobs with the Release profile, they now also get + compacted and compressed, producing a properly sized `WASM_BINARY`. + Previously `WASM_BINARY` in debug builds was identical to `WASM_BINARY_BLOATY`. +- audience: Node Dev + description: |- + Zombienet runtime upgrade tests now use compact (`WASM_BINARY`) runtimes + instead of `WASM_BINARY_BLOATY`, which had grown beyond the relay chain's + `max_code_size` limit. A new `submit_sudo_runtime_upgrade` helper verifies + that the inner sudo dispatch succeeded and renders any dispatch errors using + runtime metadata (e.g. `ParachainSystem::TooBig` instead of raw byte indices). +crates: +- name: substrate-wasm-builder + bump: patch +- name: cumulus-zombienet-sdk-helpers + bump: minor +- name: cumulus-zombienet-sdk-tests + bump: none diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 7c1de82f1f990..cdc8086d987d3 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -284,7 +284,7 @@ fn maybe_compact_and_compress_wasm( build_config: &BuildConfiguration, bloaty_changed: bool, ) -> (Option, WasmBinaryBloaty, bool) { - let needs_compact = build_config.outer_build_profile.wants_compact(); + let needs_compact = build_config.blob_build_profile.wants_compact(); let compact_path = blob_paths.compact(); let compressed_path = blob_paths.compact_compressed(); let compact_or_compressed_exists = compact_path.exists() || compressed_path.exists(); @@ -810,9 +810,7 @@ impl Profile { /// The build configuration for this build. #[derive(Debug)] struct BuildConfiguration { - /// The profile that is used to build the outer project. - pub outer_build_profile: Profile, - /// The profile to use to build the runtime blob. + /// The profile to use to build the runtime blob and decide whether to compact/compress. pub blob_build_profile: Profile, } @@ -828,9 +826,7 @@ impl BuildConfiguration { /// When not overridden by a env variable we always default to building wasm with the `Release` /// profile even when the main build uses the debug build. This is because wasm built with the /// `Debug` profile is too slow for normal development activities and almost never intended. - /// - /// When cargo is building in `--profile dev`, user likely intends to compile fast, so we don't - /// bother producing compact or compressed blobs. + /// Compaction and compression are also decided by this profile. /// /// # Note /// @@ -860,8 +856,8 @@ impl BuildConfiguration { .to_string(); (name, false) }; - let outer_build_profile = Profile::iter().find(|p| p.directory() == name); - let blob_build_profile = match (outer_build_profile.clone(), overridden) { + let detected_profile = Profile::iter().find(|p| p.directory() == name); + let blob_build_profile = match (detected_profile, overridden) { // When not overridden by a env variable we default to using the `Release` profile // for the wasm build even when the main build uses the debug build. This // is because the `Debug` profile is too slow for normal development activities. @@ -889,10 +885,7 @@ impl BuildConfiguration { process::exit(1); }, }; - BuildConfiguration { - outer_build_profile: outer_build_profile.unwrap_or(Profile::Release), - blob_build_profile, - } + BuildConfiguration { blob_build_profile } } }