Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 29 additions & 28 deletions .github/workflows/zombienet_polkadot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -224,34 +224,6 @@ jobs:
gh-token: ${{ secrets.GITHUB_TOKEN }}
build-id: ${{ needs.preflight.outputs.BUILD_RUN_ID }}
ref-slug: ${{ needs.preflight.outputs.SOURCE_REF_SLUG }}


#
zombienet-polkadot-functional-0010-validator-disabling:
needs: [preflight]
if: ${{ (needs.preflight.outputs.changes_substrate || needs.preflight.outputs.changes_polkadot) && ! contains(needs.preflight.outputs.FLAKY_TESTS, 'zombienet-polkadot-functional-0010-validator-disabling') }}
runs-on: ${{ needs.preflight.outputs.ZOMBIENET_LARGE_RUNNER }}
timeout-minutes: 60
container:
image: ${{ needs.preflight.outputs.ZOMBIENET_IMAGE }}
env:
ZOMBIENET_INTEGRATION_TEST_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/polkadot-debug:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
COL_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/colander:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
MALUS_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/malus:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
DEBUG: ${{ needs.preflight.outputs.DEBUG }}
ZOMBIENET_PROVIDER: ${{ needs.preflight.outputs.ZOMBIENET_PROVIDER }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: zombienet_test
uses: ./.github/actions/zombienet
with:
test: "0010-validator-disabling.zndsl"
local-dir: "${{ env.LOCAL_DIR }}/functional"
gh-token: ${{ secrets.GITHUB_TOKEN }}
build-id: ${{ needs.preflight.outputs.BUILD_RUN_ID }}
ref-slug: ${{ needs.preflight.outputs.SOURCE_REF_SLUG }}
#
#
zombienet-polkadot-functional-0013-systematic-chunk-recovery:
Expand Down Expand Up @@ -996,6 +968,35 @@ jobs:
test: "functional::approved_peer_mixed_validators::approved_peer_mixed_validators_test"
prefix: "polkadot"

#
#
zombienet-polkadot-functional-validator-disabling:
needs: [preflight]
if: ${{ (needs.preflight.outputs.changes_substrate || needs.preflight.outputs.changes_polkadot) && ! contains(needs.preflight.outputs.FLAKY_TESTS, 'zombienet-polkadot-functional-0010-validator-disabling') }}
runs-on: ${{ needs.preflight.outputs.ZOMBIENET_LARGE_RUNNER }}
timeout-minutes: 60
container:
image: ${{ needs.preflight.outputs.ZOMBIENET_SDK_IMAGE }}
env:
POLKADOT_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/polkadot-debug:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
COL_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/colander:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
CUMULUS_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/polkadot-parachain-debug:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
MALUS_IMAGE: "${{ needs.preflight.outputs.TEMP_IMAGES_BASE }}/malus:${{ needs.preflight.outputs.DOCKER_IMAGES_VERSION }}"
RUST_LOG: ${{ needs.preflight.outputs.RUST_LOG }}
ZOMBIE_PROVIDER: ${{ needs.preflight.outputs.ZOMBIE_PROVIDER }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: zombienet_test
uses: ./.github/actions/zombienet-sdk
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
build-id: ${{ needs.preflight.outputs.BUILD_RUN_ID }}
ref-slug: ${{ needs.preflight.outputs.SOURCE_REF_SLUG }}
test: "functional::validator_disabling::validator_disabling_test"
prefix: "polkadot"

#
#
zombienet-polkadot-shared-core-idle-parachain:
Expand Down
2 changes: 1 addition & 1 deletion cumulus/zombienet/zombienet-sdk-helpers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub async fn assert_finalized_para_throughput(
for (para_id, expected_candidate_range) in expected_candidate_ranges {
let actual = candidate_count
.get(&para_id)
.expect("ParaId did not have any backed candidates");
.unwrap_or_else(|| panic!("ParaId: {para_id} did not have any backed candidates"));
assert!(
expected_candidate_range.contains(actual),
"Candidate count {actual} not within range {expected_candidate_range:?}"
Expand Down
1 change: 1 addition & 0 deletions polkadot/zombienet-sdk-tests/tests/functional/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ mod duplicate_collations;
mod shared_core_idle_parachain;
mod spam_statement_distribution_requests;
mod sync_backing;
mod validator_disabling;
142 changes: 142 additions & 0 deletions polkadot/zombienet-sdk-tests/tests/functional/validator_disabling.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Test checks that misbehaving validators disabled.

use anyhow::anyhow;

use cumulus_zombienet_sdk_helpers::assert_finalized_para_throughput;
use polkadot_primitives::{BlockNumber, CandidateHash, DisputeState, SessionIndex};
use serde_json::json;
use tokio::time::Duration;
use zombienet_orchestrator::network::node::LogLineCountOptions;
use zombienet_sdk::{
subxt::{OnlineClient, PolkadotConfig},
NetworkConfigBuilder,
};

#[tokio::test(flavor = "multi_thread")]
async fn validator_disabling_test() -> Result<(), anyhow::Error> {
let _ = env_logger::try_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_builder = NetworkConfigBuilder::new()
.with_relaychain(|r| {
let r = r
.with_chain("westend-local") // Use westend-local so the disabling can take effect.
.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": {
"group_rotation_frequency": 10,
"max_validators_per_core": 1
},
"needed_approvals": 2,
}
}
}))
// Adding malicious validator.
.with_node(|node| {
node.with_name("malus-validator")
.with_image(
std::env::var("MALUS_IMAGE")
.unwrap_or("docker.io/paritypr/malus".to_string())
.as_str(),
)
.with_command("malus")
.with_subcommand("suggest-garbage-candidate")
.with_args(vec![
"-lMALUS=trace".into(),
// Without this the malus validator won't run on macOS.
"--insecure-validator-i-know-what-i-do".into(),
])
// Make it vulenrable so disabling really happens
.invulnerable(false)
});
// Also honest validators.
let r = (0..3).fold(r, |acc, i| {
acc.with_node(|node| {
node.with_name(&format!("honest-validator-{i}"))
.with_args(vec![("-lparachain=debug,runtime::staking=debug".into())])
})
});
r
})
.with_parachain(|p| {
p.with_id(1000)
.with_default_command("adder-collator")
.cumulus_based(false)
.with_default_image(images.cumulus.as_str())
.with_default_args(vec!["-lparachain=debug".into()])
.with_collator(|n| n.with_name("alice"))
})
.build()
.map_err(|e| {
let errors = e.into_iter().map(|e| e.to_string()).collect::<Vec<_>>().join(" ");
anyhow!("config errors: {errors}")
})?;

let spawn_fn = zombienet_sdk::environment::get_spawn_fn();
log::info!("Spawning network");
let network = spawn_fn(config_builder).await?;

log::info!("Waiting for parablocks to be produced");
let honest_validator = network.get_node("honest-validator-0")?;
let relay_client: OnlineClient<PolkadotConfig> = honest_validator.wait_client().await?;

assert_finalized_para_throughput(
&relay_client,
20,
[(polkadot_primitives::Id::from(1000), 10..30)].into_iter().collect(),
)
.await?;

log::info!("Wait for a dispute to be initialized.");
let mut best_blocks = relay_client.blocks().subscribe_best().await?;
let mut dispute_session: u32 = u32::MAX;
// Check next new block from the current best fork
while let Some(block) = best_blocks.next().await {
let disputes = relay_client
.runtime_api()
.at(block?.hash())
.call_raw::<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>>(
"ParachainHost_disputes",
None,
)
.await?;
if let Some((session, _, _)) = disputes.first() {
dispute_session = *session;
break;
}
}
assert_ne!(dispute_session, u32::MAX);
log::info!("Dispute initiated.");

let concluded_dispute_metric =
"polkadot_parachain_candidate_dispute_concluded{validity=\"invalid\"}";
let parachain_candidate_dispute_metric = "parachain_candidate_disputes_total";
// honest-validator-1: reports parachain_candidate_disputes_total is at least 1 within 600
// seconds
honest_validator
.wait_metric_with_timeout(parachain_candidate_dispute_metric, |d| d >= 1.0, 600_u64)
.await?;
// honest-validator: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"}
// is at least 1 within 200 seconds
honest_validator
.wait_metric_with_timeout(concluded_dispute_metric, |d| d >= 1.0, 200_u64)
.await?;
// honest-validator: log line contains "Disabled validators detected" within 180 seconds
let result = honest_validator
.wait_log_line_count_with_timeout(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is desired to check the logs, but why don't you read Session::DisabledValidators storage items?

"*Disabled validators detected*",
true,
LogLineCountOptions::new(|n| n == 1, Duration::from_secs(180_u64), false),
)
.await?;
assert!(result.success());
Ok(())
}
41 changes: 0 additions & 41 deletions polkadot/zombienet_tests/functional/0010-validator-disabling.toml

This file was deleted.

21 changes: 0 additions & 21 deletions polkadot/zombienet_tests/functional/0010-validator-disabling.zndsl

This file was deleted.

8 changes: 8 additions & 0 deletions prdoc/pr_9128.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title: Rewrite validator disabling test with zombienet-sdk

doc:
- audience: Node Dev
description: |-
Migrate validator disabling test to the new version of zombienet

crates: []