Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
1afe20d
add scheduling tests for v3 descriptor with v2 collators
mchristou Mar 10, 2026
3bdb714
enable tests in CI
mchristou Mar 10, 2026
79c5d29
add validators with experimental protocol
mchristou Mar 11, 2026
144f42c
enable v3 on the fly
mchristou Mar 11, 2026
a9544cf
add rolling upgrade test for mixed V2/V3 validator fleet
mchristou Mar 11, 2026
5f0caa3
remove reduntant tests
mchristou Mar 11, 2026
8a7569b
address comments
mchristou Mar 12, 2026
8a2aeb9
use async backing in rolling upgrade
mchristou Mar 12, 2026
57226e6
add V2 descriptor field checks in assert_candidates_version
mchristou Mar 12, 2026
6702ec3
add V1 descriptor acceptance tests for V3-capable runtime and validator
mchristou Mar 13, 2026
25fff8c
add runtime api test: max_relay_parent_session_age returns 0 post-mig…
mchristou Mar 16, 2026
281b92c
add subsystem tests: V3-capable validator backs and distributes V1 de…
mchristou Mar 16, 2026
2bbd9d4
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Mar 16, 2026
9a5e471
fix v1_descriptor_version_detection_with_v3_enabled
mchristou Mar 16, 2026
aa290c8
Merge remote-tracking branch 'origin/master' into mchr-v3-descriptor-…
mchristou Mar 16, 2026
247345a
test: no reputation penalty for V3 advert with feature disabled
mchristou Mar 16, 2026
462820b
update finality lag limit for dynamic enablement
mchristou Mar 17, 2026
fa4db74
update finality lag limit for rolling upgrade
mchristou Mar 17, 2026
f21020a
Merge remote-tracking branch 'origin/master' into mchr-v3-descriptor-…
mchristou Mar 17, 2026
a9ee8ce
use slot based collator for rolling upgrade
mchristou Mar 17, 2026
1d97053
changes from feedback
mchristou Mar 18, 2026
09fc92b
fmt
mchristou Mar 18, 2026
8361585
adjust throughput range
mchristou Mar 18, 2026
c9d853f
reject v3 advertisements when v3 feature is disabled
mchristou Mar 18, 2026
360eaa8
remove check in handle_advertisement_v3 && fix test
mchristou Mar 19, 2026
592f0a5
Merge remote-tracking branch 'origin/master' into mchr-v3-descriptor-…
mchristou Mar 19, 2026
60be3a2
fix clippy
mchristou Mar 19, 2026
9d80aad
move tests under functional
mchristou Mar 20, 2026
131b65d
changes from feedback
mchristou Mar 20, 2026
6c04c06
Merge remote-tracking branch 'origin/master' into mchr-v3-descriptor-…
mchristou Mar 20, 2026
a3fcb10
remove reduntant loop
mchristou Mar 20, 2026
e8da0e4
Merge branch 'master' into mchr-v3-descriptor-tests
iulianbarbu Mar 21, 2026
416bb16
fix
mchristou Mar 21, 2026
cc69c2e
Report back when candidate is rejected.
eskimor Mar 22, 2026
3b63992
Update from github-actions[bot] running command 'prdoc --audience nod…
github-actions[bot] Mar 23, 2026
37e6b02
Update prdoc
eskimor Mar 23, 2026
6c59771
Merge branch 'rk-report-back-invalid-candidates' of github.com:parity…
iulianbarbu Mar 23, 2026
20742f3
polkadot(tests): v3 advertisement rejection when v3 disabled
iulianbarbu Mar 24, 2026
be1d55e
Revert "Merge branch 'rk-report-back-invalid-candidates' of github.co…
iulianbarbu Mar 24, 2026
3f4e265
Merge branch 'master' of github.com:paritytech/polkadot-sdk into mchr…
iulianbarbu Mar 24, 2026
213e62a
Update polkadot/node/network/collator-protocol/src/validator_side/tes…
iulianbarbu Mar 24, 2026
7111501
polkadot(tests): clippy fixups
iulianbarbu Mar 24, 2026
de01254
polkadot(tests): revert changes to existing test
iulianbarbu Mar 24, 2026
0bc850c
polkadot(tests): clippy fixes and review addressing
iulianbarbu Mar 24, 2026
e6418a1
address some more review comments
iulianbarbu Mar 24, 2026
f6bea18
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Mar 24, 2026
0422211
fix paras_inherent bench builder
iulianbarbu Mar 24, 2026
f1f79ac
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Mar 24, 2026
a0b8b25
Revert "fix paras_inherent bench builder"
iulianbarbu Mar 24, 2026
b8945ce
polkadot: bench builder can create v1 now
iulianbarbu Mar 24, 2026
8c3d2a2
Merge branch 'master' of github.com:paritytech/polkadot-sdk into mchr…
iulianbarbu Mar 24, 2026
c6df8d2
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Mar 25, 2026
16777eb
polkadot(tests): refactor v3 wise
iulianbarbu Mar 25, 2026
d6806f4
polkadot(tests): address a few more review comments
iulianbarbu Mar 25, 2026
43c74ce
Merge branch 'master' into mchr-v3-descriptor-tests
iulianbarbu Mar 25, 2026
ad65e56
polkadot(tests): remove unneeded tests
iulianbarbu Mar 25, 2026
86b6ca9
polkadot(tests): remove uneeded tests for v3
iulianbarbu Mar 25, 2026
b85b9dc
fix clippy
iulianbarbu Mar 25, 2026
8b289d2
rename test
iulianbarbu Mar 25, 2026
72ac5e2
polkadot(zn-tests): use enable_node_feature is systemic chnk recovery
iulianbarbu Mar 25, 2026
f82d312
fix clippy again
iulianbarbu Mar 25, 2026
5a121a1
Merge branch 'master' into mchr-v3-descriptor-tests
iulianbarbu Mar 25, 2026
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
33 changes: 33 additions & 0 deletions .github/zombienet-tests/zombienet_polkadot_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,36 @@
test-filter: "functional::coretime_partitioning::coretime_assignment_boundary_test"
runner-type: "default"
use-zombienet-sdk: true

- job-name: "zombienet-polkadot-scheduling-v3-dynamic-enablement"
test-filter: "scheduling::v3_dynamic_enablement::v3_dynamic_enablement_test"
Comment thread
mchristou marked this conversation as resolved.
Outdated
runner-type: "default"
use-zombienet-sdk: true
cumulus-image: "test-parachain"

- job-name: "zombienet-polkadot-scheduling-v3-rolling-upgrade"
test-filter: "scheduling::v3_rolling_upgrade::v3_rolling_upgrade"
runner-type: "default"
use-zombienet-sdk: true
cumulus-image: "test-parachain"
additional-setup: |
BIN_DIR="$(pwd)/bin_old"
Comment thread
iulianbarbu marked this conversation as resolved.
mkdir -p $BIN_DIR
for bin in polkadot polkadot-parachain; do
Comment thread
iulianbarbu marked this conversation as resolved.
Outdated
OLD_NAME="$bin-old"
echo "downloading $bin as $OLD_NAME in $BIN_DIR";
curl -L -o $BIN_DIR/$OLD_NAME https://github.com/paritytech/polkadot-sdk/releases/download/polkadot-stable2506/$bin
Comment thread
mchristou marked this conversation as resolved.
Outdated
chmod 755 $BIN_DIR/$OLD_NAME;
done
for bin in polkadot-execute-worker polkadot-prepare-worker; do
OLD_NAME="$bin"
Comment thread
iulianbarbu marked this conversation as resolved.
Outdated
echo "downloading $bin as $OLD_NAME in $BIN_DIR";
curl -L -o $BIN_DIR/$OLD_NAME https://github.com/paritytech/polkadot-sdk/releases/download/polkadot-stable2506/$bin
chmod 755 $BIN_DIR/$OLD_NAME;
done
ls -ltr $BIN_DIR
export PATH=$BIN_DIR:$PATH
echo "PATH=$PATH" >> $GITHUB_ENV
additional-env:
OLD_POLKADOT_IMAGE: "docker.io/paritypr/polkadot-debug:master-187cddde"
OLD_POLKADOT_COMMAND: "polkadot-old"
Original file line number Diff line number Diff line change
Expand Up @@ -1960,6 +1960,109 @@ fn v3_descriptor(#[case] v3_feature_enabled: bool, #[case] crafted_unknown: bool
});
}

/// Test that a V3-capable validator (V3 node feature enabled) correctly identifies a V1 descriptor
#[test]
fn v1_descriptor_version_detection_with_v3_enabled() {
let mut test_state = TestState::default();

// Enable both V2 and V3 features — this is a "V3-capable" validator.
test_state
.node_features
.resize(node_features::FeatureIndex::CandidateReceiptV3 as usize + 1, false);
test_state
.node_features
.set(node_features::FeatureIndex::CandidateReceiptV3 as u8 as usize, true);

test_harness(ReputationAggregator::new(|_| true), HashSet::new(), |test_harness| async move {
let TestHarness { mut virtual_overseer, keystore } = test_harness;

let pair_a = CollatorPair::generate().0;

let head_b = Hash::from_low_u64_be(128);
let head_b_num: u32 = 0;

update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await;

let peer_a = PeerId::random();

// Collator connects using the legacy V1 wire protocol.
connect_and_declare_collator(
&mut virtual_overseer,
peer_a,
pair_a.clone(),
test_state.chain_ids[0],
CollationVersion::V1,
)
.await;

advertise_collation(&mut virtual_overseer, peer_a, head_b, None).await;

let response_channel = assert_fetch_collation_request(
&mut virtual_overseer,
head_b,
test_state.chain_ids[0],
None,
)
.await;

// Build a V1 descriptor: `dummy_candidate_receipt_bad_sig` populates `collator` with
// `dummy_collator()` (non-zero) and `signature` with `dummy_collator_signature()`
// (non-zero). In the V2 layout these bytes occupy `reserved2`, triggering V1 detection.
let mut candidate = dummy_candidate_receipt_bad_sig(head_b, Some(Default::default()));
candidate.descriptor.para_id = test_state.chain_ids[0];
candidate.descriptor.persisted_validation_data_hash = dummy_pvd().hash();

let commitments = CandidateCommitments {
head_data: HeadData(vec![1u8]),
horizontal_messages: Default::default(),
upward_messages: Default::default(),
new_validation_code: None,
processed_downward_messages: 0,
hrmp_watermark: 0,
};
candidate.commitments_hash = commitments.hash();

// Convert to CandidateReceiptV2 and assert version detection.
let candidate: CandidateReceipt = candidate.into();
assert_eq!(
candidate.descriptor.version(true),
CandidateDescriptorVersion::V1,
"non-zero reserved2 bytes must be detected as V1 even when v3_enabled=true"
);

let pov = PoV { block_data: BlockData(vec![1]) };

response_channel
.send(Ok((
request_v2::CollationFetchingResponse::Collation(candidate.clone(), pov.clone())
.encode(),
ProtocolName::from(""),
)))
.expect("Sending response should succeed");

// The subsystem must take the legacy path: RuntimeApi::PersistedValidationData,
// NOT ProspectiveParachains::GetProspectiveValidationData.
// assert_candidate_backing_second with CollationVersion::V1 asserts exactly that.
assert_candidate_backing_second(
&mut virtual_overseer,
head_b,
test_state.chain_ids[0],
&pov,
CollationVersion::V1,
)
.await;

let committed =
CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments };
send_seconded_statement(&mut virtual_overseer, keystore.clone(), &committed).await;

assert_collation_seconded(&mut virtual_overseer, head_b, peer_a, CollationVersion::V1)
.await;

virtual_overseer
});
}

#[test]
fn invalid_v2_descriptor() {
let mut test_state = TestState::default();
Expand Down
13 changes: 13 additions & 0 deletions polkadot/runtime/parachains/src/configuration/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use super::*;
use crate::{
configuration,
mock::{new_test_ext, Configuration, MockGenesisConfig, ParasShared, RuntimeOrigin, Test},
runtime_api_impl,
};
use bitvec::{bitvec, prelude::Lsb0};
use frame_support::{assert_err, assert_ok};
Expand Down Expand Up @@ -587,3 +588,15 @@ fn active_config_hrmp_channel_size_and_capacity_ratio_works() {
);
})
}

#[test]
fn max_relay_parent_session_age_runtime_api_returns_zero_post_migration() {
Comment thread
mchristou marked this conversation as resolved.
Outdated
// Verify that the `max_relay_parent_session_age` runtime API also
// returns 0 when queried against the default / post-migration active config.
new_test_ext(Default::default()).execute_with(|| {
assert_eq!(
runtime_api_impl::vstaging::max_relay_parent_session_age::<Test>(),
0,
);
});
}
90 changes: 90 additions & 0 deletions polkadot/runtime/parachains/src/paras_inherent/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2399,6 +2399,96 @@ mod enter {
);
});
}

/// Verifies that a V3-capable runtime (CandidateReceiptV3 enabled) correctly accepts V1
/// descriptors from non-upgraded collators: not filtered, backed, and placed in
/// `PendingAvailability`.
#[test]
fn v1_descriptor_accepted_by_v3_capable_runtime() {
let config = MockGenesisConfig::default();

new_test_ext(config).execute_with(|| {
configuration::Pallet::<Test>::set_node_feature(
RuntimeOrigin::root(),
FeatureIndex::CandidateReceiptV3 as u8,
true,
)
.unwrap();

let mut backed_and_concluding = BTreeMap::new();
backed_and_concluding.insert(0, 1);
backed_and_concluding.insert(1, 1);

// Set non-zero collator/signature bytes so the V3 detection algorithm
// (checks reserved1[0..16]) identifies these as V1. Clear UMP signals
Comment thread
iulianbarbu marked this conversation as resolved.
Outdated
// since V1 candidates must not carry them.
let candidate_modifier = |mut candidate: CommittedCandidateReceiptV2| {
Comment thread
iulianbarbu marked this conversation as resolved.
Outdated
candidate.commitments.upward_messages.clear();

let mut v1: CandidateDescriptor = candidate.descriptor.into();
Comment thread
iulianbarbu marked this conversation as resolved.
Outdated
v1.collator = junk_collator();
v1.signature = junk_collator_signature();
candidate.descriptor = v1.into();

candidate
};

let scenario = make_inherent_data(TestConfig {
dispute_statements: BTreeMap::new(),
dispute_sessions: vec![],
backed_and_concluding,
num_validators_per_core: 1,
code_upgrade: None,
elastic_paras: BTreeMap::new(),
unavailable_cores: vec![],
descriptor_version: CandidateDescriptorVersionConfig::V1,
approved_peer_signal: None,
candidate_modifier: Some(candidate_modifier),
});

let expected_para_inherent_data = scenario.data.clone();

assert_eq!(expected_para_inherent_data.bitfields.len(), 2);
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);

for candidate in &expected_para_inherent_data.backed_candidates {
assert_eq!(candidate.descriptor().version(true), CandidateDescriptorVersion::V1);
assert!(candidate.descriptor().session_index(true).is_none());
}

let mut inherent_data = InherentData::new();
inherent_data
.put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data)
.unwrap();

assert_eq!(
Pallet::<Test>::create_inherent_inner(&inherent_data).unwrap(),
expected_para_inherent_data
);

assert_eq!(
OnChainVotes::<Test>::get().unwrap().backing_validators_per_candidate.len(),
2
);

assert_eq!(
inclusion::PendingAvailability::<Test>::get(ParaId::from(0))
.unwrap()
.into_iter()
.map(|c| c.core_occupied())
.collect::<Vec<_>>(),
vec![CoreIndex(0)]
);
assert_eq!(
inclusion::PendingAvailability::<Test>::get(ParaId::from(1))
.unwrap()
.into_iter()
.map(|c| c.core_occupied())
.collect::<Vec<_>>(),
vec![CoreIndex(1)]
);
});
}
}

fn default_header() -> polkadot_primitives::Header {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use anyhow::anyhow;

use cumulus_zombienet_sdk_helpers::{assert_finality_lag, assert_para_throughput, assign_cores};
use polkadot_primitives::Id as ParaId;
use polkadot_primitives::{CandidateDescriptorVersion, Id as ParaId};
use serde_json::json;
use zombienet_sdk::{
subxt::{OnlineClient, PolkadotConfig},
Expand Down Expand Up @@ -98,6 +98,18 @@ async fn slot_based_3cores_test() -> Result<(), anyhow::Error> {
assign_cores(&relay_client, 2100, vec![0, 1]).await?;
assign_cores(&relay_client, 2200, vec![2, 3]).await?;

crate::utils::enable_v3_node_features(&relay_client).await?;

crate::scheduling::assert_candidates_version(
Comment thread
iulianbarbu marked this conversation as resolved.
Outdated
&relay_client,
ParaId::from(2200),
CandidateDescriptorVersion::V2,
true,
15,
20,
)
.await?;

// Expect a backed candidate count of at least 39 for each parachain in 15 relay chain blocks
// (2.6 candidates per para per relay chain block).
// Note that only blocks after the first session change and blocks that don't contain a session
Expand Down
2 changes: 2 additions & 0 deletions polkadot/zombienet-sdk-tests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ mod functional;
#[cfg(feature = "zombie-ci")]
mod parachains;
#[cfg(feature = "zombie-ci")]
mod scheduling;
#[cfg(feature = "zombie-ci")]
mod smoke;
#[cfg(feature = "zombie-ci")]
mod utils;
Loading
Loading