Skip to content

Commit

Permalink
rewrite first test using zombienet-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
alindima committed Dec 2, 2024
1 parent 478fbb7 commit 6f4dbb4
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 52 deletions.
45 changes: 16 additions & 29 deletions .gitlab/pipeline/zombienet/polkadot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,35 +190,6 @@ zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains:
--local-dir="${LOCAL_DIR}/elastic_scaling"
--test="0002-elastic-scaling-doesnt-break-parachains.zndsl"

zombienet-polkadot-elastic-scaling-0003-slot-based-3cores:
extends:
- .zombienet-polkadot-common
variables:
FORCED_INFRA_INSTANCE: "spot-iops"
before_script:
- !reference [ .zombienet-polkadot-common, before_script ]
- cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/elastic_scaling
# override COL_IMAGE to use test-parachain
- export COL_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}"
script:
- /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh
--local-dir="${LOCAL_DIR}/elastic_scaling"
--test="0003-slot-based-3cores.zndsl"

zombienet-polkadot-elastic-scaling-0004-mixed-receipt-versions:
extends:
- .zombienet-polkadot-common
variables:
FORCED_INFRA_INSTANCE: "spot-iops"
before_script:
- !reference [ .zombienet-polkadot-common, before_script ]
- cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/elastic_scaling
# override COL_IMAGE to use test-parachain
- export COL_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}"
script:
- /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh
--local-dir="${LOCAL_DIR}/elastic_scaling"
--test="0004-mixed-receipt-versions.zndsl"

.zombienet-polkadot-functional-0012-spam-statement-distribution-requests:
extends:
Expand Down Expand Up @@ -416,3 +387,19 @@ zombienet-polkadot-malus-0001-dispute-valid:
- unset NEXTEST_FAILURE_OUTPUT
- unset NEXTEST_SUCCESS_OUTPUT
- cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- smoke::coretime_revenue::coretime_revenue_test

zombienet-polkadot-coretime-revenue:
extends:
- .zombienet-polkadot-common
needs:
- job: build-polkadot-zombienet-tests
artifacts: true
before_script:
- !reference [ ".zombienet-polkadot-common", "before_script" ]
- export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
- export CUMULUS_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}
script:
# we want to use `--no-capture` in zombienet tests.
- unset NEXTEST_FAILURE_OUTPUT
- unset NEXTEST_SUCCESS_OUTPUT
- cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- elastic_scaling::slot_based_3cores::slot_based_3cores_test
65 changes: 43 additions & 22 deletions polkadot/zombienet-sdk-tests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,47 @@ fn make_env_key(k: &str) -> String {
replace_dashes(&k.to_ascii_uppercase())
}

fn wasm_sub_path(chain: &str) -> String {
let (package, runtime_name) =
if let Some(cumulus_test_runtime) = chain.strip_prefix("cumulus-test-runtime-") {
(
"cumulus-test-runtime".to_string(),
format!("wasm_binary_{}.rs", replace_dashes(cumulus_test_runtime)),
)
} else {
(format!("{chain}-runtime"), replace_dashes(&format!("{chain}-runtime")))
};

format!("{}/{}.wasm", package, runtime_name)
}

fn find_wasm(chain: &str) -> Option<PathBuf> {
const PROFILES: [&str; 2] = ["release", "testnet"];
let manifest_path = env::var("CARGO_WORKSPACE_ROOT_DIR").unwrap();
let manifest_path = manifest_path.strip_suffix('/').unwrap();
debug_output!("manifest_path is : {}", manifest_path);
let package = format!("{chain}-runtime");

let sub_path = wasm_sub_path(chain);

let profile = PROFILES.into_iter().find(|p| {
let full_path = format!(
"{}/target/{}/wbuild/{}/{}.wasm",
manifest_path,
p,
&package,
replace_dashes(&package)
);
let full_path = format!("{}/target/{}/wbuild/{}", manifest_path, p, sub_path);
debug_output!("checking wasm at : {}", full_path);
matches!(path::PathBuf::from(&full_path).try_exists(), Ok(true))
});

debug_output!("profile is : {:?}", profile);
profile.map(|profile| {
PathBuf::from(&format!(
"{}/target/{}/wbuild/{}/{}.wasm",
manifest_path,
profile,
&package,
replace_dashes(&package)
))
PathBuf::from(&format!("{}/target/{}/wbuild/{}", manifest_path, profile, sub_path))
})
}

// based on https://gist.github.com/s0me0ne-unkn0wn/bbd83fe32ce10327086adbf13e750eec
fn build_wasm(chain: &str) -> PathBuf {
let package = format!("{chain}-runtime");
let package = if chain.starts_with("cumulus-test-runtime-") {
String::from("cumulus-test-runtime")
} else {
format!("{chain}-runtime")
};

let cargo = env::var("CARGO").unwrap();
let target = env::var("TARGET").unwrap();
Expand All @@ -68,7 +76,7 @@ fn build_wasm(chain: &str) -> PathBuf {
"-p",
&package,
"--profile",
"release",
"testnet",
"--target",
&target,
"--target-dir",
Expand All @@ -81,11 +89,7 @@ fn build_wasm(chain: &str) -> PathBuf {
.status()
.unwrap();

let wasm_path = &format!(
"{target_dir}/{target}/release/wbuild/{}/{}.wasm",
&package,
replace_dashes(&package)
);
let wasm_path = &format!("{target_dir}/{target}/testnet/wbuild/{}", wasm_sub_path(chain));
PathBuf::from(wasm_path)
}

Expand Down Expand Up @@ -127,6 +131,8 @@ fn main() {
let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap();
const METADATA_DIR: &str = "metadata-files";
const CHAINS: [&str; 2] = ["rococo", "coretime-rococo"];
const CUMULUS_TEST_RUNTIMES: [&str; 2] =
["cumulus-test-runtime-elastic-scaling", "cumulus-test-runtime-elastic-scaling-mvp"];

let metadata_path = format!("{manifest_path}/{METADATA_DIR}");

Expand All @@ -145,6 +151,21 @@ fn main() {
};
}

for chain in CUMULUS_TEST_RUNTIMES {
let full_path = format!("{metadata_path}/{chain}-local.scale");
let output_path = path::PathBuf::from(&full_path);

match output_path.try_exists() {
Ok(true) => {
debug_output!("got: {}", full_path);
},
_ => {
debug_output!("needs: {}", full_path);
fetch_metadata_file(chain, &output_path);
},
};
}

substrate_build_script_utils::generate_cargo_keys();
substrate_build_script_utils::rerun_if_git_head_changed();
println!("cargo:rerun-if-changed={}", metadata_path);
Expand Down
5 changes: 5 additions & 0 deletions polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

#[cfg(feature = "zombie-metadata")]
mod slot_based_3cores;
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Test that parachains that use a single slot-based collator with elastic scaling MVP and with
// elastic scaling with RFC103 can achieve full throughput of 3 candidates per block.

use anyhow::anyhow;
#[subxt::subxt(runtime_metadata_path = "metadata-files/rococo-local.scale")]
pub mod rococo {}

#[subxt::subxt(
runtime_metadata_path = "metadata-files/cumulus-test-runtime-elastic-scaling-local.scale"
)]
mod elastic_scaling_para {}

#[subxt::subxt(
runtime_metadata_path = "metadata-files/cumulus-test-runtime-elastic-scaling-mvp-local.scale"
)]
mod elastic_scaling_mvp_para {}

use rococo::runtime_types::{
pallet_broker::coretime_interface::CoreAssignment,
polkadot_runtime_parachains::assigner_coretime::PartsOf57600,
};
use serde_json::json;
use std::collections::HashMap;
use subxt::{OnlineClient, PolkadotConfig};
use subxt_signer::sr25519::dev;
use zombienet_sdk::NetworkConfigBuilder;

use rococo::{self as rococo_api};

#[tokio::test(flavor = "multi_thread")]
async fn slot_based_3cores_test() -> Result<(), anyhow::Error> {
env_logger::init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);

let images = zombienet_sdk::environment::get_images_from_env();

let config = NetworkConfigBuilder::new()
.with_relaychain(|r| {
let r = r
.with_chain("rococo-local")
.with_default_command("polkadot")
.with_default_image(images.polkadot.as_str())
.with_genesis_overrides(json!({
"configuration": {
"config": {
"scheduler_params": {
// Num cores is 4, because 2 extra will be added automatically when registering the paras.
"num_cores": 4,
"max_validators_per_core": 1
},
"async_backing_params": {
"max_candidate_depth": 6,
"allowed_ancestry_len": 2
}
}
}
}))
// Have to set a `with_node` outside of the loop below, so that `r` has the right
// type.
.with_node(|node| node.with_name(&format!("validator-0")));

(1..6)
.into_iter()
.fold(r, |acc, i| acc.with_node(|node| node.with_name(&format!("validator-{i}"))))
})
.with_parachain(|p| {
// Para 2100 uses the old elastic scaling mvp, which doesn't send the new UMP signal
// commitment for selecting the core index.
p.with_id(2100)
.with_default_command("test-parachain")
.with_default_image(images.cumulus.as_str())
.with_chain("elastic-scaling-mvp")
.with_default_args(vec![("--experimental-use-slot-based").into()])
.with_collator(|n| n.with_name("collator-elastic-mvp"))
})
.with_parachain(|p| {
// Para 2200 uses the new RFC103-enabled collator which sens the UMP signal commitment
// for selecting the core index
p.with_id(2200)
.with_default_command("test-parachain")
.with_default_image(images.cumulus.as_str())
.with_chain("elastic-scaling")
.with_default_args(vec![("--experimental-use-slot-based").into()])
.with_collator(|n| n.with_name("collator-elastic"))
})
.build()
.map_err(|e| {
let errs = e.into_iter().map(|e| e.to_string()).collect::<Vec<_>>().join(" ");
anyhow!("config errs: {errs}")
})?;

let spawn_fn = zombienet_sdk::environment::get_spawn_fn();
let network = spawn_fn(config).await?;

let relay_node = network.get_node("validator-0")?;

let relay_client: OnlineClient<PolkadotConfig> = relay_node.wait_client().await?;
let alice = dev::alice();

// Assign two extra cores to each parachain.
relay_client
.tx()
.sign_and_submit_then_watch_default(
&rococo_api::tx().sudo().sudo(
rococo::runtime_types::rococo_runtime::RuntimeCall::Utility(
rococo::runtime_types::pallet_utility::pallet::Call::batch {
calls: vec![
rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime(
rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core {
core: 0,
begin: 0,
assignment: vec![(CoreAssignment::Task(2100), PartsOf57600(57600))],
end_hint: None
}
),
rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime(
rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core {
core: 1,
begin: 0,
assignment: vec![(CoreAssignment::Task(2100), PartsOf57600(57600))],
end_hint: None
}
),
rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime(
rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core {
core: 2,
begin: 0,
assignment: vec![(CoreAssignment::Task(2200), PartsOf57600(57600))],
end_hint: None
}
),
rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime(
rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core {
core: 3,
begin: 0,
assignment: vec![(CoreAssignment::Task(2200), PartsOf57600(57600))],
end_hint: None
}
)
],
},
),
),
&alice,
)
.await?
.wait_for_finalized_success()
.await?;

log::info!("2 more cores assigned to each parachain");

// Expect a backed candidate count of 40 for each parachain in 15 relay chain blocks (2.66
// candidates per para per relay chain block).
// Note that only blocks after the first session change and blocks that don't contain a session
// change will be counted.
assert_para_throughput(&relay_client, 15, [(2100, 40), (2200, 40)].into_iter().collect())
.await?;

log::info!("Test finished successfully");

Ok(())
}

async fn assert_para_throughput(
relay_client: &OnlineClient<PolkadotConfig>,
stop_at: u32,
expected_candidate_counts: HashMap<u32, u32>,
) -> Result<(), anyhow::Error> {
let mut blocks_sub = relay_client.blocks().subscribe_finalized().await?;
let mut candidate_count: HashMap<u32, u32> = HashMap::new();
let mut current_block_count = 0;
let mut had_first_session_change = false;

while let Some(block) = blocks_sub.next().await {
let block = block?;
log::debug!("Finalized relay chain block {}", block.number());
let events = block.events().await?;
let is_session_change = events.has::<rococo::session::events::NewSession>()?;

if !had_first_session_change && is_session_change {
had_first_session_change = true;
}

if had_first_session_change && !is_session_change {
current_block_count += 1;

for event in events.find::<rococo::para_inclusion::events::CandidateBacked>() {
*(candidate_count.entry(event?.0.descriptor.para_id.0).or_default()) += 1;
}
}

if current_block_count == stop_at {
break;
}
}

log::info!(
"Reached {} finalized relay chain blocks that contain backed candidates. The per-parachain distribution is: {:#?}",
stop_at,
candidate_count
);

for (para_id, expected_candidate_count) in expected_candidate_counts {
let actual = *candidate_count
.get(&para_id)
.expect("ParaId did not have any backed candidates");
assert!(
actual >= expected_candidate_count,
"Expected {expected_candidate_count} lower than actual {actual}"
);
}

Ok(())
}
Loading

0 comments on commit 6f4dbb4

Please sign in to comment.