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:
Robert Klotzner
2021-07-09 04:29:53 +02:00
committed by GitHub
parent 20993b32b1
commit b5257b2407
52 changed files with 4040 additions and 407 deletions
@@ -60,11 +60,11 @@ impl From<runtime::Error> for Error {
#[derive(Debug, Error)]
pub enum Fatal {
/// Requester channel is never closed.
#[error("Requester receiver stream finished.")]
#[error("Requester receiver stream finished")]
RequesterReceiverFinished,
/// Responder channel is never closed.
#[error("Responder receiver stream finished.")]
#[error("Responder receiver stream finished")]
ResponderReceiverFinished,
/// Spawning a running task failed.
@@ -580,7 +580,7 @@ struct FetchingInfo {
}
/// Messages to be handled in this subsystem.
enum Message {
enum MuxedMessage {
/// Messages from other subsystems.
Subsystem(FatalResult<FromOverseer<StatementDistributionMessage>>),
/// Messages from spawned requester background tasks.
@@ -589,12 +589,12 @@ enum Message {
Responder(Option<ResponderMessage>)
}
impl Message {
impl MuxedMessage {
async fn receive(
ctx: &mut (impl SubsystemContext<Message = StatementDistributionMessage> + overseer::SubsystemContext<Message = StatementDistributionMessage>),
from_requester: &mut mpsc::Receiver<RequesterMessage>,
from_responder: &mut mpsc::Receiver<ResponderMessage>,
) -> Message {
) -> MuxedMessage {
// We are only fusing here to make `select` happy, in reality we will quit if one of those
// streams end:
let from_overseer = ctx.recv().fuse();
@@ -602,9 +602,9 @@ impl Message {
let from_responder = from_responder.next();
futures::pin_mut!(from_overseer, from_requester, from_responder);
futures::select! {
msg = from_overseer => Message::Subsystem(msg.map_err(Fatal::SubsystemReceive)),
msg = from_requester => Message::Requester(msg),
msg = from_responder => Message::Responder(msg),
msg = from_overseer => MuxedMessage::Subsystem(msg.map_err(Fatal::SubsystemReceive)),
msg = from_requester => MuxedMessage::Requester(msg),
msg = from_responder => MuxedMessage::Responder(msg),
}
}
}
@@ -1614,9 +1614,9 @@ impl StatementDistribution {
let (res_sender, mut res_receiver) = mpsc::channel(1);
loop {
let message = Message::receive(&mut ctx, &mut req_receiver, &mut res_receiver).await;
let message = MuxedMessage::receive(&mut ctx, &mut req_receiver, &mut res_receiver).await;
match message {
Message::Subsystem(result) => {
MuxedMessage::Subsystem(result) => {
let result = self.handle_subsystem_message(
&mut ctx,
&mut runtime,
@@ -1637,7 +1637,7 @@ impl StatementDistribution {
tracing::debug!(target: LOG_TARGET, ?error)
}
}
Message::Requester(result) => {
MuxedMessage::Requester(result) => {
let result = self.handle_requester_message(
&mut ctx,
&gossip_peers,
@@ -1649,7 +1649,7 @@ impl StatementDistribution {
.await;
log_error(result.map_err(From::from), "handle_requester_message")?;
}
Message::Responder(result) => {
MuxedMessage::Responder(result) => {
let result = self.handle_responder_message(
&peers,
&mut active_heads,
@@ -1856,8 +1856,8 @@ impl StatementDistribution {
"New active leaf",
);
let session_index = runtime.get_session_index(ctx, relay_parent).await?;
let info = runtime.get_session_info_by_index(ctx, relay_parent, session_index).await?;
let session_index = runtime.get_session_index(ctx.sender(), relay_parent).await?;
let info = runtime.get_session_info_by_index(ctx.sender(), relay_parent, session_index).await?;
let session_info = &info.session_info;
active_heads.entry(relay_parent)
@@ -1899,7 +1899,7 @@ impl StatementDistribution {
}
}
let info = runtime.get_session_info(ctx, relay_parent).await?;
let info = runtime.get_session_info(ctx.sender(), relay_parent).await?;
let session_info = &info.session_info;
let validator_info = &info.validator_info;
@@ -16,8 +16,6 @@
use futures::{SinkExt, StreamExt, channel::{mpsc, oneshot}, stream::FuturesUnordered};
use parity_scale_codec::Decode;
use polkadot_node_network_protocol::{
PeerId, UnifiedReputationChange as Rep,
request_response::{
@@ -85,35 +83,26 @@ pub async fn respond(
Some(v) => v,
};
let sc_network::config::IncomingRequest {
payload,
peer,
pending_response,
} = raw;
let payload = match StatementFetchingRequest::decode(&mut payload.as_ref()) {
let req =
match IncomingRequest::<StatementFetchingRequest>::try_from_raw(
raw,
vec![COST_INVALID_REQUEST],
) {
Err(err) => {
tracing::debug!(
target: LOG_TARGET,
?err,
"Decoding request failed"
);
report_peer(pending_response, COST_INVALID_REQUEST);
continue
}
Ok(payload) => payload,
};
let req = IncomingRequest::new(
peer,
payload,
pending_response
);
let (tx, rx) = oneshot::channel();
if let Err(err) = sender.feed(
ResponderMessage::GetData {
requesting_peer: peer,
requesting_peer: req.peer,
relay_parent: req.payload.relay_parent,
candidate_hash: req.payload.candidate_hash,
tx,
@@ -152,20 +141,3 @@ pub async fn respond(
}
}
}
/// Report peer who sent us a request.
fn report_peer(
tx: oneshot::Sender<sc_network::config::OutgoingResponse>,
rep: Rep,
) {
if let Err(_) = tx.send(sc_network::config::OutgoingResponse {
result: Err(()),
reputation_changes: vec![rep.into_base_rep()],
sent_feedback: None,
}) {
tracing::debug!(
target: LOG_TARGET,
"Reporting peer failed."
);
}
}
@@ -18,6 +18,7 @@ use std::time::Duration;
use std::sync::Arc;
use std::iter::FromIterator as _;
use parity_scale_codec::{Decode, Encode};
use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore;
use super::*;
use sp_keyring::Sr25519Keyring;
use sp_application_crypto::{AppKey, sr25519::Pair, Pair as TraitPair};
@@ -1704,14 +1705,3 @@ fn make_session_info(validators: Vec<Pair>, groups: Vec<Vec<u32>>) -> SessionInf
needed_approvals: 0,
}
}
pub fn make_ferdie_keystore() -> SyncCryptoStorePtr {
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
SyncCryptoStore::sr25519_generate_new(
&*keystore,
ValidatorId::ID,
Some(&Sr25519Keyring::Ferdie.to_seed()),
)
.expect("Insert key into keystore");
keystore
}