refactor+feat: allow subsystems to send only declared messages, generate graphviz (#5314)

Closes #3774
Closes #3826
This commit is contained in:
Bernhard Schuster
2022-05-12 17:39:05 +02:00
committed by GitHub
parent 26340b9054
commit 511891dcce
102 changed files with 3853 additions and 2514 deletions
+5
View File
@@ -7028,10 +7028,14 @@ version = "0.9.19"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"expander 0.0.6", "expander 0.0.6",
"petgraph",
"polkadot-overseer-gen",
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
"thiserror",
"tracing-gum",
] ]
[[package]] [[package]]
@@ -7400,6 +7404,7 @@ dependencies = [
"polkadot-node-primitives", "polkadot-node-primitives",
"polkadot-node-subsystem", "polkadot-node-subsystem",
"polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-test-helpers",
"polkadot-node-subsystem-types",
"polkadot-node-subsystem-util", "polkadot-node-subsystem-util",
"polkadot-overseer", "polkadot-overseer",
"polkadot-parachain", "polkadot-parachain",
+2
View File
@@ -16,6 +16,7 @@ Best/MS
BlockId BlockId
BlockNumber BlockNumber
BridgeStorage BridgeStorage
clonable
CLI/MS CLI/MS
Chain1 Chain1
Chain2 Chain2
@@ -177,6 +178,7 @@ plancks
polkadot/MS polkadot/MS
pov-block/MS pov-block/MS
precommit precommit
proc-macro/MS
prometheus prometheus
proxying proxying
provisioner/MS provisioner/MS
+1 -1
View File
@@ -60,7 +60,7 @@ pub type ChainId = u32;
/// A hash of some data used by the relay chain. /// A hash of some data used by the relay chain.
pub type Hash = sp_core::H256; pub type Hash = sp_core::H256;
/// Unit type wrapper around [`Hash`] that represents a candidate hash. /// Unit type wrapper around [`type@Hash`] that represents a candidate hash.
/// ///
/// This type is produced by [`CandidateReceipt::hash`]. /// This type is produced by [`CandidateReceipt::hash`].
/// ///
+16 -24
View File
@@ -22,9 +22,9 @@ use futures::{channel::mpsc, future::FutureExt, join, select, sink::SinkExt, str
use parity_scale_codec::Encode; use parity_scale_codec::Encode;
use polkadot_node_primitives::{AvailableData, CollationGenerationConfig, PoV}; use polkadot_node_primitives::{AvailableData, CollationGenerationConfig, PoV};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{AllMessages, CollationGenerationMessage, CollatorProtocolMessage}, messages::{CollationGenerationMessage, CollatorProtocolMessage},
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext,
SubsystemError, SubsystemResult, SubsystemSender, SubsystemError, SubsystemResult,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
request_availability_cores, request_persisted_validation_data, request_validation_code, request_availability_cores, request_persisted_validation_data, request_validation_code,
@@ -54,6 +54,7 @@ pub struct CollationGenerationSubsystem {
metrics: Metrics, metrics: Metrics,
} }
#[overseer::contextbounds(CollationGeneration, prefix = self::overseer)]
impl CollationGenerationSubsystem { impl CollationGenerationSubsystem {
/// Create a new instance of the `CollationGenerationSubsystem`. /// Create a new instance of the `CollationGenerationSubsystem`.
pub fn new(metrics: Metrics) -> Self { pub fn new(metrics: Metrics) -> Self {
@@ -71,11 +72,7 @@ impl CollationGenerationSubsystem {
/// ///
/// If `err_tx` is not `None`, errors are forwarded onto that channel as they occur. /// If `err_tx` is not `None`, errors are forwarded onto that channel as they occur.
/// Otherwise, most are logged and then discarded. /// Otherwise, most are logged and then discarded.
async fn run<Context>(mut self, mut ctx: Context) async fn run<Context>(mut self, mut ctx: Context) {
where
Context: SubsystemContext<Message = CollationGenerationMessage>,
Context: overseer::SubsystemContext<Message = CollationGenerationMessage>,
{
// when we activate new leaves, we spawn a bunch of sub-tasks, each of which is // when we activate new leaves, we spawn a bunch of sub-tasks, each of which is
// expected to generate precisely one message. We don't want to block the main loop // expected to generate precisely one message. We don't want to block the main loop
// at any point waiting for them all, so instead, we create a channel on which they can // at any point waiting for them all, so instead, we create a channel on which they can
@@ -108,12 +105,8 @@ impl CollationGenerationSubsystem {
&mut self, &mut self,
incoming: SubsystemResult<FromOverseer<<Context as SubsystemContext>::Message>>, incoming: SubsystemResult<FromOverseer<<Context as SubsystemContext>::Message>>,
ctx: &mut Context, ctx: &mut Context,
sender: &mpsc::Sender<AllMessages>, sender: &mpsc::Sender<overseer::CollationGenerationOutgoingMessages>,
) -> bool ) -> bool {
where
Context: SubsystemContext<Message = CollationGenerationMessage>,
Context: overseer::SubsystemContext<Message = CollationGenerationMessage>,
{
match incoming { match incoming {
Ok(FromOverseer::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { Ok(FromOverseer::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate {
activated, activated,
@@ -162,11 +155,8 @@ impl CollationGenerationSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for CollationGenerationSubsystem #[overseer::subsystem(CollationGeneration, error=SubsystemError, prefix=self::overseer)]
where impl<Context> CollationGenerationSubsystem {
Context: SubsystemContext<Message = CollationGenerationMessage>,
Context: overseer::SubsystemContext<Message = CollationGenerationMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = async move { let future = async move {
self.run(ctx).await; self.run(ctx).await;
@@ -178,12 +168,13 @@ where
} }
} }
async fn handle_new_activations<Context: SubsystemContext>( #[overseer::contextbounds(CollationGeneration, prefix = self::overseer)]
async fn handle_new_activations<Context>(
config: Arc<CollationGenerationConfig>, config: Arc<CollationGenerationConfig>,
activated: impl IntoIterator<Item = Hash>, activated: impl IntoIterator<Item = Hash>,
ctx: &mut Context, ctx: &mut Context,
metrics: Metrics, metrics: Metrics,
sender: &mpsc::Sender<AllMessages>, sender: &mpsc::Sender<overseer::CollationGenerationOutgoingMessages>,
) -> crate::error::Result<()> { ) -> crate::error::Result<()> {
// follow the procedure from the guide: // follow the procedure from the guide:
// https://w3f.github.io/parachain-implementers-guide/node/collators/collation-generation.html // https://w3f.github.io/parachain-implementers-guide/node/collators/collation-generation.html
@@ -393,9 +384,10 @@ async fn handle_new_activations<Context: SubsystemContext>(
metrics.on_collation_generated(); metrics.on_collation_generated();
if let Err(err) = task_sender if let Err(err) = task_sender
.send(AllMessages::CollatorProtocol( .send(
CollatorProtocolMessage::DistributeCollation(ccr, pov, result_sender), CollatorProtocolMessage::DistributeCollation(ccr, pov, result_sender)
)) .into(),
)
.await .await
{ {
gum::warn!( gum::warn!(
@@ -417,7 +409,7 @@ async fn obtain_current_validation_code_hash(
relay_parent: Hash, relay_parent: Hash,
para_id: ParaId, para_id: ParaId,
assumption: OccupiedCoreAssumption, assumption: OccupiedCoreAssumption,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::CollationGenerationSenderTrait,
) -> Result<Option<ValidationCodeHash>, crate::error::Error> { ) -> Result<Option<ValidationCodeHash>, crate::error::Error> {
use polkadot_node_subsystem::RuntimeApiError; use polkadot_node_subsystem::RuntimeApiError;
@@ -296,7 +296,7 @@ mod handle_new_activations {
*subsystem_sent_messages.lock().await = rx.collect().await; *subsystem_sent_messages.lock().await = rx.collect().await;
}); });
let sent_messages = Arc::try_unwrap(sent_messages) let mut sent_messages = Arc::try_unwrap(sent_messages)
.expect("subsystem should have shut down by now") .expect("subsystem should have shut down by now")
.into_inner(); .into_inner();
@@ -328,7 +328,7 @@ mod handle_new_activations {
}; };
assert_eq!(sent_messages.len(), 1); assert_eq!(sent_messages.len(), 1);
match &sent_messages[0] { match AllMessages::from(sent_messages.pop().unwrap()) {
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation(
CandidateReceipt { descriptor, .. }, CandidateReceipt { descriptor, .. },
_pov, _pov,
@@ -356,7 +356,7 @@ mod handle_new_activations {
expect_descriptor.erasure_root = descriptor.erasure_root.clone(); expect_descriptor.erasure_root = descriptor.erasure_root.clone();
expect_descriptor expect_descriptor
}; };
assert_eq!(descriptor, &expect_descriptor); assert_eq!(descriptor, expect_descriptor);
}, },
_ => panic!("received wrong message type"), _ => panic!("received wrong message type"),
} }
@@ -470,11 +470,13 @@ mod handle_new_activations {
assert_eq!(sent_messages.len(), 1); assert_eq!(sent_messages.len(), 1);
match &sent_messages[0] { match &sent_messages[0] {
AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( overseer::CollationGenerationOutgoingMessages::CollatorProtocolMessage(
CandidateReceipt { descriptor, .. }, CollatorProtocolMessage::DistributeCollation(
_pov, CandidateReceipt { descriptor, .. },
.., _pov,
)) => { ..,
),
) => {
assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash); assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash);
}, },
_ => panic!("received wrong message type"), _ => panic!("received wrong message type"),
@@ -38,7 +38,7 @@ use polkadot_node_subsystem::{
ApprovalDistributionMessage, ChainApiMessage, ChainSelectionMessage, RuntimeApiMessage, ApprovalDistributionMessage, ChainApiMessage, ChainSelectionMessage, RuntimeApiMessage,
RuntimeApiRequest, RuntimeApiRequest,
}, },
overseer, RuntimeApiError, SubsystemContext, SubsystemError, SubsystemResult, overseer, RuntimeApiError, SubsystemError, SubsystemResult,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
determine_new_blocks, determine_new_blocks,
@@ -107,8 +107,9 @@ enum ImportedBlockInfoError {
} }
/// Computes information about the imported block. Returns an error if the info couldn't be extracted. /// Computes information about the imported block. Returns an error if the info couldn't be extracted.
async fn imported_block_info( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), async fn imported_block_info<Context>(
ctx: &mut Context,
env: ImportedBlockInfoEnv<'_>, env: ImportedBlockInfoEnv<'_>,
block_hash: Hash, block_hash: Hash,
block_header: &Header, block_header: &Header,
@@ -319,10 +320,11 @@ pub struct BlockImportedCandidates {
/// * and return information about all candidates imported under each block. /// * and return information about all candidates imported under each block.
/// ///
/// It is the responsibility of the caller to schedule wakeups for each block. /// It is the responsibility of the caller to schedule wakeups for each block.
pub(crate) async fn handle_new_head( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), pub(crate) async fn handle_new_head<Context, B: Backend>(
ctx: &mut Context,
state: &mut State, state: &mut State,
db: &mut OverlayedBackend<'_, impl Backend>, db: &mut OverlayedBackend<'_, B>,
head: Hash, head: Hash,
finalized_number: &Option<BlockNumber>, finalized_number: &Option<BlockNumber>,
) -> SubsystemResult<Vec<BlockImportedCandidates>> { ) -> SubsystemResult<Vec<BlockImportedCandidates>> {
@@ -609,7 +611,7 @@ pub(crate) mod tests {
use assert_matches::assert_matches; use assert_matches::assert_matches;
use merlin::Transcript; use merlin::Transcript;
use polkadot_node_primitives::approval::{VRFOutput, VRFProof}; use polkadot_node_primitives::approval::{VRFOutput, VRFProof};
use polkadot_node_subsystem::messages::AllMessages; use polkadot_node_subsystem::messages::{AllMessages, ApprovalVotingMessage};
use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_test_helpers::make_subsystem_context;
use polkadot_node_subsystem_util::database::Database; use polkadot_node_subsystem_util::database::Database;
use polkadot_primitives::v2::{Id as ParaId, SessionInfo, ValidatorIndex}; use polkadot_primitives::v2::{Id as ParaId, SessionInfo, ValidatorIndex};
@@ -724,7 +726,8 @@ pub(crate) mod tests {
#[test] #[test]
fn imported_block_info_is_good() { fn imported_block_info_is_good() {
let pool = TaskExecutor::new(); let pool = TaskExecutor::new();
let (mut ctx, mut handle) = make_subsystem_context::<(), _>(pool.clone()); let (mut ctx, mut handle) =
make_subsystem_context::<ApprovalVotingMessage, _>(pool.clone());
let session = 5; let session = 5;
let session_info = dummy_session_info(session); let session_info = dummy_session_info(session);
@@ -847,7 +850,8 @@ pub(crate) mod tests {
#[test] #[test]
fn imported_block_info_fails_if_no_babe_vrf() { fn imported_block_info_fails_if_no_babe_vrf() {
let pool = TaskExecutor::new(); let pool = TaskExecutor::new();
let (mut ctx, mut handle) = make_subsystem_context::<(), _>(pool.clone()); let (mut ctx, mut handle) =
make_subsystem_context::<ApprovalVotingMessage, _>(pool.clone());
let session = 5; let session = 5;
let session_info = dummy_session_info(session); let session_info = dummy_session_info(session);
@@ -950,7 +954,8 @@ pub(crate) mod tests {
#[test] #[test]
fn imported_block_info_fails_if_ancient_session() { fn imported_block_info_fails_if_ancient_session() {
let pool = TaskExecutor::new(); let pool = TaskExecutor::new();
let (mut ctx, mut handle) = make_subsystem_context::<(), _>(pool.clone()); let (mut ctx, mut handle) =
make_subsystem_context::<ApprovalVotingMessage, _>(pool.clone());
let session = 5; let session = 5;
@@ -1027,7 +1032,7 @@ pub(crate) mod tests {
#[test] #[test]
fn imported_block_info_extracts_force_approve() { fn imported_block_info_extracts_force_approve() {
let pool = TaskExecutor::new(); let pool = TaskExecutor::new();
let (mut ctx, mut handle) = make_subsystem_context::<(), _>(pool.clone()); let (mut ctx, mut handle) = make_subsystem_context(pool.clone());
let session = 5; let session = 5;
let session_info = dummy_session_info(session); let session_info = dummy_session_info(session);
@@ -1158,7 +1163,8 @@ pub(crate) mod tests {
let mut overlay_db = OverlayedBackend::new(&db); let mut overlay_db = OverlayedBackend::new(&db);
let pool = TaskExecutor::new(); let pool = TaskExecutor::new();
let (mut ctx, mut handle) = make_subsystem_context::<(), _>(pool.clone()); let (mut ctx, mut handle) =
make_subsystem_context::<ApprovalVotingMessage, _>(pool.clone());
let session = 5; let session = 5;
let irrelevant = 666; let irrelevant = 666;
+64 -74
View File
@@ -37,9 +37,8 @@ use polkadot_node_subsystem::{
ChainSelectionMessage, DisputeCoordinatorMessage, HighestApprovedAncestorBlock, ChainSelectionMessage, DisputeCoordinatorMessage, HighestApprovedAncestorBlock,
RuntimeApiMessage, RuntimeApiRequest, RuntimeApiMessage, RuntimeApiRequest,
}, },
overseer::{self, SubsystemSender as _}, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult,
FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemError, SubsystemSender,
SubsystemResult, SubsystemSender,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
database::Database, database::Database,
@@ -355,11 +354,8 @@ impl ApprovalVotingSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for ApprovalVotingSubsystem #[overseer::subsystem(ApprovalVoting, error = SubsystemError, prefix = self::overseer)]
where impl<Context: Send> ApprovalVotingSubsystem {
Context: SubsystemContext<Message = ApprovalVotingMessage>,
Context: overseer::SubsystemContext<Message = ApprovalVotingMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let backend = DbBackend::new(self.db.clone(), self.db_config); let backend = DbBackend::new(self.db.clone(), self.db_config);
let future = run::<DbBackend, Context>( let future = run::<DbBackend, Context>(
@@ -597,27 +593,34 @@ struct State {
assignment_criteria: Box<dyn AssignmentCriteria + Send + Sync>, assignment_criteria: Box<dyn AssignmentCriteria + Send + Sync>,
} }
#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
impl State { impl State {
fn session_info(&self, i: SessionIndex) -> Option<&SessionInfo> { fn session_info(&self, i: SessionIndex) -> Option<&SessionInfo> {
self.session_window.as_ref().and_then(|w| w.session_info(i)) self.session_window.as_ref().and_then(|w| w.session_info(i))
} }
/// Bring `session_window` up to date. /// Bring `session_window` up to date.
pub async fn cache_session_info_for_head( pub async fn cache_session_info_for_head<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
head: Hash, head: Hash,
) -> Result<Option<SessionWindowUpdate>, SessionsUnavailable> { ) -> Result<Option<SessionWindowUpdate>, SessionsUnavailable>
where
<Context as overseer::SubsystemContext>::Sender: Sized + Send,
{
let session_window = self.session_window.take(); let session_window = self.session_window.take();
match session_window { match session_window {
None => { None => {
let sender = ctx.sender().clone();
self.session_window = self.session_window =
Some(RollingSessionWindow::new(ctx, APPROVAL_SESSIONS, head).await?); Some(RollingSessionWindow::new(sender, APPROVAL_SESSIONS, head).await?);
Ok(None) Ok(None)
}, },
Some(mut session_window) => { Some(mut session_window) => {
let r = let r = session_window
session_window.cache_session_info_for_head(ctx, head).await.map(Option::Some); .cache_session_info_for_head(ctx.sender(), head)
.await
.map(Option::Some);
self.session_window = Some(session_window); self.session_window = Some(session_window);
r r
}, },
@@ -701,6 +704,7 @@ enum Action {
Conclude, Conclude,
} }
#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
async fn run<B, Context>( async fn run<B, Context>(
mut ctx: Context, mut ctx: Context,
mut subsystem: ApprovalVotingSubsystem, mut subsystem: ApprovalVotingSubsystem,
@@ -709,8 +713,6 @@ async fn run<B, Context>(
mut backend: B, mut backend: B,
) -> SubsystemResult<()> ) -> SubsystemResult<()>
where where
Context: SubsystemContext<Message = ApprovalVotingMessage>,
Context: overseer::SubsystemContext<Message = ApprovalVotingMessage>,
B: Backend, B: Backend,
{ {
let mut state = State { let mut state = State {
@@ -848,9 +850,9 @@ where
// https://github.com/paritytech/polkadot/issues/3311 // https://github.com/paritytech/polkadot/issues/3311
// //
// returns `true` if any of the actions was a `Conclude` command. // returns `true` if any of the actions was a `Conclude` command.
async fn handle_actions( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext<Message = ApprovalVotingMessage> async fn handle_actions<Context>(
+ overseer::SubsystemContext<Message = ApprovalVotingMessage>), ctx: &mut Context,
state: &mut State, state: &mut State,
overlayed_db: &mut OverlayedBackend<'_, impl Backend>, overlayed_db: &mut OverlayedBackend<'_, impl Backend>,
metrics: &Metrics, metrics: &Metrics,
@@ -868,7 +870,6 @@ async fn handle_actions(
Action::ScheduleWakeup { block_hash, block_number, candidate_hash, tick } => Action::ScheduleWakeup { block_hash, block_number, candidate_hash, tick } =>
wakeups.schedule(block_hash, block_number, candidate_hash, tick), wakeups.schedule(block_hash, block_number, candidate_hash, tick),
Action::IssueApproval(candidate_hash, approval_request) => { Action::IssueApproval(candidate_hash, approval_request) => {
let mut sender = ctx.sender().clone();
// Note that the IssueApproval action will create additional // Note that the IssueApproval action will create additional
// actions that will need to all be processed before we can // actions that will need to all be processed before we can
// handle the next action in the set passed to the ambient // handle the next action in the set passed to the ambient
@@ -881,7 +882,7 @@ async fn handle_actions(
// Note that chaining these iterators is O(n) as we must consume // Note that chaining these iterators is O(n) as we must consume
// the prior iterator. // the prior iterator.
let next_actions: Vec<Action> = issue_approval( let next_actions: Vec<Action> = issue_approval(
&mut sender, ctx,
state, state,
overlayed_db, overlayed_db,
metrics, metrics,
@@ -1086,9 +1087,9 @@ fn distribution_messages_for_activation(
} }
// Handle an incoming signal from the overseer. Returns true if execution should conclude. // Handle an incoming signal from the overseer. Returns true if execution should conclude.
async fn handle_from_overseer( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext<Message = ApprovalVotingMessage> async fn handle_from_overseer<Context>(
+ overseer::SubsystemContext<Message = ApprovalVotingMessage>), ctx: &mut Context,
state: &mut State, state: &mut State,
db: &mut OverlayedBackend<'_, impl Backend>, db: &mut OverlayedBackend<'_, impl Backend>,
metrics: &Metrics, metrics: &Metrics,
@@ -1197,8 +1198,9 @@ async fn handle_from_overseer(
Ok(actions) Ok(actions)
} }
async fn handle_approved_ancestor( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), async fn handle_approved_ancestor<Context>(
ctx: &mut Context,
db: &OverlayedBackend<'_, impl Backend>, db: &OverlayedBackend<'_, impl Backend>,
target: Hash, target: Hash,
lower_bound: BlockNumber, lower_bound: BlockNumber,
@@ -2147,9 +2149,9 @@ fn process_wakeup(
// Launch approval work, returning an `AbortHandle` which corresponds to the background task // Launch approval work, returning an `AbortHandle` which corresponds to the background task
// spawned. When the background work is no longer needed, the `AbortHandle` should be dropped // spawned. When the background work is no longer needed, the `AbortHandle` should be dropped
// to cancel the background work and any requests it has spawned. // to cancel the background work and any requests it has spawned.
async fn launch_approval( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext<Message = ApprovalVotingMessage> async fn launch_approval<Context>(
+ overseer::SubsystemContext<Message = ApprovalVotingMessage>), ctx: &mut Context,
metrics: Metrics, metrics: Metrics,
session_index: SessionIndex, session_index: SessionIndex,
candidate: CandidateReceipt, candidate: CandidateReceipt,
@@ -2242,15 +2244,12 @@ async fn launch_approval(
); );
sender sender
.send_message( .send_message(DisputeCoordinatorMessage::IssueLocalStatement(
DisputeCoordinatorMessage::IssueLocalStatement( session_index,
session_index, candidate_hash,
candidate_hash, candidate.clone(),
candidate.clone(), false,
false, ))
)
.into(),
)
.await; .await;
metrics_guard.take().on_approval_invalid(); metrics_guard.take().on_approval_invalid();
}, },
@@ -2281,17 +2280,14 @@ async fn launch_approval(
let (val_tx, val_rx) = oneshot::channel(); let (val_tx, val_rx) = oneshot::channel();
sender sender
.send_message( .send_message(CandidateValidationMessage::ValidateFromExhaustive(
CandidateValidationMessage::ValidateFromExhaustive( available_data.validation_data,
available_data.validation_data, validation_code,
validation_code, candidate.clone(),
candidate.clone(), available_data.pov,
available_data.pov, APPROVAL_EXECUTION_TIMEOUT,
APPROVAL_EXECUTION_TIMEOUT, val_tx,
val_tx, ))
)
.into(),
)
.await; .await;
match val_rx.await { match val_rx.await {
@@ -2309,15 +2305,12 @@ async fn launch_approval(
} else { } else {
// Commitments mismatch - issue a dispute. // Commitments mismatch - issue a dispute.
sender sender
.send_message( .send_message(DisputeCoordinatorMessage::IssueLocalStatement(
DisputeCoordinatorMessage::IssueLocalStatement( session_index,
session_index, candidate_hash,
candidate_hash, candidate.clone(),
candidate.clone(), false,
false, ))
)
.into(),
)
.await; .await;
metrics_guard.take().on_approval_invalid(); metrics_guard.take().on_approval_invalid();
@@ -2334,15 +2327,12 @@ async fn launch_approval(
); );
sender sender
.send_message( .send_message(DisputeCoordinatorMessage::IssueLocalStatement(
DisputeCoordinatorMessage::IssueLocalStatement( session_index,
session_index, candidate_hash,
candidate_hash, candidate.clone(),
candidate.clone(), false,
false, ))
)
.into(),
)
.await; .await;
metrics_guard.take().on_approval_invalid(); metrics_guard.take().on_approval_invalid();
@@ -2368,8 +2358,9 @@ async fn launch_approval(
// Issue and import a local approval vote. Should only be invoked after approval checks // Issue and import a local approval vote. Should only be invoked after approval checks
// have been done. // have been done.
async fn issue_approval( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)]
ctx: &mut impl SubsystemSender, async fn issue_approval<Context>(
ctx: &mut Context,
state: &mut State, state: &mut State,
db: &mut OverlayedBackend<'_, impl Backend>, db: &mut OverlayedBackend<'_, impl Backend>,
metrics: &Metrics, metrics: &Metrics,
@@ -2527,15 +2518,14 @@ async fn issue_approval(
metrics.on_approval_produced(); metrics.on_approval_produced();
// dispatch to approval distribution. // dispatch to approval distribution.
ctx.send_unbounded_message( ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeApproval(
ApprovalDistributionMessage::DistributeApproval(IndirectSignedApprovalVote { IndirectSignedApprovalVote {
block_hash, block_hash,
candidate_index: candidate_index as _, candidate_index: candidate_index as _,
validator: validator_index, validator: validator_index,
signature: sig, signature: sig,
}) },
.into(), ));
);
// dispatch to dispute coordinator. // dispatch to dispute coordinator.
actions.extend(inform_disputes_action); actions.extend(inform_disputes_action);
+14 -33
View File
@@ -36,8 +36,7 @@ use polkadot_node_primitives::{AvailableData, ErasureChunk};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::{ChainApiError, RuntimeApiError}, errors::{ChainApiError, RuntimeApiError},
messages::{AvailabilityStoreMessage, ChainApiMessage}, messages::{AvailabilityStoreMessage, ChainApiMessage},
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
SubsystemError,
}; };
use polkadot_node_subsystem_util as util; use polkadot_node_subsystem_util as util;
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
@@ -519,23 +518,17 @@ impl KnownUnfinalizedBlocks {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for AvailabilityStoreSubsystem #[overseer::subsystem(AvailabilityStore, error=SubsystemError, prefix=self::overseer)]
where impl<Context> AvailabilityStoreSubsystem {
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run(self, ctx).map(|_| Ok(())).boxed(); let future = run::<Context>(self, ctx).map(|_| Ok(())).boxed();
SpawnedSubsystem { name: "availability-store-subsystem", future } SpawnedSubsystem { name: "availability-store-subsystem", future }
} }
} }
async fn run<Context>(mut subsystem: AvailabilityStoreSubsystem, mut ctx: Context) #[overseer::contextbounds(AvailabilityStore, prefix = self::overseer)]
where async fn run<Context>(mut subsystem: AvailabilityStoreSubsystem, mut ctx: Context) {
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let mut next_pruning = Delay::new(subsystem.pruning_config.pruning_interval).fuse(); let mut next_pruning = Delay::new(subsystem.pruning_config.pruning_interval).fuse();
loop { loop {
@@ -556,15 +549,12 @@ where
} }
} }
#[overseer::contextbounds(AvailabilityStore, prefix = self::overseer)]
async fn run_iteration<Context>( async fn run_iteration<Context>(
ctx: &mut Context, ctx: &mut Context,
subsystem: &mut AvailabilityStoreSubsystem, subsystem: &mut AvailabilityStoreSubsystem,
mut next_pruning: &mut future::Fuse<Delay>, mut next_pruning: &mut future::Fuse<Delay>,
) -> Result<bool, Error> ) -> Result<bool, Error> {
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
select! { select! {
incoming = ctx.recv().fuse() => { incoming = ctx.recv().fuse() => {
match incoming.map_err(|_| Error::ContextChannelClosed)? { match incoming.map_err(|_| Error::ContextChannelClosed)? {
@@ -608,15 +598,12 @@ where
Ok(false) Ok(false)
} }
#[overseer::contextbounds(AvailabilityStore, prefix = self::overseer)]
async fn process_block_activated<Context>( async fn process_block_activated<Context>(
ctx: &mut Context, ctx: &mut Context,
subsystem: &mut AvailabilityStoreSubsystem, subsystem: &mut AvailabilityStoreSubsystem,
activated: Hash, activated: Hash,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let now = subsystem.clock.now()?; let now = subsystem.clock.now()?;
let block_header = { let block_header = {
@@ -663,6 +650,7 @@ where
Ok(()) Ok(())
} }
#[overseer::contextbounds(AvailabilityStore, prefix = self::overseer)]
async fn process_new_head<Context>( async fn process_new_head<Context>(
ctx: &mut Context, ctx: &mut Context,
db: &Arc<dyn Database>, db: &Arc<dyn Database>,
@@ -672,11 +660,7 @@ async fn process_new_head<Context>(
now: Duration, now: Duration,
hash: Hash, hash: Hash,
header: Header, header: Header,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let candidate_events = util::request_candidate_events(hash, ctx.sender()).await.await??; let candidate_events = util::request_candidate_events(hash, ctx.sender()).await.await??;
// We need to request the number of validators based on the parent state, // We need to request the number of validators based on the parent state,
@@ -814,16 +798,13 @@ macro_rules! peek_num {
}; };
} }
#[overseer::contextbounds(AvailabilityStore, prefix = self::overseer)]
async fn process_block_finalized<Context>( async fn process_block_finalized<Context>(
ctx: &mut Context, ctx: &mut Context,
subsystem: &AvailabilityStoreSubsystem, subsystem: &AvailabilityStoreSubsystem,
finalized_hash: Hash, finalized_hash: Hash,
finalized_number: BlockNumber, finalized_number: BlockNumber,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let now = subsystem.clock.now()?; let now = subsystem.clock.now()?;
let mut next_possible_batch = 0; let mut next_possible_batch = 0;
+4 -4
View File
@@ -309,13 +309,13 @@ fn store_chunk_works() {
let chunk_msg = let chunk_msg =
AvailabilityStoreMessage::StoreChunk { candidate_hash, chunk: chunk.clone(), tx }; AvailabilityStoreMessage::StoreChunk { candidate_hash, chunk: chunk.clone(), tx };
overseer_send(&mut virtual_overseer, chunk_msg.into()).await; overseer_send(&mut virtual_overseer, chunk_msg).await;
assert_eq!(rx.await.unwrap(), Ok(())); assert_eq!(rx.await.unwrap(), Ok(()));
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let query_chunk = AvailabilityStoreMessage::QueryChunk(candidate_hash, validator_index, tx); let query_chunk = AvailabilityStoreMessage::QueryChunk(candidate_hash, validator_index, tx);
overseer_send(&mut virtual_overseer, query_chunk.into()).await; overseer_send(&mut virtual_overseer, query_chunk).await;
assert_eq!(rx.await.unwrap().unwrap(), chunk); assert_eq!(rx.await.unwrap().unwrap(), chunk);
virtual_overseer virtual_overseer
@@ -341,13 +341,13 @@ fn store_chunk_does_nothing_if_no_entry_already() {
let chunk_msg = let chunk_msg =
AvailabilityStoreMessage::StoreChunk { candidate_hash, chunk: chunk.clone(), tx }; AvailabilityStoreMessage::StoreChunk { candidate_hash, chunk: chunk.clone(), tx };
overseer_send(&mut virtual_overseer, chunk_msg.into()).await; overseer_send(&mut virtual_overseer, chunk_msg).await;
assert_eq!(rx.await.unwrap(), Err(())); assert_eq!(rx.await.unwrap(), Err(()));
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let query_chunk = AvailabilityStoreMessage::QueryChunk(candidate_hash, validator_index, tx); let query_chunk = AvailabilityStoreMessage::QueryChunk(candidate_hash, validator_index, tx);
overseer_send(&mut virtual_overseer, query_chunk.into()).await; overseer_send(&mut virtual_overseer, query_chunk).await;
assert!(rx.await.unwrap().is_none()); assert!(rx.await.unwrap().is_none());
virtual_overseer virtual_overseer
+61 -87
View File
@@ -37,13 +37,12 @@ use polkadot_node_primitives::{
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{ messages::{
AllMessages, AvailabilityDistributionMessage, AvailabilityStoreMessage, AvailabilityDistributionMessage, AvailabilityStoreMessage, CandidateBackingMessage,
CandidateBackingMessage, CandidateValidationMessage, CollatorProtocolMessage, CandidateValidationMessage, CollatorProtocolMessage, DisputeCoordinatorMessage,
DisputeCoordinatorMessage, ProvisionableData, ProvisionerMessage, RuntimeApiRequest, ProvisionableData, ProvisionerMessage, RuntimeApiRequest, StatementDistributionMessage,
StatementDistributionMessage,
}, },
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, PerLeafSpan, SpawnedSubsystem, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, PerLeafSpan, SpawnedSubsystem,
Stage, SubsystemContext, SubsystemError, SubsystemSender, Stage, SubsystemError,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
self as util, request_from_runtime, request_session_index_for_child, request_validator_groups, self as util, request_from_runtime, request_session_index_for_child, request_validator_groups,
@@ -131,10 +130,10 @@ impl CandidateBackingSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for CandidateBackingSubsystem #[overseer::subsystem(CandidateBacking, error = SubsystemError, prefix = self::overseer)]
impl<Context> CandidateBackingSubsystem
where where
Context: SubsystemContext<Message = CandidateBackingMessage>, Context: Send + Sync,
Context: overseer::SubsystemContext<Message = CandidateBackingMessage>,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = async move { let future = async move {
@@ -148,15 +147,12 @@ where
} }
} }
#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
async fn run<Context>( async fn run<Context>(
mut ctx: Context, mut ctx: Context,
keystore: SyncCryptoStorePtr, keystore: SyncCryptoStorePtr,
metrics: Metrics, metrics: Metrics,
) -> FatalResult<()> ) -> FatalResult<()> {
where
Context: SubsystemContext<Message = CandidateBackingMessage>,
Context: overseer::SubsystemContext<Message = CandidateBackingMessage>,
{
let (background_validation_tx, mut background_validation_rx) = mpsc::channel(16); let (background_validation_tx, mut background_validation_rx) = mpsc::channel(16);
let mut jobs = HashMap::new(); let mut jobs = HashMap::new();
@@ -180,6 +176,7 @@ where
Ok(()) Ok(())
} }
#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
async fn run_iteration<Context>( async fn run_iteration<Context>(
ctx: &mut Context, ctx: &mut Context,
keystore: SyncCryptoStorePtr, keystore: SyncCryptoStorePtr,
@@ -187,11 +184,7 @@ async fn run_iteration<Context>(
jobs: &mut HashMap<Hash, JobAndSpan<Context>>, jobs: &mut HashMap<Hash, JobAndSpan<Context>>,
background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>,
background_validation_rx: &mut mpsc::Receiver<(Hash, ValidatedCandidateCommand)>, background_validation_rx: &mut mpsc::Receiver<(Hash, ValidatedCandidateCommand)>,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = CandidateBackingMessage>,
Context: overseer::SubsystemContext<Message = CandidateBackingMessage>,
{
loop { loop {
futures::select!( futures::select!(
validated_command = background_validation_rx.next().fuse() => { validated_command = background_validation_rx.next().fuse() => {
@@ -225,16 +218,13 @@ where
} }
} }
#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
async fn handle_validated_candidate_command<Context>( async fn handle_validated_candidate_command<Context>(
ctx: &mut Context, ctx: &mut Context,
jobs: &mut HashMap<Hash, JobAndSpan<Context>>, jobs: &mut HashMap<Hash, JobAndSpan<Context>>,
relay_parent: Hash, relay_parent: Hash,
command: ValidatedCandidateCommand, command: ValidatedCandidateCommand,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = CandidateBackingMessage>,
Context: overseer::SubsystemContext<Message = CandidateBackingMessage>,
{
if let Some(job) = jobs.get_mut(&relay_parent) { if let Some(job) = jobs.get_mut(&relay_parent) {
job.job.handle_validated_candidate_command(&job.span, ctx, command).await?; job.job.handle_validated_candidate_command(&job.span, ctx, command).await?;
} else { } else {
@@ -245,15 +235,12 @@ where
Ok(()) Ok(())
} }
#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
async fn handle_communication<Context>( async fn handle_communication<Context>(
ctx: &mut Context, ctx: &mut Context,
jobs: &mut HashMap<Hash, JobAndSpan<Context>>, jobs: &mut HashMap<Hash, JobAndSpan<Context>>,
message: CandidateBackingMessage, message: CandidateBackingMessage,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = CandidateBackingMessage>,
Context: overseer::SubsystemContext<Message = CandidateBackingMessage>,
{
match message { match message {
CandidateBackingMessage::Second(relay_parent, candidate, pov) => { CandidateBackingMessage::Second(relay_parent, candidate, pov) => {
if let Some(job) = jobs.get_mut(&relay_parent) { if let Some(job) = jobs.get_mut(&relay_parent) {
@@ -274,6 +261,7 @@ where
Ok(()) Ok(())
} }
#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
async fn handle_active_leaves_update<Context>( async fn handle_active_leaves_update<Context>(
ctx: &mut Context, ctx: &mut Context,
update: ActiveLeavesUpdate, update: ActiveLeavesUpdate,
@@ -281,11 +269,7 @@ async fn handle_active_leaves_update<Context>(
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
background_validation_tx: &mpsc::Sender<(Hash, ValidatedCandidateCommand)>, background_validation_tx: &mpsc::Sender<(Hash, ValidatedCandidateCommand)>,
metrics: &Metrics, metrics: &Metrics,
) -> Result<(), Error> ) -> Result<(), Error> {
where
Context: SubsystemContext<Message = CandidateBackingMessage>,
Context: overseer::SubsystemContext<Message = CandidateBackingMessage>,
{
for deactivated in update.deactivated { for deactivated in update.deactivated {
jobs.remove(&deactivated); jobs.remove(&deactivated);
} }
@@ -578,22 +562,19 @@ fn table_attested_to_backed(
} }
async fn store_available_data( async fn store_available_data(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::CandidateBackingSenderTrait,
n_validators: u32, n_validators: u32,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
available_data: AvailableData, available_data: AvailableData,
) -> Result<(), Error> { ) -> Result<(), Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(AvailabilityStoreMessage::StoreAvailableData {
AvailabilityStoreMessage::StoreAvailableData { candidate_hash,
candidate_hash, n_validators,
n_validators, available_data,
available_data, tx,
tx, })
}
.into(),
)
.await; .await;
let _ = rx.await.map_err(Error::StoreAvailableData)?; let _ = rx.await.map_err(Error::StoreAvailableData)?;
@@ -605,8 +586,9 @@ async fn store_available_data(
// //
// This will compute the erasure root internally and compare it to the expected erasure root. // This will compute the erasure root internally and compare it to the expected erasure root.
// This returns `Err()` iff there is an internal error. Otherwise, it returns either `Ok(Ok(()))` or `Ok(Err(_))`. // This returns `Err()` iff there is an internal error. Otherwise, it returns either `Ok(Ok(()))` or `Ok(Err(_))`.
async fn make_pov_available( async fn make_pov_available(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::CandidateBackingSenderTrait,
n_validators: usize, n_validators: usize,
pov: Arc<PoV>, pov: Arc<PoV>,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
@@ -639,7 +621,7 @@ async fn make_pov_available(
} }
async fn request_pov( async fn request_pov(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::CandidateBackingSenderTrait,
relay_parent: Hash, relay_parent: Hash,
from_validator: ValidatorIndex, from_validator: ValidatorIndex,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
@@ -647,16 +629,13 @@ async fn request_pov(
) -> Result<Arc<PoV>, Error> { ) -> Result<Arc<PoV>, Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(AvailabilityDistributionMessage::FetchPoV {
AvailabilityDistributionMessage::FetchPoV { relay_parent,
relay_parent, from_validator,
from_validator, candidate_hash,
candidate_hash, pov_hash,
pov_hash, tx,
tx, })
}
.into(),
)
.await; .await;
let pov = rx.await.map_err(|_| Error::FetchPoV)?; let pov = rx.await.map_err(|_| Error::FetchPoV)?;
@@ -664,22 +643,19 @@ async fn request_pov(
} }
async fn request_candidate_validation( async fn request_candidate_validation(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::CandidateBackingSenderTrait,
candidate_receipt: CandidateReceipt, candidate_receipt: CandidateReceipt,
pov: Arc<PoV>, pov: Arc<PoV>,
) -> Result<ValidationResult, Error> { ) -> Result<ValidationResult, Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(CandidateValidationMessage::ValidateFromChainState(
CandidateValidationMessage::ValidateFromChainState( candidate_receipt,
candidate_receipt, pov,
pov, BACKING_EXECUTION_TIMEOUT,
BACKING_EXECUTION_TIMEOUT, tx,
tx, ))
)
.into(),
)
.await; .await;
match rx.await { match rx.await {
@@ -692,7 +668,7 @@ async fn request_candidate_validation(
type BackgroundValidationResult = type BackgroundValidationResult =
Result<(CandidateReceipt, CandidateCommitments, Arc<PoV>), CandidateReceipt>; Result<(CandidateReceipt, CandidateCommitments, Arc<PoV>), CandidateReceipt>;
struct BackgroundValidationParams<S: overseer::SubsystemSender<AllMessages>, F> { struct BackgroundValidationParams<S: overseer::CandidateBackingSenderTrait, F> {
sender: S, sender: S,
tx_command: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, tx_command: mpsc::Sender<(Hash, ValidatedCandidateCommand)>,
candidate: CandidateReceipt, candidate: CandidateReceipt,
@@ -705,7 +681,7 @@ struct BackgroundValidationParams<S: overseer::SubsystemSender<AllMessages>, F>
async fn validate_and_make_available( async fn validate_and_make_available(
params: BackgroundValidationParams< params: BackgroundValidationParams<
impl SubsystemSender, impl overseer::CandidateBackingSenderTrait,
impl Fn(BackgroundValidationResult) -> ValidatedCandidateCommand + Sync, impl Fn(BackgroundValidationResult) -> ValidatedCandidateCommand + Sync,
>, >,
) -> Result<(), Error> { ) -> Result<(), Error> {
@@ -809,11 +785,8 @@ async fn validate_and_make_available(
struct ValidatorIndexOutOfBounds; struct ValidatorIndexOutOfBounds;
impl<Context> CandidateBackingJob<Context> #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
where impl<Context> CandidateBackingJob<Context> {
Context: SubsystemContext,
Context: overseer::SubsystemContext,
{
async fn handle_validated_candidate_command( async fn handle_validated_candidate_command(
&mut self, &mut self,
root_span: &jaeger::Span, root_span: &jaeger::Span,
@@ -896,7 +869,7 @@ where
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
params: BackgroundValidationParams< params: BackgroundValidationParams<
impl SubsystemSender, impl overseer::CandidateBackingSenderTrait,
impl Fn(BackgroundValidationResult) -> ValidatedCandidateCommand + Send + 'static + Sync, impl Fn(BackgroundValidationResult) -> ValidatedCandidateCommand + Send + 'static + Sync,
>, >,
) -> Result<(), Error> { ) -> Result<(), Error> {
@@ -1001,7 +974,7 @@ where
} }
/// Check if there have happened any new misbehaviors and issue necessary messages. /// Check if there have happened any new misbehaviors and issue necessary messages.
fn issue_new_misbehaviors(&mut self, ctx: &mut Context) { fn issue_new_misbehaviors(&mut self, sender: &mut impl overseer::CandidateBackingSenderTrait) {
// collect the misbehaviors to avoid double mutable self borrow issues // collect the misbehaviors to avoid double mutable self borrow issues
let misbehaviors: Vec<_> = self.table.drain_misbehaviors().collect(); let misbehaviors: Vec<_> = self.table.drain_misbehaviors().collect();
for (validator_id, report) in misbehaviors { for (validator_id, report) in misbehaviors {
@@ -1010,7 +983,7 @@ where
// //
// Misbehaviors are bounded by the number of validators and // Misbehaviors are bounded by the number of validators and
// the block production protocol. // the block production protocol.
ctx.send_unbounded_message(ProvisionerMessage::ProvisionableData( sender.send_unbounded_message(ProvisionerMessage::ProvisionableData(
self.parent, self.parent,
ProvisionableData::MisbehaviorReport(self.parent, validator_id, report), ProvisionableData::MisbehaviorReport(self.parent, validator_id, report),
)); ));
@@ -1042,7 +1015,7 @@ where
}; };
if let Err(ValidatorIndexOutOfBounds) = self if let Err(ValidatorIndexOutOfBounds) = self
.dispatch_new_statement_to_dispute_coordinator(ctx, candidate_hash, &statement) .dispatch_new_statement_to_dispute_coordinator(ctx.sender(), candidate_hash, &statement)
.await .await
{ {
gum::warn!( gum::warn!(
@@ -1101,7 +1074,7 @@ where
None None
}; };
self.issue_new_misbehaviors(ctx); self.issue_new_misbehaviors(ctx.sender());
// It is important that the child span is dropped before its parent span (`unbacked_span`) // It is important that the child span is dropped before its parent span (`unbacked_span`)
drop(import_statement_span); drop(import_statement_span);
@@ -1123,8 +1096,8 @@ where
/// the networking component responsible for feeding statements to the backing subsystem /// the networking component responsible for feeding statements to the backing subsystem
/// is meant to check the signature and provenance of all statements before submission. /// is meant to check the signature and provenance of all statements before submission.
async fn dispatch_new_statement_to_dispute_coordinator( async fn dispatch_new_statement_to_dispute_coordinator(
&mut self, &self,
ctx: &mut Context, sender: &mut impl overseer::CandidateBackingSenderTrait,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
statement: &SignedFullStatement, statement: &SignedFullStatement,
) -> Result<(), ValidatorIndexOutOfBounds> { ) -> Result<(), ValidatorIndexOutOfBounds> {
@@ -1157,14 +1130,15 @@ where
if let (Some(candidate_receipt), Some(dispute_statement)) = if let (Some(candidate_receipt), Some(dispute_statement)) =
(maybe_candidate_receipt, maybe_signed_dispute_statement) (maybe_candidate_receipt, maybe_signed_dispute_statement)
{ {
ctx.send_message(DisputeCoordinatorMessage::ImportStatements { sender
candidate_hash, .send_message(DisputeCoordinatorMessage::ImportStatements {
candidate_receipt, candidate_hash,
session: self.session_index, candidate_receipt,
statements: vec![(dispute_statement, validator_index)], session: self.session_index,
pending_confirmation: None, statements: vec![(dispute_statement, validator_index)],
}) pending_confirmation: None,
.await; })
.await;
} }
Ok(()) Ok(())
+4 -1
View File
@@ -23,7 +23,10 @@ use assert_matches::assert_matches;
use futures::{future, Future}; use futures::{future, Future};
use polkadot_node_primitives::{BlockData, InvalidCandidate}; use polkadot_node_primitives::{BlockData, InvalidCandidate};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{CollatorProtocolMessage, RuntimeApiMessage, RuntimeApiRequest, ValidationFailed}, messages::{
AllMessages, CollatorProtocolMessage, RuntimeApiMessage, RuntimeApiRequest,
ValidationFailed,
},
ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, LeafStatus, OverseerSignal, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, LeafStatus, OverseerSignal,
}; };
use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_test_helpers as test_helpers;
+15 -9
View File
@@ -34,7 +34,7 @@ use polkadot_node_subsystem::{
AvailabilityStoreMessage, BitfieldDistributionMessage, BitfieldSigningMessage, AvailabilityStoreMessage, BitfieldDistributionMessage, BitfieldSigningMessage,
RuntimeApiMessage, RuntimeApiRequest, RuntimeApiMessage, RuntimeApiRequest,
}, },
ActivatedLeaf, LeafStatus, PerLeafSpan, SubsystemSender, overseer, ActivatedLeaf, LeafStatus, PerLeafSpan, SubsystemSender,
}; };
use polkadot_node_subsystem_util::{self as util, JobSender, JobSubsystem, JobTrait, Validator}; use polkadot_node_subsystem_util::{self as util, JobSender, JobSubsystem, JobTrait, Validator};
use polkadot_primitives::v2::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex}; use polkadot_primitives::v2::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex};
@@ -53,7 +53,7 @@ const JOB_DELAY: Duration = Duration::from_millis(1500);
const LOG_TARGET: &str = "parachain::bitfield-signing"; const LOG_TARGET: &str = "parachain::bitfield-signing";
/// Each `BitfieldSigningJob` prepares a signed bitfield for a single relay parent. /// Each `BitfieldSigningJob` prepares a signed bitfield for a single relay parent.
pub struct BitfieldSigningJob; pub struct BitfieldSigningJob<Sender>(std::marker::PhantomData<Sender>);
/// Errors we may encounter in the course of executing the `BitfieldSigningSubsystem`. /// Errors we may encounter in the course of executing the `BitfieldSigningSubsystem`.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@@ -83,7 +83,7 @@ pub enum Error {
async fn get_core_availability( async fn get_core_availability(
core: &CoreState, core: &CoreState,
validator_idx: ValidatorIndex, validator_idx: ValidatorIndex,
sender: &Mutex<&mut impl SubsystemSender>, sender: &Mutex<&mut impl SubsystemSender<overseer::BitfieldSigningOutgoingMessages>>,
span: &jaeger::Span, span: &jaeger::Span,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
if let &CoreState::Occupied(ref core) = core { if let &CoreState::Occupied(ref core) = core {
@@ -122,7 +122,7 @@ async fn get_core_availability(
/// delegates to the v1 runtime API /// delegates to the v1 runtime API
async fn get_availability_cores( async fn get_availability_cores(
relay_parent: Hash, relay_parent: Hash,
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<overseer::BitfieldSigningOutgoingMessages>,
) -> Result<Vec<CoreState>, Error> { ) -> Result<Vec<CoreState>, Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
@@ -146,7 +146,7 @@ async fn construct_availability_bitfield(
relay_parent: Hash, relay_parent: Hash,
span: &jaeger::Span, span: &jaeger::Span,
validator_idx: ValidatorIndex, validator_idx: ValidatorIndex,
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<overseer::BitfieldSigningOutgoingMessages>,
) -> Result<AvailabilityBitfield, Error> { ) -> Result<AvailabilityBitfield, Error> {
// get the set of availability cores from the runtime // get the set of availability cores from the runtime
let availability_cores = { let availability_cores = {
@@ -182,8 +182,13 @@ async fn construct_availability_bitfield(
Ok(AvailabilityBitfield(core_bits)) Ok(AvailabilityBitfield(core_bits))
} }
impl JobTrait for BitfieldSigningJob { impl<Sender> JobTrait for BitfieldSigningJob<Sender>
where
Sender: overseer::BitfieldSigningSenderTrait + Unpin,
{
type ToJob = BitfieldSigningMessage; type ToJob = BitfieldSigningMessage;
type OutgoingMessages = overseer::BitfieldSigningOutgoingMessages;
type Sender = Sender;
type Error = Error; type Error = Error;
type RunArgs = SyncCryptoStorePtr; type RunArgs = SyncCryptoStorePtr;
type Metrics = Metrics; type Metrics = Metrics;
@@ -191,12 +196,12 @@ impl JobTrait for BitfieldSigningJob {
const NAME: &'static str = "bitfield-signing-job"; const NAME: &'static str = "bitfield-signing-job";
/// Run a job for the parent block indicated /// Run a job for the parent block indicated
fn run<S: SubsystemSender>( fn run(
leaf: ActivatedLeaf, leaf: ActivatedLeaf,
keystore: Self::RunArgs, keystore: Self::RunArgs,
metrics: Self::Metrics, metrics: Self::Metrics,
_receiver: mpsc::Receiver<BitfieldSigningMessage>, _receiver: mpsc::Receiver<BitfieldSigningMessage>,
mut sender: JobSender<S>, mut sender: JobSender<Sender>,
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> { ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> {
let metrics = metrics.clone(); let metrics = metrics.clone();
async move { async move {
@@ -286,4 +291,5 @@ impl JobTrait for BitfieldSigningJob {
} }
/// `BitfieldSigningSubsystem` manages a number of bitfield signing jobs. /// `BitfieldSigningSubsystem` manages a number of bitfield signing jobs.
pub type BitfieldSigningSubsystem<Spawner> = JobSubsystem<BitfieldSigningJob, Spawner>; pub type BitfieldSigningSubsystem<Spawner, Sender> =
JobSubsystem<BitfieldSigningJob<Sender>, Spawner>;
@@ -35,8 +35,8 @@ use polkadot_node_subsystem::{
CandidateValidationMessage, PreCheckOutcome, RuntimeApiMessage, RuntimeApiRequest, CandidateValidationMessage, PreCheckOutcome, RuntimeApiMessage, RuntimeApiRequest,
ValidationFailed, ValidationFailed,
}, },
overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemError, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult,
SubsystemResult, SubsystemSender, SubsystemSender,
}; };
use polkadot_parachain::primitives::{ValidationParams, ValidationResult as WasmValidationResult}; use polkadot_parachain::primitives::{ValidationParams, ValidationResult as WasmValidationResult};
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
@@ -93,11 +93,8 @@ impl CandidateValidationSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for CandidateValidationSubsystem #[overseer::subsystem(CandidateValidation, error=SubsystemError, prefix=self::overseer)]
where impl<Context> CandidateValidationSubsystem {
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run( let future = run(
ctx, ctx,
@@ -112,17 +109,14 @@ where
} }
} }
#[overseer::contextbounds(CandidateValidation, prefix = self::overseer)]
async fn run<Context>( async fn run<Context>(
mut ctx: Context, mut ctx: Context,
metrics: Metrics, metrics: Metrics,
pvf_metrics: polkadot_node_core_pvf::Metrics, pvf_metrics: polkadot_node_core_pvf::Metrics,
cache_path: PathBuf, cache_path: PathBuf,
program_path: PathBuf, program_path: PathBuf,
) -> SubsystemResult<()> ) -> SubsystemResult<()> {
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
let (validation_host, task) = polkadot_node_core_pvf::start( let (validation_host, task) = polkadot_node_core_pvf::start(
polkadot_node_core_pvf::Config::new(cache_path, program_path), polkadot_node_core_pvf::Config::new(cache_path, program_path),
pvf_metrics, pvf_metrics,
@@ -235,7 +229,7 @@ async fn runtime_api_request<T, Sender>(
receiver: oneshot::Receiver<Result<T, RuntimeApiError>>, receiver: oneshot::Receiver<Result<T, RuntimeApiError>>,
) -> Result<T, RuntimeRequestFailed> ) -> Result<T, RuntimeRequestFailed>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
sender sender
.send_message(RuntimeApiMessage::Request(relay_parent, request).into()) .send_message(RuntimeApiMessage::Request(relay_parent, request).into())
@@ -268,7 +262,7 @@ async fn request_validation_code_by_hash<Sender>(
validation_code_hash: ValidationCodeHash, validation_code_hash: ValidationCodeHash,
) -> Result<Option<ValidationCode>, RuntimeRequestFailed> ) -> Result<Option<ValidationCode>, RuntimeRequestFailed>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
runtime_api_request( runtime_api_request(
@@ -287,7 +281,7 @@ async fn precheck_pvf<Sender>(
validation_code_hash: ValidationCodeHash, validation_code_hash: ValidationCodeHash,
) -> PreCheckOutcome ) -> PreCheckOutcome
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
let validation_code = let validation_code =
match request_validation_code_by_hash(sender, relay_parent, validation_code_hash).await { match request_validation_code_by_hash(sender, relay_parent, validation_code_hash).await {
@@ -342,7 +336,7 @@ async fn check_assumption_validation_data<Sender>(
assumption: OccupiedCoreAssumption, assumption: OccupiedCoreAssumption,
) -> AssumptionCheckOutcome ) -> AssumptionCheckOutcome
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
let validation_data = { let validation_data = {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -386,7 +380,7 @@ async fn find_assumed_validation_data<Sender>(
descriptor: &CandidateDescriptor, descriptor: &CandidateDescriptor,
) -> AssumptionCheckOutcome ) -> AssumptionCheckOutcome
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
// The candidate descriptor has a `persisted_validation_data_hash` which corresponds to // The candidate descriptor has a `persisted_validation_data_hash` which corresponds to
// one of up to two possible values that we can derive from the state of the // one of up to two possible values that we can derive from the state of the
@@ -421,7 +415,7 @@ pub async fn find_validation_data<Sender>(
descriptor: &CandidateDescriptor, descriptor: &CandidateDescriptor,
) -> Result<Option<(PersistedValidationData, ValidationCode)>, ValidationFailed> ) -> Result<Option<(PersistedValidationData, ValidationCode)>, ValidationFailed>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
match find_assumed_validation_data(sender, &descriptor).await { match find_assumed_validation_data(sender, &descriptor).await {
AssumptionCheckOutcome::Matches(validation_data, validation_code) => AssumptionCheckOutcome::Matches(validation_data, validation_code) =>
@@ -446,7 +440,7 @@ async fn validate_from_chain_state<Sender>(
metrics: &Metrics, metrics: &Metrics,
) -> Result<ValidationResult, ValidationFailed> ) -> Result<ValidationResult, ValidationFailed>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
let mut new_sender = sender.clone(); let mut new_sender = sender.clone();
let (validation_data, validation_code) = let (validation_data, validation_code) =
+4 -6
View File
@@ -39,7 +39,7 @@ use sp_blockchain::HeaderBackend;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::ChainApiMessage, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, messages::ChainApiMessage, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemError, SubsystemResult, SubsystemError, SubsystemResult,
}; };
use polkadot_primitives::v2::{Block, BlockId}; use polkadot_primitives::v2::{Block, BlockId};
@@ -64,11 +64,10 @@ impl<Client> ChainApiSubsystem<Client> {
} }
} }
impl<Client, Context> overseer::Subsystem<Context, SubsystemError> for ChainApiSubsystem<Client> #[overseer::subsystem(ChainApi, error = SubsystemError, prefix = self::overseer)]
impl<Client, Context> ChainApiSubsystem<Client>
where where
Client: HeaderBackend<Block> + AuxStore + 'static, Client: HeaderBackend<Block> + AuxStore + 'static,
Context: SubsystemContext<Message = ChainApiMessage>,
Context: overseer::SubsystemContext<Message = ChainApiMessage>,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run::<Client, Context>(ctx, self) let future = run::<Client, Context>(ctx, self)
@@ -78,14 +77,13 @@ where
} }
} }
#[overseer::contextbounds(ChainApi, prefix = self::overseer)]
async fn run<Client, Context>( async fn run<Client, Context>(
mut ctx: Context, mut ctx: Context,
subsystem: ChainApiSubsystem<Client>, subsystem: ChainApiSubsystem<Client>,
) -> SubsystemResult<()> ) -> SubsystemResult<()>
where where
Client: HeaderBackend<Block> + AuxStore, Client: HeaderBackend<Block> + AuxStore,
Context: SubsystemContext<Message = ChainApiMessage>,
Context: overseer::SubsystemContext<Message = ChainApiMessage>,
{ {
loop { loop {
match ctx.recv().await? { match ctx.recv().await? {
+23 -27
View File
@@ -20,7 +20,8 @@ use polkadot_node_primitives::BlockWeight;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::ChainApiError, errors::ChainApiError,
messages::{ChainApiMessage, ChainSelectionMessage}, messages::{ChainApiMessage, ChainSelectionMessage},
overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemError, overseer::{self, SubsystemSender},
FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
}; };
use polkadot_node_subsystem_util::database::Database; use polkadot_node_subsystem_util::database::Database;
use polkadot_primitives::v2::{BlockNumber, ConsensusLog, Hash, Header}; use polkadot_primitives::v2::{BlockNumber, ConsensusLog, Hash, Header};
@@ -328,11 +329,8 @@ impl ChainSelectionSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for ChainSelectionSubsystem #[overseer::subsystem(ChainSelection, error = SubsystemError, prefix = self::overseer)]
where impl<Context> ChainSelectionSubsystem {
Context: SubsystemContext<Message = ChainSelectionMessage>,
Context: overseer::SubsystemContext<Message = ChainSelectionMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let backend = db_backend::v1::DbBackend::new( let backend = db_backend::v1::DbBackend::new(
self.db, self.db,
@@ -348,14 +346,13 @@ where
} }
} }
#[overseer::contextbounds(ChainSelection, prefix = self::overseer)]
async fn run<Context, B>( async fn run<Context, B>(
mut ctx: Context, mut ctx: Context,
mut backend: B, mut backend: B,
stagnant_check_interval: StagnantCheckInterval, stagnant_check_interval: StagnantCheckInterval,
clock: Box<dyn Clock + Send + Sync>, clock: Box<dyn Clock + Send + Sync>,
) where ) where
Context: SubsystemContext<Message = ChainSelectionMessage>,
Context: overseer::SubsystemContext<Message = ChainSelectionMessage>,
B: Backend, B: Backend,
{ {
loop { loop {
@@ -363,7 +360,7 @@ async fn run<Context, B>(
match res { match res {
Err(e) => { Err(e) => {
e.trace(); e.trace();
// All errors right now are considered fatal: // All errors are considered fatal right now:
break break
}, },
Ok(()) => { Ok(()) => {
@@ -379,6 +376,7 @@ async fn run<Context, B>(
// //
// A return value of `Ok` indicates that an exit should be made, while non-fatal errors // A return value of `Ok` indicates that an exit should be made, while non-fatal errors
// lead to another call to this function. // lead to another call to this function.
#[overseer::contextbounds(ChainSelection, prefix = self::overseer)]
async fn run_until_error<Context, B>( async fn run_until_error<Context, B>(
ctx: &mut Context, ctx: &mut Context,
backend: &mut B, backend: &mut B,
@@ -386,8 +384,6 @@ async fn run_until_error<Context, B>(
clock: &(dyn Clock + Sync), clock: &(dyn Clock + Sync),
) -> Result<(), Error> ) -> Result<(), Error>
where where
Context: SubsystemContext<Message = ChainSelectionMessage>,
Context: overseer::SubsystemContext<Message = ChainSelectionMessage>,
B: Backend, B: Backend,
{ {
let mut stagnant_check_stream = stagnant_check_interval.timeout_stream(); let mut stagnant_check_stream = stagnant_check_interval.timeout_stream();
@@ -402,7 +398,7 @@ where
FromOverseer::Signal(OverseerSignal::ActiveLeaves(update)) => { FromOverseer::Signal(OverseerSignal::ActiveLeaves(update)) => {
for leaf in update.activated { for leaf in update.activated {
let write_ops = handle_active_leaf( let write_ops = handle_active_leaf(
ctx, ctx.sender(),
&*backend, &*backend,
clock.timestamp_now() + STAGNANT_TIMEOUT, clock.timestamp_now() + STAGNANT_TIMEOUT,
leaf.hash, leaf.hash,
@@ -419,7 +415,7 @@ where
handle_approved_block(backend, hash)? handle_approved_block(backend, hash)?
} }
ChainSelectionMessage::Leaves(tx) => { ChainSelectionMessage::Leaves(tx) => {
let leaves = load_leaves(ctx, &*backend).await?; let leaves = load_leaves(ctx.sender(), &*backend).await?;
let _ = tx.send(leaves); let _ = tx.send(leaves);
} }
ChainSelectionMessage::BestLeafContaining(required, tx) => { ChainSelectionMessage::BestLeafContaining(required, tx) => {
@@ -446,11 +442,11 @@ where
} }
async fn fetch_finalized( async fn fetch_finalized(
ctx: &mut impl SubsystemContext, sender: &mut impl SubsystemSender<ChainApiMessage>,
) -> Result<Option<(Hash, BlockNumber)>, Error> { ) -> Result<Option<(Hash, BlockNumber)>, Error> {
let (number_tx, number_rx) = oneshot::channel(); let (number_tx, number_rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::FinalizedBlockNumber(number_tx)).await; sender.send_message(ChainApiMessage::FinalizedBlockNumber(number_tx)).await;
let number = match number_rx.await? { let number = match number_rx.await? {
Ok(number) => number, Ok(number) => number,
@@ -462,7 +458,7 @@ async fn fetch_finalized(
let (hash_tx, hash_rx) = oneshot::channel(); let (hash_tx, hash_rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::FinalizedBlockHash(number, hash_tx)).await; sender.send_message(ChainApiMessage::FinalizedBlockHash(number, hash_tx)).await;
match hash_rx.await? { match hash_rx.await? {
Err(err) => { Err(err) => {
@@ -478,11 +474,11 @@ async fn fetch_finalized(
} }
async fn fetch_header( async fn fetch_header(
ctx: &mut impl SubsystemContext, sender: &mut impl SubsystemSender<ChainApiMessage>,
hash: Hash, hash: Hash,
) -> Result<Option<Header>, Error> { ) -> Result<Option<Header>, Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockHeader(hash, tx)).await; sender.send_message(ChainApiMessage::BlockHeader(hash, tx)).await;
Ok(rx.await?.unwrap_or_else(|err| { Ok(rx.await?.unwrap_or_else(|err| {
gum::warn!(target: LOG_TARGET, ?hash, ?err, "Missing hash for finalized block number"); gum::warn!(target: LOG_TARGET, ?hash, ?err, "Missing hash for finalized block number");
@@ -491,11 +487,11 @@ async fn fetch_header(
} }
async fn fetch_block_weight( async fn fetch_block_weight(
ctx: &mut impl SubsystemContext, sender: &mut impl overseer::SubsystemSender<ChainApiMessage>,
hash: Hash, hash: Hash,
) -> Result<Option<BlockWeight>, Error> { ) -> Result<Option<BlockWeight>, Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockWeight(hash, tx)).await; sender.send_message(ChainApiMessage::BlockWeight(hash, tx)).await;
let res = rx.await?; let res = rx.await?;
@@ -507,7 +503,7 @@ async fn fetch_block_weight(
// Handle a new active leaf. // Handle a new active leaf.
async fn handle_active_leaf( async fn handle_active_leaf(
ctx: &mut impl SubsystemContext, sender: &mut impl overseer::ChainSelectionSenderTrait,
backend: &impl Backend, backend: &impl Backend,
stagnant_at: Timestamp, stagnant_at: Timestamp,
hash: Hash, hash: Hash,
@@ -519,10 +515,10 @@ async fn handle_active_leaf(
// tree. // tree.
l.saturating_sub(1) l.saturating_sub(1)
}, },
None => fetch_finalized(ctx).await?.map_or(1, |(_, n)| n), None => fetch_finalized(sender).await?.map_or(1, |(_, n)| n),
}; };
let header = match fetch_header(ctx, hash).await? { let header = match fetch_header(sender, hash).await? {
None => { None => {
gum::warn!(target: LOG_TARGET, ?hash, "Missing header for new head"); gum::warn!(target: LOG_TARGET, ?hash, "Missing header for new head");
return Ok(Vec::new()) return Ok(Vec::new())
@@ -531,7 +527,7 @@ async fn handle_active_leaf(
}; };
let new_blocks = polkadot_node_subsystem_util::determine_new_blocks( let new_blocks = polkadot_node_subsystem_util::determine_new_blocks(
ctx.sender(), sender,
|h| backend.load_block_entry(h).map(|b| b.is_some()), |h| backend.load_block_entry(h).map(|b| b.is_some()),
hash, hash,
&header, &header,
@@ -544,7 +540,7 @@ async fn handle_active_leaf(
// determine_new_blocks gives blocks in descending order. // determine_new_blocks gives blocks in descending order.
// for this, we want ascending order. // for this, we want ascending order.
for (hash, header) in new_blocks.into_iter().rev() { for (hash, header) in new_blocks.into_iter().rev() {
let weight = match fetch_block_weight(ctx, hash).await? { let weight = match fetch_block_weight(sender, hash).await? {
None => { None => {
gum::warn!( gum::warn!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -654,13 +650,13 @@ fn detect_stagnant(backend: &mut impl Backend, now: Timestamp) -> Result<(), Err
// Load the leaves from the backend. If there are no leaves, then return // Load the leaves from the backend. If there are no leaves, then return
// the finalized block. // the finalized block.
async fn load_leaves( async fn load_leaves(
ctx: &mut impl SubsystemContext, sender: &mut impl overseer::SubsystemSender<ChainApiMessage>,
backend: &impl Backend, backend: &impl Backend,
) -> Result<Vec<Hash>, Error> { ) -> Result<Vec<Hash>, Error> {
let leaves: Vec<_> = backend.load_leaves()?.into_hashes_descending().collect(); let leaves: Vec<_> = backend.load_leaves()?.into_hashes_descending().collect();
if leaves.is_empty() { if leaves.is_empty() {
Ok(fetch_finalized(ctx).await?.map_or(Vec::new(), |(h, _)| vec![h])) Ok(fetch_finalized(sender).await?.map_or(Vec::new(), |(h, _)| vec![h]))
} else { } else {
Ok(leaves) Ok(leaves)
} }
@@ -34,7 +34,7 @@ use polkadot_node_subsystem::{
BlockDescription, DisputeCoordinatorMessage, DisputeDistributionMessage, BlockDescription, DisputeCoordinatorMessage, DisputeDistributionMessage,
ImportStatementsResult, ImportStatementsResult,
}, },
overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SubsystemContext, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal,
}; };
use polkadot_node_subsystem_util::rolling_session_window::{ use polkadot_node_subsystem_util::rolling_session_window::{
RollingSessionWindow, SessionWindowUpdate, SessionsUnavailable, RollingSessionWindow, SessionWindowUpdate, SessionsUnavailable,
@@ -83,6 +83,7 @@ pub struct Initialized {
error: Option<SessionsUnavailable>, error: Option<SessionsUnavailable>,
} }
#[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
impl Initialized { impl Initialized {
/// Make initialized subsystem, ready to `run`. /// Make initialized subsystem, ready to `run`.
pub fn new( pub fn new(
@@ -123,8 +124,6 @@ impl Initialized {
clock: Box<dyn Clock>, clock: Box<dyn Clock>,
) -> FatalResult<()> ) -> FatalResult<()>
where where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
B: Backend, B: Backend,
{ {
loop { loop {
@@ -161,8 +160,6 @@ impl Initialized {
clock: &dyn Clock, clock: &dyn Clock,
) -> Result<()> ) -> Result<()>
where where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
B: Backend, B: Backend,
{ {
for (priority, request) in participations.drain(..) { for (priority, request) in participations.drain(..) {
@@ -253,10 +250,9 @@ impl Initialized {
} }
} }
async fn process_active_leaves_update( async fn process_active_leaves_update<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = DisputeCoordinatorMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = DisputeCoordinatorMessage>),
overlay_db: &mut OverlayedBackend<'_, impl Backend>, overlay_db: &mut OverlayedBackend<'_, impl Backend>,
update: ActiveLeavesUpdate, update: ActiveLeavesUpdate,
now: u64, now: u64,
@@ -268,7 +264,7 @@ impl Initialized {
if let Some(new_leaf) = update.activated { if let Some(new_leaf) = update.activated {
match self match self
.rolling_session_window .rolling_session_window
.cache_session_info_for_head(ctx, new_leaf.hash) .cache_session_info_for_head(ctx.sender(), new_leaf.hash)
.await .await
{ {
Err(e) => { Err(e) => {
@@ -318,10 +314,9 @@ impl Initialized {
/// Scrapes on-chain votes (backing votes and concluded disputes) for a active leaf of the /// Scrapes on-chain votes (backing votes and concluded disputes) for a active leaf of the
/// relay chain. /// relay chain.
async fn process_on_chain_votes( async fn process_on_chain_votes<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = DisputeCoordinatorMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = DisputeCoordinatorMessage>),
overlay_db: &mut OverlayedBackend<'_, impl Backend>, overlay_db: &mut OverlayedBackend<'_, impl Backend>,
votes: ScrapedOnChainVotes, votes: ScrapedOnChainVotes,
now: u64, now: u64,
@@ -497,9 +492,9 @@ impl Initialized {
Ok(()) Ok(())
} }
async fn handle_incoming( async fn handle_incoming<Context>(
&mut self, &mut self,
ctx: &mut impl SubsystemContext, ctx: &mut Context,
overlay_db: &mut OverlayedBackend<'_, impl Backend>, overlay_db: &mut OverlayedBackend<'_, impl Backend>,
message: DisputeCoordinatorMessage, message: DisputeCoordinatorMessage,
now: Timestamp, now: Timestamp,
@@ -634,9 +629,9 @@ impl Initialized {
Ok(()) Ok(())
} }
async fn handle_import_statements( async fn handle_import_statements<Context>(
&mut self, &mut self,
ctx: &mut impl SubsystemContext, ctx: &mut Context,
overlay_db: &mut OverlayedBackend<'_, impl Backend>, overlay_db: &mut OverlayedBackend<'_, impl Backend>,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
candidate_receipt: MaybeCandidateReceipt, candidate_receipt: MaybeCandidateReceipt,
@@ -923,9 +918,9 @@ impl Initialized {
Ok(ImportStatementsResult::ValidImport) Ok(ImportStatementsResult::ValidImport)
} }
async fn issue_local_statement( async fn issue_local_statement<Context>(
&mut self, &mut self,
ctx: &mut impl SubsystemContext, ctx: &mut Context,
overlay_db: &mut OverlayedBackend<'_, impl Backend>, overlay_db: &mut OverlayedBackend<'_, impl Backend>,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
candidate_receipt: CandidateReceipt, candidate_receipt: CandidateReceipt,
@@ -1054,10 +1049,10 @@ enum MuxedMessage {
Participation(participation::WorkerMessage), Participation(participation::WorkerMessage),
} }
#[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
impl MuxedMessage { impl MuxedMessage {
async fn receive( async fn receive<Context>(
ctx: &mut (impl SubsystemContext<Message = DisputeCoordinatorMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = DisputeCoordinatorMessage>),
from_sender: &mut participation::WorkerMessageReceiver, from_sender: &mut participation::WorkerMessageReceiver,
) -> FatalResult<Self> { ) -> FatalResult<Self> {
// We are only fusing here to make `select` happy, in reality we will quit if the stream // We are only fusing here to make `select` happy, in reality we will quit if the stream
@@ -32,8 +32,7 @@ use sc_keystore::LocalKeystore;
use polkadot_node_primitives::{CandidateVotes, DISPUTE_WINDOW}; use polkadot_node_primitives::{CandidateVotes, DISPUTE_WINDOW};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::DisputeCoordinatorMessage, overseer, ActivatedLeaf, FromOverseer, OverseerSignal, overseer, ActivatedLeaf, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
SpawnedSubsystem, SubsystemContext, SubsystemError,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
database::Database, rolling_session_window::RollingSessionWindow, database::Database, rolling_session_window::RollingSessionWindow,
@@ -124,11 +123,8 @@ impl Config {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for DisputeCoordinatorSubsystem #[overseer::subsystem(DisputeCoordinator, error=SubsystemError, prefix=self::overseer)]
where impl<Context: Send> DisputeCoordinatorSubsystem {
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = async { let future = async {
let backend = DbBackend::new(self.store.clone(), self.config.column_config()); let backend = DbBackend::new(self.store.clone(), self.config.column_config());
@@ -142,6 +138,7 @@ where
} }
} }
#[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
impl DisputeCoordinatorSubsystem { impl DisputeCoordinatorSubsystem {
/// Create a new instance of the subsystem. /// Create a new instance of the subsystem.
pub fn new( pub fn new(
@@ -161,8 +158,6 @@ impl DisputeCoordinatorSubsystem {
clock: Box<dyn Clock>, clock: Box<dyn Clock>,
) -> FatalResult<()> ) -> FatalResult<()>
where where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
B: Backend + 'static, B: Backend + 'static,
{ {
let res = self.initialize(&mut ctx, backend, &*clock).await?; let res = self.initialize(&mut ctx, backend, &*clock).await?;
@@ -194,8 +189,6 @@ impl DisputeCoordinatorSubsystem {
)>, )>,
> >
where where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
B: Backend + 'static, B: Backend + 'static,
{ {
loop { loop {
@@ -260,11 +253,7 @@ impl DisputeCoordinatorSubsystem {
Vec<ScrapedOnChainVotes>, Vec<ScrapedOnChainVotes>,
SpamSlots, SpamSlots,
ChainScraper, ChainScraper,
)> )> {
where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
{
// Prune obsolete disputes: // Prune obsolete disputes:
db::v1::note_current_session(overlay_db, rolling_session_window.latest_session())?; db::v1::note_current_session(overlay_db, rolling_session_window.latest_session())?;
@@ -358,17 +347,15 @@ impl DisputeCoordinatorSubsystem {
} }
/// Wait for `ActiveLeavesUpdate` on startup, returns `None` if `Conclude` signal came first. /// Wait for `ActiveLeavesUpdate` on startup, returns `None` if `Conclude` signal came first.
#[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
async fn get_rolling_session_window<Context>( async fn get_rolling_session_window<Context>(
ctx: &mut Context, ctx: &mut Context,
) -> Result<Option<(ActivatedLeaf, RollingSessionWindow)>> ) -> Result<Option<(ActivatedLeaf, RollingSessionWindow)>> {
where if let Some(leaf) = { wait_for_first_leaf(ctx) }.await? {
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>, let sender = ctx.sender().clone();
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
{
if let Some(leaf) = wait_for_first_leaf(ctx).await? {
Ok(Some(( Ok(Some((
leaf.clone(), leaf.clone(),
RollingSessionWindow::new(ctx, DISPUTE_WINDOW, leaf.hash) RollingSessionWindow::new(sender, DISPUTE_WINDOW, leaf.hash)
.await .await
.map_err(JfyiError::RollingSessionWindow)?, .map_err(JfyiError::RollingSessionWindow)?,
))) )))
@@ -378,11 +365,8 @@ where
} }
/// Wait for `ActiveLeavesUpdate`, returns `None` if `Conclude` signal came first. /// Wait for `ActiveLeavesUpdate`, returns `None` if `Conclude` signal came first.
async fn wait_for_first_leaf<Context>(ctx: &mut Context) -> Result<Option<ActivatedLeaf>> #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
where async fn wait_for_first_leaf<Context>(ctx: &mut Context) -> Result<Option<ActivatedLeaf>> {
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
{
loop { loop {
match ctx.recv().await? { match ctx.recv().await? {
FromOverseer::Signal(OverseerSignal::Conclude) => return Ok(None), FromOverseer::Signal(OverseerSignal::Conclude) => return Ok(None),
@@ -28,7 +28,7 @@ use futures_timer::Delay;
use polkadot_node_primitives::{ValidationResult, APPROVAL_EXECUTION_TIMEOUT}; use polkadot_node_primitives::{ValidationResult, APPROVAL_EXECUTION_TIMEOUT};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage, CandidateValidationMessage}, messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage, CandidateValidationMessage},
ActiveLeavesUpdate, RecoveryError, SubsystemContext, SubsystemSender, overseer, ActiveLeavesUpdate, RecoveryError,
}; };
use polkadot_node_subsystem_util::runtime::get_validation_code_by_hash; use polkadot_node_subsystem_util::runtime::get_validation_code_by_hash;
use polkadot_primitives::v2::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex}; use polkadot_primitives::v2::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex};
@@ -123,6 +123,7 @@ impl WorkerMessage {
} }
} }
#[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
impl Participation { impl Participation {
/// Get ready for managing dispute participation requests. /// Get ready for managing dispute participation requests.
/// ///
@@ -144,7 +145,7 @@ impl Participation {
/// `on_active_leaves_update`, the participation will be launched right away. /// `on_active_leaves_update`, the participation will be launched right away.
/// ///
/// Returns: false, if queues are already full. /// Returns: false, if queues are already full.
pub async fn queue_participation<Context: SubsystemContext>( pub async fn queue_participation<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
priority: ParticipationPriority, priority: ParticipationPriority,
@@ -174,7 +175,7 @@ impl Participation {
/// ///
/// Returns: The received `ParticipationStatement` or a fatal error, in case /// Returns: The received `ParticipationStatement` or a fatal error, in case
/// something went wrong when dequeuing more requests (tasks could not be spawned). /// something went wrong when dequeuing more requests (tasks could not be spawned).
pub async fn get_participation_result<Context: SubsystemContext>( pub async fn get_participation_result<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
msg: WorkerMessage, msg: WorkerMessage,
@@ -190,7 +191,7 @@ impl Participation {
/// ///
/// Make sure we to dequeue participations if that became possible and update most recent /// Make sure we to dequeue participations if that became possible and update most recent
/// block. /// block.
pub async fn process_active_leaves_update<Context: SubsystemContext>( pub async fn process_active_leaves_update<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
update: &ActiveLeavesUpdate, update: &ActiveLeavesUpdate,
@@ -212,7 +213,8 @@ impl Participation {
} }
/// Dequeue until `MAX_PARALLEL_PARTICIPATIONS` is reached. /// Dequeue until `MAX_PARALLEL_PARTICIPATIONS` is reached.
async fn dequeue_until_capacity<Context: SubsystemContext>(
async fn dequeue_until_capacity<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
recent_head: Hash, recent_head: Hash,
@@ -228,7 +230,7 @@ impl Participation {
} }
/// Fork a participation task in the background. /// Fork a participation task in the background.
fn fork_participation<Context: SubsystemContext>( fn fork_participation<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
req: ParticipationRequest, req: ParticipationRequest,
@@ -248,7 +250,7 @@ impl Participation {
async fn participate( async fn participate(
mut result_sender: WorkerMessageSender, mut result_sender: WorkerMessageSender,
mut sender: impl SubsystemSender, mut sender: impl overseer::DisputeCoordinatorSenderTrait,
block_hash: Hash, block_hash: Hash,
req: ParticipationRequest, req: ParticipationRequest,
) { ) {
@@ -259,15 +261,12 @@ async fn participate(
// available data // available data
let (recover_available_data_tx, recover_available_data_rx) = oneshot::channel(); let (recover_available_data_tx, recover_available_data_rx) = oneshot::channel();
sender sender
.send_message( .send_message(AvailabilityRecoveryMessage::RecoverAvailableData(
AvailabilityRecoveryMessage::RecoverAvailableData( req.candidate_receipt().clone(),
req.candidate_receipt().clone(), req.session(),
req.session(), None,
None, recover_available_data_tx,
recover_available_data_tx, ))
)
.into(),
)
.await; .await;
let available_data = match recover_available_data_rx.await { let available_data = match recover_available_data_rx.await {
@@ -326,15 +325,12 @@ async fn participate(
// in the dispute // in the dispute
let (store_available_data_tx, store_available_data_rx) = oneshot::channel(); let (store_available_data_tx, store_available_data_rx) = oneshot::channel();
sender sender
.send_message( .send_message(AvailabilityStoreMessage::StoreAvailableData {
AvailabilityStoreMessage::StoreAvailableData { candidate_hash: *req.candidate_hash(),
candidate_hash: *req.candidate_hash(), n_validators: req.n_validators() as u32,
n_validators: req.n_validators() as u32, available_data: available_data.clone(),
available_data: available_data.clone(), tx: store_available_data_tx,
tx: store_available_data_tx, })
}
.into(),
)
.await; .await;
match store_available_data_rx.await { match store_available_data_rx.await {
@@ -364,17 +360,14 @@ async fn participate(
// same level of leeway. // same level of leeway.
let (validation_tx, validation_rx) = oneshot::channel(); let (validation_tx, validation_rx) = oneshot::channel();
sender sender
.send_message( .send_message(CandidateValidationMessage::ValidateFromExhaustive(
CandidateValidationMessage::ValidateFromExhaustive( available_data.validation_data,
available_data.validation_data, validation_code,
validation_code, req.candidate_receipt().clone(),
req.candidate_receipt().clone(), available_data.pov,
available_data.pov, APPROVAL_EXECUTION_TIMEOUT,
APPROVAL_EXECUTION_TIMEOUT, validation_tx,
validation_tx, ))
)
.into(),
)
.await; .await;
// we cast votes (either positive or negative) depending on the outcome of // we cast votes (either positive or negative) depending on the outcome of
@@ -20,7 +20,7 @@ use std::{
}; };
use futures::channel::oneshot; use futures::channel::oneshot;
use polkadot_node_subsystem::{messages::ChainApiMessage, SubsystemSender}; use polkadot_node_subsystem::{messages::ChainApiMessage, overseer};
use polkadot_primitives::v2::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex}; use polkadot_primitives::v2::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex};
use crate::{ use crate::{
@@ -163,7 +163,7 @@ impl Queues {
/// Returns error in case a queue was found full already. /// Returns error in case a queue was found full already.
pub async fn queue( pub async fn queue(
&mut self, &mut self,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::DisputeCoordinatorSenderTrait,
priority: ParticipationPriority, priority: ParticipationPriority,
req: ParticipationRequest, req: ParticipationRequest,
) -> Result<()> { ) -> Result<()> {
@@ -305,7 +305,7 @@ impl CandidateComparator {
/// `Ok(None)` in case we could not lookup the candidate's relay parent, returns a /// `Ok(None)` in case we could not lookup the candidate's relay parent, returns a
/// `FatalError` in case the chain API call fails with an unexpected error. /// `FatalError` in case the chain API call fails with an unexpected error.
pub async fn new( pub async fn new(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::DisputeCoordinatorSenderTrait,
candidate: &CandidateReceipt, candidate: &CandidateReceipt,
) -> FatalResult<Option<Self>> { ) -> FatalResult<Option<Self>> {
let candidate_hash = candidate.hash(); let candidate_hash = candidate.hash();
@@ -350,11 +350,11 @@ impl Ord for CandidateComparator {
} }
async fn get_block_number( async fn get_block_number(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::DisputeCoordinatorSenderTrait,
relay_parent: Hash, relay_parent: Hash,
) -> FatalResult<Option<BlockNumber>> { ) -> FatalResult<Option<BlockNumber>> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender.send_message(ChainApiMessage::BlockNumber(relay_parent, tx).into()).await; sender.send_message(ChainApiMessage::BlockNumber(relay_parent, tx)).await;
rx.await rx.await
.map_err(|_| FatalError::ChainApiSenderDropped)? .map_err(|_| FatalError::ChainApiSenderDropped)?
.map_err(FatalError::ChainApiAncestors) .map_err(FatalError::ChainApiAncestors)
@@ -53,16 +53,15 @@ pub fn make_our_subsystem_context<S>(
make_subsystem_context(spawn) make_subsystem_context(spawn)
} }
async fn participate( #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
ctx: &mut impl SubsystemContext, async fn participate<Context>(ctx: &mut Context, participation: &mut Participation) -> Result<()> {
participation: &mut Participation,
) -> Result<()> {
let commitments = CandidateCommitments::default(); let commitments = CandidateCommitments::default();
participate_with_commitments_hash(ctx, participation, commitments.hash()).await participate_with_commitments_hash(ctx, participation, commitments.hash()).await
} }
async fn participate_with_commitments_hash( #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
ctx: &mut impl SubsystemContext, async fn participate_with_commitments_hash<Context>(
ctx: &mut Context,
participation: &mut Participation, participation: &mut Participation,
commitments_hash: Hash, commitments_hash: Hash,
) -> Result<()> { ) -> Result<()> {
@@ -81,8 +80,9 @@ async fn participate_with_commitments_hash(
.await .await
} }
async fn activate_leaf( #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)]
ctx: &mut impl SubsystemContext, async fn activate_leaf<Context>(
ctx: &mut Context,
participation: &mut Participation, participation: &mut Participation,
block_number: BlockNumber, block_number: BlockNumber,
) -> FatalResult<()> { ) -> FatalResult<()> {
@@ -21,7 +21,8 @@ use lru::LruCache;
use polkadot_node_primitives::MAX_FINALITY_LAG; use polkadot_node_primitives::MAX_FINALITY_LAG;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::ChainApiMessage, ActivatedLeaf, ActiveLeavesUpdate, ChainApiError, SubsystemSender, messages::ChainApiMessage, overseer, ActivatedLeaf, ActiveLeavesUpdate, ChainApiError,
SubsystemSender,
}; };
use polkadot_node_subsystem_util::runtime::{get_candidate_events, get_on_chain_votes}; use polkadot_node_subsystem_util::runtime::{get_candidate_events, get_on_chain_votes};
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
@@ -81,10 +82,13 @@ impl ChainScraper {
/// Create a properly initialized `OrderingProvider`. /// Create a properly initialized `OrderingProvider`.
/// ///
/// Returns: `Self` and any scraped votes. /// Returns: `Self` and any scraped votes.
pub async fn new<Sender: SubsystemSender>( pub async fn new<Sender>(
sender: &mut Sender, sender: &mut Sender,
initial_head: ActivatedLeaf, initial_head: ActivatedLeaf,
) -> Result<(Self, Vec<ScrapedOnChainVotes>)> { ) -> Result<(Self, Vec<ScrapedOnChainVotes>)>
where
Sender: overseer::DisputeCoordinatorSenderTrait,
{
let mut s = Self { let mut s = Self {
included_candidates: HashSet::new(), included_candidates: HashSet::new(),
candidates_by_block_number: BTreeMap::new(), candidates_by_block_number: BTreeMap::new(),
@@ -106,11 +110,14 @@ impl ChainScraper {
/// and updates current heads, so we can query candidates for all non finalized blocks. /// and updates current heads, so we can query candidates for all non finalized blocks.
/// ///
/// Returns: On chain vote for the leaf and any ancestors we might not yet have seen. /// Returns: On chain vote for the leaf and any ancestors we might not yet have seen.
pub async fn process_active_leaves_update<Sender: SubsystemSender>( pub async fn process_active_leaves_update<Sender>(
&mut self, &mut self,
sender: &mut Sender, sender: &mut Sender,
update: &ActiveLeavesUpdate, update: &ActiveLeavesUpdate,
) -> crate::error::Result<Vec<ScrapedOnChainVotes>> { ) -> crate::error::Result<Vec<ScrapedOnChainVotes>>
where
Sender: overseer::DisputeCoordinatorSenderTrait,
{
let activated = match update.activated.as_ref() { let activated = match update.activated.as_ref() {
Some(activated) => activated, Some(activated) => activated,
None => return Ok(Vec::new()), None => return Ok(Vec::new()),
@@ -160,12 +167,15 @@ impl ChainScraper {
/// Process candidate events of a block. /// Process candidate events of a block.
/// ///
/// Keep track of all included candidates. /// Keep track of all included candidates.
async fn process_candidate_events( async fn process_candidate_events<Sender>(
&mut self, &mut self,
sender: &mut impl SubsystemSender, sender: &mut Sender,
block_number: BlockNumber, block_number: BlockNumber,
block_hash: Hash, block_hash: Hash,
) -> Result<()> { ) -> Result<()>
where
Sender: overseer::DisputeCoordinatorSenderTrait,
{
// Get included events: // Get included events:
let included = let included =
get_candidate_events(sender, block_hash) get_candidate_events(sender, block_hash)
@@ -196,12 +206,15 @@ impl ChainScraper {
/// either at the block present in cache or at the last finalized block. /// either at the block present in cache or at the last finalized block.
/// ///
/// Both `head` and the latest finalized block are **not** included in the result. /// Both `head` and the latest finalized block are **not** included in the result.
async fn get_unfinalized_block_ancestors<Sender: SubsystemSender>( async fn get_unfinalized_block_ancestors<Sender>(
&mut self, &mut self,
sender: &mut Sender, sender: &mut Sender,
mut head: Hash, mut head: Hash,
mut head_number: BlockNumber, mut head_number: BlockNumber,
) -> Result<Vec<Hash>> { ) -> Result<Vec<Hash>>
where
Sender: overseer::DisputeCoordinatorSenderTrait,
{
let target_ancestor = get_finalized_block_number(sender).await?; let target_ancestor = get_finalized_block_number(sender).await?;
let mut ancestors = Vec::new(); let mut ancestors = Vec::new();
@@ -256,26 +269,29 @@ impl ChainScraper {
} }
} }
async fn get_finalized_block_number(sender: &mut impl SubsystemSender) -> FatalResult<BlockNumber> { async fn get_finalized_block_number<Sender>(sender: &mut Sender) -> FatalResult<BlockNumber>
where
Sender: overseer::DisputeCoordinatorSenderTrait,
{
let (number_tx, number_rx) = oneshot::channel(); let (number_tx, number_rx) = oneshot::channel();
send_message_fatal(sender, ChainApiMessage::FinalizedBlockNumber(number_tx), number_rx).await send_message_fatal(sender, ChainApiMessage::FinalizedBlockNumber(number_tx), number_rx).await
} }
async fn get_block_ancestors( async fn get_block_ancestors<Sender>(
sender: &mut impl SubsystemSender, sender: &mut Sender,
head: Hash, head: Hash,
num_ancestors: BlockNumber, num_ancestors: BlockNumber,
) -> FatalResult<Vec<Hash>> { ) -> FatalResult<Vec<Hash>>
where
Sender: overseer::DisputeCoordinatorSenderTrait,
{
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(ChainApiMessage::Ancestors {
ChainApiMessage::Ancestors { hash: head,
hash: head, k: num_ancestors as usize,
k: num_ancestors as usize, response_channel: tx,
response_channel: tx, })
}
.into(),
)
.await; .await;
rx.await rx.await
@@ -289,9 +305,9 @@ async fn send_message_fatal<Sender, Response>(
receiver: oneshot::Receiver<std::result::Result<Response, ChainApiError>>, receiver: oneshot::Receiver<std::result::Result<Response, ChainApiError>>,
) -> FatalResult<Response> ) -> FatalResult<Response>
where where
Sender: SubsystemSender, Sender: SubsystemSender<ChainApiMessage>,
{ {
sender.send_message(message.into()).await; sender.send_message(message).await;
receiver receiver
.await .await
+40 -36
View File
@@ -32,7 +32,7 @@ use polkadot_node_subsystem::{
CandidateBackingMessage, ChainApiMessage, DisputeCoordinatorMessage, ProvisionableData, CandidateBackingMessage, ChainApiMessage, DisputeCoordinatorMessage, ProvisionableData,
ProvisionerInherentData, ProvisionerMessage, ProvisionerInherentData, ProvisionerMessage,
}, },
ActivatedLeaf, LeafStatus, PerLeafSpan, SubsystemSender, overseer, ActivatedLeaf, LeafStatus, PerLeafSpan,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
request_availability_cores, request_persisted_validation_data, JobSender, JobSubsystem, request_availability_cores, request_persisted_validation_data, JobSender, JobSubsystem,
@@ -95,8 +95,12 @@ impl InherentAfter {
} }
} }
/// Provisioner run arguments.
#[derive(Debug, Clone, Copy)]
pub struct ProvisionerConfig;
/// A per-relay-parent job for the provisioning subsystem. /// A per-relay-parent job for the provisioning subsystem.
pub struct ProvisionerJob { pub struct ProvisionerJob<Sender> {
leaf: ActivatedLeaf, leaf: ActivatedLeaf,
receiver: mpsc::Receiver<ProvisionerMessage>, receiver: mpsc::Receiver<ProvisionerMessage>,
backed_candidates: Vec<CandidateReceipt>, backed_candidates: Vec<CandidateReceipt>,
@@ -104,14 +108,16 @@ pub struct ProvisionerJob {
metrics: Metrics, metrics: Metrics,
inherent_after: InherentAfter, inherent_after: InherentAfter,
awaiting_inherent: Vec<oneshot::Sender<ProvisionerInherentData>>, awaiting_inherent: Vec<oneshot::Sender<ProvisionerInherentData>>,
_phantom: std::marker::PhantomData<Sender>,
} }
/// Provisioner run arguments. impl<Sender> JobTrait for ProvisionerJob<Sender>
#[derive(Debug, Clone, Copy)] where
pub struct ProvisionerConfig; Sender: overseer::ProvisionerSenderTrait + std::marker::Unpin,
{
impl JobTrait for ProvisionerJob {
type ToJob = ProvisionerMessage; type ToJob = ProvisionerMessage;
type OutgoingMessages = overseer::ProvisionerOutgoingMessages;
type Sender = Sender;
type Error = Error; type Error = Error;
type RunArgs = ProvisionerConfig; type RunArgs = ProvisionerConfig;
type Metrics = Metrics; type Metrics = Metrics;
@@ -121,12 +127,12 @@ impl JobTrait for ProvisionerJob {
/// Run a job for the parent block indicated /// Run a job for the parent block indicated
// //
// this function is in charge of creating and executing the job's main loop // this function is in charge of creating and executing the job's main loop
fn run<S: SubsystemSender>( fn run(
leaf: ActivatedLeaf, leaf: ActivatedLeaf,
_: Self::RunArgs, _: Self::RunArgs,
metrics: Self::Metrics, metrics: Self::Metrics,
receiver: mpsc::Receiver<ProvisionerMessage>, receiver: mpsc::Receiver<ProvisionerMessage>,
mut sender: JobSender<S>, mut sender: JobSender<Sender>,
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> { ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> {
let span = leaf.span.clone(); let span = leaf.span.clone();
async move { async move {
@@ -139,7 +145,10 @@ impl JobTrait for ProvisionerJob {
} }
} }
impl ProvisionerJob { impl<Sender> ProvisionerJob<Sender>
where
Sender: overseer::ProvisionerSenderTrait,
{
fn new( fn new(
leaf: ActivatedLeaf, leaf: ActivatedLeaf,
metrics: Metrics, metrics: Metrics,
@@ -153,14 +162,11 @@ impl ProvisionerJob {
metrics, metrics,
inherent_after: InherentAfter::new_from_now(), inherent_after: InherentAfter::new_from_now(),
awaiting_inherent: Vec::new(), awaiting_inherent: Vec::new(),
_phantom: std::marker::PhantomData::<Sender>::default(),
} }
} }
async fn run_loop( async fn run_loop(mut self, sender: &mut Sender, span: PerLeafSpan) -> Result<(), Error> {
mut self,
sender: &mut impl SubsystemSender,
span: PerLeafSpan,
) -> Result<(), Error> {
loop { loop {
futures::select! { futures::select! {
msg = self.receiver.next() => match msg { msg = self.receiver.next() => match msg {
@@ -197,7 +203,7 @@ impl ProvisionerJob {
async fn send_inherent_data( async fn send_inherent_data(
&mut self, &mut self,
sender: &mut impl SubsystemSender, sender: &mut Sender,
return_senders: Vec<oneshot::Sender<ProvisionerInherentData>>, return_senders: Vec<oneshot::Sender<ProvisionerInherentData>>,
) { ) {
if let Err(err) = send_inherent_data( if let Err(err) = send_inherent_data(
@@ -275,7 +281,7 @@ async fn send_inherent_data(
bitfields: &[SignedAvailabilityBitfield], bitfields: &[SignedAvailabilityBitfield],
candidates: &[CandidateReceipt], candidates: &[CandidateReceipt],
return_senders: Vec<oneshot::Sender<ProvisionerInherentData>>, return_senders: Vec<oneshot::Sender<ProvisionerInherentData>>,
from_job: &mut impl SubsystemSender, from_job: &mut impl overseer::ProvisionerSenderTrait,
metrics: &Metrics, metrics: &Metrics,
) -> Result<(), Error> { ) -> Result<(), Error> {
let availability_cores = request_availability_cores(leaf.hash, from_job) let availability_cores = request_availability_cores(leaf.hash, from_job)
@@ -394,7 +400,7 @@ async fn select_candidates(
bitfields: &[SignedAvailabilityBitfield], bitfields: &[SignedAvailabilityBitfield],
candidates: &[CandidateReceipt], candidates: &[CandidateReceipt],
relay_parent: Hash, relay_parent: Hash,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::ProvisionerSenderTrait,
) -> Result<Vec<BackedCandidate>, Error> { ) -> Result<Vec<BackedCandidate>, Error> {
let block_number = get_block_number_under_construction(relay_parent, sender).await?; let block_number = get_block_number_under_construction(relay_parent, sender).await?;
@@ -472,14 +478,11 @@ async fn select_candidates(
// now get the backed candidates corresponding to these candidate receipts // now get the backed candidates corresponding to these candidate receipts
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(CandidateBackingMessage::GetBackedCandidates(
CandidateBackingMessage::GetBackedCandidates( relay_parent,
relay_parent, selected_candidates.clone(),
selected_candidates.clone(), tx,
tx, ))
)
.into(),
)
.await; .await;
let mut candidates = rx.await.map_err(|err| Error::CanceledBackedCandidates(err))?; let mut candidates = rx.await.map_err(|err| Error::CanceledBackedCandidates(err))?;
@@ -530,10 +533,10 @@ async fn select_candidates(
/// in the event of an invalid `relay_parent`, returns `Ok(0)` /// in the event of an invalid `relay_parent`, returns `Ok(0)`
async fn get_block_number_under_construction( async fn get_block_number_under_construction(
relay_parent: Hash, relay_parent: Hash,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::ProvisionerSenderTrait,
) -> Result<BlockNumber, Error> { ) -> Result<BlockNumber, Error> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender.send_message(ChainApiMessage::BlockNumber(relay_parent, tx).into()).await; sender.send_message(ChainApiMessage::BlockNumber(relay_parent, tx)).await;
match rx.await.map_err(|err| Error::CanceledBlockNumber(err))? { match rx.await.map_err(|err| Error::CanceledBlockNumber(err))? {
Ok(Some(n)) => Ok(n + 1), Ok(Some(n)) => Ok(n + 1),
@@ -591,7 +594,7 @@ enum RequestType {
/// Request open disputes identified by `CandidateHash` and the `SessionIndex`. /// Request open disputes identified by `CandidateHash` and the `SessionIndex`.
async fn request_disputes( async fn request_disputes(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::ProvisionerSenderTrait,
active_or_recent: RequestType, active_or_recent: RequestType,
) -> Vec<(SessionIndex, CandidateHash)> { ) -> Vec<(SessionIndex, CandidateHash)> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -600,7 +603,7 @@ async fn request_disputes(
RequestType::Active => DisputeCoordinatorMessage::ActiveDisputes(tx), RequestType::Active => DisputeCoordinatorMessage::ActiveDisputes(tx),
}; };
// Bounded by block production - `ProvisionerMessage::RequestInherentData`. // Bounded by block production - `ProvisionerMessage::RequestInherentData`.
sender.send_unbounded_message(msg.into()); sender.send_unbounded_message(msg);
let recent_disputes = match rx.await { let recent_disputes = match rx.await {
Ok(r) => r, Ok(r) => r,
@@ -614,14 +617,15 @@ async fn request_disputes(
/// Request the relevant dispute statements for a set of disputes identified by `CandidateHash` and the `SessionIndex`. /// Request the relevant dispute statements for a set of disputes identified by `CandidateHash` and the `SessionIndex`.
async fn request_votes( async fn request_votes(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::ProvisionerSenderTrait,
disputes_to_query: Vec<(SessionIndex, CandidateHash)>, disputes_to_query: Vec<(SessionIndex, CandidateHash)>,
) -> Vec<(SessionIndex, CandidateHash, CandidateVotes)> { ) -> Vec<(SessionIndex, CandidateHash, CandidateVotes)> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// Bounded by block production - `ProvisionerMessage::RequestInherentData`. // Bounded by block production - `ProvisionerMessage::RequestInherentData`.
sender.send_unbounded_message( sender.send_unbounded_message(DisputeCoordinatorMessage::QueryCandidateVotes(
DisputeCoordinatorMessage::QueryCandidateVotes(disputes_to_query, tx).into(), disputes_to_query,
); tx,
));
match rx.await { match rx.await {
Ok(v) => v, Ok(v) => v,
@@ -665,7 +669,7 @@ fn extend_by_random_subset_without_repetition(
const MAX_DISPUTES_FORWARDED_TO_RUNTIME: usize = 1_000; const MAX_DISPUTES_FORWARDED_TO_RUNTIME: usize = 1_000;
async fn select_disputes( async fn select_disputes(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::ProvisionerSenderTrait,
metrics: &metrics::Metrics, metrics: &metrics::Metrics,
_leaf: &ActivatedLeaf, _leaf: &ActivatedLeaf,
) -> Result<MultiDisputeStatementSet, Error> { ) -> Result<MultiDisputeStatementSet, Error> {
@@ -804,4 +808,4 @@ async fn select_disputes(
} }
/// The provisioner subsystem. /// The provisioner subsystem.
pub type ProvisionerSubsystem<Spawner> = JobSubsystem<ProvisionerJob, Spawner>; pub type ProvisionerSubsystem<Spawner, Sender> = JobSubsystem<ProvisionerJob<Sender>, Spawner>;
@@ -15,14 +15,17 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use crate::error::GetOnchainDisputesError; use crate::error::GetOnchainDisputesError;
use polkadot_node_subsystem::SubsystemSender; use polkadot_node_subsystem::overseer;
use polkadot_primitives::v2::{CandidateHash, DisputeState, Hash, SessionIndex}; use polkadot_primitives::v2::{CandidateHash, DisputeState, Hash, SessionIndex};
use std::collections::HashMap; use std::collections::HashMap;
pub async fn get_onchain_disputes( pub async fn get_onchain_disputes<Sender>(
_sender: &mut impl SubsystemSender, _sender: &mut Sender,
_relay_parent: Hash, _relay_parent: Hash,
) -> Result<HashMap<(SessionIndex, CandidateHash), DisputeState>, GetOnchainDisputesError> { ) -> Result<HashMap<(SessionIndex, CandidateHash), DisputeState>, GetOnchainDisputesError>
where
Sender: overseer::ProvisionerSenderTrait,
{
let _onchain = Result::< let _onchain = Result::<
HashMap<(SessionIndex, CandidateHash), DisputeState>, HashMap<(SessionIndex, CandidateHash), DisputeState>,
GetOnchainDisputesError, GetOnchainDisputesError,
@@ -46,8 +49,8 @@ mod staging_impl {
}; };
/// Gets the on-chain disputes at a given block number and returns them as a `HashSet` so that searching in them is cheap. /// Gets the on-chain disputes at a given block number and returns them as a `HashSet` so that searching in them is cheap.
pub async fn get_onchain_disputes( pub async fn get_onchain_disputes<Sender>(
sender: &mut impl SubsystemSender, sender: &mut Sender,
relay_parent: Hash, relay_parent: Hash,
) -> Result<HashMap<(SessionIndex, CandidateHash), DisputeState>, GetOnchainDisputesError> { ) -> Result<HashMap<(SessionIndex, CandidateHash), DisputeState>, GetOnchainDisputesError> {
gum::trace!(target: LOG_TARGET, ?relay_parent, "Fetching on-chain disputes"); gum::trace!(target: LOG_TARGET, ?relay_parent, "Fetching on-chain disputes");
+15 -23
View File
@@ -22,9 +22,9 @@
use futures::{channel::oneshot, future::BoxFuture, prelude::*, stream::FuturesUnordered}; use futures::{channel::oneshot, future::BoxFuture, prelude::*, stream::FuturesUnordered};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{CandidateValidationMessage, PreCheckOutcome, PvfCheckerMessage}, messages::{CandidateValidationMessage, PreCheckOutcome, PvfCheckerMessage, RuntimeApiMessage},
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
SubsystemError, SubsystemResult, SubsystemSender, SubsystemResult, SubsystemSender,
}; };
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
BlockNumber, Hash, PvfCheckStatement, SessionIndex, ValidationCodeHash, ValidatorId, BlockNumber, Hash, PvfCheckStatement, SessionIndex, ValidationCodeHash, ValidatorId,
@@ -60,11 +60,8 @@ impl PvfCheckerSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for PvfCheckerSubsystem #[overseer::subsystem(PvfChecker, error=SubsystemError, prefix = self::overseer)]
where impl<Context> PvfCheckerSubsystem {
Context: SubsystemContext<Message = PvfCheckerMessage>,
Context: overseer::SubsystemContext<Message = PvfCheckerMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
if self.enabled { if self.enabled {
let future = run(ctx, self.keystore, self.metrics) let future = run(ctx, self.keystore, self.metrics)
@@ -123,15 +120,12 @@ struct State {
FuturesUnordered<BoxFuture<'static, Option<(PreCheckOutcome, ValidationCodeHash)>>>, FuturesUnordered<BoxFuture<'static, Option<(PreCheckOutcome, ValidationCodeHash)>>>,
} }
#[overseer::contextbounds(PvfChecker, prefix = self::overseer)]
async fn run<Context>( async fn run<Context>(
mut ctx: Context, mut ctx: Context,
keystore: SyncCryptoStorePtr, keystore: SyncCryptoStorePtr,
metrics: Metrics, metrics: Metrics,
) -> SubsystemResult<()> ) -> SubsystemResult<()> {
where
Context: SubsystemContext<Message = PvfCheckerMessage>,
Context: overseer::SubsystemContext<Message = PvfCheckerMessage>,
{
let mut state = State { let mut state = State {
credentials: None, credentials: None,
recent_block: None, recent_block: None,
@@ -179,7 +173,7 @@ where
/// Handle an incoming PVF pre-check result from the candidate-validation subsystem. /// Handle an incoming PVF pre-check result from the candidate-validation subsystem.
async fn handle_pvf_check( async fn handle_pvf_check(
state: &mut State, state: &mut State,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::PvfCheckerSenderTrait,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
metrics: &Metrics, metrics: &Metrics,
outcome: PreCheckOutcome, outcome: PreCheckOutcome,
@@ -247,7 +241,7 @@ struct Conclude;
async fn handle_from_overseer( async fn handle_from_overseer(
state: &mut State, state: &mut State,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::PvfCheckerSenderTrait,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
metrics: &Metrics, metrics: &Metrics,
from_overseer: FromOverseer<PvfCheckerMessage>, from_overseer: FromOverseer<PvfCheckerMessage>,
@@ -273,7 +267,7 @@ async fn handle_from_overseer(
async fn handle_leaves_update( async fn handle_leaves_update(
state: &mut State, state: &mut State,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::PvfCheckerSenderTrait,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
metrics: &Metrics, metrics: &Metrics,
update: ActiveLeavesUpdate, update: ActiveLeavesUpdate,
@@ -355,7 +349,7 @@ struct ActivationEffect {
/// Returns `None` if the PVF pre-checking runtime API is not supported for the given leaf hash. /// Returns `None` if the PVF pre-checking runtime API is not supported for the given leaf hash.
async fn examine_activation( async fn examine_activation(
state: &mut State, state: &mut State,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::PvfCheckerSenderTrait,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
leaf_hash: Hash, leaf_hash: Hash,
leaf_number: BlockNumber, leaf_number: BlockNumber,
@@ -414,7 +408,7 @@ async fn examine_activation(
/// Checks the active validators for the given leaf. If we have a signing key for one of them, /// Checks the active validators for the given leaf. If we have a signing key for one of them,
/// returns the [`SigningCredentials`]. /// returns the [`SigningCredentials`].
async fn check_signing_credentials( async fn check_signing_credentials(
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
leaf: Hash, leaf: Hash,
) -> Option<SigningCredentials> { ) -> Option<SigningCredentials> {
@@ -443,7 +437,7 @@ async fn check_signing_credentials(
/// ///
/// If the validator already voted for the given code, this function does nothing. /// If the validator already voted for the given code, this function does nothing.
async fn sign_and_submit_pvf_check_statement( async fn sign_and_submit_pvf_check_statement(
sender: &mut impl SubsystemSender, sender: &mut impl overseer::PvfCheckerSenderTrait,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
voted: &mut HashSet<ValidationCodeHash>, voted: &mut HashSet<ValidationCodeHash>,
credentials: &SigningCredentials, credentials: &SigningCredentials,
@@ -535,7 +529,7 @@ async fn sign_and_submit_pvf_check_statement(
/// into the `currently_checking` set. /// into the `currently_checking` set.
async fn initiate_precheck( async fn initiate_precheck(
state: &mut State, state: &mut State,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::PvfCheckerSenderTrait,
relay_parent: Hash, relay_parent: Hash,
validation_code_hash: ValidationCodeHash, validation_code_hash: ValidationCodeHash,
metrics: &Metrics, metrics: &Metrics,
@@ -544,9 +538,7 @@ async fn initiate_precheck(
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(CandidateValidationMessage::PreCheck(relay_parent, validation_code_hash, tx))
CandidateValidationMessage::PreCheck(relay_parent, validation_code_hash, tx).into(),
)
.await; .await;
let timer = metrics.time_pre_check_judgement(); let timer = metrics.time_pre_check_judgement();
@@ -26,7 +26,7 @@ use polkadot_primitives::v2::{
}; };
pub(crate) async fn session_index_for_child( pub(crate) async fn session_index_for_child(
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
relay_parent: Hash, relay_parent: Hash,
) -> Result<SessionIndex, RuntimeRequestError> { ) -> Result<SessionIndex, RuntimeRequestError> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -34,7 +34,7 @@ pub(crate) async fn session_index_for_child(
} }
pub(crate) async fn validators( pub(crate) async fn validators(
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
relay_parent: Hash, relay_parent: Hash,
) -> Result<Vec<ValidatorId>, RuntimeRequestError> { ) -> Result<Vec<ValidatorId>, RuntimeRequestError> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -42,7 +42,7 @@ pub(crate) async fn validators(
} }
pub(crate) async fn submit_pvf_check_statement( pub(crate) async fn submit_pvf_check_statement(
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
relay_parent: Hash, relay_parent: Hash,
stmt: PvfCheckStatement, stmt: PvfCheckStatement,
signature: ValidatorSignature, signature: ValidatorSignature,
@@ -58,7 +58,7 @@ pub(crate) async fn submit_pvf_check_statement(
} }
pub(crate) async fn pvfs_require_precheck( pub(crate) async fn pvfs_require_precheck(
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
relay_parent: Hash, relay_parent: Hash,
) -> Result<Vec<ValidationCodeHash>, RuntimeRequestError> { ) -> Result<Vec<ValidationCodeHash>, RuntimeRequestError> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -73,7 +73,7 @@ pub(crate) enum RuntimeRequestError {
} }
pub(crate) async fn runtime_api_request<T>( pub(crate) async fn runtime_api_request<T>(
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
relay_parent: Hash, relay_parent: Hash,
request: RuntimeApiRequest, request: RuntimeApiRequest,
receiver: oneshot::Receiver<Result<T, RuntimeApiSubsystemError>>, receiver: oneshot::Receiver<Result<T, RuntimeApiSubsystemError>>,
+4 -7
View File
@@ -25,8 +25,7 @@
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::RuntimeApiError, errors::RuntimeApiError,
messages::{RuntimeApiMessage, RuntimeApiRequest as Request}, messages::{RuntimeApiMessage, RuntimeApiRequest as Request},
overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemError, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult,
SubsystemResult,
}; };
use polkadot_primitives::{ use polkadot_primitives::{
runtime_api::ParachainHost, runtime_api::ParachainHost,
@@ -92,12 +91,11 @@ impl<Client> RuntimeApiSubsystem<Client> {
} }
} }
impl<Client, Context> overseer::Subsystem<Context, SubsystemError> for RuntimeApiSubsystem<Client> #[overseer::subsystem(RuntimeApi, error = SubsystemError, prefix = self::overseer)]
impl<Client, Context> RuntimeApiSubsystem<Client>
where where
Client: ProvideRuntimeApi<Block> + Send + 'static + Sync, Client: ProvideRuntimeApi<Block> + Send + 'static + Sync,
Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>, Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Context: SubsystemContext<Message = RuntimeApiMessage>,
Context: overseer::SubsystemContext<Message = RuntimeApiMessage>,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
SpawnedSubsystem { future: run(ctx, self).boxed(), name: "runtime-api-subsystem" } SpawnedSubsystem { future: run(ctx, self).boxed(), name: "runtime-api-subsystem" }
@@ -333,6 +331,7 @@ where
} }
} }
#[overseer::contextbounds(RuntimeApi, prefix = self::overseer)]
async fn run<Client, Context>( async fn run<Client, Context>(
mut ctx: Context, mut ctx: Context,
mut subsystem: RuntimeApiSubsystem<Client>, mut subsystem: RuntimeApiSubsystem<Client>,
@@ -340,8 +339,6 @@ async fn run<Client, Context>(
where where
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static, Client: ProvideRuntimeApi<Block> + Send + Sync + 'static,
Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>, Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Context: SubsystemContext<Message = RuntimeApiMessage>,
Context: overseer::SubsystemContext<Message = RuntimeApiMessage>,
{ {
loop { loop {
select! { select! {
+80 -36
View File
@@ -21,16 +21,18 @@
//! messages on the overseer level. //! messages on the overseer level.
use polkadot_node_subsystem::*; use polkadot_node_subsystem::*;
pub use polkadot_node_subsystem::{messages::AllMessages, overseer, FromOverseer}; pub use polkadot_node_subsystem::{messages, messages::*, overseer, FromOverseer};
use std::{future::Future, pin::Pin}; use std::{future::Future, pin::Pin};
/// Filter incoming and outgoing messages. /// Filter incoming and outgoing messages.
pub trait MessageInterceptor<Sender>: Send + Sync + Clone + 'static pub trait MessageInterceptor<Sender>: Send + Sync + Clone + 'static
where where
Sender: overseer::SubsystemSender<Self::Message> + Clone + 'static, Sender: overseer::SubsystemSender<<Self::Message as overseer::AssociateOutgoing>::OutgoingMessages>
+ Clone
+ 'static,
{ {
/// The message type the original subsystem handles incoming. /// The message type the original subsystem handles incoming.
type Message: Send + 'static; type Message: overseer::AssociateOutgoing + Send + 'static;
/// Filter messages that are to be received by /// Filter messages that are to be received by
/// the subsystem. /// the subsystem.
@@ -46,7 +48,10 @@ where
} }
/// Modify outgoing messages. /// Modify outgoing messages.
fn intercept_outgoing(&self, msg: AllMessages) -> Option<AllMessages> { fn intercept_outgoing(
&self,
msg: <Self::Message as overseer::AssociateOutgoing>::OutgoingMessages,
) -> Option<<Self::Message as overseer::AssociateOutgoing>::OutgoingMessages> {
Some(msg) Some(msg)
} }
} }
@@ -59,13 +64,26 @@ pub struct InterceptedSender<Sender, Fil> {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<Sender, Fil> overseer::SubsystemSender<AllMessages> for InterceptedSender<Sender, Fil> impl<OutgoingMessage, Sender, Fil> overseer::SubsystemSender<OutgoingMessage> for InterceptedSender<Sender, Fil>
where where
Sender: overseer::SubsystemSender<AllMessages> OutgoingMessage: overseer::AssociateOutgoing + Send + 'static,
+ overseer::SubsystemSender<<Fil as MessageInterceptor<Sender>>::Message>, Sender: overseer::SubsystemSender<OutgoingMessage>
+ overseer::SubsystemSender<
<
<Fil as MessageInterceptor<Sender>>::Message as overseer::AssociateOutgoing
>::OutgoingMessages
>,
Fil: MessageInterceptor<Sender>, Fil: MessageInterceptor<Sender>,
<Fil as MessageInterceptor<Sender>>::Message: overseer::AssociateOutgoing,
<
<Fil as MessageInterceptor<Sender>>::Message as overseer::AssociateOutgoing
>::OutgoingMessages:
From<OutgoingMessage>,
{ {
async fn send_message(&mut self, msg: AllMessages) { async fn send_message(&mut self, msg: OutgoingMessage) {
let msg = <
<<Fil as MessageInterceptor<Sender>>::Message as overseer::AssociateOutgoing
>::OutgoingMessages as From<OutgoingMessage>>::from(msg);
if let Some(msg) = self.message_filter.intercept_outgoing(msg) { if let Some(msg) = self.message_filter.intercept_outgoing(msg) {
self.inner.send_message(msg).await; self.inner.send_message(msg).await;
} }
@@ -73,7 +91,7 @@ where
async fn send_messages<T>(&mut self, msgs: T) async fn send_messages<T>(&mut self, msgs: T)
where where
T: IntoIterator<Item = AllMessages> + Send, T: IntoIterator<Item = OutgoingMessage> + Send,
T::IntoIter: Send, T::IntoIter: Send,
{ {
for msg in msgs { for msg in msgs {
@@ -81,7 +99,10 @@ where
} }
} }
fn send_unbounded_message(&mut self, msg: AllMessages) { fn send_unbounded_message(&mut self, msg: OutgoingMessage) {
let msg = <
<<Fil as MessageInterceptor<Sender>>::Message as overseer::AssociateOutgoing
>::OutgoingMessages as From<OutgoingMessage>>::from(msg);
if let Some(msg) = self.message_filter.intercept_outgoing(msg) { if let Some(msg) = self.message_filter.intercept_outgoing(msg) {
self.inner.send_unbounded_message(msg); self.inner.send_unbounded_message(msg);
} }
@@ -91,11 +112,16 @@ where
/// A subsystem context, that filters the outgoing messages. /// A subsystem context, that filters the outgoing messages.
pub struct InterceptedContext<Context, Fil> pub struct InterceptedContext<Context, Fil>
where where
Context: overseer::SubsystemContext + SubsystemContext, Context: overseer::SubsystemContext<Error=SubsystemError, Signal=OverseerSignal>,
Fil: MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>, Fil: MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>,
<Context as overseer::SubsystemContext>::Sender: overseer::SubsystemSender< <Context as overseer::SubsystemContext>::Sender:
<Fil as MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>>::Message, overseer::SubsystemSender<
>, <
<
Fil as MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>
>::Message as overseer::AssociateOutgoing
>::OutgoingMessages,
>,
{ {
inner: Context, inner: Context,
message_filter: Fil, message_filter: Fil,
@@ -104,14 +130,15 @@ where
impl<Context, Fil> InterceptedContext<Context, Fil> impl<Context, Fil> InterceptedContext<Context, Fil>
where where
Context: overseer::SubsystemContext + SubsystemContext, Context: overseer::SubsystemContext<Error=SubsystemError,Signal=OverseerSignal>,
Fil: MessageInterceptor< Fil: MessageInterceptor<
<Context as overseer::SubsystemContext>::Sender, <Context as overseer::SubsystemContext>::Sender,
Message = <Context as overseer::SubsystemContext>::Message, Message = <Context as overseer::SubsystemContext>::Message,
>, >,
<Context as overseer::SubsystemContext>::Message: overseer::AssociateOutgoing,
<Context as overseer::SubsystemContext>::Sender: overseer::SubsystemSender< <Context as overseer::SubsystemContext>::Sender: overseer::SubsystemSender<
<Fil as MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>>::Message, <<Context as overseer::SubsystemContext>::Message as overseer::AssociateOutgoing>::OutgoingMessages
>, >
{ {
pub fn new(mut inner: Context, message_filter: Fil) -> Self { pub fn new(mut inner: Context, message_filter: Fil) -> Self {
let sender = InterceptedSender::<<Context as overseer::SubsystemContext>::Sender, Fil> { let sender = InterceptedSender::<<Context as overseer::SubsystemContext>::Sender, Fil> {
@@ -125,22 +152,27 @@ where
#[async_trait::async_trait] #[async_trait::async_trait]
impl<Context, Fil> overseer::SubsystemContext for InterceptedContext<Context, Fil> impl<Context, Fil> overseer::SubsystemContext for InterceptedContext<Context, Fil>
where where
Context: overseer::SubsystemContext + SubsystemContext, Context: overseer::SubsystemContext<Error=SubsystemError,Signal=OverseerSignal>,
<Context as overseer::SubsystemContext>::Message:
overseer::AssociateOutgoing,
<Context as overseer::SubsystemContext>::Sender:
overseer::SubsystemSender<
<<Context as overseer::SubsystemContext>::Message as overseer::AssociateOutgoing>::OutgoingMessages
>,
InterceptedSender<<Context as overseer::SubsystemContext>::Sender, Fil>:
overseer::SubsystemSender<
<<Context as overseer::SubsystemContext>::Message as overseer::AssociateOutgoing>::OutgoingMessages
>,
Fil: MessageInterceptor< Fil: MessageInterceptor<
<Context as overseer::SubsystemContext>::Sender, <Context as overseer::SubsystemContext>::Sender,
Message = <Context as overseer::SubsystemContext>::Message, Message = <Context as overseer::SubsystemContext>::Message,
>, >,
<Context as overseer::SubsystemContext>::AllMessages:
From<<Context as overseer::SubsystemContext>::Message>,
<Context as overseer::SubsystemContext>::Sender: overseer::SubsystemSender<
<Fil as MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>>::Message,
>,
{ {
type Message = <Context as overseer::SubsystemContext>::Message; type Message = <Context as overseer::SubsystemContext>::Message;
type Sender = InterceptedSender<<Context as overseer::SubsystemContext>::Sender, Fil>; type Sender = InterceptedSender<<Context as overseer::SubsystemContext>::Sender, Fil>;
type Error = <Context as overseer::SubsystemContext>::Error; type Error = SubsystemError;
type AllMessages = <Context as overseer::SubsystemContext>::AllMessages; type OutgoingMessages = <<Context as overseer::SubsystemContext>::Message as overseer::AssociateOutgoing>::OutgoingMessages;
type Signal = <Context as overseer::SubsystemContext>::Signal; type Signal = OverseerSignal;
async fn try_recv(&mut self) -> Result<Option<FromOverseer<Self::Message>>, ()> { async fn try_recv(&mut self) -> Result<Option<FromOverseer<Self::Message>>, ()> {
loop { loop {
@@ -200,16 +232,28 @@ impl<Sub, Interceptor> InterceptedSubsystem<Sub, Interceptor> {
impl<Context, Sub, Interceptor> overseer::Subsystem<Context, SubsystemError> for InterceptedSubsystem<Sub, Interceptor> impl<Context, Sub, Interceptor> overseer::Subsystem<Context, SubsystemError> for InterceptedSubsystem<Sub, Interceptor>
where where
Context: overseer::SubsystemContext + SubsystemContext + Sync + Send, Context:
Sub: overseer::Subsystem<InterceptedContext<Context, Interceptor>, SubsystemError>, overseer::SubsystemContext<Error=SubsystemError,Signal=OverseerSignal> + Sync + Send,
InterceptedContext<Context, Interceptor>: overseer::SubsystemContext + SubsystemContext, InterceptedContext<Context, Interceptor>:
Interceptor: MessageInterceptor< overseer::SubsystemContext<Error=SubsystemError,Signal=OverseerSignal>,
<Context as overseer::SubsystemContext>::Sender, Sub:
Message = <Context as overseer::SubsystemContext>::Message, overseer::Subsystem<InterceptedContext<Context, Interceptor>, SubsystemError>,
>, Interceptor:
<Context as overseer::SubsystemContext>::Sender: overseer::SubsystemSender< MessageInterceptor<
<Interceptor as MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>>::Message, <Context as overseer::SubsystemContext>::Sender,
>, Message = <Context as overseer::SubsystemContext>::Message,
>,
// <Context as overseer::SubsystemContext>::Sender:
// overseer::SubsystemSender<
// <Interceptor as MessageInterceptor<<Context as overseer::SubsystemContext>::Sender>>::Message,
// >,
<Context as overseer::SubsystemContext>::Message:
overseer::AssociateOutgoing,
<Context as overseer::SubsystemContext>::Sender:
overseer::SubsystemSender<
<<Context as overseer::SubsystemContext>::Message as overseer::AssociateOutgoing
>::OutgoingMessages
>,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let ctx = InterceptedContext::new(ctx, self.message_interceptor); let ctx = InterceptedContext::new(ctx, self.message_interceptor);
+6 -8
View File
@@ -19,8 +19,8 @@ use super::*;
use polkadot_node_subsystem_test_helpers::*; use polkadot_node_subsystem_test_helpers::*;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{AllMessages, AvailabilityStoreMessage}, messages::AvailabilityStoreMessage,
overseer::{dummy::DummySubsystem, gen::TimeoutExt, Subsystem}, overseer::{dummy::DummySubsystem, gen::TimeoutExt, Subsystem, AssociateOutgoing},
SubsystemError, SubsystemError,
}; };
@@ -29,8 +29,7 @@ struct BlackHoleInterceptor;
impl<Sender> MessageInterceptor<Sender> for BlackHoleInterceptor impl<Sender> MessageInterceptor<Sender> for BlackHoleInterceptor
where where
Sender: overseer::SubsystemSender<AllMessages> Sender: overseer::AvailabilityStoreSenderTrait
+ overseer::SubsystemSender<AvailabilityStoreMessage>
+ Clone + Clone
+ 'static, + 'static,
{ {
@@ -53,8 +52,7 @@ struct PassInterceptor;
impl<Sender> MessageInterceptor<Sender> for PassInterceptor impl<Sender> MessageInterceptor<Sender> for PassInterceptor
where where
Sender: overseer::SubsystemSender<AllMessages> Sender: overseer::AvailabilityStoreSenderTrait
+ overseer::SubsystemSender<AvailabilityStoreMessage>
+ Clone + Clone
+ 'static, + 'static,
{ {
@@ -68,8 +66,8 @@ async fn overseer_send<T: Into<AllMessages>>(overseer: &mut TestSubsystemContext
fn launch_harness<F, M, Sub, G>(test_gen: G) fn launch_harness<F, M, Sub, G>(test_gen: G)
where where
F: Future<Output = TestSubsystemContextHandle<M>> + Send, F: Future<Output = TestSubsystemContextHandle<M>> + Send,
M: Into<AllMessages> + std::fmt::Debug + Send + 'static, M: AssociateOutgoing + std::fmt::Debug + Send + 'static,
AllMessages: From<M>, // <M as AssociateOutgoing>::OutgoingMessages: From<M>,
Sub: Subsystem<TestSubsystemContext<M, sp_core::testing::TaskExecutor>, SubsystemError>, Sub: Subsystem<TestSubsystemContext<M, sp_core::testing::TaskExecutor>, SubsystemError>,
G: Fn(TestSubsystemContextHandle<M>) -> (F, Sub), G: Fn(TestSubsystemContextHandle<M>) -> (F, Sub),
{ {
+6 -11
View File
@@ -131,11 +131,7 @@ where
subsystem_sender: Sender, subsystem_sender: Sender,
response_sender: oneshot::Sender<Result<ValidationResult, ValidationFailed>>, response_sender: oneshot::Sender<Result<ValidationResult, ValidationFailed>>,
) where ) where
Sender: overseer::SubsystemSender<AllMessages> Sender: overseer::CandidateValidationSenderTrait + Clone + Send + 'static,
+ overseer::SubsystemSender<CandidateValidationMessage>
+ Clone
+ Send
+ 'static,
{ {
let _candidate_descriptor = candidate_descriptor.clone(); let _candidate_descriptor = candidate_descriptor.clone();
let mut subsystem_sender = subsystem_sender.clone(); let mut subsystem_sender = subsystem_sender.clone();
@@ -200,11 +196,7 @@ fn create_validation_response(
impl<Sender, Spawner> MessageInterceptor<Sender> for ReplaceValidationResult<Spawner> impl<Sender, Spawner> MessageInterceptor<Sender> for ReplaceValidationResult<Spawner>
where where
Sender: overseer::SubsystemSender<CandidateValidationMessage> Sender: overseer::CandidateValidationSenderTrait + Clone + Send + 'static,
+ overseer::SubsystemSender<AllMessages>
+ Clone
+ Send
+ 'static,
Spawner: SpawnNamed + Clone + 'static, Spawner: SpawnNamed + Clone + 'static,
{ {
type Message = CandidateValidationMessage; type Message = CandidateValidationMessage;
@@ -336,7 +328,10 @@ where
} }
} }
fn intercept_outgoing(&self, msg: AllMessages) -> Option<AllMessages> { fn intercept_outgoing(
&self,
msg: overseer::CandidateValidationOutgoingMessages,
) -> Option<overseer::CandidateValidationOutgoingMessages> {
Some(msg) Some(msg)
} }
} }
@@ -71,11 +71,7 @@ struct NoteCandidate<Spawner> {
impl<Sender, Spawner> MessageInterceptor<Sender> for NoteCandidate<Spawner> impl<Sender, Spawner> MessageInterceptor<Sender> for NoteCandidate<Spawner>
where where
Sender: overseer::SubsystemSender<AllMessages> Sender: overseer::CandidateBackingSenderTrait + Clone + Send + 'static,
+ overseer::SubsystemSender<CandidateBackingMessage>
+ Clone
+ Send
+ 'static,
Spawner: SpawnNamed + Clone + 'static, Spawner: SpawnNamed + Clone + 'static,
{ {
type Message = CandidateBackingMessage; type Message = CandidateBackingMessage;
@@ -219,20 +215,21 @@ where
} }
} }
fn intercept_outgoing(&self, msg: AllMessages) -> Option<AllMessages> { fn intercept_outgoing(
&self,
msg: overseer::CandidateBackingOutgoingMessages,
) -> Option<overseer::CandidateBackingOutgoingMessages> {
let msg = match msg { let msg = match msg {
AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded( overseer::CandidateBackingOutgoingMessages::CollatorProtocolMessage(
relay_parent, CollatorProtocolMessage::Seconded(relay_parent, statement),
statement, ) => {
)) => {
// `parachain::collator-protocol: received an unexpected `CollationSeconded`: unknown statement statement=...` // `parachain::collator-protocol: received an unexpected `CollationSeconded`: unknown statement statement=...`
// TODO: Fix this error. We get this on colaltors because `malicious backing` creates a candidate that gets backed/included. // TODO: Fix this error. We get this on colaltors because `malicious backing` creates a candidate that gets backed/included.
// It is harmless for test parachain collators, but it will prevent cumulus based collators to make progress // It is harmless for test parachain collators, but it will prevent cumulus based collators to make progress
// as they wait for the relay chain to confirm the seconding of the collation. // as they wait for the relay chain to confirm the seconding of the collation.
AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded( overseer::CandidateBackingOutgoingMessages::CollatorProtocolMessage(
relay_parent, CollatorProtocolMessage::Seconded(relay_parent, statement),
statement, )
))
}, },
msg => msg, msg => msg,
}; };
+1 -1
View File
@@ -41,7 +41,7 @@ pub fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Con
|_logger_builder, _config| {} |_logger_builder, _config| {}
} }
/// This module reexports Prometheus types and defines the [`Metrics`] trait. /// This module reexports Prometheus types and defines the [`Metrics`](metrics::Metrics) trait.
pub mod metrics { pub mod metrics {
/// Reexport Substrate Prometheus types. /// Reexport Substrate Prometheus types.
pub use substrate_prometheus_endpoint as prometheus; pub use substrate_prometheus_endpoint as prometheus;
@@ -34,8 +34,7 @@ use polkadot_node_subsystem::{
ApprovalCheckResult, ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalCheckResult, ApprovalDistributionMessage, ApprovalVotingMessage,
AssignmentCheckResult, NetworkBridgeEvent, NetworkBridgeMessage, AssignmentCheckResult, NetworkBridgeEvent, NetworkBridgeMessage,
}, },
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
SubsystemError,
}; };
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
BlockNumber, CandidateIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, BlockNumber, CandidateIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature,
@@ -321,11 +320,11 @@ enum PendingMessage {
Approval(IndirectSignedApprovalVote), Approval(IndirectSignedApprovalVote),
} }
#[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)]
impl State { impl State {
async fn handle_network_msg( async fn handle_network_msg<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
event: NetworkBridgeEvent<net_protocol::ApprovalDistributionMessage>, event: NetworkBridgeEvent<net_protocol::ApprovalDistributionMessage>,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
@@ -377,10 +376,9 @@ impl State {
} }
} }
async fn handle_new_blocks( async fn handle_new_blocks<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
metas: Vec<BlockApprovalMeta>, metas: Vec<BlockApprovalMeta>,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
@@ -421,11 +419,12 @@ impl State {
); );
{ {
let sender = ctx.sender();
for (peer_id, view) in self.peer_views.iter() { for (peer_id, view) in self.peer_views.iter() {
let intersection = view.iter().filter(|h| new_hashes.contains(h)); let intersection = view.iter().filter(|h| new_hashes.contains(h));
let view_intersection = View::new(intersection.cloned(), view.finalized_number); let view_intersection = View::new(intersection.cloned(), view.finalized_number);
Self::unify_with_peer( Self::unify_with_peer(
ctx, sender,
metrics, metrics,
&mut self.blocks, &mut self.blocks,
&self.topologies, &self.topologies,
@@ -496,10 +495,9 @@ impl State {
self.enable_aggression(ctx, Resend::Yes, metrics).await; self.enable_aggression(ctx, Resend::Yes, metrics).await;
} }
async fn handle_new_session_topology( async fn handle_new_session_topology<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
session: SessionIndex, session: SessionIndex,
topology: SessionGridTopology, topology: SessionGridTopology,
) { ) {
@@ -520,15 +518,16 @@ impl State {
.await; .await;
} }
async fn process_incoming_peer_message( async fn process_incoming_peer_message<Context, R>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
peer_id: PeerId, peer_id: PeerId,
msg: protocol_v1::ApprovalDistributionMessage, msg: protocol_v1::ApprovalDistributionMessage,
rng: &mut (impl CryptoRng + Rng), rng: &mut R,
) { ) where
R: CryptoRng + Rng,
{
match msg { match msg {
protocol_v1::ApprovalDistributionMessage::Assignments(assignments) => { protocol_v1::ApprovalDistributionMessage::Assignments(assignments) => {
gum::trace!( gum::trace!(
@@ -612,15 +611,16 @@ impl State {
// handle a peer view change: requires that the peer is already connected // handle a peer view change: requires that the peer is already connected
// and has an entry in the `PeerData` struct. // and has an entry in the `PeerData` struct.
async fn handle_peer_view_change( async fn handle_peer_view_change<Context, R>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
peer_id: PeerId, peer_id: PeerId,
view: View, view: View,
rng: &mut (impl CryptoRng + Rng), rng: &mut R,
) { ) where
R: CryptoRng + Rng,
{
gum::trace!(target: LOG_TARGET, ?view, "Peer view change"); gum::trace!(target: LOG_TARGET, ?view, "Peer view change");
let finalized_number = view.finalized_number; let finalized_number = view.finalized_number;
let old_view = let old_view =
@@ -646,7 +646,7 @@ impl State {
} }
Self::unify_with_peer( Self::unify_with_peer(
ctx, ctx.sender(),
metrics, metrics,
&mut self.blocks, &mut self.blocks,
&self.topologies, &self.topologies,
@@ -658,10 +658,9 @@ impl State {
.await; .await;
} }
async fn handle_block_finalized( async fn handle_block_finalized<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
finalized_number: BlockNumber, finalized_number: BlockNumber,
) { ) {
@@ -687,16 +686,17 @@ impl State {
self.enable_aggression(ctx, Resend::No, metrics).await; self.enable_aggression(ctx, Resend::No, metrics).await;
} }
async fn import_and_circulate_assignment( async fn import_and_circulate_assignment<Context, R>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
source: MessageSource, source: MessageSource,
assignment: IndirectAssignmentCert, assignment: IndirectAssignmentCert,
claimed_candidate_index: CandidateIndex, claimed_candidate_index: CandidateIndex,
rng: &mut (impl CryptoRng + Rng), rng: &mut R,
) { ) where
R: CryptoRng + Rng,
{
let block_hash = assignment.block_hash.clone(); let block_hash = assignment.block_hash.clone();
let validator_index = assignment.validator; let validator_index = assignment.validator;
@@ -712,7 +712,7 @@ impl State {
"Unexpected assignment", "Unexpected assignment",
); );
if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) { if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) {
modify_reputation(ctx, peer_id, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await;
} }
} }
return return
@@ -737,7 +737,7 @@ impl State {
?message_subject, ?message_subject,
"Duplicate assignment", "Duplicate assignment",
); );
modify_reputation(ctx, peer_id, COST_DUPLICATE_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_DUPLICATE_MESSAGE).await;
} }
return return
} }
@@ -749,13 +749,13 @@ impl State {
?message_subject, ?message_subject,
"Assignment from a peer is out of view", "Assignment from a peer is out of view",
); );
modify_reputation(ctx, peer_id.clone(), COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), peer_id.clone(), COST_UNEXPECTED_MESSAGE).await;
}, },
} }
// if the assignment is known to be valid, reward the peer // if the assignment is known to be valid, reward the peer
if entry.knowledge.contains(&message_subject, message_kind) { if entry.knowledge.contains(&message_subject, message_kind) {
modify_reputation(ctx, peer_id.clone(), BENEFIT_VALID_MESSAGE).await; modify_reputation(ctx.sender(), peer_id.clone(), BENEFIT_VALID_MESSAGE).await;
if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) {
gum::trace!(target: LOG_TARGET, ?peer_id, ?message_subject, "Known assignment"); gum::trace!(target: LOG_TARGET, ?peer_id, ?message_subject, "Known assignment");
peer_knowledge.received.insert(message_subject, message_kind); peer_knowledge.received.insert(message_subject, message_kind);
@@ -791,7 +791,8 @@ impl State {
); );
match result { match result {
AssignmentCheckResult::Accepted => { AssignmentCheckResult::Accepted => {
modify_reputation(ctx, peer_id.clone(), BENEFIT_VALID_MESSAGE_FIRST).await; modify_reputation(ctx.sender(), peer_id.clone(), BENEFIT_VALID_MESSAGE_FIRST)
.await;
entry.knowledge.known_messages.insert(message_subject.clone(), message_kind); entry.knowledge.known_messages.insert(message_subject.clone(), message_kind);
if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) {
peer_knowledge.received.insert(message_subject.clone(), message_kind); peer_knowledge.received.insert(message_subject.clone(), message_kind);
@@ -819,7 +820,8 @@ impl State {
?peer_id, ?peer_id,
"Got an assignment too far in the future", "Got an assignment too far in the future",
); );
modify_reputation(ctx, peer_id, COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE).await; modify_reputation(ctx.sender(), peer_id, COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE)
.await;
return return
}, },
AssignmentCheckResult::Bad(error) => { AssignmentCheckResult::Bad(error) => {
@@ -830,7 +832,7 @@ impl State {
%error, %error,
"Got a bad assignment from peer", "Got a bad assignment from peer",
); );
modify_reputation(ctx, peer_id, COST_INVALID_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_INVALID_MESSAGE).await;
return return
}, },
} }
@@ -946,10 +948,9 @@ impl State {
} }
} }
async fn import_and_circulate_approval( async fn import_and_circulate_approval<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
source: MessageSource, source: MessageSource,
vote: IndirectSignedApprovalVote, vote: IndirectSignedApprovalVote,
@@ -963,7 +964,7 @@ impl State {
_ => { _ => {
if let Some(peer_id) = source.peer_id() { if let Some(peer_id) = source.peer_id() {
if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) { if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) {
modify_reputation(ctx, peer_id, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await;
} }
} }
return return
@@ -982,7 +983,7 @@ impl State {
?message_subject, ?message_subject,
"Unknown approval assignment", "Unknown approval assignment",
); );
modify_reputation(ctx, peer_id, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await;
return return
} }
@@ -999,7 +1000,7 @@ impl State {
"Duplicate approval", "Duplicate approval",
); );
modify_reputation(ctx, peer_id, COST_DUPLICATE_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_DUPLICATE_MESSAGE).await;
} }
return return
} }
@@ -1011,14 +1012,14 @@ impl State {
?message_subject, ?message_subject,
"Approval from a peer is out of view", "Approval from a peer is out of view",
); );
modify_reputation(ctx, peer_id.clone(), COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), peer_id.clone(), COST_UNEXPECTED_MESSAGE).await;
}, },
} }
// if the approval is known to be valid, reward the peer // if the approval is known to be valid, reward the peer
if entry.knowledge.contains(&message_subject, message_kind) { if entry.knowledge.contains(&message_subject, message_kind) {
gum::trace!(target: LOG_TARGET, ?peer_id, ?message_subject, "Known approval"); gum::trace!(target: LOG_TARGET, ?peer_id, ?message_subject, "Known approval");
modify_reputation(ctx, peer_id.clone(), BENEFIT_VALID_MESSAGE).await; modify_reputation(ctx.sender(), peer_id.clone(), BENEFIT_VALID_MESSAGE).await;
if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) {
peer_knowledge.received.insert(message_subject.clone(), message_kind); peer_knowledge.received.insert(message_subject.clone(), message_kind);
} }
@@ -1049,7 +1050,8 @@ impl State {
); );
match result { match result {
ApprovalCheckResult::Accepted => { ApprovalCheckResult::Accepted => {
modify_reputation(ctx, peer_id.clone(), BENEFIT_VALID_MESSAGE_FIRST).await; modify_reputation(ctx.sender(), peer_id.clone(), BENEFIT_VALID_MESSAGE_FIRST)
.await;
entry.knowledge.insert(message_subject.clone(), message_kind); entry.knowledge.insert(message_subject.clone(), message_kind);
if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) {
@@ -1057,7 +1059,7 @@ impl State {
} }
}, },
ApprovalCheckResult::Bad(error) => { ApprovalCheckResult::Bad(error) => {
modify_reputation(ctx, peer_id, COST_INVALID_MESSAGE).await; modify_reputation(ctx.sender(), peer_id, COST_INVALID_MESSAGE).await;
gum::info!( gum::info!(
target: LOG_TARGET, target: LOG_TARGET,
?peer_id, ?peer_id,
@@ -1209,8 +1211,7 @@ impl State {
} }
async fn unify_with_peer( async fn unify_with_peer(
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> sender: &mut impl overseer::ApprovalDistributionSenderTrait,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
metrics: &Metrics, metrics: &Metrics,
entries: &mut HashMap<Hash, BlockEntry>, entries: &mut HashMap<Hash, BlockEntry>,
topologies: &SessionGridTopologies, topologies: &SessionGridTopologies,
@@ -1326,13 +1327,14 @@ impl State {
"Sending assignments to unified peer", "Sending assignments to unified peer",
); );
ctx.send_message(NetworkBridgeMessage::SendValidationMessage( sender
vec![peer_id.clone()], .send_message(NetworkBridgeMessage::SendValidationMessage(
Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( vec![peer_id.clone()],
protocol_v1::ApprovalDistributionMessage::Assignments(assignments_to_send), Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution(
)), protocol_v1::ApprovalDistributionMessage::Assignments(assignments_to_send),
)) )),
.await; ))
.await;
} }
if !approvals_to_send.is_empty() { if !approvals_to_send.is_empty() {
@@ -1343,20 +1345,20 @@ impl State {
"Sending approvals to unified peer", "Sending approvals to unified peer",
); );
ctx.send_message(NetworkBridgeMessage::SendValidationMessage( sender
vec![peer_id], .send_message(NetworkBridgeMessage::SendValidationMessage(
Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( vec![peer_id],
protocol_v1::ApprovalDistributionMessage::Approvals(approvals_to_send), Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution(
)), protocol_v1::ApprovalDistributionMessage::Approvals(approvals_to_send),
)) )),
.await; ))
.await;
} }
} }
async fn enable_aggression( async fn enable_aggression<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
resend: Resend, resend: Resend,
metrics: &Metrics, metrics: &Metrics,
) { ) {
@@ -1457,14 +1459,17 @@ impl State {
// //
// Note that the required routing of a message can be modified even if the // Note that the required routing of a message can be modified even if the
// topology is unknown yet. // topology is unknown yet.
async fn adjust_required_routing_and_propagate( #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> async fn adjust_required_routing_and_propagate<Context, BlockFilter, RoutingModifier>(
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>), ctx: &mut Context,
blocks: &mut HashMap<Hash, BlockEntry>, blocks: &mut HashMap<Hash, BlockEntry>,
topologies: &SessionGridTopologies, topologies: &SessionGridTopologies,
block_filter: impl Fn(&mut BlockEntry) -> bool, block_filter: BlockFilter,
routing_modifier: impl Fn(&mut RequiredRouting, bool, &ValidatorIndex), routing_modifier: RoutingModifier,
) { ) where
BlockFilter: Fn(&mut BlockEntry) -> bool,
RoutingModifier: Fn(&mut RequiredRouting, bool, &ValidatorIndex),
{
let mut peer_assignments = HashMap::new(); let mut peer_assignments = HashMap::new();
let mut peer_approvals = HashMap::new(); let mut peer_approvals = HashMap::new();
@@ -1566,8 +1571,7 @@ async fn adjust_required_routing_and_propagate(
/// Modify the reputation of a peer based on its behavior. /// Modify the reputation of a peer based on its behavior.
async fn modify_reputation( async fn modify_reputation(
ctx: &mut (impl SubsystemContext<Message = ApprovalDistributionMessage> sender: &mut impl overseer::ApprovalDistributionSenderTrait,
+ overseer::SubsystemContext<Message = ApprovalDistributionMessage>),
peer_id: PeerId, peer_id: PeerId,
rep: Rep, rep: Rep,
) { ) {
@@ -1578,20 +1582,17 @@ async fn modify_reputation(
"Reputation change for peer", "Reputation change for peer",
); );
ctx.send_message(NetworkBridgeMessage::ReportPeer(peer_id, rep)).await; sender.send_message(NetworkBridgeMessage::ReportPeer(peer_id, rep)).await;
} }
#[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)]
impl ApprovalDistribution { impl ApprovalDistribution {
/// Create a new instance of the [`ApprovalDistribution`] subsystem. /// Create a new instance of the [`ApprovalDistribution`] subsystem.
pub fn new(metrics: Metrics) -> Self { pub fn new(metrics: Metrics) -> Self {
Self { metrics } Self { metrics }
} }
async fn run<Context>(self, ctx: Context) async fn run<Context>(self, ctx: Context) {
where
Context: SubsystemContext<Message = ApprovalDistributionMessage>,
Context: overseer::SubsystemContext<Message = ApprovalDistributionMessage>,
{
let mut state = State::default(); let mut state = State::default();
// According to the docs of `rand`, this is a ChaCha12 RNG in practice // According to the docs of `rand`, this is a ChaCha12 RNG in practice
@@ -1606,10 +1607,7 @@ impl ApprovalDistribution {
mut ctx: Context, mut ctx: Context,
state: &mut State, state: &mut State,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = ApprovalDistributionMessage>,
Context: overseer::SubsystemContext<Message = ApprovalDistributionMessage>,
{
loop { loop {
let message = match ctx.recv().await { let message = match ctx.recv().await {
Ok(message) => message, Ok(message) => message,
@@ -1644,10 +1642,7 @@ impl ApprovalDistribution {
msg: ApprovalDistributionMessage, msg: ApprovalDistributionMessage,
metrics: &Metrics, metrics: &Metrics,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = ApprovalDistributionMessage>,
Context: overseer::SubsystemContext<Message = ApprovalDistributionMessage>,
{
match msg { match msg {
ApprovalDistributionMessage::NetworkBridgeUpdate(event) => { ApprovalDistributionMessage::NetworkBridgeUpdate(event) => {
state.handle_network_msg(ctx, metrics, event, rng).await; state.handle_network_msg(ctx, metrics, event, rng).await;
@@ -1690,11 +1685,8 @@ impl ApprovalDistribution {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for ApprovalDistribution #[overseer::subsystem(ApprovalDistribution, error=SubsystemError, prefix=self::overseer)]
where impl<Context> ApprovalDistribution {
Context: SubsystemContext<Message = ApprovalDistributionMessage>,
Context: overseer::SubsystemContext<Message = ApprovalDistributionMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = self.run(ctx).map(|_| Ok(())).boxed(); let future = self.run(ctx).map(|_| Ok(())).boxed();
@@ -21,7 +21,7 @@ use sp_keystore::SyncCryptoStorePtr;
use polkadot_node_network_protocol::request_response::{v1, IncomingRequestReceiver}; use polkadot_node_network_protocol::request_response::{v1, IncomingRequestReceiver};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::AvailabilityDistributionMessage, overseer, FromOverseer, OverseerSignal, messages::AvailabilityDistributionMessage, overseer, FromOverseer, OverseerSignal,
SpawnedSubsystem, SubsystemContext, SubsystemError, SpawnedSubsystem, SubsystemError,
}; };
/// Error and [`Result`] type for this subsystem. /// Error and [`Result`] type for this subsystem.
@@ -68,11 +68,8 @@ pub struct IncomingRequestReceivers {
pub chunk_req_receiver: IncomingRequestReceiver<v1::ChunkFetchingRequest>, pub chunk_req_receiver: IncomingRequestReceiver<v1::ChunkFetchingRequest>,
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for AvailabilityDistributionSubsystem #[overseer::subsystem(AvailabilityDistribution, error=SubsystemError, prefix=self::overseer)]
where impl<Context> AvailabilityDistributionSubsystem {
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityDistributionMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = self let future = self
.run(ctx) .run(ctx)
@@ -83,6 +80,7 @@ where
} }
} }
#[overseer::contextbounds(AvailabilityDistribution, prefix = self::overseer)]
impl AvailabilityDistributionSubsystem { impl AvailabilityDistributionSubsystem {
/// Create a new instance of the availability distribution. /// Create a new instance of the availability distribution.
pub fn new( pub fn new(
@@ -95,11 +93,7 @@ impl AvailabilityDistributionSubsystem {
} }
/// Start processing work as passed on from the Overseer. /// Start processing work as passed on from the Overseer.
async fn run<Context>(self, mut ctx: Context) -> std::result::Result<(), FatalError> async fn run<Context>(self, mut ctx: Context) -> std::result::Result<(), FatalError> {
where
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityDistributionMessage>,
{
let Self { mut runtime, recvs, metrics } = self; let Self { mut runtime, recvs, metrics } = self;
let IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver } = recvs; let IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver } = recvs;
@@ -27,7 +27,7 @@ use polkadot_node_primitives::PoV;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{IfDisconnected, NetworkBridgeMessage}, messages::{IfDisconnected, NetworkBridgeMessage},
SubsystemContext, overseer,
}; };
use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_node_subsystem_util::runtime::RuntimeInfo;
use polkadot_primitives::v2::{AuthorityDiscoveryId, CandidateHash, Hash, ValidatorIndex}; use polkadot_primitives::v2::{AuthorityDiscoveryId, CandidateHash, Hash, ValidatorIndex};
@@ -39,6 +39,7 @@ use crate::{
}; };
/// Start background worker for taking care of fetching the requested `PoV` from the network. /// Start background worker for taking care of fetching the requested `PoV` from the network.
#[overseer::contextbounds(AvailabilityDistribution, prefix = self::overseer)]
pub async fn fetch_pov<Context>( pub async fn fetch_pov<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -48,10 +49,7 @@ pub async fn fetch_pov<Context>(
pov_hash: Hash, pov_hash: Hash,
tx: oneshot::Sender<PoV>, tx: oneshot::Sender<PoV>,
metrics: Metrics, metrics: Metrics,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext,
{
let info = &runtime.get_session_info(ctx.sender(), parent).await?.session_info; let info = &runtime.get_session_info(ctx.sender(), parent).await?.session_info;
let authority_id = info let authority_id = info
.discovery_keys .discovery_keys
@@ -30,8 +30,8 @@ use polkadot_node_network_protocol::request_response::{
use polkadot_node_primitives::ErasureChunk; use polkadot_node_primitives::ErasureChunk;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{AllMessages, AvailabilityStoreMessage, IfDisconnected, NetworkBridgeMessage}, messages::{AvailabilityStoreMessage, IfDisconnected, NetworkBridgeMessage},
SubsystemContext, overseer,
}; };
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
AuthorityDiscoveryId, BlakeTwo256, CandidateHash, GroupIndex, Hash, HashT, OccupiedCore, AuthorityDiscoveryId, BlakeTwo256, CandidateHash, GroupIndex, Hash, HashT, OccupiedCore,
@@ -84,7 +84,7 @@ enum FetchedState {
/// Messages sent from `FetchTask`s to be handled/forwarded. /// Messages sent from `FetchTask`s to be handled/forwarded.
pub enum FromFetchTask { pub enum FromFetchTask {
/// Message to other subsystem. /// Message to other subsystem.
Message(AllMessages), Message(overseer::AvailabilityDistributionOutgoingMessages),
/// Concluded with result. /// Concluded with result.
/// ///
@@ -171,14 +171,12 @@ impl FetchTaskConfig {
} }
} }
#[overseer::contextbounds(AvailabilityDistribution, prefix = self::overseer)]
impl FetchTask { impl FetchTask {
/// Start fetching a chunk. /// Start fetching a chunk.
/// ///
/// A task handling the fetching of the configured chunk will be spawned. /// A task handling the fetching of the configured chunk will be spawned.
pub async fn start<Context>(config: FetchTaskConfig, ctx: &mut Context) -> Result<Self> pub async fn start<Context>(config: FetchTaskConfig, ctx: &mut Context) -> Result<Self> {
where
Context: SubsystemContext,
{
let FetchTaskConfig { prepared_running, live_in } = config; let FetchTaskConfig { prepared_running, live_in } = config;
if let Some(running) = prepared_running { if let Some(running) = prepared_running {
@@ -333,9 +331,10 @@ impl RunningTask {
let requests = Requests::ChunkFetchingV1(full_request); let requests = Requests::ChunkFetchingV1(full_request);
self.sender self.sender
.send(FromFetchTask::Message(AllMessages::NetworkBridge( .send(FromFetchTask::Message(
NetworkBridgeMessage::SendRequests(vec![requests], IfDisconnected::ImmediateError), NetworkBridgeMessage::SendRequests(vec![requests], IfDisconnected::ImmediateError)
))) .into(),
))
.await .await
.map_err(|_| TaskError::ShuttingDown)?; .map_err(|_| TaskError::ShuttingDown)?;
@@ -413,13 +412,14 @@ impl RunningTask {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let r = self let r = self
.sender .sender
.send(FromFetchTask::Message(AllMessages::AvailabilityStore( .send(FromFetchTask::Message(
AvailabilityStoreMessage::StoreChunk { AvailabilityStoreMessage::StoreChunk {
candidate_hash: self.request.candidate_hash, candidate_hash: self.request.candidate_hash,
chunk, chunk,
tx, tx,
}, }
))) .into(),
))
.await; .await;
if let Err(err) = r { if let Err(err) = r {
gum::error!(target: LOG_TARGET, err= ?err, "Storing erasure chunk failed, system shutting down?"); gum::error!(target: LOG_TARGET, err= ?err, "Storing erasure chunk failed, system shutting down?");
@@ -227,7 +227,11 @@ impl TestRun {
/// Returns true, if after processing of the given message it would be OK for the stream to /// Returns true, if after processing of the given message it would be OK for the stream to
/// end. /// end.
async fn handle_message(&self, msg: AllMessages) -> bool { async fn handle_message(
&self,
msg: overseer::AvailabilityDistributionOutgoingMessages,
) -> bool {
let msg = AllMessages::from(msg);
match msg { match msg {
AllMessages::NetworkBridge(NetworkBridgeMessage::SendRequests( AllMessages::NetworkBridge(NetworkBridgeMessage::SendRequests(
reqs, reqs,
@@ -33,8 +33,8 @@ use futures::{
}; };
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{AllMessages, ChainApiMessage}, messages::{ChainApiMessage, RuntimeApiMessage},
ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, SubsystemContext, overseer, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus,
}; };
use polkadot_node_subsystem_util::runtime::{get_occupied_cores, RuntimeInfo}; use polkadot_node_subsystem_util::runtime::{get_occupied_cores, RuntimeInfo};
use polkadot_primitives::v2::{CandidateHash, Hash, OccupiedCore, SessionIndex}; use polkadot_primitives::v2::{CandidateHash, Hash, OccupiedCore, SessionIndex};
@@ -78,6 +78,7 @@ pub struct Requester {
metrics: Metrics, metrics: Metrics,
} }
#[overseer::contextbounds(AvailabilityDistribution, prefix = self::overseer)]
impl Requester { impl Requester {
/// How many ancestors of the leaf should we consider along with it. /// How many ancestors of the leaf should we consider along with it.
pub(crate) const LEAF_ANCESTRY_LEN_WITHIN_SESSION: usize = 3; pub(crate) const LEAF_ANCESTRY_LEN_WITHIN_SESSION: usize = 3;
@@ -99,10 +100,7 @@ impl Requester {
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
update: ActiveLeavesUpdate, update: ActiveLeavesUpdate,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext,
{
gum::trace!(target: LOG_TARGET, ?update, "Update fetching heads"); gum::trace!(target: LOG_TARGET, ?update, "Update fetching heads");
let ActiveLeavesUpdate { activated, deactivated } = update; let ActiveLeavesUpdate { activated, deactivated } = update;
// Stale leaves happen after a reversion - we don't want to re-run availability there. // Stale leaves happen after a reversion - we don't want to re-run availability there.
@@ -125,13 +123,11 @@ impl Requester {
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
new_head: ActivatedLeaf, new_head: ActivatedLeaf,
) -> Result<()> ) -> Result<()> {
where let sender = &mut ctx.sender().clone();
Context: SubsystemContext,
{
let ActivatedLeaf { hash: leaf, .. } = new_head; let ActivatedLeaf { hash: leaf, .. } = new_head;
let (leaf_session_index, ancestors_in_session) = get_block_ancestors_in_same_session( let (leaf_session_index, ancestors_in_session) = get_block_ancestors_in_same_session(
ctx, sender,
runtime, runtime,
leaf, leaf,
Self::LEAF_ANCESTRY_LEN_WITHIN_SESSION, Self::LEAF_ANCESTRY_LEN_WITHIN_SESSION,
@@ -139,7 +135,7 @@ impl Requester {
.await?; .await?;
// Also spawn or bump tasks for candidates in ancestry in the same session. // Also spawn or bump tasks for candidates in ancestry in the same session.
for hash in std::iter::once(leaf).chain(ancestors_in_session) { for hash in std::iter::once(leaf).chain(ancestors_in_session) {
let cores = get_occupied_cores(ctx, hash).await?; let cores = get_occupied_cores(sender, hash).await?;
gum::trace!( gum::trace!(
target: LOG_TARGET, target: LOG_TARGET,
occupied_cores = ?cores, occupied_cores = ?cores,
@@ -177,15 +173,12 @@ impl Requester {
/// passed in leaf might be some later block where the candidate is still pending availability. /// passed in leaf might be some later block where the candidate is still pending availability.
async fn add_cores<Context>( async fn add_cores<Context>(
&mut self, &mut self,
ctx: &mut Context, context: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
leaf: Hash, leaf: Hash,
leaf_session_index: SessionIndex, leaf_session_index: SessionIndex,
cores: impl IntoIterator<Item = OccupiedCore>, cores: impl IntoIterator<Item = OccupiedCore>,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext,
{
for core in cores { for core in cores {
match self.fetches.entry(core.candidate_hash) { match self.fetches.entry(core.candidate_hash) {
Entry::Occupied(mut e) => Entry::Occupied(mut e) =>
@@ -200,7 +193,7 @@ impl Requester {
let task_cfg = self let task_cfg = self
.session_cache .session_cache
.with_session_info( .with_session_info(
ctx, context,
runtime, runtime,
// We use leaf here, the relay_parent must be in the same session as the // We use leaf here, the relay_parent must be in the same session as the
// leaf. This is guaranteed by runtime which ensures that cores are cleared // leaf. This is guaranteed by runtime which ensures that cores are cleared
@@ -221,7 +214,7 @@ impl Requester {
}); });
if let Ok(Some(task_cfg)) = task_cfg { if let Ok(Some(task_cfg)) = task_cfg {
e.insert(FetchTask::start(task_cfg, ctx).await?); e.insert(FetchTask::start(task_cfg, context).await?);
} }
// Not a validator, nothing to do. // Not a validator, nothing to do.
}, },
@@ -232,9 +225,9 @@ impl Requester {
} }
impl Stream for Requester { impl Stream for Requester {
type Item = AllMessages; type Item = overseer::AvailabilityDistributionOutgoingMessages;
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<AllMessages>> { fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<Self::Item>> {
loop { loop {
match Pin::new(&mut self.rx).poll_next(ctx) { match Pin::new(&mut self.rx).poll_next(ctx) {
Poll::Ready(Some(FromFetchTask::Message(m))) => return Poll::Ready(Some(m)), Poll::Ready(Some(FromFetchTask::Message(m))) => return Poll::Ready(Some(m)),
@@ -257,26 +250,27 @@ impl Stream for Requester {
/// Requests up to `limit` ancestor hashes of relay parent in the same session. /// Requests up to `limit` ancestor hashes of relay parent in the same session.
/// ///
/// Also returns session index of the `head`. /// Also returns session index of the `head`.
async fn get_block_ancestors_in_same_session<Context>( async fn get_block_ancestors_in_same_session<Sender>(
ctx: &mut Context, sender: &mut Sender,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
head: Hash, head: Hash,
limit: usize, limit: usize,
) -> Result<(SessionIndex, Vec<Hash>)> ) -> Result<(SessionIndex, Vec<Hash>)>
where where
Context: SubsystemContext, Sender:
overseer::SubsystemSender<RuntimeApiMessage> + overseer::SubsystemSender<ChainApiMessage>,
{ {
// The order is parent, grandparent, ... // The order is parent, grandparent, ...
// //
// `limit + 1` since a session index for the last element in ancestry // `limit + 1` since a session index for the last element in ancestry
// is obtained through its parent. It always gets truncated because // is obtained through its parent. It always gets truncated because
// `session_ancestry_len` can only be incremented `ancestors.len() - 1` times. // `session_ancestry_len` can only be incremented `ancestors.len() - 1` times.
let mut ancestors = get_block_ancestors(ctx, head, limit + 1).await?; let mut ancestors = get_block_ancestors(sender, head, limit + 1).await?;
let mut ancestors_iter = ancestors.iter(); let mut ancestors_iter = ancestors.iter();
// `head` is the child of the first block in `ancestors`, request its session index. // `head` is the child of the first block in `ancestors`, request its session index.
let head_session_index = match ancestors_iter.next() { let head_session_index = match ancestors_iter.next() {
Some(parent) => runtime.get_session_index_for_child(ctx.sender(), *parent).await?, Some(parent) => runtime.get_session_index_for_child(sender, *parent).await?,
None => { None => {
// No first element, i.e. empty. // No first element, i.e. empty.
return Ok((0, ancestors)) return Ok((0, ancestors))
@@ -287,7 +281,7 @@ where
// The first parent is skipped. // The first parent is skipped.
for parent in ancestors_iter { for parent in ancestors_iter {
// Parent is the i-th ancestor, request session index for its child -- (i-1)th element. // Parent is the i-th ancestor, request session index for its child -- (i-1)th element.
let session_index = runtime.get_session_index_for_child(ctx.sender(), *parent).await?; let session_index = runtime.get_session_index_for_child(sender, *parent).await?;
if session_index == head_session_index { if session_index == head_session_index {
session_ancestry_len += 1; session_ancestry_len += 1;
} else { } else {
@@ -302,21 +296,22 @@ where
} }
/// Request up to `limit` ancestor hashes of relay parent from the Chain API. /// Request up to `limit` ancestor hashes of relay parent from the Chain API.
async fn get_block_ancestors<Context>( async fn get_block_ancestors<Sender>(
ctx: &mut Context, sender: &mut Sender,
relay_parent: Hash, relay_parent: Hash,
limit: usize, limit: usize,
) -> Result<Vec<Hash>> ) -> Result<Vec<Hash>>
where where
Context: SubsystemContext, Sender: overseer::SubsystemSender<ChainApiMessage>,
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::Ancestors { sender
hash: relay_parent, .send_message(ChainApiMessage::Ancestors {
k: limit, hash: relay_parent,
response_channel: tx, k: limit,
}) response_channel: tx,
.await; })
.await;
let ancestors = rx let ancestors = rx
.await .await
@@ -19,7 +19,7 @@ use std::collections::HashSet;
use lru::LruCache; use lru::LruCache;
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use polkadot_node_subsystem::SubsystemContext; use polkadot_node_subsystem::overseer;
use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_node_subsystem_util::runtime::RuntimeInfo;
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
AuthorityDiscoveryId, GroupIndex, Hash, SessionIndex, ValidatorIndex, AuthorityDiscoveryId, GroupIndex, Hash, SessionIndex, ValidatorIndex,
@@ -79,6 +79,7 @@ pub struct BadValidators {
pub bad_validators: Vec<AuthorityDiscoveryId>, pub bad_validators: Vec<AuthorityDiscoveryId>,
} }
#[overseer::contextbounds(AvailabilityDistribution, prefix = self::overseer)]
impl SessionCache { impl SessionCache {
/// Create a new `SessionCache`. /// Create a new `SessionCache`.
pub fn new() -> Self { pub fn new() -> Self {
@@ -103,7 +104,6 @@ impl SessionCache {
with_info: F, with_info: F,
) -> Result<Option<R>> ) -> Result<Option<R>>
where where
Context: SubsystemContext,
F: FnOnce(&SessionInfo) -> R, F: FnOnce(&SessionInfo) -> R,
{ {
if let Some(o_info) = self.session_info_cache.get(&session_index) { if let Some(o_info) = self.session_info_cache.get(&session_index) {
@@ -178,10 +178,7 @@ impl SessionCache {
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
relay_parent: Hash, relay_parent: Hash,
session_index: SessionIndex, session_index: SessionIndex,
) -> Result<Option<SessionInfo>> ) -> Result<Option<SessionInfo>> {
where
Context: SubsystemContext,
{
let info = runtime let info = runtime
.get_session_info_by_index(ctx.sender(), relay_parent, session_index) .get_session_info_by_index(ctx.sender(), relay_parent, session_index)
.await?; .await?;
@@ -43,7 +43,7 @@ pub async fn run_pov_receiver<Sender>(
mut receiver: IncomingRequestReceiver<v1::PoVFetchingRequest>, mut receiver: IncomingRequestReceiver<v1::PoVFetchingRequest>,
metrics: Metrics, metrics: Metrics,
) where ) where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
loop { loop {
match receiver.recv(|| vec![COST_INVALID_REQUEST]).await.into_nested() { match receiver.recv(|| vec![COST_INVALID_REQUEST]).await.into_nested() {
@@ -71,7 +71,7 @@ pub async fn run_chunk_receiver<Sender>(
mut receiver: IncomingRequestReceiver<v1::ChunkFetchingRequest>, mut receiver: IncomingRequestReceiver<v1::ChunkFetchingRequest>,
metrics: Metrics, metrics: Metrics,
) where ) where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
loop { loop {
match receiver.recv(|| vec![COST_INVALID_REQUEST]).await.into_nested() { match receiver.recv(|| vec![COST_INVALID_REQUEST]).await.into_nested() {
@@ -105,7 +105,7 @@ pub async fn answer_pov_request_log<Sender>(
req: IncomingRequest<v1::PoVFetchingRequest>, req: IncomingRequest<v1::PoVFetchingRequest>,
metrics: &Metrics, metrics: &Metrics,
) where ) where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
let res = answer_pov_request(sender, req).await; let res = answer_pov_request(sender, req).await;
match res { match res {
@@ -130,7 +130,7 @@ pub async fn answer_chunk_request_log<Sender>(
metrics: &Metrics, metrics: &Metrics,
) -> () ) -> ()
where where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
let res = answer_chunk_request(sender, req).await; let res = answer_chunk_request(sender, req).await;
match res { match res {
@@ -154,7 +154,7 @@ pub async fn answer_pov_request<Sender>(
req: IncomingRequest<v1::PoVFetchingRequest>, req: IncomingRequest<v1::PoVFetchingRequest>,
) -> Result<bool> ) -> Result<bool>
where where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
let _span = jaeger::Span::new(req.payload.candidate_hash, "answer-pov-request"); let _span = jaeger::Span::new(req.payload.candidate_hash, "answer-pov-request");
@@ -182,7 +182,7 @@ pub async fn answer_chunk_request<Sender>(
req: IncomingRequest<v1::ChunkFetchingRequest>, req: IncomingRequest<v1::ChunkFetchingRequest>,
) -> Result<bool> ) -> Result<bool>
where where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
let span = jaeger::Span::new(req.payload.candidate_hash, "answer-chunk-request"); let span = jaeger::Span::new(req.payload.candidate_hash, "answer-chunk-request");
@@ -217,7 +217,7 @@ async fn query_chunk<Sender>(
validator_index: ValidatorIndex, validator_index: ValidatorIndex,
) -> std::result::Result<Option<ErasureChunk>, JfyiError> ) -> std::result::Result<Option<ErasureChunk>, JfyiError>
where where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
@@ -245,7 +245,7 @@ async fn query_available_data<Sender>(
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
) -> Result<Option<AvailableData>> ) -> Result<Option<AvailableData>>
where where
Sender: SubsystemSender, Sender: SubsystemSender<AvailabilityStoreMessage>,
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
@@ -51,9 +51,8 @@ use polkadot_node_subsystem::{
errors::RecoveryError, errors::RecoveryError,
jaeger, jaeger,
messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage, NetworkBridgeMessage}, messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage, NetworkBridgeMessage},
overseer::{self, Subsystem}, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemResult,
SubsystemError, SubsystemResult, SubsystemSender,
}; };
use polkadot_node_subsystem_util::request_session_info; use polkadot_node_subsystem_util::request_session_info;
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
@@ -156,8 +155,8 @@ enum Source {
/// A stateful reconstruction of availability data in reference to /// A stateful reconstruction of availability data in reference to
/// a candidate hash. /// a candidate hash.
struct RecoveryTask<S> { struct RecoveryTask<Sender> {
sender: S, sender: Sender,
/// The parameters of the recovery process. /// The parameters of the recovery process.
params: RecoveryParams, params: RecoveryParams,
@@ -177,7 +176,7 @@ impl RequestFromBackers {
async fn run( async fn run(
&mut self, &mut self,
params: &RecoveryParams, params: &RecoveryParams,
sender: &mut impl SubsystemSender, sender: &mut impl overseer::AvailabilityRecoverySenderTrait,
) -> Result<AvailableData, RecoveryError> { ) -> Result<AvailableData, RecoveryError> {
gum::trace!( gum::trace!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -199,13 +198,10 @@ impl RequestFromBackers {
); );
sender sender
.send_message( .send_message(NetworkBridgeMessage::SendRequests(
NetworkBridgeMessage::SendRequests( vec![Requests::AvailableDataFetchingV1(req)],
vec![Requests::AvailableDataFetchingV1(req)], IfDisconnected::ImmediateError,
IfDisconnected::ImmediateError, ))
)
.into(),
)
.await; .await;
match response.await { match response.await {
@@ -298,11 +294,13 @@ impl RequestChunksFromValidators {
) )
} }
async fn launch_parallel_requests( async fn launch_parallel_requests<Sender>(
&mut self, &mut self,
params: &RecoveryParams, params: &RecoveryParams,
sender: &mut impl SubsystemSender, sender: &mut Sender,
) { ) where
Sender: overseer::AvailabilityRecoverySenderTrait,
{
let num_requests = self.get_desired_request_count(params.threshold); let num_requests = self.get_desired_request_count(params.threshold);
let candidate_hash = &params.candidate_hash; let candidate_hash = &params.candidate_hash;
let already_requesting_count = self.requesting_chunks.len(); let already_requesting_count = self.requesting_chunks.len();
@@ -358,9 +356,10 @@ impl RequestChunksFromValidators {
} }
sender sender
.send_message( .send_message(NetworkBridgeMessage::SendRequests(
NetworkBridgeMessage::SendRequests(requests, IfDisconnected::ImmediateError).into(), requests,
) IfDisconnected::ImmediateError,
))
.await; .await;
} }
@@ -483,20 +482,21 @@ impl RequestChunksFromValidators {
} }
} }
async fn run( async fn run<Sender>(
&mut self, &mut self,
params: &RecoveryParams, params: &RecoveryParams,
sender: &mut impl SubsystemSender, sender: &mut Sender,
) -> Result<AvailableData, RecoveryError> { ) -> Result<AvailableData, RecoveryError>
where
Sender: overseer::AvailabilityRecoverySenderTrait,
{
let metrics = &params.metrics; let metrics = &params.metrics;
// First query the store for any chunks we've got. // First query the store for any chunks we've got.
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
sender sender
.send_message( .send_message(AvailabilityStoreMessage::QueryAllChunks(params.candidate_hash, tx))
AvailabilityStoreMessage::QueryAllChunks(params.candidate_hash, tx).into(),
)
.await; .await;
match rx.await { match rx.await {
@@ -646,16 +646,19 @@ fn reconstructed_data_matches_root(
branches.root() == *expected_root branches.root() == *expected_root
} }
impl<S: SubsystemSender> RecoveryTask<S> { impl<Sender> RecoveryTask<Sender>
where
Sender: overseer::AvailabilityRecoverySenderTrait,
{
async fn run(mut self) -> Result<AvailableData, RecoveryError> { async fn run(mut self) -> Result<AvailableData, RecoveryError> {
// First just see if we have the data available locally. // First just see if we have the data available locally.
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.sender self.sender
.send_message( .send_message(AvailabilityStoreMessage::QueryAvailableData(
AvailabilityStoreMessage::QueryAvailableData(self.params.candidate_hash, tx) self.params.candidate_hash,
.into(), tx,
) ))
.await; .await;
match rx.await { match rx.await {
@@ -799,11 +802,8 @@ impl Default for State {
} }
} }
impl<Context> Subsystem<Context, SubsystemError> for AvailabilityRecoverySubsystem #[overseer::subsystem(AvailabilityRecovery, error=SubsystemError, prefix=self::overseer)]
where impl<Context> AvailabilityRecoverySubsystem {
Context: SubsystemContext<Message = AvailabilityRecoveryMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityRecoveryMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = self let future = self
.run(ctx) .run(ctx)
@@ -832,6 +832,7 @@ async fn handle_signal(state: &mut State, signal: OverseerSignal) -> SubsystemRe
} }
/// Machinery around launching recovery tasks into the background. /// Machinery around launching recovery tasks into the background.
#[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)]
async fn launch_recovery_task<Context>( async fn launch_recovery_task<Context>(
state: &mut State, state: &mut State,
ctx: &mut Context, ctx: &mut Context,
@@ -840,11 +841,7 @@ async fn launch_recovery_task<Context>(
backing_group: Option<GroupIndex>, backing_group: Option<GroupIndex>,
response_sender: oneshot::Sender<Result<AvailableData, RecoveryError>>, response_sender: oneshot::Sender<Result<AvailableData, RecoveryError>>,
metrics: &Metrics, metrics: &Metrics,
) -> error::Result<()> ) -> error::Result<()> {
where
Context: SubsystemContext<Message = AvailabilityRecoveryMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityRecoveryMessage>,
{
let candidate_hash = receipt.hash(); let candidate_hash = receipt.hash();
let params = RecoveryParams { let params = RecoveryParams {
@@ -885,6 +882,7 @@ where
} }
/// Handles an availability recovery request. /// Handles an availability recovery request.
#[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)]
async fn handle_recover<Context>( async fn handle_recover<Context>(
state: &mut State, state: &mut State,
ctx: &mut Context, ctx: &mut Context,
@@ -893,11 +891,7 @@ async fn handle_recover<Context>(
backing_group: Option<GroupIndex>, backing_group: Option<GroupIndex>,
response_sender: oneshot::Sender<Result<AvailableData, RecoveryError>>, response_sender: oneshot::Sender<Result<AvailableData, RecoveryError>>,
metrics: &Metrics, metrics: &Metrics,
) -> error::Result<()> ) -> error::Result<()> {
where
Context: SubsystemContext<Message = AvailabilityRecoveryMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityRecoveryMessage>,
{
let candidate_hash = receipt.hash(); let candidate_hash = receipt.hash();
let span = jaeger::Span::new(candidate_hash, "availbility-recovery") let span = jaeger::Span::new(candidate_hash, "availbility-recovery")
@@ -953,14 +947,11 @@ where
} }
/// Queries a chunk from av-store. /// Queries a chunk from av-store.
#[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)]
async fn query_full_data<Context>( async fn query_full_data<Context>(
ctx: &mut Context, ctx: &mut Context,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
) -> error::Result<Option<AvailableData>> ) -> error::Result<Option<AvailableData>> {
where
Context: SubsystemContext<Message = AvailabilityRecoveryMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityRecoveryMessage>,
{
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
ctx.send_message(AvailabilityStoreMessage::QueryAvailableData(candidate_hash, tx)) ctx.send_message(AvailabilityStoreMessage::QueryAvailableData(candidate_hash, tx))
.await; .await;
@@ -968,6 +959,7 @@ where
Ok(rx.await.map_err(error::Error::CanceledQueryFullData)?) Ok(rx.await.map_err(error::Error::CanceledQueryFullData)?)
} }
#[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)]
impl AvailabilityRecoverySubsystem { impl AvailabilityRecoverySubsystem {
/// Create a new instance of `AvailabilityRecoverySubsystem` which starts with a fast path to /// Create a new instance of `AvailabilityRecoverySubsystem` which starts with a fast path to
/// request data from backers. /// request data from backers.
@@ -986,11 +978,7 @@ impl AvailabilityRecoverySubsystem {
Self { fast_path: false, req_receiver, metrics } Self { fast_path: false, req_receiver, metrics }
} }
async fn run<Context>(self, mut ctx: Context) -> SubsystemResult<()> async fn run<Context>(self, mut ctx: Context) -> SubsystemResult<()> {
where
Context: SubsystemContext<Message = AvailabilityRecoveryMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityRecoveryMessage>,
{
let mut state = State::default(); let mut state = State::default();
let Self { fast_path, mut req_receiver, metrics } = self; let Self { fast_path, mut req_receiver, metrics } = self;
@@ -31,7 +31,7 @@ use polkadot_node_network_protocol::{
}; };
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, PerLeafSpan, jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, PerLeafSpan,
SpawnedSubsystem, SubsystemContext, SubsystemError, SubsystemResult, SpawnedSubsystem, SubsystemError, SubsystemResult,
}; };
use polkadot_node_subsystem_util::{self as util}; use polkadot_node_subsystem_util::{self as util};
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
@@ -204,6 +204,7 @@ pub struct BitfieldDistribution {
metrics: Metrics, metrics: Metrics,
} }
#[overseer::contextbounds(BitfieldDistribution, prefix = self::overseer)]
impl BitfieldDistribution { impl BitfieldDistribution {
/// Create a new instance of the `BitfieldDistribution` subsystem. /// Create a new instance of the `BitfieldDistribution` subsystem.
pub fn new(metrics: Metrics) -> Self { pub fn new(metrics: Metrics) -> Self {
@@ -211,11 +212,7 @@ impl BitfieldDistribution {
} }
/// Start processing work as passed on from the Overseer. /// Start processing work as passed on from the Overseer.
async fn run<Context>(self, ctx: Context) async fn run<Context>(self, ctx: Context) {
where
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
Context: overseer::SubsystemContext<Message = BitfieldDistributionMessage>,
{
let mut state = ProtocolState::default(); let mut state = ProtocolState::default();
let mut rng = rand::rngs::StdRng::from_entropy(); let mut rng = rand::rngs::StdRng::from_entropy();
self.run_inner(ctx, &mut state, &mut rng).await self.run_inner(ctx, &mut state, &mut rng).await
@@ -226,10 +223,7 @@ impl BitfieldDistribution {
mut ctx: Context, mut ctx: Context,
state: &mut ProtocolState, state: &mut ProtocolState,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
Context: overseer::SubsystemContext<Message = BitfieldDistributionMessage>,
{
// work: process incoming messages from the overseer and process accordingly. // work: process incoming messages from the overseer and process accordingly.
loop { loop {
@@ -316,17 +310,20 @@ impl BitfieldDistribution {
} }
/// Modify the reputation of a peer based on its behavior. /// Modify the reputation of a peer based on its behavior.
async fn modify_reputation<Context>(ctx: &mut Context, relay_parent: Hash, peer: PeerId, rep: Rep) async fn modify_reputation(
where sender: &mut impl overseer::BitfieldDistributionSenderTrait,
Context: SubsystemContext<Message = BitfieldDistributionMessage>, relay_parent: Hash,
{ peer: PeerId,
rep: Rep,
) {
gum::trace!(target: LOG_TARGET, ?relay_parent, ?rep, %peer, "reputation change"); gum::trace!(target: LOG_TARGET, ?relay_parent, ?rep, %peer, "reputation change");
ctx.send_message(NetworkBridgeMessage::ReportPeer(peer, rep)).await sender.send_message(NetworkBridgeMessage::ReportPeer(peer, rep)).await
} }
/// Distribute a given valid and signature checked bitfield message. /// Distribute a given valid and signature checked bitfield message.
/// ///
/// For this variant the source is this node. /// For this variant the source is this node.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn handle_bitfield_distribution<Context>( async fn handle_bitfield_distribution<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut ProtocolState, state: &mut ProtocolState,
@@ -334,9 +331,7 @@ async fn handle_bitfield_distribution<Context>(
relay_parent: Hash, relay_parent: Hash,
signed_availability: SignedAvailabilityBitfield, signed_availability: SignedAvailabilityBitfield,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let _timer = metrics.time_handle_bitfield_distribution(); let _timer = metrics.time_handle_bitfield_distribution();
// Ignore anything the overseer did not tell this subsystem to work on // Ignore anything the overseer did not tell this subsystem to work on
@@ -389,6 +384,7 @@ async fn handle_bitfield_distribution<Context>(
/// Distribute a given valid and signature checked bitfield message. /// Distribute a given valid and signature checked bitfield message.
/// ///
/// Can be originated by another subsystem or received via network from another peer. /// Can be originated by another subsystem or received via network from another peer.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn relay_message<Context>( async fn relay_message<Context>(
ctx: &mut Context, ctx: &mut Context,
job_data: &mut PerRelayParentData, job_data: &mut PerRelayParentData,
@@ -398,9 +394,7 @@ async fn relay_message<Context>(
message: BitfieldGossipMessage, message: BitfieldGossipMessage,
required_routing: RequiredRouting, required_routing: RequiredRouting,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let relay_parent = message.relay_parent; let relay_parent = message.relay_parent;
let span = job_data.span.child("relay-msg"); let span = job_data.span.child("relay-msg");
@@ -478,6 +472,7 @@ async fn relay_message<Context>(
} }
/// Handle an incoming message from a peer. /// Handle an incoming message from a peer.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn process_incoming_peer_message<Context>( async fn process_incoming_peer_message<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut ProtocolState, state: &mut ProtocolState,
@@ -485,9 +480,7 @@ async fn process_incoming_peer_message<Context>(
origin: PeerId, origin: PeerId,
message: protocol_v1::BitfieldDistributionMessage, message: protocol_v1::BitfieldDistributionMessage,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let protocol_v1::BitfieldDistributionMessage::Bitfield(relay_parent, bitfield) = message; let protocol_v1::BitfieldDistributionMessage::Bitfield(relay_parent, bitfield) = message;
gum::trace!( gum::trace!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -497,7 +490,7 @@ async fn process_incoming_peer_message<Context>(
); );
// we don't care about this, not part of our view. // we don't care about this, not part of our view.
if !state.view.contains(&relay_parent) { if !state.view.contains(&relay_parent) {
modify_reputation(ctx, relay_parent, origin, COST_NOT_IN_VIEW).await; modify_reputation(ctx.sender(), relay_parent, origin, COST_NOT_IN_VIEW).await;
return return
} }
@@ -506,7 +499,7 @@ async fn process_incoming_peer_message<Context>(
let job_data: &mut _ = if let Some(ref mut job_data) = job_data { let job_data: &mut _ = if let Some(ref mut job_data) = job_data {
job_data job_data
} else { } else {
modify_reputation(ctx, relay_parent, origin, COST_NOT_IN_VIEW).await; modify_reputation(ctx.sender(), relay_parent, origin, COST_NOT_IN_VIEW).await;
return return
}; };
@@ -523,7 +516,7 @@ async fn process_incoming_peer_message<Context>(
let validator_set = &job_data.validator_set; let validator_set = &job_data.validator_set;
if validator_set.is_empty() { if validator_set.is_empty() {
gum::trace!(target: LOG_TARGET, ?relay_parent, ?origin, "Validator set is empty",); gum::trace!(target: LOG_TARGET, ?relay_parent, ?origin, "Validator set is empty",);
modify_reputation(ctx, relay_parent, origin, COST_MISSING_PEER_SESSION_KEY).await; modify_reputation(ctx.sender(), relay_parent, origin, COST_MISSING_PEER_SESSION_KEY).await;
return return
} }
@@ -533,7 +526,7 @@ async fn process_incoming_peer_message<Context>(
let validator = if let Some(validator) = validator_set.get(validator_index.0 as usize) { let validator = if let Some(validator) = validator_set.get(validator_index.0 as usize) {
validator.clone() validator.clone()
} else { } else {
modify_reputation(ctx, relay_parent, origin, COST_VALIDATOR_INDEX_INVALID).await; modify_reputation(ctx.sender(), relay_parent, origin, COST_VALIDATOR_INDEX_INVALID).await;
return return
}; };
@@ -546,7 +539,7 @@ async fn process_incoming_peer_message<Context>(
received_set.insert(validator.clone()); received_set.insert(validator.clone());
} else { } else {
gum::trace!(target: LOG_TARGET, ?validator_index, ?origin, "Duplicate message"); gum::trace!(target: LOG_TARGET, ?validator_index, ?origin, "Duplicate message");
modify_reputation(ctx, relay_parent, origin, COST_PEER_DUPLICATE_MESSAGE).await; modify_reputation(ctx.sender(), relay_parent, origin, COST_PEER_DUPLICATE_MESSAGE).await;
return return
}; };
@@ -560,13 +553,13 @@ async fn process_incoming_peer_message<Context>(
"already received a message for validator", "already received a message for validator",
); );
if old_message.signed_availability.as_unchecked() == &bitfield { if old_message.signed_availability.as_unchecked() == &bitfield {
modify_reputation(ctx, relay_parent, origin, BENEFIT_VALID_MESSAGE).await; modify_reputation(ctx.sender(), relay_parent, origin, BENEFIT_VALID_MESSAGE).await;
} }
return return
} }
let signed_availability = match bitfield.try_into_checked(&signing_context, &validator) { let signed_availability = match bitfield.try_into_checked(&signing_context, &validator) {
Err(_) => { Err(_) => {
modify_reputation(ctx, relay_parent, origin, COST_SIGNATURE_INVALID).await; modify_reputation(ctx.sender(), relay_parent, origin, COST_SIGNATURE_INVALID).await;
return return
}, },
Ok(bitfield) => bitfield, Ok(bitfield) => bitfield,
@@ -592,20 +585,19 @@ async fn process_incoming_peer_message<Context>(
) )
.await; .await;
modify_reputation(ctx, relay_parent, origin, BENEFIT_VALID_MESSAGE_FIRST).await modify_reputation(ctx.sender(), relay_parent, origin, BENEFIT_VALID_MESSAGE_FIRST).await
} }
/// Deal with network bridge updates and track what needs to be tracked /// Deal with network bridge updates and track what needs to be tracked
/// which depends on the message type received. /// which depends on the message type received.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn handle_network_msg<Context>( async fn handle_network_msg<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut ProtocolState, state: &mut ProtocolState,
metrics: &Metrics, metrics: &Metrics,
bridge_message: NetworkBridgeEvent<net_protocol::BitfieldDistributionMessage>, bridge_message: NetworkBridgeEvent<net_protocol::BitfieldDistributionMessage>,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let _timer = metrics.time_handle_network_msg(); let _timer = metrics.time_handle_network_msg();
match bridge_message { match bridge_message {
@@ -677,15 +669,14 @@ fn handle_our_view_change(state: &mut ProtocolState, view: OurView) {
// Send the difference between two views which were not sent // Send the difference between two views which were not sent
// to that particular peer. // to that particular peer.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn handle_peer_view_change<Context>( async fn handle_peer_view_change<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut ProtocolState, state: &mut ProtocolState,
origin: PeerId, origin: PeerId,
view: View, view: View,
rng: &mut (impl CryptoRng + Rng), rng: &mut (impl CryptoRng + Rng),
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let added = state let added = state
.peer_views .peer_views
.entry(origin.clone()) .entry(origin.clone())
@@ -736,15 +727,14 @@ async fn handle_peer_view_change<Context>(
} }
/// Send a gossip message and track it in the per relay parent data. /// Send a gossip message and track it in the per relay parent data.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn send_tracked_gossip_message<Context>( async fn send_tracked_gossip_message<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut ProtocolState, state: &mut ProtocolState,
dest: PeerId, dest: PeerId,
validator: ValidatorId, validator: ValidatorId,
message: BitfieldGossipMessage, message: BitfieldGossipMessage,
) where ) {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let job_data = if let Some(job_data) = state.per_relay_parent.get_mut(&message.relay_parent) { let job_data = if let Some(job_data) = state.per_relay_parent.get_mut(&message.relay_parent) {
job_data job_data
} else { } else {
@@ -773,11 +763,8 @@ async fn send_tracked_gossip_message<Context>(
.await; .await;
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for BitfieldDistribution #[overseer::subsystem(BitfieldDistribution, error=SubsystemError, prefix=self::overseer)]
where impl<Context> BitfieldDistribution {
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
Context: overseer::SubsystemContext<Message = BitfieldDistributionMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = self.run(ctx).map(|_| Ok(())).boxed(); let future = self.run(ctx).map(|_| Ok(())).boxed();
@@ -786,13 +773,11 @@ where
} }
/// Query our validator set and signing context for a particular relay parent. /// Query our validator set and signing context for a particular relay parent.
#[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)]
async fn query_basics<Context>( async fn query_basics<Context>(
ctx: &mut Context, ctx: &mut Context,
relay_parent: Hash, relay_parent: Hash,
) -> SubsystemResult<Option<(Vec<ValidatorId>, SigningContext)>> ) -> SubsystemResult<Option<(Vec<ValidatorId>, SigningContext)>> {
where
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
let (validators_tx, validators_rx) = oneshot::channel(); let (validators_tx, validators_rx) = oneshot::channel();
let (session_tx, session_rx) = oneshot::channel(); let (session_tx, session_rx) = oneshot::channel();
+63 -234
View File
@@ -33,17 +33,18 @@ use polkadot_node_network_protocol::{
v1 as protocol_v1, ObservedRole, OurView, PeerId, ProtocolVersion, v1 as protocol_v1, ObservedRole, OurView, PeerId, ProtocolVersion,
UnifiedReputationChange as Rep, Versioned, View, UnifiedReputationChange as Rep, Versioned, View,
}; };
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::{SubsystemError, SubsystemResult}, errors::{SubsystemError, SubsystemResult},
messages::{ messages::{
network_bridge_event::{NewGossipTopology, TopologyPeerInfo}, network_bridge_event::{NewGossipTopology, TopologyPeerInfo},
AllMessages, CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeMessage, ApprovalDistributionMessage, BitfieldDistributionMessage, CollatorProtocolMessage,
GossipSupportMessage, NetworkBridgeEvent, NetworkBridgeMessage,
StatementDistributionMessage,
}, },
overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemSender,
}; };
use polkadot_node_subsystem_util::metrics::{self, prometheus}; use polkadot_overseer::gen::OverseerError;
use polkadot_overseer::gen::{OverseerError, Subsystem};
use polkadot_primitives::v2::{AuthorityDiscoveryId, BlockNumber, Hash, ValidatorIndex}; use polkadot_primitives::v2::{AuthorityDiscoveryId, BlockNumber, Hash, ValidatorIndex};
/// Peer set info for network initialization. /// Peer set info for network initialization.
@@ -67,6 +68,9 @@ use network::{send_message, Network};
use crate::network::get_peer_id_by_authority_id; use crate::network::get_peer_id_by_authority_id;
mod metrics;
use self::metrics::Metrics;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@@ -83,206 +87,6 @@ const EMPTY_VIEW_COST: Rep = Rep::CostMajor("Peer sent us an empty view");
// network bridge log target // network bridge log target
const LOG_TARGET: &'static str = "parachain::network-bridge"; const LOG_TARGET: &'static str = "parachain::network-bridge";
/// Metrics for the network bridge.
#[derive(Clone, Default)]
pub struct Metrics(Option<MetricsInner>);
fn peer_set_label(peer_set: PeerSet, version: ProtocolVersion) -> &'static str {
// Higher level code is meant to protect against this ever happening.
peer_set.get_protocol_name_static(version).unwrap_or("<internal error>")
}
impl Metrics {
fn on_peer_connected(&self, peer_set: PeerSet, version: ProtocolVersion) {
self.0.as_ref().map(|metrics| {
metrics
.connected_events
.with_label_values(&[peer_set_label(peer_set, version)])
.inc()
});
}
fn on_peer_disconnected(&self, peer_set: PeerSet, version: ProtocolVersion) {
self.0.as_ref().map(|metrics| {
metrics
.disconnected_events
.with_label_values(&[peer_set_label(peer_set, version)])
.inc()
});
}
fn note_peer_count(&self, peer_set: PeerSet, version: ProtocolVersion, count: usize) {
self.0.as_ref().map(|metrics| {
metrics
.peer_count
.with_label_values(&[peer_set_label(peer_set, version)])
.set(count as u64)
});
}
fn on_notification_received(&self, peer_set: PeerSet, version: ProtocolVersion, size: usize) {
if let Some(metrics) = self.0.as_ref() {
metrics
.notifications_received
.with_label_values(&[peer_set_label(peer_set, version)])
.inc();
metrics
.bytes_received
.with_label_values(&[peer_set_label(peer_set, version)])
.inc_by(size as u64);
}
}
fn on_notification_sent(
&self,
peer_set: PeerSet,
version: ProtocolVersion,
size: usize,
to_peers: usize,
) {
if let Some(metrics) = self.0.as_ref() {
metrics
.notifications_sent
.with_label_values(&[peer_set_label(peer_set, version)])
.inc_by(to_peers as u64);
metrics
.bytes_sent
.with_label_values(&[peer_set_label(peer_set, version)])
.inc_by((size * to_peers) as u64);
}
}
fn note_desired_peer_count(&self, peer_set: PeerSet, size: usize) {
self.0.as_ref().map(|metrics| {
metrics
.desired_peer_count
.with_label_values(&[peer_set.get_default_protocol_name()])
.set(size as u64)
});
}
fn on_report_event(&self) {
if let Some(metrics) = self.0.as_ref() {
metrics.report_events.inc()
}
}
}
#[derive(Clone)]
struct MetricsInner {
peer_count: prometheus::GaugeVec<prometheus::U64>,
connected_events: prometheus::CounterVec<prometheus::U64>,
disconnected_events: prometheus::CounterVec<prometheus::U64>,
desired_peer_count: prometheus::GaugeVec<prometheus::U64>,
report_events: prometheus::Counter<prometheus::U64>,
notifications_received: prometheus::CounterVec<prometheus::U64>,
notifications_sent: prometheus::CounterVec<prometheus::U64>,
bytes_received: prometheus::CounterVec<prometheus::U64>,
bytes_sent: prometheus::CounterVec<prometheus::U64>,
}
impl metrics::Metrics for Metrics {
fn try_register(
registry: &prometheus::Registry,
) -> std::result::Result<Self, prometheus::PrometheusError> {
let metrics = MetricsInner {
peer_count: prometheus::register(
prometheus::GaugeVec::new(
prometheus::Opts::new(
"polkadot_parachain_peer_count",
"The number of peers on a parachain-related peer-set",
),
&["protocol"]
)?,
registry,
)?,
connected_events: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_peer_connect_events_total",
"The number of peer connect events on a parachain notifications protocol",
),
&["protocol"]
)?,
registry,
)?,
disconnected_events: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_peer_disconnect_events_total",
"The number of peer disconnect events on a parachain notifications protocol",
),
&["protocol"]
)?,
registry,
)?,
desired_peer_count: prometheus::register(
prometheus::GaugeVec::new(
prometheus::Opts::new(
"polkadot_parachain_desired_peer_count",
"The number of peers that the local node is expected to connect to on a parachain-related peer-set (either including or not including unresolvable authorities, depending on whether `ConnectToValidators` or `ConnectToValidatorsResolved` was used.)",
),
&["protocol"]
)?,
registry,
)?,
report_events: prometheus::register(
prometheus::Counter::new(
"polkadot_parachain_network_report_events_total",
"The amount of reputation changes issued by subsystems",
)?,
registry,
)?,
notifications_received: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notifications_received_total",
"The number of notifications received on a parachain protocol",
),
&["protocol"]
)?,
registry,
)?,
notifications_sent: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notifications_sent_total",
"The number of notifications sent on a parachain protocol",
),
&["protocol"]
)?,
registry,
)?,
bytes_received: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notification_bytes_received_total",
"The number of bytes received on a parachain notification protocol",
),
&["protocol"]
)?,
registry,
)?,
bytes_sent: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notification_bytes_sent_total",
"The number of bytes sent on a parachain notification protocol",
),
&["protocol"]
)?,
registry,
)?,
};
Ok(Metrics(Some(metrics)))
}
}
/// Messages from and to the network. /// Messages from and to the network.
/// ///
/// As transmitted to and received from subsystems. /// As transmitted to and received from subsystems.
@@ -320,12 +124,11 @@ impl<N, AD> NetworkBridge<N, AD> {
} }
} }
impl<Net, AD, Context> Subsystem<Context, SubsystemError> for NetworkBridge<Net, AD> #[overseer::subsystem(NetworkBridge, error = SubsystemError, prefix = self::overseer)]
impl<Net, AD, Context> NetworkBridge<Net, AD>
where where
Net: Network + Sync, Net: Network + Sync,
AD: validator_discovery::AuthorityDiscovery + Clone, AD: validator_discovery::AuthorityDiscovery + Clone,
Context: SubsystemContext<Message = NetworkBridgeMessage>
+ overseer::SubsystemContext<Message = NetworkBridgeMessage>,
{ {
fn start(mut self, ctx: Context) -> SpawnedSubsystem { fn start(mut self, ctx: Context) -> SpawnedSubsystem {
// The stream of networking events has to be created at initialization, otherwise the // The stream of networking events has to be created at initialization, otherwise the
@@ -382,6 +185,7 @@ enum Mode {
Active, Active,
} }
#[overseer::contextbounds(NetworkBridge, prefix = self::overseer)]
async fn handle_subsystem_messages<Context, N, AD>( async fn handle_subsystem_messages<Context, N, AD>(
mut ctx: Context, mut ctx: Context,
mut network_service: N, mut network_service: N,
@@ -391,8 +195,6 @@ async fn handle_subsystem_messages<Context, N, AD>(
metrics: Metrics, metrics: Metrics,
) -> Result<(), UnexpectedAbort> ) -> Result<(), UnexpectedAbort>
where where
Context: SubsystemContext<Message = NetworkBridgeMessage>,
Context: overseer::SubsystemContext<Message = NetworkBridgeMessage>,
N: Network, N: Network,
AD: validator_discovery::AuthorityDiscovery + Clone, AD: validator_discovery::AuthorityDiscovery + Clone,
{ {
@@ -678,7 +480,7 @@ where
} }
async fn handle_network_messages<AD: validator_discovery::AuthorityDiscovery>( async fn handle_network_messages<AD: validator_discovery::AuthorityDiscovery>(
mut sender: impl SubsystemSender, mut sender: impl overseer::NetworkBridgeSenderTrait,
mut network_service: impl Network, mut network_service: impl Network,
network_stream: BoxStream<'static, NetworkEvent>, network_stream: BoxStream<'static, NetworkEvent>,
mut authority_discovery_service: AD, mut authority_discovery_service: AD,
@@ -1031,6 +833,7 @@ async fn handle_network_messages<AD: validator_discovery::AuthorityDiscovery>(
/// #fn is_send<T: Send>(); /// #fn is_send<T: Send>();
/// #is_send::<parking_lot::MutexGuard<'static, ()>(); /// #is_send::<parking_lot::MutexGuard<'static, ()>();
/// ``` /// ```
#[overseer::contextbounds(NetworkBridge, prefix = self::overseer)]
async fn run_network<N, AD, Context>( async fn run_network<N, AD, Context>(
bridge: NetworkBridge<N, AD>, bridge: NetworkBridge<N, AD>,
mut ctx: Context, mut ctx: Context,
@@ -1039,8 +842,6 @@ async fn run_network<N, AD, Context>(
where where
N: Network, N: Network,
AD: validator_discovery::AuthorityDiscovery + Clone, AD: validator_discovery::AuthorityDiscovery + Clone,
Context: SubsystemContext<Message = NetworkBridgeMessage>
+ overseer::SubsystemContext<Message = NetworkBridgeMessage>,
{ {
let shared = Shared::default(); let shared = Shared::default();
@@ -1105,14 +906,17 @@ fn construct_view(
View::new(live_heads.take(MAX_VIEW_HEADS), finalized_number) View::new(live_heads.take(MAX_VIEW_HEADS), finalized_number)
} }
fn update_our_view( #[overseer::contextbounds(NetworkBridge, prefix = self::overseer)]
net: &mut impl Network, fn update_our_view<Net, Context>(
ctx: &mut impl SubsystemContext<Message = NetworkBridgeMessage, AllMessages = AllMessages>, net: &mut Net,
ctx: &mut Context,
live_heads: &[ActivatedLeaf], live_heads: &[ActivatedLeaf],
shared: &Shared, shared: &Shared,
finalized_number: BlockNumber, finalized_number: BlockNumber,
metrics: &Metrics, metrics: &Metrics,
) { ) where
Net: Network,
{
let new_view = construct_view(live_heads.iter().map(|v| v.hash), finalized_number); let new_view = construct_view(live_heads.iter().map(|v| v.hash), finalized_number);
let (validation_peers, collation_peers) = { let (validation_peers, collation_peers) = {
@@ -1238,54 +1042,79 @@ fn send_collation_message_v1(
async fn dispatch_validation_event_to_all( async fn dispatch_validation_event_to_all(
event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>, event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>,
ctx: &mut impl SubsystemSender, ctx: &mut impl overseer::NetworkBridgeSenderTrait,
) { ) {
dispatch_validation_events_to_all(std::iter::once(event), ctx).await dispatch_validation_events_to_all(std::iter::once(event), ctx).await
} }
async fn dispatch_collation_event_to_all( async fn dispatch_collation_event_to_all(
event: NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>, event: NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>,
ctx: &mut impl SubsystemSender, ctx: &mut impl overseer::NetworkBridgeSenderTrait,
) { ) {
dispatch_collation_events_to_all(std::iter::once(event), ctx).await dispatch_collation_events_to_all(std::iter::once(event), ctx).await
} }
fn dispatch_validation_event_to_all_unbounded( fn dispatch_validation_event_to_all_unbounded(
event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>, event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>,
ctx: &mut impl SubsystemSender, sender: &mut impl overseer::NetworkBridgeSenderTrait,
) { ) {
for msg in AllMessages::dispatch_iter(event) { event
ctx.send_unbounded_message(msg); .focus()
} .ok()
.map(StatementDistributionMessage::from)
.and_then(|msg| Some(sender.send_unbounded_message(msg)));
event
.focus()
.ok()
.map(BitfieldDistributionMessage::from)
.and_then(|msg| Some(sender.send_unbounded_message(msg)));
event
.focus()
.ok()
.map(ApprovalDistributionMessage::from)
.and_then(|msg| Some(sender.send_unbounded_message(msg)));
event
.focus()
.ok()
.map(GossipSupportMessage::from)
.and_then(|msg| Some(sender.send_unbounded_message(msg)));
} }
fn dispatch_collation_event_to_all_unbounded( fn dispatch_collation_event_to_all_unbounded(
event: NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>, event: NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>,
ctx: &mut impl SubsystemSender, sender: &mut impl overseer::NetworkBridgeSenderTrait,
) { ) {
if let Some(msg) = event.focus().ok().map(CollatorProtocolMessage::NetworkBridgeUpdate) { if let Ok(msg) = event.focus() {
ctx.send_unbounded_message(msg.into()); sender.send_unbounded_message(CollatorProtocolMessage::NetworkBridgeUpdate(msg))
} }
} }
async fn dispatch_validation_events_to_all<I>(events: I, ctx: &mut impl SubsystemSender) async fn dispatch_validation_events_to_all<I>(
where events: I,
sender: &mut impl overseer::NetworkBridgeSenderTrait,
) where
I: IntoIterator<Item = NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>>, I: IntoIterator<Item = NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>>,
I::IntoIter: Send, I::IntoIter: Send,
{ {
ctx.send_messages(events.into_iter().flat_map(AllMessages::dispatch_iter)).await for event in events {
sender
.send_messages(event.focus().map(StatementDistributionMessage::from))
.await;
sender.send_messages(event.focus().map(BitfieldDistributionMessage::from)).await;
sender.send_messages(event.focus().map(ApprovalDistributionMessage::from)).await;
sender.send_messages(event.focus().map(GossipSupportMessage::from)).await;
}
} }
async fn dispatch_collation_events_to_all<I>(events: I, ctx: &mut impl SubsystemSender) async fn dispatch_collation_events_to_all<I>(
where events: I,
ctx: &mut impl overseer::NetworkBridgeSenderTrait,
) where
I: IntoIterator<Item = NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>>, I: IntoIterator<Item = NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>>,
I::IntoIter: Send, I::IntoIter: Send,
{ {
let messages_for = |event: NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>| { let messages_for = |event: NetworkBridgeEvent<net_protocol::VersionedCollationProtocol>| {
event event.focus().ok().map(|m| CollatorProtocolMessage::NetworkBridgeUpdate(m))
.focus()
.ok()
.map(|m| AllMessages::CollatorProtocol(CollatorProtocolMessage::NetworkBridgeUpdate(m)))
}; };
ctx.send_messages(events.into_iter().flat_map(messages_for)).await ctx.send_messages(events.into_iter().flat_map(messages_for)).await
+223
View File
@@ -0,0 +1,223 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::{PeerSet, ProtocolVersion};
use polkadot_node_subsystem_util::metrics::{self, prometheus};
/// Metrics for the network bridge.
#[derive(Clone, Default)]
pub struct Metrics(pub(crate) Option<MetricsInner>);
fn peer_set_label(peer_set: PeerSet, version: ProtocolVersion) -> &'static str {
// Higher level code is meant to protect against this ever happening.
peer_set.get_protocol_name_static(version).unwrap_or("<internal error>")
}
impl Metrics {
pub fn on_peer_connected(&self, peer_set: PeerSet, version: ProtocolVersion) {
self.0.as_ref().map(|metrics| {
metrics
.connected_events
.with_label_values(&[peer_set_label(peer_set, version)])
.inc()
});
}
pub fn on_peer_disconnected(&self, peer_set: PeerSet, version: ProtocolVersion) {
self.0.as_ref().map(|metrics| {
metrics
.disconnected_events
.with_label_values(&[peer_set_label(peer_set, version)])
.inc()
});
}
pub fn note_peer_count(&self, peer_set: PeerSet, version: ProtocolVersion, count: usize) {
self.0.as_ref().map(|metrics| {
metrics
.peer_count
.with_label_values(&[peer_set_label(peer_set, version)])
.set(count as u64)
});
}
pub fn on_notification_received(
&self,
peer_set: PeerSet,
version: ProtocolVersion,
size: usize,
) {
if let Some(metrics) = self.0.as_ref() {
metrics
.notifications_received
.with_label_values(&[peer_set_label(peer_set, version)])
.inc();
metrics
.bytes_received
.with_label_values(&[peer_set_label(peer_set, version)])
.inc_by(size as u64);
}
}
pub fn on_notification_sent(
&self,
peer_set: PeerSet,
version: ProtocolVersion,
size: usize,
to_peers: usize,
) {
if let Some(metrics) = self.0.as_ref() {
metrics
.notifications_sent
.with_label_values(&[peer_set_label(peer_set, version)])
.inc_by(to_peers as u64);
metrics
.bytes_sent
.with_label_values(&[peer_set_label(peer_set, version)])
.inc_by((size * to_peers) as u64);
}
}
pub fn note_desired_peer_count(&self, peer_set: PeerSet, size: usize) {
self.0.as_ref().map(|metrics| {
metrics
.desired_peer_count
.with_label_values(&[peer_set.get_default_protocol_name()])
.set(size as u64)
});
}
pub fn on_report_event(&self) {
if let Some(metrics) = self.0.as_ref() {
metrics.report_events.inc()
}
}
}
#[derive(Clone)]
pub(crate) struct MetricsInner {
peer_count: prometheus::GaugeVec<prometheus::U64>,
connected_events: prometheus::CounterVec<prometheus::U64>,
disconnected_events: prometheus::CounterVec<prometheus::U64>,
desired_peer_count: prometheus::GaugeVec<prometheus::U64>,
report_events: prometheus::Counter<prometheus::U64>,
notifications_received: prometheus::CounterVec<prometheus::U64>,
notifications_sent: prometheus::CounterVec<prometheus::U64>,
bytes_received: prometheus::CounterVec<prometheus::U64>,
bytes_sent: prometheus::CounterVec<prometheus::U64>,
}
impl metrics::Metrics for Metrics {
fn try_register(
registry: &prometheus::Registry,
) -> std::result::Result<Self, prometheus::PrometheusError> {
let metrics = MetricsInner {
peer_count: prometheus::register(
prometheus::GaugeVec::new(
prometheus::Opts::new(
"polkadot_parachain_peer_count",
"The number of peers on a parachain-related peer-set",
),
&["protocol"]
)?,
registry,
)?,
connected_events: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_peer_connect_events_total",
"The number of peer connect events on a parachain notifications protocol",
),
&["protocol"]
)?,
registry,
)?,
disconnected_events: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_peer_disconnect_events_total",
"The number of peer disconnect events on a parachain notifications protocol",
),
&["protocol"]
)?,
registry,
)?,
desired_peer_count: prometheus::register(
prometheus::GaugeVec::new(
prometheus::Opts::new(
"polkadot_parachain_desired_peer_count",
"The number of peers that the local node is expected to connect to on a parachain-related peer-set (either including or not including unresolvable authorities, depending on whether `ConnectToValidators` or `ConnectToValidatorsResolved` was used.)",
),
&["protocol"]
)?,
registry,
)?,
report_events: prometheus::register(
prometheus::Counter::new(
"polkadot_parachain_network_report_events_total",
"The amount of reputation changes issued by subsystems",
)?,
registry,
)?,
notifications_received: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notifications_received_total",
"The number of notifications received on a parachain protocol",
),
&["protocol"]
)?,
registry,
)?,
notifications_sent: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notifications_sent_total",
"The number of notifications sent on a parachain protocol",
),
&["protocol"]
)?,
registry,
)?,
bytes_received: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notification_bytes_received_total",
"The number of bytes received on a parachain notification protocol",
),
&["protocol"]
)?,
registry,
)?,
bytes_sent: prometheus::register(
prometheus::CounterVec::new(
prometheus::Opts::new(
"polkadot_parachain_notification_bytes_sent_total",
"The number of bytes sent on a parachain notification protocol",
),
&["protocol"]
)?,
registry,
)?,
};
Ok(Metrics(Some(metrics)))
}
}
+5 -52
View File
@@ -34,8 +34,8 @@ use polkadot_node_network_protocol::{
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{ messages::{
ApprovalDistributionMessage, BitfieldDistributionMessage, GossipSupportMessage, AllMessages, ApprovalDistributionMessage, BitfieldDistributionMessage,
StatementDistributionMessage, GossipSupportMessage, StatementDistributionMessage,
}, },
ActiveLeavesUpdate, FromOverseer, LeafStatus, OverseerSignal, ActiveLeavesUpdate, FromOverseer, LeafStatus, OverseerSignal,
}; };
@@ -313,8 +313,9 @@ async fn assert_sends_validation_event_to_all(
event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>, event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>,
virtual_overseer: &mut TestSubsystemContextHandle<NetworkBridgeMessage>, virtual_overseer: &mut TestSubsystemContextHandle<NetworkBridgeMessage>,
) { ) {
// Ordering must match the enum variant order // Ordering must be consistent across:
// in `AllMessages`. // `fn dispatch_validation_event_to_all_unbounded`
// `dispatch_validation_events_to_all`
assert_matches!( assert_matches!(
virtual_overseer.recv().await, virtual_overseer.recv().await,
AllMessages::StatementDistribution( AllMessages::StatementDistribution(
@@ -1190,54 +1191,6 @@ fn send_messages_to_peers() {
}); });
} }
#[test]
fn spread_event_to_subsystems_is_up_to_date() {
// Number of subsystems expected to be interested in a network event,
// and hence the network event broadcasted to.
const EXPECTED_COUNT: usize = 4;
let mut cnt = 0_usize;
for msg in AllMessages::dispatch_iter(NetworkBridgeEvent::PeerDisconnected(PeerId::random())) {
match msg {
AllMessages::Empty => unreachable!("Nobody cares about the dummy"),
AllMessages::CandidateValidation(_) => unreachable!("Not interested in network events"),
AllMessages::CandidateBacking(_) => unreachable!("Not interested in network events"),
AllMessages::ChainApi(_) => unreachable!("Not interested in network events"),
AllMessages::CollatorProtocol(_) => unreachable!("Not interested in network events"),
AllMessages::StatementDistribution(_) => {
cnt += 1;
},
AllMessages::AvailabilityDistribution(_) =>
unreachable!("Not interested in network events"),
AllMessages::AvailabilityRecovery(_) =>
unreachable!("Not interested in network events"),
AllMessages::BitfieldDistribution(_) => {
cnt += 1;
},
AllMessages::BitfieldSigning(_) => unreachable!("Not interested in network events"),
AllMessages::Provisioner(_) => unreachable!("Not interested in network events"),
AllMessages::RuntimeApi(_) => unreachable!("Not interested in network events"),
AllMessages::AvailabilityStore(_) => unreachable!("Not interested in network events"),
AllMessages::NetworkBridge(_) => unreachable!("Not interested in network events"),
AllMessages::CollationGeneration(_) => unreachable!("Not interested in network events"),
AllMessages::ApprovalVoting(_) => unreachable!("Not interested in network events"),
AllMessages::ApprovalDistribution(_) => {
cnt += 1;
},
AllMessages::GossipSupport(_) => {
cnt += 1;
},
AllMessages::DisputeCoordinator(_) => unreachable!("Not interested in network events"),
AllMessages::DisputeDistribution(_) => unreachable!("Not interested in network events"),
AllMessages::ChainSelection(_) => unreachable!("Not interested in network events"),
AllMessages::PvfChecker(_) => unreachable!("Not interested in network events"),
// Add variants here as needed, `{ cnt += 1; }` for those that need to be
// notified, `unreachable!()` for those that should not.
}
}
assert_eq!(cnt, EXPECTED_COUNT);
}
#[test] #[test]
fn our_view_updates_decreasing_order_and_limited_to_max() { fn our_view_updates_decreasing_order_and_limited_to_max() {
test_harness(done_syncing_oracle(), |test_harness| async move { test_harness(done_syncing_oracle(), |test_harness| async move {
@@ -38,8 +38,10 @@ use polkadot_node_network_protocol::{
use polkadot_node_primitives::{CollationSecondedSignal, PoV, Statement}; use polkadot_node_primitives::{CollationSecondedSignal, PoV, Statement};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeMessage}, messages::{
overseer, FromOverseer, OverseerSignal, PerLeafSpan, SubsystemContext, CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeMessage, RuntimeApiMessage,
},
overseer, FromOverseer, OverseerSignal, PerLeafSpan,
}; };
use polkadot_node_subsystem_util::{ use polkadot_node_subsystem_util::{
metrics::{self, prometheus}, metrics::{self, prometheus},
@@ -360,6 +362,7 @@ impl State {
/// or the relay-parent isn't in the active-leaves set, we ignore the message /// or the relay-parent isn't in the active-leaves set, we ignore the message
/// as it must be invalid in that case - although this indicates a logic error /// as it must be invalid in that case - although this indicates a logic error
/// elsewhere in the node. /// elsewhere in the node.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn distribute_collation<Context>( async fn distribute_collation<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -368,11 +371,7 @@ async fn distribute_collation<Context>(
receipt: CandidateReceipt, receipt: CandidateReceipt,
pov: PoV, pov: PoV,
result_sender: Option<oneshot::Sender<CollationSecondedSignal>>, result_sender: Option<oneshot::Sender<CollationSecondedSignal>>,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let relay_parent = receipt.descriptor.relay_parent; let relay_parent = receipt.descriptor.relay_parent;
// This collation is not in the active-leaves set. // This collation is not in the active-leaves set.
@@ -398,7 +397,7 @@ where
// Determine which core the para collated-on is assigned to. // Determine which core the para collated-on is assigned to.
// If it is not scheduled then ignore the message. // If it is not scheduled then ignore the message.
let (our_core, num_cores) = match determine_core(ctx, id, relay_parent).await? { let (our_core, num_cores) = match determine_core(ctx.sender(), id, relay_parent).await? {
Some(core) => core, Some(core) => core,
None => { None => {
gum::warn!( gum::warn!(
@@ -461,16 +460,12 @@ where
/// Get the Id of the Core that is assigned to the para being collated on if any /// Get the Id of the Core that is assigned to the para being collated on if any
/// and the total number of cores. /// and the total number of cores.
async fn determine_core<Context>( async fn determine_core(
ctx: &mut Context, sender: &mut impl overseer::SubsystemSender<RuntimeApiMessage>,
para_id: ParaId, para_id: ParaId,
relay_parent: Hash, relay_parent: Hash,
) -> Result<Option<(CoreIndex, usize)>> ) -> Result<Option<(CoreIndex, usize)>> {
where let cores = get_availability_cores(sender, relay_parent).await?;
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let cores = get_availability_cores(ctx, relay_parent).await?;
for (idx, core) in cores.iter().enumerate() { for (idx, core) in cores.iter().enumerate() {
if let CoreState::Scheduled(occupied) = core { if let CoreState::Scheduled(occupied) = core {
@@ -493,17 +488,14 @@ struct GroupValidators {
/// Figure out current group of validators assigned to the para being collated on. /// Figure out current group of validators assigned to the para being collated on.
/// ///
/// Returns [`ValidatorId`]'s of current group as determined based on the `relay_parent`. /// Returns [`ValidatorId`]'s of current group as determined based on the `relay_parent`.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn determine_our_validators<Context>( async fn determine_our_validators<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
core_index: CoreIndex, core_index: CoreIndex,
cores: usize, cores: usize,
relay_parent: Hash, relay_parent: Hash,
) -> Result<GroupValidators> ) -> Result<GroupValidators> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let session_index = runtime.get_session_index_for_child(ctx.sender(), relay_parent).await?; let session_index = runtime.get_session_index_for_child(ctx.sender(), relay_parent).await?;
let info = &runtime let info = &runtime
.get_session_info_by_index(ctx.sender(), relay_parent, session_index) .get_session_info_by_index(ctx.sender(), relay_parent, session_index)
@@ -511,7 +503,7 @@ where
.session_info; .session_info;
gum::debug!(target: LOG_TARGET, ?session_index, "Received session info"); gum::debug!(target: LOG_TARGET, ?session_index, "Received session info");
let groups = &info.validator_groups; let groups = &info.validator_groups;
let rotation_info = get_group_rotation_info(ctx, relay_parent).await?; let rotation_info = get_group_rotation_info(ctx.sender(), relay_parent).await?;
let current_group_index = rotation_info.group_for_core(core_index, cores); let current_group_index = rotation_info.group_for_core(core_index, cores);
let current_validators = groups let current_validators = groups
@@ -530,11 +522,8 @@ where
} }
/// Issue a `Declare` collation message to the given `peer`. /// Issue a `Declare` collation message to the given `peer`.
async fn declare<Context>(ctx: &mut Context, state: &mut State, peer: PeerId) #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
where async fn declare<Context>(ctx: &mut Context, state: &mut State, peer: PeerId) {
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let declare_signature_payload = protocol_v1::declare_signature_payload(&state.local_peer_id); let declare_signature_payload = protocol_v1::declare_signature_payload(&state.local_peer_id);
if let Some(para_id) = state.collating_on { if let Some(para_id) = state.collating_on {
@@ -554,11 +543,11 @@ where
/// Issue a connection request to a set of validators and /// Issue a connection request to a set of validators and
/// revoke the previous connection request. /// revoke the previous connection request.
async fn connect_to_validators<Context>(ctx: &mut Context, validator_ids: Vec<AuthorityDiscoveryId>) #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
where async fn connect_to_validators<Context>(
Context: SubsystemContext<Message = CollatorProtocolMessage>, ctx: &mut Context,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>, validator_ids: Vec<AuthorityDiscoveryId>,
{ ) {
// ignore address resolution failure // ignore address resolution failure
// will reissue a new request on new collation // will reissue a new request on new collation
let (failed, _) = oneshot::channel(); let (failed, _) = oneshot::channel();
@@ -574,15 +563,13 @@ where
/// ///
/// This will only advertise a collation if there exists one for the given `relay_parent` and the given `peer` is /// This will only advertise a collation if there exists one for the given `relay_parent` and the given `peer` is
/// set as validator for our para at the given `relay_parent`. /// set as validator for our para at the given `relay_parent`.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn advertise_collation<Context>( async fn advertise_collation<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
relay_parent: Hash, relay_parent: Hash,
peer: PeerId, peer: PeerId,
) where ) {
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let should_advertise = state let should_advertise = state
.our_validators_groups .our_validators_groups
.get(&relay_parent) .get(&relay_parent)
@@ -635,16 +622,13 @@ async fn advertise_collation<Context>(
} }
/// The main incoming message dispatching switch. /// The main incoming message dispatching switch.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn process_msg<Context>( async fn process_msg<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
state: &mut State, state: &mut State,
msg: CollatorProtocolMessage, msg: CollatorProtocolMessage,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
use CollatorProtocolMessage::*; use CollatorProtocolMessage::*;
match msg { match msg {
@@ -748,17 +732,14 @@ async fn send_collation(
} }
/// A networking messages switch. /// A networking messages switch.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_incoming_peer_message<Context>( async fn handle_incoming_peer_message<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
state: &mut State, state: &mut State,
origin: PeerId, origin: PeerId,
msg: protocol_v1::CollatorProtocolMessage, msg: protocol_v1::CollatorProtocolMessage,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
use protocol_v1::CollatorProtocolMessage::*; use protocol_v1::CollatorProtocolMessage::*;
match msg { match msg {
@@ -831,15 +812,12 @@ where
} }
/// Process an incoming network request for a collation. /// Process an incoming network request for a collation.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_incoming_request<Context>( async fn handle_incoming_request<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
req: IncomingRequest<request_v1::CollationFetchingRequest>, req: IncomingRequest<request_v1::CollationFetchingRequest>,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let _span = state let _span = state
.span_per_relay_parent .span_per_relay_parent
.get(&req.payload.relay_parent) .get(&req.payload.relay_parent)
@@ -907,15 +885,13 @@ where
} }
/// Our view has changed. /// Our view has changed.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_peer_view_change<Context>( async fn handle_peer_view_change<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
peer_id: PeerId, peer_id: PeerId,
view: View, view: View,
) where ) {
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
let current = state.peer_views.entry(peer_id.clone()).or_default(); let current = state.peer_views.entry(peer_id.clone()).or_default();
let added: Vec<Hash> = view.difference(&*current).cloned().collect(); let added: Vec<Hash> = view.difference(&*current).cloned().collect();
@@ -928,16 +904,13 @@ async fn handle_peer_view_change<Context>(
} }
/// Bridge messages switch. /// Bridge messages switch.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_network_msg<Context>( async fn handle_network_msg<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
state: &mut State, state: &mut State,
bridge_message: NetworkBridgeEvent<net_protocol::CollatorProtocolMessage>, bridge_message: NetworkBridgeEvent<net_protocol::CollatorProtocolMessage>,
) -> Result<()> ) -> Result<()> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
use NetworkBridgeEvent::*; use NetworkBridgeEvent::*;
match bridge_message { match bridge_message {
@@ -1021,17 +994,14 @@ async fn handle_our_view_change(state: &mut State, view: OurView) -> Result<()>
} }
/// The collator protocol collator side main loop. /// The collator protocol collator side main loop.
#[overseer::contextbounds(CollatorProtocol, prefix = crate::overseer)]
pub(crate) async fn run<Context>( pub(crate) async fn run<Context>(
mut ctx: Context, mut ctx: Context,
local_peer_id: PeerId, local_peer_id: PeerId,
collator_pair: CollatorPair, collator_pair: CollatorPair,
mut req_receiver: IncomingRequestReceiver<request_v1::CollationFetchingRequest>, mut req_receiver: IncomingRequestReceiver<request_v1::CollationFetchingRequest>,
metrics: Metrics, metrics: Metrics,
) -> std::result::Result<(), FatalError> ) -> std::result::Result<(), FatalError> {
where
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
{
use OverseerSignal::*; use OverseerSignal::*;
let mut state = State::new(local_peer_id, collator_pair, metrics); let mut state = State::new(local_peer_id, collator_pair, metrics);
@@ -34,9 +34,7 @@ use polkadot_node_network_protocol::{
use polkadot_primitives::v2::CollatorPair; use polkadot_primitives::v2::CollatorPair;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::SubsystemError, errors::SubsystemError, messages::NetworkBridgeMessage, overseer, SpawnedSubsystem,
messages::{CollatorProtocolMessage, NetworkBridgeMessage},
overseer, SpawnedSubsystem, SubsystemContext, SubsystemSender,
}; };
mod error; mod error;
@@ -89,6 +87,7 @@ pub struct CollatorProtocolSubsystem {
protocol_side: ProtocolSide, protocol_side: ProtocolSide,
} }
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
impl CollatorProtocolSubsystem { impl CollatorProtocolSubsystem {
/// Start the collator protocol. /// Start the collator protocol.
/// If `id` is `Some` this is a collator side of the protocol. /// If `id` is `Some` this is a collator side of the protocol.
@@ -98,11 +97,7 @@ impl CollatorProtocolSubsystem {
Self { protocol_side } Self { protocol_side }
} }
async fn run<Context>(self, ctx: Context) -> std::result::Result<(), error::FatalError> async fn run<Context>(self, ctx: Context) -> std::result::Result<(), error::FatalError> {
where
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
match self.protocol_side { match self.protocol_side {
ProtocolSide::Validator { keystore, eviction_policy, metrics } => ProtocolSide::Validator { keystore, eviction_policy, metrics } =>
validator_side::run(ctx, keystore, eviction_policy, metrics).await, validator_side::run(ctx, keystore, eviction_policy, metrics).await,
@@ -112,12 +107,8 @@ impl CollatorProtocolSubsystem {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for CollatorProtocolSubsystem #[overseer::subsystem(CollatorProtocol, error=SubsystemError, prefix=self::overseer)]
where impl<Context> CollatorProtocolSubsystem {
Context: SubsystemContext<Message = CollatorProtocolMessage>,
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
<Context as SubsystemContext>::Sender: SubsystemSender,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = self let future = self
.run(ctx) .run(ctx)
@@ -129,10 +120,11 @@ where
} }
/// Modify the reputation of a peer based on its behavior. /// Modify the reputation of a peer based on its behavior.
async fn modify_reputation<Context>(ctx: &mut Context, peer: PeerId, rep: Rep) async fn modify_reputation(
where sender: &mut impl overseer::CollatorProtocolSenderTrait,
Context: SubsystemContext, peer: PeerId,
{ rep: Rep,
) {
gum::trace!( gum::trace!(
target: LOG_TARGET, target: LOG_TARGET,
rep = ?rep, rep = ?rep,
@@ -140,5 +132,5 @@ where
"reputation change for peer", "reputation change for peer",
); );
ctx.send_message(NetworkBridgeMessage::ReportPeer(peer, rep)).await; sender.send_message(NetworkBridgeMessage::ReportPeer(peer, rep)).await;
} }
@@ -48,9 +48,9 @@ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{ messages::{
CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected, NetworkBridgeEvent, CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected, NetworkBridgeEvent,
NetworkBridgeMessage, NetworkBridgeMessage, RuntimeApiMessage,
}, },
overseer, FromOverseer, OverseerSignal, PerLeafSpan, SubsystemContext, SubsystemSender, overseer, FromOverseer, OverseerSignal, PerLeafSpan, SubsystemSender,
}; };
use polkadot_node_subsystem_util::metrics::{self, prometheus}; use polkadot_node_subsystem_util::metrics::{self, prometheus};
use polkadot_primitives::v2::{CandidateReceipt, CollatorId, Hash, Id as ParaId}; use polkadot_primitives::v2::{CandidateReceipt, CollatorId, Hash, Id as ParaId};
@@ -362,7 +362,7 @@ struct ActiveParas {
impl ActiveParas { impl ActiveParas {
async fn assign_incoming( async fn assign_incoming(
&mut self, &mut self,
sender: &mut impl SubsystemSender, sender: &mut impl SubsystemSender<RuntimeApiMessage>,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
new_relay_parents: impl IntoIterator<Item = Hash>, new_relay_parents: impl IntoIterator<Item = Hash>,
) { ) {
@@ -630,25 +630,19 @@ fn collator_peer_id(
}) })
} }
async fn disconnect_peer<Context>(ctx: &mut Context, peer_id: PeerId) async fn disconnect_peer(sender: &mut impl overseer::CollatorProtocolSenderTrait, peer_id: PeerId) {
where sender
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>, .send_message(NetworkBridgeMessage::DisconnectPeer(peer_id, PeerSet::Collation))
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
ctx.send_message(NetworkBridgeMessage::DisconnectPeer(peer_id, PeerSet::Collation))
.await .await
} }
/// Another subsystem has requested to fetch collations on a particular leaf for some para. /// Another subsystem has requested to fetch collations on a particular leaf for some para.
async fn fetch_collation<Context>( async fn fetch_collation(
ctx: &mut Context, sender: &mut impl overseer::CollatorProtocolSenderTrait,
state: &mut State, state: &mut State,
pc: PendingCollation, pc: PendingCollation,
id: CollatorId, id: CollatorId,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let PendingCollation { relay_parent, para_id, peer_id, .. } = pc; let PendingCollation { relay_parent, para_id, peer_id, .. } = pc;
@@ -663,7 +657,7 @@ async fn fetch_collation<Context>(
if let Some(peer_data) = state.peer_data.get(&peer_id) { if let Some(peer_data) = state.peer_data.get(&peer_id) {
if peer_data.has_advertised(&relay_parent) { if peer_data.has_advertised(&relay_parent) {
request_collation(ctx, state, relay_parent, para_id, peer_id, tx).await; request_collation(sender, state, relay_parent, para_id, peer_id, tx).await;
} else { } else {
gum::debug!( gum::debug!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -687,51 +681,44 @@ async fn fetch_collation<Context>(
} }
/// Report a collator for some malicious actions. /// Report a collator for some malicious actions.
async fn report_collator<Context>( async fn report_collator(
ctx: &mut Context, sender: &mut impl overseer::CollatorProtocolSenderTrait,
peer_data: &HashMap<PeerId, PeerData>, peer_data: &HashMap<PeerId, PeerData>,
id: CollatorId, id: CollatorId,
) where ) {
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
if let Some(peer_id) = collator_peer_id(peer_data, &id) { if let Some(peer_id) = collator_peer_id(peer_data, &id) {
modify_reputation(ctx, peer_id, COST_REPORT_BAD).await; modify_reputation(sender, peer_id, COST_REPORT_BAD).await;
} }
} }
/// Some other subsystem has reported a collator as a good one, bump reputation. /// Some other subsystem has reported a collator as a good one, bump reputation.
async fn note_good_collation<Context>( async fn note_good_collation(
ctx: &mut Context, sender: &mut impl overseer::CollatorProtocolSenderTrait,
peer_data: &HashMap<PeerId, PeerData>, peer_data: &HashMap<PeerId, PeerData>,
id: CollatorId, id: CollatorId,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
if let Some(peer_id) = collator_peer_id(peer_data, &id) { if let Some(peer_id) = collator_peer_id(peer_data, &id) {
modify_reputation(ctx, peer_id, BENEFIT_NOTIFY_GOOD).await; modify_reputation(sender, peer_id, BENEFIT_NOTIFY_GOOD).await;
} }
} }
/// Notify a collator that its collation got seconded. /// Notify a collator that its collation got seconded.
async fn notify_collation_seconded<Context>( async fn notify_collation_seconded(
ctx: &mut Context, sender: &mut impl overseer::CollatorProtocolSenderTrait,
peer_id: PeerId, peer_id: PeerId,
relay_parent: Hash, relay_parent: Hash,
statement: SignedFullStatement, statement: SignedFullStatement,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
let wire_message = let wire_message =
protocol_v1::CollatorProtocolMessage::CollationSeconded(relay_parent, statement.into()); protocol_v1::CollatorProtocolMessage::CollationSeconded(relay_parent, statement.into());
ctx.send_message(NetworkBridgeMessage::SendCollationMessage( sender
vec![peer_id], .send_message(NetworkBridgeMessage::SendCollationMessage(
Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)), vec![peer_id],
)) Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)),
.await; ))
.await;
modify_reputation(ctx, peer_id, BENEFIT_NOTIFY_GOOD).await; modify_reputation(sender, peer_id, BENEFIT_NOTIFY_GOOD).await;
} }
/// A peer's view has changed. A number of things should be done: /// A peer's view has changed. A number of things should be done:
@@ -754,17 +741,14 @@ async fn handle_peer_view_change(state: &mut State, peer_id: PeerId, view: View)
/// - Check if the requested collation is in our view. /// - Check if the requested collation is in our view.
/// - Update `PerRequest` records with the `result` field if necessary. /// - Update `PerRequest` records with the `result` field if necessary.
/// And as such invocations of this function may rely on that. /// And as such invocations of this function may rely on that.
async fn request_collation<Context>( async fn request_collation(
ctx: &mut Context, sender: &mut impl overseer::CollatorProtocolSenderTrait,
state: &mut State, state: &mut State,
relay_parent: Hash, relay_parent: Hash,
para_id: ParaId, para_id: ParaId,
peer_id: PeerId, peer_id: PeerId,
result: oneshot::Sender<(CandidateReceipt, PoV)>, result: oneshot::Sender<(CandidateReceipt, PoV)>,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
if !state.view.contains(&relay_parent) { if !state.view.contains(&relay_parent) {
gum::debug!( gum::debug!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -815,29 +799,28 @@ async fn request_collation<Context>(
"Requesting collation", "Requesting collation",
); );
ctx.send_message(NetworkBridgeMessage::SendRequests( sender
vec![requests], .send_message(NetworkBridgeMessage::SendRequests(
IfDisconnected::ImmediateError, vec![requests],
)) IfDisconnected::ImmediateError,
.await; ))
.await;
} }
/// Networking message has been received. /// Networking message has been received.
#[overseer::contextbounds(CollatorProtocol, prefix = overseer)]
async fn process_incoming_peer_message<Context>( async fn process_incoming_peer_message<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
origin: PeerId, origin: PeerId,
msg: protocol_v1::CollatorProtocolMessage, msg: protocol_v1::CollatorProtocolMessage,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
use protocol_v1::CollatorProtocolMessage::*; use protocol_v1::CollatorProtocolMessage::*;
use sp_runtime::traits::AppVerify; use sp_runtime::traits::AppVerify;
match msg { match msg {
Declare(collator_id, para_id, signature) => { Declare(collator_id, para_id, signature) => {
if collator_peer_id(&state.peer_data, &collator_id).is_some() { if collator_peer_id(&state.peer_data, &collator_id).is_some() {
modify_reputation(ctx, origin, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), origin, COST_UNEXPECTED_MESSAGE).await;
return return
} }
@@ -850,7 +833,7 @@ async fn process_incoming_peer_message<Context>(
?para_id, ?para_id,
"Unknown peer", "Unknown peer",
); );
modify_reputation(ctx, origin, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), origin, COST_UNEXPECTED_MESSAGE).await;
return return
}, },
}; };
@@ -862,7 +845,7 @@ async fn process_incoming_peer_message<Context>(
?para_id, ?para_id,
"Peer is not in the collating state", "Peer is not in the collating state",
); );
modify_reputation(ctx, origin, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), origin, COST_UNEXPECTED_MESSAGE).await;
return return
} }
@@ -873,7 +856,7 @@ async fn process_incoming_peer_message<Context>(
?para_id, ?para_id,
"Signature verification failure", "Signature verification failure",
); );
modify_reputation(ctx, origin, COST_INVALID_SIGNATURE).await; modify_reputation(ctx.sender(), origin, COST_INVALID_SIGNATURE).await;
return return
} }
@@ -896,9 +879,9 @@ async fn process_incoming_peer_message<Context>(
"Declared as collator for unneeded para", "Declared as collator for unneeded para",
); );
modify_reputation(ctx, origin.clone(), COST_UNNEEDED_COLLATOR).await; modify_reputation(ctx.sender(), origin.clone(), COST_UNNEEDED_COLLATOR).await;
gum::trace!(target: LOG_TARGET, "Disconnecting unneeded collator"); gum::trace!(target: LOG_TARGET, "Disconnecting unneeded collator");
disconnect_peer(ctx, origin).await; disconnect_peer(ctx.sender(), origin).await;
} }
}, },
AdvertiseCollation(relay_parent) => { AdvertiseCollation(relay_parent) => {
@@ -914,7 +897,7 @@ async fn process_incoming_peer_message<Context>(
"Advertise collation out of view", "Advertise collation out of view",
); );
modify_reputation(ctx, origin, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), origin, COST_UNEXPECTED_MESSAGE).await;
return return
} }
@@ -926,7 +909,7 @@ async fn process_incoming_peer_message<Context>(
?relay_parent, ?relay_parent,
"Advertise collation message has been received from an unknown peer", "Advertise collation message has been received from an unknown peer",
); );
modify_reputation(ctx, origin, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), origin, COST_UNEXPECTED_MESSAGE).await;
return return
}, },
Some(p) => p, Some(p) => p,
@@ -962,7 +945,8 @@ async fn process_incoming_peer_message<Context>(
collations.status = CollationStatus::Fetching; collations.status = CollationStatus::Fetching;
collations.waiting_collation = Some(id.clone()); collations.waiting_collation = Some(id.clone());
fetch_collation(ctx, state, pending_collation.clone(), id).await; fetch_collation(ctx.sender(), state, pending_collation.clone(), id)
.await;
}, },
CollationStatus::Seconded => { CollationStatus::Seconded => {
gum::trace!( gum::trace!(
@@ -984,7 +968,7 @@ async fn process_incoming_peer_message<Context>(
"Invalid advertisement", "Invalid advertisement",
); );
modify_reputation(ctx, origin, COST_UNEXPECTED_MESSAGE).await; modify_reputation(ctx.sender(), origin, COST_UNEXPECTED_MESSAGE).await;
}, },
} }
}, },
@@ -1011,16 +995,13 @@ async fn remove_relay_parent(state: &mut State, relay_parent: Hash) -> Result<()
} }
/// Our view has changed. /// Our view has changed.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_our_view_change<Context>( async fn handle_our_view_change<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
view: OurView, view: OurView,
) -> Result<()> ) -> Result<()> {
where
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
let old_view = std::mem::replace(&mut state.view, view); let old_view = std::mem::replace(&mut state.view, view);
let added: HashMap<Hash, Arc<jaeger::Span>> = state let added: HashMap<Hash, Arc<jaeger::Span>> = state
@@ -1061,7 +1042,7 @@ where
?para_id, ?para_id,
"Disconnecting peer on view change (not current parachain id)" "Disconnecting peer on view change (not current parachain id)"
); );
disconnect_peer(ctx, peer_id.clone()).await; disconnect_peer(ctx.sender(), peer_id.clone()).await;
} }
} }
} }
@@ -1070,16 +1051,13 @@ where
} }
/// Bridge event switch. /// Bridge event switch.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_network_msg<Context>( async fn handle_network_msg<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
bridge_message: NetworkBridgeEvent<net_protocol::CollatorProtocolMessage>, bridge_message: NetworkBridgeEvent<net_protocol::CollatorProtocolMessage>,
) -> Result<()> ) -> Result<()> {
where
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
use NetworkBridgeEvent::*; use NetworkBridgeEvent::*;
match bridge_message { match bridge_message {
@@ -1109,15 +1087,13 @@ where
} }
/// The main message receiver switch. /// The main message receiver switch.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn process_msg<Context>( async fn process_msg<Context>(
ctx: &mut Context, ctx: &mut Context,
keystore: &SyncCryptoStorePtr, keystore: &SyncCryptoStorePtr,
msg: CollatorProtocolMessage, msg: CollatorProtocolMessage,
state: &mut State, state: &mut State,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
use CollatorProtocolMessage::*; use CollatorProtocolMessage::*;
let _timer = state.metrics.time_process_msg(); let _timer = state.metrics.time_process_msg();
@@ -1137,7 +1113,7 @@ async fn process_msg<Context>(
); );
}, },
ReportCollator(id) => { ReportCollator(id) => {
report_collator(ctx, &state.peer_data, id).await; report_collator(ctx.sender(), &state.peer_data, id).await;
}, },
NetworkBridgeUpdate(event) => { NetworkBridgeUpdate(event) => {
if let Err(e) = handle_network_msg(ctx, state, keystore, event).await { if let Err(e) = handle_network_msg(ctx, state, keystore, event).await {
@@ -1152,8 +1128,8 @@ async fn process_msg<Context>(
if let Some(collation_event) = state.pending_candidates.remove(&parent) { if let Some(collation_event) = state.pending_candidates.remove(&parent) {
let (collator_id, pending_collation) = collation_event; let (collator_id, pending_collation) = collation_event;
let PendingCollation { relay_parent, peer_id, .. } = pending_collation; let PendingCollation { relay_parent, peer_id, .. } = pending_collation;
note_good_collation(ctx, &state.peer_data, collator_id).await; note_good_collation(ctx.sender(), &state.peer_data, collator_id).await;
notify_collation_seconded(ctx, peer_id, relay_parent, stmt).await; notify_collation_seconded(ctx.sender(), peer_id, relay_parent, stmt).await;
if let Some(collations) = state.collations_per_relay_parent.get_mut(&parent) { if let Some(collations) = state.collations_per_relay_parent.get_mut(&parent) {
collations.status = CollationStatus::Seconded; collations.status = CollationStatus::Seconded;
@@ -1184,7 +1160,7 @@ async fn process_msg<Context>(
Entry::Vacant(_) => return, Entry::Vacant(_) => return,
}; };
report_collator(ctx, &state.peer_data, id.clone()).await; report_collator(ctx.sender(), &state.peer_data, id.clone()).await;
dequeue_next_collation_and_fetch(ctx, state, parent, id).await; dequeue_next_collation_and_fetch(ctx, state, parent, id).await;
}, },
@@ -1211,16 +1187,13 @@ fn infinite_stream(every: Duration) -> impl FusedStream<Item = ()> {
} }
/// The main run loop. /// The main run loop.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
pub(crate) async fn run<Context>( pub(crate) async fn run<Context>(
mut ctx: Context, mut ctx: Context,
keystore: SyncCryptoStorePtr, keystore: SyncCryptoStorePtr,
eviction_policy: crate::CollatorEvictionPolicy, eviction_policy: crate::CollatorEvictionPolicy,
metrics: Metrics, metrics: Metrics,
) -> std::result::Result<(), crate::error::FatalError> ) -> std::result::Result<(), crate::error::FatalError> {
where
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
let mut state = State { metrics, ..Default::default() }; let mut state = State { metrics, ..Default::default() };
let next_inactivity_stream = infinite_stream(ACTIVITY_POLL); let next_inactivity_stream = infinite_stream(ACTIVITY_POLL);
@@ -1247,7 +1220,7 @@ where
} }
} }
_ = next_inactivity_stream.next() => { _ = next_inactivity_stream.next() => {
disconnect_inactive_peers(&mut ctx, &eviction_policy, &state.peer_data).await; disconnect_inactive_peers(ctx.sender(), &eviction_policy, &state.peer_data).await;
} }
res = state.collation_fetches.select_next_some() => { res = state.collation_fetches.select_next_some() => {
handle_collation_fetched_result(&mut ctx, &mut state, res).await; handle_collation_fetched_result(&mut ctx, &mut state, res).await;
@@ -1270,7 +1243,7 @@ where
).await; ).await;
for (peer_id, rep) in reputation_changes { for (peer_id, rep) in reputation_changes {
modify_reputation(&mut ctx, peer_id, rep).await; modify_reputation(ctx.sender(), peer_id, rep).await;
} }
}, },
} }
@@ -1304,9 +1277,9 @@ async fn poll_requests(
} }
/// Dequeue another collation and fetch. /// Dequeue another collation and fetch.
async fn dequeue_next_collation_and_fetch( #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
ctx: &mut (impl SubsystemContext<Message = CollatorProtocolMessage> async fn dequeue_next_collation_and_fetch<Context>(
+ overseer::SubsystemContext<Message = CollatorProtocolMessage>), ctx: &mut Context,
state: &mut State, state: &mut State,
relay_parent: Hash, relay_parent: Hash,
// The collator we tried to fetch from last. // The collator we tried to fetch from last.
@@ -1323,7 +1296,7 @@ async fn dequeue_next_collation_and_fetch(
?id, ?id,
"Successfully dequeued next advertisement - fetching ..." "Successfully dequeued next advertisement - fetching ..."
); );
fetch_collation(ctx, state, next, id).await; fetch_collation(ctx.sender(), state, next, id).await;
} else { } else {
gum::debug!( gum::debug!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -1335,14 +1308,12 @@ async fn dequeue_next_collation_and_fetch(
} }
/// Handle a fetched collation result. /// Handle a fetched collation result.
#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)]
async fn handle_collation_fetched_result<Context>( async fn handle_collation_fetched_result<Context>(
ctx: &mut Context, ctx: &mut Context,
state: &mut State, state: &mut State,
(mut collation_event, res): PendingCollationFetch, (mut collation_event, res): PendingCollationFetch,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
// If no prior collation for this relay parent has been seconded, then // If no prior collation for this relay parent has been seconded, then
// memorize the `collation_event` for that `relay_parent`, such that we may // memorize the `collation_event` for that `relay_parent`, such that we may
// notify the collator of their successful second backing // notify the collator of their successful second backing
@@ -1380,12 +1351,13 @@ async fn handle_collation_fetched_result<Context>(
if let Entry::Vacant(entry) = state.pending_candidates.entry(relay_parent) { if let Entry::Vacant(entry) = state.pending_candidates.entry(relay_parent) {
collation_event.1.commitments_hash = Some(candidate_receipt.commitments_hash); collation_event.1.commitments_hash = Some(candidate_receipt.commitments_hash);
ctx.send_message(CandidateBackingMessage::Second( ctx.sender()
relay_parent.clone(), .send_message(CandidateBackingMessage::Second(
candidate_receipt, relay_parent.clone(),
pov, candidate_receipt,
)) pov,
.await; ))
.await;
entry.insert(collation_event); entry.insert(collation_event);
} else { } else {
@@ -1401,18 +1373,15 @@ async fn handle_collation_fetched_result<Context>(
// This issues `NetworkBridge` notifications to disconnect from all inactive peers at the // This issues `NetworkBridge` notifications to disconnect from all inactive peers at the
// earliest possible point. This does not yet clean up any metadata, as that will be done upon // earliest possible point. This does not yet clean up any metadata, as that will be done upon
// receipt of the `PeerDisconnected` event. // receipt of the `PeerDisconnected` event.
async fn disconnect_inactive_peers<Context>( async fn disconnect_inactive_peers(
ctx: &mut Context, sender: &mut impl overseer::CollatorProtocolSenderTrait,
eviction_policy: &crate::CollatorEvictionPolicy, eviction_policy: &crate::CollatorEvictionPolicy,
peers: &HashMap<PeerId, PeerData>, peers: &HashMap<PeerId, PeerData>,
) where ) {
Context: overseer::SubsystemContext<Message = CollatorProtocolMessage>,
Context: SubsystemContext<Message = CollatorProtocolMessage>,
{
for (peer, peer_data) in peers { for (peer, peer_data) in peers {
if peer_data.is_inactive(&eviction_policy) { if peer_data.is_inactive(&eviction_policy) {
gum::trace!(target: LOG_TARGET, "Disconnecting inactive peer"); gum::trace!(target: LOG_TARGET, "Disconnecting inactive peer");
disconnect_peer(ctx, peer.clone()).await; disconnect_peer(sender, peer.clone()).await;
} }
} }
} }
@@ -33,7 +33,7 @@ use polkadot_node_network_protocol::request_response::{incoming::IncomingRequest
use polkadot_node_primitives::DISPUTE_WINDOW; use polkadot_node_primitives::DISPUTE_WINDOW;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::DisputeDistributionMessage, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, messages::DisputeDistributionMessage, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemError, SubsystemError,
}; };
use polkadot_node_subsystem_util::{runtime, runtime::RuntimeInfo}; use polkadot_node_subsystem_util::{runtime, runtime::RuntimeInfo};
@@ -114,12 +114,11 @@ pub struct DisputeDistributionSubsystem<AD> {
metrics: Metrics, metrics: Metrics,
} }
impl<Context, AD> overseer::Subsystem<Context, SubsystemError> for DisputeDistributionSubsystem<AD> #[overseer::subsystem(DisputeDistribution, error = SubsystemError, prefix = self::overseer)]
impl<Context, AD> DisputeDistributionSubsystem<AD>
where where
Context: SubsystemContext<Message = DisputeDistributionMessage> <Context as overseer::DisputeDistributionContextTrait>::Sender:
+ overseer::SubsystemContext<Message = DisputeDistributionMessage> overseer::DisputeDistributionSenderTrait + Sync + Send,
+ Sync
+ Send,
AD: AuthorityDiscovery + Clone, AD: AuthorityDiscovery + Clone,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
@@ -132,6 +131,7 @@ where
} }
} }
#[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
impl<AD> DisputeDistributionSubsystem<AD> impl<AD> DisputeDistributionSubsystem<AD>
where where
AD: AuthorityDiscovery + Clone, AD: AuthorityDiscovery + Clone,
@@ -160,13 +160,7 @@ where
} }
/// Start processing work as passed on from the Overseer. /// Start processing work as passed on from the Overseer.
async fn run<Context>(mut self, mut ctx: Context) -> std::result::Result<(), FatalError> async fn run<Context>(mut self, mut ctx: Context) -> std::result::Result<(), FatalError> {
where
Context: SubsystemContext<Message = DisputeDistributionMessage>
+ overseer::SubsystemContext<Message = DisputeDistributionMessage>
+ Sync
+ Send,
{
let receiver = DisputesReceiver::new( let receiver = DisputesReceiver::new(
ctx.sender().clone(), ctx.sender().clone(),
self.req_receiver self.req_receiver
@@ -205,7 +199,7 @@ where
} }
/// Handle overseer signals. /// Handle overseer signals.
async fn handle_signals<Context: SubsystemContext>( async fn handle_signals<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
signal: OverseerSignal, signal: OverseerSignal,
@@ -221,7 +215,7 @@ where
} }
/// Handle `DisputeDistributionMessage`s. /// Handle `DisputeDistributionMessage`s.
async fn handle_subsystem_message<Context: SubsystemContext>( async fn handle_subsystem_message<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
msg: DisputeDistributionMessage, msg: DisputeDistributionMessage,
@@ -243,10 +237,10 @@ enum MuxedMessage {
Sender(Option<TaskFinish>), Sender(Option<TaskFinish>),
} }
#[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
impl MuxedMessage { impl MuxedMessage {
async fn receive( async fn receive<Context>(
ctx: &mut (impl SubsystemContext<Message = DisputeDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = DisputeDistributionMessage>),
from_sender: &mut mpsc::Receiver<TaskFinish>, from_sender: &mut mpsc::Receiver<TaskFinish>,
) -> Self { ) -> Self {
// We are only fusing here to make `select` happy, in reality we will quit if the stream // We are only fusing here to make `select` happy, in reality we will quit if the stream
@@ -40,8 +40,8 @@ use polkadot_node_network_protocol::{
}; };
use polkadot_node_primitives::DISPUTE_WINDOW; use polkadot_node_primitives::DISPUTE_WINDOW;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::{AllMessages, DisputeCoordinatorMessage, ImportStatementsResult}, messages::{DisputeCoordinatorMessage, ImportStatementsResult},
SubsystemSender, overseer,
}; };
use polkadot_node_subsystem_util::{runtime, runtime::RuntimeInfo}; use polkadot_node_subsystem_util::{runtime, runtime::RuntimeInfo};
@@ -132,9 +132,10 @@ impl MuxedMessage {
} }
} }
impl<Sender: SubsystemSender, AD> DisputesReceiver<Sender, AD> impl<Sender, AD> DisputesReceiver<Sender, AD>
where where
AD: AuthorityDiscovery, AD: AuthorityDiscovery,
Sender: overseer::DisputeDistributionSenderTrait,
{ {
/// Create a new receiver which can be `run`. /// Create a new receiver which can be `run`.
pub fn new( pub fn new(
@@ -265,15 +266,13 @@ where
let (pending_confirmation, confirmation_rx) = oneshot::channel(); let (pending_confirmation, confirmation_rx) = oneshot::channel();
let candidate_hash = candidate_receipt.hash(); let candidate_hash = candidate_receipt.hash();
self.sender self.sender
.send_message(AllMessages::DisputeCoordinator( .send_message(DisputeCoordinatorMessage::ImportStatements {
DisputeCoordinatorMessage::ImportStatements { candidate_hash,
candidate_hash, candidate_receipt,
candidate_receipt, session: valid_vote.0.session_index(),
session: valid_vote.0.session_index(), statements: vec![valid_vote, invalid_vote],
statements: vec![valid_vote, invalid_vote], pending_confirmation: Some(pending_confirmation),
pending_confirmation: Some(pending_confirmation), })
},
))
.await; .await;
self.pending_imports.push(peer, confirmation_rx, pending_response); self.pending_imports.push(peer, confirmation_rx, pending_response);
@@ -20,10 +20,7 @@ use futures::channel::{mpsc, oneshot};
use polkadot_node_network_protocol::request_response::v1::DisputeRequest; use polkadot_node_network_protocol::request_response::v1::DisputeRequest;
use polkadot_node_primitives::{CandidateVotes, DisputeMessage, SignedDisputeStatement}; use polkadot_node_primitives::{CandidateVotes, DisputeMessage, SignedDisputeStatement};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{messages::DisputeCoordinatorMessage, overseer, ActiveLeavesUpdate};
messages::{AllMessages, DisputeCoordinatorMessage},
ActiveLeavesUpdate, SubsystemContext,
};
use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_node_subsystem_util::runtime::RuntimeInfo;
use polkadot_primitives::v2::{CandidateHash, DisputeStatement, Hash, SessionIndex}; use polkadot_primitives::v2::{CandidateHash, DisputeStatement, Hash, SessionIndex};
@@ -66,6 +63,7 @@ pub struct DisputeSender {
metrics: Metrics, metrics: Metrics,
} }
#[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
impl DisputeSender { impl DisputeSender {
/// Create a new `DisputeSender` which can be used to start dispute sendings. /// Create a new `DisputeSender` which can be used to start dispute sendings.
pub fn new(tx: mpsc::Sender<TaskFinish>, metrics: Metrics) -> Self { pub fn new(tx: mpsc::Sender<TaskFinish>, metrics: Metrics) -> Self {
@@ -79,7 +77,7 @@ impl DisputeSender {
} }
/// Create a `SendTask` for a particular new dispute. /// Create a `SendTask` for a particular new dispute.
pub async fn start_sender<Context: SubsystemContext>( pub async fn start_sender<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -114,7 +112,7 @@ impl DisputeSender {
/// - Get new authorities to send messages to. /// - Get new authorities to send messages to.
/// - Get rid of obsolete tasks and disputes. /// - Get rid of obsolete tasks and disputes.
/// - Get dispute sending started in case we missed one for some reason (e.g. on node startup) /// - Get dispute sending started in case we missed one for some reason (e.g. on node startup)
pub async fn update_leaves<Context: SubsystemContext>( pub async fn update_leaves<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -179,7 +177,7 @@ impl DisputeSender {
/// Call `start_sender` on all passed in disputes. /// Call `start_sender` on all passed in disputes.
/// ///
/// Recover necessary votes for building up `DisputeMessage` and start sending for all of them. /// Recover necessary votes for building up `DisputeMessage` and start sending for all of them.
async fn start_send_for_dispute<Context: SubsystemContext>( async fn start_send_for_dispute<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -303,7 +301,7 @@ impl DisputeSender {
/// Make active sessions correspond to currently active heads. /// Make active sessions correspond to currently active heads.
/// ///
/// Returns: true if sessions changed. /// Returns: true if sessions changed.
async fn refresh_sessions<Context: SubsystemContext>( async fn refresh_sessions<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -321,7 +319,8 @@ impl DisputeSender {
/// Retrieve the currently active sessions. /// Retrieve the currently active sessions.
/// ///
/// List is all indices of all active sessions together with the head that was used for the query. /// List is all indices of all active sessions together with the head that was used for the query.
async fn get_active_session_indices<Context: SubsystemContext>( #[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
async fn get_active_session_indices<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
active_heads: &Vec<Hash>, active_heads: &Vec<Hash>,
@@ -336,27 +335,29 @@ async fn get_active_session_indices<Context: SubsystemContext>(
} }
/// Retrieve Set of active disputes from the dispute coordinator. /// Retrieve Set of active disputes from the dispute coordinator.
async fn get_active_disputes<Context: SubsystemContext>( #[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
async fn get_active_disputes<Context>(
ctx: &mut Context, ctx: &mut Context,
) -> JfyiErrorResult<Vec<(SessionIndex, CandidateHash)>> { ) -> JfyiErrorResult<Vec<(SessionIndex, CandidateHash)>> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// Caller scope is in `update_leaves` and this is bounded by fork count. // Caller scope is in `update_leaves` and this is bounded by fork count.
ctx.send_unbounded_message(AllMessages::DisputeCoordinator( ctx.send_unbounded_message(DisputeCoordinatorMessage::ActiveDisputes(tx));
DisputeCoordinatorMessage::ActiveDisputes(tx),
));
rx.await.map_err(|_| JfyiError::AskActiveDisputesCanceled) rx.await.map_err(|_| JfyiError::AskActiveDisputesCanceled)
} }
/// Get all locally available dispute votes for a given dispute. /// Get all locally available dispute votes for a given dispute.
async fn get_candidate_votes<Context: SubsystemContext>( #[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
async fn get_candidate_votes<Context>(
ctx: &mut Context, ctx: &mut Context,
session_index: SessionIndex, session_index: SessionIndex,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
) -> JfyiErrorResult<Option<CandidateVotes>> { ) -> JfyiErrorResult<Option<CandidateVotes>> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// Caller scope is in `update_leaves` and this is bounded by fork count. // Caller scope is in `update_leaves` and this is bounded by fork count.
ctx.send_unbounded_message(AllMessages::DisputeCoordinator( ctx.send_unbounded_message(DisputeCoordinatorMessage::QueryCandidateVotes(
DisputeCoordinatorMessage::QueryCandidateVotes(vec![(session_index, candidate_hash)], tx), vec![(session_index, candidate_hash)],
tx,
)); ));
rx.await rx.await
.map(|v| v.get(0).map(|inner| inner.to_owned().2)) .map(|v| v.get(0).map(|inner| inner.to_owned().2))
@@ -26,10 +26,7 @@ use polkadot_node_network_protocol::{
}, },
IfDisconnected, IfDisconnected,
}; };
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{messages::NetworkBridgeMessage, overseer};
messages::{AllMessages, NetworkBridgeMessage},
SubsystemContext,
};
use polkadot_node_subsystem_util::{metrics, runtime::RuntimeInfo}; use polkadot_node_subsystem_util::{metrics, runtime::RuntimeInfo};
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
AuthorityDiscoveryId, CandidateHash, Hash, SessionIndex, ValidatorIndex, AuthorityDiscoveryId, CandidateHash, Hash, SessionIndex, ValidatorIndex,
@@ -100,9 +97,10 @@ impl TaskResult {
} }
} }
#[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
impl SendTask { impl SendTask {
/// Initiates sending a dispute message to peers. /// Initiates sending a dispute message to peers.
pub async fn new<Context: SubsystemContext>( pub async fn new<Context>(
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
active_sessions: &HashMap<SessionIndex, Hash>, active_sessions: &HashMap<SessionIndex, Hash>,
@@ -120,7 +118,7 @@ impl SendTask {
/// ///
/// This function is called at construction and should also be called whenever a session change /// This function is called at construction and should also be called whenever a session change
/// happens and on a regular basis to ensure we are retrying failed attempts. /// happens and on a regular basis to ensure we are retrying failed attempts.
pub async fn refresh_sends<Context: SubsystemContext>( pub async fn refresh_sends<Context>(
&mut self, &mut self,
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -197,7 +195,8 @@ impl SendTask {
/// ///
/// This is all parachain validators of the session the candidate occurred and all authorities /// This is all parachain validators of the session the candidate occurred and all authorities
/// of all currently active sessions, determined by currently active heads. /// of all currently active sessions, determined by currently active heads.
async fn get_relevant_validators<Context: SubsystemContext>(
async fn get_relevant_validators<Context>(
&self, &self,
ctx: &mut Context, ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
@@ -241,7 +240,8 @@ impl SendTask {
/// Start sending of the given message to all given authorities. /// Start sending of the given message to all given authorities.
/// ///
/// And spawn tasks for handling the response. /// And spawn tasks for handling the response.
async fn send_requests<Context: SubsystemContext>( #[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)]
async fn send_requests<Context>(
ctx: &mut Context, ctx: &mut Context,
tx: mpsc::Sender<TaskFinish>, tx: mpsc::Sender<TaskFinish>,
receivers: Vec<AuthorityDiscoveryId>, receivers: Vec<AuthorityDiscoveryId>,
@@ -271,7 +271,7 @@ async fn send_requests<Context: SubsystemContext>(
} }
let msg = NetworkBridgeMessage::SendRequests(reqs, IfDisconnected::ImmediateError); let msg = NetworkBridgeMessage::SendRequests(reqs, IfDisconnected::ImmediateError);
ctx.send_message(AllMessages::NetworkBridge(msg)).await; ctx.send_message(msg).await;
Ok(statuses) Ok(statuses)
} }
+43 -59
View File
@@ -48,8 +48,7 @@ use polkadot_node_subsystem::{
GossipSupportMessage, NetworkBridgeEvent, NetworkBridgeMessage, RuntimeApiMessage, GossipSupportMessage, NetworkBridgeEvent, NetworkBridgeMessage, RuntimeApiMessage,
RuntimeApiRequest, RuntimeApiRequest,
}, },
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
SubsystemError,
}; };
use polkadot_node_subsystem_util as util; use polkadot_node_subsystem_util as util;
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
@@ -115,6 +114,7 @@ pub struct GossipSupport<AD> {
metrics: Metrics, metrics: Metrics,
} }
#[overseer::contextbounds(GossipSupport, prefix = self::overseer)]
impl<AD> GossipSupport<AD> impl<AD> GossipSupport<AD>
where where
AD: AuthorityDiscovery, AD: AuthorityDiscovery,
@@ -138,11 +138,7 @@ where
} }
} }
async fn run<Context>(mut self, mut ctx: Context) -> Self async fn run<Context>(mut self, mut ctx: Context) -> Self {
where
Context: SubsystemContext<Message = GossipSupportMessage>,
Context: overseer::SubsystemContext<Message = GossipSupportMessage>,
{
fn get_connectivity_check_delay() -> Delay { fn get_connectivity_check_delay() -> Delay {
Delay::new(LOW_CONNECTIVITY_WARN_DELAY) Delay::new(LOW_CONNECTIVITY_WARN_DELAY)
} }
@@ -178,7 +174,7 @@ where
gum::trace!(target: LOG_TARGET, "active leaves signal"); gum::trace!(target: LOG_TARGET, "active leaves signal");
let leaves = activated.into_iter().map(|a| a.hash); let leaves = activated.into_iter().map(|a| a.hash);
if let Err(e) = self.handle_active_leaves(&mut ctx, leaves).await { if let Err(e) = self.handle_active_leaves(ctx.sender(), leaves).await {
gum::debug!(target: LOG_TARGET, error = ?e); gum::debug!(target: LOG_TARGET, error = ?e);
} }
}, },
@@ -191,18 +187,13 @@ where
/// 1. Determine if the current session index has changed. /// 1. Determine if the current session index has changed.
/// 2. If it has, determine relevant validators /// 2. If it has, determine relevant validators
/// and issue a connection request. /// and issue a connection request.
async fn handle_active_leaves<Context>( async fn handle_active_leaves(
&mut self, &mut self,
ctx: &mut Context, sender: &mut impl overseer::GossipSupportSenderTrait,
leaves: impl Iterator<Item = Hash>, leaves: impl Iterator<Item = Hash>,
) -> Result<(), util::Error> ) -> Result<(), util::Error> {
where
Context: SubsystemContext<Message = GossipSupportMessage>,
Context: overseer::SubsystemContext<Message = GossipSupportMessage>,
{
for leaf in leaves { for leaf in leaves {
let current_index = let current_index = util::request_session_index_for_child(leaf, sender).await.await??;
util::request_session_index_for_child(leaf, ctx.sender()).await.await??;
let since_failure = self.last_failure.map(|i| i.elapsed()).unwrap_or_default(); let since_failure = self.last_failure.map(|i| i.elapsed()).unwrap_or_default();
let force_request = since_failure >= BACKOFF_DURATION; let force_request = since_failure >= BACKOFF_DURATION;
let leaf_session = Some((current_index, leaf)); let leaf_session = Some((current_index, leaf));
@@ -216,7 +207,7 @@ where
if let Some((session_index, relay_parent)) = maybe_issue_connection { if let Some((session_index, relay_parent)) = maybe_issue_connection {
let session_info = let session_info =
util::request_session_info(leaf, session_index, ctx.sender()).await.await??; util::request_session_info(leaf, session_index, sender).await.await??;
let session_info = match session_info { let session_info = match session_info {
Some(s) => s, Some(s) => s,
@@ -255,13 +246,13 @@ where
// by virtue of a new session being entered. Therefore we maintain // by virtue of a new session being entered. Therefore we maintain
// connections to a much broader set of validators. // connections to a much broader set of validators.
{ {
let mut connections = authorities_past_present_future(ctx, leaf).await?; let mut connections = authorities_past_present_future(sender, leaf).await?;
// Remove all of our locally controlled validator indices so we don't connect to ourself. // Remove all of our locally controlled validator indices so we don't connect to ourself.
// If we control none of them, don't issue connection requests - we're outside // If we control none of them, don't issue connection requests - we're outside
// of the 'clique' of recent validators. // of the 'clique' of recent validators.
if remove_all_controlled(&self.keystore, &mut connections).await != 0 { if remove_all_controlled(&self.keystore, &mut connections).await != 0 {
self.issue_connection_request(ctx, connections).await; self.issue_connection_request(sender, connections).await;
} }
} }
@@ -273,7 +264,7 @@ where
self.update_authority_status_metrics(&session_info).await; self.update_authority_status_metrics(&session_info).await;
update_gossip_topology( update_gossip_topology(
ctx, sender,
our_index, our_index,
session_info.discovery_keys, session_info.discovery_keys,
relay_parent, relay_parent,
@@ -317,13 +308,12 @@ where
} }
} }
async fn issue_connection_request<Context>( async fn issue_connection_request<Sender>(
&mut self, &mut self,
ctx: &mut Context, sender: &mut Sender,
authorities: Vec<AuthorityDiscoveryId>, authorities: Vec<AuthorityDiscoveryId>,
) where ) where
Context: SubsystemContext<Message = GossipSupportMessage>, Sender: overseer::GossipSupportSenderTrait,
Context: overseer::SubsystemContext<Message = GossipSupportMessage>,
{ {
let num = authorities.len(); let num = authorities.len();
let mut validator_addrs = Vec::with_capacity(authorities.len()); let mut validator_addrs = Vec::with_capacity(authorities.len());
@@ -347,11 +337,12 @@ where
self.resolved_authorities = resolved; self.resolved_authorities = resolved;
gum::debug!(target: LOG_TARGET, %num, "Issuing a connection request"); gum::debug!(target: LOG_TARGET, %num, "Issuing a connection request");
ctx.send_message(NetworkBridgeMessage::ConnectToResolvedValidators { sender
validator_addrs, .send_message(NetworkBridgeMessage::ConnectToResolvedValidators {
peer_set: PeerSet::Validation, validator_addrs,
}) peer_set: PeerSet::Validation,
.await; })
.await;
// issue another request for the same session // issue another request for the same session
// if at least a third of the authorities were not resolved. // if at least a third of the authorities were not resolved.
@@ -442,15 +433,11 @@ where
} }
// Get the authorities of the past, present, and future. // Get the authorities of the past, present, and future.
async fn authorities_past_present_future<Context>( async fn authorities_past_present_future(
ctx: &mut Context, sender: &mut impl overseer::GossipSupportSenderTrait,
relay_parent: Hash, relay_parent: Hash,
) -> Result<Vec<AuthorityDiscoveryId>, util::Error> ) -> Result<Vec<AuthorityDiscoveryId>, util::Error> {
where let authorities = util::request_authorities(relay_parent, sender).await.await??;
Context: SubsystemContext<Message = GossipSupportMessage>,
Context: overseer::SubsystemContext<Message = GossipSupportMessage>,
{
let authorities = util::request_authorities(relay_parent, ctx.sender()).await.await??;
gum::debug!( gum::debug!(
target: LOG_TARGET, target: LOG_TARGET,
authority_count = ?authorities.len(), authority_count = ?authorities.len(),
@@ -500,28 +487,25 @@ async fn remove_all_controlled(
/// This limits the amount of gossip peers to 2 * `sqrt(len)` and ensures the diameter of 2. /// This limits the amount of gossip peers to 2 * `sqrt(len)` and ensures the diameter of 2.
/// ///
/// [web3]: https://research.web3.foundation/en/latest/polkadot/networking/3-avail-valid.html#topology /// [web3]: https://research.web3.foundation/en/latest/polkadot/networking/3-avail-valid.html#topology
async fn update_gossip_topology<Context>( async fn update_gossip_topology(
ctx: &mut Context, sender: &mut impl overseer::GossipSupportSenderTrait,
our_index: usize, our_index: usize,
authorities: Vec<AuthorityDiscoveryId>, authorities: Vec<AuthorityDiscoveryId>,
relay_parent: Hash, relay_parent: Hash,
session_index: SessionIndex, session_index: SessionIndex,
) -> Result<(), util::Error> ) -> Result<(), util::Error> {
where
Context: SubsystemContext<Message = GossipSupportMessage>,
Context: overseer::SubsystemContext<Message = GossipSupportMessage>,
{
// retrieve BABE randomness // retrieve BABE randomness
let random_seed = { let random_seed = {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// TODO https://github.com/paritytech/polkadot/issues/5316: // TODO https://github.com/paritytech/polkadot/issues/5316:
// get the random seed from the `SessionInfo` instead. // get the random seed from the `SessionInfo` instead.
ctx.send_message(RuntimeApiMessage::Request( sender
relay_parent, .send_message(RuntimeApiMessage::Request(
RuntimeApiRequest::CurrentBabeEpoch(tx), relay_parent,
)) RuntimeApiRequest::CurrentBabeEpoch(tx),
.await; ))
.await;
let randomness = rx.await??.randomness; let randomness = rx.await??.randomness;
let mut subject = [0u8; 40]; let mut subject = [0u8; 40];
@@ -553,12 +537,13 @@ where
.map(|i| (authorities[i].clone(), ValidatorIndex::from(i as u32))) .map(|i| (authorities[i].clone(), ValidatorIndex::from(i as u32)))
.collect(); .collect();
ctx.send_message(NetworkBridgeMessage::NewGossipTopology { sender
session: session_index, .send_message(NetworkBridgeMessage::NewGossipTopology {
our_neighbors_x: row_neighbors, session: session_index,
our_neighbors_y: column_neighbors, our_neighbors_x: row_neighbors,
}) our_neighbors_y: column_neighbors,
.await; })
.await;
Ok(()) Ok(())
} }
@@ -596,10 +581,9 @@ fn matrix_neighbors(
} }
} }
impl<Context, AD> overseer::Subsystem<Context, SubsystemError> for GossipSupport<AD> #[overseer::subsystem(GossipSupport, error = SubsystemError, prefix = self::overseer)]
impl<Context, AD> GossipSupport<AD>
where where
Context: SubsystemContext<Message = GossipSupportMessage>,
Context: overseer::SubsystemContext<Message = GossipSupportMessage>,
AD: AuthorityDiscovery + Clone, AD: AuthorityDiscovery + Clone,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
@@ -38,11 +38,11 @@ use polkadot_node_subsystem_util::{self as util, rand, MIN_GOSSIP_PEERS};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{ messages::{
AllMessages, CandidateBackingMessage, NetworkBridgeEvent, NetworkBridgeMessage, CandidateBackingMessage, NetworkBridgeEvent, NetworkBridgeMessage,
StatementDistributionMessage, StatementDistributionMessage,
}, },
overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, PerLeafSpan, SpawnedSubsystem, overseer, ActiveLeavesUpdate, FromOverseer, OverseerSignal, PerLeafSpan, SpawnedSubsystem,
SubsystemContext, SubsystemError, SubsystemError,
}; };
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
AuthorityDiscoveryId, CandidateHash, CommittedCandidateReceipt, CompactStatement, Hash, AuthorityDiscoveryId, CandidateHash, CommittedCandidateReceipt, CompactStatement, Hash,
@@ -127,12 +127,8 @@ pub struct StatementDistributionSubsystem<R> {
rng: R, rng: R,
} }
impl<Context, R: rand::Rng + Send + Sync + 'static> overseer::Subsystem<Context, SubsystemError> #[overseer::subsystem(StatementDistribution, error=SubsystemError, prefix=self::overseer)]
for StatementDistributionSubsystem<R> impl<Context, R: rand::Rng + Send + Sync + 'static> StatementDistributionSubsystem<R> {
where
Context: SubsystemContext<Message = StatementDistributionMessage>,
Context: overseer::SubsystemContext<Message = StatementDistributionMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
// Swallow error because failure is fatal to the node and we log with more precision // Swallow error because failure is fatal to the node and we log with more precision
// within `run`. // within `run`.
@@ -630,10 +626,10 @@ enum MuxedMessage {
Responder(Option<ResponderMessage>), Responder(Option<ResponderMessage>),
} }
#[overseer::contextbounds(StatementDistribution, prefix = self::overseer)]
impl MuxedMessage { impl MuxedMessage {
async fn receive( async fn receive<Context>(
ctx: &mut (impl SubsystemContext<Message = StatementDistributionMessage> ctx: &mut Context,
+ overseer::SubsystemContext<Message = StatementDistributionMessage>),
from_requester: &mut mpsc::Receiver<RequesterMessage>, from_requester: &mut mpsc::Receiver<RequesterMessage>,
from_responder: &mut mpsc::Receiver<ResponderMessage>, from_responder: &mut mpsc::Receiver<ResponderMessage>,
) -> MuxedMessage { ) -> MuxedMessage {
@@ -890,11 +886,12 @@ fn check_statement_signature(
/// circulates the statement to all peers who have not seen it yet, and /// circulates the statement to all peers who have not seen it yet, and
/// sends all statements dependent on that statement to peers who could previously not receive /// sends all statements dependent on that statement to peers who could previously not receive
/// them but now can. /// them but now can.
async fn circulate_statement_and_dependents( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn circulate_statement_and_dependents<Context>(
gossip_peers: &HashSet<PeerId>, gossip_peers: &HashSet<PeerId>,
peers: &mut HashMap<PeerId, PeerData>, peers: &mut HashMap<PeerId, PeerData>,
active_heads: &mut HashMap<Hash, ActiveHeadData>, active_heads: &mut HashMap<Hash, ActiveHeadData>,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
relay_parent: Hash, relay_parent: Hash,
statement: SignedFullStatement, statement: SignedFullStatement,
priority_peers: Vec<PeerId>, priority_peers: Vec<PeerId>,
@@ -1006,10 +1003,11 @@ fn is_statement_large(statement: &SignedFullStatement) -> (bool, Option<usize>)
/// Circulates a statement to all peers who have not seen it yet, and returns /// Circulates a statement to all peers who have not seen it yet, and returns
/// an iterator over peers who need to have dependent statements sent. /// an iterator over peers who need to have dependent statements sent.
async fn circulate_statement<'a>( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn circulate_statement<'a, Context>(
gossip_peers: &HashSet<PeerId>, gossip_peers: &HashSet<PeerId>,
peers: &mut HashMap<PeerId, PeerData>, peers: &mut HashMap<PeerId, PeerData>,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
relay_parent: Hash, relay_parent: Hash,
stored: StoredStatement<'a>, stored: StoredStatement<'a>,
mut priority_peers: Vec<PeerId>, mut priority_peers: Vec<PeerId>,
@@ -1081,10 +1079,10 @@ async fn circulate_statement<'a>(
statement = ?stored.statement, statement = ?stored.statement,
"Sending statement", "Sending statement",
); );
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage( ctx.send_message(NetworkBridgeMessage::SendValidationMessage(
peers_to_send.iter().map(|(p, _)| p.clone()).collect(), peers_to_send.iter().map(|(p, _)| p.clone()).collect(),
payload, payload,
))) ))
.await; .await;
} }
@@ -1095,10 +1093,11 @@ async fn circulate_statement<'a>(
} }
/// Send all statements about a given candidate hash to a peer. /// Send all statements about a given candidate hash to a peer.
async fn send_statements_about( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn send_statements_about<Context>(
peer: PeerId, peer: PeerId,
peer_data: &mut PeerData, peer_data: &mut PeerData,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
relay_parent: Hash, relay_parent: Hash,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
active_head: &ActiveHeadData, active_head: &ActiveHeadData,
@@ -1120,21 +1119,19 @@ async fn send_statements_about(
statement = ?statement.statement, statement = ?statement.statement,
"Sending statement", "Sending statement",
); );
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage( ctx.send_message(NetworkBridgeMessage::SendValidationMessage(vec![peer.clone()], payload))
vec![peer.clone()], .await;
payload,
)))
.await;
metrics.on_statement_distributed(); metrics.on_statement_distributed();
} }
} }
/// Send all statements at a given relay-parent to a peer. /// Send all statements at a given relay-parent to a peer.
async fn send_statements( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn send_statements<Context>(
peer: PeerId, peer: PeerId,
peer_data: &mut PeerData, peer_data: &mut PeerData,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
relay_parent: Hash, relay_parent: Hash,
active_head: &ActiveHeadData, active_head: &ActiveHeadData,
metrics: &Metrics, metrics: &Metrics,
@@ -1154,23 +1151,19 @@ async fn send_statements(
statement = ?statement.statement, statement = ?statement.statement,
"Sending statement" "Sending statement"
); );
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage( ctx.send_message(NetworkBridgeMessage::SendValidationMessage(vec![peer.clone()], payload))
vec![peer.clone()], .await;
payload,
)))
.await;
metrics.on_statement_distributed(); metrics.on_statement_distributed();
} }
} }
async fn report_peer( async fn report_peer(
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), sender: &mut impl overseer::StatementDistributionSenderTrait,
peer: PeerId, peer: PeerId,
rep: Rep, rep: Rep,
) { ) {
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::ReportPeer(peer, rep))) sender.send_message(NetworkBridgeMessage::ReportPeer(peer, rep)).await
.await
} }
/// If message contains a statement, then retrieve it, otherwise fork task to fetch it. /// If message contains a statement, then retrieve it, otherwise fork task to fetch it.
@@ -1180,11 +1173,12 @@ async fn report_peer(
/// your statement. /// your statement.
/// ///
/// If the message was large, but the result has been fetched already that one is returned. /// If the message was large, but the result has been fetched already that one is returned.
async fn retrieve_statement_from_message<'a>( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn retrieve_statement_from_message<'a, Context>(
peer: PeerId, peer: PeerId,
message: protocol_v1::StatementDistributionMessage, message: protocol_v1::StatementDistributionMessage,
active_head: &'a mut ActiveHeadData, active_head: &'a mut ActiveHeadData,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
req_sender: &mpsc::Sender<RequesterMessage>, req_sender: &mpsc::Sender<RequesterMessage>,
metrics: &Metrics, metrics: &Metrics,
) -> Option<UncheckedSignedFullStatement> { ) -> Option<UncheckedSignedFullStatement> {
@@ -1272,11 +1266,12 @@ async fn retrieve_statement_from_message<'a>(
/// Launch request for a large statement and get tracking status. /// Launch request for a large statement and get tracking status.
/// ///
/// Returns `None` if spawning task failed. /// Returns `None` if spawning task failed.
async fn launch_request( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn launch_request<Context>(
meta: StatementMetadata, meta: StatementMetadata,
peer: PeerId, peer: PeerId,
req_sender: mpsc::Sender<RequesterMessage>, req_sender: mpsc::Sender<RequesterMessage>,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
metrics: &Metrics, metrics: &Metrics,
) -> Option<LargeStatementStatus> { ) -> Option<LargeStatementStatus> {
let (task, handle) = let (task, handle) =
@@ -1302,19 +1297,21 @@ async fn launch_request(
} }
/// Handle incoming message and circulate it to peers, if we did not know it already. /// Handle incoming message and circulate it to peers, if we did not know it already.
/// #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn handle_incoming_message_and_circulate<'a>( async fn handle_incoming_message_and_circulate<'a, Context, R>(
peer: PeerId, peer: PeerId,
gossip_peers: &HashSet<PeerId>, gossip_peers: &HashSet<PeerId>,
peers: &mut HashMap<PeerId, PeerData>, peers: &mut HashMap<PeerId, PeerData>,
active_heads: &'a mut HashMap<Hash, ActiveHeadData>, active_heads: &'a mut HashMap<Hash, ActiveHeadData>,
recent_outdated_heads: &RecentOutdatedHeads, recent_outdated_heads: &RecentOutdatedHeads,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
message: protocol_v1::StatementDistributionMessage, message: protocol_v1::StatementDistributionMessage,
req_sender: &mpsc::Sender<RequesterMessage>, req_sender: &mpsc::Sender<RequesterMessage>,
metrics: &Metrics, metrics: &Metrics,
rng: &mut impl rand::Rng, rng: &mut R,
) { ) where
R: rand::Rng,
{
let handled_incoming = match peers.get_mut(&peer) { let handled_incoming = match peers.get_mut(&peer) {
Some(data) => Some(data) =>
handle_incoming_message( handle_incoming_message(
@@ -1360,12 +1357,13 @@ async fn handle_incoming_message_and_circulate<'a>(
// //
// This function checks the signature and ensures the statement is compatible with our // This function checks the signature and ensures the statement is compatible with our
// view. It also notifies candidate backing if the statement was previously unknown. // view. It also notifies candidate backing if the statement was previously unknown.
async fn handle_incoming_message<'a>( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn handle_incoming_message<'a, Context>(
peer: PeerId, peer: PeerId,
peer_data: &mut PeerData, peer_data: &mut PeerData,
active_heads: &'a mut HashMap<Hash, ActiveHeadData>, active_heads: &'a mut HashMap<Hash, ActiveHeadData>,
recent_outdated_heads: &RecentOutdatedHeads, recent_outdated_heads: &RecentOutdatedHeads,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
message: protocol_v1::StatementDistributionMessage, message: protocol_v1::StatementDistributionMessage,
req_sender: &mpsc::Sender<RequesterMessage>, req_sender: &mpsc::Sender<RequesterMessage>,
metrics: &Metrics, metrics: &Metrics,
@@ -1383,7 +1381,7 @@ async fn handle_incoming_message<'a>(
); );
if !recent_outdated_heads.is_recent_outdated(&relay_parent) { if !recent_outdated_heads.is_recent_outdated(&relay_parent) {
report_peer(ctx, peer, COST_UNEXPECTED_STATEMENT).await; report_peer(ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await;
} }
return None return None
@@ -1393,7 +1391,7 @@ async fn handle_incoming_message<'a>(
if let protocol_v1::StatementDistributionMessage::LargeStatement(_) = message { if let protocol_v1::StatementDistributionMessage::LargeStatement(_) = message {
if let Err(rep) = peer_data.receive_large_statement(&relay_parent) { if let Err(rep) = peer_data.receive_large_statement(&relay_parent) {
gum::debug!(target: LOG_TARGET, ?peer, ?message, ?rep, "Unexpected large statement.",); gum::debug!(target: LOG_TARGET, ?peer, ?message, ?rep, "Unexpected large statement.",);
report_peer(ctx, peer, rep).await; report_peer(ctx.sender(), peer, rep).await;
return None return None
} }
} }
@@ -1434,16 +1432,16 @@ async fn handle_incoming_message<'a>(
// Report peer merely if this is not a duplicate out-of-view statement that // Report peer merely if this is not a duplicate out-of-view statement that
// was caused by a missing Seconded statement from this peer // was caused by a missing Seconded statement from this peer
if unexpected_count == 0_usize { if unexpected_count == 0_usize {
report_peer(ctx, peer, rep).await; report_peer(ctx.sender(), peer, rep).await;
} }
}, },
// This happens when we have an unexpected remote peer that announced Seconded // This happens when we have an unexpected remote peer that announced Seconded
COST_UNEXPECTED_STATEMENT_REMOTE => { COST_UNEXPECTED_STATEMENT_REMOTE => {
metrics.on_unexpected_statement_seconded(); metrics.on_unexpected_statement_seconded();
report_peer(ctx, peer, rep).await; report_peer(ctx.sender(), peer, rep).await;
}, },
_ => { _ => {
report_peer(ctx, peer, rep).await; report_peer(ctx.sender(), peer, rep).await;
}, },
} }
@@ -1464,7 +1462,7 @@ async fn handle_incoming_message<'a>(
peer_data peer_data
.receive(&relay_parent, &fingerprint, max_message_count) .receive(&relay_parent, &fingerprint, max_message_count)
.expect("checked in `check_can_receive` above; qed"); .expect("checked in `check_can_receive` above; qed");
report_peer(ctx, peer, BENEFIT_VALID_STATEMENT).await; report_peer(ctx.sender(), peer, BENEFIT_VALID_STATEMENT).await;
return None return None
}, },
@@ -1474,7 +1472,7 @@ async fn handle_incoming_message<'a>(
match check_statement_signature(&active_head, relay_parent, unchecked_compact) { match check_statement_signature(&active_head, relay_parent, unchecked_compact) {
Err(statement) => { Err(statement) => {
gum::debug!(target: LOG_TARGET, ?peer, ?statement, "Invalid statement signature"); gum::debug!(target: LOG_TARGET, ?peer, ?statement, "Invalid statement signature");
report_peer(ctx, peer, COST_INVALID_SIGNATURE).await; report_peer(ctx.sender(), peer, COST_INVALID_SIGNATURE).await;
return None return None
}, },
Ok(statement) => statement, Ok(statement) => statement,
@@ -1500,7 +1498,7 @@ async fn handle_incoming_message<'a>(
is_large_statement, is_large_statement,
"Full statement had bad payload." "Full statement had bad payload."
); );
report_peer(ctx, peer, COST_WRONG_HASH).await; report_peer(ctx.sender(), peer, COST_WRONG_HASH).await;
return None return None
}, },
Ok(statement) => statement, Ok(statement) => statement,
@@ -1539,7 +1537,7 @@ async fn handle_incoming_message<'a>(
unreachable!("checked in `is_useful_or_unknown` above; qed"); unreachable!("checked in `is_useful_or_unknown` above; qed");
}, },
NotedStatement::Fresh(statement) => { NotedStatement::Fresh(statement) => {
report_peer(ctx, peer, BENEFIT_VALID_STATEMENT_FIRST).await; report_peer(ctx.sender(), peer, BENEFIT_VALID_STATEMENT_FIRST).await;
let mut _span = handle_incoming_span.child("notify-backing"); let mut _span = handle_incoming_span.child("notify-backing");
@@ -1557,16 +1555,19 @@ async fn handle_incoming_message<'a>(
} }
/// Update a peer's view. Sends all newly unlocked statements based on the previous /// Update a peer's view. Sends all newly unlocked statements based on the previous
async fn update_peer_view_and_maybe_send_unlocked( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn update_peer_view_and_maybe_send_unlocked<Context, R>(
peer: PeerId, peer: PeerId,
gossip_peers: &HashSet<PeerId>, gossip_peers: &HashSet<PeerId>,
peer_data: &mut PeerData, peer_data: &mut PeerData,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
active_heads: &HashMap<Hash, ActiveHeadData>, active_heads: &HashMap<Hash, ActiveHeadData>,
new_view: View, new_view: View,
metrics: &Metrics, metrics: &Metrics,
rng: &mut impl rand::Rng, rng: &mut R,
) { ) where
R: rand::Rng,
{
let old_view = std::mem::replace(&mut peer_data.view, new_view); let old_view = std::mem::replace(&mut peer_data.view, new_view);
// Remove entries for all relay-parents in the old view but not the new. // Remove entries for all relay-parents in the old view but not the new.
@@ -1596,18 +1597,21 @@ async fn update_peer_view_and_maybe_send_unlocked(
} }
} }
async fn handle_network_update( #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)]
async fn handle_network_update<Context, R>(
peers: &mut HashMap<PeerId, PeerData>, peers: &mut HashMap<PeerId, PeerData>,
gossip_peers: &mut HashSet<PeerId>, gossip_peers: &mut HashSet<PeerId>,
authorities: &mut HashMap<AuthorityDiscoveryId, PeerId>, authorities: &mut HashMap<AuthorityDiscoveryId, PeerId>,
active_heads: &mut HashMap<Hash, ActiveHeadData>, active_heads: &mut HashMap<Hash, ActiveHeadData>,
recent_outdated_heads: &RecentOutdatedHeads, recent_outdated_heads: &RecentOutdatedHeads,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
req_sender: &mpsc::Sender<RequesterMessage>, req_sender: &mpsc::Sender<RequesterMessage>,
update: NetworkBridgeEvent<net_protocol::StatementDistributionMessage>, update: NetworkBridgeEvent<net_protocol::StatementDistributionMessage>,
metrics: &Metrics, metrics: &Metrics,
rng: &mut impl rand::Rng, rng: &mut R,
) { ) where
R: rand::Rng,
{
match update { match update {
NetworkBridgeEvent::PeerConnected(peer, role, _, maybe_authority) => { NetworkBridgeEvent::PeerConnected(peer, role, _, maybe_authority) => {
gum::trace!(target: LOG_TARGET, ?peer, ?role, "Peer connected"); gum::trace!(target: LOG_TARGET, ?peer, ?role, "Peer connected");
@@ -1701,6 +1705,7 @@ async fn handle_network_update(
} }
} }
#[overseer::contextbounds(StatementDistribution, prefix = self::overseer)]
impl<R: rand::Rng> StatementDistributionSubsystem<R> { impl<R: rand::Rng> StatementDistributionSubsystem<R> {
/// Create a new Statement Distribution Subsystem /// Create a new Statement Distribution Subsystem
pub fn new( pub fn new(
@@ -1712,11 +1717,7 @@ impl<R: rand::Rng> StatementDistributionSubsystem<R> {
Self { keystore, req_receiver: Some(req_receiver), metrics, rng } Self { keystore, req_receiver: Some(req_receiver), metrics, rng }
} }
async fn run( async fn run<Context>(mut self, mut ctx: Context) -> std::result::Result<(), FatalError> {
mut self,
mut ctx: (impl SubsystemContext<Message = StatementDistributionMessage>
+ overseer::SubsystemContext<Message = StatementDistributionMessage>),
) -> std::result::Result<(), FatalError> {
let mut peers: HashMap<PeerId, PeerData> = HashMap::new(); let mut peers: HashMap<PeerId, PeerData> = HashMap::new();
let mut gossip_peers: HashSet<PeerId> = HashSet::new(); let mut gossip_peers: HashSet<PeerId> = HashSet::new();
let mut authorities: HashMap<AuthorityDiscoveryId, PeerId> = HashMap::new(); let mut authorities: HashMap<AuthorityDiscoveryId, PeerId> = HashMap::new();
@@ -1832,9 +1833,9 @@ impl<R: rand::Rng> StatementDistributionSubsystem<R> {
Ok(()) Ok(())
} }
async fn handle_requester_message( async fn handle_requester_message<Context>(
&mut self, &mut self,
ctx: &mut impl SubsystemContext, ctx: &mut Context,
gossip_peers: &HashSet<PeerId>, gossip_peers: &HashSet<PeerId>,
peers: &mut HashMap<PeerId, PeerData>, peers: &mut HashMap<PeerId, PeerData>,
active_heads: &mut HashMap<Hash, ActiveHeadData>, active_heads: &mut HashMap<Hash, ActiveHeadData>,
@@ -1851,9 +1852,9 @@ impl<R: rand::Rng> StatementDistributionSubsystem<R> {
bad_peers, bad_peers,
} => { } => {
for bad in bad_peers { for bad in bad_peers {
report_peer(ctx, bad, COST_FETCH_FAIL).await; report_peer(ctx.sender(), bad, COST_FETCH_FAIL).await;
} }
report_peer(ctx, from_peer, BENEFIT_VALID_RESPONSE).await; report_peer(ctx.sender(), from_peer, BENEFIT_VALID_RESPONSE).await;
let active_head = active_heads let active_head = active_heads
.get_mut(&relay_parent) .get_mut(&relay_parent)
@@ -1898,10 +1899,10 @@ impl<R: rand::Rng> StatementDistributionSubsystem<R> {
} }
}, },
RequesterMessage::SendRequest(req) => { RequesterMessage::SendRequest(req) => {
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendRequests( ctx.send_message(NetworkBridgeMessage::SendRequests(
vec![req], vec![req],
IfDisconnected::ImmediateError, IfDisconnected::ImmediateError,
))) ))
.await; .await;
}, },
RequesterMessage::GetMorePeers { relay_parent, candidate_hash, tx } => { RequesterMessage::GetMorePeers { relay_parent, candidate_hash, tx } => {
@@ -1935,14 +1936,14 @@ impl<R: rand::Rng> StatementDistributionSubsystem<R> {
} }
} }
}, },
RequesterMessage::ReportPeer(peer, rep) => report_peer(ctx, peer, rep).await, RequesterMessage::ReportPeer(peer, rep) => report_peer(ctx.sender(), peer, rep).await,
} }
Ok(()) Ok(())
} }
async fn handle_subsystem_message( async fn handle_subsystem_message<Context>(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), ctx: &mut Context,
runtime: &mut RuntimeInfo, runtime: &mut RuntimeInfo,
peers: &mut HashMap<PeerId, PeerData>, peers: &mut HashMap<PeerId, PeerData>,
gossip_peers: &mut HashSet<PeerId>, gossip_peers: &mut HashSet<PeerId>,
@@ -29,7 +29,7 @@ use polkadot_node_network_protocol::{
use polkadot_node_primitives::{Statement, UncheckedSignedFullStatement}; use polkadot_node_primitives::{Statement, UncheckedSignedFullStatement};
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
jaeger, jaeger,
messages::{network_bridge_event, RuntimeApiMessage, RuntimeApiRequest}, messages::{network_bridge_event, AllMessages, RuntimeApiMessage, RuntimeApiRequest},
ActivatedLeaf, LeafStatus, ActivatedLeaf, LeafStatus,
}; };
use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore; use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore;
@@ -24,14 +24,12 @@ use std::time::Duration;
use ::test_helpers::{dummy_candidate_descriptor, dummy_hash}; use ::test_helpers::{dummy_candidate_descriptor, dummy_hash};
use polkadot_node_primitives::{BlockData, PoV}; use polkadot_node_primitives::{BlockData, PoV};
use polkadot_node_subsystem_types::messages::{ use polkadot_node_subsystem_types::messages::CandidateValidationMessage;
CandidateBackingMessage, CandidateValidationMessage,
};
use polkadot_overseer::{ use polkadot_overseer::{
self as overseer, self as overseer,
dummy::dummy_overseer_builder, dummy::dummy_overseer_builder,
gen::{FromOverseer, SpawnedSubsystem}, gen::{FromOverseer, SpawnedSubsystem},
AllMessages, HeadSupportsParachains, OverseerSignal, SubsystemError, HeadSupportsParachains, SubsystemError,
}; };
use polkadot_primitives::v2::{CandidateReceipt, Hash}; use polkadot_primitives::v2::{CandidateReceipt, Hash};
@@ -46,15 +44,9 @@ impl HeadSupportsParachains for AlwaysSupportsParachains {
struct Subsystem1; struct Subsystem1;
#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)]
impl Subsystem1 { impl Subsystem1 {
async fn run<Ctx>(mut ctx: Ctx) -> () async fn run<Context>(mut ctx: Context) {
where
Ctx: overseer::SubsystemContext<
Message = CandidateBackingMessage,
AllMessages = AllMessages,
Signal = OverseerSignal,
>,
{
'louy: loop { 'louy: loop {
match ctx.try_recv().await { match ctx.try_recv().await {
Ok(Some(msg)) => { Ok(Some(msg)) => {
@@ -84,21 +76,14 @@ impl Subsystem1 {
Default::default(), Default::default(),
tx, tx,
); );
ctx.send_message(<Ctx as overseer::SubsystemContext>::AllMessages::from(msg)) ctx.send_message(msg).await;
.await;
} }
() ()
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for Subsystem1 #[overseer::subsystem(CandidateBacking, error = SubsystemError, prefix = self::overseer)]
where impl<Context> Subsystem1 {
Context: overseer::SubsystemContext<
Message = CandidateBackingMessage,
AllMessages = AllMessages,
Signal = OverseerSignal,
>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem<SubsystemError> { fn start(self, ctx: Context) -> SpawnedSubsystem<SubsystemError> {
let future = Box::pin(async move { let future = Box::pin(async move {
Self::run(ctx).await; Self::run(ctx).await;
@@ -113,15 +98,9 @@ where
struct Subsystem2; struct Subsystem2;
#[overseer::contextbounds(CandidateValidation, prefix = self::overseer)]
impl Subsystem2 { impl Subsystem2 {
async fn run<Ctx>(mut ctx: Ctx) async fn run<Context>(mut ctx: Context) -> () {
where
Ctx: overseer::SubsystemContext<
Message = CandidateValidationMessage,
AllMessages = AllMessages,
Signal = OverseerSignal,
>,
{
ctx.spawn( ctx.spawn(
"subsystem-2-job", "subsystem-2-job",
Box::pin(async { Box::pin(async {
@@ -151,14 +130,8 @@ impl Subsystem2 {
} }
} }
impl<Context> overseer::Subsystem<Context, SubsystemError> for Subsystem2 #[overseer::subsystem(CandidateValidation, error = SubsystemError, prefix = self::overseer)]
where impl<Context> Subsystem2 {
Context: overseer::SubsystemContext<
Message = CandidateValidationMessage,
AllMessages = AllMessages,
Signal = OverseerSignal,
>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem<SubsystemError> { fn start(self, ctx: Context) -> SpawnedSubsystem<SubsystemError> {
let future = Box::pin(async move { let future = Box::pin(async move {
Self::run(ctx).await; Self::run(ctx).await;
@@ -181,6 +154,7 @@ fn main() {
.unwrap() .unwrap()
.replace_candidate_validation(|_| Subsystem2) .replace_candidate_validation(|_| Subsystem2)
.replace_candidate_backing(|orig| orig) .replace_candidate_backing(|orig| orig)
.replace_candidate_backing(|_orig| Subsystem1)
.build() .build()
.unwrap(); .unwrap();
@@ -4,6 +4,7 @@ version = "0.9.19"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021" edition = "2021"
description = "Generate an overseer including builder pattern and message wrapper from a single struct." description = "Generate an overseer including builder pattern and message wrapper from a single struct."
autoexamples = false
[dependencies] [dependencies]
gum = { package = "tracing-gum", path = "../../gum" } gum = { package = "tracing-gum", path = "../../gum" }
@@ -22,6 +23,16 @@ pin-project = "1.0"
trybuild = "1.0.61" trybuild = "1.0.61"
rustversion = "1.0.6" rustversion = "1.0.6"
[[example]]
name = "duo"
crate-type = ["bin"]
[[example]]
name = "solo"
crate-type = ["bin"]
[features] [features]
default = [] default = []
expand = ["polkadot-overseer-gen-proc-macro/expand"] expand = ["polkadot-overseer-gen-proc-macro/expand"]
@@ -11,17 +11,20 @@ declarative.
```rust ```rust
#[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)] #[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
pub struct Overseer { pub struct Overseer {
#[subsystem(MsgA)] #[subsystem(MsgA, sends: [MsgB])]
sub_a: AwesomeSubSysA, sub_a: AwesomeSubSysA,
#[subsystem(MsgB)] #[subsystem(MsgB, sends: [MsgA])]
sub_b: AwesomeSubSysB, sub_b: AwesomeSubSysB,
} }
``` ```
* Each subsystem is annotated with `#[subsystem(_)]` where `MsgA` respectively `MsgB` are the messages * Each subsystem is annotated with `#[subsystem(_)]` where `MsgA` respectively `MsgB` are the messages
being consumed by that particular subsystem. Each of those subsystems is required to implement the subsystem being consumed by that particular subsystem. Each of those subsystems is required to implement the subsystem
trait. trait with the correct trait bounds. Commonly this is achieved
by using `#[subsystem]` and `#[contextbounds]` macro.
* `#[contextbounds(Foo, error=Yikes, prefix=wherethetraitsat)]` can applied to `impl`-blocks and `fn`-blocks. It will add additional trait bounds for the generic `Context` with `Context: FooContextTrait` for `<Context as FooContextTrait>::Sender: FooSenderTrait` besides a few more. Note that `Foo` here references the name of the subsystem as declared in `#[overlord(..)]` macro.
* `#[subsystem(Foo, error=Yikes, prefix=wherethetraitsat)]` is a extension to the above, implementing `trait Subsystem<Context, Yikes>`.
* `error=` tells the overseer to use the user provided * `error=` tells the overseer to use the user provided
error type, if not provided a builtin one is used. Note that this is the one error type used throughout all calls, so make sure it does impl `From<E>` for all other error types `E` that are relevant to your application. error type, if not provided a builtin one is used. Note that this is the one error type used throughout all calls, so make sure it does impl `From<E>` for all other error types `E` that are relevant to your application.
* `event=` declares an external event type, that injects certain events * `event=` declares an external event type, that injects certain events
@@ -63,10 +66,10 @@ is not ready to be included in the Overseer:
```rust ```rust
#[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)] #[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
pub struct Overseer { pub struct Overseer {
#[subsystem(MsgA)] #[subsystem(MsgA, sends: MsgB)]
sub_a: AwesomeSubSysA, sub_a: AwesomeSubSysA,
#[subsystem(MsgB), wip] #[subsystem(MsgB, sends: MsgA), wip]
sub_b: AwesomeSubSysB, // This subsystem will not be required nor allowed to be set sub_b: AwesomeSubSysB, // This subsystem will not be required nor allowed to be set
} }
``` ```
@@ -0,0 +1,21 @@
# Limit outgoing messages
## Status
Accepted + implemented.
## Context
Previously, there was no way to limit and hence reason about a subset of subsystems, and if they form a cycle. Limiting the outgoing message types is a first step to create respective graphs and use classic graph algorithms to detect those and leave it to the user to resolve these.
## Decision
Annotate the `#[overlord]` inner `#[subsystem(..)]` annotation
with an aditional set of outgoing messages and enforce this via more fine grained trait bounds on the `Sender` and `<Context>::Sender` bounds.
## Consequences
* A graph will be spawn for every compilation under the `OUT_DIR` of the crate where `#[overlord]` is specified.
* Each subsystem has a consuming message which is often referred to as generic `M` (no change on that, is as before), but now we have trait `AssociateOutgoing { type OutgoingMessages = ..; }` which defines an outgoing helper `enum` that is generated with an ident constructed as `${Subsystem}OutgoingMessages` where `${Subsystem}` is the subsystem identifier as used in the overseer declaration. `${Subsystem}OutgoingMessages` is used throughout everywhere to constrain the outgoing messages (commonly referred to as `OutgoingMessage` generic bounded by `${Subsystem}OutgoingMessages: From<OutgoingMessage>` or `::OutgoingMessages: From`. It's what allows the construction of the graph and compile time verification.
* `${Subsystem}SenderTrait` and `${Subsystem}ContextTrait` are accumulation traits or wrapper traits, that combine over all annotated M or `OutgoingMessages` from the overseer declaration or their respective outgoing types. It is usage convenience and assures consistency within a subsystem while also maintaining a single source of truth for which messages can be sent by a particular subsystem. Note that this is sidestepped for the test subsystem, which may consume `gen=AllMessages`, the global message wrapper type.
* `Job`-based subsystems, being on their way out, are patched, but they now are generic over the `Sender` type, leaking that type.
@@ -1,143 +0,0 @@
//! A dummy to be used with cargo expand
use polkadot_node_network_protocol::WrongVariant;
use polkadot_overseer_gen::*;
use std::collections::HashMap;
/// Concrete subsystem implementation for `MsgStrukt` msg type.
#[derive(Default)]
pub struct AwesomeSubSys;
impl ::polkadot_overseer_gen::Subsystem<XxxSubsystemContext<MsgStrukt>, Yikes> for AwesomeSubSys {
fn start(self, _ctx: XxxSubsystemContext<MsgStrukt>) -> SpawnedSubsystem<Yikes> {
unimplemented!("starting yay!")
}
}
#[derive(Default)]
pub struct GoblinTower;
impl ::polkadot_overseer_gen::Subsystem<XxxSubsystemContext<Plinko>, Yikes> for GoblinTower {
fn start(self, _ctx: XxxSubsystemContext<Plinko>) -> SpawnedSubsystem<Yikes> {
unimplemented!("welcum")
}
}
/// A signal sent by the overseer.
#[derive(Debug, Clone)]
pub struct SigSigSig;
/// The external event.
#[derive(Debug, Clone)]
pub struct EvX;
impl EvX {
pub fn focus<'a, T>(&'a self) -> Result<EvX, ()> {
unimplemented!("dispatch")
}
}
#[derive(Debug, Clone, Copy)]
pub struct Yikes;
impl std::fmt::Display for Yikes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "yikes!")
}
}
impl std::error::Error for Yikes {}
impl From<polkadot_overseer_gen::OverseerError> for Yikes {
fn from(_: polkadot_overseer_gen::OverseerError) -> Yikes {
Yikes
}
}
impl From<polkadot_overseer_gen::mpsc::SendError> for Yikes {
fn from(_: polkadot_overseer_gen::mpsc::SendError) -> Yikes {
Yikes
}
}
#[derive(Debug, Clone)]
pub struct MsgStrukt(u8);
#[derive(Debug, Clone, Copy)]
pub struct Plinko;
impl From<NetworkMsg> for MsgStrukt {
fn from(_event: NetworkMsg) -> Self {
MsgStrukt(1u8)
}
}
#[derive(Debug, Clone, Copy)]
pub enum NetworkMsg {
A,
B,
C,
}
impl NetworkMsg {
fn focus(&self) -> Result<Self, WrongVariant> {
Ok(match self {
Self::B => return Err(WrongVariant),
Self::A | Self::C => self.clone(),
})
}
}
#[overlord(signal=SigSigSig, event=EvX, error=Yikes, network=NetworkMsg, gen=AllMessages)]
struct Xxx<T> {
#[subsystem(MsgStrukt)]
sub0: AwesomeSubSys,
#[subsystem(no_dispatch, blocking, Plinko)]
plinkos: GoblinTower,
i_like_pi: f64,
i_like_generic: T,
i_like_hash: HashMap<f64, f64>,
}
#[derive(Debug, Clone)]
struct DummySpawner;
impl SpawnNamed for DummySpawner {
fn spawn_blocking(
&self,
task_name: &'static str,
subsystem_name: Option<&'static str>,
_future: futures::future::BoxFuture<'static, ()>,
) {
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
}
fn spawn(
&self,
task_name: &'static str,
subsystem_name: Option<&'static str>,
_future: futures::future::BoxFuture<'static, ()>,
) {
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
}
}
#[derive(Debug, Clone)]
struct DummyCtx;
fn main() {
let (overseer, _handle): (Xxx<_, f64>, _) = Xxx::builder()
.sub0(AwesomeSubSys::default())
.plinkos(GoblinTower::default())
.i_like_pi(::std::f64::consts::PI)
.i_like_generic(42.0)
.i_like_hash(HashMap::new())
.spawner(DummySpawner)
.build()
.unwrap();
assert_eq!(overseer.i_like_pi.floor() as i8, 3);
assert_eq!(overseer.i_like_generic.floor() as i8, 42);
assert_eq!(overseer.i_like_hash.len() as i8, 0);
}
@@ -0,0 +1,89 @@
#![allow(dead_code)] // overseer events are not used
//! A dummy to be used with cargo expand
use polkadot_overseer_gen::{self as overseer, SpawnNamed, *};
use std::collections::HashMap;
mod misc;
pub use self::misc::*;
/// Concrete subsystem implementation for `MsgStrukt` msg type.
#[derive(Default)]
pub struct AwesomeSubSys;
#[overseer::subsystem(Awesome, error=Yikes)]
impl<Context> AwesomeSubSys {
fn start(self, mut ctx: Context) -> SpawnedSubsystem<Yikes> {
let mut sender = ctx.sender().clone();
ctx.spawn(
"AwesomeSubsys",
Box::pin(async move {
sender.send_message(Plinko).await;
}),
)
.unwrap();
unimplemented!("starting yay!")
}
}
#[derive(Default)]
pub struct Fortified;
#[overseer::subsystem(GoblinTower, error=Yikes)]
impl<Context> Fortified {
fn start(self, mut ctx: Context) -> SpawnedSubsystem<Yikes> {
let mut sender = ctx.sender().clone();
ctx.spawn(
"GoblinTower",
Box::pin(async move {
sender.send_message(MsgStrukt(8u8)).await;
}),
)
.unwrap();
unimplemented!("welcum")
}
}
#[overlord(signal=SigSigSig, event=EvX, error=Yikes, gen=AllMessages)]
struct Duo<T> {
#[subsystem(consumes: MsgStrukt, sends: [Plinko])]
sub0: Awesome,
#[subsystem(blocking, consumes: Plinko, sends: [MsgStrukt])]
plinkos: GoblinTower,
i_like_pi: f64,
i_like_generic: T,
i_like_hash: HashMap<f64, f64>,
}
fn main() {
use futures::{executor, pin_mut};
executor::block_on(async move {
let (overseer, _handle): (Duo<_, f64>, _) = Duo::builder()
.sub0(AwesomeSubSys::default())
.plinkos(Fortified::default())
.i_like_pi(::std::f64::consts::PI)
.i_like_generic(42.0)
.i_like_hash(HashMap::new())
.spawner(DummySpawner)
.build()
.unwrap();
assert_eq!(overseer.i_like_pi.floor() as i8, 3);
assert_eq!(overseer.i_like_generic.floor() as i8, 42);
assert_eq!(overseer.i_like_hash.len() as i8, 0);
let overseer_fut = overseer
.running_subsystems
.into_future()
.timeout(std::time::Duration::from_millis(300))
.fuse();
pin_mut!(overseer_fut);
overseer_fut.await
});
}
@@ -0,0 +1,69 @@
use polkadot_overseer_gen::{SpawnNamed, *};
#[derive(Debug, Clone, Copy)]
pub enum SigSigSig {
Conclude,
Foo,
}
#[derive(Debug, Clone)]
pub struct DummySpawner;
impl SpawnNamed for DummySpawner {
fn spawn_blocking(
&self,
task_name: &'static str,
subsystem_name: Option<&'static str>,
_future: futures::future::BoxFuture<'static, ()>,
) {
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
}
fn spawn(
&self,
task_name: &'static str,
subsystem_name: Option<&'static str>,
_future: futures::future::BoxFuture<'static, ()>,
) {
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
}
}
/// The external event.
#[derive(Debug, Clone)]
pub struct EvX;
impl EvX {
pub fn focus<'a, T>(&'a self) -> Result<EvX, ()> {
unimplemented!("focus")
}
}
#[derive(Debug, Clone, Copy)]
pub struct Yikes;
impl std::fmt::Display for Yikes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "yikes!")
}
}
impl std::error::Error for Yikes {}
impl From<polkadot_overseer_gen::OverseerError> for Yikes {
fn from(_: polkadot_overseer_gen::OverseerError) -> Yikes {
Yikes
}
}
impl From<polkadot_overseer_gen::mpsc::SendError> for Yikes {
fn from(_: polkadot_overseer_gen::mpsc::SendError) -> Yikes {
Yikes
}
}
#[derive(Debug, Clone)]
pub struct MsgStrukt(pub u8);
#[derive(Debug, Clone, Copy)]
pub struct Plinko;
@@ -0,0 +1,54 @@
#![allow(dead_code)] // overseer events are not used
//! A minimal demo to be used with cargo expand.
use polkadot_overseer_gen::{self as overseer, SpawnNamed, *};
mod misc;
pub use self::misc::*;
#[overlord(signal=SigSigSig, event=EvX, error=Yikes, gen=AllMessages)]
struct Solo<T> {
#[subsystem(consumes: Plinko, sends: [MsgStrukt])]
goblin_tower: GoblinTower,
}
#[derive(Default)]
pub struct Fortified;
#[overseer::subsystem(GoblinTower, error=Yikes)]
impl<Context> Fortified {
fn start(self, mut ctx: Context) -> SpawnedSubsystem<Yikes> {
let mut sender = ctx.sender().clone();
ctx.spawn(
"GoblinTower",
Box::pin(async move {
sender.send_message(MsgStrukt(8u8)).await;
}),
)
.unwrap();
unimplemented!("welcum")
}
}
fn main() {
use futures::{executor, pin_mut};
executor::block_on(async move {
let (overseer, _handle): (Solo<_>, _) = Solo::builder()
.goblin_tower(Fortified::default())
.spawner(DummySpawner)
.build()
.unwrap();
let overseer_fut = overseer
.running_subsystems
.into_future()
.timeout(std::time::Duration::from_millis(300))
.fuse();
pin_mut!(overseer_fut);
overseer_fut.await
});
}
@@ -17,12 +17,19 @@ quote = "1.0.18"
proc-macro2 = "1.0.37" proc-macro2 = "1.0.37"
proc-macro-crate = "1.1.3" proc-macro-crate = "1.1.3"
expander = { version = "0.0.6", default-features = false } expander = { version = "0.0.6", default-features = false }
petgraph = "0.6.0"
[dev-dependencies] [dev-dependencies]
assert_matches = "1.5.0" assert_matches = "1.5.0"
polkadot-overseer-gen = { path = "../" }
thiserror = "1"
gum = { package = "tracing-gum", path = "../../../gum" }
[features] [features]
default = [] default = ["graph", "expand"]
# write the expanded version to a `overlord-expansion.[a-f0-9]{10}.rs` # write the expanded version to a `overlord-expansion.[a-f0-9]{10}.rs`
# in the `OUT_DIR` as defined by `cargo` for the `expander` crate. # in the `OUT_DIR` as defined by `cargo` for the `expander` crate.
expand = [] expand = []
# Create directional message consuming / outgoing graph.
# Generates: `${OUT_DIR}/${overseer|lowercase}-subsystem-messaging.dot`
graph = []
@@ -0,0 +1,3 @@
fn main() {
// populate OUT_DIR
}
@@ -103,7 +103,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
info.subsystems().iter().filter(|ssf| !ssf.wip).enumerate().map(|(idx, ssf)| { info.subsystems().iter().filter(|ssf| !ssf.wip).enumerate().map(|(idx, ssf)| {
let field_name = &ssf.name; let field_name = &ssf.name;
let field_type = &ssf.generic; let field_type = &ssf.generic;
let subsystem_consumes = &ssf.consumes; let subsystem_consumes = &ssf.message_to_consume;
// Remove state generic for the item to be replaced. It sufficient to know `field_type` for // Remove state generic for the item to be replaced. It sufficient to know `field_type` for
// that since we always move from `Init<#field_type>` to `Init<NEW>`. // that since we always move from `Init<#field_type>` to `Init<NEW>`.
let impl_subsystem_state_generics = recollect_without_idx(&subsystem_passthrough_state_generics[..], idx); let impl_subsystem_state_generics = recollect_without_idx(&subsystem_passthrough_state_generics[..], idx);
@@ -130,19 +130,28 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
// see the loop below. // see the loop below.
let to_keep_subsystem_name = recollect_without_idx(&subsystem_name[..], idx); let to_keep_subsystem_name = recollect_without_idx(&subsystem_name[..], idx);
let subsystem_sender_trait = format_ident!("{}SenderTrait", field_type);
let _subsystem_ctx_trait = format_ident!("{}ContextTrait", field_type);
let builder_where_clause = quote!{
#field_type : #support_crate::Subsystem< #subsystem_ctx_name< #subsystem_consumes >, #error_ty>,
< #subsystem_ctx_name < #subsystem_consumes > as #support_crate :: SubsystemContext>::Sender:
#subsystem_sender_trait,
};
// Create the field init `fn` // Create the field init `fn`
quote! { quote! {
impl <InitStateSpawner, #field_type, #( #impl_subsystem_state_generics, )* #( #baggage_passthrough_state_generics, )*> impl <InitStateSpawner, #field_type, #( #impl_subsystem_state_generics, )* #( #baggage_passthrough_state_generics, )*>
#builder <InitStateSpawner, #( #current_state_generics, )* #( #baggage_passthrough_state_generics, )*> #builder <InitStateSpawner, #( #current_state_generics, )* #( #baggage_passthrough_state_generics, )*>
where where
#field_type : Subsystem<#subsystem_ctx_name<#subsystem_consumes>, #error_ty>, #builder_where_clause
{ {
/// Specify the subsystem in the builder directly /// Specify the subsystem in the builder directly
pub fn #field_name (self, var: #field_type ) -> pub fn #field_name (self, var: #field_type ) ->
#builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*> #builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*>
{ {
#builder { #builder {
#field_name: Init::<#field_type>::Value(var), #field_name: Init::< #field_type >::Value(var),
#( #(
#to_keep_subsystem_name: self. #to_keep_subsystem_name, #to_keep_subsystem_name: self. #to_keep_subsystem_name,
)* )*
@@ -158,7 +167,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
/// Specify the the initialization function for a subsystem /// Specify the the initialization function for a subsystem
pub fn #field_name_with<'a, F>(self, subsystem_init_fn: F ) -> pub fn #field_name_with<'a, F>(self, subsystem_init_fn: F ) ->
#builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*> #builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*>
where where
F: 'static + FnOnce(#handle) -> F: 'static + FnOnce(#handle) ->
::std::result::Result<#field_type, #error_ty>, ::std::result::Result<#field_type, #error_ty>,
{ {
@@ -185,7 +194,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
impl <InitStateSpawner, #field_type, #( #impl_subsystem_state_generics, )* #( #baggage_passthrough_state_generics, )*> impl <InitStateSpawner, #field_type, #( #impl_subsystem_state_generics, )* #( #baggage_passthrough_state_generics, )*>
#builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*> #builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*>
where where
#field_type : Subsystem<#subsystem_ctx_name<#subsystem_consumes>, #error_ty>, #builder_where_clause
{ {
/// Replace a subsystem by another implementation for the /// Replace a subsystem by another implementation for the
/// consumable message type. /// consumable message type.
@@ -301,6 +310,28 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
S, #( #baggage_generic_ty, )* #( #subsystem_generics, )* S, #( #baggage_generic_ty, )* #( #subsystem_generics, )*
}; };
let builder_where_clause = info
.subsystems()
.iter()
.map(|ssf| {
let field_type = &ssf.generic;
let consumes = &ssf.message_to_consume;
let subsystem_sender_trait = format_ident!("{}SenderTrait", ssf.generic);
let subsystem_ctx_trait = format_ident!("{}ContextTrait", ssf.generic);
quote! {
#field_type:
#support_crate::Subsystem< #subsystem_ctx_name < #consumes>, #error_ty>,
<#subsystem_ctx_name< #consumes > as #subsystem_ctx_trait>::Sender:
#subsystem_sender_trait,
#subsystem_ctx_name< #consumes >:
#subsystem_ctx_trait,
}
})
.fold(TokenStream::new(), |mut ts, addendum| {
ts.extend(addendum);
ts
});
let mut ts = quote! { let mut ts = quote! {
/// Convenience alias. /// Convenience alias.
type SubsystemInitFn<T> = Box<dyn FnOnce(#handle) -> ::std::result::Result<T, #error_ty> >; type SubsystemInitFn<T> = Box<dyn FnOnce(#handle) -> ::std::result::Result<T, #error_ty> >;
@@ -332,14 +363,15 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
} }
} }
impl<S, #( #baggage_generic_ty, )*> #overseer_name <S, #( #baggage_generic_ty, )*> where #spawner_where_clause { impl<S #(, #baggage_generic_ty )*> #overseer_name <S #(, #baggage_generic_ty)*>
where
#spawner_where_clause,
{
/// Create a new overseer utilizing the builder. /// Create a new overseer utilizing the builder.
pub fn builder< #( #subsystem_generics),* >() -> pub fn builder< #( #subsystem_generics),* >() ->
#builder<Missing<S> #(, Missing<#field_type> )* > #builder<Missing<S> #(, Missing< #field_type > )* >
where where
#( #builder_where_clause
#subsystem_generics : Subsystem<#subsystem_ctx_name< #consumes >, #error_ty>,
)*
{ {
#builder :: new() #builder :: new()
} }
@@ -398,7 +430,8 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
ts.extend(quote!{ ts.extend(quote!{
/// Builder pattern to create compile time safe construction path. /// Builder pattern to create compile time safe construction path.
pub struct #builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*> { pub struct #builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*>
{
#( #(
#subsystem_name: #subsystem_passthrough_state_generics, #subsystem_name: #subsystem_passthrough_state_generics,
)* )*
@@ -445,7 +478,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
impl<S, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*> impl<S, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*>
#builder<Missing<S>, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*> #builder<Missing<S>, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*>
where where
#spawner_where_clause #spawner_where_clause,
{ {
/// The `spawner` to use for spawning tasks. /// The `spawner` to use for spawning tasks.
pub fn spawner(self, spawner: S) -> #builder< pub fn spawner(self, spawner: S) -> #builder<
@@ -490,6 +523,12 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
} }
}); });
// Create the string literals for spawn.
let subsystem_name_str_literal = subsystem_name
.iter()
.map(|ident| proc_macro2::Literal::string(ident.to_string().replace("_", "-").as_str()))
.collect::<Vec<_>>();
ts.extend(quote! { ts.extend(quote! {
/// Type used to represent a builder where all fields are initialized and the overseer could be constructed. /// Type used to represent a builder where all fields are initialized and the overseer could be constructed.
pub type #initialized_builder<#initialized_builder_generics> = #builder<Init<S>, #( Init<#field_type>, )*>; pub type #initialized_builder<#initialized_builder_generics> = #builder<Init<S>, #( Init<#field_type>, )*>;
@@ -498,9 +537,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
impl<#initialized_builder_generics> #initialized_builder<#initialized_builder_generics> impl<#initialized_builder_generics> #initialized_builder<#initialized_builder_generics>
where where
#spawner_where_clause, #spawner_where_clause,
#( #builder_where_clause
#subsystem_generics : Subsystem<#subsystem_ctx_name< #consumes >, #error_ty>,
)*
{ {
/// Complete the construction and create the overseer type. /// Complete the construction and create the overseer type.
pub fn build(self) pub fn build(self)
@@ -577,17 +614,12 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
self.signal_capacity.unwrap_or(SIGNAL_CHANNEL_CAPACITY) self.signal_capacity.unwrap_or(SIGNAL_CHANNEL_CAPACITY)
); );
// Generate subsystem name based on overseer field name.
let subsystem_string = String::from(stringify!(#subsystem_name));
// Convert owned `snake case` string to a `kebab case` static str.
let subsystem_static_str = Box::leak(subsystem_string.replace("_", "-").into_boxed_str());
let ctx = #subsystem_ctx_name::< #consumes >::new( let ctx = #subsystem_ctx_name::< #consumes >::new(
signal_rx, signal_rx,
message_rx, message_rx,
channels_out.clone(), channels_out.clone(),
to_overseer_tx.clone(), to_overseer_tx.clone(),
subsystem_static_str #subsystem_name_str_literal
); );
let #subsystem_name: OverseenSubsystem< #consumes > = let #subsystem_name: OverseenSubsystem< #consumes > =
@@ -598,7 +630,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
unbounded_meter, unbounded_meter,
ctx, ctx,
#subsystem_name, #subsystem_name,
subsystem_static_str, #subsystem_name_str_literal,
&mut running_subsystems, &mut running_subsystems,
)?; )?;
)* )*
@@ -65,6 +65,7 @@ pub(crate) fn impl_channels_out_struct(info: &OverseerInfo) -> Result<proc_macro
signals_received: usize, signals_received: usize,
message: #message_wrapper, message: #message_wrapper,
) { ) {
let res: ::std::result::Result<_, _> = match message { let res: ::std::result::Result<_, _> = match message {
#( #(
#message_wrapper :: #consumes_variant ( inner ) => { #message_wrapper :: #consumes_variant ( inner ) => {
@@ -79,6 +80,13 @@ pub(crate) fn impl_channels_out_struct(info: &OverseerInfo) -> Result<proc_macro
)* )*
// dummy message type // dummy message type
#message_wrapper :: Empty => Ok(()), #message_wrapper :: Empty => Ok(()),
#[allow(unreachable_patterns)]
// And everything that's not WIP but no subsystem consumes it
unused_msg => {
#support_crate :: gum :: warn!("Nothing consumes {:?}", unused_msg);
Ok(())
}
}; };
if let Err(subsystem_name) = res { if let Err(subsystem_name) = res {
@@ -110,7 +118,14 @@ pub(crate) fn impl_channels_out_struct(info: &OverseerInfo) -> Result<proc_macro
#message_wrapper :: #unconsumes_variant ( _ ) => Ok(()), #message_wrapper :: #unconsumes_variant ( _ ) => Ok(()),
)* )*
// dummy message type // dummy message type
#message_wrapper :: Empty => Ok(()) #message_wrapper :: Empty => Ok(()),
// And everything that's not WIP but no subsystem consumes it
#[allow(unreachable_patterns)]
unused_msg => {
#support_crate :: gum :: warn!("Nothing consumes {:?}", unused_msg);
Ok(())
}
}; };
if let Err(subsystem_name) = res { if let Err(subsystem_name) = res {
@@ -1,70 +0,0 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::Path;
pub(crate) fn impl_dispatch(info: &OverseerInfo) -> TokenStream {
let message_wrapper = &info.message_wrapper;
let dispatchable_variant = info
.subsystems()
.into_iter()
.filter(|ssf| !ssf.no_dispatch)
.filter(|ssf| !ssf.wip)
.map(|ssf| ssf.generic.clone())
.collect::<Vec<Ident>>();
let dispatchable_message = info
.subsystems()
.into_iter()
.filter(|ssf| !ssf.no_dispatch)
.filter(|ssf| !ssf.wip)
.map(|ssf| ssf.consumes.clone())
.collect::<Vec<Path>>();
let mut ts = TokenStream::new();
if let Some(extern_network_ty) = &info.extern_network_ty.clone() {
ts.extend(quote! {
impl #message_wrapper {
/// Generated dispatch iterator generator.
pub fn dispatch_iter(extern_msg: #extern_network_ty) -> impl Iterator<Item=Self> + Send {
[
#(
extern_msg
// focuses on a `NetworkBridgeEvent< protocol_v1::* >`
// TODO do not require this to be hardcoded, either externalize or ...
// https://github.com/paritytech/polkadot/issues/3427
.focus()
.ok()
.map(|event| {
#message_wrapper :: #dispatchable_variant (
// the inner type of the enum variant
#dispatchable_message :: from( event )
)
}),
)*
]
.into_iter()
.filter_map(|x: Option<_>| x)
}
}
});
}
ts
}
@@ -21,7 +21,7 @@ use super::*;
/// Generates the wrapper type enum. /// Generates the wrapper type enum.
pub(crate) fn impl_message_wrapper_enum(info: &OverseerInfo) -> Result<proc_macro2::TokenStream> { pub(crate) fn impl_message_wrapper_enum(info: &OverseerInfo) -> Result<proc_macro2::TokenStream> {
let consumes = info.consumes(); let consumes = info.any_message();
let consumes_variant = info.variant_names(); let consumes_variant = info.variant_names();
let outgoing = &info.outgoing_ty; let outgoing = &info.outgoing_ty;
@@ -52,7 +52,8 @@ pub(crate) fn impl_message_wrapper_enum(info: &OverseerInfo) -> Result<proc_macr
}; };
let ts = quote! { let ts = quote! {
/// Generated message type wrapper /// Generated message type wrapper over all possible messages
/// used by any subsystem.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug)] #[derive(Debug)]
pub enum #message_wrapper { pub enum #message_wrapper {
@@ -1,259 +0,0 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use quote::quote;
use syn::Ident;
use super::*;
/// Implement a builder pattern for the `Overseer`-type,
/// which acts as the gateway to constructing the overseer.
pub(crate) fn impl_misc(info: &OverseerInfo) -> proc_macro2::TokenStream {
let overseer_name = info.overseer_name.clone();
let subsystem_sender_name =
Ident::new(&(overseer_name.to_string() + "SubsystemSender"), overseer_name.span());
let subsystem_ctx_name =
Ident::new(&(overseer_name.to_string() + "SubsystemContext"), overseer_name.span());
let consumes = &info.consumes();
let signal = &info.extern_signal_ty;
let wrapper_message = &info.message_wrapper;
let error_ty = &info.extern_error_ty;
let support_crate = info.support_crate_name();
let ts = quote! {
/// Connector to send messages towards all subsystems,
/// while tracking the which signals where already received.
#[derive(Debug, Clone)]
pub struct #subsystem_sender_name {
/// Collection of channels to all subsystems.
channels: ChannelsOut,
/// Systemwide tick for which signals were received by all subsystems.
signals_received: SignalsReceived,
}
/// implementation for wrapping message type...
#[#support_crate ::async_trait]
impl SubsystemSender< #wrapper_message > for #subsystem_sender_name {
async fn send_message(&mut self, msg: #wrapper_message) {
self.channels.send_and_log_error(self.signals_received.load(), msg).await;
}
async fn send_messages<T>(&mut self, msgs: T)
where
T: IntoIterator<Item = #wrapper_message> + Send,
T::IntoIter: Send,
{
// This can definitely be optimized if necessary.
for msg in msgs {
self.send_message(msg).await;
}
}
fn send_unbounded_message(&mut self, msg: #wrapper_message) {
self.channels.send_unbounded_and_log_error(self.signals_received.load(), msg);
}
}
// ... but also implement for all individual messages to avoid
// the necessity for manual wrapping, and do the conversion
// based on the generated `From::from` impl for the individual variants.
#(
#[#support_crate ::async_trait]
impl SubsystemSender< #consumes > for #subsystem_sender_name {
async fn send_message(&mut self, msg: #consumes) {
self.channels.send_and_log_error(self.signals_received.load(), #wrapper_message ::from ( msg )).await;
}
async fn send_messages<T>(&mut self, msgs: T)
where
T: IntoIterator<Item = #consumes> + Send,
T::IntoIter: Send,
{
// This can definitely be optimized if necessary.
for msg in msgs {
self.send_message(msg).await;
}
}
fn send_unbounded_message(&mut self, msg: #consumes) {
self.channels.send_unbounded_and_log_error(self.signals_received.load(), #wrapper_message ::from ( msg ));
}
}
)*
/// A context type that is given to the [`Subsystem`] upon spawning.
/// It can be used by [`Subsystem`] to communicate with other [`Subsystem`]s
/// or to spawn it's [`SubsystemJob`]s.
///
/// [`Overseer`]: struct.Overseer.html
/// [`Subsystem`]: trait.Subsystem.html
/// [`SubsystemJob`]: trait.SubsystemJob.html
#[derive(Debug)]
#[allow(missing_docs)]
pub struct #subsystem_ctx_name<M>{
signals: #support_crate ::metered::MeteredReceiver< #signal >,
messages: SubsystemIncomingMessages<M>,
to_subsystems: #subsystem_sender_name,
to_overseer: #support_crate ::metered::UnboundedMeteredSender<
#support_crate ::ToOverseer
>,
signals_received: SignalsReceived,
pending_incoming: Option<(usize, M)>,
name: &'static str
}
impl<M> #subsystem_ctx_name<M> {
/// Create a new context.
fn new(
signals: #support_crate ::metered::MeteredReceiver< #signal >,
messages: SubsystemIncomingMessages<M>,
to_subsystems: ChannelsOut,
to_overseer: #support_crate ::metered::UnboundedMeteredSender<#support_crate:: ToOverseer>,
name: &'static str
) -> Self {
let signals_received = SignalsReceived::default();
#subsystem_ctx_name {
signals,
messages,
to_subsystems: #subsystem_sender_name {
channels: to_subsystems,
signals_received: signals_received.clone(),
},
to_overseer,
signals_received,
pending_incoming: None,
name
}
}
fn name(&self) -> &'static str {
self.name
}
}
#[#support_crate ::async_trait]
impl<M: std::fmt::Debug + Send + 'static> #support_crate ::SubsystemContext for #subsystem_ctx_name<M>
where
#subsystem_sender_name: #support_crate ::SubsystemSender< #wrapper_message >,
#wrapper_message: From<M>,
{
type Message = M;
type Signal = #signal;
type Sender = #subsystem_sender_name;
type AllMessages = #wrapper_message;
type Error = #error_ty;
async fn try_recv(&mut self) -> ::std::result::Result<Option<FromOverseer<M, #signal>>, ()> {
match #support_crate ::poll!(self.recv()) {
#support_crate ::Poll::Ready(msg) => Ok(Some(msg.map_err(|_| ())?)),
#support_crate ::Poll::Pending => Ok(None),
}
}
async fn recv(&mut self) -> ::std::result::Result<FromOverseer<M, #signal>, #error_ty> {
loop {
// If we have a message pending an overseer signal, we only poll for signals
// in the meantime.
if let Some((needs_signals_received, msg)) = self.pending_incoming.take() {
if needs_signals_received <= self.signals_received.load() {
return Ok(#support_crate ::FromOverseer::Communication { msg });
} else {
self.pending_incoming = Some((needs_signals_received, msg));
// wait for next signal.
let signal = self.signals.next().await
.ok_or(#support_crate ::OverseerError::Context(
"Signal channel is terminated and empty."
.to_owned()
))?;
self.signals_received.inc();
return Ok(#support_crate ::FromOverseer::Signal(signal))
}
}
let mut await_message = self.messages.next().fuse();
let mut await_signal = self.signals.next().fuse();
let signals_received = self.signals_received.load();
let pending_incoming = &mut self.pending_incoming;
// Otherwise, wait for the next signal or incoming message.
let from_overseer = #support_crate ::futures::select_biased! {
signal = await_signal => {
let signal = signal
.ok_or(#support_crate ::OverseerError::Context(
"Signal channel is terminated and empty."
.to_owned()
))?;
#support_crate ::FromOverseer::Signal(signal)
}
msg = await_message => {
let packet = msg
.ok_or(#support_crate ::OverseerError::Context(
"Message channel is terminated and empty."
.to_owned()
))?;
if packet.signals_received > signals_received {
// wait until we've received enough signals to return this message.
*pending_incoming = Some((packet.signals_received, packet.message));
continue;
} else {
// we know enough to return this message.
#support_crate ::FromOverseer::Communication { msg: packet.message}
}
}
};
if let #support_crate ::FromOverseer::Signal(_) = from_overseer {
self.signals_received.inc();
}
return Ok(from_overseer);
}
}
fn sender(&mut self) -> &mut Self::Sender {
&mut self.to_subsystems
}
fn spawn(&mut self, name: &'static str, s: Pin<Box<dyn Future<Output = ()> + Send>>)
-> ::std::result::Result<(), #error_ty>
{
self.to_overseer.unbounded_send(#support_crate ::ToOverseer::SpawnJob {
name,
subsystem: Some(self.name()),
s,
}).map_err(|_| #support_crate ::OverseerError::TaskSpawn(name))?;
Ok(())
}
fn spawn_blocking(&mut self, name: &'static str, s: Pin<Box<dyn Future<Output = ()> + Send>>)
-> ::std::result::Result<(), #error_ty>
{
self.to_overseer.unbounded_send(#support_crate ::ToOverseer::SpawnBlockingJob {
name,
subsystem: Some(self.name()),
s,
}).map_err(|_| #support_crate ::OverseerError::TaskSpawn(name))?;
Ok(())
}
}
};
ts
}
@@ -37,7 +37,7 @@ pub(crate) fn impl_overseer_struct(info: &OverseerInfo) -> proc_macro2::TokenStr
S: #support_crate ::SpawnNamed, S: #support_crate ::SpawnNamed,
}; };
// TODO add `where ..` clauses for baggage types // TODO add `where ..` clauses for baggage types
// TODO https://github.com/paritytech/polkadot/issues/3427 // TODO <https://github.com/paritytech/polkadot/issues/3427>
let consumes = &info.consumes_without_wip(); let consumes = &info.consumes_without_wip();
let consumes_variant = &info.variant_names_without_wip(); let consumes_variant = &info.variant_names_without_wip();
@@ -148,6 +148,12 @@ pub(crate) fn impl_overseer_struct(info: &OverseerInfo) -> proc_macro2::TokenStr
#message_wrapper :: #unconsumes_variant ( _ ) => {} #message_wrapper :: #unconsumes_variant ( _ ) => {}
)* )*
#message_wrapper :: Empty => {} #message_wrapper :: Empty => {}
// And everything that's not WIP but no subsystem consumes it
#[allow(unreachable_patterns)]
unused_msg => {
#support_crate :: gum :: warn!("Nothing consumes {:?}", unused_msg);
}
} }
Ok(()) Ok(())
} }
@@ -0,0 +1,712 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Ident, Path, Result, Type};
use petgraph::{
dot::{self, Dot},
graph::NodeIndex,
visit::EdgeRef,
Direction,
};
use std::collections::HashMap;
use super::*;
/// Render a graphviz (aka dot graph) to a file.
fn graphviz(
graph: &petgraph::Graph<Ident, Path>,
dest: &mut impl std::io::Write,
) -> std::io::Result<()> {
let config = &[dot::Config::EdgeNoLabel, dot::Config::NodeNoLabel][..];
let dot = Dot::with_attr_getters(
graph,
config,
&|_graph, edge| -> String {
format!(
r#"label="{}""#,
edge.weight().get_ident().expect("Must have a trailing identifier. qed")
)
},
&|_graph, (_node_index, subsystem_name)| -> String {
format!(r#"label="{}""#, subsystem_name,)
},
);
dest.write_all(format!("{:?}", &dot).as_bytes())?;
Ok(())
}
/// Generates all subsystem types and related accumulation traits.
pub(crate) fn impl_subsystem_types_all(info: &OverseerInfo) -> Result<TokenStream> {
let mut ts = TokenStream::new();
let overseer_name = &info.overseer_name;
let span = overseer_name.span();
let all_messages_wrapper = &info.message_wrapper;
let support_crate = info.support_crate_name();
let signal_ty = &info.extern_signal_ty;
let error_ty = &info.extern_error_ty;
// create a directed graph with all the subsystems as nodes and the messages as edges
// key is always the message path, values are node indices in the graph and the subsystem generic identifier
// store the message path and the source sender, both in the graph as well as identifier
let mut outgoing_lut = HashMap::<&Path, Vec<(Ident, NodeIndex)>>::with_capacity(128);
// same for consuming the incoming messages
let mut consuming_lut = HashMap::<&Path, (Ident, NodeIndex)>::with_capacity(128);
// Ident = Node = subsystem generic names
// Path = Edge = messages
let mut graph = petgraph::Graph::<Ident, Path>::new();
// prepare the full index of outgoing and source subsystems
for ssf in info.subsystems() {
let node_index = graph.add_node(ssf.generic.clone());
for outgoing in ssf.messages_to_send.iter() {
outgoing_lut
.entry(outgoing)
.or_default()
.push((ssf.generic.clone(), node_index));
}
consuming_lut.insert(&ssf.message_to_consume, (ssf.generic.clone(), node_index));
}
for (message_ty, (_consuming_subsystem_ident, consuming_node_index)) in consuming_lut.iter() {
// match the outgoing ones that were registered above with the consumed message
if let Some(origin_subsystems) = outgoing_lut.get(message_ty) {
for (_origin_subsystem_ident, sending_node_index) in origin_subsystems.iter() {
graph.add_edge(*sending_node_index, *consuming_node_index, (*message_ty).clone());
}
}
}
// All outgoing edges are now usable to derive everything we need
for node_index in graph.node_indices() {
let subsystem_name = graph[node_index].to_string();
let outgoing_wrapper = Ident::new(&(subsystem_name + "OutgoingMessages"), span);
// cannot be a hashmap, duplicate keys and sorting required
// maps outgoing messages to the subsystem that consumes it
let outgoing_to_consumer = graph
.edges_directed(node_index, Direction::Outgoing)
.map(|edge| {
let message_ty = edge.weight();
let subsystem_generic_consumer = graph[edge.target()].clone();
Ok((to_variant(message_ty, span.clone())?, subsystem_generic_consumer))
})
.collect::<Result<Vec<(Ident, Ident)>>>()?;
// Split it for usage with quote
let outgoing_variant = outgoing_to_consumer.iter().map(|x| x.0.clone()).collect::<Vec<_>>();
let subsystem_generic = outgoing_to_consumer.into_iter().map(|x| x.1).collect::<Vec<_>>();
ts.extend(quote! {
impl ::std::convert::From< #outgoing_wrapper > for #all_messages_wrapper {
fn from(message: #outgoing_wrapper) -> Self {
match message {
#(
#outgoing_wrapper :: #outgoing_variant ( msg ) => #all_messages_wrapper :: #subsystem_generic ( msg ),
)*
#outgoing_wrapper :: Empty => #all_messages_wrapper :: Empty,
// And everything that's not WIP but no subsystem consumes it
#[allow(unreachable_patterns)]
unused_msg => {
#support_crate :: gum :: warn!("Nothing consumes {:?}", unused_msg);
#all_messages_wrapper :: Empty
}
}
}
}
})
}
// Dump the graph to file.
if cfg!(feature = "graph") || true {
let path = std::path::PathBuf::from(env!("OUT_DIR"))
.join(overseer_name.to_string().to_lowercase() + "-subsystem-messaging.dot");
if let Err(e) = std::fs::OpenOptions::new()
.truncate(true)
.create(true)
.write(true)
.open(&path)
.and_then(|mut f| graphviz(&graph, &mut f))
{
eprintln!("Failed to write dot graph to {}: {:?}", path.display(), e);
} else {
println!("Wrote dot graph to {}", path.display());
}
}
let subsystem_sender_name = &Ident::new(&(overseer_name.to_string() + "Sender"), span);
let subsystem_ctx_name = &Ident::new(&(overseer_name.to_string() + "SubsystemContext"), span);
ts.extend(impl_subsystem_context(info, &subsystem_sender_name, &subsystem_ctx_name));
ts.extend(impl_associate_outgoing_messages_trait(&all_messages_wrapper));
ts.extend(impl_subsystem_sender(
support_crate,
info.subsystems().iter().map(|ssf| {
let outgoing_wrapper =
Ident::new(&(ssf.generic.to_string() + "OutgoingMessages"), span);
outgoing_wrapper
}),
&all_messages_wrapper,
&subsystem_sender_name,
));
// Create all subsystem specific types, one by one
for ssf in info.subsystems() {
let subsystem_name = ssf.generic.to_string();
let outgoing_wrapper = &Ident::new(&(subsystem_name.clone() + "OutgoingMessages"), span);
let subsystem_ctx_trait = &Ident::new(&(subsystem_name.clone() + "ContextTrait"), span);
let subsystem_sender_trait = &Ident::new(&(subsystem_name.clone() + "SenderTrait"), span);
ts.extend(impl_per_subsystem_helper_traits(
info,
subsystem_ctx_name,
subsystem_ctx_trait,
subsystem_sender_name,
subsystem_sender_trait,
&ssf.message_to_consume,
&ssf.messages_to_send,
outgoing_wrapper,
));
ts.extend(impl_associate_outgoing_messages(&ssf.message_to_consume, &outgoing_wrapper));
ts.extend(impl_wrapper_enum(&outgoing_wrapper, ssf.messages_to_send.as_slice())?);
}
// impl the emtpy tuple handling for tests
let empty_tuple: Type = parse_quote! { () };
ts.extend(impl_subsystem_context_trait_for(
empty_tuple.clone(),
&[],
empty_tuple,
all_messages_wrapper,
subsystem_ctx_name,
subsystem_sender_name,
support_crate,
signal_ty,
error_ty,
));
Ok(ts)
}
/// Extract the final component of the message type path as used in the `#[subsystem(consumes: path::to::Foo)]` annotation.
fn to_variant(path: &Path, span: Span) -> Result<Ident> {
let ident = path
.segments
.last()
.ok_or_else(|| syn::Error::new(span, "Path is empty, but it must end with an identifier"))
.map(|segment| segment.ident.clone())?;
Ok(ident)
}
/// Converts the outgoing message types to variants.
///
/// Note: Commonly this is `${X}Message` becomes `${X}OutgoingMessages::${X}Message`
/// where for `AllMessages` it would be `AllMessages::${X}`.
fn to_variants(message_types: &[Path], span: Span) -> Result<Vec<Ident>> {
let variants: Vec<_> =
Result::from_iter(message_types.into_iter().map(|path| to_variant(path, span.clone())))?;
Ok(variants)
}
/// Generates the wrapper type enum, no bells or whistles.
pub(crate) fn impl_wrapper_enum(wrapper: &Ident, message_types: &[Path]) -> Result<TokenStream> {
// The message types are path based, each of them must finish with a type
// and as such we do this upfront.
let variants = to_variants(message_types, wrapper.span())?;
let ts = quote! {
#[allow(missing_docs)]
#[derive(Debug)]
pub enum #wrapper {
#(
#variants ( #message_types ),
)*
Empty,
}
#(
impl ::std::convert::From< #message_types > for #wrapper {
fn from(message: #message_types) -> Self {
#wrapper :: #variants ( message )
}
}
)*
// Useful for unit and integration tests:
impl ::std::convert::From< () > for #wrapper {
fn from(_message: ()) -> Self {
#wrapper :: Empty
}
}
};
Ok(ts)
}
/// Create the subsystem sender type and implements `trait SubsystemSender`
/// for the `#outgoing_wrappers: From<OutgoingMessage>` with the proper associated types.
pub(crate) fn impl_subsystem_sender(
support_crate: &Path,
outgoing_wrappers: impl IntoIterator<Item = Ident>,
all_messages_wrapper: &Ident,
subsystem_sender_name: &Ident,
) -> TokenStream {
let mut ts = quote! {
/// Connector to send messages towards all subsystems,
/// while tracking the which signals where already received.
#[derive(Debug)]
pub struct #subsystem_sender_name < OutgoingWrapper > {
/// Collection of channels to all subsystems.
channels: ChannelsOut,
/// Systemwide tick for which signals were received by all subsystems.
signals_received: SignalsReceived,
/// Keep that marker around.
_phantom: ::core::marker::PhantomData< OutgoingWrapper >,
}
// can't derive due to `PhantomData` and `OutgoingWrapper` not being
// bounded by `Clone`.
impl<OutgoingWrapper> std::clone::Clone for #subsystem_sender_name < OutgoingWrapper > {
fn clone(&self) -> Self {
Self {
channels: self.channels.clone(),
signals_received: self.signals_received.clone(),
_phantom: ::core::marker::PhantomData::default(),
}
}
}
};
// Create the same for a wrapping enum:
//
// 1. subsystem specific `*OutgoingMessages`-type
// 2. overseer-global-`AllMessages`-type
let wrapped = |outgoing_wrapper: &TokenStream| {
quote! {
#[#support_crate ::async_trait]
impl<OutgoingMessage> SubsystemSender< OutgoingMessage > for #subsystem_sender_name < #outgoing_wrapper >
where
OutgoingMessage: Send + 'static,
#outgoing_wrapper: ::std::convert::From<OutgoingMessage> + Send,
#all_messages_wrapper: ::std::convert::From< #outgoing_wrapper > + Send,
{
async fn send_message(&mut self, msg: OutgoingMessage)
{
self.channels.send_and_log_error(
self.signals_received.load(),
<#all_messages_wrapper as ::std::convert::From<_>> ::from (
<#outgoing_wrapper as ::std::convert::From<_>> :: from ( msg )
)
).await;
}
async fn send_messages<I>(&mut self, msgs: I)
where
I: IntoIterator<Item=OutgoingMessage> + Send,
I::IntoIter: Iterator<Item=OutgoingMessage> + Send,
{
for msg in msgs {
self.send_message( msg ).await;
}
}
fn send_unbounded_message(&mut self, msg: OutgoingMessage)
{
self.channels.send_unbounded_and_log_error(
self.signals_received.load(),
<#all_messages_wrapper as ::std::convert::From<_>> ::from (
<#outgoing_wrapper as ::std::convert::From<_>> :: from ( msg )
)
);
}
}
}
};
for outgoing_wrapper in outgoing_wrappers {
ts.extend(wrapped(&quote! {
#outgoing_wrapper
}));
}
ts.extend(wrapped(&quote! {
()
}));
ts
}
/// Define the `trait AssociateOutgoing` and implement it for `#all_messages_wrapper` and `()`.
pub(crate) fn impl_associate_outgoing_messages_trait(all_messages_wrapper: &Ident) -> TokenStream {
quote! {
/// Binds a generated type covering all declared outgoing messages,
/// which implements `#generated_outgoing: From<M>` for all annotated types
/// of a particular subsystem.
///
/// Note: This works because there is a 1?:1 relation between consumed messages and subsystems.
pub trait AssociateOutgoing: ::std::fmt::Debug + Send {
/// The associated _outgoing_ messages for a subsystem that _consumes_ the message `Self`.
type OutgoingMessages: Into< #all_messages_wrapper > + ::std::fmt::Debug + Send;
}
// Helper for tests, where nothing is ever sent.
impl AssociateOutgoing for () {
type OutgoingMessages = ();
}
// Helper for tests, allows sending of arbitrary messages give
// an test context.
impl AssociateOutgoing for #all_messages_wrapper {
type OutgoingMessages = #all_messages_wrapper ;
}
}
}
/// Implement `AssociateOutgoing` for `#consumes` being handled by a particular subsystem.
///
/// Binds the outgoing messages to the inbound message.
///
/// Note: Works, since there is a 1:1 relation between inbound message type and subsystem declarations.
/// Note: A workaround until default associated types work in `rustc`.
pub(crate) fn impl_associate_outgoing_messages(
consumes: &Path,
outgoing_wrapper: &Ident,
) -> TokenStream {
quote! {
impl AssociateOutgoing for #outgoing_wrapper {
type OutgoingMessages = #outgoing_wrapper;
}
impl AssociateOutgoing for #consumes {
type OutgoingMessages = #outgoing_wrapper;
}
}
}
/// Implement `trait SubsystemContext` for a particular subsystem context,
/// that is generated by the proc-macro too.
pub(crate) fn impl_subsystem_context_trait_for(
consumes: Type,
outgoing: &[Type],
outgoing_wrapper: Type,
all_messages_wrapper: &Ident,
subsystem_ctx_name: &Ident,
subsystem_sender_name: &Ident,
support_crate: &Path,
signal: &Path,
error_ty: &Path,
) -> TokenStream {
// impl the subsystem context trait
let where_clause = quote! {
#consumes: AssociateOutgoing + ::std::fmt::Debug + Send + 'static,
#all_messages_wrapper: From< #outgoing_wrapper >,
#all_messages_wrapper: From< #consumes >,
#outgoing_wrapper: #( From< #outgoing > )+*,
};
quote! {
#[#support_crate ::async_trait]
impl #support_crate ::SubsystemContext for #subsystem_ctx_name < #consumes >
where
#where_clause
{
type Message = #consumes;
type Signal = #signal;
type OutgoingMessages = #outgoing_wrapper;
type Sender = #subsystem_sender_name < #outgoing_wrapper >;
type Error = #error_ty;
async fn try_recv(&mut self) -> ::std::result::Result<Option<FromOverseer< Self::Message, #signal>>, ()> {
match #support_crate ::poll!(self.recv()) {
#support_crate ::Poll::Ready(msg) => Ok(Some(msg.map_err(|_| ())?)),
#support_crate ::Poll::Pending => Ok(None),
}
}
async fn recv(&mut self) -> ::std::result::Result<FromOverseer<Self::Message, #signal>, #error_ty> {
loop {
// If we have a message pending an overseer signal, we only poll for signals
// in the meantime.
if let Some((needs_signals_received, msg)) = self.pending_incoming.take() {
if needs_signals_received <= self.signals_received.load() {
return Ok( #support_crate ::FromOverseer::Communication { msg });
} else {
self.pending_incoming = Some((needs_signals_received, msg));
// wait for next signal.
let signal = self.signals.next().await
.ok_or(#support_crate ::OverseerError::Context(
"Signal channel is terminated and empty."
.to_owned()
))?;
self.signals_received.inc();
return Ok( #support_crate ::FromOverseer::Signal(signal))
}
}
let mut await_message = self.messages.next().fuse();
let mut await_signal = self.signals.next().fuse();
let signals_received = self.signals_received.load();
let pending_incoming = &mut self.pending_incoming;
// Otherwise, wait for the next signal or incoming message.
let from_overseer = #support_crate ::futures::select_biased! {
signal = await_signal => {
let signal = signal
.ok_or( #support_crate ::OverseerError::Context(
"Signal channel is terminated and empty."
.to_owned()
))?;
#support_crate ::FromOverseer::Signal(signal)
}
msg = await_message => {
let packet = msg
.ok_or( #support_crate ::OverseerError::Context(
"Message channel is terminated and empty."
.to_owned()
))?;
if packet.signals_received > signals_received {
// wait until we've received enough signals to return this message.
*pending_incoming = Some((packet.signals_received, packet.message));
continue;
} else {
// we know enough to return this message.
#support_crate ::FromOverseer::Communication { msg: packet.message}
}
}
};
if let #support_crate ::FromOverseer::Signal(_) = from_overseer {
self.signals_received.inc();
}
return Ok(from_overseer);
}
}
fn sender(&mut self) -> &mut Self::Sender {
&mut self.to_subsystems
}
fn spawn(&mut self, name: &'static str, s: Pin<Box<dyn Future<Output = ()> + Send>>)
-> ::std::result::Result<(), #error_ty>
{
self.to_overseer.unbounded_send(#support_crate ::ToOverseer::SpawnJob {
name,
subsystem: Some(self.name()),
s,
}).map_err(|_| #support_crate ::OverseerError::TaskSpawn(name))?;
Ok(())
}
fn spawn_blocking(&mut self, name: &'static str, s: Pin<Box<dyn Future<Output = ()> + Send>>)
-> ::std::result::Result<(), #error_ty>
{
self.to_overseer.unbounded_send(#support_crate ::ToOverseer::SpawnBlockingJob {
name,
subsystem: Some(self.name()),
s,
}).map_err(|_| #support_crate ::OverseerError::TaskSpawn(name))?;
Ok(())
}
}
}
}
/// Implement the additional subsystem accumulation traits, for simplified usage,
/// i.e. `${Subsystem}SenderTrait` and `${Subsystem}ContextTrait`.
pub(crate) fn impl_per_subsystem_helper_traits(
info: &OverseerInfo,
subsystem_ctx_name: &Ident,
subsystem_ctx_trait: &Ident,
subsystem_sender_name: &Ident,
subsystem_sender_trait: &Ident,
consumes: &Path,
outgoing: &[Path],
outgoing_wrapper: &Ident,
) -> TokenStream {
let all_messages_wrapper = &info.message_wrapper;
let signal_ty = &info.extern_signal_ty;
let error_ty = &info.extern_error_ty;
let support_crate = info.support_crate_name();
let mut ts = TokenStream::new();
// Create a helper trait bound of all outgoing messages, and the generated wrapper type
// for ease of use within subsystems:
let acc_sender_trait_bounds = quote! {
#support_crate ::SubsystemSender< #outgoing_wrapper >
#(
+ #support_crate ::SubsystemSender< #outgoing >
)*
+ #support_crate ::SubsystemSender< () >
+ Send
+ 'static
};
ts.extend(quote! {
/// A abstracting trait for usage with subsystems.
pub trait #subsystem_sender_trait : #acc_sender_trait_bounds
{}
impl<T> #subsystem_sender_trait for T
where
T: #acc_sender_trait_bounds
{}
});
// Create a helper accumulated per subsystem trait bound:
let where_clause = quote! {
#consumes: AssociateOutgoing + ::std::fmt::Debug + Send + 'static,
#all_messages_wrapper: From< #outgoing_wrapper >,
#all_messages_wrapper: From< #consumes >,
#all_messages_wrapper: From< () >,
#outgoing_wrapper: #( From< #outgoing > )+*,
#outgoing_wrapper: From< () >,
};
ts.extend(quote! {
/// Accumulative trait for a particular subsystem wrapper.
pub trait #subsystem_ctx_trait : SubsystemContext <
Message = #consumes,
Signal = #signal_ty,
OutgoingMessages = #outgoing_wrapper,
// Sender,
Error = #error_ty,
>
where
#where_clause
<Self as SubsystemContext>::Sender:
#subsystem_sender_trait
+ #acc_sender_trait_bounds,
{
/// Sender.
type Sender: #subsystem_sender_trait;
}
impl<T> #subsystem_ctx_trait for T
where
T: SubsystemContext <
Message = #consumes,
Signal = #signal_ty,
OutgoingMessages = #outgoing_wrapper,
// Sender
Error = #error_ty,
>,
#where_clause
<T as SubsystemContext>::Sender:
#subsystem_sender_trait
+ #acc_sender_trait_bounds,
{
type Sender = <T as SubsystemContext>::Sender;
}
});
ts.extend(impl_subsystem_context_trait_for(
parse_quote! { #consumes },
&Vec::from_iter(outgoing.iter().map(|path| {
parse_quote! { #path }
})),
parse_quote! { #outgoing_wrapper },
all_messages_wrapper,
subsystem_ctx_name,
subsystem_sender_name,
support_crate,
signal_ty,
error_ty,
));
ts
}
/// Generate the subsystem context type and provide `fn new` on it.
///
/// Note: The generated `fn new` is used by the [builder pattern](../impl_builder.rs).
pub(crate) fn impl_subsystem_context(
info: &OverseerInfo,
subsystem_sender_name: &Ident,
subsystem_ctx_name: &Ident,
) -> TokenStream {
let signal_ty = &info.extern_signal_ty;
let support_crate = info.support_crate_name();
let ts = quote! {
/// A context type that is given to the [`Subsystem`] upon spawning.
/// It can be used by [`Subsystem`] to communicate with other [`Subsystem`]s
/// or to spawn it's [`SubsystemJob`]s.
///
/// [`Overseer`]: struct.Overseer.html
/// [`Subsystem`]: trait.Subsystem.html
/// [`SubsystemJob`]: trait.SubsystemJob.html
#[derive(Debug)]
#[allow(missing_docs)]
pub struct #subsystem_ctx_name<M: AssociateOutgoing + Send + 'static> {
signals: #support_crate ::metered::MeteredReceiver< #signal_ty >,
messages: SubsystemIncomingMessages< M >,
to_subsystems: #subsystem_sender_name < <M as AssociateOutgoing>::OutgoingMessages >,
to_overseer: #support_crate ::metered::UnboundedMeteredSender<
#support_crate ::ToOverseer
>,
signals_received: SignalsReceived,
pending_incoming: Option<(usize, M)>,
name: &'static str
}
impl<M> #subsystem_ctx_name <M>
where
M: AssociateOutgoing + Send + 'static,
{
/// Create a new context.
fn new(
signals: #support_crate ::metered::MeteredReceiver< #signal_ty >,
messages: SubsystemIncomingMessages< M >,
to_subsystems: ChannelsOut,
to_overseer: #support_crate ::metered::UnboundedMeteredSender<#support_crate:: ToOverseer>,
name: &'static str
) -> Self {
let signals_received = SignalsReceived::default();
#subsystem_ctx_name :: <M> {
signals,
messages,
to_subsystems: #subsystem_sender_name :: < <M as AssociateOutgoing>::OutgoingMessages > {
channels: to_subsystems,
signals_received: signals_received.clone(),
_phantom: ::core::marker::PhantomData::default(),
},
to_overseer,
signals_received,
pending_incoming: None,
name
}
}
fn name(&self) -> &'static str {
self.name
}
}
};
ts
}
@@ -14,33 +14,44 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
#![deny(unused_crate_dependencies)]
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens}; use syn::{parse_quote, spanned::Spanned, Path};
use syn::{parse2, Result};
mod impl_builder; mod impl_builder;
mod impl_channels_out; mod impl_channels_out;
mod impl_dispatch;
mod impl_message_wrapper; mod impl_message_wrapper;
mod impl_misc;
mod impl_overseer; mod impl_overseer;
mod parse_attr; mod impl_subsystem_ctx_sender;
mod parse_struct; mod overseer;
mod parse;
use impl_builder::*; mod subsystem;
use impl_channels_out::*;
use impl_dispatch::*;
use impl_message_wrapper::*;
use impl_misc::*;
use impl_overseer::*;
use parse_attr::*;
use parse_struct::*;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use impl_builder::*;
use impl_channels_out::*;
use impl_message_wrapper::*;
use impl_overseer::*;
use impl_subsystem_ctx_sender::*;
use parse::*;
use self::{overseer::*, subsystem::*};
/// Obtain the support crate `Path` as `TokenStream`.
pub(crate) fn support_crate() -> Result<Path, proc_macro_crate::Error> {
Ok(if cfg!(test) {
parse_quote! {crate}
} else {
use proc_macro_crate::{crate_name, FoundCrate};
let crate_name = crate_name("polkadot-overseer-gen")?;
match crate_name {
FoundCrate::Itself => parse_quote! {crate},
FoundCrate::Name(name) => Ident::new(&name, Span::call_site()).into(),
}
})
}
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn overlord( pub fn overlord(
attr: proc_macro::TokenStream, attr: proc_macro::TokenStream,
@@ -53,58 +64,26 @@ pub fn overlord(
.into() .into()
} }
pub(crate) fn impl_overseer_gen( #[proc_macro_attribute]
attr: TokenStream, pub fn subsystem(
orig: TokenStream, attr: proc_macro::TokenStream,
) -> Result<proc_macro2::TokenStream> { item: proc_macro::TokenStream,
let args: AttrArgs = parse2(attr)?; ) -> proc_macro::TokenStream {
let message_wrapper = args.message_wrapper; let attr: TokenStream = attr.into();
let item: TokenStream = item.into();
let of: OverseerGuts = parse2(orig)?; impl_subsystem_context_trait_bounds(attr, item, MakeSubsystem::ImplSubsystemTrait)
.unwrap_or_else(|err| err.to_compile_error())
let support_crate_name = if cfg!(test) { .into()
quote! {crate} }
} else {
use proc_macro_crate::{crate_name, FoundCrate}; #[proc_macro_attribute]
let crate_name = crate_name("polkadot-overseer-gen") pub fn contextbounds(
.expect("Support crate polkadot-overseer-gen is present in `Cargo.toml`. qed"); attr: proc_macro::TokenStream,
match crate_name { item: proc_macro::TokenStream,
FoundCrate::Itself => quote! {crate}, ) -> proc_macro::TokenStream {
FoundCrate::Name(name) => Ident::new(&name, Span::call_site()).to_token_stream(), let attr: TokenStream = attr.into();
} let item: TokenStream = item.into();
}; impl_subsystem_context_trait_bounds(attr, item, MakeSubsystem::AddContextTraitBounds)
let info = OverseerInfo { .unwrap_or_else(|err| err.to_compile_error())
support_crate_name, .into()
subsystems: of.subsystems,
baggage: of.baggage,
overseer_name: of.name,
message_wrapper,
message_channel_capacity: args.message_channel_capacity,
signal_channel_capacity: args.signal_channel_capacity,
extern_event_ty: args.extern_event_ty,
extern_signal_ty: args.extern_signal_ty,
extern_error_ty: args.extern_error_ty,
extern_network_ty: args.extern_network_ty,
outgoing_ty: args.outgoing_ty,
};
let mut additive = impl_overseer_struct(&info);
additive.extend(impl_builder(&info));
additive.extend(impl_overseen_subsystem(&info));
additive.extend(impl_channels_out_struct(&info));
additive.extend(impl_misc(&info));
additive.extend(impl_message_wrapper_enum(&info)?);
additive.extend(impl_dispatch(&info));
let ts = expander::Expander::new("overlord-expansion")
.add_comment("Generated overseer code by `#[overlord(..)]`".to_owned())
.dry(!cfg!(feature = "expand"))
.verbose(false)
.fmt(expander::Edition::_2021)
.write_to_out_dir(additive)
.expect("Expander does not fail due to IO in OUT_DIR. qed");
Ok(ts)
} }
@@ -0,0 +1,67 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::TokenStream;
use syn::{parse2, Result};
use super::{parse::*, *};
pub(crate) fn impl_overseer_gen(
attr: TokenStream,
orig: TokenStream,
) -> Result<proc_macro2::TokenStream> {
let args: OverseerAttrArgs = parse2(attr)?;
let message_wrapper = args.message_wrapper;
let of: OverseerGuts = parse2(orig)?;
let support_crate = support_crate().expect("The crate this macro is run for, includes the proc-macro support as dependency, otherwise it could not be run in the first place. qed");
let info = OverseerInfo {
support_crate,
subsystems: of.subsystems,
baggage: of.baggage,
overseer_name: of.name,
message_wrapper,
message_channel_capacity: args.message_channel_capacity,
signal_channel_capacity: args.signal_channel_capacity,
extern_event_ty: args.extern_event_ty,
extern_signal_ty: args.extern_signal_ty,
extern_error_ty: args.extern_error_ty,
outgoing_ty: args.outgoing_ty,
};
let mut additive = impl_overseer_struct(&info);
additive.extend(impl_builder(&info));
additive.extend(impl_overseen_subsystem(&info));
additive.extend(impl_channels_out_struct(&info));
additive.extend(impl_subsystem_types_all(&info)?);
additive.extend(impl_message_wrapper_enum(&info)?);
let ts = expander::Expander::new("overlord-expansion")
.add_comment("Generated overseer code by `#[overlord(..)]`".to_owned())
.dry(!cfg!(feature = "expand"))
.verbose(true)
// once all our needed format options are available on stable
// we should enabled this again, until then too many warnings
// are generated
// .fmt(expander::Edition::_2021)
.write_to_out_dir(additive)
.expect("Expander does not fail due to IO in OUT_DIR. qed");
Ok(ts)
}
@@ -0,0 +1,39 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
mod kw {
syn::custom_keyword!(event);
syn::custom_keyword!(signal);
syn::custom_keyword!(error);
syn::custom_keyword!(outgoing);
syn::custom_keyword!(gen);
syn::custom_keyword!(signal_capacity);
syn::custom_keyword!(message_capacity);
syn::custom_keyword!(subsystem);
syn::custom_keyword!(prefix);
}
mod parse_overseer_attr;
mod parse_overseer_struct;
mod parse_subsystem_attr;
#[cfg(test)]
mod tests;
pub(crate) use self::{parse_overseer_attr::*, parse_overseer_struct::*};
pub(crate) use self::parse_subsystem_attr::*;
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::kw;
use proc_macro2::Span; use proc_macro2::Span;
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use std::collections::{hash_map::RandomState, HashMap}; use std::collections::{hash_map::RandomState, HashMap};
@@ -24,21 +25,9 @@ use syn::{
Error, Ident, LitInt, Path, Result, Token, Error, Ident, LitInt, Path, Result, Token,
}; };
mod kw {
syn::custom_keyword!(event);
syn::custom_keyword!(signal);
syn::custom_keyword!(error);
syn::custom_keyword!(network);
syn::custom_keyword!(outgoing);
syn::custom_keyword!(gen);
syn::custom_keyword!(signal_capacity);
syn::custom_keyword!(message_capacity);
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum OverseerAttrItem { enum OverseerAttrItem {
ExternEventType { tag: kw::event, eq_token: Token![=], value: Path }, ExternEventType { tag: kw::event, eq_token: Token![=], value: Path },
ExternNetworkType { tag: kw::network, eq_token: Token![=], value: Path },
ExternOverseerSignalType { tag: kw::signal, eq_token: Token![=], value: Path }, ExternOverseerSignalType { tag: kw::signal, eq_token: Token![=], value: Path },
ExternErrorType { tag: kw::error, eq_token: Token![=], value: Path }, ExternErrorType { tag: kw::error, eq_token: Token![=], value: Path },
OutgoingType { tag: kw::outgoing, eq_token: Token![=], value: Path }, OutgoingType { tag: kw::outgoing, eq_token: Token![=], value: Path },
@@ -53,9 +42,6 @@ impl ToTokens for OverseerAttrItem {
Self::ExternEventType { tag, eq_token, value } => { Self::ExternEventType { tag, eq_token, value } => {
quote! { #tag #eq_token, #value } quote! { #tag #eq_token, #value }
}, },
Self::ExternNetworkType { tag, eq_token, value } => {
quote! { #tag #eq_token, #value }
},
Self::ExternOverseerSignalType { tag, eq_token, value } => { Self::ExternOverseerSignalType { tag, eq_token, value } => {
quote! { #tag #eq_token, #value } quote! { #tag #eq_token, #value }
}, },
@@ -100,12 +86,6 @@ impl Parse for OverseerAttrItem {
eq_token: input.parse()?, eq_token: input.parse()?,
value: input.parse()?, value: input.parse()?,
}) })
} else if lookahead.peek(kw::network) {
Ok(OverseerAttrItem::ExternNetworkType {
tag: input.parse::<kw::network>()?,
eq_token: input.parse()?,
value: input.parse()?,
})
} else if lookahead.peek(kw::outgoing) { } else if lookahead.peek(kw::outgoing) {
Ok(OverseerAttrItem::OutgoingType { Ok(OverseerAttrItem::OutgoingType {
tag: input.parse::<kw::outgoing>()?, tag: input.parse::<kw::outgoing>()?,
@@ -138,15 +118,11 @@ impl Parse for OverseerAttrItem {
/// Attribute arguments /// Attribute arguments
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct AttrArgs { pub(crate) struct OverseerAttrArgs {
pub(crate) message_wrapper: Ident, pub(crate) message_wrapper: Ident,
pub(crate) extern_event_ty: Path, pub(crate) extern_event_ty: Path,
pub(crate) extern_signal_ty: Path, pub(crate) extern_signal_ty: Path,
pub(crate) extern_error_ty: Path, pub(crate) extern_error_ty: Path,
/// A external subsystem that both consumes and produces messages
/// but is not part of the band of subsystems, it's a mere proxy
/// to another entity that consumes/produces messages.
pub(crate) extern_network_ty: Option<Path>,
pub(crate) outgoing_ty: Option<Path>, pub(crate) outgoing_ty: Option<Path>,
pub(crate) signal_channel_capacity: usize, pub(crate) signal_channel_capacity: usize,
pub(crate) message_channel_capacity: usize, pub(crate) message_channel_capacity: usize,
@@ -170,7 +146,7 @@ macro_rules! extract_variant {
}; };
} }
impl Parse for AttrArgs { impl Parse for OverseerAttrArgs {
fn parse(input: &ParseBuffer) -> Result<Self> { fn parse(input: &ParseBuffer) -> Result<Self> {
let items: Punctuated<OverseerAttrItem, Token![,]> = let items: Punctuated<OverseerAttrItem, Token![,]> =
input.parse_terminated(OverseerAttrItem::parse)?; input.parse_terminated(OverseerAttrItem::parse)?;
@@ -198,18 +174,16 @@ impl Parse for AttrArgs {
let error = extract_variant!(unique, ExternErrorType; err = "Must declare the overseer error type via `error=..`.")?; let error = extract_variant!(unique, ExternErrorType; err = "Must declare the overseer error type via `error=..`.")?;
let event = extract_variant!(unique, ExternEventType; err = "Must declare the overseer event type via `event=..`.")?; let event = extract_variant!(unique, ExternEventType; err = "Must declare the overseer event type via `event=..`.")?;
let signal = extract_variant!(unique, ExternOverseerSignalType; err = "Must declare the overseer signal type via `span=..`.")?; let signal = extract_variant!(unique, ExternOverseerSignalType; err = "Must declare the overseer signal type via `signal=..`.")?;
let message_wrapper = extract_variant!(unique, MessageWrapperName; err = "Must declare the overseer generated wrapping message type via `gen=..`.")?; let message_wrapper = extract_variant!(unique, MessageWrapperName; err = "Must declare the overseer generated wrapping message type via `gen=..`.")?;
let network = extract_variant!(unique, ExternNetworkType);
let outgoing = extract_variant!(unique, OutgoingType); let outgoing = extract_variant!(unique, OutgoingType);
Ok(AttrArgs { Ok(OverseerAttrArgs {
signal_channel_capacity, signal_channel_capacity,
message_channel_capacity, message_channel_capacity,
extern_event_ty: event, extern_event_ty: event,
extern_signal_ty: signal, extern_signal_ty: signal,
extern_error_ty: error, extern_error_ty: error,
extern_network_ty: network,
outgoing_ty: outgoing, outgoing_ty: outgoing,
message_wrapper, message_wrapper,
}) })
@@ -17,32 +17,36 @@
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use std::collections::{hash_map::RandomState, HashMap, HashSet}; use std::collections::{hash_map::RandomState, HashMap, HashSet};
use syn::{ use syn::{
parenthesized,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
punctuated::Punctuated, punctuated::Punctuated,
spanned::Spanned, spanned::Spanned,
AttrStyle, Attribute, Error, Field, FieldsNamed, GenericParam, Ident, ItemStruct, Path, Result, token::Bracket,
Token, Type, Visibility, AttrStyle, Error, Field, FieldsNamed, GenericParam, Ident, ItemStruct, Path, Result, Token,
Type, Visibility,
}; };
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
mod kw { mod kw {
syn::custom_keyword!(wip); syn::custom_keyword!(wip);
syn::custom_keyword!(no_dispatch);
syn::custom_keyword!(blocking); syn::custom_keyword!(blocking);
syn::custom_keyword!(consumes);
syn::custom_keyword!(sends);
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum SubSysAttrItem { pub(crate) enum SubSysAttrItem {
/// The subsystem is still a work in progress /// The subsystem is still a work in progress
/// and should not be communicated with. /// and should not be communicated with.
Wip(kw::wip), Wip(kw::wip),
/// The subsystem is blocking and requires to be /// The subsystem is blocking and requires to be
/// spawned on an exclusive thread. /// spawned on an exclusive thread.
Blocking(kw::blocking), Blocking(kw::blocking),
/// External messages should not be - after being converted - /// Message to be sent by this subsystem.
/// be dispatched to the annotated subsystem. Sends(Sends),
NoDispatch(kw::no_dispatch), /// Message to be consumed by this subsystem.
Consumes(Consumes),
} }
impl Parse for SubSysAttrItem { impl Parse for SubSysAttrItem {
@@ -52,10 +56,10 @@ impl Parse for SubSysAttrItem {
Self::Wip(input.parse::<kw::wip>()?) Self::Wip(input.parse::<kw::wip>()?)
} else if lookahead.peek(kw::blocking) { } else if lookahead.peek(kw::blocking) {
Self::Blocking(input.parse::<kw::blocking>()?) Self::Blocking(input.parse::<kw::blocking>()?)
} else if lookahead.peek(kw::no_dispatch) { } else if lookahead.peek(kw::sends) {
Self::NoDispatch(input.parse::<kw::no_dispatch>()?) Self::Sends(input.parse::<Sends>()?)
} else { } else {
return Err(lookahead.error()) Self::Consumes(input.parse::<Consumes>()?)
}) })
} }
} }
@@ -69,8 +73,11 @@ impl ToTokens for SubSysAttrItem {
Self::Blocking(blocking) => { Self::Blocking(blocking) => {
quote! { #blocking } quote! { #blocking }
}, },
Self::NoDispatch(no_dispatch) => { Self::Sends(_) => {
quote! { #no_dispatch } quote! {}
},
Self::Consumes(_) => {
quote! {}
}, },
}; };
tokens.extend(ts.into_iter()); tokens.extend(ts.into_iter());
@@ -78,7 +85,7 @@ impl ToTokens for SubSysAttrItem {
} }
/// A field of the struct annotated with /// A field of the struct annotated with
/// `#[subsystem(no_dispatch, , A | B | C)]` /// `#[subsystem(A, B, C)]`
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct SubSysField { pub(crate) struct SubSysField {
/// Name of the field. /// Name of the field.
@@ -87,11 +94,10 @@ pub(crate) struct SubSysField {
/// which is also used `#wrapper_message :: #variant` variant /// which is also used `#wrapper_message :: #variant` variant
/// part. /// part.
pub(crate) generic: Ident, pub(crate) generic: Ident,
/// Type to be consumed by the subsystem. /// Type of message to be consumed by the subsystem.
pub(crate) consumes: Path, pub(crate) message_to_consume: Path,
/// If `no_dispatch` is present, if the message is incoming via /// Types of messages to be sent by the subsystem.
/// an `extern` `Event`, it will not be dispatched to all subsystems. pub(crate) messages_to_send: Vec<Path>,
pub(crate) no_dispatch: bool,
/// If the subsystem implementation is blocking execution and hence /// If the subsystem implementation is blocking execution and hence
/// has to be spawned on a separate thread or thread pool. /// has to be spawned on a separate thread or thread pool.
pub(crate) blocking: bool, pub(crate) blocking: bool,
@@ -115,6 +121,15 @@ macro_rules! extract_variant {
($unique:expr, $variant:ident ; err = $err:expr) => { ($unique:expr, $variant:ident ; err = $err:expr) => {
extract_variant!($unique, $variant).ok_or_else(|| Error::new(Span::call_site(), $err)) extract_variant!($unique, $variant).ok_or_else(|| Error::new(Span::call_site(), $err))
}; };
($unique:expr, $variant:ident take) => {
$unique.values().find_map(|item| {
if let SubSysAttrItem::$variant(value) = item {
Some(value.clone())
} else {
None
}
})
};
($unique:expr, $variant:ident) => { ($unique:expr, $variant:ident) => {
$unique.values().find_map(|item| { $unique.values().find_map(|item| {
if let SubSysAttrItem::$variant(_) = item { if let SubSysAttrItem::$variant(_) = item {
@@ -126,57 +141,113 @@ macro_rules! extract_variant {
}; };
} }
pub(crate) struct SubSystemTags { #[derive(Debug, Clone)]
pub(crate) struct Sends {
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) attrs: Vec<Attribute>, pub(crate) keyword_sends: kw::sends,
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) no_dispatch: bool, pub(crate) colon: Token![:],
/// The subsystem is in progress, only generate the `Wrapper` variant, but do not forward messages #[allow(dead_code)]
/// and also not include the subsystem in the list of subsystems. pub(crate) bracket: Option<Bracket>,
pub(crate) wip: bool, pub(crate) sends: Punctuated<Path, Token![,]>,
pub(crate) blocking: bool, }
impl Parse for Sends {
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
let content;
let keyword_sends = input.parse()?;
let colon = input.parse()?;
let (bracket, sends) = if !input.peek(syn::token::Bracket) {
let mut sends = Punctuated::new();
sends.push_value(input.parse::<Path>()?);
(None, sends)
} else {
let bracket = Some(syn::bracketed!(content in input));
let sends = Punctuated::parse_terminated(&content)?;
(bracket, sends)
};
Ok(Self { keyword_sends, colon, bracket, sends })
}
}
#[derive(Debug, Clone)]
pub(crate) struct Consumes {
#[allow(dead_code)]
pub(crate) keyword_consumes: Option<kw::consumes>,
#[allow(dead_code)]
pub(crate) colon: Option<Token![:]>,
pub(crate) consumes: Path, pub(crate) consumes: Path,
} }
impl Parse for SubSystemTags { impl Parse for Consumes {
fn parse(input: syn::parse::ParseStream) -> Result<Self> { fn parse(input: syn::parse::ParseStream) -> Result<Self> {
let attrs = Attribute::parse_outer(input)?; let lookahead = input.lookahead1();
Ok(if lookahead.peek(kw::consumes) {
Self {
keyword_consumes: Some(input.parse()?),
colon: input.parse()?,
consumes: input.parse()?,
}
} else {
Self { keyword_consumes: None, colon: None, consumes: input.parse()? }
})
}
}
/// Parses `(Foo, sends = [Bar, Baz])`
/// including the `(` and `)`.
#[derive(Debug, Clone)]
pub(crate) struct SubSystemAttrItems {
/// The subsystem is in progress, only generate the `Wrapper` variant, but do not forward messages
/// and also not include the subsystem in the list of subsystems.
pub(crate) wip: bool,
/// If there are blocking components in the subsystem and hence it should be
/// spawned on a dedicated thread pool for such subssytems.
pub(crate) blocking: bool,
/// The message type being consumed by the subsystem.
pub(crate) consumes: Option<Consumes>,
pub(crate) sends: Option<Sends>,
}
impl Parse for SubSystemAttrItems {
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
let span = input.span();
let input = input;
let content; let content;
let _ = syn::parenthesized!(content in input); let _paren_token = parenthesized!(content in input);
let mut items = Punctuated::new(); let items = content.call(Punctuated::<SubSysAttrItem, Token![,]>::parse_terminated)?;
while let Ok(tag) = content.call(SubSysAttrItem::parse) {
items.push_value(tag);
items.push_punct(content.call(<Token![,]>::parse)?);
}
assert!(items.empty_or_trailing(), "Always followed by the message type to consume. qed");
let consumes = content.parse::<Path>()?;
let mut unique = HashMap::< let mut unique = HashMap::<
std::mem::Discriminant<SubSysAttrItem>, std::mem::Discriminant<SubSysAttrItem>,
SubSysAttrItem, SubSysAttrItem,
RandomState, RandomState,
>::default(); >::default();
for item in items { for item in items {
if let Some(first) = unique.insert(std::mem::discriminant(&item), item.clone()) { if let Some(first) = unique.insert(std::mem::discriminant(&item), item.clone()) {
let mut e = Error::new( let mut e =
item.span(), Error::new(item.span(), "Duplicate definition of subsystem attribute found");
format!("Duplicate definition of subsystem attribute found"),
);
e.combine(Error::new(first.span(), "previously defined here.")); e.combine(Error::new(first.span(), "previously defined here."));
return Err(e) return Err(e)
} }
} }
let no_dispatch = extract_variant!(unique, NoDispatch; default = false); // A subsystem makes no sense if not one of them is provided
let sends = extract_variant!(unique, Sends take);
let consumes = extract_variant!(unique, Consumes take);
if sends.as_ref().map(|sends| sends.sends.is_empty()).unwrap_or(true) && consumes.is_none()
{
return Err(Error::new(
span,
"Must have at least one of `consumes: [..]` and `sends: [..]`.",
))
}
let blocking = extract_variant!(unique, Blocking; default = false); let blocking = extract_variant!(unique, Blocking; default = false);
let wip = extract_variant!(unique, Wip; default = false); let wip = extract_variant!(unique, Wip; default = false);
Ok(Self { attrs, no_dispatch, blocking, consumes, wip }) Ok(Self { blocking, wip, sends, consumes })
} }
} }
@@ -192,7 +263,7 @@ pub(crate) struct BaggageField {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct OverseerInfo { pub(crate) struct OverseerInfo {
/// Where the support crate `::polkadot_overseer_gen` lives. /// Where the support crate `::polkadot_overseer_gen` lives.
pub(crate) support_crate_name: TokenStream, pub(crate) support_crate: Path,
/// Fields annotated with `#[subsystem(..)]`. /// Fields annotated with `#[subsystem(..)]`.
pub(crate) subsystems: Vec<SubSysField>, pub(crate) subsystems: Vec<SubSysField>,
@@ -216,11 +287,8 @@ pub(crate) struct OverseerInfo {
/// Incoming event type from the outer world, usually an external framework of some sort. /// Incoming event type from the outer world, usually an external framework of some sort.
pub(crate) extern_event_ty: Path, pub(crate) extern_event_ty: Path,
/// Incoming event type from an external entity, commonly from the network.
pub(crate) extern_network_ty: Option<Path>,
/// Type of messages that are sent to an external subsystem. /// Type of messages that are sent to an external subsystem.
/// Merely here to be included during generation of `message_wrapper` type. /// Merely here to be included during generation of `#message_wrapper` type.
pub(crate) outgoing_ty: Option<Path>, pub(crate) outgoing_ty: Option<Path>,
/// Incoming event type from the outer world, commonly from the network. /// Incoming event type from the outer world, commonly from the network.
@@ -228,8 +296,8 @@ pub(crate) struct OverseerInfo {
} }
impl OverseerInfo { impl OverseerInfo {
pub(crate) fn support_crate_name(&self) -> &TokenStream { pub(crate) fn support_crate_name(&self) -> &Path {
&self.support_crate_name &self.support_crate
} }
pub(crate) fn variant_names(&self) -> Vec<Ident> { pub(crate) fn variant_names(&self) -> Vec<Ident> {
@@ -297,8 +365,11 @@ impl OverseerInfo {
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
pub(crate) fn consumes(&self) -> Vec<Path> { pub(crate) fn any_message(&self) -> Vec<Path> {
self.subsystems.iter().map(|ssf| ssf.consumes.clone()).collect::<Vec<_>>() self.subsystems
.iter()
.map(|ssf| ssf.message_to_consume.clone())
.collect::<Vec<_>>()
} }
pub(crate) fn channel_names_without_wip(&self, suffix: &'static str) -> Vec<Ident> { pub(crate) fn channel_names_without_wip(&self, suffix: &'static str) -> Vec<Ident> {
@@ -313,7 +384,7 @@ impl OverseerInfo {
self.subsystems self.subsystems
.iter() .iter()
.filter(|ssf| !ssf.wip) .filter(|ssf| !ssf.wip)
.map(|ssf| ssf.consumes.clone()) .map(|ssf| ssf.message_to_consume.clone())
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
} }
@@ -341,7 +412,8 @@ impl OverseerGuts {
// for the builder pattern besides other places. // for the builder pattern besides other places.
let mut unique_subsystem_idents = HashSet::<Ident>::new(); let mut unique_subsystem_idents = HashSet::<Ident>::new();
for Field { attrs, vis, ident, ty, .. } in fields.named.into_iter() { for Field { attrs, vis, ident, ty, .. } in fields.named.into_iter() {
let mut consumes = // collect all subsystem annotations per field
let mut subsystem_attr =
attrs.iter().filter(|attr| attr.style == AttrStyle::Outer).filter_map(|attr| { attrs.iter().filter(|attr| attr.style == AttrStyle::Outer).filter_map(|attr| {
let span = attr.path.span(); let span = attr.path.span();
attr.path.get_ident().filter(|ident| *ident == "subsystem").map(move |_ident| { attr.path.get_ident().filter(|ident| *ident == "subsystem").map(move |_ident| {
@@ -349,53 +421,75 @@ impl OverseerGuts {
(attr_tokens, span) (attr_tokens, span)
}) })
}); });
let ident = let ident = ident.ok_or_else(|| {
ident.ok_or_else(|| Error::new(ty.span(), "Missing identifier for member. BUG"))?; Error::new(
ty.span(),
"Missing identifier for field, only named fields are expceted.",
)
})?;
if let Some((attr_tokens, span)) = consumes.next() { // a `#[subsystem(..)]` annotation exists
if let Some((_attr_tokens2, span2)) = consumes.next() { if let Some((attr_tokens, span)) = subsystem_attr.next() {
if let Some((_attr_tokens2, span2)) = subsystem_attr.next() {
return Err({ return Err({
let mut err = Error::new(span, "The first subsystem annotation is at"); let mut err = Error::new(span, "The first subsystem annotation is at");
err.combine(Error::new(span2, "but another here for the same field.")); err.combine(Error::new(span2, "but another here for the same field."));
err err
}) })
} }
let mut consumes_paths = Vec::with_capacity(attrs.len());
let span = attr_tokens.span();
let attr_tokens = attr_tokens.clone(); let attr_tokens = attr_tokens.clone();
let variant: SubSystemTags = syn::parse2(attr_tokens.clone())?; let subsystem_attrs: SubSystemAttrItems = syn::parse2(attr_tokens.clone())?;
consumes_paths.push(variant.consumes);
let field_ty = try_type_to_path(ty, span)?; let field_ty = try_type_to_path(ty, span)?;
let generic = field_ty let generic = field_ty
.get_ident() .get_ident()
.ok_or_else(|| { .ok_or_else(|| {
Error::new(field_ty.span(), "Must be an identifier, not a path.") Error::new(
field_ty.span(),
"Must be an identifier, not a path. It will be used as a generic.",
)
})? })?
.clone(); .clone();
// check for unique subsystem name, otherwise we'd create invalid code:
if let Some(previous) = unique_subsystem_idents.get(&generic) { if let Some(previous) = unique_subsystem_idents.get(&generic) {
let mut e = Error::new( let mut e = Error::new(generic.span(), "Duplicate subsystem names");
generic.span(),
format!("Duplicate subsystem names `{}`", generic),
);
e.combine(Error::new(previous.span(), "previously defined here.")); e.combine(Error::new(previous.span(), "previously defined here."));
return Err(e) return Err(e)
} }
unique_subsystem_idents.insert(generic.clone()); unique_subsystem_idents.insert(generic.clone());
let SubSystemAttrItems { wip, blocking, consumes, sends, .. } = subsystem_attrs;
// messages to be sent
let sends = if let Some(sends) = sends {
Vec::from_iter(sends.sends.iter().cloned())
} else {
vec![]
};
// messages deemed for consumption
let consumes = if let Some(consumes) = consumes {
consumes.consumes
} else {
return Err(Error::new(span, "Must provide exactly one consuming message type"))
};
subsystems.push(SubSysField { subsystems.push(SubSysField {
name: ident, name: ident,
generic, generic,
consumes: consumes_paths[0].clone(), message_to_consume: consumes,
no_dispatch: variant.no_dispatch, messages_to_send: sends,
wip: variant.wip, wip,
blocking: variant.blocking, blocking,
}); });
} else { } else {
let field_ty = try_type_to_path(ty, ident.span())?; let field_ty = try_type_to_path(ty, ident.span())?;
let generic = field_ty let generic = field_ty
.get_ident() .get_ident()
.map(|ident| baggage_generics.contains(ident)) .map(|ident| baggage_generics.contains(ident))
.unwrap_or_default(); .unwrap_or(false);
baggage.push(BaggageField { field_name: ident, generic, field_ty, vis }); baggage.push(BaggageField { field_name: ident, generic, field_ty, vis });
} }
} }
@@ -0,0 +1,144 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::kw;
use proc_macro2::Span;
use quote::{quote, ToTokens};
use std::collections::{hash_map::RandomState, HashMap};
use syn::{
parse::{Parse, ParseBuffer},
punctuated::Punctuated,
spanned::Spanned,
Error, Ident, Path, Result, Token,
};
#[derive(Clone, Debug)]
enum SubsystemAttrItem {
/// Error type provided by the user.
Error { tag: kw::error, eq_token: Token![=], value: Path },
/// For which slot in the overseer this should be plugged.
///
/// The subsystem implementation can and should have a different name
/// from the declared parameter type in the overseer.
Subsystem { tag: Option<kw::subsystem>, eq_token: Option<Token![=]>, value: Ident },
/// The prefix to apply when a subsystem is implemented in a different file/crate
/// than the overseer itself.
///
/// Important for `#[subsystem(..)]` to reference the traits correctly.
TraitPrefix { tag: kw::prefix, eq_token: Token![=], value: Path },
}
impl ToTokens for SubsystemAttrItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let ts = match self {
Self::TraitPrefix { tag, eq_token, value } => {
quote! { #tag #eq_token, #value }
},
Self::Error { tag, eq_token, value } => {
quote! { #tag #eq_token, #value }
},
Self::Subsystem { tag, eq_token, value } => {
quote! { #tag #eq_token, #value }
},
};
tokens.extend(ts.into_iter());
}
}
impl Parse for SubsystemAttrItem {
fn parse(input: &ParseBuffer) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(kw::error) {
Ok(SubsystemAttrItem::Error {
tag: input.parse::<kw::error>()?,
eq_token: input.parse()?,
value: input.parse()?,
})
} else if lookahead.peek(kw::prefix) {
Ok(SubsystemAttrItem::TraitPrefix {
tag: input.parse::<kw::prefix>()?,
eq_token: input.parse()?,
value: input.parse()?,
})
} else if lookahead.peek(kw::subsystem) {
Ok(SubsystemAttrItem::Subsystem {
tag: Some(input.parse::<kw::subsystem>()?),
eq_token: Some(input.parse()?),
value: input.parse()?,
})
} else {
Ok(SubsystemAttrItem::Subsystem { tag: None, eq_token: None, value: input.parse()? })
}
}
}
/// Attribute arguments `$args` in `#[subsystem( $args )]`.
#[derive(Clone, Debug)]
pub(crate) struct SubsystemAttrArgs {
span: Span,
pub(crate) error_path: Option<Path>,
pub(crate) subsystem_ident: Ident,
pub(crate) trait_prefix_path: Option<Path>,
}
impl Spanned for SubsystemAttrArgs {
fn span(&self) -> Span {
self.span.clone()
}
}
macro_rules! extract_variant {
($unique:expr, $variant:ident ; default = $fallback:expr) => {
extract_variant!($unique, $variant).unwrap_or_else(|| $fallback)
};
($unique:expr, $variant:ident ; err = $err:expr) => {
extract_variant!($unique, $variant).ok_or_else(|| Error::new(Span::call_site(), $err))
};
($unique:expr, $variant:ident) => {
$unique.values().find_map(|item| match item {
SubsystemAttrItem::$variant { value, .. } => Some(value.clone()),
_ => None,
})
};
}
impl Parse for SubsystemAttrArgs {
fn parse(input: &ParseBuffer) -> Result<Self> {
let span = input.span();
let items: Punctuated<SubsystemAttrItem, Token![,]> =
input.parse_terminated(SubsystemAttrItem::parse)?;
let mut unique = HashMap::<
std::mem::Discriminant<SubsystemAttrItem>,
SubsystemAttrItem,
RandomState,
>::default();
for item in items {
if let Some(first) = unique.insert(std::mem::discriminant(&item), item.clone()) {
let mut e = Error::new(
item.span(),
format!("Duplicate definition of subsystem generation type found"),
);
e.combine(Error::new(first.span(), "previously defined here."));
return Err(e)
}
}
let error_path = extract_variant!(unique, Error);
let subsystem_ident = extract_variant!(unique, Subsystem; err = "Must annotate the identical overseer error type via `subsystem=..` or plainly as `Subsystem` as specified in the overseer declaration.")?;
let trait_prefix_path = extract_variant!(unique, TraitPrefix);
Ok(SubsystemAttrArgs { span, error_path, subsystem_ident, trait_prefix_path })
}
}
@@ -0,0 +1,295 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use crate::{SubSysAttrItem, SubSystemAttrItems};
use assert_matches::assert_matches;
use quote::quote;
use syn::parse_quote;
mod attr {
use super::*;
#[test]
fn attr_full_works() {
let attr: OverseerAttrArgs = parse_quote! {
gen=AllMessage, event=::some::why::ExternEvent, signal=SigSigSig, signal_capacity=111, message_capacity=222,
error=OverseerError,
};
assert_matches!(attr, OverseerAttrArgs {
message_channel_capacity,
signal_channel_capacity,
..
} => {
assert_eq!(message_channel_capacity, 222);
assert_eq!(signal_channel_capacity, 111);
});
}
#[test]
fn attr_partial_works() {
let attr: OverseerAttrArgs = parse_quote! {
gen=AllMessage, event=::some::why::ExternEvent, signal=::foo::SigSigSig,
error=OverseerError,
};
assert_matches!(attr, OverseerAttrArgs {
message_channel_capacity: _,
signal_channel_capacity: _,
..
} => {
});
}
}
mod strukt {
use super::*;
#[test]
fn parse_subsystem_attr_item_works_00_wip() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
wip
}), Ok(SubSysAttrItem::Wip(_)) => {
});
}
#[test]
fn parse_subsystem_attr_item_works_02_sends() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
sends: [A, B, C]
}), Ok(SubSysAttrItem::Sends(sends)) => {
assert_eq!(sends.sends.len(), 3);
});
}
#[test]
fn parse_subsystem_attr_item_works_03_sends() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
sends: [A]
}), Ok(SubSysAttrItem::Sends(sends)) => {
assert_eq!(sends.sends.len(), 1);
});
}
#[test]
fn parse_subsystem_attr_item_works_04_sends() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
sends: [A,]
}), Ok(SubSysAttrItem::Sends(sends)) => {
assert_eq!(sends.sends.len(), 1);
});
}
#[test]
fn parse_subsystem_attr_item_works_05_sends() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
sends: []
}), Ok(SubSysAttrItem::Sends(sends)) => {
assert_eq!(sends.sends.len(), 0);
});
}
#[test]
fn parse_subsystem_attr_item_works_06_consumes() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
consumes: Foo
}), Ok(SubSysAttrItem::Consumes(_consumes)) => {
});
}
#[test]
fn parse_subsystem_attr_item_works_07_consumes() {
assert_matches!(
syn::parse2::<SubSysAttrItem>(quote! {
Foo
}), Ok(SubSysAttrItem::Consumes(_consumes)) => {
});
}
#[test]
fn parse_subsystem_attributes_works_00() {
syn::parse2::<SubSystemAttrItems>(quote! {
(wip, blocking, consumes: Foo, sends: [])
})
.unwrap();
}
#[test]
fn parse_subsystem_attributes_works_01() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(blocking, Foo, sends: [])
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_02() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(consumes: Foo, sends: [Bar])
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_03() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(blocking, consumes: Foo, sends: [Bar])
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_04() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(wip, consumes: Foo, sends: [Bar])
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_05() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(consumes: Foo)
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_06() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(sends: [Foo], consumes: Bar)
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_07_duplicate_send() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(sends: [Foo], Bar, Y)
}), Err(e) => {
dbg!(e)
});
}
#[test]
fn parse_subsystem_attributes_works_08() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(sends: [Foo], consumes: Bar)
}), Ok(_) => {
});
}
#[test]
fn parse_subsystem_attributes_works_09_neither_consumes_nor_sends() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(sends: [])
}), Err(e) => {
// must either consume smth or sends smth, neither is NOK
dbg!(e)
});
}
#[test]
fn parse_subsystem_attributes_works_10_empty_with_braces() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
()
}), Err(e) => {
dbg!(e)
});
}
#[test]
fn parse_subsystem_attributes_works_11_empty() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
}), Err(e) => {
dbg!(e)
});
}
#[test]
fn parse_subsystem_attributes_works_12_duplicate_consumes_different_fmt() {
assert_matches!(
syn::parse2::<SubSystemAttrItems>(quote! {
(Foo, consumes = Foo)
}), Err(e) => {
dbg!(e)
});
}
#[test]
fn struct_parse_baggage() {
let item: OverseerGuts = parse_quote! {
pub struct Ooooh<X = Pffffffft> where X: Secrit {
#[subsystem(consumes: Foo, sends: [])]
sub0: FooSubsystem,
metrics: Metrics,
}
};
let _ = dbg!(item);
}
#[test]
fn struct_parse_full() {
let item: OverseerGuts = parse_quote! {
pub struct Ooooh<X = Pffffffft> where X: Secrit {
#[subsystem(consumes: Foo, sends: [])]
sub0: FooSubsystem,
#[subsystem(blocking, consumes: Bar, sends: [])]
yyy: BaersBuyBilliardBalls,
#[subsystem(blocking, consumes: Twain, sends: [])]
fff: Beeeeep,
#[subsystem(consumes: Rope)]
mc: MountainCave,
metrics: Metrics,
}
};
let _ = dbg!(item);
}
#[test]
fn struct_parse_basic() {
let item: OverseerGuts = parse_quote! {
pub struct Ooooh {
#[subsystem(consumes: Foo, sends: [])]
sub0: FooSubsystem,
}
};
let _ = dbg!(item);
}
}
@@ -0,0 +1,310 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Generates the bounds for a particular subsystem `Context` and associate `type Sender`.
//!
//!
//! ## Implement `trait Subsystem<Context, Error>` via `subsystem`
//!
//! ```ignore
//! # use polkadot_overseer_gen_proc_macro::subsystem;
//! # mod somewhere {
//! # use polkadot_overseer_gen_proc_macro::overlord;
//! # pub use polkadot_overseer_gen::*;
//! #
//! # #[derive(Debug, thiserror::Error)]
//! # #[error("Yikes!")]
//! # pub struct Yikes;
//! # impl From<OverseerError> for Yikes {
//! # fn from(_: OverseerError) -> Yikes { Yikes }
//! # }
//! # impl From<mpsc::SendError> for Yikes {
//! # fn from(_: mpsc::SendError) -> Yikes { Yikes }
//! # }
//! #
//! # #[derive(Debug)]
//! # pub struct Eve;
//! #
//! # #[derive(Debug, Clone)]
//! # pub struct Sig;
//! #
//! # #[derive(Debug, Clone, Copy)]
//! # pub struct A;
//! # #[derive(Debug, Clone, Copy)]
//! # pub struct B;
//! #
//! # #[overlord(signal=Sig, gen=AllOfThem, event=Eve, error=Yikes)]
//! # pub struct Wonderland {
//! # #[subsystem(A, sends: [B])]
//! # foo: Foo,
//! # #[subsystem(B, sends: [A])]
//! # bar: Bar,
//! # }
//! # }
//! # use somewhere::{Yikes, SpawnedSubsystem};
//! #
//! # struct FooSubsystem;
//! #
//! #[subsystem(Foo, error = Yikes, prefix = somewhere)]
//! impl<Context> FooSubsystem {
//! fn start(self, context: Context) -> SpawnedSubsystem<Yikes> {
//! // ..
//! # let _ = context;
//! # unimplemented!()
//! }
//! }
//! ```
//!
//! expands to
//!
//! ```ignore
//! # use polkadot_overseer_gen_proc_macro::subsystem;
//! # mod somewhere {
//! # use polkadot_overseer_gen_proc_macro::overlord;
//! # pub use polkadot_overseer_gen::*;
//! #
//! # #[derive(Debug, thiserror::Error)]
//! # #[error("Yikes!")]
//! # pub struct Yikes;
//! # impl From<OverseerError> for Yikes {
//! # fn from(_: OverseerError) -> Yikes { Yikes }
//! # }
//! # impl From<mpsc::SendError> for Yikes {
//! # fn from(_: mpsc::SendError) -> Yikes { Yikes }
//! # }
//! #
//! # #[derive(Debug)]
//! # pub struct Eve;
//! #
//! # #[derive(Debug, Clone)]
//! # pub struct Sig;
//! #
//! # #[derive(Debug, Clone, Copy)]
//! # pub struct A;
//! # #[derive(Debug, Clone, Copy)]
//! # pub struct B;
//! #
//! # #[overlord(signal=Sig, gen=AllOfThem, event=Eve, error=Yikes)]
//! # pub struct Wonderland {
//! # #[subsystem(A, sends: [B])]
//! # foo: Foo,
//! # #[subsystem(B, sends: [A])]
//! # bar: Bar,
//! # }
//! # }
//! # use somewhere::{Yikes, SpawnedSubsystem};
//! # use polkadot_overseer_gen as support_crate;
//! #
//! # struct FooSubsystem;
//! #
//! impl<Context> support_crate::Subsystem<Context, Yikes> for FooSubsystem
//! where
//! Context: somewhere::FooContextTrait,
//! Context: support_crate::SubsystemContext,
//! <Context as somewhere::FooContextTrait>::Sender: somewhere::FooSenderTrait,
//! <Context as support_crate::SubsystemContext>::Sender: somewhere::FooSenderTrait,
//! {
//! fn start(self, context: Context) -> SpawnedSubsystem<Yikes> {
//! // ..
//! # let _ = context;
//! # unimplemented!()
//! }
//! }
//! ```
//!
//! where `support_crate` is either equivalent to `somewhere` or derived from the cargo manifest.
//!
//!
//! ## Add additional trait bounds for a generic `Context` via `contextbounds`
//!
//! ### To an `ImplItem`
//!
//! ```ignore
//! #[contextbounds(Foo, prefix = somewhere)]
//! impl<Context> X {
//! ..
//! }
//! ```
//!
//! expands to
//!
//! ```ignore
//! impl<Context> X
//! where
//! Context: somewhere::FooSubsystemTrait,
//! Context: support_crate::SubsystemContext,
//! <Context as somewhere::FooContextTrait>::Sender: somewhere::FooSenderTrait,
//! <Context as support_crate::SubsystemContext>::Sender: somewhere::FooSenderTrait,
//! {
//! }
//! ```
//!
//! ### To a free standing `Fn` (not a method, that's covered by the above)
//!
//! ```ignore
//! #[contextbounds(Foo, prefix = somewhere)]
//! fn do_smth<Context>(context: &mut Context) {
//! ..
//! }
//! ```
//!
//! expands to
//!
//! ```ignore
//! fn do_smth<Context>(context: &mut Context)
//! where
//! Context: somewhere::FooSubsystemTrait,
//! Context: support_crate::SubsystemContext,
//! <Context as somewhere::FooContextTrait>::Sender: somewhere::FooSenderTrait,
//! <Context as support_crate::SubsystemContext>::Sender: somewhere::FooSenderTrait,
//! {
//! }
//! ```
use proc_macro2::TokenStream;
use quote::{format_ident, ToTokens};
use syn::{parse2, parse_quote, punctuated::Punctuated, Result};
use super::{parse::*, *};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum MakeSubsystem {
/// Implements `trait Subsystem` and apply the trait bounds to the `Context` generic.
///
/// Relevant to `impl Item` only.
ImplSubsystemTrait,
/// Only apply the trait bounds to the context.
AddContextTraitBounds,
}
pub(crate) fn impl_subsystem_context_trait_bounds(
attr: TokenStream,
orig: TokenStream,
make_subsystem: MakeSubsystem,
) -> Result<proc_macro2::TokenStream> {
let args = parse2::<SubsystemAttrArgs>(attr.clone())?;
let span = args.span();
let SubsystemAttrArgs { error_path, subsystem_ident, trait_prefix_path, .. } = args;
let mut item = parse2::<syn::Item>(orig)?;
// always prefer the direct usage, if it's not there, let's see if there is
// a `prefix=*` provided. Either is ok.
// Technically this is two different things:
// The place where the `#[overlord]` is annotated is where all `trait *SenderTrait` and
// `trait *ContextTrait` types exist.
// The other usage is the true support crate `polkadot-overseer-gen`, where the static ones
// are declared.
// Right now, if the `support_crate` is not included, it falls back silently to the `trait_prefix_path`.
let support_crate = support_crate()
.or_else(|_e| {
trait_prefix_path.clone().ok_or_else(|| {
syn::Error::new(attr.span(), "Couldn't find `polkadot-overseer-gen` in manifest, but also missing a `prefix=` to help trait bound resolution")
})
})?;
let trait_prefix_path = trait_prefix_path.unwrap_or_else(|| parse_quote! { self });
if trait_prefix_path.segments.trailing_punct() {
return Err(syn::Error::new(trait_prefix_path.span(), "Must not end with `::`"))
}
let subsystem_ctx_trait = format_ident!("{}ContextTrait", subsystem_ident);
let subsystem_sender_trait = format_ident!("{}SenderTrait", subsystem_ident);
let extra_where_predicates: Punctuated<syn::WherePredicate, syn::Token![,]> = parse_quote! {
Context: #trait_prefix_path::#subsystem_ctx_trait,
Context: #support_crate::SubsystemContext,
<Context as #trait_prefix_path::#subsystem_ctx_trait>::Sender: #trait_prefix_path::#subsystem_sender_trait,
<Context as #support_crate::SubsystemContext>::Sender: #trait_prefix_path::#subsystem_sender_trait,
};
let apply_ctx_bound_if_present = move |generics: &mut syn::Generics| -> bool {
if generics
.params
.iter()
.find(|generic| match generic {
syn::GenericParam::Type(ty) if ty.ident == "Context" => true,
_ => false,
})
.is_some()
{
let where_clause = generics.make_where_clause();
where_clause.predicates.extend(extra_where_predicates.clone());
true
} else {
false
}
};
match item {
syn::Item::Impl(ref mut struktured_impl) => {
if make_subsystem == MakeSubsystem::ImplSubsystemTrait {
let error_path = error_path.ok_or_else(|| {
syn::Error::new(
span,
"Must annotate the identical overseer error type via `error=..`.",
)
})?;
// Only replace the subsystem trait if it's desired.
struktured_impl.trait_.replace((
None,
parse_quote! {
#support_crate::Subsystem<Context, #error_path>
},
syn::token::For::default(),
));
}
apply_ctx_bound_if_present(&mut struktured_impl.generics);
for item in struktured_impl.items.iter_mut() {
match item {
syn::ImplItem::Method(method) => {
apply_ctx_bound_if_present(&mut method.sig.generics);
},
_others => {
// don't error, just nop
},
}
}
},
syn::Item::Fn(ref mut struktured_fn) => {
if make_subsystem == MakeSubsystem::ImplSubsystemTrait {
return Err(syn::Error::new(struktured_fn.span(), "Cannot make a free function a subsystem, did you mean to apply `contextbound` instead?"))
}
apply_ctx_bound_if_present(&mut struktured_fn.sig.generics);
},
other =>
return Err(syn::Error::new(
other.span(),
"Macro can only be annotated on functions or struct implementations",
)),
};
Ok(item.to_token_stream())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_path() {
let _p: Path = parse_quote! { self };
let _p: Path = parse_quote! { crate };
let _p: Path = parse_quote! { ::foo };
let _p: Path = parse_quote! { bar };
}
}
@@ -32,13 +32,13 @@ fn print() {
let item = quote! { let item = quote! {
pub struct Ooooh<X = Pffffffft> where X: Secrit { pub struct Ooooh<X = Pffffffft> where X: Secrit {
#[subsystem(no_dispatch, Foo)] #[subsystem(Foo)]
sub0: FooSubsystem, sub0: FooSubsystem,
#[subsystem(blocking, Bar)] #[subsystem(blocking, Bar)]
yyy: BaersBuyBilliardBalls, yyy: BaersBuyBilliardBalls,
#[subsystem(no_dispatch, blocking, Twain)] #[subsystem(blocking, Twain)]
fff: Beeeeep, fff: Beeeeep,
#[subsystem(Rope)] #[subsystem(Rope)]
@@ -57,13 +57,13 @@ fn print() {
fn struct_parse_full() { fn struct_parse_full() {
let item: OverseerGuts = parse_quote! { let item: OverseerGuts = parse_quote! {
pub struct Ooooh<X = Pffffffft> where X: Secrit { pub struct Ooooh<X = Pffffffft> where X: Secrit {
#[subsystem(no_dispatch, Foo)] #[subsystem(Foo)]
sub0: FooSubsystem, sub0: FooSubsystem,
#[subsystem(blocking, Bar)] #[subsystem(blocking, Bar)]
yyy: BaersBuyBilliardBalls, yyy: BaersBuyBilliardBalls,
#[subsystem(no_dispatch, blocking, Twain)] #[subsystem(blocking, Twain)]
fff: Beeeeep, fff: Beeeeep,
#[subsystem(Rope)] #[subsystem(Rope)]
@@ -88,11 +88,11 @@ fn struct_parse_basic() {
#[test] #[test]
fn attr_full() { fn attr_full() {
let attr: AttrArgs = parse_quote! { let attr: OverseerAttrArgs = parse_quote! {
gen=AllMessage, event=::some::why::ExternEvent, signal=SigSigSig, signal_capacity=111, message_capacity=222, gen=AllMessage, event=::some::why::ExternEvent, signal=SigSigSig, signal_capacity=111, message_capacity=222,
error=OverseerError, error=OverseerError,
}; };
assert_matches!(attr, AttrArgs { assert_matches!(attr, OverseerAttrArgs {
message_channel_capacity, message_channel_capacity,
signal_channel_capacity, signal_channel_capacity,
.. ..
@@ -104,11 +104,11 @@ fn attr_full() {
#[test] #[test]
fn attr_partial() { fn attr_partial() {
let attr: AttrArgs = parse_quote! { let attr: OverseerAttrArgs = parse_quote! {
gen=AllMessage, event=::some::why::ExternEvent, signal=::foo::SigSigSig, gen=AllMessage, event=::some::why::ExternEvent, signal=::foo::SigSigSig,
error=OverseerError, error=OverseerError,
}; };
assert_matches!(attr, AttrArgs { assert_matches!(attr, OverseerAttrArgs {
message_channel_capacity: _, message_channel_capacity: _,
signal_channel_capacity: _, signal_channel_capacity: _,
.. ..
+38 -28
View File
@@ -60,12 +60,13 @@
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(unused_crate_dependencies)] #![deny(unused_crate_dependencies)]
pub use polkadot_overseer_gen_proc_macro::overlord; pub use polkadot_overseer_gen_proc_macro::{contextbounds, overlord, subsystem};
#[doc(hidden)] #[doc(hidden)]
pub use gum; pub use gum;
#[doc(hidden)] #[doc(hidden)]
pub use metered; pub use metered;
#[doc(hidden)] #[doc(hidden)]
pub use polkadot_node_primitives::SpawnNamed; pub use polkadot_node_primitives::SpawnNamed;
@@ -101,7 +102,7 @@ use std::fmt;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
/// A type of messages that are sent from [`Subsystem`] to [`Overseer`]. /// A type of messages that are sent from a [`Subsystem`] to the declared overseer.
/// ///
/// Used to launch jobs. /// Used to launch jobs.
pub enum ToOverseer { pub enum ToOverseer {
@@ -312,7 +313,7 @@ pub struct SubsystemMeterReadouts {
/// ///
/// [`Subsystem`]: trait.Subsystem.html /// [`Subsystem`]: trait.Subsystem.html
/// ///
/// `M` here is the inner message type, and _not_ the generated `enum AllMessages`. /// `M` here is the inner message type, and _not_ the generated `enum AllMessages` or `#message_wrapper` type.
pub struct SubsystemInstance<Message, Signal> { pub struct SubsystemInstance<Message, Signal> {
/// Send sink for `Signal`s to be sent to a subsystem. /// Send sink for `Signal`s to be sent to a subsystem.
pub tx_signal: crate::metered::MeteredSender<Signal>, pub tx_signal: crate::metered::MeteredSender<Signal>,
@@ -362,20 +363,23 @@ pub trait SubsystemContext: Send + 'static {
/// The message type of this context. Subsystems launched with this context will expect /// The message type of this context. Subsystems launched with this context will expect
/// to receive messages of this type. Commonly uses the wrapping `enum` commonly called /// to receive messages of this type. Commonly uses the wrapping `enum` commonly called
/// `AllMessages`. /// `AllMessages`.
type Message: std::fmt::Debug + Send + 'static; type Message: ::std::fmt::Debug + Send + 'static;
/// And the same for signals. /// And the same for signals.
type Signal: std::fmt::Debug + Send + 'static; type Signal: ::std::fmt::Debug + Send + 'static;
/// The overarching all messages `enum`. /// The overarching messages `enum` for this particular subsystem.
/// In some cases can be identical to `Self::Message`. type OutgoingMessages: ::std::fmt::Debug + Send + 'static;
type AllMessages: From<Self::Message> + Send + 'static;
// The overarching messages `enum` for this particular subsystem.
// type AllMessages: From<Self::OutgoingMessages> + From<Self::Message> + std::fmt::Debug + Send + 'static;
/// The sender type as provided by `sender()` and underlying. /// The sender type as provided by `sender()` and underlying.
type Sender: SubsystemSender<Self::AllMessages> + Send + 'static; type Sender: Clone + Send + 'static + SubsystemSender<Self::OutgoingMessages>;
/// The error type. /// The error type.
type Error: ::std::error::Error + ::std::convert::From<OverseerError> + Sync + Send + 'static; type Error: ::std::error::Error + ::std::convert::From<OverseerError> + Sync + Send + 'static;
/// Try to asynchronously receive a message. /// Try to asynchronously receive a message.
/// ///
/// This has to be used with caution, if you loop over this without /// Has to be used with caution, if you loop over this without
/// using `pending!()` macro you will end up with a busy loop! /// using `pending!()` macro you will end up with a busy loop!
async fn try_recv(&mut self) -> Result<Option<FromOverseer<Self::Message, Self::Signal>>, ()>; async fn try_recv(&mut self) -> Result<Option<FromOverseer<Self::Message, Self::Signal>>, ()>;
@@ -397,34 +401,37 @@ pub trait SubsystemContext: Send + 'static {
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
/// Send a direct message to some other `Subsystem`, routed based on message type. /// Send a direct message to some other `Subsystem`, routed based on message type.
async fn send_message<X>(&mut self, msg: X) // #[deprecated(note = "Use `self.sender().send_message(msg) instead, avoid passing around the full context.")]
async fn send_message<T>(&mut self, msg: T)
where where
Self::AllMessages: From<X>, Self::OutgoingMessages: From<T> + Send,
X: Send, T: Send,
{ {
self.sender().send_message(<Self::AllMessages>::from(msg)).await self.sender().send_message(<Self::OutgoingMessages>::from(msg)).await
} }
/// Send multiple direct messages to other `Subsystem`s, routed based on message type. /// Send multiple direct messages to other `Subsystem`s, routed based on message type.
async fn send_messages<X, T>(&mut self, msgs: T) // #[deprecated(note = "Use `self.sender().send_message(msg) instead, avoid passing around the full context.")]
async fn send_messages<T, I>(&mut self, msgs: I)
where where
T: IntoIterator<Item = X> + Send, Self::OutgoingMessages: From<T> + Send,
T::IntoIter: Send, I: IntoIterator<Item = T> + Send,
Self::AllMessages: From<X>, I::IntoIter: Send,
X: Send, T: Send,
{ {
self.sender() self.sender()
.send_messages(msgs.into_iter().map(|x| <Self::AllMessages>::from(x))) .send_messages(msgs.into_iter().map(<Self::OutgoingMessages>::from))
.await .await
} }
/// Send a message using the unbounded connection. /// Send a message using the unbounded connection.
// #[deprecated(note = "Use `self.sender().send_unbounded_message(msg) instead, avoid passing around the full context.")]
fn send_unbounded_message<X>(&mut self, msg: X) fn send_unbounded_message<X>(&mut self, msg: X)
where where
Self::AllMessages: From<X>, Self::OutgoingMessages: From<X> + Send,
X: Send, X: Send,
{ {
self.sender().send_unbounded_message(Self::AllMessages::from(msg)) self.sender().send_unbounded_message(<Self::OutgoingMessages>::from(msg))
} }
/// Obtain the sender. /// Obtain the sender.
@@ -450,22 +457,25 @@ where
/// Sender end of a channel to interface with a subsystem. /// Sender end of a channel to interface with a subsystem.
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait SubsystemSender<Message>: Send + Clone + 'static { pub trait SubsystemSender<OutgoingMessage>: Clone + Send + 'static
where
OutgoingMessage: Send,
{
/// Send a direct message to some other `Subsystem`, routed based on message type. /// Send a direct message to some other `Subsystem`, routed based on message type.
async fn send_message(&mut self, msg: Message); async fn send_message(&mut self, msg: OutgoingMessage);
/// Send multiple direct messages to other `Subsystem`s, routed based on message type. /// Send multiple direct messages to other `Subsystem`s, routed based on message type.
async fn send_messages<T>(&mut self, msgs: T) async fn send_messages<I>(&mut self, msgs: I)
where where
T: IntoIterator<Item = Message> + Send, I: IntoIterator<Item = OutgoingMessage> + Send,
T::IntoIter: Send; I::IntoIter: Send;
/// Send a message onto the unbounded queue of some other `Subsystem`, routed based on message /// Send a message onto the unbounded queue of some other `Subsystem`, routed based on message
/// type. /// type.
/// ///
/// This function should be used only when there is some other bounding factor on the messages /// This function should be used only when there is some other bounding factor on the messages
/// sent with it. Otherwise, it risks a memory leak. /// sent with it. Otherwise, it risks a memory leak.
fn send_unbounded_message(&mut self, msg: Message); fn send_unbounded_message(&mut self, msg: OutgoingMessage);
} }
/// A future that wraps another future with a `Delay` allowing for time-limited futures. /// A future that wraps another future with a `Delay` allowing for time-limited futures.
@@ -15,7 +15,7 @@ struct MsgStrukt(u8);
#[overlord(signal=SigSigSig, event=Event, gen=AllMessages)] #[overlord(signal=SigSigSig, event=Event, gen=AllMessages)]
struct Overseer { struct Overseer {
#[subsystem(no_dispatch, MsgStrukt)] #[subsystem(MsgStrukt)]
sub0: AwesomeSubSys, sub0: AwesomeSubSys,
i_like_pie: f64, i_like_pie: f64,
@@ -21,7 +21,7 @@ pub struct MsgStrukt(u8);
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)] #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
struct Overseer { struct Overseer {
#[subsystem(no_dispatch, MsgStrukt)] #[subsystem(MsgStrukt)]
sub0: AwesomeSubSys, sub0: AwesomeSubSys,
i_like_pie: f64, i_like_pie: f64,
} }
@@ -58,4 +58,4 @@ fn main() {
.spawner(DummySpawner) .spawner(DummySpawner)
.build() .build()
.unwrap(); .unwrap();
} }
@@ -21,7 +21,7 @@ pub struct MsgStrukt(u8);
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)] #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
struct Overseer { struct Overseer {
#[subsystem(no_dispatch, MsgStrukt)] #[subsystem(MsgStrukt)]
sub0: AwesomeSubSys, sub0: AwesomeSubSys,
i_like_pie: f64, i_like_pie: f64,
} }
@@ -21,7 +21,7 @@ pub struct MsgStrukt(u8);
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)] #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
struct Overseer { struct Overseer {
#[subsystem(no_dispatch, MsgStrukt)] #[subsystem(MsgStrukt)]
sub0: AwesomeSubSys, sub0: AwesomeSubSys,
i_like_pie: f64, i_like_pie: f64,
} }
@@ -21,7 +21,7 @@ pub struct MsgStrukt(u8);
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)] #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
struct Overseer { struct Overseer {
#[subsystem(no_dispatch, MsgStrukt)] #[subsystem(MsgStrukt)]
sub0: AwesomeSubSys, sub0: AwesomeSubSys,
i_like_pie: f64, i_like_pie: f64,
} }
@@ -21,7 +21,7 @@ pub struct MsgStrukt(u8);
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)] #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
struct Overseer<T> { struct Overseer<T> {
#[subsystem(no_dispatch, MsgStrukt)] #[subsystem(MsgStrukt)]
sub0: AwesomeSubSys, sub0: AwesomeSubSys,
i_like_pie: T, i_like_pie: T,
} }
+3 -7
View File
@@ -15,8 +15,8 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use crate::{ use crate::{
prometheus::Registry, AllMessages, HeadSupportsParachains, InitializedOverseerBuilder, prometheus::Registry, HeadSupportsParachains, InitializedOverseerBuilder, MetricsTrait,
MetricsTrait, Overseer, OverseerMetrics, OverseerSignal, OverseerSubsystemContext, SpawnNamed, Overseer, OverseerMetrics, OverseerSignal, OverseerSubsystemContext, SpawnNamed,
KNOWN_LEAVES_CACHE_SIZE, KNOWN_LEAVES_CACHE_SIZE,
}; };
use lru::LruCache; use lru::LruCache;
@@ -30,11 +30,7 @@ pub struct DummySubsystem;
impl<Context> Subsystem<Context, SubsystemError> for DummySubsystem impl<Context> Subsystem<Context, SubsystemError> for DummySubsystem
where where
Context: SubsystemContext< Context: SubsystemContext<Signal = OverseerSignal, Error = SubsystemError>,
Signal = OverseerSignal,
Error = SubsystemError,
AllMessages = AllMessages,
>,
{ {
fn start(self, mut ctx: Context) -> SpawnedSubsystem<SubsystemError> { fn start(self, mut ctx: Context) -> SpawnedSubsystem<SubsystemError> {
let future = Box::pin(async move { let future = Box::pin(async move {
+111 -28
View File
@@ -77,15 +77,14 @@ use polkadot_primitives::{
}; };
use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_api::{ApiExt, ProvideRuntimeApi};
use polkadot_node_network_protocol::VersionedValidationProtocol;
use polkadot_node_subsystem_types::messages::{ use polkadot_node_subsystem_types::messages::{
ApprovalDistributionMessage, ApprovalVotingMessage, AvailabilityDistributionMessage, ApprovalDistributionMessage, ApprovalVotingMessage, AvailabilityDistributionMessage,
AvailabilityRecoveryMessage, AvailabilityStoreMessage, BitfieldDistributionMessage, AvailabilityRecoveryMessage, AvailabilityStoreMessage, BitfieldDistributionMessage,
BitfieldSigningMessage, CandidateBackingMessage, CandidateValidationMessage, ChainApiMessage, BitfieldSigningMessage, CandidateBackingMessage, CandidateValidationMessage, ChainApiMessage,
ChainSelectionMessage, CollationGenerationMessage, CollatorProtocolMessage, ChainSelectionMessage, CollationGenerationMessage, CollatorProtocolMessage,
DisputeCoordinatorMessage, DisputeDistributionMessage, GossipSupportMessage, DisputeCoordinatorMessage, DisputeDistributionMessage, GossipSupportMessage,
NetworkBridgeEvent, NetworkBridgeMessage, ProvisionerMessage, PvfCheckerMessage, NetworkBridgeMessage, ProvisionerMessage, PvfCheckerMessage, RuntimeApiMessage,
RuntimeApiMessage, StatementDistributionMessage, StatementDistributionMessage,
}; };
pub use polkadot_node_subsystem_types::{ pub use polkadot_node_subsystem_types::{
errors::{SubsystemError, SubsystemResult}, errors::{SubsystemError, SubsystemResult},
@@ -108,9 +107,9 @@ use parity_util_mem::MemoryAllocationTracker;
pub use polkadot_overseer_gen as gen; pub use polkadot_overseer_gen as gen;
pub use polkadot_overseer_gen::{ pub use polkadot_overseer_gen::{
overlord, FromOverseer, MapSubsystem, MessagePacket, SignalsReceived, SpawnNamed, Subsystem, contextbounds, overlord, subsystem, FromOverseer, MapSubsystem, MessagePacket, SignalsReceived,
SubsystemContext, SubsystemIncomingMessages, SubsystemInstance, SubsystemMeterReadouts, SpawnNamed, Subsystem, SubsystemContext, SubsystemIncomingMessages, SubsystemInstance,
SubsystemMeters, SubsystemSender, TimeoutExt, ToOverseer, SubsystemMeterReadouts, SubsystemMeters, SubsystemSender, TimeoutExt, ToOverseer,
}; };
/// Store 2 days worth of blocks, not accounting for forks, /// Store 2 days worth of blocks, not accounting for forks,
@@ -414,71 +413,155 @@ pub async fn forward_events<P: BlockchainEvents<Block>>(client: Arc<P>, mut hand
event=Event, event=Event,
signal=OverseerSignal, signal=OverseerSignal,
error=SubsystemError, error=SubsystemError,
network=NetworkBridgeEvent<VersionedValidationProtocol>,
message_capacity=2048, message_capacity=2048,
)] )]
pub struct Overseer<SupportsParachains> { pub struct Overseer<SupportsParachains> {
#[subsystem(no_dispatch, CandidateValidationMessage)] #[subsystem(CandidateValidationMessage, sends: [
RuntimeApiMessage,
])]
candidate_validation: CandidateValidation, candidate_validation: CandidateValidation,
#[subsystem(no_dispatch, PvfCheckerMessage)] #[subsystem(PvfCheckerMessage, sends: [
CandidateValidationMessage,
RuntimeApiMessage,
])]
pvf_checker: PvfChecker, pvf_checker: PvfChecker,
#[subsystem(no_dispatch, CandidateBackingMessage)] #[subsystem(CandidateBackingMessage, sends: [
CandidateValidationMessage,
CollatorProtocolMessage,
AvailabilityDistributionMessage,
AvailabilityStoreMessage,
StatementDistributionMessage,
ProvisionerMessage,
RuntimeApiMessage,
DisputeCoordinatorMessage,
])]
candidate_backing: CandidateBacking, candidate_backing: CandidateBacking,
#[subsystem(StatementDistributionMessage)] #[subsystem(StatementDistributionMessage, sends: [
NetworkBridgeMessage,
CandidateBackingMessage,
RuntimeApiMessage,
])]
statement_distribution: StatementDistribution, statement_distribution: StatementDistribution,
#[subsystem(no_dispatch, AvailabilityDistributionMessage)] #[subsystem(AvailabilityDistributionMessage, sends: [
AvailabilityStoreMessage,
AvailabilityRecoveryMessage,
ChainApiMessage,
RuntimeApiMessage,
NetworkBridgeMessage,
])]
availability_distribution: AvailabilityDistribution, availability_distribution: AvailabilityDistribution,
#[subsystem(no_dispatch, AvailabilityRecoveryMessage)] #[subsystem(AvailabilityRecoveryMessage, sends: [
NetworkBridgeMessage,
RuntimeApiMessage,
AvailabilityStoreMessage,
])]
availability_recovery: AvailabilityRecovery, availability_recovery: AvailabilityRecovery,
#[subsystem(blocking, no_dispatch, BitfieldSigningMessage)] #[subsystem(blocking, BitfieldSigningMessage, sends: [
AvailabilityStoreMessage,
RuntimeApiMessage,
BitfieldDistributionMessage,
])]
bitfield_signing: BitfieldSigning, bitfield_signing: BitfieldSigning,
#[subsystem(BitfieldDistributionMessage)] #[subsystem(BitfieldDistributionMessage, sends: [
RuntimeApiMessage,
NetworkBridgeMessage,
ProvisionerMessage,
])]
bitfield_distribution: BitfieldDistribution, bitfield_distribution: BitfieldDistribution,
#[subsystem(no_dispatch, ProvisionerMessage)] #[subsystem(ProvisionerMessage, sends: [
RuntimeApiMessage,
CandidateBackingMessage,
ChainApiMessage,
DisputeCoordinatorMessage,
])]
provisioner: Provisioner, provisioner: Provisioner,
#[subsystem(no_dispatch, blocking, RuntimeApiMessage)] #[subsystem(blocking, RuntimeApiMessage, sends: [])]
runtime_api: RuntimeApi, runtime_api: RuntimeApi,
#[subsystem(no_dispatch, blocking, AvailabilityStoreMessage)] #[subsystem(blocking, AvailabilityStoreMessage, sends: [
ChainApiMessage,
RuntimeApiMessage,
])]
availability_store: AvailabilityStore, availability_store: AvailabilityStore,
#[subsystem(no_dispatch, NetworkBridgeMessage)] #[subsystem(NetworkBridgeMessage, sends: [
BitfieldDistributionMessage,
StatementDistributionMessage,
ApprovalDistributionMessage,
GossipSupportMessage,
DisputeDistributionMessage,
CollationGenerationMessage,
CollatorProtocolMessage,
])]
network_bridge: NetworkBridge, network_bridge: NetworkBridge,
#[subsystem(no_dispatch, blocking, ChainApiMessage)] #[subsystem(blocking, ChainApiMessage, sends: [])]
chain_api: ChainApi, chain_api: ChainApi,
#[subsystem(no_dispatch, CollationGenerationMessage)] #[subsystem(CollationGenerationMessage, sends: [
RuntimeApiMessage,
CollatorProtocolMessage,
])]
collation_generation: CollationGeneration, collation_generation: CollationGeneration,
#[subsystem(no_dispatch, CollatorProtocolMessage)] #[subsystem(CollatorProtocolMessage, sends: [
NetworkBridgeMessage,
RuntimeApiMessage,
CandidateBackingMessage,
])]
collator_protocol: CollatorProtocol, collator_protocol: CollatorProtocol,
#[subsystem(ApprovalDistributionMessage)] #[subsystem(ApprovalDistributionMessage, sends: [
NetworkBridgeMessage,
ApprovalVotingMessage,
])]
approval_distribution: ApprovalDistribution, approval_distribution: ApprovalDistribution,
#[subsystem(no_dispatch, blocking, ApprovalVotingMessage)] #[subsystem(blocking, ApprovalVotingMessage, sends: [
RuntimeApiMessage,
ChainApiMessage,
ChainSelectionMessage,
DisputeCoordinatorMessage,
AvailabilityRecoveryMessage,
ApprovalDistributionMessage,
CandidateValidationMessage,
])]
approval_voting: ApprovalVoting, approval_voting: ApprovalVoting,
#[subsystem(GossipSupportMessage)] #[subsystem(GossipSupportMessage, sends: [
NetworkBridgeMessage,
RuntimeApiMessage,
ChainSelectionMessage,
])]
gossip_support: GossipSupport, gossip_support: GossipSupport,
#[subsystem(no_dispatch, blocking, DisputeCoordinatorMessage)] #[subsystem(blocking, DisputeCoordinatorMessage, sends: [
RuntimeApiMessage,
ChainApiMessage,
DisputeDistributionMessage,
CandidateValidationMessage,
AvailabilityStoreMessage,
AvailabilityRecoveryMessage,
])]
dispute_coordinator: DisputeCoordinator, dispute_coordinator: DisputeCoordinator,
#[subsystem(no_dispatch, DisputeDistributionMessage)] #[subsystem(DisputeDistributionMessage, sends: [
RuntimeApiMessage,
DisputeCoordinatorMessage,
NetworkBridgeMessage,
])]
dispute_distribution: DisputeDistribution, dispute_distribution: DisputeDistribution,
#[subsystem(no_dispatch, blocking, ChainSelectionMessage)] #[subsystem(blocking, ChainSelectionMessage, sends: [ChainApiMessage])]
chain_selection: ChainSelection, chain_selection: ChainSelection,
/// External listeners waiting for a hash to be in the active-leave set. /// External listeners waiting for a hash to be in the active-leave set.
+6 -22
View File
@@ -60,11 +60,7 @@ struct TestSubsystem1(metered::MeteredSender<usize>);
impl<C> overseer::Subsystem<C, SubsystemError> for TestSubsystem1 impl<C> overseer::Subsystem<C, SubsystemError> for TestSubsystem1
where where
C: overseer::SubsystemContext< C: overseer::SubsystemContext<Message = CandidateValidationMessage, Signal = OverseerSignal>,
Message = CandidateValidationMessage,
Signal = OverseerSignal,
AllMessages = AllMessages,
>,
{ {
fn start(self, mut ctx: C) -> SpawnedSubsystem { fn start(self, mut ctx: C) -> SpawnedSubsystem {
let mut sender = self.0; let mut sender = self.0;
@@ -95,8 +91,8 @@ impl<C> overseer::Subsystem<C, SubsystemError> for TestSubsystem2
where where
C: overseer::SubsystemContext< C: overseer::SubsystemContext<
Message = CandidateBackingMessage, Message = CandidateBackingMessage,
OutgoingMessages = <CandidateBackingMessage as AssociateOutgoing>::OutgoingMessages,
Signal = OverseerSignal, Signal = OverseerSignal,
AllMessages = AllMessages,
>, >,
{ {
fn start(self, mut ctx: C) -> SpawnedSubsystem { fn start(self, mut ctx: C) -> SpawnedSubsystem {
@@ -143,11 +139,7 @@ struct ReturnOnStart;
impl<C> overseer::Subsystem<C, SubsystemError> for ReturnOnStart impl<C> overseer::Subsystem<C, SubsystemError> for ReturnOnStart
where where
C: overseer::SubsystemContext< C: overseer::SubsystemContext<Message = CandidateBackingMessage, Signal = OverseerSignal>,
Message = CandidateBackingMessage,
Signal = OverseerSignal,
AllMessages = AllMessages,
>,
{ {
fn start(self, mut _ctx: C) -> SpawnedSubsystem { fn start(self, mut _ctx: C) -> SpawnedSubsystem {
SpawnedSubsystem { SpawnedSubsystem {
@@ -316,11 +308,7 @@ struct TestSubsystem5(metered::MeteredSender<OverseerSignal>);
impl<C> overseer::Subsystem<C, SubsystemError> for TestSubsystem5 impl<C> overseer::Subsystem<C, SubsystemError> for TestSubsystem5
where where
C: overseer::SubsystemContext< C: overseer::SubsystemContext<Message = CandidateValidationMessage, Signal = OverseerSignal>,
Message = CandidateValidationMessage,
Signal = OverseerSignal,
AllMessages = AllMessages,
>,
{ {
fn start(self, mut ctx: C) -> SpawnedSubsystem { fn start(self, mut ctx: C) -> SpawnedSubsystem {
let mut sender = self.0.clone(); let mut sender = self.0.clone();
@@ -352,11 +340,7 @@ struct TestSubsystem6(metered::MeteredSender<OverseerSignal>);
impl<C> Subsystem<C, SubsystemError> for TestSubsystem6 impl<C> Subsystem<C, SubsystemError> for TestSubsystem6
where where
C: overseer::SubsystemContext< C: overseer::SubsystemContext<Message = CandidateBackingMessage, Signal = OverseerSignal>,
Message = CandidateBackingMessage,
Signal = OverseerSignal,
AllMessages = AllMessages,
>,
{ {
fn start(self, mut ctx: C) -> SpawnedSubsystem { fn start(self, mut ctx: C) -> SpawnedSubsystem {
let mut sender = self.0.clone(); let mut sender = self.0.clone();
@@ -761,7 +745,7 @@ impl CounterSubsystem {
impl<C, M> Subsystem<C, SubsystemError> for CounterSubsystem impl<C, M> Subsystem<C, SubsystemError> for CounterSubsystem
where where
C: overseer::SubsystemContext<Message = M, Signal = OverseerSignal, AllMessages = AllMessages>, C: overseer::SubsystemContext<Message = M, Signal = OverseerSignal>,
M: Send, M: Send,
{ {
fn start(self, mut ctx: C) -> SpawnedSubsystem { fn start(self, mut ctx: C) -> SpawnedSubsystem {
+1 -1
View File
@@ -86,7 +86,7 @@ pub const MAX_FINALITY_LAG: u32 = 500;
/// We are not using `NonZeroU32` here because `expect` and `unwrap` are not yet const, so global /// We are not using `NonZeroU32` here because `expect` and `unwrap` are not yet const, so global
/// constants of `SessionWindowSize` would require `lazy_static` in that case. /// constants of `SessionWindowSize` would require `lazy_static` in that case.
/// ///
/// See: https://github.com/rust-lang/rust/issues/67441 /// See: <https://github.com/rust-lang/rust/issues/67441>
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct SessionWindowSize(SessionIndex); pub struct SessionWindowSize(SessionIndex);
+1
View File
@@ -83,6 +83,7 @@ polkadot-node-primitives = { path = "../primitives" }
polkadot-rpc = { path = "../../rpc" } polkadot-rpc = { path = "../../rpc" }
polkadot-node-subsystem = {path = "../subsystem" } polkadot-node-subsystem = {path = "../subsystem" }
polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-node-subsystem-util = { path = "../subsystem-util" }
polkadot-node-subsystem-types = { path = "../subsystem-types" }
polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-runtime-parachains = { path = "../../runtime/parachains" }
polkadot-node-network-protocol = { path = "../network/protocol" } polkadot-node-network-protocol = { path = "../network/protocol" }
+12 -4
View File
@@ -24,14 +24,16 @@ use polkadot_node_core_chain_selection::Config as ChainSelectionConfig;
use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig;
use polkadot_node_core_provisioner::ProvisionerConfig; use polkadot_node_core_provisioner::ProvisionerConfig;
use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver}; use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver};
use polkadot_node_subsystem_types::messages::{BitfieldSigningMessage, ProvisionerMessage};
#[cfg(any(feature = "malus", test))] #[cfg(any(feature = "malus", test))]
pub use polkadot_overseer::{ pub use polkadot_overseer::{
dummy::{dummy_overseer_builder, DummySubsystem}, dummy::{dummy_overseer_builder, DummySubsystem},
HeadSupportsParachains, HeadSupportsParachains,
}; };
use polkadot_overseer::{ use polkadot_overseer::{
metrics::Metrics as OverseerMetrics, BlockInfo, InitializedOverseerBuilder, MetricsTrait, gen::SubsystemContext, metrics::Metrics as OverseerMetrics, BlockInfo,
Overseer, OverseerConnector, OverseerHandle, InitializedOverseerBuilder, MetricsTrait, Overseer, OverseerConnector, OverseerHandle,
OverseerSubsystemContext,
}; };
use polkadot_primitives::runtime_api::ParachainHost; use polkadot_primitives::runtime_api::ParachainHost;
@@ -152,9 +154,15 @@ pub fn prepared_overseer_builder<'a, Spawner, RuntimeClient>(
StatementDistributionSubsystem<rand::rngs::StdRng>, StatementDistributionSubsystem<rand::rngs::StdRng>,
AvailabilityDistributionSubsystem, AvailabilityDistributionSubsystem,
AvailabilityRecoverySubsystem, AvailabilityRecoverySubsystem,
BitfieldSigningSubsystem<Spawner>, BitfieldSigningSubsystem<
Spawner,
<OverseerSubsystemContext<BitfieldSigningMessage> as SubsystemContext>::Sender,
>,
BitfieldDistributionSubsystem, BitfieldDistributionSubsystem,
ProvisionerSubsystem<Spawner>, ProvisionerSubsystem<
Spawner,
<OverseerSubsystemContext<ProvisionerMessage> as SubsystemContext>::Sender,
>,
RuntimeApiSubsystem<RuntimeClient>, RuntimeApiSubsystem<RuntimeClient>,
AvailabilityStoreSubsystem, AvailabilityStoreSubsystem,
NetworkBridgeSubsystem< NetworkBridgeSubsystem<
+21 -14
View File
@@ -20,7 +20,7 @@
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
messages::AllMessages, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, messages::AllMessages, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemError, SubsystemResult, SubsystemError, SubsystemResult,
}; };
use polkadot_node_subsystem_util::TimeoutExt; use polkadot_node_subsystem_util::TimeoutExt;
@@ -150,24 +150,25 @@ pub fn sender_receiver() -> (TestSubsystemSender, mpsc::UnboundedReceiver<AllMes
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<T> overseer::SubsystemSender<T> for TestSubsystemSender impl<OutgoingMessage> overseer::SubsystemSender<OutgoingMessage> for TestSubsystemSender
where where
T: Into<AllMessages> + Send + 'static, AllMessages: From<OutgoingMessage>,
OutgoingMessage: Send + 'static,
{ {
async fn send_message(&mut self, msg: T) { async fn send_message(&mut self, msg: OutgoingMessage) {
self.tx.send(msg.into()).await.expect("test overseer no longer live"); self.tx.send(msg.into()).await.expect("test overseer no longer live");
} }
async fn send_messages<X>(&mut self, msgs: X) async fn send_messages<I>(&mut self, msgs: I)
where where
X: IntoIterator<Item = T> + Send, I: IntoIterator<Item = OutgoingMessage> + Send,
X::IntoIter: Send, I::IntoIter: Send,
{ {
let mut iter = stream::iter(msgs.into_iter().map(|msg| Ok(msg.into()))); let mut iter = stream::iter(msgs.into_iter().map(|msg| Ok(msg.into())));
self.tx.send_all(&mut iter).await.expect("test overseer no longer live"); self.tx.send_all(&mut iter).await.expect("test overseer no longer live");
} }
fn send_unbounded_message(&mut self, msg: T) { fn send_unbounded_message(&mut self, msg: OutgoingMessage) {
self.tx.unbounded_send(msg.into()).expect("test overseer no longer live"); self.tx.unbounded_send(msg.into()).expect("test overseer no longer live");
} }
} }
@@ -180,16 +181,17 @@ pub struct TestSubsystemContext<M, S> {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<M, S> overseer::SubsystemContext for TestSubsystemContext<M, S> impl<M, Spawner> overseer::SubsystemContext for TestSubsystemContext<M, Spawner>
where where
M: std::fmt::Debug + Send + 'static, M: overseer::AssociateOutgoing + std::fmt::Debug + Send + 'static,
AllMessages: From<<M as overseer::AssociateOutgoing>::OutgoingMessages>,
AllMessages: From<M>, AllMessages: From<M>,
S: SpawnNamed + Send + 'static, Spawner: SpawnNamed + Send + 'static,
{ {
type Message = M; type Message = M;
type Sender = TestSubsystemSender; type Sender = TestSubsystemSender;
type Signal = OverseerSignal; type Signal = OverseerSignal;
type AllMessages = AllMessages; type OutgoingMessages = <M as overseer::AssociateOutgoing>::OutgoingMessages;
type Error = SubsystemError; type Error = SubsystemError;
async fn try_recv(&mut self) -> Result<Option<FromOverseer<M>>, ()> { async fn try_recv(&mut self) -> Result<Option<FromOverseer<M>>, ()> {
@@ -316,8 +318,13 @@ pub struct ForwardSubsystem<M>(pub mpsc::Sender<M>);
impl<M, Context> overseer::Subsystem<Context, SubsystemError> for ForwardSubsystem<M> impl<M, Context> overseer::Subsystem<Context, SubsystemError> for ForwardSubsystem<M>
where where
M: std::fmt::Debug + Send + 'static, M: overseer::AssociateOutgoing + std::fmt::Debug + Send + 'static,
Context: SubsystemContext<Message = M> + overseer::SubsystemContext<Message = M>, Context: overseer::SubsystemContext<
Message = M,
Signal = OverseerSignal,
Error = SubsystemError,
OutgoingMessages = <M as overseer::AssociateOutgoing>::OutgoingMessages,
>,
{ {
fn start(mut self, mut ctx: Context) -> SpawnedSubsystem { fn start(mut self, mut ctx: Context) -> SpawnedSubsystem {
let future = Box::pin(async move { let future = Box::pin(async move {
@@ -39,7 +39,7 @@ pub async fn determine_new_blocks<E, Sender>(
lower_bound_number: BlockNumber, lower_bound_number: BlockNumber,
) -> Result<Vec<(Hash, Header)>, E> ) -> Result<Vec<(Hash, Header)>, E>
where where
Sender: SubsystemSender, Sender: SubsystemSender<ChainApiMessage>,
{ {
const ANCESTRY_STEP: usize = 4; const ANCESTRY_STEP: usize = 4;
+50 -58
View File
@@ -26,9 +26,7 @@
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::{RuntimeApiError, SubsystemError}, errors::{RuntimeApiError, SubsystemError},
messages::{ messages::{BoundToRelayParent, RuntimeApiMessage, RuntimeApiRequest, RuntimeApiSender},
AllMessages, BoundToRelayParent, RuntimeApiMessage, RuntimeApiRequest, RuntimeApiSender,
},
overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemSender, SubsystemContext, SubsystemSender,
}; };
@@ -144,7 +142,7 @@ pub async fn request_from_runtime<RequestBuilder, Response, Sender>(
) -> RuntimeApiReceiver<Response> ) -> RuntimeApiReceiver<Response>
where where
RequestBuilder: FnOnce(RuntimeApiSender<Response>) -> RuntimeApiRequest, RequestBuilder: FnOnce(RuntimeApiSender<Response>) -> RuntimeApiRequest,
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -176,7 +174,7 @@ macro_rules! specialize_requests {
$( $(
$param_name: $param_ty, $param_name: $param_ty,
)* )*
sender: &mut impl SubsystemSender, sender: &mut impl overseer::SubsystemSender<RuntimeApiMessage>,
) -> RuntimeApiReceiver<$return_ty> ) -> RuntimeApiReceiver<$return_ty>
{ {
request_from_runtime(parent, sender, |tx| RuntimeApiRequest::$request_variant( request_from_runtime(parent, sender, |tx| RuntimeApiRequest::$request_variant(
@@ -329,11 +327,14 @@ pub struct Validator {
impl Validator { impl Validator {
/// Get a struct representing this node's validator if this node is in fact a validator in the context of the given block. /// Get a struct representing this node's validator if this node is in fact a validator in the context of the given block.
pub async fn new( pub async fn new<S>(
parent: Hash, parent: Hash,
keystore: SyncCryptoStorePtr, keystore: SyncCryptoStorePtr,
sender: &mut impl SubsystemSender, sender: &mut S,
) -> Result<Self, Error> { ) -> Result<Self, Error>
where
S: SubsystemSender<RuntimeApiMessage>,
{
// Note: request_validators and request_session_index_for_child do not and cannot // Note: request_validators and request_session_index_for_child do not and cannot
// run concurrently: they both have a mutable handle to the same sender. // run concurrently: they both have a mutable handle to the same sender.
// However, each of them returns a oneshot::Receiver, and those are resolved concurrently. // However, each of them returns a oneshot::Receiver, and those are resolved concurrently.
@@ -397,14 +398,14 @@ impl Drop for AbortOnDrop {
} }
/// A `JobHandle` manages a particular job for a subsystem. /// A `JobHandle` manages a particular job for a subsystem.
struct JobHandle<ToJob> { struct JobHandle<Consumes> {
_abort_handle: AbortOnDrop, _abort_handle: AbortOnDrop,
to_job: mpsc::Sender<ToJob>, to_job: mpsc::Sender<Consumes>,
} }
impl<ToJob> JobHandle<ToJob> { impl<Consumes> JobHandle<Consumes> {
/// Send a message to the job. /// Send a message to the job.
async fn send_msg(&mut self, msg: ToJob) -> Result<(), Error> { async fn send_msg(&mut self, msg: Consumes) -> Result<(), Error> {
self.to_job.send(msg).await.map_err(Into::into) self.to_job.send(msg).await.map_err(Into::into)
} }
} }
@@ -418,49 +419,25 @@ pub enum FromJobCommand {
} }
/// A sender for messages from jobs, as well as commands to the overseer. /// A sender for messages from jobs, as well as commands to the overseer.
pub struct JobSender<S: SubsystemSender> { pub struct JobSender<S> {
sender: S, sender: S,
from_job: mpsc::Sender<FromJobCommand>, from_job: mpsc::Sender<FromJobCommand>,
} }
// A custom clone impl, since M does not need to impl `Clone` // A custom clone impl, since M does not need to impl `Clone`
// which `#[derive(Clone)]` requires. // which `#[derive(Clone)]` requires.
impl<S: SubsystemSender> Clone for JobSender<S> { impl<S: Clone> Clone for JobSender<S> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { sender: self.sender.clone(), from_job: self.from_job.clone() } Self { sender: self.sender.clone(), from_job: self.from_job.clone() }
} }
} }
impl<S: SubsystemSender> JobSender<S> { impl<S> JobSender<S> {
/// Get access to the underlying subsystem sender. /// Get access to the underlying subsystem sender.
pub fn subsystem_sender(&mut self) -> &mut S { pub fn subsystem_sender(&mut self) -> &mut S {
&mut self.sender &mut self.sender
} }
/// Send a direct message to some other `Subsystem`, routed based on message type.
pub async fn send_message(&mut self, msg: impl Into<AllMessages>) {
self.sender.send_message(msg.into()).await
}
/// Send multiple direct messages to other `Subsystem`s, routed based on message type.
pub async fn send_messages<T, M>(&mut self, msgs: T)
where
T: IntoIterator<Item = M> + Send,
T::IntoIter: Send,
M: Into<AllMessages>,
{
self.sender.send_messages(msgs.into_iter().map(|m| m.into())).await
}
/// Send a message onto the unbounded queue of some other `Subsystem`, routed based on message
/// type.
///
/// This function should be used only when there is some other bounding factor on the messages
/// sent with it. Otherwise, it risks a memory leak.
pub fn send_unbounded_message(&mut self, msg: impl Into<AllMessages>) {
self.sender.send_unbounded_message(msg.into())
}
/// Send a command to the subsystem, to be relayed onwards to the overseer. /// Send a command to the subsystem, to be relayed onwards to the overseer.
pub async fn send_command(&mut self, msg: FromJobCommand) -> Result<(), mpsc::SendError> { pub async fn send_command(&mut self, msg: FromJobCommand) -> Result<(), mpsc::SendError> {
self.from_job.send(msg).await self.from_job.send(msg).await
@@ -470,23 +447,23 @@ impl<S: SubsystemSender> JobSender<S> {
#[async_trait::async_trait] #[async_trait::async_trait]
impl<S, M> overseer::SubsystemSender<M> for JobSender<S> impl<S, M> overseer::SubsystemSender<M> for JobSender<S>
where where
M: Send + 'static + Into<AllMessages>, M: Send + 'static,
S: SubsystemSender + Clone, S: SubsystemSender<M> + Clone,
{ {
async fn send_message(&mut self, msg: M) { async fn send_message(&mut self, msg: M) {
self.sender.send_message(msg.into()).await self.sender.send_message(msg).await
} }
async fn send_messages<T>(&mut self, msgs: T) async fn send_messages<I>(&mut self, msgs: I)
where where
T: IntoIterator<Item = M> + Send, I: IntoIterator<Item = M> + Send,
T::IntoIter: Send, I::IntoIter: Send,
{ {
self.sender.send_messages(msgs.into_iter().map(|m| m.into())).await self.sender.send_messages(msgs).await
} }
fn send_unbounded_message(&mut self, msg: M) { fn send_unbounded_message(&mut self, msg: M) {
self.sender.send_unbounded_message(msg.into()) self.sender.send_unbounded_message(msg)
} }
} }
@@ -506,6 +483,14 @@ impl fmt::Debug for FromJobCommand {
pub trait JobTrait: Unpin + Sized { pub trait JobTrait: Unpin + Sized {
/// Message type used to send messages to the job. /// Message type used to send messages to the job.
type ToJob: 'static + BoundToRelayParent + Send; type ToJob: 'static + BoundToRelayParent + Send;
/// The set of outgoing messages to be accumulated into.
type OutgoingMessages: 'static + Send;
/// The sender to send outgoing messages.
// The trait bounds are rather minimal.
type Sender: 'static + Send + Clone;
/// Job runtime error. /// Job runtime error.
type Error: 'static + std::error::Error + Send; type Error: 'static + std::error::Error + Send;
/// Extra arguments this job needs to run properly. /// Extra arguments this job needs to run properly.
@@ -525,12 +510,12 @@ pub trait JobTrait: Unpin + Sized {
/// Run a job for the given relay `parent`. /// Run a job for the given relay `parent`.
/// ///
/// The job should be ended when `receiver` returns `None`. /// The job should be ended when `receiver` returns `None`.
fn run<S: SubsystemSender>( fn run(
leaf: ActivatedLeaf, leaf: ActivatedLeaf,
run_args: Self::RunArgs, run_args: Self::RunArgs,
metrics: Self::Metrics, metrics: Self::Metrics,
receiver: mpsc::Receiver<Self::ToJob>, receiver: mpsc::Receiver<Self::ToJob>,
sender: JobSender<S>, sender: JobSender<Self::Sender>,
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>>; ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>>;
} }
@@ -572,15 +557,14 @@ where
} }
/// Spawn a new job for this `parent_hash`, with whatever args are appropriate. /// Spawn a new job for this `parent_hash`, with whatever args are appropriate.
fn spawn_job<Job, Sender>( fn spawn_job<Job>(
&mut self, &mut self,
leaf: ActivatedLeaf, leaf: ActivatedLeaf,
run_args: Job::RunArgs, run_args: Job::RunArgs,
metrics: Job::Metrics, metrics: Job::Metrics,
sender: Sender, sender: Job::Sender,
) where ) where
Job: JobTrait<ToJob = ToJob>, Job: JobTrait<ToJob = ToJob>,
Sender: SubsystemSender,
{ {
let hash = leaf.hash; let hash = leaf.hash;
let (to_job_tx, to_job_rx) = mpsc::channel(JOB_CHANNEL_CAPACITY); let (to_job_tx, to_job_rx) = mpsc::channel(JOB_CHANNEL_CAPACITY);
@@ -697,8 +681,12 @@ impl<Job: JobTrait, Spawner> JobSubsystem<Job, Spawner> {
pub async fn run<Context>(self, mut ctx: Context) pub async fn run<Context>(self, mut ctx: Context)
where where
Spawner: SpawnNamed + Send + Clone + Unpin + 'static, Spawner: SpawnNamed + Send + Clone + Unpin + 'static,
Context: SubsystemContext<Message = <Job as JobTrait>::ToJob, Signal = OverseerSignal>, Context: SubsystemContext<
<Context as SubsystemContext>::Sender: SubsystemSender, Message = <Job as JobTrait>::ToJob,
OutgoingMessages = <Job as JobTrait>::OutgoingMessages,
Sender = <Job as JobTrait>::Sender,
Signal = OverseerSignal,
>,
Job: 'static + JobTrait + Send, Job: 'static + JobTrait + Send,
<Job as JobTrait>::RunArgs: Clone + Sync, <Job as JobTrait>::RunArgs: Clone + Sync,
<Job as JobTrait>::ToJob: <Job as JobTrait>::ToJob:
@@ -719,7 +707,7 @@ impl<Job: JobTrait, Spawner> JobSubsystem<Job, Spawner> {
}))) => { }))) => {
for activated in activated { for activated in activated {
let sender = ctx.sender().clone(); let sender = ctx.sender().clone();
jobs.spawn_job::<Job, _>( jobs.spawn_job::<Job>(
activated, activated,
run_args.clone(), run_args.clone(),
metrics.clone(), metrics.clone(),
@@ -773,11 +761,15 @@ impl<Job: JobTrait, Spawner> JobSubsystem<Job, Spawner> {
impl<Context, Job, Spawner> Subsystem<Context, SubsystemError> for JobSubsystem<Job, Spawner> impl<Context, Job, Spawner> Subsystem<Context, SubsystemError> for JobSubsystem<Job, Spawner>
where where
Spawner: SpawnNamed + Send + Clone + Unpin + 'static, Spawner: SpawnNamed + Send + Clone + Unpin + 'static,
Context: SubsystemContext<Message = Job::ToJob, Signal = OverseerSignal>, Context: SubsystemContext<
Message = Job::ToJob,
Signal = OverseerSignal,
OutgoingMessages = <Job as JobTrait>::OutgoingMessages,
Sender = <Job as JobTrait>::Sender,
>,
Job: 'static + JobTrait + Send, Job: 'static + JobTrait + Send,
Job::RunArgs: Clone + Sync, Job::RunArgs: Clone + Sync,
<Job as JobTrait>::ToJob: <Job as JobTrait>::ToJob: Sync + From<<Context as SubsystemContext>::Message>,
Sync + From<<Context as polkadot_overseer::SubsystemContext>::Message>,
Job::Metrics: Sync, Job::Metrics: Sync,
{ {
fn start(self, ctx: Context) -> SpawnedSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem {
@@ -26,7 +26,7 @@ use futures::channel::oneshot;
use polkadot_node_subsystem::{ use polkadot_node_subsystem::{
errors::RuntimeApiError, errors::RuntimeApiError,
messages::{RuntimeApiMessage, RuntimeApiRequest}, messages::{RuntimeApiMessage, RuntimeApiRequest},
overseer, SubsystemContext, overseer,
}; };
use thiserror::Error; use thiserror::Error;
@@ -94,16 +94,19 @@ pub struct RollingSessionWindow {
impl RollingSessionWindow { impl RollingSessionWindow {
/// Initialize a new session info cache with the given window size. /// Initialize a new session info cache with the given window size.
pub async fn new( pub async fn new<Sender>(
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), mut sender: Sender,
window_size: SessionWindowSize, window_size: SessionWindowSize,
block_hash: Hash, block_hash: Hash,
) -> Result<Self, SessionsUnavailable> { ) -> Result<Self, SessionsUnavailable>
let session_index = get_session_index_for_child(ctx, block_hash).await?; where
Sender: overseer::SubsystemSender<RuntimeApiMessage>,
{
let session_index = get_session_index_for_child(&mut sender, block_hash).await?;
let window_start = session_index.saturating_sub(window_size.get() - 1); let window_start = session_index.saturating_sub(window_size.get() - 1);
match load_all_sessions(ctx, block_hash, window_start, session_index).await { match load_all_sessions(&mut sender, block_hash, window_start, session_index).await {
Err(kind) => Err(SessionsUnavailable { Err(kind) => Err(SessionsUnavailable {
kind, kind,
info: Some(SessionsUnavailableInfo { info: Some(SessionsUnavailableInfo {
@@ -154,10 +157,10 @@ impl RollingSessionWindow {
/// some backwards drift in session index is acceptable. /// some backwards drift in session index is acceptable.
pub async fn cache_session_info_for_head( pub async fn cache_session_info_for_head(
&mut self, &mut self,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), sender: &mut impl overseer::SubsystemSender<RuntimeApiMessage>,
block_hash: Hash, block_hash: Hash,
) -> Result<SessionWindowUpdate, SessionsUnavailable> { ) -> Result<SessionWindowUpdate, SessionsUnavailable> {
let session_index = get_session_index_for_child(ctx, block_hash).await?; let session_index = get_session_index_for_child(sender, block_hash).await?;
let old_window_start = self.earliest_session; let old_window_start = self.earliest_session;
@@ -177,7 +180,7 @@ impl RollingSessionWindow {
let fresh_start = if latest < window_start { window_start } else { latest + 1 }; let fresh_start = if latest < window_start { window_start } else { latest + 1 };
match load_all_sessions(ctx, block_hash, fresh_start, session_index).await { match load_all_sessions(sender, block_hash, fresh_start, session_index).await {
Err(kind) => Err(SessionsUnavailable { Err(kind) => Err(SessionsUnavailable {
kind, kind,
info: Some(SessionsUnavailableInfo { info: Some(SessionsUnavailableInfo {
@@ -215,17 +218,18 @@ impl RollingSessionWindow {
// cleaner to just call the runtime API directly without needing to create an instance // cleaner to just call the runtime API directly without needing to create an instance
// of `RuntimeInfo`. // of `RuntimeInfo`.
async fn get_session_index_for_child( async fn get_session_index_for_child(
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), sender: &mut impl overseer::SubsystemSender<RuntimeApiMessage>,
block_hash: Hash, block_hash: Hash,
) -> Result<SessionIndex, SessionsUnavailable> { ) -> Result<SessionIndex, SessionsUnavailable> {
let (s_tx, s_rx) = oneshot::channel(); let (s_tx, s_rx) = oneshot::channel();
// We're requesting session index of a child to populate the cache in advance. // We're requesting session index of a child to populate the cache in advance.
ctx.send_message(RuntimeApiMessage::Request( sender
block_hash, .send_message(RuntimeApiMessage::Request(
RuntimeApiRequest::SessionIndexForChild(s_tx), block_hash,
)) RuntimeApiRequest::SessionIndexForChild(s_tx),
.await; ))
.await;
match s_rx.await { match s_rx.await {
Ok(Ok(s)) => Ok(s), Ok(Ok(s)) => Ok(s),
@@ -243,7 +247,7 @@ async fn get_session_index_for_child(
} }
async fn load_all_sessions( async fn load_all_sessions(
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext), sender: &mut impl overseer::SubsystemSender<RuntimeApiMessage>,
block_hash: Hash, block_hash: Hash,
start: SessionIndex, start: SessionIndex,
end_inclusive: SessionIndex, end_inclusive: SessionIndex,
@@ -251,11 +255,12 @@ async fn load_all_sessions(
let mut v = Vec::new(); let mut v = Vec::new();
for i in start..=end_inclusive { for i in start..=end_inclusive {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
ctx.send_message(RuntimeApiMessage::Request( sender
block_hash, .send_message(RuntimeApiMessage::Request(
RuntimeApiRequest::SessionInfo(i, tx), block_hash,
)) RuntimeApiRequest::SessionInfo(i, tx),
.await; ))
.await;
let session_info = match rx.await { let session_info = match rx.await {
Ok(Ok(Some(s))) => s, Ok(Ok(Some(s))) => s,
@@ -274,7 +279,10 @@ async fn load_all_sessions(
mod tests { mod tests {
use super::*; use super::*;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use polkadot_node_subsystem::messages::{AllMessages, AvailabilityRecoveryMessage}; use polkadot_node_subsystem::{
messages::{AllMessages, AvailabilityRecoveryMessage},
SubsystemContext,
};
use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_test_helpers::make_subsystem_context;
use polkadot_primitives::v2::Header; use polkadot_primitives::v2::Header;
use sp_core::testing::TaskExecutor; use sp_core::testing::TaskExecutor;
@@ -319,13 +327,16 @@ mod tests {
let hash = header.hash(); let hash = header.hash();
let sender = ctx.sender();
let test_fut = { let test_fut = {
Box::pin(async move { Box::pin(async move {
let window = match window { let window = match window {
None => None => RollingSessionWindow::new(sender.clone(), TEST_WINDOW_SIZE, hash)
RollingSessionWindow::new(&mut ctx, TEST_WINDOW_SIZE, hash).await.unwrap(), .await
.unwrap(),
Some(mut window) => { Some(mut window) => {
window.cache_session_info_for_head(&mut ctx, hash).await.unwrap(); window.cache_session_info_for_head(sender, hash).await.unwrap();
window window
}, },
}; };
@@ -495,8 +506,9 @@ mod tests {
let hash = header.hash(); let hash = header.hash();
let test_fut = { let test_fut = {
let sender = ctx.sender().clone();
Box::pin(async move { Box::pin(async move {
let res = RollingSessionWindow::new(&mut ctx, TEST_WINDOW_SIZE, hash).await; let res = RollingSessionWindow::new(sender, TEST_WINDOW_SIZE, hash).await;
assert!(res.is_err()); assert!(res.is_err());
}) })
}; };
@@ -555,8 +567,9 @@ mod tests {
let test_fut = { let test_fut = {
Box::pin(async move { Box::pin(async move {
let sender = ctx.sender().clone();
let window = let window =
RollingSessionWindow::new(&mut ctx, TEST_WINDOW_SIZE, hash).await.unwrap(); RollingSessionWindow::new(sender, TEST_WINDOW_SIZE, hash).await.unwrap();
assert_eq!(window.earliest_session, session); assert_eq!(window.earliest_session, session);
assert_eq!(window.session_info, vec![dummy_session_info(session)]); assert_eq!(window.session_info, vec![dummy_session_info(session)]);
+20 -21
View File
@@ -25,7 +25,7 @@ use sp_application_crypto::AppKey;
use sp_core::crypto::ByteArray; use sp_core::crypto::ByteArray;
use sp_keystore::{CryptoStore, SyncCryptoStorePtr}; use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
use polkadot_node_subsystem::{SubsystemContext, SubsystemSender}; use polkadot_node_subsystem::{messages::RuntimeApiMessage, overseer, SubsystemSender};
use polkadot_primitives::v2::{ use polkadot_primitives::v2::{
CandidateEvent, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, OccupiedCore, CandidateEvent, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, OccupiedCore,
ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned,
@@ -123,7 +123,7 @@ impl RuntimeInfo {
parent: Hash, parent: Hash,
) -> Result<SessionIndex> ) -> Result<SessionIndex>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
match self.session_index_cache.get(&parent) { match self.session_index_cache.get(&parent) {
Some(index) => Ok(*index), Some(index) => Ok(*index),
@@ -143,7 +143,7 @@ impl RuntimeInfo {
relay_parent: Hash, relay_parent: Hash,
) -> Result<&'a ExtendedSessionInfo> ) -> Result<&'a ExtendedSessionInfo>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
let session_index = self.get_session_index_for_child(sender, relay_parent).await?; let session_index = self.get_session_index_for_child(sender, relay_parent).await?;
@@ -161,7 +161,7 @@ impl RuntimeInfo {
session_index: SessionIndex, session_index: SessionIndex,
) -> Result<&'a ExtendedSessionInfo> ) -> Result<&'a ExtendedSessionInfo>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
if !self.session_info_cache.contains(&session_index) { if !self.session_info_cache.contains(&session_index) {
let session_info = let session_info =
@@ -190,7 +190,7 @@ impl RuntimeInfo {
std::result::Result<Signed<Payload, RealPayload>, UncheckedSigned<Payload, RealPayload>>, std::result::Result<Signed<Payload, RealPayload>, UncheckedSigned<Payload, RealPayload>>,
> >
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
Payload: EncodeAs<RealPayload> + Clone, Payload: EncodeAs<RealPayload> + Clone,
RealPayload: Encode + Clone, RealPayload: Encode + Clone,
{ {
@@ -257,25 +257,25 @@ where
} }
/// Request availability cores from the runtime. /// Request availability cores from the runtime.
pub async fn get_availability_cores<Context>( pub async fn get_availability_cores<Sender>(
ctx: &mut Context, sender: &mut Sender,
relay_parent: Hash, relay_parent: Hash,
) -> Result<Vec<CoreState>> ) -> Result<Vec<CoreState>>
where where
Context: SubsystemContext, Sender: overseer::SubsystemSender<RuntimeApiMessage>,
{ {
recv_runtime(request_availability_cores(relay_parent, ctx.sender()).await).await recv_runtime(request_availability_cores(relay_parent, sender).await).await
} }
/// Variant of `request_availability_cores` that only returns occupied ones. /// Variant of `request_availability_cores` that only returns occupied ones.
pub async fn get_occupied_cores<Context>( pub async fn get_occupied_cores<Sender>(
ctx: &mut Context, sender: &mut Sender,
relay_parent: Hash, relay_parent: Hash,
) -> Result<Vec<OccupiedCore>> ) -> Result<Vec<OccupiedCore>>
where where
Context: SubsystemContext, Sender: overseer::SubsystemSender<RuntimeApiMessage>,
{ {
let cores = get_availability_cores(ctx, relay_parent).await?; let cores = get_availability_cores(sender, relay_parent).await?;
Ok(cores Ok(cores
.into_iter() .into_iter()
@@ -290,17 +290,16 @@ where
} }
/// Get group rotation info based on the given `relay_parent`. /// Get group rotation info based on the given `relay_parent`.
pub async fn get_group_rotation_info<Context>( pub async fn get_group_rotation_info<Sender>(
ctx: &mut Context, sender: &mut Sender,
relay_parent: Hash, relay_parent: Hash,
) -> Result<GroupRotationInfo> ) -> Result<GroupRotationInfo>
where where
Context: SubsystemContext, Sender: overseer::SubsystemSender<RuntimeApiMessage>,
{ {
// We drop `groups` here as we don't need them, because of `RuntimeInfo`. Ideally we would not // We drop `groups` here as we don't need them, because of `RuntimeInfo`. Ideally we would not
// fetch them in the first place. // fetch them in the first place.
let (_, info) = let (_, info) = recv_runtime(request_validator_groups(relay_parent, sender).await).await?;
recv_runtime(request_validator_groups(relay_parent, ctx.sender()).await).await?;
Ok(info) Ok(info)
} }
@@ -310,7 +309,7 @@ pub async fn get_candidate_events<Sender>(
relay_parent: Hash, relay_parent: Hash,
) -> Result<Vec<CandidateEvent>> ) -> Result<Vec<CandidateEvent>>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
recv_runtime(request_candidate_events(relay_parent, sender).await).await recv_runtime(request_candidate_events(relay_parent, sender).await).await
} }
@@ -321,7 +320,7 @@ pub async fn get_on_chain_votes<Sender>(
relay_parent: Hash, relay_parent: Hash,
) -> Result<Option<ScrapedOnChainVotes>> ) -> Result<Option<ScrapedOnChainVotes>>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
recv_runtime(request_on_chain_votes(relay_parent, sender).await).await recv_runtime(request_on_chain_votes(relay_parent, sender).await).await
} }
@@ -333,7 +332,7 @@ pub async fn get_validation_code_by_hash<Sender>(
validation_code_hash: ValidationCodeHash, validation_code_hash: ValidationCodeHash,
) -> Result<Option<ValidationCode>> ) -> Result<Option<ValidationCode>>
where where
Sender: SubsystemSender, Sender: SubsystemSender<RuntimeApiMessage>,
{ {
recv_runtime(request_validation_code_by_hash(relay_parent, validation_code_hash, sender).await) recv_runtime(request_validation_code_by_hash(relay_parent, validation_code_hash, sender).await)
.await .await
+26 -8
View File
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
#![cfg(test)]
use super::*; use super::*;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use executor::block_on; use executor::block_on;
@@ -44,8 +46,9 @@ use thiserror::Error;
// job structs are constructed within JobTrait::run // job structs are constructed within JobTrait::run
// most will want to retain the sender and receiver, as well as whatever other data they like // most will want to retain the sender and receiver, as well as whatever other data they like
struct FakeCollatorProtocolJob { struct FakeCollatorProtocolJob<Sender> {
receiver: mpsc::Receiver<CollatorProtocolMessage>, receiver: mpsc::Receiver<CollatorProtocolMessage>,
_phantom: std::marker::PhantomData<Sender>,
} }
// Error will mostly be a wrapper to make the try operator more convenient; // Error will mostly be a wrapper to make the try operator more convenient;
@@ -57,8 +60,18 @@ enum Error {
Sending(#[from] mpsc::SendError), Sending(#[from] mpsc::SendError),
} }
impl JobTrait for FakeCollatorProtocolJob { impl<Sender> JobTrait for FakeCollatorProtocolJob<Sender>
where
Sender: overseer::CollatorProtocolSenderTrait
+ std::marker::Unpin
+ overseer::SubsystemSender<CollatorProtocolMessage>,
JobSender<Sender>: overseer::CollatorProtocolSenderTrait
+ std::marker::Unpin
+ overseer::SubsystemSender<CollatorProtocolMessage>,
{
type ToJob = CollatorProtocolMessage; type ToJob = CollatorProtocolMessage;
type OutgoingMessages = overseer::CollatorProtocolOutgoingMessages;
type Sender = Sender;
type Error = Error; type Error = Error;
type RunArgs = bool; type RunArgs = bool;
type Metrics = (); type Metrics = ();
@@ -68,20 +81,21 @@ impl JobTrait for FakeCollatorProtocolJob {
/// Run a job for the parent block indicated /// Run a job for the parent block indicated
// //
// this function is in charge of creating and executing the job's main loop // this function is in charge of creating and executing the job's main loop
fn run<S: SubsystemSender>( fn run(
_: ActivatedLeaf, _: ActivatedLeaf,
run_args: Self::RunArgs, run_args: Self::RunArgs,
_metrics: Self::Metrics, _metrics: Self::Metrics,
receiver: mpsc::Receiver<CollatorProtocolMessage>, receiver: mpsc::Receiver<CollatorProtocolMessage>,
mut sender: JobSender<S>, mut sender: JobSender<Sender>,
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> { ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> {
async move { async move {
let job = FakeCollatorProtocolJob { receiver }; let job =
FakeCollatorProtocolJob { receiver, _phantom: std::marker::PhantomData::<Sender> };
if run_args { if run_args {
sender sender
.send_message(CollatorProtocolMessage::Invalid( .send_message(CollatorProtocolMessage::Invalid(
Default::default(), dummy_hash(),
dummy_candidate_receipt(dummy_hash()), dummy_candidate_receipt(dummy_hash()),
)) ))
.await; .await;
@@ -95,7 +109,10 @@ impl JobTrait for FakeCollatorProtocolJob {
} }
} }
impl FakeCollatorProtocolJob { impl<Sender> FakeCollatorProtocolJob<Sender>
where
Sender: overseer::CollatorProtocolSenderTrait,
{
async fn run_loop(mut self) -> Result<(), Error> { async fn run_loop(mut self) -> Result<(), Error> {
loop { loop {
match self.receiver.next().await { match self.receiver.next().await {
@@ -111,7 +128,8 @@ impl FakeCollatorProtocolJob {
} }
// with the job defined, it's straightforward to get a subsystem implementation. // with the job defined, it's straightforward to get a subsystem implementation.
type FakeCollatorProtocolSubsystem<Spawner> = JobSubsystem<FakeCollatorProtocolJob, Spawner>; type FakeCollatorProtocolSubsystem<Spawner> =
JobSubsystem<FakeCollatorProtocolJob<test_helpers::TestSubsystemSender>, Spawner>;
// this type lets us pretend to be the overseer // this type lets us pretend to be the overseer
type OverseerHandle = test_helpers::TestSubsystemContextHandle<CollatorProtocolMessage>; type OverseerHandle = test_helpers::TestSubsystemContextHandle<CollatorProtocolMessage>;
+1 -35
View File
@@ -24,9 +24,7 @@
pub use jaeger::*; pub use jaeger::*;
pub use polkadot_node_jaeger as jaeger; pub use polkadot_node_jaeger as jaeger;
pub use polkadot_overseer::{ pub use polkadot_overseer::{self as overseer, *};
self as overseer, ActiveLeavesUpdate, OverseerConnector, OverseerSignal,
};
pub use polkadot_node_subsystem_types::{ pub use polkadot_node_subsystem_types::{
errors::{self, *}, errors::{self, *},
@@ -54,37 +52,5 @@ pub type FromOverseer<M> = polkadot_overseer::gen::FromOverseer<M, OverseerSigna
pub type SubsystemInstance<Message> = pub type SubsystemInstance<Message> =
polkadot_overseer::gen::SubsystemInstance<Message, OverseerSignal>; polkadot_overseer::gen::SubsystemInstance<Message, OverseerSignal>;
/// Sender trait for the `AllMessages` wrapper.
pub trait SubsystemSender: polkadot_overseer::gen::SubsystemSender<messages::AllMessages> {}
impl<T> SubsystemSender for T where T: polkadot_overseer::gen::SubsystemSender<messages::AllMessages>
{}
/// Spawned subsystem. /// Spawned subsystem.
pub type SpawnedSubsystem = polkadot_overseer::gen::SpawnedSubsystem<SubsystemError>; pub type SpawnedSubsystem = polkadot_overseer::gen::SpawnedSubsystem<SubsystemError>;
/// Convenience trait specialization.
pub trait SubsystemContext:
polkadot_overseer::gen::SubsystemContext<
Signal = OverseerSignal,
AllMessages = messages::AllMessages,
Error = SubsystemError,
>
{
/// The message type the subsystem consumes.
type Message: std::fmt::Debug + Send + 'static;
/// Sender type to communicate with other subsystems.
type Sender: SubsystemSender + Send + Clone + 'static;
}
impl<T> SubsystemContext for T
where
T: polkadot_overseer::gen::SubsystemContext<
Signal = OverseerSignal,
AllMessages = messages::AllMessages,
Error = SubsystemError,
>,
{
type Message = <Self as polkadot_overseer::gen::SubsystemContext>::Message;
type Sender = <Self as polkadot_overseer::gen::SubsystemContext>::Sender;
}

Some files were not shown because too many files have changed in this diff Show More