mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 22:41:06 +00:00
Dispute Coordinator Subsystem (#3150)
* skeleton for dispute-coordinator * add coordinator and participation message types * begin dispute-coordinator DB * functions for loading * implement strongly-typed DB transaction * add some tests for DB transaction * core logic for pruning * guide: update candidate-votes key for coordinator * update candidate-votes key * use big-endian encoding for session, and implement upper bound generator * finish implementing pruning * add a test for note_current_session * define state of the subsystem itself * barebones subsystem definition * control flow * more control flow * implement session-updating logic * trace * control flow for message handling * Update node/core/dispute-coordinator/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update node/subsystem/src/messages.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * some more control flow * guide: remove overlay * more control flow * implement some DB getters * make progress on importing statements * add SignedDisputeStatement struct * move ApprovalVote to shared primitives * add a signing-payload API to explicit dispute statements * add signing-payload to CompactStatement * add relay-parent hash to seconded/valid dispute variatns * correct import * type-safe wrapper around dispute statements * use checked dispute statement in message type * extract rolling session window cache to subsystem-util * extract session window tests * approval-voting: use rolling session info cache * reduce dispute window to match runtime in practice * add byzantine_threshold and supermajority_threshold utilities to primitives * integrate rolling session window * Add PartialOrd to CandidateHash * add Ord to CandidateHash * implement active dispute update * add dispute messages to AllMessages * add dispute stubs to overseer * inform dispute participation to participate * implement issue_local_statement * implement `determine_undisputed_chain` * fix warnings * test harness for dispute coordinator tests * add more helpers to test harness * add some more helpers * some tests for dispute coordinator * ignore wrong validator indices * test finality voting rule constraint * add more tests * add variants to network bridge * fix test compilation * remove most dispute coordinator functionality as of #3222 we can do most of the work within the approval voting subsystem * Revert "remove most dispute coordinator functionality" This reverts commit 9cd615e8eb6ca0b382cbaff525d813e753d6004e. * Use thiserror Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> * Update node/core/dispute-coordinator/src/lib.rs Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> * extract tests to separate module * address nit * adjust run_iteration API Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
This commit is contained in:
committed by
GitHub
parent
7f344df160
commit
5bc2b2779d
@@ -672,6 +672,14 @@ pub enum CompactStatement {
|
||||
Valid(CandidateHash),
|
||||
}
|
||||
|
||||
impl CompactStatement {
|
||||
/// Yields the payload used for validator signatures on this kind
|
||||
/// of statement.
|
||||
pub fn signing_payload(&self, context: &SigningContext) -> Vec<u8> {
|
||||
(self, context).encode()
|
||||
}
|
||||
}
|
||||
|
||||
// Inner helper for codec on `CompactStatement`.
|
||||
#[derive(Encode, Decode)]
|
||||
enum CompactStatementInner {
|
||||
|
||||
@@ -842,6 +842,22 @@ pub struct SessionInfo {
|
||||
pub needed_approvals: u32,
|
||||
}
|
||||
|
||||
/// A vote of approval on a candidate.
|
||||
#[derive(Clone, RuntimeDebug)]
|
||||
pub struct ApprovalVote(pub CandidateHash);
|
||||
|
||||
impl ApprovalVote {
|
||||
/// Yields the signing payload for this approval vote.
|
||||
pub fn signing_payload(
|
||||
&self,
|
||||
session_index: SessionIndex,
|
||||
) -> Vec<u8> {
|
||||
const MAGIC: [u8; 4] = *b"APPR";
|
||||
|
||||
(MAGIC, &self.0, session_index).encode()
|
||||
}
|
||||
}
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// The API for querying the state of parachains on-chain.
|
||||
pub trait ParachainHost<H: Decode = Hash, N: Encode + Decode = BlockNumber> {
|
||||
@@ -1064,6 +1080,60 @@ pub enum DisputeStatement {
|
||||
Invalid(InvalidDisputeStatementKind),
|
||||
}
|
||||
|
||||
impl DisputeStatement {
|
||||
/// Get the payload data for this type of dispute statement.
|
||||
pub fn payload_data(&self, candidate_hash: CandidateHash, session: SessionIndex) -> Vec<u8> {
|
||||
match *self {
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) => {
|
||||
ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash,
|
||||
session,
|
||||
}.signing_payload()
|
||||
},
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(inclusion_parent)) => {
|
||||
CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext {
|
||||
session_index: session,
|
||||
parent_hash: inclusion_parent,
|
||||
})
|
||||
},
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) => {
|
||||
CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext {
|
||||
session_index: session,
|
||||
parent_hash: inclusion_parent,
|
||||
})
|
||||
},
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) => {
|
||||
ApprovalVote(candidate_hash).signing_payload(session)
|
||||
},
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) => {
|
||||
ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash,
|
||||
session,
|
||||
}.signing_payload()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the signature on a dispute statement.
|
||||
pub fn check_signature(
|
||||
&self,
|
||||
validator_public: &ValidatorId,
|
||||
candidate_hash: CandidateHash,
|
||||
session: SessionIndex,
|
||||
validator_signature: &ValidatorSignature,
|
||||
) -> Result<(), ()> {
|
||||
let payload = self.payload_data(candidate_hash, session);
|
||||
|
||||
if validator_signature.verify(&payload[..] , &validator_public) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Different kinds of statements of validity on a candidate.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug)]
|
||||
pub enum ValidDisputeStatementKind {
|
||||
@@ -1072,10 +1142,10 @@ pub enum ValidDisputeStatementKind {
|
||||
Explicit,
|
||||
/// A seconded statement on a candidate from the backing phase.
|
||||
#[codec(index = 1)]
|
||||
BackingSeconded,
|
||||
BackingSeconded(Hash),
|
||||
/// A valid statement on a candidate from the backing phase.
|
||||
#[codec(index = 2)]
|
||||
BackingValid,
|
||||
BackingValid(Hash),
|
||||
/// An approval vote from the approval checking phase.
|
||||
#[codec(index = 3)]
|
||||
ApprovalChecking,
|
||||
@@ -1090,7 +1160,7 @@ pub enum InvalidDisputeStatementKind {
|
||||
}
|
||||
|
||||
/// An explicit statement on a candidate issued as part of a dispute.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug)]
|
||||
#[derive(Clone, PartialEq, RuntimeDebug)]
|
||||
pub struct ExplicitDisputeStatement {
|
||||
/// Whether the candidate is valid
|
||||
pub valid: bool,
|
||||
@@ -1100,6 +1170,15 @@ pub struct ExplicitDisputeStatement {
|
||||
pub session: SessionIndex,
|
||||
}
|
||||
|
||||
impl ExplicitDisputeStatement {
|
||||
/// Produce the payload used for signing this type of statement.
|
||||
pub fn signing_payload(&self) -> Vec<u8> {
|
||||
const MAGIC: [u8; 4] = *b"DISP";
|
||||
|
||||
(MAGIC, self.valid, self.candidate_hash, self.session).encode()
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of statements about a specific candidate.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug)]
|
||||
pub struct DisputeStatementSet {
|
||||
@@ -1140,6 +1219,19 @@ pub struct InherentData<HDR: HeaderT = Header> {
|
||||
pub parent_header: HDR,
|
||||
}
|
||||
|
||||
/// The maximum number of validators `f` which may safely be faulty.
|
||||
///
|
||||
/// The total number of validators is `n = 3f + e` where `e in { 1, 2, 3 }`.
|
||||
pub fn byzantine_threshold(n: usize) -> usize {
|
||||
n.saturating_sub(1) / 3
|
||||
}
|
||||
|
||||
/// The supermajority threshold of validators which represents a subset
|
||||
/// guaranteed to have at least f+1 honest validators.
|
||||
pub fn supermajority_threshold(n: usize) -> usize {
|
||||
n - byzantine_threshold(n)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1190,4 +1282,28 @@ mod tests {
|
||||
&Hash::repeat_byte(4).into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_byzantine_threshold() {
|
||||
assert_eq!(byzantine_threshold(0), 0);
|
||||
assert_eq!(byzantine_threshold(1), 0);
|
||||
assert_eq!(byzantine_threshold(2), 0);
|
||||
assert_eq!(byzantine_threshold(3), 0);
|
||||
assert_eq!(byzantine_threshold(4), 1);
|
||||
assert_eq!(byzantine_threshold(5), 1);
|
||||
assert_eq!(byzantine_threshold(6), 1);
|
||||
assert_eq!(byzantine_threshold(7), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_supermajority_threshold() {
|
||||
assert_eq!(supermajority_threshold(0), 0);
|
||||
assert_eq!(supermajority_threshold(1), 1);
|
||||
assert_eq!(supermajority_threshold(2), 2);
|
||||
assert_eq!(supermajority_threshold(3), 3);
|
||||
assert_eq!(supermajority_threshold(4), 3);
|
||||
assert_eq!(supermajority_threshold(5), 4);
|
||||
assert_eq!(supermajority_threshold(6), 5);
|
||||
assert_eq!(supermajority_threshold(7), 5);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user