Skip to content

Commit 02e1a7f

Browse files
author
ordian
authored
collator protocol changes for elastic scaling (validator side) (#3302)
Fixes #3128. This introduces a new variant for the collation response from the collator that includes the parent head data. For now, collators won't send this new variant. We'll need to change the collator side of the collator protocol to detect all the cores assigned to a para and send the parent head data in the case when it's more than 1 core. - [x] validate approach - [x] check head data hash
1 parent e8b51f6 commit 02e1a7f

File tree

16 files changed

+406
-133
lines changed

16 files changed

+406
-133
lines changed

polkadot/node/collation-generation/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ async fn construct_and_distribute_receipt(
466466
} = collation;
467467

468468
let persisted_validation_data_hash = validation_data.hash();
469+
let parent_head_data = validation_data.parent_head.clone();
469470
let parent_head_data_hash = validation_data.parent_head.hash();
470471

471472
// Apply compression to the block data.
@@ -551,12 +552,13 @@ async fn construct_and_distribute_receipt(
551552
metrics.on_collation_generated();
552553

553554
sender
554-
.send_message(CollatorProtocolMessage::DistributeCollation(
555-
ccr,
555+
.send_message(CollatorProtocolMessage::DistributeCollation {
556+
candidate_receipt: ccr,
556557
parent_head_data_hash,
557558
pov,
559+
parent_head_data,
558560
result_sender,
559-
))
561+
})
560562
.await;
561563
}
562564

polkadot/node/collation-generation/src/tests.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -390,11 +390,11 @@ fn sends_distribute_collation_message() {
390390

391391
assert_eq!(to_collator_protocol.len(), 1);
392392
match AllMessages::from(to_collator_protocol.pop().unwrap()) {
393-
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation(
394-
CandidateReceipt { descriptor, .. },
395-
_pov,
396-
..,
397-
)) => {
393+
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation {
394+
candidate_receipt,
395+
..
396+
}) => {
397+
let CandidateReceipt { descriptor, .. } = candidate_receipt;
398398
// signature generation is non-deterministic, so we can't just assert that the
399399
// expected descriptor is correct. What we can do is validate that the produced
400400
// descriptor has a valid signature, then just copy in the generated signature
@@ -529,11 +529,11 @@ fn fallback_when_no_validation_code_hash_api() {
529529

530530
assert_eq!(to_collator_protocol.len(), 1);
531531
match &to_collator_protocol[0] {
532-
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation(
533-
CandidateReceipt { descriptor, .. },
534-
_pov,
535-
..,
536-
)) => {
532+
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation {
533+
candidate_receipt,
534+
..
535+
}) => {
536+
let CandidateReceipt { descriptor, .. } = candidate_receipt;
537537
assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash);
538538
},
539539
_ => panic!("received wrong message type"),
@@ -619,15 +619,16 @@ fn submit_collation_leads_to_distribution() {
619619

620620
assert_matches!(
621621
overseer_recv(&mut virtual_overseer).await,
622-
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation(
623-
ccr,
622+
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation {
623+
candidate_receipt,
624624
parent_head_data_hash,
625625
..
626-
)) => {
626+
}) => {
627+
let CandidateReceipt { descriptor, .. } = candidate_receipt;
627628
assert_eq!(parent_head_data_hash, parent_head.hash());
628-
assert_eq!(ccr.descriptor().persisted_validation_data_hash, expected_pvd.hash());
629-
assert_eq!(ccr.descriptor().para_head, dummy_head_data().hash());
630-
assert_eq!(ccr.descriptor().validation_code_hash, validation_code_hash);
629+
assert_eq!(descriptor.persisted_validation_data_hash, expected_pvd.hash());
630+
assert_eq!(descriptor.para_head, dummy_head_data().hash());
631+
assert_eq!(descriptor.validation_code_hash, validation_code_hash);
631632
}
632633
);
633634

polkadot/node/core/prospective-parachains/src/lib.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ use futures::{channel::oneshot, prelude::*};
3636
use polkadot_node_subsystem::{
3737
messages::{
3838
Ancestors, ChainApiMessage, FragmentTreeMembership, HypotheticalCandidate,
39-
HypotheticalFrontierRequest, IntroduceCandidateRequest, ProspectiveParachainsMessage,
40-
ProspectiveValidationDataRequest, RuntimeApiMessage, RuntimeApiRequest,
39+
HypotheticalFrontierRequest, IntroduceCandidateRequest, ParentHeadData,
40+
ProspectiveParachainsMessage, ProspectiveValidationDataRequest, RuntimeApiMessage,
41+
RuntimeApiRequest,
4142
},
4243
overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError,
4344
};
@@ -764,8 +765,14 @@ fn answer_prospective_validation_data_request(
764765
Some(s) => s,
765766
};
766767

767-
let mut head_data =
768-
storage.head_data_by_hash(&request.parent_head_data_hash).map(|x| x.clone());
768+
let (mut head_data, parent_head_data_hash) = match request.parent_head_data {
769+
ParentHeadData::OnlyHash(parent_head_data_hash) => (
770+
storage.head_data_by_hash(&parent_head_data_hash).map(|x| x.clone()),
771+
parent_head_data_hash,
772+
),
773+
ParentHeadData::WithData { head_data, hash } => (Some(head_data), hash),
774+
};
775+
769776
let mut relay_parent_info = None;
770777
let mut max_pov_size = None;
771778

@@ -783,7 +790,7 @@ fn answer_prospective_validation_data_request(
783790
}
784791
if head_data.is_none() {
785792
let required_parent = &fragment_tree.scope().base_constraints().required_parent;
786-
if required_parent.hash() == request.parent_head_data_hash {
793+
if required_parent.hash() == parent_head_data_hash {
787794
head_data = Some(required_parent.clone());
788795
}
789796
}

polkadot/node/core/prospective-parachains/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use assert_matches::assert_matches;
1919
use polkadot_node_subsystem::{
2020
errors::RuntimeApiError,
2121
messages::{
22-
AllMessages, HypotheticalFrontierRequest, ProspectiveParachainsMessage,
22+
AllMessages, HypotheticalFrontierRequest, ParentHeadData, ProspectiveParachainsMessage,
2323
ProspectiveValidationDataRequest,
2424
},
2525
};
@@ -468,7 +468,7 @@ async fn get_pvd(
468468
let request = ProspectiveValidationDataRequest {
469469
para_id,
470470
candidate_relay_parent,
471-
parent_head_data_hash: parent_head_data.hash(),
471+
parent_head_data: ParentHeadData::OnlyHash(parent_head_data.hash()),
472472
};
473473
let (tx, rx) = oneshot::channel();
474474
virtual_overseer

polkadot/node/network/collator-protocol/src/collator_side/collation.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use polkadot_node_network_protocol::{
2727
PeerId,
2828
};
2929
use polkadot_node_primitives::PoV;
30-
use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, Id as ParaId};
30+
use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, HeadData, Id as ParaId};
3131

3232
/// The status of a collation as seen from the collator.
3333
pub enum CollationStatus {
@@ -63,6 +63,8 @@ pub struct Collation {
6363
pub parent_head_data_hash: Hash,
6464
/// Proof to verify the state transition of the parachain.
6565
pub pov: PoV,
66+
/// Parent head-data needed for elastic scaling.
67+
pub parent_head_data: HeadData,
6668
/// Collation status.
6769
pub status: CollationStatus,
6870
}

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

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use polkadot_node_subsystem_util::{
5555
};
5656
use polkadot_primitives::{
5757
AuthorityDiscoveryId, CandidateHash, CandidateReceipt, CollatorPair, CoreIndex, CoreState,
58-
GroupIndex, Hash, Id as ParaId, SessionIndex,
58+
GroupIndex, Hash, HeadData, Id as ParaId, SessionIndex,
5959
};
6060

6161
use super::LOG_TARGET;
@@ -347,6 +347,7 @@ async fn distribute_collation<Context>(
347347
receipt: CandidateReceipt,
348348
parent_head_data_hash: Hash,
349349
pov: PoV,
350+
parent_head_data: HeadData,
350351
result_sender: Option<oneshot::Sender<CollationSecondedSignal>>,
351352
) -> Result<()> {
352353
let candidate_relay_parent = receipt.descriptor.relay_parent;
@@ -465,7 +466,13 @@ async fn distribute_collation<Context>(
465466

466467
per_relay_parent.collations.insert(
467468
candidate_hash,
468-
Collation { receipt, parent_head_data_hash, pov, status: CollationStatus::Created },
469+
Collation {
470+
receipt,
471+
parent_head_data_hash,
472+
pov,
473+
parent_head_data,
474+
status: CollationStatus::Created,
475+
},
469476
);
470477

471478
// If prospective parachains are disabled, a leaf should be known to peer.
@@ -763,20 +770,26 @@ async fn process_msg<Context>(
763770
CollateOn(id) => {
764771
state.collating_on = Some(id);
765772
},
766-
DistributeCollation(receipt, parent_head_data_hash, pov, result_sender) => {
773+
DistributeCollation {
774+
candidate_receipt,
775+
parent_head_data_hash,
776+
pov,
777+
parent_head_data,
778+
result_sender,
779+
} => {
767780
let _span1 = state
768781
.span_per_relay_parent
769-
.get(&receipt.descriptor.relay_parent)
782+
.get(&candidate_receipt.descriptor.relay_parent)
770783
.map(|s| s.child("distributing-collation"));
771784
let _span2 = jaeger::Span::new(&pov, "distributing-collation");
772785

773786
match state.collating_on {
774-
Some(id) if receipt.descriptor.para_id != id => {
787+
Some(id) if candidate_receipt.descriptor.para_id != id => {
775788
// If the ParaId of a collation requested to be distributed does not match
776789
// the one we expect, we ignore the message.
777790
gum::warn!(
778791
target: LOG_TARGET,
779-
para_id = %receipt.descriptor.para_id,
792+
para_id = %candidate_receipt.descriptor.para_id,
780793
collating_on = %id,
781794
"DistributeCollation for unexpected para_id",
782795
);
@@ -788,17 +801,18 @@ async fn process_msg<Context>(
788801
runtime,
789802
state,
790803
id,
791-
receipt,
804+
candidate_receipt,
792805
parent_head_data_hash,
793806
pov,
807+
parent_head_data,
794808
result_sender,
795809
)
796810
.await?;
797811
},
798812
None => {
799813
gum::warn!(
800814
target: LOG_TARGET,
801-
para_id = %receipt.descriptor.para_id,
815+
para_id = %candidate_receipt.descriptor.para_id,
802816
"DistributeCollation message while not collating on any",
803817
);
804818
},
@@ -835,20 +849,30 @@ async fn send_collation(
835849
request: VersionedCollationRequest,
836850
receipt: CandidateReceipt,
837851
pov: PoV,
852+
_parent_head_data: HeadData,
838853
) {
839854
let (tx, rx) = oneshot::channel();
840855

841856
let relay_parent = request.relay_parent();
842857
let peer_id = request.peer_id();
843858
let candidate_hash = receipt.hash();
844859

845-
// The response payload is the same for both versions of protocol
860+
// The response payload is the same for v1 and v2 versions of protocol
846861
// and doesn't have v2 alias for simplicity.
847-
let response = OutgoingResponse {
848-
result: Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)),
849-
reputation_changes: Vec::new(),
850-
sent_feedback: Some(tx),
851-
};
862+
// For now, we don't send parent head data to the collation requester.
863+
let result =
864+
// if assigned_multiple_cores {
865+
// Ok(request_v1::CollationFetchingResponse::CollationWithParentHeadData {
866+
// receipt,
867+
// pov,
868+
// parent_head_data,
869+
// })
870+
// } else {
871+
Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov))
872+
// }
873+
;
874+
let response =
875+
OutgoingResponse { result, reputation_changes: Vec::new(), sent_feedback: Some(tx) };
852876

853877
if let Err(_) = request.send_outgoing_response(response) {
854878
gum::warn!(target: LOG_TARGET, "Sending collation response failed");
@@ -1027,9 +1051,13 @@ async fn handle_incoming_request<Context>(
10271051
return Ok(())
10281052
},
10291053
};
1030-
let (receipt, pov) = if let Some(collation) = collation {
1054+
let (receipt, pov, parent_head_data) = if let Some(collation) = collation {
10311055
collation.status.advance_to_requested();
1032-
(collation.receipt.clone(), collation.pov.clone())
1056+
(
1057+
collation.receipt.clone(),
1058+
collation.pov.clone(),
1059+
collation.parent_head_data.clone(),
1060+
)
10331061
} else {
10341062
gum::warn!(
10351063
target: LOG_TARGET,
@@ -1068,7 +1096,7 @@ async fn handle_incoming_request<Context>(
10681096
waiting.collation_fetch_active = true;
10691097
// Obtain a timer for sending collation
10701098
let _ = state.metrics.time_collation_distribution("send");
1071-
send_collation(state, req, receipt, pov).await;
1099+
send_collation(state, req, receipt, pov, parent_head_data).await;
10721100
}
10731101
},
10741102
Some(our_para_id) => {
@@ -1453,8 +1481,9 @@ async fn run_inner<Context>(
14531481
if let Some(collation) = next_collation {
14541482
let receipt = collation.receipt.clone();
14551483
let pov = collation.pov.clone();
1484+
let parent_head_data = collation.parent_head_data.clone();
14561485

1457-
send_collation(&mut state, next, receipt, pov).await;
1486+
send_collation(&mut state, next, receipt, pov, parent_head_data).await;
14581487
}
14591488
},
14601489
(candidate_hash, peer_id) = state.advertisement_timeouts.select_next_some() => {

0 commit comments

Comments
 (0)