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
+55 -22
View File
@@ -16,6 +16,8 @@
//! Convenient interface to runtime information.
use std::cmp::max;
use lru::LruCache;
use parity_scale_codec::Encode;
@@ -24,7 +26,7 @@ use sp_core::crypto::Public;
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
use polkadot_primitives::v1::{CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, OccupiedCore, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ValidatorId, ValidatorIndex};
use polkadot_node_subsystem::SubsystemContext;
use polkadot_node_subsystem::{SubsystemSender, SubsystemContext};
use crate::{
@@ -39,6 +41,17 @@ mod error;
use error::{recv_runtime, Result};
pub use error::{Error, NonFatal, Fatal};
/// Configuration for construction a `RuntimeInfo`.
pub struct Config {
/// Needed for retrieval of `ValidatorInfo`
///
/// Pass `None` if you are not interested.
pub keystore: Option<SyncCryptoStorePtr>,
/// How many sessions should we keep in the cache?
pub session_cache_lru_size: usize,
}
/// Caching of session info.
///
/// It should be ensured that a cached session stays live in the cache as long as we might need it.
@@ -74,32 +87,48 @@ pub struct ValidatorInfo {
pub our_group: Option<GroupIndex>,
}
impl Default for Config {
fn default() -> Self {
Self {
keystore: None,
// Usually we need to cache the current and the last session.
session_cache_lru_size: 2,
}
}
}
impl RuntimeInfo {
/// Create a new `RuntimeInfo` for convenient runtime fetches.
pub fn new(keystore: Option<SyncCryptoStorePtr>) -> Self {
Self {
// Adjust, depending on how many forks we want to support.
session_index_cache: LruCache::new(10),
// We need to cache the current and the last session the most:
session_info_cache: LruCache::new(2),
Self::new_with_config(Config {
keystore,
..Default::default()
})
}
/// Create with more elaborate configuration options.
pub fn new_with_config(cfg: Config) -> Self {
Self {
session_index_cache: LruCache::new(max(10, cfg.session_cache_lru_size)),
session_info_cache: LruCache::new(cfg.session_cache_lru_size),
keystore: cfg.keystore,
}
}
/// Retrieve the current session index.
pub async fn get_session_index<Context>(
pub async fn get_session_index<Sender>(
&mut self,
ctx: &mut Context,
sender: &mut Sender,
parent: Hash,
) -> Result<SessionIndex>
where
Context: SubsystemContext,
Sender: SubsystemSender,
{
match self.session_index_cache.get(&parent) {
Some(index) => Ok(*index),
None => {
let index =
recv_runtime(request_session_index_for_child(parent, ctx.sender()).await)
recv_runtime(request_session_index_for_child(parent, sender).await)
.await?;
self.session_index_cache.put(parent, index);
Ok(index)
@@ -108,31 +137,35 @@ impl RuntimeInfo {
}
/// Get `ExtendedSessionInfo` by relay parent hash.
pub async fn get_session_info<'a>(
pub async fn get_session_info<'a, Sender>(
&'a mut self,
ctx: &mut impl SubsystemContext,
sender: &mut Sender,
parent: Hash,
) -> Result<&'a ExtendedSessionInfo>
where
Sender: SubsystemSender,
{
let session_index = self.get_session_index(ctx, parent).await?;
let session_index = self.get_session_index(sender, parent).await?;
self.get_session_info_by_index(ctx, parent, session_index).await
self.get_session_info_by_index(sender, parent, session_index).await
}
/// Get `ExtendedSessionInfo` by session index.
///
/// `request_session_info` still requires the parent to be passed in, so we take the parent
/// in addition to the `SessionIndex`.
pub async fn get_session_info_by_index<'a>(
pub async fn get_session_info_by_index<'a, Sender>(
&'a mut self,
ctx: &mut impl SubsystemContext,
sender: &mut Sender,
parent: Hash,
session_index: SessionIndex,
) -> Result<&'a ExtendedSessionInfo>
where
Sender: SubsystemSender,
{
if !self.session_info_cache.contains(&session_index) {
let session_info =
recv_runtime(request_session_info(parent, session_index, ctx.sender()).await)
recv_runtime(request_session_info(parent, session_index, sender).await)
.await?
.ok_or(NonFatal::NoSuchSession(session_index))?;
let validator_info = self.get_validator_info(&session_info).await?;
@@ -151,19 +184,19 @@ impl RuntimeInfo {
}
/// Convenience function for checking the signature of something signed.
pub async fn check_signature<Context, Payload, RealPayload>(
pub async fn check_signature<Sender, Payload, RealPayload>(
&mut self,
ctx: &mut Context,
sender: &mut Sender,
parent: Hash,
signed: UncheckedSigned<Payload, RealPayload>,
) -> Result<std::result::Result<Signed<Payload, RealPayload>, UncheckedSigned<Payload, RealPayload>>>
where
Context: SubsystemContext,
Sender: SubsystemSender,
Payload: EncodeAs<RealPayload> + Clone,
RealPayload: Encode + Clone,
{
let session_index = self.get_session_index(ctx, parent).await?;
let info = self.get_session_info_by_index(ctx, parent, session_index).await?;
let session_index = self.get_session_index(sender, parent).await?;
let info = self.get_session_info_by_index(sender, parent, session_index).await?;
Ok(check_signature(session_index, &info.session_info, parent, signed))
}