diff --git a/Cargo.lock b/Cargo.lock
index a856a331b626d..f9ff5a2ea94dd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -20587,7 +20587,10 @@ dependencies = [
"anyhow",
"assert_matches",
"async-trait",
+ "chrono",
"criterion",
+ "cumulus-zombienet-sdk-helpers",
+ "env_logger 0.11.3",
"futures",
"futures-timer",
"indexmap 2.9.0",
@@ -20601,6 +20604,7 @@ dependencies = [
"sc-transaction-pool-api",
"sc-utils",
"serde",
+ "serde_json",
"sp-api 26.0.0",
"sp-blockchain",
"sp-consensus",
@@ -20619,6 +20623,7 @@ dependencies = [
"tokio-stream",
"tracing",
"tracing-subscriber",
+ "zombienet-configuration",
"zombienet-sdk",
]
@@ -24914,9 +24919,9 @@ version = "4.0.0-dev"
[[package]]
name = "substrate-txtesttool"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4116d4d42f14bc24166fd5b3d1d7b90e000e563fa648a87cb9cf27055c53625"
+checksum = "c8e742db3b239740f3ec7d4cfa5cdbc06a9820ed2dd48b073aa3b5de99bb7aed"
dependencies = [
"async-trait",
"average",
diff --git a/Cargo.toml b/Cargo.toml
index 043f2abe82fe3..b47d7d30f76d5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1436,7 +1436,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.5.0", package = "substrate-txtesttool" }
+txtesttool = { version = "0.6.0", package = "substrate-txtesttool" }
unsigned-varint = { version = "0.7.2" }
url = { version = "2.5.4" }
verifiable = { version = "0.1", default-features = false }
@@ -1465,6 +1465,7 @@ xcm-runtime-apis = { path = "polkadot/xcm/xcm-runtime-apis", default-features =
xcm-simulator = { path = "polkadot/xcm/xcm-simulator", default-features = false }
yet-another-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/yet-another-parachain" }
zeroize = { version = "1.7.0", default-features = false }
+zombienet-configuration = { version = "0.3.6" }
zombienet-orchestrator = { version = "0.3.6" }
zombienet-sdk = { version = "0.3.6" }
zstd = { version = "0.12.4", default-features = false }
diff --git a/prdoc/pr_8152.prdoc b/prdoc/pr_8152.prdoc
new file mode 100644
index 0000000000000..41e3e1184a63d
--- /dev/null
+++ b/prdoc/pr_8152.prdoc
@@ -0,0 +1,7 @@
+title: '`fatxpool`: some more integration tests'
+doc:
+- audience: Node Dev
+ description: Some new test cases and improvements of zombienet integration tests for `fatxpool`.
+crates:
+- name: sc-transaction-pool
+ bump: minor
diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml
index b51ceb45d0986..4e4ec9ef8b675 100644
--- a/substrate/client/transaction-pool/Cargo.toml
+++ b/substrate/client/transaction-pool/Cargo.toml
@@ -48,9 +48,14 @@ tracing = { workspace = true, default-features = true }
[dev-dependencies]
anyhow = { workspace = true }
assert_matches = { workspace = true }
+chrono = { workspace = true }
criterion = { workspace = true, default-features = true }
+cumulus-zombienet-sdk-helpers = { workspace = true }
+env_logger = { workspace = true }
rstest = { workspace = true }
sc-block-builder = { workspace = true, default-features = true }
+serde = { workspace = true }
+serde_json = { workspace = true }
sp-consensus = { workspace = true, default-features = true }
substrate-test-runtime = { workspace = true }
substrate-test-runtime-client = { workspace = true }
@@ -59,4 +64,5 @@ thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread"] }
tracing-subscriber = { workspace = true }
txtesttool = { workspace = true }
+zombienet-configuration = { workspace = true }
zombienet-sdk = { workspace = true }
diff --git a/substrate/client/transaction-pool/tests/integration.rs b/substrate/client/transaction-pool/tests/integration.rs
index 200266848d8a2..f723a81a284e0 100644
--- a/substrate/client/transaction-pool/tests/integration.rs
+++ b/substrate/client/transaction-pool/tests/integration.rs
@@ -16,18 +16,19 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-// Testsuite of fatp integration tests.
+//! Testsuite of transaction pool integration tests.
+
pub mod zombienet;
+use std::time::Duration;
+
use crate::zombienet::{
- default_zn_scenario_builder,
- relaychain_rococo_local_network_spec::{
- parachain_asset_hub_network_spec::HIGH_POOL_LIMIT_FATP as PARACHAIN_HIGH_POOL_LIMIT_FATP,
- HIGH_POOL_LIMIT_FATP as RELAYCHAIN_HIGH_POOL_LIMIT_FATP,
- },
- NetworkSpawner,
+ default_zn_scenario_builder, relaychain_rococo_local_network_spec as relay,
+ relaychain_rococo_local_network_spec::parachain_asset_hub_network_spec as para, NetworkSpawner,
};
-use txtesttool::execution_log::ExecutionLog;
+use futures::future::join_all;
+use tracing::info;
+use txtesttool::{execution_log::ExecutionLog, scenario::ScenarioExecutor};
use zombienet::DEFAULT_SEND_FUTURE_AND_READY_TXS_TESTS_TIMEOUT_IN_SECS;
// Test which sends future and ready txs from many accounts
@@ -35,7 +36,7 @@ use zombienet::DEFAULT_SEND_FUTURE_AND_READY_TXS_TESTS_TIMEOUT_IN_SECS;
#[tokio::test(flavor = "multi_thread")]
#[ignore]
async fn send_future_and_ready_from_many_accounts_to_parachain() {
- let net = NetworkSpawner::from_toml_with_env_logger(PARACHAIN_HIGH_POOL_LIMIT_FATP)
+ let net = NetworkSpawner::from_toml_with_env_logger(para::HIGH_POOL_LIMIT_FATP)
.await
.unwrap();
@@ -86,7 +87,7 @@ async fn send_future_and_ready_from_many_accounts_to_parachain() {
#[tokio::test(flavor = "multi_thread")]
#[ignore]
async fn send_future_and_ready_from_many_accounts_to_relaychain() {
- let net = NetworkSpawner::from_toml_with_env_logger(RELAYCHAIN_HIGH_POOL_LIMIT_FATP)
+ let net = NetworkSpawner::from_toml_with_env_logger(relay::HIGH_POOL_LIMIT_FATP)
.await
.unwrap();
@@ -133,3 +134,241 @@ async fn send_future_and_ready_from_many_accounts_to_relaychain() {
assert_eq!(finalized_future, 10_000);
assert_eq!(finalized_ready, 10_000);
}
+
+// Test which sends 5m transactions to parachain. Long execution time expected.
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn send_5m_from_many_accounts_to_parachain() {
+ let net = NetworkSpawner::from_toml_with_env_logger(para::HIGH_POOL_LIMIT_FATP)
+ .await
+ .unwrap();
+
+ // Wait for the parachain collator to start block production.
+ net.wait_for_block_production("charlie").await.unwrap();
+
+ // Create txs executor.
+ let ws = net.node_rpc_uri("charlie").unwrap();
+ let executor = default_zn_scenario_builder(&net)
+ .with_rpc_uri(ws)
+ .with_start_id(0)
+ .with_last_id(999)
+ .with_txs_count(5_000)
+ .with_executor_id("txs-executor".to_string())
+ .with_send_threshold(7500)
+ .build()
+ .await;
+
+ // Execute transactions and fetch the execution logs.
+ let execution_logs = executor.execute().await;
+ let finalized_txs = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count();
+
+ assert_eq!(finalized_txs, 5_000_000);
+}
+
+// Test which sends 5m transactions to relaychain. Long execution time expected.
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn send_5m_from_many_accounts_to_relaychain() {
+ let net = NetworkSpawner::from_toml_with_env_logger(relay::HIGH_POOL_LIMIT_FATP)
+ .await
+ .unwrap();
+
+ // Wait for the parachain collator to start block production.
+ net.wait_for_block_production("alice").await.unwrap();
+
+ // Create txs executor.
+ let ws = net.node_rpc_uri("alice").unwrap();
+ let executor = default_zn_scenario_builder(&net)
+ .with_rpc_uri(ws.clone())
+ .with_start_id(0)
+ .with_last_id(999)
+ .with_txs_count(5000)
+ .with_executor_id("txs-executor".to_string())
+ .with_send_threshold(7500)
+ .build()
+ .await;
+
+ // Execute transactions and fetch the execution logs.
+ let execution_logs = executor.execute().await;
+ let finalized_txs = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count();
+
+ assert_eq!(finalized_txs, 5_000_000);
+}
+
+/// Internal test that allows to observe how transcactions are gossiped in the network. Requires
+/// external tool to track transactions presence at nodes. Was used to evaluate some metrics of
+/// existing transaction protocol.
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn gossiping() {
+ let net = NetworkSpawner::from_toml_with_env_logger(relay::HIGH_POOL_LIMIT_FATP_TRACE)
+ .await
+ .unwrap();
+
+ // Wait for the parachain collator to start block production.
+ net.wait_for_block_production("a00").await.unwrap();
+
+ // Create the txs executor.
+ let ws = net.node_rpc_uri("a00").unwrap();
+ let executor = default_zn_scenario_builder(&net)
+ .with_rpc_uri(ws)
+ .with_start_id(0)
+ .with_last_id(999)
+ .with_executor_id("txs-executor".to_string())
+ .build()
+ .await;
+
+ // Execute transactions and fetch the execution logs.
+ let execution_logs = executor.execute().await;
+ let finalized_txs = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count();
+
+ assert_eq!(finalized_txs, 1000);
+
+ tracing::info!("BASEDIR: {:?}", net.base_dir_path());
+}
+
+/// Creates new transaction scenario executor and sends given batch of ready transactions to the
+/// specified node. Single transaction is sent from single account.
+async fn send_batch(
+ net: &NetworkSpawner,
+ node_name: &str,
+ from: u32,
+ to: u32,
+ prio: u32,
+) -> ScenarioExecutor {
+ let ws = net.node_rpc_uri(node_name).unwrap();
+ info!(from, to, prio, "send_batch");
+ default_zn_scenario_builder(net)
+ .with_rpc_uri(ws)
+ .with_start_id(from)
+ .with_last_id(to)
+ .with_txs_count(1)
+ .with_tip(prio.into())
+ .with_executor_id(format!("txs-executor_{}_{}_{}", from, to, prio))
+ .with_send_threshold(usize::MAX)
+ .with_legacy_backend(true)
+ .build()
+ .await
+}
+
+/// Repeatedly sends batches of transactions to the specified node with priority provided by
+/// closure.
+///
+/// This function loops indefinitely, adjusting the priority of the transaction batch each time
+/// based on the provided function. Each batch is executed by an executor that times out after
+/// period duration if not completed.
+///
+/// The progress of transactions is intentionally not monitored; the utility is intended for
+/// transaction pool limits testing, where the accuracy of execution is challenging to monitor.
+async fn batch_loop(
+ net: &NetworkSpawner,
+ node_name: &str,
+ from: u32,
+ to: u32,
+ priority: F,
+ period: std::time::Duration,
+) where
+ F: Fn(u32) -> u32,
+{
+ let mut prio = 0;
+ loop {
+ prio = priority(prio);
+ let executor = send_batch(&net, node_name, from, to, prio).await;
+ let start = std::time::Instant::now();
+ let _results = tokio::time::timeout(period, executor.execute()).await;
+ let elapsed = start.elapsed();
+ if elapsed < period {
+ tokio::time::sleep(period - elapsed).await;
+ }
+ }
+}
+
+/// Tests the transaction pool limits by continuously sending transaction batches to a parachain
+/// network node. This test checks the pool's behavior under high load by simulating multiple
+/// senders with increasing priorities.
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn test_limits_increasing_prio_parachain() {
+ let net = NetworkSpawner::from_toml_with_env_logger(para::LOW_POOL_LIMIT_FATP)
+ .await
+ .unwrap();
+
+ net.wait_for_block_production("charlie").await.unwrap();
+
+ let mut executors = vec![];
+ let senders_count = 25;
+ let sender_batch = 2000;
+
+ for i in 0..senders_count {
+ let from = 0 + i * sender_batch;
+ let to = from + sender_batch - 1;
+ executors.push(batch_loop(
+ &net,
+ "charlie",
+ from,
+ to,
+ |prio| prio + 1,
+ Duration::from_secs(60),
+ ));
+ }
+
+ let _results = join_all(executors).await;
+}
+
+/// Tests the transaction pool limits by continuously sending transaction batches to a relaychain
+/// network node. This test checks the pool's behavior under high load by simulating multiple
+/// senders with increasing priorities.
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn test_limits_increasing_prio_relaychain() {
+ let net = NetworkSpawner::from_toml_with_env_logger(relay::LOW_POOL_LIMIT_FATP)
+ .await
+ .unwrap();
+
+ net.wait_for_block_production("alice").await.unwrap();
+
+ let mut executors = vec![];
+ //this looks like current limit of what we can handle. A bit choky but almost no empty blocks.
+ let senders_count = 50;
+ let sender_batch = 2000;
+
+ for i in 0..senders_count {
+ let from = 0 + i * sender_batch;
+ let to = from + sender_batch - 1;
+ executors.push(batch_loop(
+ &net,
+ "alice",
+ from,
+ to,
+ |prio| prio + 1,
+ Duration::from_secs(15),
+ ));
+ }
+
+ let _results = join_all(executors).await;
+}
+
+/// Tests the transaction pool limits by continuously sending transaction batches to a relaychain
+/// network node. This test checks the pool's behavior under high load by simulating multiple
+/// senders with increasing priorities.
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn test_limits_same_prio_relaychain() {
+ let net = NetworkSpawner::from_toml_with_env_logger(relay::LOW_POOL_LIMIT_FATP)
+ .await
+ .unwrap();
+
+ net.wait_for_block_production("alice").await.unwrap();
+
+ let mut executors = vec![];
+ let senders_count = 50;
+ let sender_batch = 2000;
+
+ for i in 0..senders_count {
+ let from = 0 + i * sender_batch;
+ let to = from + sender_batch - 1;
+ executors.push(batch_loop(&net, "alice", from, to, |prio| prio, Duration::from_secs(15)));
+ }
+
+ let _results = join_all(executors).await;
+}
diff --git a/substrate/client/transaction-pool/tests/zombienet/mod.rs b/substrate/client/transaction-pool/tests/zombienet/mod.rs
index 206c69b0c657b..3c55d207ab24d 100644
--- a/substrate/client/transaction-pool/tests/zombienet/mod.rs
+++ b/substrate/client/transaction-pool/tests/zombienet/mod.rs
@@ -20,10 +20,12 @@
//! across integration tests for transaction pool.
use anyhow::anyhow;
+use std::time::SystemTime;
use tracing_subscriber::EnvFilter;
use txtesttool::scenario::{ChainType, ScenarioBuilder};
use zombienet_sdk::{
- subxt::SubstrateConfig, LocalFileSystem, Network, NetworkConfig, NetworkConfigExt,
+ subxt::SubstrateConfig, GlobalSettingsBuilder, LocalFileSystem, Network, NetworkConfig,
+ NetworkConfigBuilder, NetworkConfigExt, WithRelaychain,
};
/// Gathers TOML files paths for relaychains and for parachains' (that use rococo-local based
@@ -31,6 +33,10 @@ use zombienet_sdk::{
pub mod relaychain_rococo_local_network_spec {
pub const HIGH_POOL_LIMIT_FATP: &'static str =
"tests/zombienet/network-specs/rococo-local-high-pool-limit-fatp.toml";
+ pub const LOW_POOL_LIMIT_FATP: &'static str =
+ "tests/zombienet/network-specs/rococo-local-low-pool-limit-fatp.toml";
+ pub const HIGH_POOL_LIMIT_FATP_TRACE: &'static str =
+ "tests/zombienet/network-specs/rococo-local-gossiping.toml";
/// Network specs used for fork-aware tx pool testing of parachains.
pub mod parachain_asset_hub_network_spec {
@@ -41,6 +47,8 @@ pub mod relaychain_rococo_local_network_spec {
}
}
+mod yap_test;
+
/// Default time that we expect to need for a full run of current tests that send future and ready
/// txs to parachain or relaychain networks.
pub const DEFAULT_SEND_FUTURE_AND_READY_TXS_TESTS_TIMEOUT_IN_SECS: u64 = 1500;
@@ -60,12 +68,57 @@ pub enum Error {
/// Result of work related to network spawning.
pub type Result = std::result::Result;
+/// Environment variable defining the location of zombienet network base dir.
+const TXPOOL_TEST_DIR_ENV: &str = "TXPOOL_TEST_DIR";
+
/// Provides logic to spawn a network based on a Zombienet toml file.
pub struct NetworkSpawner {
network: Network,
}
impl NetworkSpawner {
+ /// Initialize the network spawner using given `builder` closure.
+ pub async fn with_closure(builder: F) -> Result
+ where
+ F: FnOnce() -> NetworkConfigBuilder,
+ {
+ let _ = env_logger::try_init_from_env(
+ env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
+ );
+
+ let config_builder = builder();
+
+ let net_config = config_builder
+ .with_global_settings(|global_settings| match NetworkSpawner::base_dir_from_env() {
+ Some(val) => global_settings.with_base_dir(val),
+ _ => global_settings,
+ })
+ .build()
+ .map_err(|errs| {
+ let msg = errs.into_iter().map(|e| e.to_string()).collect::>().join(", ");
+ Error::NetworkInit(anyhow!(msg))
+ })?;
+
+ Ok(NetworkSpawner {
+ network: net_config
+ .spawn_native()
+ .await
+ .map_err(|err| Error::NetworkInit(anyhow!(err.to_string())))?,
+ })
+ }
+
+ /// Generates a directory path from an environment variable and the current timestamp.
+ /// The format is "/test_YMD_HMS"
+ pub fn base_dir_from_env() -> Option {
+ std::env::var(TXPOOL_TEST_DIR_ENV)
+ .map(|pool_test_dir| {
+ let datetime: chrono::DateTime = SystemTime::now().into();
+ let formatted_date = datetime.format("%Y%m%d_%H%M%S");
+ format!("{}/test_{}", pool_test_dir, formatted_date)
+ })
+ .ok()
+ }
+
/// Initialize the network spawner based on a Zombienet toml file
pub async fn from_toml_with_env_logger(toml_path: &'static str) -> Result {
// Initialize the subscriber with a default log level of INFO if RUST_LOG is not set
@@ -76,7 +129,15 @@ impl NetworkSpawner {
.with_env_filter(env_filter) // Use the env filter
.init();
- let net_config = NetworkConfig::load_from_toml(toml_path).map_err(Error::NetworkInit)?;
+ let net_config = if let Some(base_dir) = Self::base_dir_from_env() {
+ let settings = GlobalSettingsBuilder::new().with_base_dir(base_dir).build().unwrap();
+ NetworkConfig::load_from_toml_with_settings(toml_path, &settings)
+ .map_err(Error::NetworkInit)?
+ } else {
+ tracing::info!("'{TXPOOL_TEST_DIR_ENV}' env not set, proceeding with defaults.");
+ NetworkConfig::load_from_toml(toml_path).map_err(Error::NetworkInit)?
+ };
+
Ok(NetworkSpawner {
network: net_config
.spawn_native()
@@ -164,4 +225,5 @@ pub fn default_zn_scenario_builder(net_spawner: &NetworkSpawner) -> ScenarioBuil
.with_block_monitoring(shared_params.does_block_monitoring)
.with_chain_type(shared_params.chain_type)
.with_base_dir_path(net_spawner.base_dir_path().unwrap().to_string())
+ .with_timeout_in_secs(21600) //6 hours
}
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 8ca7a134e18ae..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
@@ -40,7 +40,7 @@ default_args = [
]
[parachains.genesis.runtimeGenesis.patch.balances]
devAccounts = [
- 100,
+ 1000,
1000000000000000000,
"//Sender//{}",
]
diff --git a/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-low-pool-limit-fatp.toml b/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-low-pool-limit-fatp.toml
index 2a4a276eb1913..3c0b603d09e19 100644
--- a/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-low-pool-limit-fatp.toml
+++ b/substrate/client/transaction-pool/tests/zombienet/network-specs/asset-hub-low-pool-limit-fatp.toml
@@ -24,9 +24,9 @@ default_command = "polkadot-parachain"
default_args = [
"--force-authoring",
"--pool-kbytes 2048000",
- "--pool-limit 300",
+ "--pool-limit 10000",
"--pool-type=fork-aware",
- "--rpc-max-connections 15000",
+ "--rpc-max-connections 100000",
"--rpc-max-response-size 150",
"--rpc-max-subscriptions-per-connection=128000",
"--state-pruning=1024",
@@ -36,10 +36,11 @@ default_args = [
"-lsub-libp2p=info",
"-lsync=info",
"-ltxpool=debug",
+ "-ltxpoolstat=debug",
]
[parachains.genesis.runtimeGenesis.patch.balances]
devAccounts = [
- 100,
+ 80000,
1000000000000000000,
"//Sender//{}",
]
diff --git a/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-gossiping.toml b/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-gossiping.toml
new file mode 100644
index 0000000000000..4c62372a6a275
--- /dev/null
+++ b/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-gossiping.toml
@@ -0,0 +1,112 @@
+[settings]
+timeout = 1500
+
+[relaychain]
+default_image = "parity/polkadot:latest"
+default_command = "polkadot"
+chain = "rococo-local"
+default_args = [
+ # "--network-backend litep2p",
+ "--pool-kbytes 2048000",
+ "--pool-limit 500000",
+ "--pool-type=fork-aware",
+ "--rpc-max-connections 15000",
+ "--rpc-max-response-size 150",
+ "--rpc-max-subscriptions-per-connection=128000",
+ "--state-pruning=1024",
+ "-ltxpool=trace",
+ "-lsync=trace",
+ "--out-peers=3",
+ "--in-peers=3",
+]
+[relaychain.genesis.runtimeGenesis.patch.balances]
+devAccounts = [
+ 1000,
+ 1000000000000000000,
+ "//Sender//{}",
+]
+
+[[relaychain.nodes]]
+name = "a00"
+rpc_port = 9944
+validator = true
+
+[[relaychain.nodes]]
+name = "b00"
+validator=true
+
+[[relaychain.nodes]]
+name = "b01"
+validator=true
+
+[[relaychain.nodes]]
+name = "b02"
+validator=true
+
+[[relaychain.nodes]]
+name = "b03"
+validator=true
+
+[[relaychain.nodes]]
+name = "b04"
+validator=true
+
+[[relaychain.nodes]]
+name = "b05"
+validator=true
+
+[[relaychain.nodes]]
+name = "b06"
+validator=true
+
+[[relaychain.nodes]]
+name = "b07"
+validator=true
+
+[[relaychain.nodes]]
+name = "b08"
+validator=true
+
+[[relaychain.nodes]]
+name = "b09"
+validator=true
+
+[[relaychain.nodes]]
+name = "b10"
+validator=true
+
+[[relaychain.nodes]]
+name = "b11"
+validator=true
+
+[[relaychain.nodes]]
+name = "b12"
+validator=true
+
+[[relaychain.nodes]]
+name = "b13"
+validator=true
+
+[[relaychain.nodes]]
+name = "b14"
+validator=true
+
+[[relaychain.nodes]]
+name = "b15"
+validator=true
+
+[[relaychain.nodes]]
+name = "b16"
+validator=true
+
+[[relaychain.nodes]]
+name = "b17"
+validator=true
+
+[[relaychain.nodes]]
+name = "b18"
+validator=true
+
+[[relaychain.nodes]]
+name = "b19"
+validator=true
diff --git a/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-high-pool-limit-fatp.toml b/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-high-pool-limit-fatp.toml
index a67e0a4f444e5..5b601c1055750 100644
--- a/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-high-pool-limit-fatp.toml
+++ b/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-high-pool-limit-fatp.toml
@@ -18,7 +18,7 @@ default_args = [
]
[relaychain.genesis.runtimeGenesis.patch.balances]
devAccounts = [
- 100,
+ 1000,
1000000000000000000,
"//Sender//{}",
]
diff --git a/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-low-pool-limit-fatp.toml b/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-low-pool-limit-fatp.toml
new file mode 100644
index 0000000000000..df5b3a3e288ad
--- /dev/null
+++ b/substrate/client/transaction-pool/tests/zombienet/network-specs/rococo-local-low-pool-limit-fatp.toml
@@ -0,0 +1,42 @@
+[settings]
+timeout = 1500
+
+[relaychain]
+default_image = "parity/polkadot:latest"
+default_command = "polkadot"
+chain = "rococo-local"
+default_args = [
+ "--pool-kbytes 2048000",
+ "--pool-limit 100000",
+ "--pool-type=fork-aware",
+ "--rpc-max-connections 15000",
+ "--rpc-max-response-size 150",
+ "--rpc-max-subscriptions-per-connection=128000",
+ "--state-pruning=1024",
+ "-lsync=info",
+ "-ltxpool=debug",
+ "-ltxpoolstat=debug",
+]
+[relaychain.genesis.runtimeGenesis.patch.balances]
+devAccounts = [
+ 100000,
+ 1000000000000000000,
+ "//Sender//{}",
+]
+
+[[relaychain.nodes]]
+# command = "/home/miszka/parity/14-txpool-forks/polkadot-sdk-master-02/target/release-tokio-console/polkadot"
+name = "alice"
+rpc_port = 9944
+validator = false
+
+[[relaychain.nodes]]
+name = "bob"
+rpc_port = 9945
+validator = true
+
+
+[[relaychain.nodes]]
+name = "charlie"
+rpc_port = 9946
+validator = true
diff --git a/substrate/client/transaction-pool/tests/zombienet/yap_test.rs b/substrate/client/transaction-pool/tests/zombienet/yap_test.rs
new file mode 100644
index 0000000000000..19ae86b361cfb
--- /dev/null
+++ b/substrate/client/transaction-pool/tests/zombienet/yap_test.rs
@@ -0,0 +1,145 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+// Test inspired (copied) from:
+// https://github.com/paritytech/polkadot-sdk/blob/85b71daf7aac59da4d2186b45d589c7c619f0981/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_3cores.rs#L21
+// and patched as in:
+// https://github.com/paritytech/polkadot-sdk/pull/7220#issuecomment-2808830472
+
+use crate::zombienet::{NetworkSpawner, ScenarioBuilderSharedParams};
+use cumulus_zombienet_sdk_helpers::create_assign_core_call;
+use serde_json::json;
+use txtesttool::{execution_log::ExecutionLog, scenario::ScenarioBuilder};
+use zombienet_sdk::{
+ subxt::{OnlineClient, PolkadotConfig},
+ subxt_signer::sr25519::dev,
+ NetworkConfigBuilder,
+};
+
+#[tokio::test(flavor = "multi_thread")]
+#[ignore]
+async fn slot_based_3cores_test() -> Result<(), anyhow::Error> {
+ let spawner = NetworkSpawner::with_closure(|| {
+ let images = zombienet_sdk::environment::get_images_from_env();
+ let names = ["alice", "bob", "charlie"];
+ NetworkConfigBuilder::new()
+ .with_relaychain(|r| {
+ let r = r
+ .with_chain("rococo-local")
+ .with_default_command("polkadot")
+ .with_default_image(images.polkadot.as_str())
+ .with_default_args(vec![("-lparachain=debug").into()])
+ .with_genesis_overrides(json!({
+ "configuration": {
+ "config": {
+ "scheduler_params": {
+ // Num cores is 2, because 1 extra will be added automatically when registering the para.
+ "num_cores": 2,
+ "max_validators_per_core": 1
+ }
+ }
+ }
+ }))
+ .with_default_resources(|resources| {
+ resources.with_request_cpu(4).with_request_memory("4G")
+ })
+ // Have to set a `with_node` outside of the loop below, so that `r` has the
+ // right type.
+ .with_node(|node| node.with_name(names[0]));
+
+ (1..3).fold(r, |acc, i| acc.with_node(|node| node.with_name(names[i])))
+ })
+ .with_parachain(|p| {
+ // Para 2200 uses the new RFC103-enabled collator which sends the UMP signal
+ // commitment for selecting the core index
+ p.with_id(2200)
+ .with_default_command("polkadot-parachain")
+ .with_default_image(images.cumulus.as_str())
+ .with_chain("yap-rococo-local-2200")
+ .with_genesis_overrides(json!({
+ "balances": {
+ "devAccounts": [
+ 100000, 1000000000000000000u64, "//Sender//{}"
+ ]
+ }
+ }))
+ .with_default_args(vec![
+ "--authoring=slot-based".into(),
+ "--rpc-max-subscriptions-per-connection=256000".into(),
+ "--rpc-max-connections=128000".into(),
+ "--rpc-max-response-size=150".into(),
+ "--pool-limit=2500000".into(),
+ "--pool-kbytes=4048000".into(),
+ "--pool-type=fork-aware".into(),
+ ("-lparachain=debug,aura=debug,txpool=debug,txpoolstat=debug").into(),
+ ])
+ .with_collator(|n| n.with_name("dave").with_rpc_port(9944))
+ })
+ })
+ .await
+ .unwrap();
+
+ let relay_node = spawner.network().get_node("alice")?;
+
+ let relay_client: OnlineClient = relay_node.wait_client().await?;
+ let alice = dev::alice();
+
+ let assign_cores_call = create_assign_core_call(&[(0, 2200), (1, 2200)]);
+ // Assign two extra cores to each parachain.
+ relay_client
+ .tx()
+ .sign_and_submit_then_watch_default(&assign_cores_call, &alice)
+ .await?
+ .wait_for_finalized_success()
+ .await?;
+
+ tracing::info!("2 more cores assigned to the parachain");
+
+ // Wait for the parachain collator to start block production.
+ spawner.wait_for_block_production("dave").await.unwrap();
+
+ // Create txs executor.
+ let ws = spawner.node_rpc_uri("dave").unwrap();
+ let executor = {
+ let shared_params = ScenarioBuilderSharedParams::default();
+ ScenarioBuilder::new()
+ .with_watched_txs(shared_params.watched_txs)
+ .with_send_threshold(shared_params.send_threshold)
+ .with_block_monitoring(shared_params.does_block_monitoring)
+ .with_chain_type(shared_params.chain_type)
+ .with_base_dir_path(spawner.base_dir_path().unwrap().to_string())
+ .with_timeout_in_secs(21600) //6 hours
+ .with_legacy_backend(true)
+ }
+ .with_rpc_uri(ws)
+ .with_start_id(0)
+ .with_last_id(99999)
+ .with_txs_count(150)
+ .with_executor_id("txs-executor".to_string())
+ .with_send_threshold(25000)
+ .build()
+ .await;
+
+ // Execute transactions and fetch the execution logs.
+ let execution_logs = executor.execute().await;
+ let finalized_txs = execution_logs.values().filter_map(|tx_log| tx_log.finalized()).count();
+
+ assert_eq!(finalized_txs, 15_000_000);
+
+ Ok(())
+}