From 9a174d8b772d27a9c847c1fa13c6e0c57d138a4f Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:06:53 +0100 Subject: [PATCH 1/9] overshoot test added --- cumulus/test/runtime/src/lib.rs | 2 +- cumulus/test/runtime/src/test_pallet.rs | 28 +++ cumulus/zombienet/zombienet-sdk/Cargo.toml | 2 + .../zombienet-sdk/tests/zombie_ci/mod.rs | 1 + .../overshooting_shall_not_happen_test.rs | 191 ++++++++++++++++++ 5 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 75859680b5199..27113a772a8da 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -239,7 +239,7 @@ parameter_types! { pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() .base_block(BlockExecutionWeight::get()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); + weights.base_extrinsic = ExtrinsicBaseWeight::get().div(2); }) .for_class(DispatchClass::Normal, |weights| { weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); diff --git a/cumulus/test/runtime/src/test_pallet.rs b/cumulus/test/runtime/src/test_pallet.rs index a972198c300d9..bc865995e62fe 100644 --- a/cumulus/test/runtime/src/test_pallet.rs +++ b/cumulus/test/runtime/src/test_pallet.rs @@ -38,6 +38,11 @@ pub mod pallet { #[pallet::storage] pub type TestMap = StorageMap<_, Twox64Concat, u32, (), ValueQuery>; + /// Development data storage for testing (e.g., PoV reclaim testing). + /// Maps index to value, where value equals index. + #[pallet::storage] + pub type DevData = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; + #[pallet::hooks] impl Hooks> for Pallet {} @@ -105,11 +110,29 @@ pub mod pallet { TestMap::::remove(key); Ok(()) } + + /// Remove development data entries from storage. + /// + /// Removes `count` entries starting from index `start`. + #[pallet::weight(0)] + pub fn kill_dev_entry( + _: OriginFor, + start: u32, + count: u32, + ) -> DispatchResult { + for i in start..start.saturating_add(count) { + DevData::::remove(i); + } + Ok(()) + } } #[derive(frame_support::DefaultNoBound)] #[pallet::genesis_config] pub struct GenesisConfig { + /// Number of development data entries to create in DevData storage. + /// Entry i will have value i. + pub dev_data_entries: u32, #[serde(skip)] pub _config: core::marker::PhantomData, } @@ -118,6 +141,11 @@ pub mod pallet { impl BuildGenesisConfig for GenesisConfig { fn build(&self) { sp_io::storage::set(TEST_RUNTIME_UPGRADE_KEY, &[1, 2, 3, 4]); + + // Populate DevData storage entries. + for i in 0..self.dev_data_entries { + DevData::::insert(i, i); + } } } } diff --git a/cumulus/zombienet/zombienet-sdk/Cargo.toml b/cumulus/zombienet/zombienet-sdk/Cargo.toml index 4e33a22c56c32..f069f1c497058 100644 --- a/cumulus/zombienet/zombienet-sdk/Cargo.toml +++ b/cumulus/zombienet/zombienet-sdk/Cargo.toml @@ -26,6 +26,8 @@ sp-keyring = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } codec = { workspace = true } rstest = { workspace = true } +tracing = { workspace = true } +txtesttool = { path = "/home/miszka/parity/23-pov-reclaim/tx-test-tool", package = "substrate-txtesttool" } [features] zombie-ci = [] diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/mod.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/mod.rs index 13e75ac866cbf..733d5024d34be 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/mod.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/mod.rs @@ -6,6 +6,7 @@ mod elastic_scaling; mod full_node_catching_up; mod full_node_warp_sync; mod migrate_solo; +mod overshooting_shall_not_happen_test; mod parachain_extrinsic_get_finalized; mod pov_recovery; mod rpc_collator_build_blocks; diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs new file mode 100644 index 0000000000000..5954b0f773ccb --- /dev/null +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs @@ -0,0 +1,191 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +//! Test that sends one ready transaction from each of 20k accounts to a parachain collator. +//! Network configuration is hardcoded via zombienet SDK API based on +//! asset-hub-high-pool-limit-fatp.toml. + +use anyhow::anyhow; +use serde_json::json; + +use crate::utils::{initialize_network, BEST_BLOCK_METRIC}; +use tracing::info; +use txtesttool::{ + execution_log::ExecutionLog, + scenario::{ChainType, ScenarioBuilder}, +}; +use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder}; + +const PARA_ID: u32 = 2000; +const ACCOUNT_COUNT: usize = 100; +const FROM_SINGLE_ACCOUNT: usize = 200; +const TOTAL_COUNT: usize = ACCOUNT_COUNT * FROM_SINGLE_ACCOUNT; +const TEST_TIMEOUT_SECS: u64 = 3600; // 1 hour + // + +#[tokio::test(flavor = "multi_thread")] +async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { + let config = build_network_config().await?; + let network = initialize_network(config).await?; + + let alice = network.get_node("alice")?; + let bob = network.get_node("bob")?; + let charlie = network.get_node("charlie")?; + + // Ensure relaychain nodes are producing blocks + for node in [alice, bob] { + info!("Ensuring {} reports block production", node.name()); + assert!(node + .wait_metric_with_timeout(BEST_BLOCK_METRIC, |b| b > 2.0, 120u64) + .await + .is_ok()); + } + + // Ensure parachain collator is producing blocks + info!("Ensuring charlie reports block production"); + assert!(charlie + .wait_metric_with_timeout(BEST_BLOCK_METRIC, |b| b > 2.0, 180u64) + .await + .is_ok()); + + // Get WebSocket URI for charlie (parachain collator) + let ws = charlie.ws_uri().to_string(); + let base_dir = network.base_dir().map(|s| s.to_string()); + + // Build scenario executor using ScenarioBuilder + // - 20k accounts (start_id=0 to last_id=19999) + // - 1 transaction per account + // - nonce_from=0 means ready transactions (not future) + info!("Building scenario executor for {} accounts", ACCOUNT_COUNT); + let mut builder = ScenarioBuilder::new() + .with_rpc_uri(ws) + .with_start_id(0) + .with_last_id((ACCOUNT_COUNT - 1) as u32) + .with_txs_count(FROM_SINGLE_ACCOUNT as u32) + .with_nonce_from(Some(0)) + .with_watched_txs(true) + .with_send_threshold(6_000) + .with_block_monitoring(false) + .with_chain_type(ChainType::Sub) + .with_timeout_in_secs(TEST_TIMEOUT_SECS) + .with_executor_id("overshooting-test".to_string()) + .with_custom_sub_payload_builder(|ctx| { + let id = ctx.account.parse::().unwrap(); + let entries_per_account = 5; + let start = txtesttool::subxt_transaction::dynamic::Value::u128( + (entries_per_account * (ctx.nonce * (ACCOUNT_COUNT as u128)+ id)) as u128, + ); + let count = txtesttool::subxt_transaction::dynamic::Value::u128(entries_per_account); + txtesttool::subxt_transaction::dynamic::tx( + "TestPallet", + "kill_dev_entry", + vec![start, count], + ) + }); + + if let Some(dir) = base_dir { + builder = builder.with_base_dir_path(dir); + } + + let executor = builder.build().await; + + // Execute transactions and fetch the execution logs + info!("Submitting {} transactions", TOTAL_COUNT); + let execution_logs = executor.execute().await; + + // Count finalized transactions + let finalized_count = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count(); + + assert_eq!( + finalized_count, TOTAL_COUNT, + "Expected all {} transactions to finalize, but got {} finalized", + TOTAL_COUNT, finalized_count + ); + + Ok(()) +} + +async fn build_network_config() -> Result { + let _ = env_logger::try_init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + info!("Building network config for overshooting test"); + + let images = zombienet_sdk::environment::get_images_from_env(); + info!("Using images: {images:?}"); + + // Network configuration based on asset-hub-high-pool-limit-fatp.toml + let config = NetworkConfigBuilder::new() + .with_relaychain(|r| { + r.with_chain("rococo-local") + .with_default_command("polkadot") + .with_default_image(images.polkadot.as_str()) + .with_default_args(vec![ + "-lparachain::candidate-validation=trace".into(), + "-lparachain::candidate-validation=debug".into(), + "-lparachain::pvf=debug".into(), + "-lparachain::pvf-execute-worker=debug".into(), + "-lparachain::candidate-backing=debug".into(), + "-lcumulus-collator=debug".into(), + "-lparachain-system=debug".into(), + "-lwasm-heap=debug".into(), + ]) + .with_genesis_overrides(json!({ + "configuration": { + "config": { + "executor_params": [{"MaxMemoryPages": 8192}] + } + } + })) + .with_node(|node| node.with_name("alice").validator(true)) + .with_node(|node| node.with_name("bob").validator(true)) + }) + .with_parachain(|p| { + p.with_id(PARA_ID) + .with_default_command("test-parachain") + .with_default_image(images.cumulus.as_str()) + .with_default_args(vec![ + "--force-authoring".into(), + "--experimental-max-pov-percentage=100".into(), + "--pool-kbytes=2048000".into(), + "--pool-limit=500000".into(), + "--pool-type=fork-aware".into(), + "--rpc-max-connections=15000".into(), + "--rpc-max-response-size=150".into(), + "--rpc-max-subscriptions-per-connection=128000".into(), + "--state-pruning=1024".into(), + "-laura::cumulus=trace".into(), + "-lbasic-authorship=trace".into(), + "-lpeerset=info".into(), + "-lsub-libp2p=info".into(), + "-lsync=info".into(), + "-ltxpool=debug".into(), + "-lxxx=trace".into(), + "-lruntime=trace".into(), + ]) + .with_genesis_overrides(json!({ + "testPallet": { + "devDataEntries":2000000 + }, + "balances": { + "devAccounts": [ + ACCOUNT_COUNT, + 1000000000000000000u64, + "//Sender//{}" + ], + } + })) + .with_collator(|n| n.with_name("charlie").validator(true)) + }) + .with_global_settings(|global_settings| match std::env::var("ZOMBIENET_SDK_BASE_DIR") { + Ok(val) => global_settings.with_base_dir(val), + _ => global_settings, + }) + .build() + .map_err(|e| { + let errs = e.into_iter().map(|e| e.to_string()).collect::>().join(" "); + anyhow!("config errs: {errs}") + })?; + + Ok(config) +} From f2cd0ec475e82de05b5e23e8f30b4f4128450111 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 4 Dec 2025 23:30:02 +0100 Subject: [PATCH 2/9] improvements --- cumulus/test/runtime/src/lib.rs | 2 +- .../overshooting_shall_not_happen_test.rs | 113 +++++++++++++++--- 2 files changed, 96 insertions(+), 19 deletions(-) diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 27113a772a8da..75859680b5199 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -239,7 +239,7 @@ parameter_types! { pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() .base_block(BlockExecutionWeight::get()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get().div(2); + weights.base_extrinsic = ExtrinsicBaseWeight::get(); }) .for_class(DispatchClass::Normal, |weights| { weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs index 5954b0f773ccb..2e352c38b9030 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs @@ -1,19 +1,33 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 -//! Test that sends one ready transaction from each of 20k accounts to a parachain collator. -//! Network configuration is hardcoded via zombienet SDK API based on -//! asset-hub-high-pool-limit-fatp.toml. +//! Test that validates the POV (Proof of Validity) reclaim mechanism correctly accounts for trie +//! node access. +//! +//! Storage reclaim returns unused storage proof space to enable more follow-up transactions. +//! However, the accurate accounting of storage proof size must consider the trie nodes accessed +//! during storage root computation, not just the storage items read by extrinsic. +//! +//! This test submits transactions that delete many storage entries (`kill_dev_entry`), causing +//! significant trie modifications. These modifications result in many new trie nodes being added to +//! the proof during storage root calculation. If the POV reclaim mechanism doesn't properly account +//! for these trie node accesses, the chain would overshoot the total PoV budget. +//! +//! **Expected behavior**: With the POV reclaim fix (gh-6020), this test should pass by ensuring all +//! transactions finalize. Without the fix, the test will fail due to POV size being exceeded. +//! +//! Network configuration is hardcoded via zombienet SDK API. use anyhow::anyhow; use serde_json::json; +use tracing::{error, info}; use crate::utils::{initialize_network, BEST_BLOCK_METRIC}; -use tracing::info; use txtesttool::{ execution_log::ExecutionLog, scenario::{ChainType, ScenarioBuilder}, }; +use zombienet_orchestrator::network::node::NetworkNode; use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder}; const PARA_ID: u32 = 2000; @@ -21,7 +35,6 @@ const ACCOUNT_COUNT: usize = 100; const FROM_SINGLE_ACCOUNT: usize = 200; const TOTAL_COUNT: usize = ACCOUNT_COUNT * FROM_SINGLE_ACCOUNT; const TEST_TIMEOUT_SECS: u64 = 3600; // 1 hour - // #[tokio::test(flavor = "multi_thread")] async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { @@ -35,28 +48,30 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { // Ensure relaychain nodes are producing blocks for node in [alice, bob] { info!("Ensuring {} reports block production", node.name()); - assert!(node - .wait_metric_with_timeout(BEST_BLOCK_METRIC, |b| b > 2.0, 120u64) + node.wait_metric_with_timeout(BEST_BLOCK_METRIC, |b| b > 2.0, 120u64) .await - .is_ok()); + .expect("relaychain node should produce blocks"); } // Ensure parachain collator is producing blocks info!("Ensuring charlie reports block production"); - assert!(charlie + charlie .wait_metric_with_timeout(BEST_BLOCK_METRIC, |b| b > 2.0, 180u64) .await - .is_ok()); + .expect("parachain collator should produce blocks"); // Get WebSocket URI for charlie (parachain collator) let ws = charlie.ws_uri().to_string(); let base_dir = network.base_dir().map(|s| s.to_string()); // Build scenario executor using ScenarioBuilder - // - 20k accounts (start_id=0 to last_id=19999) - // - 1 transaction per account + // - Multiple accounts (ACCOUNT_COUNT total) + // - Multiple transactions per account (FROM_SINGLE_ACCOUNT per account) // - nonce_from=0 means ready transactions (not future) - info!("Building scenario executor for {} accounts", ACCOUNT_COUNT); + info!( + "Building scenario executor for {} accounts, {} txs each", + ACCOUNT_COUNT, FROM_SINGLE_ACCOUNT + ); let mut builder = ScenarioBuilder::new() .with_rpc_uri(ws) .with_start_id(0) @@ -71,9 +86,12 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { .with_executor_id("overshooting-test".to_string()) .with_custom_sub_payload_builder(|ctx| { let id = ctx.account.parse::().unwrap(); - let entries_per_account = 5; + let entries_per_account = 20; + // Map each (nonce, id) pair to a unique 20-entry range in dev_data_entries. + // Nonce selects a batch of (ACCOUNT_COUNT * 20) entries, + // and id selects a specific 20-entry range within that batch. let start = txtesttool::subxt_transaction::dynamic::Value::u128( - (entries_per_account * (ctx.nonce * (ACCOUNT_COUNT as u128)+ id)) as u128, + (entries_per_account * (ctx.nonce * (ACCOUNT_COUNT as u128) + id)) as u128, ); let count = txtesttool::subxt_transaction::dynamic::Value::u128(entries_per_account); txtesttool::subxt_transaction::dynamic::tx( @@ -91,11 +109,30 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { // Execute transactions and fetch the execution logs info!("Submitting {} transactions", TOTAL_COUNT); - let execution_logs = executor.execute().await; - // Count finalized transactions - let finalized_count = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count(); + // Create executor future for concurrent polling with POV check + let mut executor_future = std::pin::pin!(executor.execute()); + + // Spawn a task to check for POV errors when alice reaches block 30 + let mut pov_check_task = + tokio::spawn(check_pov_errors_at_block_30(alice.clone(), charlie.clone())); + + // Run executor and POV check in parallel, racing them + let execution_logs = tokio::select! { + execution_logs = &mut executor_future => { + info!("Executor finished before block 30 checkpoint"); + pov_check_task.abort(); + execution_logs + } + pov_check_result = &mut pov_check_task => { + pov_check_result??; + info!("POV check passed at block 30, waiting for executor to complete"); + (&mut executor_future).await + } + }; + // Verify all transactions finalized + let finalized_count = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count(); assert_eq!( finalized_count, TOTAL_COUNT, "Expected all {} transactions to finalize, but got {} finalized", @@ -105,6 +142,46 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { Ok(()) } +/// Checks for POV size exceeded errors in charlie's logs when alice reaches block 30. +/// +/// Returns an error if any "Failed to submit collation" or "POVSizeExceeded" messages are found, +/// indicating that the POV exceeded the maximum allowed size. +async fn check_pov_errors_at_block_30( + alice: NetworkNode, + charlie: NetworkNode, +) -> Result<(), anyhow::Error> { + info!("Waiting for alice (relaychain) to reach block 30"); + alice + .wait_metric_with_timeout(BEST_BLOCK_METRIC, |b| b >= 30.0, 300u64) + .await + .map_err(|e| anyhow!("Failed to wait for block 30: {}", e))?; + + info!("At block 30 - checking charlie's logs for POV errors"); + let logs = charlie.logs().await?; + let pov_error_lines = logs + .lines() + .filter(|line| { + line.contains("Failed to submit collation") || line.contains("POVSizeExceeded") + }) + .collect::>(); + + if !pov_error_lines.is_empty() { + error!( + "Found {} POV/collation submission errors in charlie's logs:", + pov_error_lines.len() + ); + for line in &pov_error_lines { + error!(" {}", line); + } + return Err(anyhow!( + "Found {} POV size exceeded or collation submission failures at block 30 checkpoint", + pov_error_lines.len() + )); + } + info!("No POV errors found at block 30 checkpoint"); + Ok(()) +} + async fn build_network_config() -> Result { let _ = env_logger::try_init_from_env( env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), From 889daafb5b376ecbfdddbe37175c46c7a2bac829 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 5 Dec 2025 09:14:56 +0100 Subject: [PATCH 3/9] use github txtt --- cumulus/zombienet/zombienet-sdk/Cargo.toml | 2 +- .../tests/zombie_ci/overshooting_shall_not_happen_test.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cumulus/zombienet/zombienet-sdk/Cargo.toml b/cumulus/zombienet/zombienet-sdk/Cargo.toml index f069f1c497058..28f8be9779229 100644 --- a/cumulus/zombienet/zombienet-sdk/Cargo.toml +++ b/cumulus/zombienet/zombienet-sdk/Cargo.toml @@ -27,7 +27,7 @@ sp-core = { workspace = true, default-features = true } codec = { workspace = true } rstest = { workspace = true } tracing = { workspace = true } -txtesttool = { path = "/home/miszka/parity/23-pov-reclaim/tx-test-tool", package = "substrate-txtesttool" } +txtesttool = { version = "0.8.0", package="substrate-txtesttool", git = "https://github.com/michalkucharczyk/tx-test-tool", branch = "mku-payload-builder" } [features] zombie-ci = [] diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs index 2e352c38b9030..ea86d60d75d98 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs @@ -84,7 +84,7 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { .with_chain_type(ChainType::Sub) .with_timeout_in_secs(TEST_TIMEOUT_SECS) .with_executor_id("overshooting-test".to_string()) - .with_custom_sub_payload_builder(|ctx| { + .with_tx_payload_builder_sub(|ctx| { let id = ctx.account.parse::().unwrap(); let entries_per_account = 20; // Map each (nonce, id) pair to a unique 20-entry range in dev_data_entries. From 57d993ea51c87e55ed832d8ae132843f2af90621 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:39:37 +0100 Subject: [PATCH 4/9] Cargo.lock --- Cargo.lock | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index f51b14678ae44..0ab0cb1e8f89a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5332,7 +5332,9 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring", "sp-statement-store", + "substrate-txtesttool 0.8.0", "tokio", + "tracing", "zombienet-configuration", "zombienet-orchestrator", "zombienet-sdk", @@ -21284,7 +21286,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "substrate-txtesttool", + "substrate-txtesttool 0.7.0", "thiserror 1.0.65", "tokio", "tokio-stream", @@ -24949,6 +24951,39 @@ dependencies = [ "tracing-subscriber 0.3.18", ] +[[package]] +name = "substrate-txtesttool" +version = "0.8.0" +source = "git+https://github.com/michalkucharczyk/tx-test-tool?branch=mku-payload-builder#8f2ba617cb6d9d670153cdd9ae2afbcf87182070" +dependencies = [ + "async-trait", + "average", + "chrono", + "clap", + "clap_derive", + "ctrlc", + "futures", + "futures-util", + "hex", + "jsonrpsee", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand 0.9.0", + "serde", + "serde_json", + "subxt 0.41.0", + "subxt-core 0.41.0", + "subxt-rpcs 0.41.0", + "subxt-signer 0.41.0", + "termplot", + "thiserror 2.0.12", + "time", + "tokio", + "tokio-util", + "tracing", + "tracing-subscriber 0.3.18", +] + [[package]] name = "substrate-wasm-builder" version = "17.0.0" From 34daf6f45f6eedd47c64d8293aa0470fdd4cc3f7 Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:14:02 +0000 Subject: [PATCH 5/9] Update from github-actions[bot] running command 'fmt' --- cumulus/test/runtime/src/test_pallet.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cumulus/test/runtime/src/test_pallet.rs b/cumulus/test/runtime/src/test_pallet.rs index bc865995e62fe..257f81f2e4ae3 100644 --- a/cumulus/test/runtime/src/test_pallet.rs +++ b/cumulus/test/runtime/src/test_pallet.rs @@ -115,11 +115,7 @@ pub mod pallet { /// /// Removes `count` entries starting from index `start`. #[pallet::weight(0)] - pub fn kill_dev_entry( - _: OriginFor, - start: u32, - count: u32, - ) -> DispatchResult { + pub fn kill_dev_entry(_: OriginFor, start: u32, count: u32) -> DispatchResult { for i in start..start.saturating_add(count) { DevData::::remove(i); } From be09a003fcc9d9c7f63954ae71f1363d9f0e04e5 Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:40:00 +0000 Subject: [PATCH 6/9] Update from github-actions[bot] running command 'prdoc --bump major --audience node_dev' --- prdoc/pr_10549.prdoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 prdoc/pr_10549.prdoc diff --git a/prdoc/pr_10549.prdoc b/prdoc/pr_10549.prdoc new file mode 100644 index 0000000000000..9b2ea33e23745 --- /dev/null +++ b/prdoc/pr_10549.prdoc @@ -0,0 +1,14 @@ +title: PoV reclaim overshooting test +doc: +- audience: Node Dev + description: |- + This PR adds a zombienet integration test that validates if the POV reclaim mechanism (for extrinsic) correctly accounts for trie nodes accessed during storage root computation, as described in #6020 and in #10215. + + The test submits transactions that delete storage entries (triggering trie modifications) and verifies all transactions finalize without exceeding the PoV budget. + + Additionally extends `TestPallet` with: + - `kill_dev_entry` call to trigger trie modifications + - `devDataEntries` genesis config for test data allowing to bloat the state + + Note: test is expected to fail on master branch. +crates: [] From ffff3dc21115c88a9e69d4d47f811a7ba532cbf7 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:27:41 +0100 Subject: [PATCH 7/9] clippy --- .../tests/zombie_ci/overshooting_shall_not_happen_test.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs index ea86d60d75d98..caebc049d99a6 100644 --- a/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs +++ b/cumulus/zombienet/zombienet-sdk/tests/zombie_ci/overshooting_shall_not_happen_test.rs @@ -91,7 +91,7 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { // Nonce selects a batch of (ACCOUNT_COUNT * 20) entries, // and id selects a specific 20-entry range within that batch. let start = txtesttool::subxt_transaction::dynamic::Value::u128( - (entries_per_account * (ctx.nonce * (ACCOUNT_COUNT as u128) + id)) as u128, + entries_per_account * (ctx.nonce * (ACCOUNT_COUNT as u128) + id), ); let count = txtesttool::subxt_transaction::dynamic::Value::u128(entries_per_account); txtesttool::subxt_transaction::dynamic::tx( @@ -135,8 +135,7 @@ async fn overshooting_shall_not_happen_test() -> Result<(), anyhow::Error> { let finalized_count = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count(); assert_eq!( finalized_count, TOTAL_COUNT, - "Expected all {} transactions to finalize, but got {} finalized", - TOTAL_COUNT, finalized_count + "Expected all {TOTAL_COUNT} transactions to finalize, but got {finalized_count} finalized", ); Ok(()) From 4c4ca75de63d31d1f69b82dbfecbb0c2ab31ff97 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:47:42 +0100 Subject: [PATCH 8/9] fixes --- .../zombienet_cumulus_tests.yml | 6 ++ Cargo.lock | 43 ++----------- Cargo.toml | 2 +- cumulus/zombienet/zombienet-sdk/Cargo.toml | 2 +- .../asset-hub-high-pool-limit-fatp.toml | 60 +++++++++++++------ 5 files changed, 54 insertions(+), 59 deletions(-) diff --git a/.github/zombienet-tests/zombienet_cumulus_tests.yml b/.github/zombienet-tests/zombienet_cumulus_tests.yml index 2de3c3160799d..c8b3663252239 100644 --- a/.github/zombienet-tests/zombienet_cumulus_tests.yml +++ b/.github/zombienet-tests/zombienet_cumulus_tests.yml @@ -86,3 +86,9 @@ cumulus-image: "test-parachain" use-zombienet-sdk: true needs-wasm-binary: true + +- job-name: "zombienet-cumulus-0015-overshooting_shall_not_happen" + test-filter: "zombie_ci::overshooting_shall_not_happen_test::overshooting_shall_not_happen_test" + runner-type: "default" + cumulus-image: "test-parachain" + use-zombienet-sdk: true diff --git a/Cargo.lock b/Cargo.lock index 0ab0cb1e8f89a..652be6d5d6468 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5332,7 +5332,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring", "sp-statement-store", - "substrate-txtesttool 0.8.0", + "substrate-txtesttool", "tokio", "tracing", "zombienet-configuration", @@ -18125,7 +18125,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.10.5", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -21286,7 +21286,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "substrate-txtesttool 0.7.0", + "substrate-txtesttool", "thiserror 1.0.65", "tokio", "tokio-stream", @@ -24917,44 +24917,11 @@ dependencies = [ name = "substrate-test-utils" version = "4.0.0-dev" -[[package]] -name = "substrate-txtesttool" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda461f1ab3a919493e83cb54ed0de6220377c08df59fb60ba6a91de56e2005d" -dependencies = [ - "async-trait", - "average", - "chrono", - "clap", - "clap_derive", - "ctrlc", - "futures", - "futures-util", - "hex", - "jsonrpsee", - "parity-scale-codec", - "parking_lot 0.12.3", - "rand 0.9.0", - "serde", - "serde_json", - "subxt 0.41.0", - "subxt-core 0.41.0", - "subxt-rpcs 0.41.0", - "subxt-signer 0.41.0", - "termplot", - "thiserror 2.0.12", - "time", - "tokio", - "tokio-util", - "tracing", - "tracing-subscriber 0.3.18", -] - [[package]] name = "substrate-txtesttool" version = "0.8.0" -source = "git+https://github.com/michalkucharczyk/tx-test-tool?branch=mku-payload-builder#8f2ba617cb6d9d670153cdd9ae2afbcf87182070" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ec45ef6eb845285f9828e2acba2d8e4fc25c83ee3ffcc318f89b7336f5eab9" dependencies = [ "async-trait", "average", diff --git a/Cargo.toml b/Cargo.toml index f61817fff4142..9ad6279820aff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1463,7 +1463,7 @@ trybuild = { version = "1.0.103" } tt-call = { version = "1.0.8" } tuplex = { version = "0.1", default-features = false } twox-hash = { version = "1.6.3", default-features = false } -txtesttool = { version = "0.7.0", package = "substrate-txtesttool" } +txtesttool = { version = "0.8.0", package = "substrate-txtesttool" } unsigned-varint = { version = "0.7.2" } url = { version = "2.5.4" } verifiable = { version = "0.1", default-features = false } diff --git a/cumulus/zombienet/zombienet-sdk/Cargo.toml b/cumulus/zombienet/zombienet-sdk/Cargo.toml index 28f8be9779229..0d65092dd688c 100644 --- a/cumulus/zombienet/zombienet-sdk/Cargo.toml +++ b/cumulus/zombienet/zombienet-sdk/Cargo.toml @@ -27,7 +27,7 @@ sp-core = { workspace = true, default-features = true } codec = { workspace = true } rstest = { workspace = true } tracing = { workspace = true } -txtesttool = { version = "0.8.0", package="substrate-txtesttool", git = "https://github.com/michalkucharczyk/tx-test-tool", branch = "mku-payload-builder" } +txtesttool = { workspace = true } [features] zombie-ci = [] diff --git a/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml b/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml index fc0d034307fac..8ed2cae7e8519 100644 --- a/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml +++ b/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml @@ -1,10 +1,24 @@ [settings] -timeout = 1500 +timeout = 150000 +node_spawn_timeout = 150000 [relaychain] default_image = "parity/polkadot:latest" default_command = "polkadot" chain = "rococo-local" +default_args = [ + "-lparachain::candidate-validation=trace", + "-lparachain::candidate-validation=debug", + "-lparachain::pvf=debug", + "-lparachain::pvf-execute-worker=debug", + "-lparachain::candidate-backing=debug", + "-lcumulus-collator=debug", + "-lparachain-system=debug", + "-lwasm-heap=debug", +] + +[[relaychain.genesis.runtimeGenesis.patch.configuration.config.executor_params]] +MaxMemoryPages=8192 [[relaychain.nodes]] name = "alice" @@ -19,11 +33,17 @@ validator = true [[parachains]] id = 2000 chain = "asset-hub-rococo-local" +chain_spec_path = "zombie-chain_spec-20kde.json" +# chain_spec_path = "zombie-chain_spec-2M.json" +# chain_spec_path = "zombie-chain_spec-2M.json" +# chain_spec_path = "chain-spec-200k.json" + default_command = "polkadot-parachain" default_image = "parity/polkadot-parachain:latest" cumulus_based = true default_args = [ "--force-authoring", + "--experimental-max-pov-percentage 100", "--pool-kbytes 2048000", "--pool-limit 500000", "--pool-type=fork-aware", @@ -31,36 +51,38 @@ default_args = [ "--rpc-max-response-size 150", "--rpc-max-subscriptions-per-connection=128000", "--state-pruning=1024", - "-laura::cumulus=info", - "-lbasic-authorship=info", + "-laura::cumulus=trace", + "-lbasic-authorship=trace", "-lpeerset=info", "-lsub-libp2p=info", "-lsync=info", "-ltxpool=debug", + "-lxxx=trace", + "-lruntime=trace", ] [parachains.genesis.runtimeGenesis.patch.balances] devAccounts = [ - 1000, + 2000, 1000000000000000000, "//Sender//{}", ] [[parachains.collators]] name = "charlie" -validator = false -rpc_port = 9933 - -[[parachains.collators]] -name = "dave" validator = true -rpc_port = 9934 - -[[parachains.collators]] -name = "eve" -validator = true -rpc_port = 9935 +rpc_port = 9933 -[[parachains.collators]] -name = "ferdie" -validator = true -rpc_port = 9936 +# [[parachains.collators]] +# name = "dave" +# validator = true +# rpc_port = 9934 +# +# [[parachains.collators]] +# name = "eve" +# validator = true +# rpc_port = 9935 +# +# [[parachains.collators]] +# name = "ferdie" +# validator = true +# rpc_port = 9936 From 32f8cb4de0f6082440f6ae47cdfe5d7c3775af2c Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:14:43 +0100 Subject: [PATCH 9/9] fix --- .../asset-hub-high-pool-limit-fatp.toml | 60 ++++++------------- 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml b/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml index 8ed2cae7e8519..fc0d034307fac 100644 --- a/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml +++ b/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-high-pool-limit-fatp.toml @@ -1,24 +1,10 @@ [settings] -timeout = 150000 -node_spawn_timeout = 150000 +timeout = 1500 [relaychain] default_image = "parity/polkadot:latest" default_command = "polkadot" chain = "rococo-local" -default_args = [ - "-lparachain::candidate-validation=trace", - "-lparachain::candidate-validation=debug", - "-lparachain::pvf=debug", - "-lparachain::pvf-execute-worker=debug", - "-lparachain::candidate-backing=debug", - "-lcumulus-collator=debug", - "-lparachain-system=debug", - "-lwasm-heap=debug", -] - -[[relaychain.genesis.runtimeGenesis.patch.configuration.config.executor_params]] -MaxMemoryPages=8192 [[relaychain.nodes]] name = "alice" @@ -33,17 +19,11 @@ validator = true [[parachains]] id = 2000 chain = "asset-hub-rococo-local" -chain_spec_path = "zombie-chain_spec-20kde.json" -# chain_spec_path = "zombie-chain_spec-2M.json" -# chain_spec_path = "zombie-chain_spec-2M.json" -# chain_spec_path = "chain-spec-200k.json" - default_command = "polkadot-parachain" default_image = "parity/polkadot-parachain:latest" cumulus_based = true default_args = [ "--force-authoring", - "--experimental-max-pov-percentage 100", "--pool-kbytes 2048000", "--pool-limit 500000", "--pool-type=fork-aware", @@ -51,38 +31,36 @@ default_args = [ "--rpc-max-response-size 150", "--rpc-max-subscriptions-per-connection=128000", "--state-pruning=1024", - "-laura::cumulus=trace", - "-lbasic-authorship=trace", + "-laura::cumulus=info", + "-lbasic-authorship=info", "-lpeerset=info", "-lsub-libp2p=info", "-lsync=info", "-ltxpool=debug", - "-lxxx=trace", - "-lruntime=trace", ] [parachains.genesis.runtimeGenesis.patch.balances] devAccounts = [ - 2000, + 1000, 1000000000000000000, "//Sender//{}", ] [[parachains.collators]] name = "charlie" -validator = true +validator = false rpc_port = 9933 -# [[parachains.collators]] -# name = "dave" -# validator = true -# rpc_port = 9934 -# -# [[parachains.collators]] -# name = "eve" -# validator = true -# rpc_port = 9935 -# -# [[parachains.collators]] -# name = "ferdie" -# validator = true -# rpc_port = 9936 +[[parachains.collators]] +name = "dave" +validator = true +rpc_port = 9934 + +[[parachains.collators]] +name = "eve" +validator = true +rpc_port = 9935 + +[[parachains.collators]] +name = "ferdie" +validator = true +rpc_port = 9936