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:
Branislav Kontur
2023-08-17 09:15:24 +02:00
committed by GitHub
parent 840ca86741
commit 061eee1382
40 changed files with 2177 additions and 250 deletions
@@ -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};
@@ -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)?;
@@ -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 },
}