mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 10:21:05 +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:
@@ -22,14 +22,12 @@
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use futures::Future;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr, Error as KeystoreError};
|
||||
use sp_application_crypto::AppKey;
|
||||
|
||||
pub use sp_core::traits::SpawnNamed;
|
||||
pub use sp_consensus_babe::{
|
||||
@@ -40,20 +38,32 @@ use polkadot_primitives::v1::{
|
||||
BlakeTwo256, CandidateCommitments, CandidateHash, CollatorPair, CommittedCandidateReceipt,
|
||||
CompactStatement, EncodeAs, Hash, HashT, HeadData, Id as ParaId, OutboundHrmpMessage,
|
||||
PersistedValidationData, Signed, UncheckedSigned, UpwardMessage, ValidationCode,
|
||||
ValidatorIndex, ValidatorSignature, ValidDisputeStatementKind, InvalidDisputeStatementKind,
|
||||
CandidateReceipt, ValidatorId, SessionIndex, DisputeStatement, MAX_CODE_SIZE, MAX_POV_SIZE,
|
||||
ValidatorIndex, SessionIndex, MAX_CODE_SIZE, MAX_POV_SIZE,
|
||||
};
|
||||
|
||||
pub use polkadot_parachain::primitives::BlockData;
|
||||
|
||||
pub mod approval;
|
||||
|
||||
/// Disputes related types.
|
||||
pub mod disputes;
|
||||
pub use disputes::{
|
||||
SignedDisputeStatement, UncheckedDisputeMessage, DisputeMessage, CandidateVotes, InvalidDisputeVote, ValidDisputeVote,
|
||||
DisputeMessageCheckError,
|
||||
};
|
||||
|
||||
/// The bomb limit for decompressing code blobs.
|
||||
pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize;
|
||||
|
||||
/// The bomb limit for decompressing PoV blobs.
|
||||
pub const POV_BOMB_LIMIT: usize = (MAX_POV_SIZE * 4u32) as usize;
|
||||
|
||||
/// It would be nice to draw this from the chain state, but we have no tools for it right now.
|
||||
/// On Polkadot this is 1 day, and on Kusama it's 6 hours.
|
||||
///
|
||||
/// Number of sessions we want to consider in disputes.
|
||||
pub const DISPUTE_WINDOW: SessionIndex = 6;
|
||||
|
||||
/// The cumulative weight of a block in a fork-choice rule.
|
||||
pub type BlockWeight = u32;
|
||||
|
||||
@@ -283,125 +293,3 @@ pub fn maybe_compress_pov(pov: PoV) -> PoV {
|
||||
let pov = PoV { block_data: BlockData(raw) };
|
||||
pov
|
||||
}
|
||||
|
||||
/// Tracked votes on candidates, for the purposes of dispute resolution.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CandidateVotes {
|
||||
/// The receipt of the candidate itself.
|
||||
pub candidate_receipt: CandidateReceipt,
|
||||
/// Votes of validity, sorted by validator index.
|
||||
pub valid: Vec<(ValidDisputeStatementKind, ValidatorIndex, ValidatorSignature)>,
|
||||
/// Votes of invalidity, sorted by validator index.
|
||||
pub invalid: Vec<(InvalidDisputeStatementKind, ValidatorIndex, ValidatorSignature)>,
|
||||
}
|
||||
|
||||
impl CandidateVotes {
|
||||
/// Get the set of all validators who have votes in the set, ascending.
|
||||
pub fn voted_indices(&self) -> Vec<ValidatorIndex> {
|
||||
let mut v: Vec<_> = self.valid.iter().map(|x| x.1).chain(
|
||||
self.invalid.iter().map(|x| x.1)
|
||||
).collect();
|
||||
|
||||
v.sort();
|
||||
v.dedup();
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A checked dispute statement from an associated validator.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SignedDisputeStatement {
|
||||
dispute_statement: DisputeStatement,
|
||||
candidate_hash: CandidateHash,
|
||||
validator_public: ValidatorId,
|
||||
validator_signature: ValidatorSignature,
|
||||
session_index: SessionIndex,
|
||||
}
|
||||
|
||||
impl SignedDisputeStatement {
|
||||
/// Create a new `SignedDisputeStatement`, which is only possible by checking the signature.
|
||||
pub fn new_checked(
|
||||
dispute_statement: DisputeStatement,
|
||||
candidate_hash: CandidateHash,
|
||||
session_index: SessionIndex,
|
||||
validator_public: ValidatorId,
|
||||
validator_signature: ValidatorSignature,
|
||||
) -> Result<Self, ()> {
|
||||
dispute_statement.check_signature(
|
||||
&validator_public,
|
||||
candidate_hash,
|
||||
session_index,
|
||||
&validator_signature,
|
||||
).map(|_| SignedDisputeStatement {
|
||||
dispute_statement,
|
||||
candidate_hash,
|
||||
validator_public,
|
||||
validator_signature,
|
||||
session_index,
|
||||
})
|
||||
}
|
||||
|
||||
/// Sign this statement with the given keystore and key. Pass `valid = true` to
|
||||
/// indicate validity of the candidate, and `valid = false` to indicate invalidity.
|
||||
pub async fn sign_explicit(
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
valid: bool,
|
||||
candidate_hash: CandidateHash,
|
||||
session_index: SessionIndex,
|
||||
validator_public: ValidatorId,
|
||||
) -> Result<Option<Self>, KeystoreError> {
|
||||
let dispute_statement = if valid {
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit)
|
||||
} else {
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit)
|
||||
};
|
||||
|
||||
let data = dispute_statement.payload_data(candidate_hash, session_index);
|
||||
let signature = CryptoStore::sign_with(
|
||||
&**keystore,
|
||||
ValidatorId::ID,
|
||||
&validator_public.clone().into(),
|
||||
&data,
|
||||
).await?;
|
||||
|
||||
let signature = match signature {
|
||||
Some(sig) => sig.try_into().map_err(|_| KeystoreError::KeyNotSupported(ValidatorId::ID))?,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
Ok(Some(Self {
|
||||
dispute_statement,
|
||||
candidate_hash,
|
||||
validator_public,
|
||||
validator_signature: signature,
|
||||
session_index,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Access the underlying dispute statement
|
||||
pub fn statement(&self) -> &DisputeStatement {
|
||||
&self.dispute_statement
|
||||
}
|
||||
|
||||
/// Access the underlying candidate hash.
|
||||
pub fn candidate_hash(&self) -> &CandidateHash {
|
||||
&self.candidate_hash
|
||||
}
|
||||
|
||||
/// Access the underlying validator public key.
|
||||
pub fn validator_public(&self) -> &ValidatorId {
|
||||
&self.validator_public
|
||||
}
|
||||
|
||||
/// Access the underlying validator signature.
|
||||
pub fn validator_signature(&self) -> &ValidatorSignature {
|
||||
&self.validator_signature
|
||||
}
|
||||
|
||||
/// Access the underlying session index.
|
||||
pub fn session_index(&self) -> SessionIndex {
|
||||
self.session_index
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user