mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 08:11:03 +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:
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "bp-asset-hub-kusama"
|
||||
description = "Primitives of AssetHubKusama parachain runtime."
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false }
|
||||
scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
|
||||
|
||||
# Substrate Dependencies
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
# Bridge Dependencies
|
||||
bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"bp-xcm-bridge-hub-router/std",
|
||||
"frame-support/std",
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Module with configuration which reflects AssetHubKusama runtime setup.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall;
|
||||
|
||||
/// `AssetHubKusama` Runtime `Call` enum.
|
||||
///
|
||||
/// The enum represents a subset of possible `Call`s we can send to `AssetHubKusama` chain.
|
||||
/// Ideally this code would be auto-generated from metadata, because we want to
|
||||
/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
|
||||
///
|
||||
/// All entries here (like pretty much in the entire file) must be kept in sync with
|
||||
/// `AssetHubKusama` `construct_runtime`, so that we maintain SCALE-compatibility.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
|
||||
pub enum Call {
|
||||
/// `ToPolkadotXcmRouter` bridge pallet.
|
||||
#[codec(index = 43)]
|
||||
ToPolkadotXcmRouter(XcmBridgeHubRouterCall),
|
||||
}
|
||||
|
||||
frame_support::parameter_types! {
|
||||
/// Some sane weight to execute `xcm::Transact(pallet-xcm-bridge-hub-router::Call::report_bridge_status)`.
|
||||
pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144);
|
||||
|
||||
/// Base delivery fee to `BridgeHubKusama`.
|
||||
/// (initially was calculated `170733333` + `10%` by test `BridgeHubKusama::can_calculate_weight_for_paid_export_message_with_reserve_transfer`)
|
||||
pub const BridgeHubKusamaBaseFeeInDots: u128 = 187806666;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "bp-asset-hub-polkadot"
|
||||
description = "Primitives of AssetHubPolkadot parachain runtime."
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false }
|
||||
scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
|
||||
|
||||
# Substrate Dependencies
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
# Bridge Dependencies
|
||||
bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"bp-xcm-bridge-hub-router/std",
|
||||
"frame-support/std",
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Module with configuration which reflects AssetHubPolkadot runtime setup.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall;
|
||||
|
||||
/// `AssetHubPolkadot` Runtime `Call` enum.
|
||||
///
|
||||
/// The enum represents a subset of possible `Call`s we can send to `AssetHubPolkadot` chain.
|
||||
/// Ideally this code would be auto-generated from metadata, because we want to
|
||||
/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
|
||||
///
|
||||
/// All entries here (like pretty much in the entire file) must be kept in sync with
|
||||
/// `AssetHubPolkadot` `construct_runtime`, so that we maintain SCALE-compatibility.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
|
||||
pub enum Call {
|
||||
/// `ToKusamaXcmRouter` bridge pallet.
|
||||
#[codec(index = 43)]
|
||||
ToKusamaXcmRouter(XcmBridgeHubRouterCall),
|
||||
}
|
||||
|
||||
frame_support::parameter_types! {
|
||||
/// Some sane weight to execute `xcm::Transact(pallet-xcm-bridge-hub-router::Call::report_bridge_status)`.
|
||||
pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144);
|
||||
|
||||
/// Base delivery fee to `BridgeHubPolkadot`.
|
||||
/// (initially was calculated `51220000` + `10%` by test `BridgeHubPolkadot::can_calculate_weight_for_paid_export_message_with_reserve_transfer`)
|
||||
pub const BridgeHubPolkadotBaseFeeInDots: u128 = 56342000;
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use crate::justification::{
|
||||
GrandpaJustification, JustificationVerificationContext, JustificationVerificationError,
|
||||
};
|
||||
use bp_runtime::{
|
||||
BasicOperatingMode, Chain, HashOf, HasherOf, HeaderOf, RawStorageProof, StorageProofChecker,
|
||||
StorageProofError, UnderlyingChainProvider,
|
||||
@@ -30,7 +33,7 @@ use scale_info::TypeInfo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_consensus_grandpa::{AuthorityList, ConsensusLog, SetId, GRANDPA_ENGINE_ID};
|
||||
use sp_runtime::{traits::Header as HeaderT, Digest, RuntimeDebug};
|
||||
use sp_std::boxed::Box;
|
||||
use sp_std::{boxed::Box, vec::Vec};
|
||||
|
||||
pub mod justification;
|
||||
pub mod storage_keys;
|
||||
@@ -172,13 +175,48 @@ impl<Number: Codec> ConsensusLogReader for GrandpaConsensusLogReader<Number> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The Grandpa-related info associated to a header.
|
||||
/// The finality-related info associated to a header.
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Clone, TypeInfo)]
|
||||
pub struct HeaderGrandpaInfo<Header: HeaderT> {
|
||||
/// The header justification
|
||||
pub justification: justification::GrandpaJustification<Header>,
|
||||
/// The authority set introduced by the header.
|
||||
pub authority_set: Option<AuthoritySet>,
|
||||
pub struct HeaderFinalityInfo<FinalityProof, FinalityVerificationContext> {
|
||||
/// The header finality proof.
|
||||
pub finality_proof: FinalityProof,
|
||||
/// The new verification context introduced by the header.
|
||||
pub new_verification_context: Option<FinalityVerificationContext>,
|
||||
}
|
||||
|
||||
/// Grandpa-related info associated to a header. This info can be saved to events.
|
||||
pub type StoredHeaderGrandpaInfo<Header> =
|
||||
HeaderFinalityInfo<GrandpaJustification<Header>, AuthoritySet>;
|
||||
|
||||
/// Processed Grandpa-related info associated to a header.
|
||||
pub type HeaderGrandpaInfo<Header> =
|
||||
HeaderFinalityInfo<GrandpaJustification<Header>, JustificationVerificationContext>;
|
||||
|
||||
impl<Header: HeaderT> TryFrom<StoredHeaderGrandpaInfo<Header>> for HeaderGrandpaInfo<Header> {
|
||||
type Error = JustificationVerificationError;
|
||||
|
||||
fn try_from(grandpa_info: StoredHeaderGrandpaInfo<Header>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
finality_proof: grandpa_info.finality_proof,
|
||||
new_verification_context: match grandpa_info.new_verification_context {
|
||||
Some(authority_set) => Some(authority_set.try_into()?),
|
||||
None => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for finding equivocations in finality proofs.
|
||||
pub trait FindEquivocations<FinalityProof, FinalityVerificationContext, EquivocationProof> {
|
||||
/// The type returned when encountering an error while looking for equivocations.
|
||||
type Error;
|
||||
|
||||
/// Find equivocations.
|
||||
fn find_equivocations(
|
||||
verification_context: &FinalityVerificationContext,
|
||||
synced_proof: &FinalityProof,
|
||||
source_proofs: &[FinalityProof],
|
||||
) -> Result<Vec<EquivocationProof>, Self::Error>;
|
||||
}
|
||||
|
||||
/// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime.
|
||||
@@ -244,16 +282,17 @@ pub trait ChainWithGrandpa: Chain {
|
||||
const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32;
|
||||
}
|
||||
|
||||
/// A trait that provides the type of the underlying `ChainWithGrandpa`.
|
||||
pub trait UnderlyingChainWithGrandpaProvider: UnderlyingChainProvider {
|
||||
/// Underlying `ChainWithGrandpa` type.
|
||||
type ChainWithGrandpa: ChainWithGrandpa;
|
||||
}
|
||||
|
||||
impl<T> UnderlyingChainWithGrandpaProvider for T
|
||||
impl<T> ChainWithGrandpa for T
|
||||
where
|
||||
T: UnderlyingChainProvider,
|
||||
T: Chain + UnderlyingChainProvider,
|
||||
T::Chain: ChainWithGrandpa,
|
||||
{
|
||||
type ChainWithGrandpa = T::Chain;
|
||||
const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str =
|
||||
<T::Chain as ChainWithGrandpa>::WITH_CHAIN_GRANDPA_PALLET_NAME;
|
||||
const MAX_AUTHORITIES_COUNT: u32 = <T::Chain as ChainWithGrandpa>::MAX_AUTHORITIES_COUNT;
|
||||
const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 =
|
||||
<T::Chain as ChainWithGrandpa>::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY;
|
||||
const MAX_HEADER_SIZE: u32 = <T::Chain as ChainWithGrandpa>::MAX_HEADER_SIZE;
|
||||
const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 =
|
||||
<T::Chain as ChainWithGrandpa>::AVERAGE_HEADER_SIZE_IN_JUSTIFICATION;
|
||||
}
|
||||
|
||||
@@ -22,14 +22,15 @@
|
||||
//! but their purpose is different.
|
||||
|
||||
use bp_header_chain::justification::{
|
||||
verify_justification, GrandpaJustification, JustificationVerificationError, PrecommitError,
|
||||
verify_justification, GrandpaJustification, JustificationVerificationContext,
|
||||
JustificationVerificationError, PrecommitError,
|
||||
};
|
||||
use bp_test_utils::{
|
||||
header_id, make_justification_for_header, signed_precommit, test_header, Account,
|
||||
JustificationGeneratorParams, ALICE, BOB, CHARLIE, DAVE, EVE, FERDIE, TEST_GRANDPA_SET_ID,
|
||||
};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use sp_consensus_grandpa::{AuthorityId, AuthorityWeight};
|
||||
use sp_consensus_grandpa::{AuthorityId, AuthorityWeight, SetId};
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
|
||||
type TestHeader = sp_runtime::testing::Header;
|
||||
@@ -81,6 +82,11 @@ fn full_voter_set() -> VoterSet<AuthorityId> {
|
||||
VoterSet::new(full_accounts_set().iter().map(|(id, w)| (AuthorityId::from(*id), *w))).unwrap()
|
||||
}
|
||||
|
||||
pub fn full_verification_context(set_id: SetId) -> JustificationVerificationContext {
|
||||
let voter_set = full_voter_set();
|
||||
JustificationVerificationContext { voter_set, authority_set_id: set_id }
|
||||
}
|
||||
|
||||
/// Get a minimal set of accounts.
|
||||
fn minimal_accounts_set() -> Vec<(Account, AuthorityWeight)> {
|
||||
// there are 5 accounts in the full set => we need 2/3 + 1 accounts, which results in 4 accounts
|
||||
@@ -115,8 +121,7 @@ fn same_result_when_precommit_target_has_lower_number_than_commit_target() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::UnrelatedAncestryVote)),
|
||||
@@ -148,8 +153,7 @@ fn same_result_when_precommit_target_is_not_descendant_of_commit_target() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::UnrelatedAncestryVote)),
|
||||
@@ -182,8 +186,7 @@ fn same_result_when_there_are_not_enough_cumulative_weight_to_finalize_commit_ta
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::TooLowCumulativeWeight),
|
||||
@@ -220,8 +223,7 @@ fn different_result_when_justification_contains_duplicate_vote() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::DuplicateAuthorityVote)),
|
||||
@@ -261,8 +263,7 @@ fn different_results_when_authority_equivocates_once_in_a_round() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::DuplicateAuthorityVote)),
|
||||
@@ -314,8 +315,7 @@ fn different_results_when_authority_equivocates_twice_in_a_round() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::DuplicateAuthorityVote)),
|
||||
@@ -353,8 +353,7 @@ fn different_results_when_there_are_more_than_enough_votes() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::RedundantAuthorityVote)),
|
||||
@@ -394,8 +393,7 @@ fn different_results_when_there_is_a_vote_of_unknown_authority() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&full_voter_set(),
|
||||
&full_verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::UnknownAuthorityVote)),
|
||||
|
||||
@@ -25,19 +25,18 @@ type TestHeader = sp_runtime::testing::Header;
|
||||
|
||||
#[test]
|
||||
fn duplicate_votes_are_not_considered_equivocations() {
|
||||
let voter_set = voter_set();
|
||||
let verification_context = verification_context(TEST_GRANDPA_SET_ID);
|
||||
let base_justification = make_default_justification::<TestHeader>(&test_header(1));
|
||||
|
||||
let mut collector =
|
||||
EquivocationsCollector::new(TEST_GRANDPA_SET_ID, &voter_set, &base_justification).unwrap();
|
||||
collector.parse_justification(&base_justification.clone()).unwrap();
|
||||
EquivocationsCollector::new(&verification_context, &base_justification).unwrap();
|
||||
collector.parse_justifications(&[base_justification.clone()]);
|
||||
|
||||
assert_eq!(collector.into_equivocation_proofs().len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn equivocations_are_detected_in_base_justification_redundant_votes() {
|
||||
let voter_set = voter_set();
|
||||
let mut base_justification = make_default_justification::<TestHeader>(&test_header(1));
|
||||
|
||||
let first_vote = base_justification.commit.precommits[0].clone();
|
||||
@@ -49,8 +48,9 @@ fn equivocations_are_detected_in_base_justification_redundant_votes() {
|
||||
);
|
||||
base_justification.commit.precommits.push(equivocation.clone());
|
||||
|
||||
let verification_context = verification_context(TEST_GRANDPA_SET_ID);
|
||||
let collector =
|
||||
EquivocationsCollector::new(TEST_GRANDPA_SET_ID, &voter_set, &base_justification).unwrap();
|
||||
EquivocationsCollector::new(&verification_context, &base_justification).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
collector.into_equivocation_proofs(),
|
||||
@@ -80,7 +80,6 @@ fn equivocations_are_detected_in_base_justification_redundant_votes() {
|
||||
|
||||
#[test]
|
||||
fn equivocations_are_detected_in_extra_justification_redundant_votes() {
|
||||
let voter_set = voter_set();
|
||||
let base_justification = make_default_justification::<TestHeader>(&test_header(1));
|
||||
let first_vote = base_justification.commit.precommits[0].clone();
|
||||
|
||||
@@ -93,9 +92,10 @@ fn equivocations_are_detected_in_extra_justification_redundant_votes() {
|
||||
);
|
||||
extra_justification.commit.precommits.push(equivocation.clone());
|
||||
|
||||
let verification_context = verification_context(TEST_GRANDPA_SET_ID);
|
||||
let mut collector =
|
||||
EquivocationsCollector::new(TEST_GRANDPA_SET_ID, &voter_set, &base_justification).unwrap();
|
||||
collector.parse_justification(&extra_justification).unwrap();
|
||||
EquivocationsCollector::new(&verification_context, &base_justification).unwrap();
|
||||
collector.parse_justifications(&[extra_justification]);
|
||||
|
||||
assert_eq!(
|
||||
collector.into_equivocation_proofs(),
|
||||
|
||||
@@ -30,8 +30,7 @@ fn optimizer_does_noting_with_minimal_justification() {
|
||||
let num_precommits_before = justification.commit.precommits.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -53,8 +52,7 @@ fn unknown_authority_votes_are_removed_by_optimizer() {
|
||||
let num_precommits_before = justification.commit.precommits.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -74,8 +72,7 @@ fn duplicate_authority_votes_are_removed_by_optimizer() {
|
||||
let num_precommits_before = justification.commit.precommits.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -105,8 +102,7 @@ fn invalid_authority_signatures_are_removed_by_optimizer() {
|
||||
let num_precommits_before = justification.commit.precommits.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -128,8 +124,7 @@ fn redundant_authority_votes_are_removed_by_optimizer() {
|
||||
let num_precommits_before = justification.commit.precommits.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -154,8 +149,7 @@ fn unrelated_ancestry_votes_are_removed_by_optimizer() {
|
||||
let num_precommits_before = justification.commit.precommits.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(2),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -172,8 +166,7 @@ fn redundant_votes_ancestries_are_removed_by_optimizer() {
|
||||
let num_votes_ancestries_before = justification.votes_ancestries.len();
|
||||
verify_and_optimize_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&mut justification,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
//! Tests for Grandpa strict justification verifier code.
|
||||
|
||||
use bp_header_chain::justification::{
|
||||
required_justification_precommits, verify_justification, JustificationVerificationError,
|
||||
PrecommitError,
|
||||
required_justification_precommits, verify_justification, JustificationVerificationContext,
|
||||
JustificationVerificationError, PrecommitError,
|
||||
};
|
||||
use bp_test_utils::*;
|
||||
|
||||
@@ -40,8 +40,7 @@ fn valid_justification_accepted() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Ok(()),
|
||||
@@ -65,8 +64,7 @@ fn valid_justification_accepted_with_single_fork() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&make_justification_for_header::<TestHeader>(params)
|
||||
),
|
||||
Ok(()),
|
||||
@@ -100,8 +98,7 @@ fn valid_justification_accepted_with_arbitrary_number_of_authorities() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set,
|
||||
&JustificationVerificationContext { voter_set, authority_set_id: TEST_GRANDPA_SET_ID },
|
||||
&make_justification_for_header::<TestHeader>(params)
|
||||
),
|
||||
Ok(()),
|
||||
@@ -113,8 +110,7 @@ fn justification_with_invalid_target_rejected() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(2),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&make_default_justification::<TestHeader>(&test_header(1)),
|
||||
),
|
||||
Err(JustificationVerificationError::InvalidJustificationTarget),
|
||||
@@ -129,8 +125,7 @@ fn justification_with_invalid_commit_rejected() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::TooLowCumulativeWeight),
|
||||
@@ -146,8 +141,7 @@ fn justification_with_invalid_authority_signature_rejected() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::Precommit(PrecommitError::InvalidAuthoritySignature)),
|
||||
@@ -162,8 +156,7 @@ fn justification_with_invalid_precommit_ancestry() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&justification,
|
||||
),
|
||||
Err(JustificationVerificationError::RedundantVotesAncestries),
|
||||
@@ -187,8 +180,7 @@ fn justification_is_invalid_if_we_dont_meet_threshold() {
|
||||
assert_eq!(
|
||||
verify_justification::<TestHeader>(
|
||||
header_id::<TestHeader>(1),
|
||||
TEST_GRANDPA_SET_ID,
|
||||
&voter_set(),
|
||||
&verification_context(TEST_GRANDPA_SET_ID),
|
||||
&make_justification_for_header::<TestHeader>(params)
|
||||
),
|
||||
Err(JustificationVerificationError::TooLowCumulativeWeight),
|
||||
|
||||
@@ -387,6 +387,14 @@ impl Default for OutboundLaneData {
|
||||
}
|
||||
}
|
||||
|
||||
impl OutboundLaneData {
|
||||
/// Return nonces of all currently queued messages (i.e. messages that we believe
|
||||
/// are not delivered yet).
|
||||
pub fn queued_messages(&self) -> RangeInclusive<MessageNonce> {
|
||||
(self.latest_received_nonce + 1)..=self.latest_generated_nonce
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the number of messages that the relayers have delivered.
|
||||
pub fn calc_relayers_rewards<AccountId>(
|
||||
messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
|
||||
|
||||
@@ -115,11 +115,26 @@ impl<AccountId> DeliveryConfirmationPayments<AccountId> for () {
|
||||
}
|
||||
}
|
||||
|
||||
/// Callback that is called at the source chain (bridge hub) when we get delivery confirmation
|
||||
/// for new messages.
|
||||
pub trait OnMessagesDelivered {
|
||||
/// New messages delivery has been confirmed.
|
||||
///
|
||||
/// The only argument of the function is the number of yet undelivered messages
|
||||
fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce);
|
||||
}
|
||||
|
||||
impl OnMessagesDelivered for () {
|
||||
fn on_messages_delivered(_lane: LaneId, _enqueued_messages: MessageNonce) {}
|
||||
}
|
||||
|
||||
/// Send message artifacts.
|
||||
#[derive(Eq, RuntimeDebug, PartialEq)]
|
||||
pub struct SendMessageArtifacts {
|
||||
/// Nonce of the message.
|
||||
pub nonce: MessageNonce,
|
||||
/// Number of enqueued messages at the lane, after the message is sent.
|
||||
pub enqueued_messages: MessageNonce,
|
||||
}
|
||||
|
||||
/// Messages bridge API to be used from other pallets.
|
||||
@@ -141,7 +156,7 @@ impl<Payload> MessagesBridge<Payload> for NoopMessagesBridge {
|
||||
type Error = &'static str;
|
||||
|
||||
fn send_message(_lane: LaneId, _message: Payload) -> Result<SendMessageArtifacts, Self::Error> {
|
||||
Ok(SendMessageArtifacts { nonce: 0 })
|
||||
Ok(SendMessageArtifacts { nonce: 0, enqueued_messages: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,15 @@ pub trait MessageDispatch {
|
||||
/// Fine-grained result of single message dispatch (for better diagnostic purposes)
|
||||
type DispatchLevelResult: Clone + sp_std::fmt::Debug + Eq;
|
||||
|
||||
/// Returns `true` if dispatcher is ready to accept additional messages. The `false` should
|
||||
/// be treated as a hint by both dispatcher and its consumers - i.e. dispatcher shall not
|
||||
/// simply drop messages if it returns `false`. The consumer may still call the `dispatch`
|
||||
/// if dispatcher has returned `false`.
|
||||
///
|
||||
/// We check it in the messages delivery transaction prologue. So if it becomes `false`
|
||||
/// after some portion of messages is already dispatched, it doesn't fail the whole transaction.
|
||||
fn is_active() -> bool;
|
||||
|
||||
/// Estimate dispatch weight.
|
||||
///
|
||||
/// This function must return correct upper bound of dispatch weight. The return value
|
||||
@@ -186,6 +195,10 @@ impl<MessagesProof, DispatchPayload: Decode> MessageDispatch
|
||||
type DispatchPayload = DispatchPayload;
|
||||
type DispatchLevelResult = ();
|
||||
|
||||
fn is_active() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight {
|
||||
Weight::MAX
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ macro_rules! decl_bridge_finality_runtime_apis {
|
||||
}
|
||||
};
|
||||
($chain: ident, grandpa) => {
|
||||
decl_bridge_finality_runtime_apis!($chain, grandpa => bp_header_chain::HeaderGrandpaInfo<Header>);
|
||||
decl_bridge_finality_runtime_apis!($chain, grandpa => bp_header_chain::StoredHeaderGrandpaInfo<Header>);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
//! Utilities for working with test accounts.
|
||||
|
||||
use bp_header_chain::{justification::JustificationVerificationContext, AuthoritySet};
|
||||
use codec::Encode;
|
||||
use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use sp_consensus_grandpa::{AuthorityId, AuthorityList, AuthorityWeight};
|
||||
use sp_consensus_grandpa::{AuthorityId, AuthorityList, AuthorityWeight, SetId};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
@@ -78,6 +79,11 @@ pub fn voter_set() -> VoterSet<AuthorityId> {
|
||||
VoterSet::new(authority_list()).unwrap()
|
||||
}
|
||||
|
||||
/// Get a valid justification verification context for a GRANDPA round.
|
||||
pub fn verification_context(set_id: SetId) -> JustificationVerificationContext {
|
||||
AuthoritySet { authorities: authority_list(), set_id }.try_into().unwrap()
|
||||
}
|
||||
|
||||
/// Convenience function to get a list of Grandpa authorities.
|
||||
pub fn authority_list() -> AuthorityList {
|
||||
test_keyring().iter().map(|(id, w)| (AuthorityId::from(*id), *w)).collect()
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "bp-xcm-bridge-hub-router"
|
||||
description = "Primitives of the xcm-bridge-hub fee pallet."
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] }
|
||||
scale-info = { version = "2.9.0", default-features = false, features = ["bit-vec", "derive"] }
|
||||
|
||||
# Substrate Dependencies
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
"sp-runtime/std",
|
||||
"sp-core/std",
|
||||
]
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Primitives of the `xcm-bridge-hub-router` pallet.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{FixedU128, RuntimeDebug};
|
||||
|
||||
/// Minimal delivery fee factor.
|
||||
pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1);
|
||||
|
||||
/// XCM channel status provider that may report whether it is congested or not.
|
||||
///
|
||||
/// By channel we mean the physical channel that is used to deliver messages of one
|
||||
/// of the bridge queues.
|
||||
pub trait XcmChannelStatusProvider {
|
||||
/// Returns true if the channel is currently congested.
|
||||
fn is_congested() -> bool;
|
||||
}
|
||||
|
||||
impl XcmChannelStatusProvider for () {
|
||||
fn is_congested() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Current status of the bridge.
|
||||
#[derive(Clone, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)]
|
||||
pub struct BridgeState {
|
||||
/// Current delivery fee factor.
|
||||
pub delivery_fee_factor: FixedU128,
|
||||
/// Bridge congestion flag.
|
||||
pub is_congested: bool,
|
||||
}
|
||||
|
||||
impl Default for BridgeState {
|
||||
fn default() -> BridgeState {
|
||||
BridgeState { delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, is_congested: false }
|
||||
}
|
||||
}
|
||||
|
||||
/// A minimized version of `pallet-xcm-bridge-hub-router::Call` that can be used without a runtime.
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum XcmBridgeHubRouterCall {
|
||||
/// `pallet-xcm-bridge-hub-router::Call::report_bridge_status`
|
||||
#[codec(index = 0)]
|
||||
report_bridge_status { bridge_id: H256, is_congested: bool },
|
||||
}
|
||||
Reference in New Issue
Block a user