diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index 4e8060f576..1e9308eae5 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -188,9 +188,9 @@ dependencies = [
[[package]]
name = "assert_matches"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "695579f0f2520f3774bb40461e5adb066459d4e0af4d59d20175484fb8e9edf1"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
[[package]]
name = "async-channel"
@@ -5526,6 +5526,7 @@ dependencies = [
"polkadot-node-primitives",
"polkadot-node-subsystem-test-helpers",
"polkadot-primitives",
+ "polkadot-procmacro-subsystem-dispatch-gen",
"polkadot-statement-table",
"sc-network",
"smallvec 1.6.1",
@@ -5686,6 +5687,17 @@ dependencies = [
"sp-version",
]
+[[package]]
+name = "polkadot-procmacro-subsystem-dispatch-gen"
+version = "0.1.0"
+dependencies = [
+ "assert_matches",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "trybuild",
+]
+
[[package]]
name = "polkadot-rpc"
version = "0.8.29"
@@ -6402,9 +6414,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.7"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
@@ -9893,6 +9905,20 @@ dependencies = [
"structopt",
]
+[[package]]
+name = "trybuild"
+version = "1.0.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99471a206425fba51842a9186315f32d91c56eadc21ea4c21f847b59cf778f8b"
+dependencies = [
+ "glob",
+ "lazy_static",
+ "serde",
+ "serde_json",
+ "termcolor",
+ "toml",
+]
+
[[package]]
name = "twox-hash"
version = "1.5.0"
diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml
index 5e2e6350cc..44f464812a 100644
--- a/polkadot/Cargo.toml
+++ b/polkadot/Cargo.toml
@@ -65,6 +65,7 @@ members = [
"node/primitives",
"node/service",
"node/subsystem",
+ "node/subsystem/dispatch-gen",
"node/subsystem-test-helpers",
"node/subsystem-util",
"node/jaeger",
diff --git a/polkadot/cli/src/browser.rs b/polkadot/cli/src/browser.rs
index f4645b64b7..9efea40f8b 100644
--- a/polkadot/cli/src/browser.rs
+++ b/polkadot/cli/src/browser.rs
@@ -14,27 +14,22 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
+use browser_utils::{browser_configuration, init_logging_and_telemetry, set_console_error_panic_hook, Client};
use log::info;
use wasm_bindgen::prelude::*;
-use browser_utils::{
- Client,
- browser_configuration, init_logging_and_telemetry, set_console_error_panic_hook,
-};
/// Starts the client.
#[wasm_bindgen]
pub async fn start_client(chain_spec: String, log_level: String) -> Result {
- start_inner(chain_spec, log_level)
- .await
- .map_err(|err| JsValue::from_str(&err.to_string()))
+ start_inner(chain_spec, log_level).await.map_err(|err| JsValue::from_str(&err.to_string()))
}
async fn start_inner(chain_spec: String, log_directives: String) -> Result> {
set_console_error_panic_hook();
let telemetry_worker = init_logging_and_telemetry(&log_directives)?;
- let chain_spec = service::PolkadotChainSpec::from_json_bytes(chain_spec.as_bytes().to_vec())
- .map_err(|e| format!("{:?}", e))?;
+ let chain_spec =
+ service::PolkadotChainSpec::from_json_bytes(chain_spec.as_bytes().to_vec()).map_err(|e| format!("{:?}", e))?;
let telemetry_handle = telemetry_worker.handle();
let config = browser_configuration(chain_spec, Some(telemetry_handle)).await?;
diff --git a/polkadot/node/network/bridge/src/lib.rs b/polkadot/node/network/bridge/src/lib.rs
index 794721a70b..d63796d734 100644
--- a/polkadot/node/network/bridge/src/lib.rs
+++ b/polkadot/node/network/bridge/src/lib.rs
@@ -28,10 +28,8 @@ use polkadot_subsystem::{
SubsystemResult, jaeger,
};
use polkadot_subsystem::messages::{
- NetworkBridgeMessage, AllMessages, AvailabilityDistributionMessage,
- BitfieldDistributionMessage, PoVDistributionMessage, StatementDistributionMessage,
- CollatorProtocolMessage, ApprovalDistributionMessage, NetworkBridgeEvent,
- AvailabilityRecoveryMessage,
+ NetworkBridgeMessage, AllMessages,
+ CollatorProtocolMessage, NetworkBridgeEvent,
};
use polkadot_primitives::v1::{Hash, BlockNumber};
use polkadot_node_network_protocol::{
@@ -565,35 +563,7 @@ async fn dispatch_validation_events_to_all(
I: IntoIterator- >,
I::IntoIter: Send,
{
- let messages_for = |event: NetworkBridgeEvent| {
- let av_d = std::iter::once(event.focus().ok().map(|m| AllMessages::AvailabilityDistribution(
- AvailabilityDistributionMessage::NetworkBridgeUpdateV1(m)
- )));
-
- let b = std::iter::once(event.focus().ok().map(|m| AllMessages::BitfieldDistribution(
- BitfieldDistributionMessage::NetworkBridgeUpdateV1(m)
- )));
-
- let p = std::iter::once(event.focus().ok().map(|m| AllMessages::PoVDistribution(
- PoVDistributionMessage::NetworkBridgeUpdateV1(m)
- )));
-
- let s = std::iter::once(event.focus().ok().map(|m| AllMessages::StatementDistribution(
- StatementDistributionMessage::NetworkBridgeUpdateV1(m)
- )));
-
- let ap = std::iter::once(event.focus().ok().map(|m| AllMessages::ApprovalDistribution(
- ApprovalDistributionMessage::NetworkBridgeUpdateV1(m)
- )));
-
- let av_r = std::iter::once(event.focus().ok().map(|m| AllMessages::AvailabilityRecovery(
- AvailabilityRecoveryMessage::NetworkBridgeUpdateV1(m)
- )));
-
- av_d.chain(b).chain(p).chain(s).chain(ap).chain(av_r).filter_map(|x| x)
- };
-
- ctx.send_messages(events.into_iter().flat_map(messages_for)).await
+ ctx.send_messages(events.into_iter().flat_map(AllMessages::dispatch_iter)).await
}
#[tracing::instrument(level = "trace", skip(events, ctx), fields(subsystem = LOG_TARGET))]
@@ -635,8 +605,12 @@ mod tests {
use polkadot_subsystem::{ActiveLeavesUpdate, FromOverseer, OverseerSignal};
use polkadot_subsystem::messages::{
- StatementDistributionMessage, BitfieldDistributionMessage,
+ AvailabilityDistributionMessage,
+ AvailabilityRecoveryMessage,
ApprovalDistributionMessage,
+ BitfieldDistributionMessage,
+ PoVDistributionMessage,
+ StatementDistributionMessage
};
use polkadot_node_subsystem_test_helpers::{
SingleItemSink, SingleItemStream, TestSubsystemContextHandle,
@@ -818,6 +792,15 @@ mod tests {
event: NetworkBridgeEvent,
virtual_overseer: &mut TestSubsystemContextHandle,
) {
+ // Ordering must match the enum variant order
+ // in `AllMessages`.
+ assert_matches!(
+ virtual_overseer.recv().await,
+ AllMessages::StatementDistribution(
+ StatementDistributionMessage::NetworkBridgeUpdateV1(e)
+ ) if e == event.focus().expect("could not focus message")
+ );
+
assert_matches!(
virtual_overseer.recv().await,
AllMessages::AvailabilityDistribution(
@@ -825,6 +808,13 @@ mod tests {
) if e == event.focus().expect("could not focus message")
);
+ assert_matches!(
+ virtual_overseer.recv().await,
+ AllMessages::AvailabilityRecovery(
+ AvailabilityRecoveryMessage::NetworkBridgeUpdateV1(e)
+ ) if e == event.focus().expect("could not focus message")
+ );
+
assert_matches!(
virtual_overseer.recv().await,
AllMessages::BitfieldDistribution(
@@ -839,26 +829,12 @@ mod tests {
) if e == event.focus().expect("could not focus message")
);
- assert_matches!(
- virtual_overseer.recv().await,
- AllMessages::StatementDistribution(
- StatementDistributionMessage::NetworkBridgeUpdateV1(e)
- ) if e == event.focus().expect("could not focus message")
- );
-
assert_matches!(
virtual_overseer.recv().await,
AllMessages::ApprovalDistribution(
ApprovalDistributionMessage::NetworkBridgeUpdateV1(e)
) if e == event.focus().expect("could not focus message")
);
-
- assert_matches!(
- virtual_overseer.recv().await,
- AllMessages::AvailabilityRecovery(
- AvailabilityRecoveryMessage::NetworkBridgeUpdateV1(e)
- ) if e == event.focus().expect("could not focus message")
- );
}
async fn assert_sends_collation_event_to_all(
@@ -1546,4 +1522,38 @@ mod tests {
}
});
}
+
+ #[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 = 6;
+
+ let mut cnt = 0_usize;
+ for msg in AllMessages::dispatch_iter(NetworkBridgeEvent::PeerDisconnected(PeerId::random())) {
+ match msg {
+ AllMessages::CandidateValidation(_) => unreachable!("Not interested in network events"),
+ AllMessages::CandidateBacking(_) => unreachable!("Not interested in network events"),
+ AllMessages::CandidateSelection(_) => 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(_) => { cnt += 1; }
+ AllMessages::AvailabilityRecovery(_) => { cnt += 1; }
+ AllMessages::BitfieldDistribution(_) => { cnt += 1; }
+ AllMessages::BitfieldSigning(_) => unreachable!("Not interested in network events"),
+ AllMessages::Provisioner(_) => unreachable!("Not interested in network events"),
+ AllMessages::PoVDistribution(_) => { cnt += 1; }
+ 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; }
+ // 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);
+ }
}
diff --git a/polkadot/node/subsystem/Cargo.toml b/polkadot/node/subsystem/Cargo.toml
index 3fa2061f04..9dd4e9b80e 100644
--- a/polkadot/node/subsystem/Cargo.toml
+++ b/polkadot/node/subsystem/Cargo.toml
@@ -23,6 +23,7 @@ polkadot-node-network-protocol = { path = "../network/protocol" }
polkadot-primitives = { path = "../../primitives" }
polkadot-statement-table = { path = "../../statement-table" }
polkadot-node-jaeger = { path = "../jaeger" }
+polkadot-procmacro-subsystem-dispatch-gen = { path = "dispatch-gen" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
smallvec = "1.6.1"
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
diff --git a/polkadot/node/subsystem/dispatch-gen/Cargo.toml b/polkadot/node/subsystem/dispatch-gen/Cargo.toml
new file mode 100644
index 0000000000..09de1362c9
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "polkadot-procmacro-subsystem-dispatch-gen"
+version = "0.1.0"
+authors = ["Parity Technologies "]
+edition = "2018"
+description = "Small proc macro to create the distribution code for network events"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = { version = "1.0.60", features = ["full"] }
+quote = "1.0.9"
+proc-macro2 = "1.0.24"
+assert_matches = "1.5.0"
+
+[dev-dependencies]
+trybuild = "1.0.41"
diff --git a/polkadot/node/subsystem/dispatch-gen/src/lib.rs b/polkadot/node/subsystem/dispatch-gen/src/lib.rs
new file mode 100644
index 0000000000..737712639c
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/src/lib.rs
@@ -0,0 +1,208 @@
+// 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 .
+
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use std::fmt;
+use syn::{parse2, Error, Fields, FieldsNamed, FieldsUnnamed, Ident, ItemEnum, Path, Result, Type, Variant};
+
+#[proc_macro_attribute]
+pub fn subsystem_dispatch_gen(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let attr: TokenStream = attr.into();
+ let item: TokenStream = item.into();
+ let mut backup = item.clone();
+ impl_subsystem_dispatch_gen(attr.into(), item).unwrap_or_else(|err| {
+ backup.extend(err.to_compile_error());
+ backup
+ }).into()
+}
+
+/// An enum variant without base type.
+#[derive(Clone)]
+struct EnumVariantDispatchWithTy {
+ // enum ty name
+ ty: Ident,
+ // variant
+ variant: EnumVariantDispatch,
+}
+
+impl fmt::Debug for EnumVariantDispatchWithTy {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}::{:?}", self.ty, self.variant)
+ }
+}
+
+impl ToTokens for EnumVariantDispatchWithTy {
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+ if let Some(inner) = &self.variant.inner {
+ let enum_name = &self.ty;
+ let variant_name = &self.variant.name;
+
+ let quoted = quote! {
+ #enum_name::#variant_name(#inner::from(event))
+ };
+ quoted.to_tokens(tokens);
+ }
+ }
+}
+
+/// An enum variant without the base type, contains the relevant inner type.
+#[derive(Clone)]
+struct EnumVariantDispatch {
+ /// variant name
+ name: Ident,
+ /// The inner type for which a `From::from` impl is anticipated from the input type.
+ /// No code will be generated for this enum variant if `inner` is `None`.
+ inner: Option,
+}
+
+impl fmt::Debug for EnumVariantDispatch {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}(..)", self.name)
+ }
+}
+
+fn prepare_enum_variant(variant: &mut Variant) -> Result {
+ let skip = variant.attrs.iter().find(|attr| attr.path.is_ident("skip")).is_some();
+ variant.attrs = variant.attrs.iter().filter(|attr| !attr.path.is_ident("skip")).cloned().collect::>();
+
+ let variant = variant.clone();
+ let span = variant.ident.span();
+ let inner = match variant.fields.clone() {
+ // look for one called inner
+ Fields::Named(FieldsNamed { brace_token: _, named }) if !skip => named
+ .iter()
+ .find_map(
+ |field| {
+ if let Some(ident) = &field.ident {
+ if ident == "inner" {
+ return Some(Some(field.ty.clone()))
+ }
+ }
+ None
+ },
+ )
+ .ok_or_else(|| {
+ Error::new(span, "To dispatch with struct enum variant, one element must named `inner`")
+ })?,
+
+ // technically, if it has no inner types we cound not require the #[skip] annotation, but better make it consistent
+ Fields::Unnamed(FieldsUnnamed { paren_token: _, unnamed }) if !skip => unnamed
+ .first()
+ .map(|field| Some(field.ty.clone()))
+ .ok_or_else(|| Error::new(span, "Must be annotated with skip, even if no inner types exist."))?,
+ _ if skip => None,
+ Fields::Unit => {
+ return Err(Error::new(
+ span,
+ "Must be annotated with #[skip].",
+ ))
+ }
+ Fields::Unnamed(_) => {
+ return Err(Error::new(
+ span,
+ "Must be annotated with #[skip] or have in `inner` element which impls `From<_>`.",
+ ))
+ }
+ Fields::Named(_) => {
+ return Err(Error::new(
+ span,
+ "Must be annotated with #[skip] or the first wrapped type must impl `From<_>`.",
+ ))
+ }
+ };
+
+ Ok(EnumVariantDispatch { name: variant.ident, inner })
+}
+
+fn impl_subsystem_dispatch_gen(attr: TokenStream, item: TokenStream) -> Result {
+ let event_ty = parse2::(attr)?;
+
+ let mut ie = parse2::(item)?;
+
+ let message_enum = ie.ident.clone();
+ let variants = ie.variants.iter_mut().try_fold(Vec::::new(), |mut acc, variant| {
+ let variant = prepare_enum_variant(variant)?;
+ if variant.inner.is_some() {
+ acc.push(EnumVariantDispatchWithTy { ty: message_enum.clone(), variant })
+ }
+ Ok::<_, syn::Error>(acc)
+ })?;
+
+ let mut orig = ie.to_token_stream();
+
+ let msg = "Generated by #[subsystem_dispatch_gen] proc-macro.";
+
+ orig.extend(quote! {
+ impl #message_enum {
+ #[doc = #msg]
+ pub fn dispatch_iter(event: #event_ty) -> impl Iterator
- + Send {
+ let mut iter = None.into_iter();
+
+ #(
+ let mut iter = iter.chain(std::iter::once(event.focus().ok().map(|event| {
+ #variants
+ })));
+ )*
+ iter.filter_map(|x| x)
+ }
+ }
+ });
+ Ok(orig)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn basic() {
+ let attr = quote! {
+ NetEvent
+ };
+
+ let item = quote! {
+ /// Documentation.
+ #[derive(Clone)]
+ enum AllMessages {
+
+ Sub1(Inner1),
+
+ #[skip]
+ /// D3
+ Sub3,
+
+ /// D4
+ #[skip]
+ Sub4(Inner2),
+
+ /// D2
+ Sub2(Inner2),
+ }
+ };
+
+ let output = impl_subsystem_dispatch_gen(attr, item).expect("Simple example always works. qed");
+ println!("//generated:");
+ println!("{}", output);
+ }
+
+ #[test]
+ fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/err-*.rs");
+ t.pass("tests/ui/ok-*.rs");
+ }
+}
diff --git a/polkadot/node/subsystem/dispatch-gen/tests/ui/err-01-missing-skip.rs b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-01-missing-skip.rs
new file mode 100644
index 0000000000..7248a7181e
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-01-missing-skip.rs
@@ -0,0 +1,37 @@
+#![allow(dead_code)]
+
+use polkadot_procmacro_subsystem_dispatch_gen::subsystem_dispatch_gen;
+
+/// The event type in question.
+#[derive(Clone, Copy)]
+enum Event {
+ Smth,
+ Else,
+}
+
+impl Event {
+ fn focus(&self) -> std::result::Result {
+ unimplemented!("foo")
+ }
+}
+
+/// This should have a `From` impl but does not.
+#[derive(Clone)]
+enum Inner {
+ Foo,
+ Bar(Event),
+}
+
+#[subsystem_dispatch_gen(Event)]
+#[derive(Clone)]
+enum AllMessages {
+ /// Foo
+ Vvvvvv(Inner),
+
+ /// Missing a `#[skip]` annotation
+ Uuuuu,
+}
+
+fn main() {
+ let _x = AllMessages::dispatch_iter(Event::Else);
+}
diff --git a/polkadot/node/subsystem/dispatch-gen/tests/ui/err-01-missing-skip.stderr b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-01-missing-skip.stderr
new file mode 100644
index 0000000000..855521d2c4
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-01-missing-skip.stderr
@@ -0,0 +1,14 @@
+error: Must be annotated with #[skip].
+ --> $DIR/err-01-missing-skip.rs:32:5
+ |
+32 | Uuuuu,
+ | ^^^^^
+
+error[E0599]: no variant or associated item named `dispatch_iter` found for enum `AllMessages` in the current scope
+ --> $DIR/err-01-missing-skip.rs:36:27
+ |
+27 | enum AllMessages {
+ | ---------------- variant or associated item `dispatch_iter` not found here
+...
+36 | let _x = AllMessages::dispatch_iter(Event::Else);
+ | ^^^^^^^^^^^^^ variant or associated item not found in `AllMessages`
diff --git a/polkadot/node/subsystem/dispatch-gen/tests/ui/err-02-missing-from.rs b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-02-missing-from.rs
new file mode 100644
index 0000000000..a7abef2c87
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-02-missing-from.rs
@@ -0,0 +1,41 @@
+#![allow(dead_code)]
+
+use polkadot_procmacro_subsystem_dispatch_gen::subsystem_dispatch_gen;
+
+/// The event type in question.
+#[derive(Clone, Copy, Debug)]
+enum Event {
+ Smth,
+ Else,
+}
+
+impl Event {
+ fn focus(&self) -> std::result::Result {
+ Ok(Intermediate(self.clone()))
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Intermediate(Event);
+
+
+/// This should have a `From` impl but does not.
+#[derive(Debug, Clone)]
+enum Inner {
+ Foo,
+ Bar(Intermediate),
+}
+
+#[subsystem_dispatch_gen(Event)]
+#[derive(Clone)]
+enum AllMessages {
+ /// Foo
+ Vvvvvv(Inner),
+
+ #[skip]
+ Uuuuu,
+}
+
+fn main() {
+ let _x = AllMessages::dispatch_iter(Event::Else);
+}
diff --git a/polkadot/node/subsystem/dispatch-gen/tests/ui/err-02-missing-from.stderr b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-02-missing-from.stderr
new file mode 100644
index 0000000000..bf82201a7e
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/tests/ui/err-02-missing-from.stderr
@@ -0,0 +1,10 @@
+error[E0308]: mismatched types
+ --> $DIR/err-02-missing-from.rs:29:1
+ |
+29 | #[subsystem_dispatch_gen(Event)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected enum `Inner`, found struct `Intermediate`
+ | help: try using a variant of the expected enum: `Inner::Bar(#[subsystem_dispatch_gen(Event)])`
+ |
+ = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/polkadot/node/subsystem/dispatch-gen/tests/ui/ok-01-with-intermediate.rs b/polkadot/node/subsystem/dispatch-gen/tests/ui/ok-01-with-intermediate.rs
new file mode 100644
index 0000000000..b160bf9ce1
--- /dev/null
+++ b/polkadot/node/subsystem/dispatch-gen/tests/ui/ok-01-with-intermediate.rs
@@ -0,0 +1,48 @@
+#![allow(dead_code)]
+
+use polkadot_procmacro_subsystem_dispatch_gen::subsystem_dispatch_gen;
+
+/// The event type in question.
+#[derive(Clone, Copy, Debug)]
+enum Event {
+ Smth,
+ Else,
+}
+
+impl Event {
+ fn focus(&self) -> std::result::Result {
+ Ok(Intermediate(self.clone()))
+ }
+}
+
+
+#[derive(Debug, Clone)]
+struct Intermediate(Event);
+
+
+/// This should have a `From` impl but does not.
+#[derive(Clone, Debug)]
+enum Inner {
+ Foo,
+ Bar(Intermediate),
+}
+
+impl From for Inner {
+ fn from(src: Intermediate) -> Self {
+ Inner::Bar(src)
+ }
+}
+
+#[subsystem_dispatch_gen(Event)]
+#[derive(Clone)]
+enum AllMessages {
+ /// Foo
+ Vvvvvv(Inner),
+
+ #[skip]
+ Uuuuu,
+}
+
+fn main() {
+ let _x = AllMessages::dispatch_iter(Event::Else);
+}
diff --git a/polkadot/node/subsystem/src/lib.rs b/polkadot/node/subsystem/src/lib.rs
index a48eaee028..825614e3b1 100644
--- a/polkadot/node/subsystem/src/lib.rs
+++ b/polkadot/node/subsystem/src/lib.rs
@@ -32,14 +32,14 @@ use polkadot_primitives::v1::{Hash, BlockNumber};
use async_trait::async_trait;
use smallvec::SmallVec;
-use crate::messages::AllMessages;
-
pub mod errors;
pub mod messages;
pub use polkadot_node_jaeger as jaeger;
pub use jaeger::*;
+use self::messages::AllMessages;
+
/// How many slots are stack-reserved for active leaves updates
///
/// If there are fewer than this number of slots, then we've wasted some stack space.
diff --git a/polkadot/node/subsystem/src/messages.rs b/polkadot/node/subsystem/src/messages.rs
index 857b1e90ae..4415da3257 100644
--- a/polkadot/node/subsystem/src/messages.rs
+++ b/polkadot/node/subsystem/src/messages.rs
@@ -44,6 +44,7 @@ use polkadot_primitives::v1::{
CandidateIndex, GroupIndex,
};
use polkadot_statement_table::v1::Misbehavior;
+use polkadot_procmacro_subsystem_dispatch_gen::subsystem_dispatch_gen;
use std::{sync::Arc, collections::btree_map::BTreeMap};
@@ -171,7 +172,7 @@ impl CandidateValidationMessage {
/// Messages received by the Collator Protocol subsystem.
-#[derive(Debug)]
+#[derive(Debug, derive_more::From)]
pub enum CollatorProtocolMessage {
/// Signal to the collator protocol that it should connect to validators with the expectation
/// of collating on the given para. This is only expected to be called once, early on, if at all,
@@ -195,6 +196,7 @@ pub enum CollatorProtocolMessage {
/// Notify a collator that its collation was seconded.
NotifyCollationSeconded(CollatorId, SignedFullStatement),
/// Get a network bridge update.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
@@ -270,13 +272,15 @@ impl NetworkBridgeMessage {
#[derive(Debug, derive_more::From)]
pub enum AvailabilityDistributionMessage {
/// Event from the network bridge.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
/// Incoming request for an availability chunk.
+ #[from]
AvailabilityFetchingRequest(IncomingRequest)
}
/// Availability Recovery Message.
-#[derive(Debug)]
+#[derive(Debug, derive_more::From)]
pub enum AvailabilityRecoveryMessage {
/// Recover available data from validators on the network.
RecoverAvailableData(
@@ -286,6 +290,7 @@ pub enum AvailabilityRecoveryMessage {
oneshot::Sender>,
),
/// Event from the network bridge.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
@@ -300,12 +305,13 @@ impl AvailabilityDistributionMessage {
}
/// Bitfield distribution message.
-#[derive(Debug)]
+#[derive(Debug, derive_more::From)]
pub enum BitfieldDistributionMessage {
/// Distribute a bitfield via gossip to other validators.
DistributeBitfield(Hash, SignedAvailabilityBitfield),
/// Event from the network bridge.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
@@ -509,12 +515,13 @@ impl RuntimeApiMessage {
}
/// Statement distribution message.
-#[derive(Debug)]
+#[derive(Debug, derive_more::From)]
pub enum StatementDistributionMessage {
/// We have originated a signed statement in the context of
/// given relay-parent hash and it should be distributed to other validators.
Share(Hash, SignedFullStatement),
/// Event from the network bridge.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
@@ -572,7 +579,7 @@ impl BoundToRelayParent for ProvisionerMessage {
}
/// Message to the PoV Distribution subsystem.
-#[derive(Debug)]
+#[derive(Debug, derive_more::From)]
pub enum PoVDistributionMessage {
/// Fetch a PoV from the network.
///
@@ -583,6 +590,7 @@ pub enum PoVDistributionMessage {
/// The PoV should correctly hash to the PoV hash mentioned in the CandidateDescriptor
DistributePoV(Hash, CandidateDescriptor, Arc),
/// An update from the network bridge.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
@@ -662,7 +670,7 @@ pub enum ApprovalVotingMessage {
}
/// Message to the Approval Distribution subsystem.
-#[derive(Debug)]
+#[derive(Debug, derive_more::From)]
pub enum ApprovalDistributionMessage {
/// Notify the `ApprovalDistribution` subsystem about new blocks
/// and the candidates contained within them.
@@ -675,21 +683,28 @@ pub enum ApprovalDistributionMessage {
/// If not, the subsystem is free to drop the message.
DistributeApproval(IndirectSignedApprovalVote),
/// An update from the network bridge.
+ #[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
/// A message type tying together all message types that are used across Subsystems.
+#[subsystem_dispatch_gen(NetworkBridgeEvent)]
#[derive(Debug, derive_more::From)]
pub enum AllMessages {
/// Message for the validation subsystem.
+ #[skip]
CandidateValidation(CandidateValidationMessage),
/// Message for the candidate backing subsystem.
+ #[skip]
CandidateBacking(CandidateBackingMessage),
/// Message for the candidate selection subsystem.
+ #[skip]
CandidateSelection(CandidateSelectionMessage),
/// Message for the Chain API subsystem.
+ #[skip]
ChainApi(ChainApiMessage),
/// Message for the Collator Protocol subsystem.
+ #[skip]
CollatorProtocol(CollatorProtocolMessage),
/// Message for the statement distribution subsystem.
StatementDistribution(StatementDistributionMessage),
@@ -700,20 +715,27 @@ pub enum AllMessages {
/// Message for the bitfield distribution subsystem.
BitfieldDistribution(BitfieldDistributionMessage),
/// Message for the bitfield signing subsystem.
+ #[skip]
BitfieldSigning(BitfieldSigningMessage),
/// Message for the Provisioner subsystem.
+ #[skip]
Provisioner(ProvisionerMessage),
/// Message for the PoV Distribution subsystem.
PoVDistribution(PoVDistributionMessage),
/// Message for the Runtime API subsystem.
+ #[skip]
RuntimeApi(RuntimeApiMessage),
/// Message for the availability store subsystem.
+ #[skip]
AvailabilityStore(AvailabilityStoreMessage),
/// Message for the network bridge subsystem.
+ #[skip]
NetworkBridge(NetworkBridgeMessage),
/// Message for the Collation Generation subsystem.
+ #[skip]
CollationGeneration(CollationGenerationMessage),
/// Message for the Approval Voting subsystem.
+ #[skip]
ApprovalVoting(ApprovalVotingMessage),
/// Message for the Approval Distribution subsystem.
ApprovalDistribution(ApprovalDistributionMessage),