Skip to content

Commit 2f9a3d8

Browse files
paritytech-release-backport-bot[bot]AlexandruCihodarugithub-actions[bot]
authored
[stable2603] Backport #11306 (#11478)
Backport #11306 into `stable2603` from AlexandruCihodaru. See the [documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md) on how to use this bot. <!-- # To be used by other automation, do not modify: original-pr-number: #${pull_number} --> Signed-off-by: Alexandru Cihodaru <alexandru.cihodaru@parity.io> Co-authored-by: Alexandru Cihodaru <40807189+AlexandruCihodaru@users.noreply.github.com> Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent dfb404c commit 2f9a3d8

File tree

12 files changed

+934
-263
lines changed

12 files changed

+934
-263
lines changed

polkadot/node/network/collator-protocol/src/lib.rs

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,32 @@
2222
#![recursion_limit = "256"]
2323

2424
use std::{
25-
collections::HashSet,
25+
collections::{HashMap, HashSet},
2626
sync::Arc,
2727
time::{Duration, Instant},
2828
};
2929

3030
use futures::{
31+
channel::oneshot,
3132
stream::{FusedStream, StreamExt},
3233
FutureExt, TryFutureExt,
3334
};
3435

36+
use polkadot_node_subsystem::CollatorProtocolSenderTrait;
3537
use polkadot_node_subsystem_util::{database::Database, reputation::ReputationAggregator};
38+
use sp_consensus_babe::digests::CompatibleDigestItem;
39+
use sp_core::H256;
3640
use sp_keystore::KeystorePtr;
3741

3842
use polkadot_node_network_protocol::{
3943
request_response::{v2 as protocol_v2, IncomingRequestReceiver},
4044
PeerId, UnifiedReputationChange as Rep,
4145
};
42-
use polkadot_node_subsystem::{errors::SubsystemError, overseer, DummySubsystem, SpawnedSubsystem};
43-
use polkadot_primitives::CollatorPair;
46+
use polkadot_node_subsystem::{
47+
errors::SubsystemError, messages::ChainApiMessage, overseer, DummySubsystem, SpawnedSubsystem,
48+
};
49+
use polkadot_primitives::{CollatorPair, Hash, RELAY_CHAIN_SLOT_DURATION_MILLIS};
50+
use sp_consensus_slots::SlotDuration;
4451
pub use validator_side_experimental::ReputationConfig;
4552

4653
mod collator_side;
@@ -206,3 +213,48 @@ fn tick_stream(period: Duration) -> impl FusedStream<Item = ()> {
206213
})
207214
.fuse()
208215
}
216+
217+
/// Scheduling info tracked per active leaf, used for V3 scheduling parent validation.
218+
/// Stores the leaf's BABE slot and parent hash so the validator can determine whether
219+
/// the scheduling parent corresponds to the last finished relay chain slot.
220+
struct LeafSchedulingInfo {
221+
/// The parent hash of the leaf block.
222+
parent_hash: Hash,
223+
/// The BABE slot of the leaf block.
224+
slot: sp_consensus_slots::Slot,
225+
}
226+
227+
pub(crate) async fn extract_leaf_scheduling_info<Sender: CollatorProtocolSenderTrait>(
228+
sender: &mut Sender,
229+
leaf: H256,
230+
) -> Option<LeafSchedulingInfo> {
231+
// Fetch leaf header to extract BABE slot for V3 scheduling parent validation.
232+
// Without this info, V3 advertisements referencing this leaf will be rejected.
233+
let (tx, rx) = oneshot::channel();
234+
sender.send_message(ChainApiMessage::BlockHeader(leaf, tx)).await;
235+
let header = rx.await.ok().and_then(|r| r.ok().flatten());
236+
header.and_then(|header| {
237+
let slot = header.digest.logs().iter().find_map(|log| log.as_babe_pre_digest())?.slot();
238+
Some(LeafSchedulingInfo { parent_hash: header.parent_hash, slot })
239+
})
240+
}
241+
242+
pub(crate) fn is_scheduling_parent_valid(
243+
scheduling_parent: &Hash,
244+
leaf_scheduling_info: &HashMap<Hash, LeafSchedulingInfo>,
245+
) -> bool {
246+
let slot_duration = SlotDuration::from_millis(RELAY_CHAIN_SLOT_DURATION_MILLIS);
247+
let current_slot =
248+
sp_consensus_slots::Slot::from_timestamp(sp_timestamp::Timestamp::current(), slot_duration);
249+
if let Some(info) = leaf_scheduling_info.get(scheduling_parent) {
250+
// scheduling_parent is a leaf. This is allowed only when the leaf's slot is
251+
// the previous slot.
252+
*current_slot == *info.slot + 1
253+
} else {
254+
// scheduling_parent is not a leaf. This is allowed only if the sp is the parent of
255+
// any leaf whose slot is still in progress.
256+
leaf_scheduling_info
257+
.iter()
258+
.any(|(_, info)| *current_slot == *info.slot && *scheduling_parent == info.parent_hash)
259+
}
260+
}

polkadot/node/network/collator-protocol/src/validator_side/mod.rs

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ use tokio_util::sync::CancellationToken;
143143

144144
use sp_keystore::KeystorePtr;
145145

146+
use crate::{extract_leaf_scheduling_info, is_scheduling_parent_valid, LeafSchedulingInfo};
146147
use polkadot_node_network_protocol::{
147148
self as net_protocol,
148149
peer_set::{CollationVersion, PeerSet, MAX_AUTHORITY_INCOMING_STREAMS},
@@ -156,9 +157,9 @@ use polkadot_node_network_protocol::{
156157
use polkadot_node_primitives::{SignedFullStatement, Statement};
157158
use polkadot_node_subsystem::{
158159
messages::{
159-
CanSecondRequest, CandidateBackingMessage, ChainApiMessage, CollatorProtocolMessage,
160-
IfDisconnected, NetworkBridgeEvent, NetworkBridgeTxMessage, ParentHeadData,
161-
ProspectiveParachainsMessage, ProspectiveValidationDataRequest,
160+
CanSecondRequest, CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected,
161+
NetworkBridgeEvent, NetworkBridgeTxMessage, ParentHeadData, ProspectiveParachainsMessage,
162+
ProspectiveValidationDataRequest,
162163
},
163164
overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, SubsystemError,
164165
};
@@ -170,10 +171,7 @@ use polkadot_node_subsystem_util::{
170171
use polkadot_primitives::{
171172
CandidateDescriptorV2, CandidateDescriptorVersion, CandidateHash, CollatorId, CoreIndex, Hash,
172173
HeadData, Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, SessionIndex,
173-
RELAY_CHAIN_SLOT_DURATION_MILLIS,
174174
};
175-
use sp_consensus_babe::digests::CompatibleDigestItem;
176-
use sp_consensus_slots::SlotDuration;
177175

178176
use super::{modify_reputation, tick_stream, LOG_TARGET};
179177

@@ -580,16 +578,6 @@ struct HeldOffAdvertisement {
580578
advertised_descriptor_version: Option<CandidateDescriptorVersion>,
581579
}
582580

583-
/// Scheduling info tracked per active leaf, used for V3 scheduling parent validation.
584-
/// Stores the leaf's BABE slot and parent hash so the validator can determine whether
585-
/// the scheduling parent corresponds to the last finished relay chain slot.
586-
struct LeafSchedulingInfo {
587-
/// The parent hash of the leaf block.
588-
parent_hash: Hash,
589-
/// The BABE slot of the leaf block.
590-
slot: sp_consensus_slots::Slot,
591-
}
592-
593581
/// All state relevant for the validator side of the protocol lives here.
594582
#[derive(Default)]
595583
struct State {
@@ -1752,26 +1740,7 @@ where
17521740
// finished relay chain slot. We compare slot numbers rather than timestamps to keep
17531741
// the logic simple and aligned with how BABE/Aura reason about slots.
17541742
if candidate_descriptor_version == CandidateDescriptorVersion::V3 {
1755-
let slot_duration = SlotDuration::from_millis(RELAY_CHAIN_SLOT_DURATION_MILLIS);
1756-
let current_slot = sp_consensus_slots::Slot::from_timestamp(
1757-
sp_timestamp::Timestamp::current(),
1758-
slot_duration,
1759-
);
1760-
1761-
let scheduling_parent_valid =
1762-
if let Some(info) = state.leaf_scheduling_info.get(&scheduling_parent) {
1763-
// scheduling_parent is a leaf — valid only if the leaf's slot is exactly
1764-
// one behind the current slot (i.e., it just finished).
1765-
*current_slot == *info.slot + 1
1766-
} else {
1767-
// scheduling_parent is not a leaf — valid if it's the parent of any leaf
1768-
// whose slot is the current slot (still in progress).
1769-
state.leaf_scheduling_info.iter().any(|(_leaf_hash, info)| {
1770-
*current_slot == *info.slot && scheduling_parent == info.parent_hash
1771-
})
1772-
};
1773-
1774-
if !scheduling_parent_valid {
1743+
if !is_scheduling_parent_valid(&scheduling_parent, &state.leaf_scheduling_info) {
17751744
return Err(AdvertisementError::SchedulingParentNotValid);
17761745
}
17771746
}
@@ -2001,15 +1970,7 @@ where
20011970
state.per_scheduling_parent.insert(*leaf, per_scheduling_parent);
20021971
state.leaf_claim_queues.insert(*leaf, leaf_claim_queue);
20031972

2004-
// Fetch leaf header to extract BABE slot for V3 scheduling parent validation.
2005-
// Without this info, V3 advertisements referencing this leaf will be rejected.
2006-
let (tx, rx) = oneshot::channel();
2007-
sender.send_message(ChainApiMessage::BlockHeader(*leaf, tx)).await;
2008-
let header = rx.await.ok().and_then(|r| r.ok()).flatten();
2009-
match header.and_then(|h| {
2010-
let slot = h.digest.logs().iter().find_map(|log| log.as_babe_pre_digest())?.slot();
2011-
Some(LeafSchedulingInfo { parent_hash: h.parent_hash, slot })
2012-
}) {
1973+
match extract_leaf_scheduling_info(sender, *leaf).await {
20131974
Some(info) => {
20141975
state.leaf_scheduling_info.insert(*leaf, info);
20151976
},

polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use polkadot_node_subsystem::messages::ChainApiMessage;
2222
use polkadot_primitives::{
2323
BlockNumber, CandidateCommitments, CandidateDescriptorVersion,
2424
CommittedCandidateReceiptV2 as CommittedCandidateReceipt, Header, MutateDescriptorV2,
25-
SigningContext, ValidatorId,
25+
SigningContext, ValidatorId, RELAY_CHAIN_SLOT_DURATION_MILLIS,
2626
};
2727
use polkadot_primitives_test_helpers::{
2828
dummy_committed_candidate_receipt_v2, dummy_committed_candidate_receipt_v3,

0 commit comments

Comments
 (0)