BridgeHubRococo/Wococo nits + updated subtree (#2572)

* Nits (merge before separatelly)

* Small cosmetics for Rococo/Wococo bridge local run

* Squashed 'bridges/' changes from 04b3dda6aa..5fc377ab34

5fc377ab34 Support for kusama-polkadot relaying (#2128)
01f4b7f1ba Fix clippy warnings (#2127)
696ff1c368 BHK/P alignments (#2115)
2a66aa3248 Small fixes (#2126)
7810f1a988 Cosmetics (#2124)
daf250f69c Remove some `expect()` statements (#2123)
1c5fba8274 temporarily remove balance guard (#2121)
3d0e547361 Propagate message receival confirmation errors (#2116)
1c33143f07 Propagate message verification errors (#2114)
b075b00910 Bump time from 0.3.20 to 0.3.21
51a3a51618 Bump serde from 1.0.160 to 1.0.162
da88d044a6 Bump clap from 4.2.5 to 4.2.7
cdca322cd6 Bump sysinfo from 0.28.4 to 0.29.0

git-subtree-dir: bridges
git-subtree-split: 5fc377ab34f7dfd3293099c5feec49255e827812

* Fix

* Allow to change storage constants (DeliveryReward, RequiredStakeForStakeAndSlash) + tests

* Clippy

* New SA for RO/WO

* Squashed 'bridges/' changes from 5fc377ab34..0f6091d481

0f6091d481 Bump polkadot/substrate (#2134)
9233f0a337 Bump tokio from 1.28.0 to 1.28.1
a29c1caa93 Bump serde from 1.0.162 to 1.0.163

git-subtree-dir: bridges
git-subtree-split: 0f6091d48184ebb4f75cb3089befa6b92cf37335
This commit is contained in:
Branislav Kontur
2023-05-17 00:33:30 +02:00
committed by GitHub
parent 90de06876a
commit 17b2e1b300
41 changed files with 770 additions and 619 deletions
@@ -72,12 +72,10 @@ pub type Address = MultiAddress<AccountId, ()>;
pub const BRIDGE_HUB_KUSAMA_PARACHAIN_ID: u32 = 1002;
/// Name of the With-BridgeHubKusama messages pallet instance that is deployed at bridged chains.
// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945)
pub const WITH_BRIDGE_HUB_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessages";
/// Name of the With-BridgeHubKusama bridge-relayers pallet instance that is deployed at bridged
/// chains.
// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945)
pub const WITH_BRIDGE_HUB_KUSAMA_RELAYERS_PALLET_NAME: &str = "BridgeRelayers";
decl_bridge_finality_runtime_apis!(bridge_hub_kusama);
@@ -59,16 +59,13 @@ impl Parachain for BridgeHubPolkadot {
}
/// Identifier of BridgeHubPolkadot in the Polkadot relay chain.
// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945)
pub const BRIDGE_HUB_POLKADOT_PARACHAIN_ID: u32 = 1002;
/// Name of the With-BridgeHubPolkadot messages pallet instance that is deployed at bridged chains.
// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945)
pub const WITH_BRIDGE_HUB_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotMessages";
/// Name of the With-BridgeHubPolkadot bridge-relayers pallet instance that is deployed at bridged
/// chains.
// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945)
pub const WITH_BRIDGE_HUB_POLKADOT_RELAYERS_PALLET_NAME: &str = "BridgeRelayers";
decl_bridge_finality_runtime_apis!(bridge_hub_polkadot);
@@ -62,4 +62,11 @@ pub const PARAS_PALLET_NAME: &str = "Paras";
/// Name of the With-Kusama GRANDPA pallet instance that is deployed at bridged chains.
pub const WITH_KUSAMA_GRANDPA_PALLET_NAME: &str = "BridgeKusamaGrandpa";
/// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Polkadot
/// parachains.
///
/// It includes the block number and state root, so it shall be near 40 bytes, but let's have some
/// reserve.
pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
decl_bridge_finality_runtime_apis!(kusama);
@@ -62,4 +62,11 @@ pub const PARAS_PALLET_NAME: &str = "Paras";
/// Name of the With-Polkadot GRANDPA pallet instance that is deployed at bridged chains.
pub const WITH_POLKADOT_GRANDPA_PALLET_NAME: &str = "BridgePolkadotGrandpa";
/// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Polkadot
/// parachains.
///
/// It includes the block number and state root, so it shall be near 40 bytes, but let's have some
/// reserve.
pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
decl_bridge_finality_runtime_apis!(polkadot);
@@ -49,6 +49,7 @@ pub struct GrandpaJustification<Header: HeaderT> {
pub votes_ancestries: Vec<Header>,
}
// TODO: remove and use `RuntimeDebug` (https://github.com/paritytech/parity-bridges-common/issues/2136)
impl<Header: HeaderT> sp_std::fmt::Debug for GrandpaJustification<Header> {
fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
#[cfg(feature = "std")]
@@ -73,18 +73,14 @@ impl<H: HeaderT> StoredHeaderDataBuilder<H::Number, H::Hash> for H {
pub trait HeaderChain<C: Chain> {
/// Returns state (storage) root of given finalized header.
fn finalized_header_state_root(header_hash: HashOf<C>) -> Option<HashOf<C>>;
/// Parse storage proof using finalized header.
fn parse_finalized_storage_proof<R>(
/// Get storage proof checker using finalized header.
fn storage_proof_checker(
header_hash: HashOf<C>,
storage_proof: RawStorageProof,
parse: impl FnOnce(StorageProofChecker<HasherOf<C>>) -> R,
) -> Result<R, HeaderChainError> {
) -> Result<StorageProofChecker<HasherOf<C>>, HeaderChainError> {
let state_root = Self::finalized_header_state_root(header_hash)
.ok_or(HeaderChainError::UnknownHeader)?;
let storage_proof_checker = bp_runtime::StorageProofChecker::new(state_root, storage_proof)
.map_err(HeaderChainError::StorageProof)?;
Ok(parse(storage_proof_checker))
StorageProofChecker::new(state_root, storage_proof).map_err(HeaderChainError::StorageProof)
}
}
@@ -14,6 +14,7 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
# Bridge dependencies
bp-runtime = { path = "../runtime", default-features = false }
bp-header-chain = { path = "../header-chain", default-features = false }
# Substrate Dependencies
@@ -29,6 +30,7 @@ hex-literal = "0.4"
default = ["std"]
std = [
"bp-runtime/std",
"bp-header-chain/std",
"codec/std",
"frame-support/std",
"scale-info/std",
+67 -41
View File
@@ -20,9 +20,15 @@
// RuntimeApi generated functions
#![allow(clippy::too_many_arguments)]
use bp_runtime::{BasicOperatingMode, OperatingMode, RangeInclusiveExt};
use bp_header_chain::HeaderChainError;
use bp_runtime::{
messages::MessageDispatchResult, BasicOperatingMode, OperatingMode, RangeInclusiveExt,
StorageProofError,
};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::RuntimeDebug;
use frame_support::{PalletError, RuntimeDebug};
// Weight is reexported to avoid additional frame-support dependencies in related crates.
pub use frame_support::weights::Weight;
use scale_info::TypeInfo;
use source_chain::RelayersRewards;
use sp_core::TypeId;
@@ -32,10 +38,6 @@ pub mod source_chain;
pub mod storage_keys;
pub mod target_chain;
use bp_runtime::messages::MessageDispatchResult;
// Weight is reexported to avoid additional frame-support dependencies in related crates.
pub use frame_support::weights::Weight;
/// Messages pallet operating mode.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
@@ -189,6 +191,17 @@ impl<RelayerId> InboundLaneData<RelayerId> {
.map(|entry| entry.messages.end)
.unwrap_or(self.last_confirmed_nonce)
}
/// Returns the total number of messages in the `relayers` vector,
/// saturating in case of underflow or overflow.
pub fn total_unrewarded_messages(&self) -> MessageNonce {
let relayers = &self.relayers;
match (relayers.front(), relayers.back()) {
(Some(front), Some(back)) =>
(front.messages.begin..=back.messages.end).saturating_len(),
_ => 0,
}
}
}
/// Outbound message details, returned by runtime APIs.
@@ -285,7 +298,7 @@ impl DeliveredMessages {
/// Return total count of delivered messages.
pub fn total_messages(&self) -> MessageNonce {
(self.begin..=self.end).checked_len().unwrap_or(0)
(self.begin..=self.end).saturating_len()
}
/// Note new dispatched message.
@@ -316,6 +329,13 @@ pub struct UnrewardedRelayersState {
pub last_delivered_nonce: MessageNonce,
}
impl UnrewardedRelayersState {
// Verify that the relayers state corresponds with the `InboundLaneData`.
pub fn is_valid<RelayerId>(&self, lane_data: &InboundLaneData<RelayerId>) -> bool {
self == &lane_data.into()
}
}
impl<RelayerId> From<&InboundLaneData<RelayerId>> for UnrewardedRelayersState {
fn from(lane: &InboundLaneData<RelayerId>) -> UnrewardedRelayersState {
UnrewardedRelayersState {
@@ -323,9 +343,9 @@ impl<RelayerId> From<&InboundLaneData<RelayerId>> for UnrewardedRelayersState {
messages_in_oldest_entry: lane
.relayers
.front()
.and_then(|entry| (entry.messages.begin..=entry.messages.end).checked_len())
.map(|entry| entry.messages.total_messages())
.unwrap_or(0),
total_messages: total_unrewarded_messages(&lane.relayers).unwrap_or(MessageNonce::MAX),
total_messages: lane.total_unrewarded_messages(),
last_delivered_nonce: lane.last_delivered_nonce(),
}
}
@@ -355,24 +375,6 @@ impl Default for OutboundLaneData {
}
}
/// Returns total number of messages in the `InboundLaneData::relayers` vector.
///
/// Returns `None` if there are more messages that `MessageNonce` may fit (i.e. `MessageNonce + 1`).
pub fn total_unrewarded_messages<RelayerId>(
relayers: &VecDeque<UnrewardedRelayer<RelayerId>>,
) -> Option<MessageNonce> {
match (relayers.front(), relayers.back()) {
(Some(front), Some(back)) => {
if let Some(difference) = back.messages.end.checked_sub(front.messages.begin) {
difference.checked_add(1)
} else {
Some(0)
}
},
_ => Some(0),
}
}
/// Calculate the number of messages that the relayers have delivered.
pub fn calc_relayers_rewards<AccountId>(
messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
@@ -414,26 +416,50 @@ pub enum BridgeMessagesCall<AccountId, MessagesProof, MessagesDeliveryProof> {
},
}
/// Error that happens during message verification.
#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)]
pub enum VerificationError {
/// The message proof is empty.
EmptyMessageProof,
/// Error returned by the bridged header chain.
HeaderChain(HeaderChainError),
/// Error returned while reading/decoding inbound lane data from the storage proof.
InboundLaneStorage(StorageProofError),
/// The declared message weight is incorrect.
InvalidMessageWeight,
/// Declared messages count doesn't match actual value.
MessagesCountMismatch,
/// Error returned while reading/decoding message data from the storage proof.
MessageStorage(StorageProofError),
/// The message is too large.
MessageTooLarge,
/// Error returned while reading/decoding outbound lane data from the storage proof.
OutboundLaneStorage(StorageProofError),
/// Storage proof related error.
StorageProof(StorageProofError),
/// Custom error
Other(#[codec(skip)] &'static str),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn total_unrewarded_messages_does_not_overflow() {
assert_eq!(
total_unrewarded_messages(
&vec![
UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) },
UnrewardedRelayer {
relayer: 2,
messages: DeliveredMessages::new(MessageNonce::MAX)
},
]
.into_iter()
.collect()
),
None,
);
let lane_data = InboundLaneData {
relayers: vec![
UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) },
UnrewardedRelayer {
relayer: 2,
messages: DeliveredMessages::new(MessageNonce::MAX),
},
]
.into_iter()
.collect(),
last_confirmed_nonce: 0,
};
assert_eq!(lane_data.total_unrewarded_messages(), MessageNonce::MAX);
}
#[test]
@@ -16,7 +16,7 @@
//! Primitives of messages module, that are used on the source chain.
use crate::{InboundLaneData, LaneId, MessageNonce, OutboundLaneData};
use crate::{InboundLaneData, LaneId, MessageNonce, OutboundLaneData, VerificationError};
use crate::UnrewardedRelayer;
use bp_runtime::Size;
@@ -40,9 +40,6 @@ pub type RelayersRewards<AccountId> = BTreeMap<AccountId, MessageNonce>;
/// source chain to the target chain. The `AccountId` type here means the account
/// type used by the source chain.
pub trait TargetHeaderChain<Payload, AccountId> {
/// Error type.
type Error: Debug;
/// Proof that messages have been received by target chain.
type MessagesDeliveryProof: Parameter + Size;
@@ -58,12 +55,12 @@ pub trait TargetHeaderChain<Payload, AccountId> {
/// 1MB. BTC nodes aren't accepting transactions that are larger than 1MB, so relayer
/// will be unable to craft valid transaction => this (and all subsequent) messages will
/// never be delivered.
fn verify_message(payload: &Payload) -> Result<(), Self::Error>;
fn verify_message(payload: &Payload) -> Result<(), VerificationError>;
/// Verify messages delivery proof and return lane && nonce of the latest received message.
fn verify_messages_delivery_proof(
proof: Self::MessagesDeliveryProof,
) -> Result<(LaneId, InboundLaneData<AccountId>), Self::Error>;
) -> Result<(LaneId, InboundLaneData<AccountId>), VerificationError>;
}
/// Lane message verifier.
@@ -75,9 +72,6 @@ pub trait TargetHeaderChain<Payload, AccountId> {
///
/// Any fee requirements should also be enforced here.
pub trait LaneMessageVerifier<SenderOrigin, Payload> {
/// Error type.
type Error: Debug + Into<&'static str>;
/// Verify message payload and return Ok(()) if message is valid and allowed to be sent over the
/// lane.
fn verify_message(
@@ -85,7 +79,7 @@ pub trait LaneMessageVerifier<SenderOrigin, Payload> {
lane: &LaneId,
outbound_data: &OutboundLaneData,
payload: &Payload,
) -> Result<(), Self::Error>;
) -> Result<(), VerificationError>;
}
/// Manages payments that are happening at the source chain during delivery confirmation
@@ -169,31 +163,27 @@ const ALL_OUTBOUND_MESSAGES_REJECTED: &str =
"This chain is configured to reject all outbound messages";
impl<Payload, AccountId> TargetHeaderChain<Payload, AccountId> for ForbidOutboundMessages {
type Error = &'static str;
type MessagesDeliveryProof = ();
fn verify_message(_payload: &Payload) -> Result<(), Self::Error> {
Err(ALL_OUTBOUND_MESSAGES_REJECTED)
fn verify_message(_payload: &Payload) -> Result<(), VerificationError> {
Err(VerificationError::Other(ALL_OUTBOUND_MESSAGES_REJECTED))
}
fn verify_messages_delivery_proof(
_proof: Self::MessagesDeliveryProof,
) -> Result<(LaneId, InboundLaneData<AccountId>), Self::Error> {
Err(ALL_OUTBOUND_MESSAGES_REJECTED)
) -> Result<(LaneId, InboundLaneData<AccountId>), VerificationError> {
Err(VerificationError::Other(ALL_OUTBOUND_MESSAGES_REJECTED))
}
}
impl<SenderOrigin, Payload> LaneMessageVerifier<SenderOrigin, Payload> for ForbidOutboundMessages {
type Error = &'static str;
fn verify_message(
_submitter: &SenderOrigin,
_lane: &LaneId,
_outbound_data: &OutboundLaneData,
_payload: &Payload,
) -> Result<(), Self::Error> {
Err(ALL_OUTBOUND_MESSAGES_REJECTED)
) -> Result<(), VerificationError> {
Err(VerificationError::Other(ALL_OUTBOUND_MESSAGES_REJECTED))
}
}
@@ -16,7 +16,9 @@
//! Primitives of messages module, that are used on the target chain.
use crate::{LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData};
use crate::{
LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, VerificationError,
};
use bp_runtime::{messages::MessageDispatchResult, Size};
use codec::{Decode, Encode, Error as CodecError};
@@ -58,9 +60,6 @@ pub struct DispatchMessage<DispatchPayload> {
/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane
/// that's stuck) and/or processing messages without paying fees.
pub trait SourceHeaderChain {
/// Error type.
type Error: Debug;
/// Proof that messages are sent from source chain. This may also include proof
/// of corresponding outbound lane states.
type MessagesProof: Parameter + Size;
@@ -79,7 +78,7 @@ pub trait SourceHeaderChain {
fn verify_messages_proof(
proof: Self::MessagesProof,
messages_count: u32,
) -> Result<ProvedMessages<Message>, Self::Error>;
) -> Result<ProvedMessages<Message>, VerificationError>;
}
/// Called when inbound message is received.
@@ -164,21 +163,20 @@ pub struct ForbidInboundMessages<MessagesProof, DispatchPayload>(
PhantomData<(MessagesProof, DispatchPayload)>,
);
/// Error message that is used in `ForbidOutboundMessages` implementation.
/// Error message that is used in `ForbidInboundMessages` implementation.
const ALL_INBOUND_MESSAGES_REJECTED: &str =
"This chain is configured to reject all inbound messages";
impl<MessagesProof: Parameter + Size, DispatchPayload> SourceHeaderChain
for ForbidInboundMessages<MessagesProof, DispatchPayload>
{
type Error = &'static str;
type MessagesProof = MessagesProof;
fn verify_messages_proof(
_proof: Self::MessagesProof,
_messages_count: u32,
) -> Result<ProvedMessages<Message>, Self::Error> {
Err(ALL_INBOUND_MESSAGES_REJECTED)
) -> Result<ProvedMessages<Message>, VerificationError> {
Err(VerificationError::Other(ALL_INBOUND_MESSAGES_REJECTED))
}
}
@@ -18,8 +18,8 @@
//!
//! Even though this (bridges) repository references polkadot repository, we can't
//! reference polkadot crates from pallets. That's because bridges repository is
//! included in the polkadot repository and included pallets are used by polkadot
//! chains. Having pallets that are referencing polkadot, would mean that there may
//! included in the Cumulus repository and included pallets are used by Cumulus
//! parachains. Having pallets that are referencing polkadot, would mean that there may
//! be two versions of polkadot crates included in the runtime. Which is bad.
use bp_runtime::{RawStorageProof, Size};
@@ -232,6 +232,14 @@ where
const PARACHAIN_ID: u32 = <<T as UnderlyingChainProvider>::Chain as Parachain>::PARACHAIN_ID;
}
/// Adapter for `Get<u32>` to access `PARACHAIN_ID` from `trait Parachain`
pub struct ParachainIdOf<Para>(sp_std::marker::PhantomData<Para>);
impl<Para: Parachain> frame_support::traits::Get<u32> for ParachainIdOf<Para> {
fn get() -> u32 {
Para::PARACHAIN_ID
}
}
/// Underlying chain type.
pub type UnderlyingChainOf<C> = <C as UnderlyingChainProvider>::Chain;
+15 -5
View File
@@ -31,11 +31,11 @@ use sp_std::{convert::TryFrom, fmt::Debug, ops::RangeInclusive, vec, vec::Vec};
pub use chain::{
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
HasherOf, HeaderOf, IndexOf, Parachain, SignatureOf, TransactionEraOf, UnderlyingChainOf,
UnderlyingChainProvider,
HasherOf, HeaderOf, IndexOf, Parachain, ParachainIdOf, SignatureOf, TransactionEraOf,
UnderlyingChainOf, UnderlyingChainProvider,
};
pub use frame_support::storage::storage_prefix as storage_value_final_key;
use num_traits::{CheckedAdd, CheckedSub, One};
use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero};
pub use storage_proof::{
record_all_keys as record_all_trie_keys, Error as StorageProofError,
ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker,
@@ -95,7 +95,7 @@ pub const BRIDGE_HUB_WOCOCO_CHAIN_ID: ChainId = *b"bhwo";
pub const BRIDGE_HUB_KUSAMA_CHAIN_ID: ChainId = *b"bhks";
/// BridgeHubPolkadot chain id.
pub const BRIDGE_HUB_POLKADOT_CHAIN_ID: ChainId = *b"bhwo";
pub const BRIDGE_HUB_POLKADOT_CHAIN_ID: ChainId = *b"bhpd";
/// Generic header Id.
#[derive(
@@ -527,17 +527,27 @@ impl<T> Debug for StrippableError<T> {
pub trait RangeInclusiveExt<Idx> {
/// Computes the length of the `RangeInclusive`, checking for underflow and overflow.
fn checked_len(&self) -> Option<Idx>;
/// Computes the length of the `RangeInclusive`, saturating in case of underflow or overflow.
fn saturating_len(&self) -> Idx;
}
impl<Idx> RangeInclusiveExt<Idx> for RangeInclusive<Idx>
where
Idx: CheckedSub + CheckedAdd + One,
Idx: CheckedSub + CheckedAdd + SaturatingAdd + One + Zero,
{
fn checked_len(&self) -> Option<Idx> {
self.end()
.checked_sub(self.start())
.and_then(|len| len.checked_add(&Idx::one()))
}
fn saturating_len(&self) -> Idx {
let len = match self.end().checked_sub(self.start()) {
Some(len) => len,
None => return Idx::zero(),
};
len.saturating_add(&Idx::one())
}
}
#[cfg(test)]