mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 21:41:02 +00:00
Bridges subtree sync (#3022)
* Squashed 'bridges/' changes from edf33a2c85..277f0d5496 277f0d5496 Dynamic fees for bridges-v1 (#2294) b1c51f7dd2 Finality loop refactoring (#2357) 620db2b10f Add equivocation detector crate and implement clients (#2348) (#2353) 3fe4b13eb4 Add basic equivocation detection pipeline schema (#2338) (#2341) git-subtree-dir: bridges git-subtree-split: 277f0d54961c800b231d8123c6445f378b1deb89 * [dynfees] Rococo/Wococo does not need congestion and dynamic fees (for now) * Fix * ".git/.scripts/commands/fmt/fmt.sh" * Forgotten bridges/Cargo.lock --------- Co-authored-by: command-bot <>
This commit is contained in:
@@ -23,10 +23,11 @@ mod verification;
|
||||
|
||||
use crate::ChainWithGrandpa;
|
||||
pub use verification::{
|
||||
equivocation::{EquivocationsCollector, Error as EquivocationsCollectorError},
|
||||
equivocation::{EquivocationsCollector, GrandpaEquivocationsFinder},
|
||||
optimizer::verify_and_optimize_justification,
|
||||
strict::verify_justification,
|
||||
AncestryChain, Error as JustificationVerificationError, PrecommitError,
|
||||
AncestryChain, Error as JustificationVerificationError, JustificationVerificationContext,
|
||||
PrecommitError,
|
||||
};
|
||||
|
||||
use bp_runtime::{BlockNumberOf, Chain, HashOf, HeaderId};
|
||||
|
||||
+61
-47
@@ -16,33 +16,26 @@
|
||||
|
||||
//! Logic for extracting equivocations from multiple GRANDPA Finality Proofs.
|
||||
|
||||
use crate::justification::{
|
||||
verification::{
|
||||
Error as JustificationVerificationError, JustificationVerifier, PrecommitError,
|
||||
SignedPrecommit,
|
||||
use crate::{
|
||||
justification::{
|
||||
verification::{
|
||||
Error as JustificationVerificationError, IterationFlow,
|
||||
JustificationVerificationContext, JustificationVerifier, PrecommitError,
|
||||
SignedPrecommit,
|
||||
},
|
||||
GrandpaJustification,
|
||||
},
|
||||
GrandpaJustification,
|
||||
ChainWithGrandpa, FindEquivocations,
|
||||
};
|
||||
|
||||
use crate::justification::verification::IterationFlow;
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use frame_support::RuntimeDebug;
|
||||
use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, EquivocationProof, Precommit, SetId};
|
||||
use bp_runtime::{BlockNumberOf, HashOf, HeaderOf};
|
||||
use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, EquivocationProof, Precommit};
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_std::{
|
||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// Justification verification error.
|
||||
#[derive(Eq, RuntimeDebug, PartialEq)]
|
||||
pub enum Error {
|
||||
/// Justification is targeting unexpected round.
|
||||
InvalidRound,
|
||||
/// Justification verification error.
|
||||
JustificationVerification(JustificationVerificationError),
|
||||
}
|
||||
|
||||
enum AuthorityVotes<Header: HeaderT> {
|
||||
SingleVote(SignedPrecommit<Header>),
|
||||
Equivocation(
|
||||
@@ -53,8 +46,7 @@ enum AuthorityVotes<Header: HeaderT> {
|
||||
/// Structure that can extract equivocations from multiple GRANDPA justifications.
|
||||
pub struct EquivocationsCollector<'a, Header: HeaderT> {
|
||||
round: u64,
|
||||
authorities_set_id: SetId,
|
||||
authorities_set: &'a VoterSet<AuthorityId>,
|
||||
context: &'a JustificationVerificationContext,
|
||||
|
||||
votes: BTreeMap<AuthorityId, AuthorityVotes<Header>>,
|
||||
}
|
||||
@@ -62,38 +54,34 @@ pub struct EquivocationsCollector<'a, Header: HeaderT> {
|
||||
impl<'a, Header: HeaderT> EquivocationsCollector<'a, Header> {
|
||||
/// Create a new instance of `EquivocationsCollector`.
|
||||
pub fn new(
|
||||
authorities_set_id: SetId,
|
||||
authorities_set: &'a VoterSet<AuthorityId>,
|
||||
context: &'a JustificationVerificationContext,
|
||||
base_justification: &GrandpaJustification<Header>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut checker = Self {
|
||||
round: base_justification.round,
|
||||
authorities_set_id,
|
||||
authorities_set,
|
||||
votes: BTreeMap::new(),
|
||||
};
|
||||
) -> Result<Self, JustificationVerificationError> {
|
||||
let mut checker = Self { round: base_justification.round, context, votes: BTreeMap::new() };
|
||||
|
||||
checker.verify_justification(
|
||||
(base_justification.commit.target_hash, base_justification.commit.target_number),
|
||||
checker.context,
|
||||
base_justification,
|
||||
)?;
|
||||
|
||||
checker.parse_justification(base_justification)?;
|
||||
Ok(checker)
|
||||
}
|
||||
|
||||
/// Parse an additional justification for equivocations.
|
||||
pub fn parse_justification(
|
||||
&mut self,
|
||||
justification: &GrandpaJustification<Header>,
|
||||
) -> Result<(), Error> {
|
||||
// The justification should target the same round as the base justification.
|
||||
if self.round != justification.round {
|
||||
return Err(Error::InvalidRound)
|
||||
/// Parse additional justifications for equivocations.
|
||||
pub fn parse_justifications(&mut self, justifications: &[GrandpaJustification<Header>]) {
|
||||
let round = self.round;
|
||||
for justification in
|
||||
justifications.iter().filter(|justification| round == justification.round)
|
||||
{
|
||||
// We ignore the Errors received here since we don't care if the proofs are valid.
|
||||
// We only care about collecting equivocations.
|
||||
let _ = self.verify_justification(
|
||||
(justification.commit.target_hash, justification.commit.target_number),
|
||||
self.context,
|
||||
justification,
|
||||
);
|
||||
}
|
||||
|
||||
self.verify_justification(
|
||||
(justification.commit.target_hash, justification.commit.target_number),
|
||||
self.authorities_set_id,
|
||||
self.authorities_set,
|
||||
justification,
|
||||
)
|
||||
.map_err(Error::JustificationVerification)
|
||||
}
|
||||
|
||||
/// Extract the equivocation proofs that have been collected.
|
||||
@@ -102,7 +90,7 @@ impl<'a, Header: HeaderT> EquivocationsCollector<'a, Header> {
|
||||
for (_authority, vote) in self.votes {
|
||||
if let AuthorityVotes::Equivocation(equivocation) = vote {
|
||||
equivocations.push(EquivocationProof::new(
|
||||
self.authorities_set_id,
|
||||
self.context.authority_set_id,
|
||||
sp_consensus_grandpa::Equivocation::Precommit(equivocation),
|
||||
));
|
||||
}
|
||||
@@ -177,3 +165,29 @@ impl<'a, Header: HeaderT> JustificationVerifier<Header> for EquivocationsCollect
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper struct for finding equivocations in GRANDPA proofs.
|
||||
pub struct GrandpaEquivocationsFinder<C>(sp_std::marker::PhantomData<C>);
|
||||
|
||||
impl<C: ChainWithGrandpa>
|
||||
FindEquivocations<
|
||||
GrandpaJustification<HeaderOf<C>>,
|
||||
JustificationVerificationContext,
|
||||
EquivocationProof<HashOf<C>, BlockNumberOf<C>>,
|
||||
> for GrandpaEquivocationsFinder<C>
|
||||
{
|
||||
type Error = JustificationVerificationError;
|
||||
|
||||
fn find_equivocations(
|
||||
verification_context: &JustificationVerificationContext,
|
||||
synced_proof: &GrandpaJustification<HeaderOf<C>>,
|
||||
source_proofs: &[GrandpaJustification<HeaderOf<C>>],
|
||||
) -> Result<Vec<EquivocationProof<HashOf<C>, BlockNumberOf<C>>>, Self::Error> {
|
||||
let mut equivocations_collector =
|
||||
EquivocationsCollector::new(verification_context, synced_proof)?;
|
||||
|
||||
equivocations_collector.parse_justifications(source_proofs);
|
||||
|
||||
Ok(equivocations_collector.into_equivocation_proofs())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ pub mod equivocation;
|
||||
pub mod optimizer;
|
||||
pub mod strict;
|
||||
|
||||
use crate::justification::GrandpaJustification;
|
||||
use crate::{justification::GrandpaJustification, AuthoritySet};
|
||||
|
||||
use bp_runtime::HeaderId;
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
@@ -114,6 +114,8 @@ impl<Header: HeaderT> AncestryChain<Header> {
|
||||
/// Justification verification error.
|
||||
#[derive(Eq, RuntimeDebug, PartialEq)]
|
||||
pub enum Error {
|
||||
/// Could not convert `AuthorityList` to `VoterSet`.
|
||||
InvalidAuthorityList,
|
||||
/// Justification is finalizing unexpected header.
|
||||
InvalidJustificationTarget,
|
||||
/// Error validating a precommit
|
||||
@@ -141,6 +143,24 @@ pub enum PrecommitError {
|
||||
UnrelatedAncestryVote,
|
||||
}
|
||||
|
||||
/// The context needed for validating GRANDPA finality proofs.
|
||||
pub struct JustificationVerificationContext {
|
||||
/// The authority set used to verify the justification.
|
||||
pub voter_set: VoterSet<AuthorityId>,
|
||||
/// The ID of the authority set used to verify the justification.
|
||||
pub authority_set_id: SetId,
|
||||
}
|
||||
|
||||
impl TryFrom<AuthoritySet> for JustificationVerificationContext {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(authority_set: AuthoritySet) -> Result<Self, Self::Error> {
|
||||
let voter_set =
|
||||
VoterSet::new(authority_set.authorities).ok_or(Error::InvalidAuthorityList)?;
|
||||
Ok(JustificationVerificationContext { voter_set, authority_set_id: authority_set.set_id })
|
||||
}
|
||||
}
|
||||
|
||||
enum IterationFlow {
|
||||
Run,
|
||||
Skip,
|
||||
@@ -185,8 +205,7 @@ trait JustificationVerifier<Header: HeaderT> {
|
||||
fn verify_justification(
|
||||
&mut self,
|
||||
finalized_target: (Header::Hash, Header::Number),
|
||||
authorities_set_id: SetId,
|
||||
authorities_set: &VoterSet<AuthorityId>,
|
||||
context: &JustificationVerificationContext,
|
||||
justification: &GrandpaJustification<Header>,
|
||||
) -> Result<(), Error> {
|
||||
// ensure that it is justification for the expected header
|
||||
@@ -196,7 +215,7 @@ trait JustificationVerifier<Header: HeaderT> {
|
||||
return Err(Error::InvalidJustificationTarget)
|
||||
}
|
||||
|
||||
let threshold = authorities_set.threshold().get();
|
||||
let threshold = context.voter_set.threshold().get();
|
||||
let mut chain = AncestryChain::new(justification);
|
||||
let mut signature_buffer = Vec::new();
|
||||
let mut cumulative_weight = 0u64;
|
||||
@@ -211,7 +230,7 @@ trait JustificationVerifier<Header: HeaderT> {
|
||||
}
|
||||
|
||||
// authority must be in the set
|
||||
let authority_info = match authorities_set.get(&signed.id) {
|
||||
let authority_info = match context.voter_set.get(&signed.id) {
|
||||
Some(authority_info) => {
|
||||
// The implementer may want to do extra checks here.
|
||||
// For example to see if the authority has already voted in the same round.
|
||||
@@ -248,7 +267,7 @@ trait JustificationVerifier<Header: HeaderT> {
|
||||
&signed.id,
|
||||
&signed.signature,
|
||||
justification.round,
|
||||
authorities_set_id,
|
||||
context.authority_set_id,
|
||||
&mut signature_buffer,
|
||||
) {
|
||||
self.process_invalid_signature_vote(precommit_idx).map_err(Error::Precommit)?;
|
||||
|
||||
+6
-11
@@ -21,9 +21,10 @@ use crate::justification::{
|
||||
GrandpaJustification,
|
||||
};
|
||||
|
||||
use crate::justification::verification::{IterationFlow, SignedPrecommit};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use sp_consensus_grandpa::{AuthorityId, SetId};
|
||||
use crate::justification::verification::{
|
||||
IterationFlow, JustificationVerificationContext, SignedPrecommit,
|
||||
};
|
||||
use sp_consensus_grandpa::AuthorityId;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_std::{collections::btree_set::BTreeSet, prelude::*};
|
||||
|
||||
@@ -111,8 +112,7 @@ impl<Header: HeaderT> JustificationVerifier<Header> for JustificationOptimizer<H
|
||||
/// Verify and optimize given justification by removing unknown and duplicate votes.
|
||||
pub fn verify_and_optimize_justification<Header: HeaderT>(
|
||||
finalized_target: (Header::Hash, Header::Number),
|
||||
authorities_set_id: SetId,
|
||||
authorities_set: &VoterSet<AuthorityId>,
|
||||
context: &JustificationVerificationContext,
|
||||
justification: &mut GrandpaJustification<Header>,
|
||||
) -> Result<(), Error> {
|
||||
let mut optimizer = JustificationOptimizer {
|
||||
@@ -120,12 +120,7 @@ pub fn verify_and_optimize_justification<Header: HeaderT>(
|
||||
extra_precommits: vec![],
|
||||
redundant_votes_ancestries: Default::default(),
|
||||
};
|
||||
optimizer.verify_justification(
|
||||
finalized_target,
|
||||
authorities_set_id,
|
||||
authorities_set,
|
||||
justification,
|
||||
)?;
|
||||
optimizer.verify_justification(finalized_target, context, justification)?;
|
||||
optimizer.optimize(justification);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -21,9 +21,10 @@ use crate::justification::{
|
||||
GrandpaJustification,
|
||||
};
|
||||
|
||||
use crate::justification::verification::{IterationFlow, SignedPrecommit};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use sp_consensus_grandpa::{AuthorityId, SetId};
|
||||
use crate::justification::verification::{
|
||||
IterationFlow, JustificationVerificationContext, SignedPrecommit,
|
||||
};
|
||||
use sp_consensus_grandpa::AuthorityId;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_std::collections::btree_set::BTreeSet;
|
||||
|
||||
@@ -92,15 +93,9 @@ impl<Header: HeaderT> JustificationVerifier<Header> for StrictJustificationVerif
|
||||
/// Verify that justification, that is generated by given authority set, finalizes given header.
|
||||
pub fn verify_justification<Header: HeaderT>(
|
||||
finalized_target: (Header::Hash, Header::Number),
|
||||
authorities_set_id: SetId,
|
||||
authorities_set: &VoterSet<AuthorityId>,
|
||||
context: &JustificationVerificationContext,
|
||||
justification: &GrandpaJustification<Header>,
|
||||
) -> Result<(), Error> {
|
||||
let mut verifier = StrictJustificationVerifier { votes: BTreeSet::new() };
|
||||
verifier.verify_justification(
|
||||
finalized_target,
|
||||
authorities_set_id,
|
||||
authorities_set,
|
||||
justification,
|
||||
)
|
||||
verifier.verify_justification(finalized_target, context, justification)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user