mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 04:01:10 +00:00
Dispute distribution implementation (#3282)
* Dispute protocol. * Dispute distribution protocol. * Get network requests routed. * WIP: Basic dispute sender logic. * Basic validator determination logic. * WIP: Getting things to typecheck. * Slightly larger timeout. * More typechecking stuff. * Cleanup. * Finished most of the sending logic. * Handle active leaves updates - Cleanup dead disputes - Update sends for new sessions - Retry on errors * Pass sessions in already. * Startup dispute sending. * Provide incoming decoding facilities and use them in statement-distribution. * Relaxed runtime util requirements. We only need a `SubsystemSender` not a full `SubsystemContext`. * Better usability of incoming requests. Make it possible to consume stuff without clones. * Add basic receiver functionality. * Cleanup + fixes for sender. * One more sender fix. * Start receiver. * Make sure to send responses back. * WIP: Exposed authority discovery * Make tests pass. * Fully featured receiver. * Decrease cost of `NotAValidator`. * Make `RuntimeInfo` LRU cache size configurable. * Cache more sessions. * Fix collator protocol. * Disable metrics for now. * Make dispute-distribution a proper subsystem. * Fix naming. * Code style fixes. * Factored out 4x copied mock function. * WIP: Tests. * Whitespace cleanup. * Accessor functions. * More testing. * More Debug instances. * Fix busy loop. * Working tests. * More tests. * Cleanup. * Fix build. * Basic receiving test. * Non validator message gets dropped. * More receiving tests. * Test nested and subsequent imports. * Fix spaces. * Better formatted imports. * Import cleanup. * Metrics. * Message -> MuxedMessage * Message -> MuxedMessage * More review remarks. * Add missing metrics.rs. * Fix flaky test. * Dispute coordinator - deliver confirmations. * Send out `DisputeMessage` on issue local statement. * Unwire dispute distribution. * Review remarks. * Review remarks. * Better docs.
This commit is contained in:
@@ -24,6 +24,7 @@ use parity_scale_codec::{Encode, Decode};
|
||||
use parking_lot::Mutex;
|
||||
use futures::prelude::*;
|
||||
use futures::stream::BoxStream;
|
||||
use polkadot_subsystem::messages::DisputeDistributionMessage;
|
||||
use sc_network::Event as NetworkEvent;
|
||||
use sp_consensus::SyncOracle;
|
||||
|
||||
@@ -57,7 +58,8 @@ use polkadot_node_subsystem_util::metrics::{self, prometheus};
|
||||
/// To be added to [`NetworkConfiguration::extra_sets`].
|
||||
pub use polkadot_node_network_protocol::peer_set::{peer_sets_info, IsAuthority};
|
||||
|
||||
use std::collections::{HashMap, hash_map, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, hash_map};
|
||||
use std::sync::Arc;
|
||||
|
||||
mod validator_discovery;
|
||||
@@ -66,12 +68,14 @@ mod validator_discovery;
|
||||
///
|
||||
/// Defines the `Network` trait with an implementation for an `Arc<NetworkService>`.
|
||||
mod network;
|
||||
use network::{Network, send_message, get_peer_id_by_authority_id};
|
||||
use network::{Network, send_message};
|
||||
|
||||
/// Request multiplexer for combining the multiple request sources into a single `Stream` of `AllMessages`.
|
||||
mod multiplexer;
|
||||
pub use multiplexer::RequestMultiplexer;
|
||||
|
||||
use crate::network::get_peer_id_by_authority_id;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -304,7 +308,7 @@ impl<N, AD> NetworkBridge<N, AD> {
|
||||
impl<Net, AD, Context> Subsystem<Context, SubsystemError> for NetworkBridge<Net, AD>
|
||||
where
|
||||
Net: Network + Sync,
|
||||
AD: validator_discovery::AuthorityDiscovery,
|
||||
AD: validator_discovery::AuthorityDiscovery + Clone,
|
||||
Context: SubsystemContext<Message = NetworkBridgeMessage> + overseer::SubsystemContext<Message = NetworkBridgeMessage>,
|
||||
{
|
||||
fn start(mut self, ctx: Context) -> SpawnedSubsystem {
|
||||
@@ -380,7 +384,7 @@ where
|
||||
Context: SubsystemContext<Message = NetworkBridgeMessage>,
|
||||
Context: overseer::SubsystemContext<Message = NetworkBridgeMessage>,
|
||||
N: Network,
|
||||
AD: validator_discovery::AuthorityDiscovery,
|
||||
AD: validator_discovery::AuthorityDiscovery + Clone,
|
||||
{
|
||||
// This is kept sorted, descending, by block number.
|
||||
let mut live_heads: Vec<ActivatedLeaf> = Vec::with_capacity(MAX_VIEW_HEADS);
|
||||
@@ -877,7 +881,7 @@ async fn run_network<N, AD, Context>(
|
||||
) -> SubsystemResult<()>
|
||||
where
|
||||
N: Network,
|
||||
AD: validator_discovery::AuthorityDiscovery,
|
||||
AD: validator_discovery::AuthorityDiscovery + Clone,
|
||||
Context: SubsystemContext<Message=NetworkBridgeMessage> + overseer::SubsystemContext<Message=NetworkBridgeMessage>,
|
||||
{
|
||||
let shared = Shared::default();
|
||||
@@ -894,6 +898,10 @@ where
|
||||
.get_statement_fetching()
|
||||
.expect("Gets initialized, must be `Some` on startup. qed.");
|
||||
|
||||
let dispute_receiver = request_multiplexer
|
||||
.get_dispute_sending()
|
||||
.expect("Gets initialized, must be `Some` on startup. qed.");
|
||||
|
||||
let (remote, network_event_handler) = handle_network_messages::<>(
|
||||
ctx.sender().clone(),
|
||||
network_service.clone(),
|
||||
@@ -906,6 +914,9 @@ where
|
||||
|
||||
ctx.spawn("network-bridge-network-worker", Box::pin(remote))?;
|
||||
|
||||
ctx.send_message(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(dispute_receiver)
|
||||
).await;
|
||||
ctx.send_message(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(statement_receiver)
|
||||
).await;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::unreachable;
|
||||
|
||||
use futures::channel::mpsc;
|
||||
use futures::stream::{FusedStream, Stream};
|
||||
@@ -42,6 +43,7 @@ use polkadot_overseer::AllMessages;
|
||||
pub struct RequestMultiplexer {
|
||||
receivers: Vec<(Protocol, mpsc::Receiver<network::IncomingRequest>)>,
|
||||
statement_fetching: Option<mpsc::Receiver<network::IncomingRequest>>,
|
||||
dispute_sending: Option<mpsc::Receiver<network::IncomingRequest>>,
|
||||
next_poll: usize,
|
||||
}
|
||||
|
||||
@@ -68,6 +70,8 @@ impl RequestMultiplexer {
|
||||
})
|
||||
.unzip();
|
||||
|
||||
// Ok this code is ugly as hell, it is also a hack, see https://github.com/paritytech/polkadot/issues/2842.
|
||||
// But it works and is executed on startup so, if anything is wrong here it will be noticed immediately.
|
||||
let index = receivers.iter().enumerate().find_map(|(i, (p, _))|
|
||||
if let Protocol::StatementFetching = p {
|
||||
Some(i)
|
||||
@@ -77,10 +81,20 @@ impl RequestMultiplexer {
|
||||
).expect("Statement fetching must be registered. qed.");
|
||||
let statement_fetching = Some(receivers.remove(index).1);
|
||||
|
||||
let index = receivers.iter().enumerate().find_map(|(i, (p, _))|
|
||||
if let Protocol::DisputeSending = p {
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
).expect("Dispute sending must be registered. qed.");
|
||||
let dispute_sending = Some(receivers.remove(index).1);
|
||||
|
||||
(
|
||||
Self {
|
||||
receivers,
|
||||
statement_fetching,
|
||||
dispute_sending,
|
||||
next_poll: 0,
|
||||
},
|
||||
cfgs,
|
||||
@@ -93,6 +107,13 @@ impl RequestMultiplexer {
|
||||
pub fn get_statement_fetching(&mut self) -> Option<mpsc::Receiver<network::IncomingRequest>> {
|
||||
std::mem::take(&mut self.statement_fetching)
|
||||
}
|
||||
|
||||
/// Get the receiver for handling dispute sending requests.
|
||||
///
|
||||
/// This function will only return `Some` once.
|
||||
pub fn get_dispute_sending(&mut self) -> Option<mpsc::Receiver<network::IncomingRequest>> {
|
||||
std::mem::take(&mut self.dispute_sending)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for RequestMultiplexer {
|
||||
@@ -174,6 +195,9 @@ fn multiplex_single(
|
||||
Protocol::StatementFetching => {
|
||||
unreachable!("Statement fetching requests are handled directly. qed.");
|
||||
}
|
||||
Protocol::DisputeSending => {
|
||||
unreachable!("Dispute sending request are handled directly. qed.");
|
||||
}
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ struct TestNetwork {
|
||||
_req_configs: Vec<RequestResponseConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct TestAuthorityDiscovery;
|
||||
|
||||
// The test's view of the network. This receives updates from the subsystem in the form
|
||||
@@ -688,6 +688,12 @@ fn peer_view_updates_sent_via_overseer() {
|
||||
|
||||
let view = view![Hash::repeat_byte(1)];
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
@@ -740,6 +746,12 @@ fn peer_messages_sent_via_overseer() {
|
||||
ObservedRole::Full,
|
||||
).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
@@ -812,6 +824,12 @@ fn peer_disconnect_from_just_one_peerset() {
|
||||
network_handle.connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full).await;
|
||||
network_handle.connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
@@ -894,6 +912,12 @@ fn relays_collation_protocol_messages() {
|
||||
let peer_a = PeerId::random();
|
||||
let peer_b = PeerId::random();
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
@@ -992,6 +1016,12 @@ fn different_views_on_different_peer_sets() {
|
||||
network_handle.connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full).await;
|
||||
network_handle.connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
@@ -1153,6 +1183,12 @@ fn send_messages_to_peers() {
|
||||
network_handle.connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full).await;
|
||||
network_handle.connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
@@ -1279,7 +1315,8 @@ fn spread_event_to_subsystems_is_up_to_date() {
|
||||
AllMessages::ApprovalDistribution(_) => { cnt += 1; }
|
||||
AllMessages::GossipSupport(_) => unreachable!("Not interested in network events"),
|
||||
AllMessages::DisputeCoordinator(_) => unreachable!("Not interested in network events"),
|
||||
AllMessages::DisputeParticipation(_) => unreachable!("Not interetsed in network events"),
|
||||
AllMessages::DisputeParticipation(_) => unreachable!("Not interested in network events"),
|
||||
AllMessages::DisputeDistribution(_) => unreachable!("Not interested in network events"),
|
||||
AllMessages::ChainSelection(_) => 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.
|
||||
@@ -1325,6 +1362,12 @@ fn our_view_updates_decreasing_order_and_limited_to_max() {
|
||||
0,
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(
|
||||
DisputeDistributionMessage::DisputeSendingReceiver(_)
|
||||
)
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
|
||||
@@ -21,37 +21,16 @@ use crate::Network;
|
||||
use core::marker::PhantomData;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::channel::oneshot;
|
||||
|
||||
use sc_network::multiaddr::Multiaddr;
|
||||
use sc_authority_discovery::Service as AuthorityDiscoveryService;
|
||||
use polkadot_node_network_protocol::PeerId;
|
||||
|
||||
use polkadot_primitives::v1::AuthorityDiscoveryId;
|
||||
use polkadot_node_network_protocol::peer_set::{PeerSet, PerPeerSet};
|
||||
pub use polkadot_node_network_protocol::authority_discovery::AuthorityDiscovery;
|
||||
|
||||
const LOG_TARGET: &str = "parachain::validator-discovery";
|
||||
|
||||
/// An abstraction over the authority discovery service.
|
||||
#[async_trait]
|
||||
pub trait AuthorityDiscovery: Send + Clone + 'static {
|
||||
/// Get the addresses for the given [`AuthorityId`] from the local address cache.
|
||||
async fn get_addresses_by_authority_id(&mut self, authority: AuthorityDiscoveryId) -> Option<Vec<Multiaddr>>;
|
||||
/// Get the [`AuthorityId`] for the given [`PeerId`] from the local address cache.
|
||||
async fn get_authority_id_by_peer_id(&mut self, peer_id: PeerId) -> Option<AuthorityDiscoveryId>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AuthorityDiscovery for AuthorityDiscoveryService {
|
||||
async fn get_addresses_by_authority_id(&mut self, authority: AuthorityDiscoveryId) -> Option<Vec<Multiaddr>> {
|
||||
AuthorityDiscoveryService::get_addresses_by_authority_id(self, authority).await
|
||||
}
|
||||
|
||||
async fn get_authority_id_by_peer_id(&mut self, peer_id: PeerId) -> Option<AuthorityDiscoveryId> {
|
||||
AuthorityDiscoveryService::get_authority_id_by_peer_id(self, peer_id).await
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Service<N, AD> {
|
||||
state: PerPeerSet<StatePerPeerSet>,
|
||||
// PhantomData used to make the struct generic instead of having generic methods
|
||||
@@ -147,9 +126,10 @@ mod tests {
|
||||
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
use futures::stream::BoxStream;
|
||||
use async_trait::async_trait;
|
||||
use sc_network::{Event as NetworkEvent, IfDisconnected};
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use polkadot_node_network_protocol::request_response::request::Requests;
|
||||
use polkadot_node_network_protocol::{PeerId, request_response::request::Requests};
|
||||
|
||||
fn new_service() -> Service<TestNetwork, TestAuthorityDiscovery> {
|
||||
Service::new()
|
||||
@@ -164,7 +144,7 @@ mod tests {
|
||||
peers_set: HashSet<Multiaddr>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, Debug)]
|
||||
struct TestAuthorityDiscovery {
|
||||
by_authority_id: HashMap<AuthorityDiscoveryId, Multiaddr>,
|
||||
by_peer_id: HashMap<PeerId, AuthorityDiscoveryId>,
|
||||
|
||||
Reference in New Issue
Block a user