mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 08:11:03 +00:00
Notify collators about seconded collation (#2430)
* Notify collators about seconded collation This pr adds functionality to inform a collator that its collation was seconded by a parachain validator. Before this signed statement was only gossiped over the validation substream. Now, we explicitly send the seconded statement to the collator after it was validated successfully. Besides that it changes the `CollatorFn` to return an optional result sender that is informed when the build collation was seconded by a parachain validator. * Add test * Make sure we only send `Seconded` statements * Make sure we only receive valid statements * Review feedback
This commit is contained in:
@@ -15,6 +15,7 @@ futures = "0.3.12"
|
||||
futures-timer = "3.0.2"
|
||||
log = "0.4.13"
|
||||
structopt = "0.3.21"
|
||||
assert_matches = "1.4.0"
|
||||
|
||||
test-parachain-adder = { path = ".." }
|
||||
polkadot-primitives = { path = "../../../../primitives" }
|
||||
|
||||
@@ -17,16 +17,18 @@
|
||||
//! Collator for the adder test parachain.
|
||||
|
||||
use futures_timer::Delay;
|
||||
use polkadot_node_primitives::{Collation, CollatorFn};
|
||||
use polkadot_node_primitives::{Collation, CollatorFn, CollationResult, Statement, SignedFullStatement};
|
||||
use polkadot_primitives::v1::{CollatorId, CollatorPair, PoV};
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use sp_core::Pair;
|
||||
use sp_core::{Pair, traits::SpawnNamed};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Mutex},
|
||||
sync::{Arc, Mutex, atomic::{AtomicU32, Ordering}},
|
||||
time::Duration,
|
||||
};
|
||||
use test_parachain_adder::{execute, hash_state, BlockData, HeadData};
|
||||
use futures::channel::oneshot;
|
||||
use assert_matches::assert_matches;
|
||||
|
||||
/// The amount we add when producing a new block.
|
||||
///
|
||||
@@ -102,6 +104,7 @@ impl State {
|
||||
pub struct Collator {
|
||||
state: Arc<Mutex<State>>,
|
||||
key: CollatorPair,
|
||||
seconded_collations: Arc<AtomicU32>,
|
||||
}
|
||||
|
||||
impl Collator {
|
||||
@@ -110,6 +113,7 @@ impl Collator {
|
||||
Self {
|
||||
state: Arc::new(Mutex::new(State::genesis())),
|
||||
key: CollatorPair::generate().0,
|
||||
seconded_collations: Arc::new(AtomicU32::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,10 +146,11 @@ impl Collator {
|
||||
/// Create the collation function.
|
||||
///
|
||||
/// This collation function can be plugged into the overseer to generate collations for the adder parachain.
|
||||
pub fn create_collation_function(&self) -> CollatorFn {
|
||||
pub fn create_collation_function(&self, spawner: impl SpawnNamed + Clone + 'static) -> CollatorFn {
|
||||
use futures::FutureExt as _;
|
||||
|
||||
let state = self.state.clone();
|
||||
let seconded_collations = self.seconded_collations.clone();
|
||||
|
||||
Box::new(move |relay_parent, validation_data| {
|
||||
let parent = HeadData::decode(&mut &validation_data.parent_head.0[..])
|
||||
@@ -159,19 +164,33 @@ impl Collator {
|
||||
block_data,
|
||||
);
|
||||
|
||||
let pov = PoV { block_data: block_data.encode().into() };
|
||||
|
||||
let collation = Collation {
|
||||
upward_messages: Vec::new(),
|
||||
horizontal_messages: Vec::new(),
|
||||
new_validation_code: None,
|
||||
head_data: head_data.encode().into(),
|
||||
proof_of_validity: PoV {
|
||||
block_data: block_data.encode().into(),
|
||||
},
|
||||
proof_of_validity: pov.clone(),
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: validation_data.relay_parent_number,
|
||||
};
|
||||
|
||||
async move { Some(collation) }.boxed()
|
||||
let (result_sender, recv) = oneshot::channel::<SignedFullStatement>();
|
||||
let seconded_collations = seconded_collations.clone();
|
||||
spawner.spawn("adder-collator-seconded", async move {
|
||||
if let Ok(res) = recv.await {
|
||||
assert_matches!(
|
||||
res.payload(),
|
||||
Statement::Seconded(s) if s.descriptor.pov_hash == pov.hash(),
|
||||
"Seconded statement should match our collation!",
|
||||
);
|
||||
|
||||
seconded_collations.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}.boxed());
|
||||
|
||||
async move { Some(CollationResult { collation, result_sender: Some(result_sender) }) }.boxed()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -188,6 +207,21 @@ impl Collator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait until `seconded` collations of this collator are seconded by a parachain validator.
|
||||
///
|
||||
/// The internal counter isn't de-duplicating the collations when counting the number of seconded collations. This
|
||||
/// means when one collation is seconded by X validators, we record X seconded messages.
|
||||
pub async fn wait_for_seconded_collations(&self, seconded: u32) {
|
||||
let seconded_collations = self.seconded_collations.clone();
|
||||
loop {
|
||||
Delay::new(Duration::from_secs(1)).await;
|
||||
|
||||
if seconded <= seconded_collations.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -200,8 +234,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn collator_works() {
|
||||
let spawner = sp_core::testing::TaskExecutor::new();
|
||||
let collator = Collator::new();
|
||||
let collation_function = collator.create_collation_function();
|
||||
let collation_function = collator.create_collation_function(spawner);
|
||||
|
||||
for i in 0..5 {
|
||||
let parent_head = collator
|
||||
@@ -220,11 +255,15 @@ mod tests {
|
||||
|
||||
let collation =
|
||||
block_on(collation_function(Default::default(), &validation_data)).unwrap();
|
||||
validate_collation(&collator, (*parent_head).clone(), collation);
|
||||
validate_collation(&collator, (*parent_head).clone(), collation.collation);
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_collation(collator: &Collator, parent_head: HeadData, collation: Collation) {
|
||||
fn validate_collation(
|
||||
collator: &Collator,
|
||||
parent_head: HeadData,
|
||||
collation: Collation,
|
||||
) {
|
||||
let ret = polkadot_parachain::wasm_executor::validate_candidate(
|
||||
collator.validation_code(),
|
||||
ValidationParams {
|
||||
|
||||
@@ -81,7 +81,7 @@ fn main() -> Result<()> {
|
||||
|
||||
let config = CollationGenerationConfig {
|
||||
key: collator.collator_key(),
|
||||
collator: collator.create_collation_function(),
|
||||
collator: collator.create_collation_function(full_node.task_manager.spawn_handle()),
|
||||
para_id,
|
||||
};
|
||||
overseer_handler
|
||||
|
||||
@@ -63,11 +63,18 @@ async fn collating_using_adder_collator(task_executor: sc_service::TaskExecutor)
|
||||
collator.collator_id(),
|
||||
);
|
||||
|
||||
charlie.register_collator(collator.collator_key(), para_id, collator.create_collation_function()).await;
|
||||
charlie.register_collator(
|
||||
collator.collator_key(),
|
||||
para_id,
|
||||
collator.create_collation_function(charlie.task_manager.spawn_handle()),
|
||||
).await;
|
||||
|
||||
// Wait until the parachain has 4 blocks produced.
|
||||
collator.wait_for_blocks(4).await;
|
||||
|
||||
// Wait until the collator received `12` seconded statements for its collations.
|
||||
collator.wait_for_seconded_collations(12).await;
|
||||
|
||||
join!(
|
||||
alice.task_manager.clean_shutdown(),
|
||||
bob.task_manager.clean_shutdown(),
|
||||
|
||||
Reference in New Issue
Block a user