From bded8f42183874c603f877e0aa1058f3b0349592 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Wed, 1 Mar 2023 11:03:18 +0200 Subject: [PATCH] Update bridges subtree (#2254) * Squashed 'bridges/' changes from 3c15c3645..d05a98473 d05a98473 Refund messages confirmation tx (#1904) e2e8a7198 Relayers pallet: extend payment source id (#1907) cccf73b3f fix nightly clippy issues (#1915) a33a91e79 Bump tempfile from 3.3.0 to 3.4.0 1df768a2e Bump time from 0.3.17 to 0.3.20 cf17b424f Bump sysinfo from 0.28.0 to 0.28.1 0b6276b41 Bump jsonrpsee from 0.15.1 to 0.16.2 328dde02b Bump rand from 0.7.3 to 0.8.5 2f302a4b6 Bump trie-db from 0.25.1 to 0.26.0 b5d5d03ab CI add jobs to publish Docker images description to hub.docker.com (#1906) db5168f18 Do not stall on lost transaction (#1903) 2d83d6389 Fix init-bridge (#1900) git-subtree-dir: bridges git-subtree-split: d05a98473dc933cfed9e5f59023efa2ec811f03c * Rewards adjustments --- Cargo.lock | 23 +- bridges/bin/runtime-common/Cargo.toml | 1 + bridges/bin/runtime-common/src/lib.rs | 3 +- .../runtime-common/src/messages_call_ext.rs | 219 +++++++----- bridges/bin/runtime-common/src/mock.rs | 12 +- .../src/refund_relayer_extension.rs | 329 ++++++++++++++---- .../dockerhub-bridges-common-relay.README.md | 1 + .../dockerhub-millau-bridge-node.README.md | 1 + .../dockerhub-rialto-bridge-node.README.md | 1 + ...kerhub-rialto-parachain-collator.README.md | 1 + .../docs/dockerhub-substrate-relay.README.md | 1 + bridges/modules/grandpa/src/lib.rs | 2 +- bridges/modules/relayers/Cargo.toml | 1 + bridges/modules/relayers/src/benchmarking.rs | 12 +- bridges/modules/relayers/src/lib.rs | 146 +++++--- bridges/modules/relayers/src/mock.rs | 7 +- .../modules/relayers/src/payment_adapter.rs | 96 +++-- bridges/modules/relayers/src/weights.rs | 24 +- .../header-chain/src/justification.rs | 2 +- .../header-chain/tests/justification.rs | 11 +- bridges/primitives/relayers/Cargo.toml | 2 + bridges/primitives/relayers/src/lib.rs | 122 +++++-- bridges/primitives/runtime/Cargo.toml | 2 +- bridges/primitives/runtime/src/lib.rs | 6 + .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 7 +- 25 files changed, 717 insertions(+), 315 deletions(-) create mode 100644 bridges/docs/dockerhub-bridges-common-relay.README.md create mode 100644 bridges/docs/dockerhub-millau-bridge-node.README.md create mode 100644 bridges/docs/dockerhub-rialto-bridge-node.README.md create mode 100644 bridges/docs/dockerhub-rialto-parachain-collator.README.md create mode 100644 bridges/docs/dockerhub-substrate-relay.README.md diff --git a/Cargo.lock b/Cargo.lock index b344a77d6f4..279fe33f983 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -815,6 +815,8 @@ dependencies = [ "frame-support", "hex", "hex-literal", + "parity-scale-codec", + "scale-info", "sp-runtime", "sp-std", ] @@ -849,7 +851,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-trie", - "trie-db", + "trie-db 0.26.0", ] [[package]] @@ -1116,6 +1118,7 @@ dependencies = [ "bp-messages", "bp-parachains", "bp-polkadot-core", + "bp-relayers", "bp-runtime", "bp-test-utils", "frame-support", @@ -6479,6 +6482,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", + "pallet-bridge-messages", "parity-scale-codec", "scale-info", "sp-arithmetic", @@ -12568,7 +12572,7 @@ dependencies = [ "sp-std", "thiserror", "tracing", - "trie-db", + "trie-db 0.25.1", "trie-root", ] @@ -12990,7 +12994,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-trie", - "trie-db", + "trie-db 0.25.1", ] [[package]] @@ -13654,6 +13658,19 @@ dependencies = [ "smallvec", ] +[[package]] +name = "trie-db" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879380c0061b165ba1f036325b7f3478bc1a947814d9fc36d22c5d8e960b11bd" +dependencies = [ + "hash-db", + "hashbrown 0.13.2", + "log", + "rustc-hex", + "smallvec", +] + [[package]] name = "trie-root" version = "0.17.0" diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 27e305751e4..dde9e70f576 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -19,6 +19,7 @@ bp-header-chain = { path = "../../primitives/header-chain", default-features = f bp-messages = { path = "../../primitives/messages", default-features = false } bp-parachains = { path = "../../primitives/parachains", default-features = false } bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../primitives/relayers", default-features = false } bp-runtime = { path = "../../primitives/runtime", default-features = false } pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../modules/messages", default-features = false } diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index 32ea500db3e..d9c87049077 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -77,8 +77,7 @@ where /// even honest relayers may lose their funds if there are multiple relays running and /// submitting the same messages/confirmations. fn validate(call: &T::RuntimeCall) -> TransactionValidity { - call.check_obsolete_receive_messages_proof()?; - call.check_obsolete_receive_messages_delivery_proof() + call.check_obsolete_call() } } diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index 740d17129c8..588afad106d 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -22,25 +22,57 @@ use frame_support::{dispatch::CallableCallFor, traits::IsSubType, RuntimeDebug}; use pallet_bridge_messages::{Config, Pallet}; use sp_runtime::transaction_validity::TransactionValidity; -/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. +/// Generic info about a messages delivery/confirmation proof. #[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesProofInfo { +pub struct BaseMessagesProofInfo { pub lane_id: LaneId, - pub best_proof_nonce: MessageNonce, + pub best_bundled_nonce: MessageNonce, pub best_stored_nonce: MessageNonce, } -/// Helper struct that provides methods for working with the `ReceiveMessagesProof` call. -pub struct ReceiveMessagesProofHelper, I: 'static> { +impl BaseMessagesProofInfo { + fn is_obsolete(&self) -> bool { + self.best_bundled_nonce <= self.best_stored_nonce + } +} + +/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesProofInfo(pub BaseMessagesProofInfo); + +/// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); + +/// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call +/// which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub enum CallInfo { + ReceiveMessagesProof(ReceiveMessagesProofInfo), + ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), +} + +/// Helper struct that provides methods for working with a call supported by `CallInfo`. +pub struct CallHelper, I: 'static> { pub _phantom_data: sp_std::marker::PhantomData<(T, I)>, } -impl, I: 'static> ReceiveMessagesProofHelper { - /// Check if the `ReceiveMessagesProof` call delivered at least some of the messages that - /// it contained. - pub fn was_partially_successful(info: &ReceiveMessagesProofInfo) -> bool { - let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(info.lane_id); - inbound_lane_data.last_delivered_nonce() > info.best_stored_nonce +impl, I: 'static> CallHelper { + /// Check if a call delivered proof/confirmation for at least some of the messages that it + /// contained. + pub fn was_partially_successful(info: &CallInfo) -> bool { + match info { + CallInfo::ReceiveMessagesProof(info) => { + let inbound_lane_data = + pallet_bridge_messages::InboundLanes::::get(info.0.lane_id); + inbound_lane_data.last_delivered_nonce() > info.0.best_stored_nonce + }, + CallInfo::ReceiveMessagesDeliveryProof(info) => { + let outbound_lane_data = + pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id); + outbound_lane_data.latest_received_nonce > info.0.best_stored_nonce + }, + } } } @@ -51,17 +83,21 @@ pub trait MessagesCallSubType, I: 'static>: /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call. fn receive_messages_proof_info(&self) -> Option; - /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call, - /// if the call is for the provided lane. - fn receive_messages_proof_info_for(&self, lane_id: LaneId) -> Option; + /// Create a new instance of `ReceiveMessagesDeliveryProofInfo` from + /// a `ReceiveMessagesDeliveryProof` call. + fn receive_messages_delivery_proof_info(&self) -> Option; + + /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// or a `ReceiveMessagesDeliveryProof` call. + fn call_info(&self) -> Option; - /// Check that a `ReceiveMessagesProof` call is trying to deliver at least some messages that - /// are better than the ones we know of. - fn check_obsolete_receive_messages_proof(&self) -> TransactionValidity; + /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// or a `ReceiveMessagesDeliveryProof` call, if the call is for the provided lane. + fn call_info_for(&self, lane_id: LaneId) -> Option; - /// Check that a `ReceiveMessagesDeliveryProof` call is trying to deliver at least some message - /// confirmations that are better than the ones we know of. - fn check_obsolete_receive_messages_delivery_proof(&self) -> TransactionValidity; + /// Check that a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call is trying + /// to deliver/confirm at least some messages that are better than the ones we know of. + fn check_obsolete_call(&self) -> TransactionValidity; } impl< @@ -88,40 +124,17 @@ impl< { let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane); - return Some(ReceiveMessagesProofInfo { + return Some(ReceiveMessagesProofInfo(BaseMessagesProofInfo { lane_id: proof.lane, - best_proof_nonce: proof.nonces_end, + best_bundled_nonce: proof.nonces_end, best_stored_nonce: inbound_lane_data.last_delivered_nonce(), - }) + })) } None } - fn receive_messages_proof_info_for(&self, lane_id: LaneId) -> Option { - self.receive_messages_proof_info().filter(|info| info.lane_id == lane_id) - } - - fn check_obsolete_receive_messages_proof(&self) -> TransactionValidity { - if let Some(proof_info) = self.receive_messages_proof_info() { - if proof_info.best_proof_nonce <= proof_info.best_stored_nonce { - log::trace!( - target: pallet_bridge_messages::LOG_TARGET, - "Rejecting obsolete messages delivery transaction: \ - lane {:?}, bundled {:?}, best {:?}", - proof_info.lane_id, - proof_info.best_proof_nonce, - proof_info.best_stored_nonce, - ); - - return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() - } - } - - Ok(sp_runtime::transaction_validity::ValidTransaction::default()) - } - - fn check_obsolete_receive_messages_delivery_proof(&self) -> TransactionValidity { + fn receive_messages_delivery_proof_info(&self) -> Option { if let Some(pallet_bridge_messages::Call::::receive_messages_delivery_proof { ref proof, ref relayers_state, @@ -129,18 +142,62 @@ impl< }) = self.is_sub_type() { let outbound_lane_data = pallet_bridge_messages::OutboundLanes::::get(proof.lane); - if relayers_state.last_delivered_nonce <= outbound_lane_data.latest_received_nonce { + + return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { + lane_id: proof.lane, + best_bundled_nonce: relayers_state.last_delivered_nonce, + best_stored_nonce: outbound_lane_data.latest_received_nonce, + })) + } + + None + } + + fn call_info(&self) -> Option { + if let Some(info) = self.receive_messages_proof_info() { + return Some(CallInfo::ReceiveMessagesProof(info)) + } + + if let Some(info) = self.receive_messages_delivery_proof_info() { + return Some(CallInfo::ReceiveMessagesDeliveryProof(info)) + } + + None + } + + fn call_info_for(&self, lane_id: LaneId) -> Option { + self.call_info().filter(|info| { + let actual_lane_id = match info { + CallInfo::ReceiveMessagesProof(info) => info.0.lane_id, + CallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, + }; + actual_lane_id == lane_id + }) + } + + fn check_obsolete_call(&self) -> TransactionValidity { + match self.call_info() { + Some(CallInfo::ReceiveMessagesProof(proof_info)) if proof_info.0.is_obsolete() => { log::trace!( target: pallet_bridge_messages::LOG_TARGET, - "Rejecting obsolete messages confirmation transaction: \ - lane {:?}, bundled {:?}, best {:?}", - proof.lane, - relayers_state.last_delivered_nonce, - outbound_lane_data.latest_received_nonce, + "Rejecting obsolete messages delivery transaction: {:?}", + proof_info ); return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() - } + }, + Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info)) + if proof_info.0.is_obsolete() => + { + log::trace!( + target: pallet_bridge_messages::LOG_TARGET, + "Rejecting obsolete messages confirmation transaction: {:?}", + proof_info, + ); + + return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() + }, + _ => {}, } Ok(sp_runtime::transaction_validity::ValidTransaction::default()) @@ -153,8 +210,8 @@ mod tests { messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }, + messages_call_ext::MessagesCallSubType, mock::{TestRuntime, ThisChainRuntimeCall}, - BridgeRuntimeFilterCall, }; use bp_messages::UnrewardedRelayersState; @@ -169,22 +226,21 @@ mod tests { nonces_start: bp_messages::MessageNonce, nonces_end: bp_messages::MessageNonce, ) -> bool { - pallet_bridge_messages::Pallet::::validate( - &ThisChainRuntimeCall::BridgeMessages( - pallet_bridge_messages::Call::::receive_messages_proof { - relayer_id_at_bridged_chain: 42, - messages_count: (nonces_end - nonces_start + 1) as u32, - dispatch_weight: frame_support::weights::Weight::zero(), - proof: FromBridgedChainMessagesProof { - bridged_header_hash: Default::default(), - storage_proof: vec![], - lane: bp_messages::LaneId([0, 0, 0, 0]), - nonces_start, - nonces_end, - }, + ThisChainRuntimeCall::BridgeMessages( + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: 42, + messages_count: (nonces_end - nonces_start + 1) as u32, + dispatch_weight: frame_support::weights::Weight::zero(), + proof: FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: vec![], + lane: bp_messages::LaneId([0, 0, 0, 0]), + nonces_start, + nonces_end, }, - ), + }, ) + .check_obsolete_call() .is_ok() } @@ -230,21 +286,20 @@ mod tests { } fn validate_message_confirmation(last_delivered_nonce: bp_messages::MessageNonce) -> bool { - pallet_bridge_messages::Pallet::::validate( - &ThisChainRuntimeCall::BridgeMessages( - pallet_bridge_messages::Call::::receive_messages_delivery_proof { - proof: FromBridgedChainMessagesDeliveryProof { - bridged_header_hash: Default::default(), - storage_proof: Vec::new(), - lane: bp_messages::LaneId([0, 0, 0, 0]), - }, - relayers_state: UnrewardedRelayersState { - last_delivered_nonce, - ..Default::default() - }, + ThisChainRuntimeCall::BridgeMessages( + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: Vec::new(), + lane: bp_messages::LaneId([0, 0, 0, 0]), + }, + relayers_state: UnrewardedRelayersState { + last_delivered_nonce, + ..Default::default() }, - ), + }, ) + .check_obsolete_call() .is_ok() } diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index a5ae9131f03..c2cd8e9ba83 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -85,6 +85,8 @@ pub type BridgedChainHeader = /// Message lane used in tests. pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); +/// Bridged chain id used in tests. +pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; /// Maximal number of queued messages at the test lane. pub const MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE: MessageNonce = 32; /// Minimal extrinsic weight at the `BridgedChain`. @@ -118,7 +120,7 @@ crate::generate_bridge_reject_obsolete_headers_and_messages! { parameter_types! { pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; - pub const BridgedChainId: ChainId = *b"brdg"; + pub const BridgedChainId: ChainId = TEST_BRIDGED_CHAIN_ID; pub const BridgedParasPalletName: &'static str = "Paras"; pub const ExistentialDeposit: ThisChainBalance = 500; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; @@ -227,8 +229,8 @@ impl pallet_bridge_messages::Config for TestRuntime { type LaneMessageVerifier = FromThisChainMessageVerifier; type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, - frame_support::traits::ConstU64<100_000>, - frame_support::traits::ConstU64<10_000>, + (), + ConstU64<100_000>, >; type SourceHeaderChain = SourceHeaderChainAdapter; @@ -251,7 +253,7 @@ pub struct OnThisChainBridge; impl MessageBridge for OnThisChainBridge { const THIS_CHAIN_ID: ChainId = *b"this"; - const BRIDGED_CHAIN_ID: ChainId = *b"brdg"; + const BRIDGED_CHAIN_ID: ChainId = TEST_BRIDGED_CHAIN_ID; const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; type ThisChain = ThisChain; @@ -265,7 +267,7 @@ impl MessageBridge for OnThisChainBridge { pub struct OnBridgedChainBridge; impl MessageBridge for OnBridgedChainBridge { - const THIS_CHAIN_ID: ChainId = *b"brdg"; + const THIS_CHAIN_ID: ChainId = TEST_BRIDGED_CHAIN_ID; const BRIDGED_CHAIN_ID: ChainId = *b"this"; const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index df4eae6f737..0a61f4fdd02 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -20,9 +20,10 @@ //! (parachain or relay chain). use crate::messages_call_ext::{ - MessagesCallSubType, ReceiveMessagesProofHelper, ReceiveMessagesProofInfo, + CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, }; use bp_messages::LaneId; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::StaticStrProvider; use codec::{Decode, Encode}; use frame_support::{ @@ -142,23 +143,23 @@ pub struct PreDispatchData { /// Type of the call that the extension recognizes. #[derive(RuntimeDebugNoBound, PartialEq)] pub enum CallInfo { - /// Relay chain finality + parachain finality + message delivery calls. - AllFinalityAndDelivery( + /// Relay chain finality + parachain finality + message delivery/confirmation calls. + AllFinalityAndMsgs( SubmitFinalityProofInfo, SubmitParachainHeadsInfo, - ReceiveMessagesProofInfo, + MessagesCallInfo, ), - /// Parachain finality + message delivery calls. - ParachainFinalityAndDelivery(SubmitParachainHeadsInfo, ReceiveMessagesProofInfo), - /// Standalone message delivery call. - Delivery(ReceiveMessagesProofInfo), + /// Parachain finality + message delivery/confirmation calls. + ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), + /// Standalone message delivery/confirmation call. + Msgs(MessagesCallInfo), } impl CallInfo { /// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call. fn submit_finality_proof_info(&self) -> Option> { match *self { - Self::AllFinalityAndDelivery(info, _, _) => Some(info), + Self::AllFinalityAndMsgs(info, _, _) => Some(info), _ => None, } } @@ -166,18 +167,18 @@ impl CallInfo { /// Returns the pre-dispatch `SubmitParachainHeadsInfo`. fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> { match self { - Self::AllFinalityAndDelivery(_, info, _) => Some(info), - Self::ParachainFinalityAndDelivery(info, _) => Some(info), + Self::AllFinalityAndMsgs(_, info, _) => Some(info), + Self::ParachainFinalityAndMsgs(info, _) => Some(info), _ => None, } } /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. - fn receive_messages_proof_info(&self) -> &ReceiveMessagesProofInfo { + fn messages_call_info(&self) -> &MessagesCallInfo { match self { - Self::AllFinalityAndDelivery(_, _, info) => info, - Self::ParachainFinalityAndDelivery(_, info) => info, - Self::Delivery(info) => info, + Self::AllFinalityAndMsgs(_, _, info) => info, + Self::ParachainFinalityAndMsgs(_, info) => info, + Self::Msgs(info) => info, } } } @@ -268,7 +269,7 @@ where for nested_call in calls { nested_call.check_obsolete_submit_finality_proof()?; nested_call.check_obsolete_submit_parachain_heads()?; - nested_call.check_obsolete_receive_messages_proof()?; + nested_call.check_obsolete_call()?; } } @@ -289,18 +290,16 @@ where let parse_call = || { let mut calls = self.expand_call(call)?.into_iter(); match calls.len() { - 3 => Some(CallInfo::AllFinalityAndDelivery( + 3 => Some(CallInfo::AllFinalityAndMsgs( calls.next()?.submit_finality_proof_info()?, calls.next()?.submit_parachain_heads_info_for(Para::Id::get())?, - calls.next()?.receive_messages_proof_info_for(Msgs::Id::get())?, + calls.next()?.call_info_for(Msgs::Id::get())?, )), - 2 => Some(CallInfo::ParachainFinalityAndDelivery( + 2 => Some(CallInfo::ParachainFinalityAndMsgs( calls.next()?.submit_parachain_heads_info_for(Para::Id::get())?, - calls.next()?.receive_messages_proof_info_for(Msgs::Id::get())?, - )), - 1 => Some(CallInfo::Delivery( - calls.next()?.receive_messages_proof_info_for(Msgs::Id::get())?, + calls.next()?.call_info_for(Msgs::Id::get())?, )), + 1 => Some(CallInfo::Msgs(calls.next()?.call_info_for(Msgs::Id::get())?)), _ => None, } }; @@ -373,10 +372,9 @@ where // Check if the `ReceiveMessagesProof` call delivered at least some of the messages that // it contained. If this happens, we consider the transaction "helpful" and refund it. - let msgs_proof_info = call_info.receive_messages_proof_info(); - if !ReceiveMessagesProofHelper::::was_partially_successful( - msgs_proof_info, - ) { + let msgs_call_info = call_info.messages_call_info(); + if !MessagesCallHelper::::was_partially_successful(msgs_call_info) + { return Ok(()) } @@ -397,7 +395,19 @@ where let refund = Refund::compute_refund(info, &post_info, post_info_len, tip); // finally - register refund in relayers pallet - RelayersPallet::::register_relayer_reward(Msgs::Id::get(), &relayer, refund); + let rewards_account_owner = match msgs_call_info { + MessagesCallInfo::ReceiveMessagesProof(_) => RewardsAccountOwner::ThisChain, + MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => RewardsAccountOwner::BridgedChain, + }; + RelayersPallet::::register_relayer_reward( + RewardsAccountParams::new( + Msgs::Id::get(), + Runtime::BridgedChainId::get(), + rewards_account_owner, + ), + &relayer, + refund, + ); log::trace!( target: "runtime::bridge", @@ -416,8 +426,16 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{messages::target::FromBridgedChainMessagesProof, mock::*}; - use bp_messages::{InboundLaneData, MessageNonce}; + use crate::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + }, + messages_call_ext::{ + BaseMessagesProofInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, + }, + mock::*, + }; + use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayersState}; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::HeaderId; @@ -433,6 +451,8 @@ mod tests { parameter_types! { TestParachain: u32 = 1000; pub TestLaneId: LaneId = TEST_LANE_ID; + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new(TEST_LANE_ID, TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::ThisChain); + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new(TEST_LANE_ID, TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain); } bp_runtime::generate_static_str_provider!(TestExtension); @@ -456,7 +476,7 @@ mod tests { best_relay_header_number: RelayBlockNumber, parachain_head_at_relay_header_number: RelayBlockNumber, parachain_head_hash: ParaHash, - best_delivered_message: MessageNonce, + best_message: MessageNonce, ) { let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect(); let best_relay_header = HeaderId(best_relay_header_number, RelayBlockHash::default()); @@ -476,9 +496,13 @@ mod tests { pallet_bridge_parachains::ParasInfo::::insert(para_id, para_info); let lane_id = TestLaneId::get(); - let lane_data = - InboundLaneData { last_confirmed_nonce: best_delivered_message, ..Default::default() }; - pallet_bridge_messages::InboundLanes::::insert(lane_id, lane_data); + let in_lane_data = + InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); + + let out_lane_data = + OutboundLaneData { latest_received_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::OutboundLanes::::insert(lane_id, out_lane_data); } fn submit_relay_header_call(relay_header_number: RelayBlockNumber) -> RuntimeCall { @@ -522,6 +546,20 @@ mod tests { }) } + fn message_confirmation_call(best_message: MessageNonce) -> RuntimeCall { + RuntimeCall::BridgeMessages(MessagesCall::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: vec![], + lane: TestLaneId::get(), + }, + relayers_state: UnrewardedRelayersState { + last_delivered_nonce: best_message, + ..Default::default() + }, + }) + } + fn parachain_finality_and_delivery_batch_call( parachain_head_at_relay_header_number: RelayBlockNumber, best_message: MessageNonce, @@ -534,6 +572,18 @@ mod tests { }) } + fn parachain_finality_and_confirmation_batch_call( + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_confirmation_call(best_message), + ], + }) + } + fn all_finality_and_delivery_batch_call( relay_header_number: RelayBlockNumber, parachain_head_at_relay_header_number: RelayBlockNumber, @@ -548,10 +598,24 @@ mod tests { }) } + fn all_finality_and_confirmation_batch_call( + relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_relay_header_call(relay_header_number), + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_confirmation_call(best_message), + ], + }) + } + fn all_finality_pre_dispatch_data() -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::AllFinalityAndDelivery( + call_info: CallInfo::AllFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, extra_weight: Weight::zero(), @@ -562,11 +626,38 @@ mod tests { para_id: ParaId(TestParachain::get()), para_head_hash: [1u8; 32].into(), }, - ReceiveMessagesProofInfo { - lane_id: TEST_LANE_ID, - best_proof_nonce: 200, - best_stored_nonce: 100, + MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo( + BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + best_bundled_nonce: 200, + best_stored_nonce: 100, + }, + )), + ), + } + } + + fn all_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::AllFinalityAndMsgs( + SubmitFinalityProofInfo { + block_number: 200, + extra_weight: Weight::zero(), + extra_size: 0, + }, + SubmitParachainHeadsInfo { + at_relay_block_number: 200, + para_id: ParaId(TestParachain::get()), + para_head_hash: [1u8; 32].into(), }, + MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( + BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + best_bundled_nonce: 200, + best_stored_nonce: 100, + }, + )), ), } } @@ -574,17 +665,39 @@ mod tests { fn parachain_finality_pre_dispatch_data() -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::ParachainFinalityAndDelivery( + call_info: CallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { at_relay_block_number: 200, para_id: ParaId(TestParachain::get()), para_head_hash: [1u8; 32].into(), }, - ReceiveMessagesProofInfo { - lane_id: TEST_LANE_ID, - best_proof_nonce: 200, - best_stored_nonce: 100, + MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo( + BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + best_bundled_nonce: 200, + best_stored_nonce: 100, + }, + )), + ), + } + } + + fn parachain_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::ParachainFinalityAndMsgs( + SubmitParachainHeadsInfo { + at_relay_block_number: 200, + para_id: ParaId(TestParachain::get()), + para_head_hash: [1u8; 32].into(), }, + MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( + BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + best_bundled_nonce: 200, + best_stored_nonce: 100, + }, + )), ), } } @@ -592,11 +705,26 @@ mod tests { fn delivery_pre_dispatch_data() -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::Delivery(ReceiveMessagesProofInfo { - lane_id: TEST_LANE_ID, - best_proof_nonce: 200, - best_stored_nonce: 100, - }), + call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( + ReceiveMessagesProofInfo(BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + best_bundled_nonce: 200, + best_stored_nonce: 100, + }), + )), + } + } + + fn confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( + ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + best_bundled_nonce: 200, + best_stored_nonce: 100, + }), + )), } } @@ -659,16 +787,28 @@ mod tests { initialize_environment(100, 100, Default::default(), 100); assert_eq!(run_validate(message_delivery_call(200)), Ok(ValidTransaction::default()),); + assert_eq!( + run_validate(message_confirmation_call(200)), + Ok(ValidTransaction::default()), + ); assert_eq!( run_validate(parachain_finality_and_delivery_batch_call(200, 200)), Ok(ValidTransaction::default()), ); + assert_eq!( + run_validate(parachain_finality_and_confirmation_batch_call(200, 200)), + Ok(ValidTransaction::default()), + ); assert_eq!( run_validate(all_finality_and_delivery_batch_call(200, 200, 200)), Ok(ValidTransaction::default()), ); + assert_eq!( + run_validate(all_finality_and_confirmation_batch_call(200, 200, 200)), + Ok(ValidTransaction::default()), + ); }); } @@ -698,17 +838,15 @@ mod tests { run_pre_dispatch(all_finality_and_delivery_batch_call(101, 100, 200)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); - assert_eq!( - run_pre_dispatch(parachain_finality_and_delivery_batch_call(100, 200)), + run_validate(all_finality_and_delivery_batch_call(101, 100, 200)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); assert_eq!( - run_validate(all_finality_and_delivery_batch_call(101, 100, 200)), + run_pre_dispatch(parachain_finality_and_delivery_batch_call(100, 200)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); - assert_eq!( run_validate(parachain_finality_and_delivery_batch_call(100, 200)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), @@ -725,9 +863,8 @@ mod tests { run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 100)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); - assert_eq!( - run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 100)), + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 100)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); @@ -735,11 +872,28 @@ mod tests { run_validate(all_finality_and_delivery_batch_call(200, 200, 100)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); + assert_eq!( + run_validate(all_finality_and_confirmation_batch_call(200, 200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); assert_eq!( run_validate(parachain_finality_and_delivery_batch_call(200, 100)), Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), ); + assert_eq!( + run_validate(parachain_finality_and_confirmation_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); }); } @@ -752,6 +906,10 @@ mod tests { run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)), Ok(Some(all_finality_pre_dispatch_data())), ); + assert_eq!( + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)), + Ok(Some(all_finality_confirmation_pre_dispatch_data())), + ); }); } @@ -764,6 +922,10 @@ mod tests { run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)), Ok(Some(parachain_finality_pre_dispatch_data())), ); + assert_eq!( + run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)), + Ok(Some(parachain_finality_confirmation_pre_dispatch_data())), + ); }); } @@ -791,7 +953,7 @@ mod tests { } #[test] - fn pre_dispatch_parses_message_delivery_transaction() { + fn pre_dispatch_parses_message_transaction() { run_test(|| { initialize_environment(100, 100, Default::default(), 100); @@ -799,6 +961,10 @@ mod tests { run_pre_dispatch(message_delivery_call(200)), Ok(Some(delivery_pre_dispatch_data())), ); + assert_eq!( + run_pre_dispatch(message_confirmation_call(200)), + Ok(Some(confirmation_pre_dispatch_data())), + ); }); } @@ -852,6 +1018,16 @@ mod tests { Ok(()) )); assert_storage_noop!(run_post_dispatch(Some(delivery_pre_dispatch_data()), Ok(()))); + + assert_storage_noop!(run_post_dispatch( + Some(all_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(()))); }); } @@ -872,7 +1048,7 @@ mod tests { assert_eq!( RelayersPallet::::relayer_reward( relayer_account_at_this_chain(), - TestLaneId::get() + MsgProofsRewardsAccount::get() ), Some(regular_reward), ); @@ -880,7 +1056,7 @@ mod tests { // now repeat the same with size+weight refund: we expect smaller reward let mut pre_dispatch_data = all_finality_pre_dispatch_data(); match pre_dispatch_data.call_info { - CallInfo::AllFinalityAndDelivery(ref mut info, ..) => { + CallInfo::AllFinalityAndMsgs(ref mut info, ..) => { info.extra_weight.set_ref_time( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, ); @@ -891,7 +1067,7 @@ mod tests { run_post_dispatch(Some(pre_dispatch_data), Ok(())); let reward_after_two_calls = RelayersPallet::::relayer_reward( relayer_account_at_this_chain(), - TestLaneId::get(), + MsgProofsRewardsAccount::get(), ) .unwrap(); assert!( @@ -912,7 +1088,16 @@ mod tests { assert_eq!( RelayersPallet::::relayer_reward( relayer_account_at_this_chain(), - TestLaneId::get() + MsgProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + + run_post_dispatch(Some(all_finality_confirmation_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgDeliveryProofsRewardsAccount::get() ), Some(expected_reward()), ); @@ -928,7 +1113,16 @@ mod tests { assert_eq!( RelayersPallet::::relayer_reward( relayer_account_at_this_chain(), - TestLaneId::get() + MsgProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + + run_post_dispatch(Some(parachain_finality_confirmation_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgDeliveryProofsRewardsAccount::get() ), Some(expected_reward()), ); @@ -936,7 +1130,7 @@ mod tests { } #[test] - fn post_dispatch_refunds_relayer_in_message_delivery_transaction() { + fn post_dispatch_refunds_relayer_in_message_transaction() { run_test(|| { initialize_environment(200, 200, Default::default(), 200); @@ -944,7 +1138,16 @@ mod tests { assert_eq!( RelayersPallet::::relayer_reward( relayer_account_at_this_chain(), - TestLaneId::get() + MsgProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + + run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgDeliveryProofsRewardsAccount::get() ), Some(expected_reward()), ); diff --git a/bridges/docs/dockerhub-bridges-common-relay.README.md b/bridges/docs/dockerhub-bridges-common-relay.README.md new file mode 100644 index 00000000000..d199227c9c6 --- /dev/null +++ b/bridges/docs/dockerhub-bridges-common-relay.README.md @@ -0,0 +1 @@ +# bridges-common-relay diff --git a/bridges/docs/dockerhub-millau-bridge-node.README.md b/bridges/docs/dockerhub-millau-bridge-node.README.md new file mode 100644 index 00000000000..481ad46b7c6 --- /dev/null +++ b/bridges/docs/dockerhub-millau-bridge-node.README.md @@ -0,0 +1 @@ +# millau-bridge-node diff --git a/bridges/docs/dockerhub-rialto-bridge-node.README.md b/bridges/docs/dockerhub-rialto-bridge-node.README.md new file mode 100644 index 00000000000..2393e6f8129 --- /dev/null +++ b/bridges/docs/dockerhub-rialto-bridge-node.README.md @@ -0,0 +1 @@ +# rialto-bridge-node diff --git a/bridges/docs/dockerhub-rialto-parachain-collator.README.md b/bridges/docs/dockerhub-rialto-parachain-collator.README.md new file mode 100644 index 00000000000..a09f6b1561b --- /dev/null +++ b/bridges/docs/dockerhub-rialto-parachain-collator.README.md @@ -0,0 +1 @@ +# rialto-parachain-collator diff --git a/bridges/docs/dockerhub-substrate-relay.README.md b/bridges/docs/dockerhub-substrate-relay.README.md new file mode 100644 index 00000000000..1a9f22c425c --- /dev/null +++ b/bridges/docs/dockerhub-substrate-relay.README.md @@ -0,0 +1 @@ +# substrate-relay diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index e94d91a5c16..4304e82eeb1 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -181,7 +181,7 @@ pub mod pallet { let is_authorities_change_enacted = try_enact_authority_change::(&finality_target, set_id)?; let may_refund_call_fee = is_authorities_change_enacted && - submit_finality_proof_info_from_args::(&*finality_target, &justification) + submit_finality_proof_info_from_args::(&finality_target, &justification) .fits_limits(); >::mutate(|count| *count += 1); insert_header::(*finality_target, hash); diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 954818a3b50..200fbbca309 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -16,6 +16,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" bp-messages = { path = "../../primitives/messages", default-features = false } bp-relayers = { path = "../../primitives/relayers", default-features = false } bp-runtime = { path = "../../primitives/runtime", default-features = false } +pallet-bridge-messages = { path = "../messages", default-features = false } # Substrate Dependencies diff --git a/bridges/modules/relayers/src/benchmarking.rs b/bridges/modules/relayers/src/benchmarking.rs index 7195b316bb6..7dcf77eb958 100644 --- a/bridges/modules/relayers/src/benchmarking.rs +++ b/bridges/modules/relayers/src/benchmarking.rs @@ -20,6 +20,8 @@ use crate::*; +use bp_messages::LaneId; +use bp_relayers::RewardsAccountOwner; use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_system::RawOrigin; @@ -32,19 +34,21 @@ pub struct Pallet(crate::Pallet); /// Trait that must be implemented by runtime. pub trait Config: crate::Config { /// Prepare environment for paying given reward for serving given lane. - fn prepare_environment(lane: LaneId, reward: Self::Reward); + fn prepare_environment(account_params: RewardsAccountParams, reward: Self::Reward); } benchmarks! { // Benchmark `claim_rewards` call. claim_rewards { let lane = LaneId([0, 0, 0, 0]); + let account_params = + RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); let relayer: T::AccountId = whitelisted_caller(); let reward = T::Reward::from(REWARD_AMOUNT); - T::prepare_environment(lane, reward); - RelayerRewards::::insert(&relayer, lane, reward); - }: _(RawOrigin::Signed(relayer), lane) + T::prepare_environment(account_params, reward); + RelayerRewards::::insert(&relayer, account_params, reward); + }: _(RawOrigin::Signed(relayer), account_params) verify { // we can't check anything here, because `PaymentProcedure` is responsible for // payment logic, so we assume that if call has succeeded, the procedure has diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index 2ceebd0336e..3d32e3c7a14 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -20,8 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] -use bp_messages::LaneId; -use bp_relayers::{PaymentProcedure, RelayerRewardsKeyProvider}; +use bp_relayers::{PaymentProcedure, RelayerRewardsKeyProvider, RewardsAccountParams}; use bp_runtime::StorageDoubleMapKeyProvider; use frame_support::sp_runtime::Saturating; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; @@ -72,28 +71,32 @@ pub mod pallet { /// Claim accumulated rewards. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::claim_rewards())] - pub fn claim_rewards(origin: OriginFor, lane_id: LaneId) -> DispatchResult { + pub fn claim_rewards( + origin: OriginFor, + rewards_account_params: RewardsAccountParams, + ) -> DispatchResult { let relayer = ensure_signed(origin)?; RelayerRewards::::try_mutate_exists( &relayer, - lane_id, + rewards_account_params, |maybe_reward| -> DispatchResult { let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; - T::PaymentProcedure::pay_reward(&relayer, lane_id, reward).map_err(|e| { - log::trace!( - target: LOG_TARGET, - "Failed to pay {:?} rewards to {:?}: {:?}", - lane_id, - relayer, - e, - ); - Error::::FailedToPayReward - })?; + T::PaymentProcedure::pay_reward(&relayer, rewards_account_params, reward) + .map_err(|e| { + log::trace!( + target: LOG_TARGET, + "Failed to pay {:?} rewards to {:?}: {:?}", + rewards_account_params, + relayer, + e, + ); + Error::::FailedToPayReward + })?; Self::deposit_event(Event::::RewardPaid { relayer: relayer.clone(), - lane_id, + rewards_account_params, reward, }); Ok(()) @@ -104,23 +107,31 @@ pub mod pallet { impl Pallet { /// Register reward for given relayer. - pub fn register_relayer_reward(lane_id: LaneId, relayer: &T::AccountId, reward: T::Reward) { + pub fn register_relayer_reward( + rewards_account_params: RewardsAccountParams, + relayer: &T::AccountId, + reward: T::Reward, + ) { if reward.is_zero() { return } - RelayerRewards::::mutate(relayer, lane_id, |old_reward: &mut Option| { - let new_reward = old_reward.unwrap_or_else(Zero::zero).saturating_add(reward); - *old_reward = Some(new_reward); - - log::trace!( - target: crate::LOG_TARGET, - "Relayer {:?} can now claim reward for serving lane {:?}: {:?}", - relayer, - lane_id, - new_reward, - ); - }); + RelayerRewards::::mutate( + relayer, + rewards_account_params, + |old_reward: &mut Option| { + let new_reward = old_reward.unwrap_or_else(Zero::zero).saturating_add(reward); + *old_reward = Some(new_reward); + + log::trace!( + target: crate::LOG_TARGET, + "Relayer {:?} can now claim reward for serving payer {:?}: {:?}", + relayer, + rewards_account_params, + new_reward, + ); + }, + ); } } @@ -131,8 +142,8 @@ pub mod pallet { RewardPaid { /// Relayer account that has been rewarded. relayer: T::AccountId, - /// Relayer has received reward for serving this lane. - lane_id: LaneId, + /// Relayer has received reward from this account. + rewards_account_params: RewardsAccountParams, /// Reward amount. reward: T::Reward, }, @@ -166,6 +177,8 @@ mod tests { use mock::{RuntimeEvent as TestEvent, *}; use crate::Event::RewardPaid; + use bp_messages::LaneId; + use bp_relayers::RewardsAccountOwner; use frame_support::{ assert_noop, assert_ok, traits::fungible::{Inspect, Mutate}, @@ -182,7 +195,10 @@ mod tests { fn root_cant_claim_anything() { run_test(|| { assert_noop!( - Pallet::::claim_rewards(RuntimeOrigin::root(), TEST_LANE_ID), + Pallet::::claim_rewards( + RuntimeOrigin::root(), + TEST_REWARDS_ACCOUNT_PARAMS + ), DispatchError::BadOrigin, ); }); @@ -194,7 +210,7 @@ mod tests { assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::signed(REGULAR_RELAYER), - TEST_LANE_ID + TEST_REWARDS_ACCOUNT_PARAMS ), Error::::NoRewardForRelayer, ); @@ -204,11 +220,15 @@ mod tests { #[test] fn relayer_cant_claim_if_payment_procedure_fails() { run_test(|| { - RelayerRewards::::insert(FAILING_RELAYER, TEST_LANE_ID, 100); + RelayerRewards::::insert( + FAILING_RELAYER, + TEST_REWARDS_ACCOUNT_PARAMS, + 100, + ); assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::signed(FAILING_RELAYER), - TEST_LANE_ID + TEST_REWARDS_ACCOUNT_PARAMS ), Error::::FailedToPayReward, ); @@ -220,12 +240,19 @@ mod tests { run_test(|| { get_ready_for_events(); - RelayerRewards::::insert(REGULAR_RELAYER, TEST_LANE_ID, 100); + RelayerRewards::::insert( + REGULAR_RELAYER, + TEST_REWARDS_ACCOUNT_PARAMS, + 100, + ); assert_ok!(Pallet::::claim_rewards( RuntimeOrigin::signed(REGULAR_RELAYER), - TEST_LANE_ID + TEST_REWARDS_ACCOUNT_PARAMS )); - assert_eq!(RelayerRewards::::get(REGULAR_RELAYER, TEST_LANE_ID), None); + assert_eq!( + RelayerRewards::::get(REGULAR_RELAYER, TEST_REWARDS_ACCOUNT_PARAMS), + None + ); //Check if the `RewardPaid` event was emitted. assert_eq!( @@ -234,7 +261,7 @@ mod tests { phase: Phase::Initialization, event: TestEvent::Relayers(RewardPaid { relayer: REGULAR_RELAYER, - lane_id: TEST_LANE_ID, + rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, reward: 100 }), topics: vec![], @@ -244,30 +271,39 @@ mod tests { } #[test] - fn pay_lane_reward_from_account_actually_pays_reward() { + fn pay_reward_from_account_actually_pays_reward() { type Balances = pallet_balances::Pallet; - type PayLaneRewardFromAccount = bp_relayers::PayLaneRewardFromAccount; + type PayLaneRewardFromAccount = bp_relayers::PayRewardFromAccount; run_test(|| { - let lane0_rewards_account = - PayLaneRewardFromAccount::lane_rewards_account(LaneId([0, 0, 0, 0])); - let lane1_rewards_account = - PayLaneRewardFromAccount::lane_rewards_account(LaneId([0, 0, 0, 1])); - - Balances::mint_into(&lane0_rewards_account, 100).unwrap(); - Balances::mint_into(&lane1_rewards_account, 100).unwrap(); - assert_eq!(Balances::balance(&lane0_rewards_account), 100); - assert_eq!(Balances::balance(&lane1_rewards_account), 100); + let in_lane_0 = RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::ThisChain, + ); + let out_lane_1 = RewardsAccountParams::new( + LaneId([0, 0, 0, 1]), + *b"test", + RewardsAccountOwner::BridgedChain, + ); + + let in_lane0_rewards_account = PayLaneRewardFromAccount::rewards_account(in_lane_0); + let out_lane1_rewards_account = PayLaneRewardFromAccount::rewards_account(out_lane_1); + + Balances::mint_into(&in_lane0_rewards_account, 100).unwrap(); + Balances::mint_into(&out_lane1_rewards_account, 100).unwrap(); + assert_eq!(Balances::balance(&in_lane0_rewards_account), 100); + assert_eq!(Balances::balance(&out_lane1_rewards_account), 100); assert_eq!(Balances::balance(&1), 0); - PayLaneRewardFromAccount::pay_reward(&1, LaneId([0, 0, 0, 0]), 100).unwrap(); - assert_eq!(Balances::balance(&lane0_rewards_account), 0); - assert_eq!(Balances::balance(&lane1_rewards_account), 100); + PayLaneRewardFromAccount::pay_reward(&1, in_lane_0, 100).unwrap(); + assert_eq!(Balances::balance(&in_lane0_rewards_account), 0); + assert_eq!(Balances::balance(&out_lane1_rewards_account), 100); assert_eq!(Balances::balance(&1), 100); - PayLaneRewardFromAccount::pay_reward(&1, LaneId([0, 0, 0, 1]), 100).unwrap(); - assert_eq!(Balances::balance(&lane0_rewards_account), 0); - assert_eq!(Balances::balance(&lane1_rewards_account), 0); + PayLaneRewardFromAccount::pay_reward(&1, out_lane_1, 100).unwrap(); + assert_eq!(Balances::balance(&in_lane0_rewards_account), 0); + assert_eq!(Balances::balance(&out_lane1_rewards_account), 0); assert_eq!(Balances::balance(&1), 200); }); } diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 89b3ead0411..c40c86f1db5 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -19,7 +19,7 @@ use crate as pallet_bridge_relayers; use bp_messages::LaneId; -use bp_relayers::PaymentProcedure; +use bp_relayers::{PaymentProcedure, RewardsAccountOwner, RewardsAccountParams}; use frame_support::{parameter_types, weights::RuntimeDbWeight}; use sp_core::H256; use sp_runtime::{ @@ -96,7 +96,8 @@ impl pallet_bridge_relayers::Config for TestRuntime { } /// Message lane that we're using in tests. -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); +pub const TEST_REWARDS_ACCOUNT_PARAMS: RewardsAccountParams = + RewardsAccountParams::new(LaneId([0, 0, 0, 0]), *b"test", RewardsAccountOwner::ThisChain); /// Regular relayer that may receive rewards. pub const REGULAR_RELAYER: AccountId = 1; @@ -112,7 +113,7 @@ impl PaymentProcedure for TestPaymentProcedure { fn pay_reward( relayer: &AccountId, - _lane_id: LaneId, + _lane_id: RewardsAccountParams, _reward: Balance, ) -> Result<(), Self::Error> { match *relayer { diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index 946b31cf7af..2752044958b 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -18,28 +18,32 @@ use crate::{Config, Pallet}; -use bp_messages::source_chain::{DeliveryConfirmationPayments, RelayersRewards}; +use bp_messages::{ + source_chain::{DeliveryConfirmationPayments, RelayersRewards}, + LaneId, +}; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; -use sp_arithmetic::traits::{Saturating, UniqueSaturatedFrom, Zero}; +use sp_arithmetic::traits::{Saturating, Zero}; use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; /// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism /// for the messages pallet. -pub struct DeliveryConfirmationPaymentsAdapter( - PhantomData<(T, DeliveryReward, ConfirmationReward)>, +pub struct DeliveryConfirmationPaymentsAdapter( + PhantomData<(T, MI, DeliveryReward)>, ); -impl DeliveryConfirmationPayments - for DeliveryConfirmationPaymentsAdapter +impl DeliveryConfirmationPayments + for DeliveryConfirmationPaymentsAdapter where - T: Config, + T: Config + pallet_bridge_messages::Config, + MI: 'static, DeliveryReward: Get, - ConfirmationReward: Get, { type Error = &'static str; fn pay_reward( - lane_id: bp_messages::LaneId, + lane_id: LaneId, messages_relayers: VecDeque>, confirmation_relayer: &T::AccountId, received_range: &RangeInclusive, @@ -50,9 +54,12 @@ where register_relayers_rewards::( confirmation_relayer, relayers_rewards, - lane_id, + RewardsAccountParams::new( + lane_id, + T::BridgedChainId::get(), + RewardsAccountOwner::BridgedChain, + ), DeliveryReward::get(), - ConfirmationReward::get(), ); } } @@ -61,34 +68,19 @@ where fn register_relayers_rewards( confirmation_relayer: &T::AccountId, relayers_rewards: RelayersRewards, - lane_id: bp_messages::LaneId, + lane_id: RewardsAccountParams, delivery_fee: T::Reward, - confirmation_fee: T::Reward, ) { // reward every relayer except `confirmation_relayer` let mut confirmation_relayer_reward = T::Reward::zero(); for (relayer, messages) in relayers_rewards { // sane runtime configurations guarantee that the number of messages will be below // `u32::MAX` - let mut relayer_reward = - T::Reward::unique_saturated_from(messages).saturating_mul(delivery_fee); + let relayer_reward = T::Reward::saturated_from(messages).saturating_mul(delivery_fee); if relayer != *confirmation_relayer { - // If delivery confirmation is submitted by other relayer, let's deduct confirmation fee - // from relayer reward. - // - // If confirmation fee has been increased (or if it was the only component of message - // fee), then messages relayer may receive zero reward. - let mut confirmation_reward = - T::Reward::saturated_from(messages).saturating_mul(confirmation_fee); - confirmation_reward = sp_std::cmp::min(confirmation_reward, relayer_reward); - relayer_reward = relayer_reward.saturating_sub(confirmation_reward); - confirmation_relayer_reward = - confirmation_relayer_reward.saturating_add(confirmation_reward); Pallet::::register_relayer_reward(lane_id, &relayer, relayer_reward); } else { - // If delivery confirmation is submitted by this relayer, let's add confirmation fee - // from other relayers to this relayer reward. confirmation_relayer_reward = confirmation_relayer_reward.saturating_add(relayer_reward); } @@ -121,47 +113,43 @@ mod tests { register_relayers_rewards::( &RELAYER_2, relayers_rewards(), - TEST_LANE_ID, + TEST_REWARDS_ACCOUNT_PARAMS, 50, - 10, ); - assert_eq!(RelayerRewards::::get(RELAYER_1, TEST_LANE_ID), Some(80)); - assert_eq!(RelayerRewards::::get(RELAYER_2, TEST_LANE_ID), Some(170)); - }); - } - - #[test] - fn confirmation_relayer_is_rewarded_if_it_has_not_delivered_any_delivered_messages() { - run_test(|| { - register_relayers_rewards::( - &RELAYER_3, - relayers_rewards(), - TEST_LANE_ID, - 50, - 10, + assert_eq!( + RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + Some(100) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + Some(150) ); - - assert_eq!(RelayerRewards::::get(RELAYER_1, TEST_LANE_ID), Some(80)); - assert_eq!(RelayerRewards::::get(RELAYER_2, TEST_LANE_ID), Some(120)); - assert_eq!(RelayerRewards::::get(RELAYER_3, TEST_LANE_ID), Some(50)); }); } #[test] - fn only_confirmation_relayer_is_rewarded_if_confirmation_fee_has_significantly_increased() { + fn confirmation_relayer_is_not_rewarded_if_it_has_not_delivered_any_messages() { run_test(|| { register_relayers_rewards::( &RELAYER_3, relayers_rewards(), - TEST_LANE_ID, + TEST_REWARDS_ACCOUNT_PARAMS, 50, - 1000, ); - assert_eq!(RelayerRewards::::get(RELAYER_1, TEST_LANE_ID), None); - assert_eq!(RelayerRewards::::get(RELAYER_2, TEST_LANE_ID), None); - assert_eq!(RelayerRewards::::get(RELAYER_3, TEST_LANE_ID), Some(250)); + assert_eq!( + RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + Some(100) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + Some(150) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_3, TEST_REWARDS_ACCOUNT_PARAMS), + None + ); }); } } diff --git a/bridges/modules/relayers/src/weights.rs b/bridges/modules/relayers/src/weights.rs index fdaeee4f22a..572935f6302 100644 --- a/bridges/modules/relayers/src/weights.rs +++ b/bridges/modules/relayers/src/weights.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for pallet_bridge_relayers //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! HOSTNAME: `serban-ROG-Zephyrus`, CPU: `12th Gen Intel(R) Core(TM) i7-12700H` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -60,7 +60,7 @@ pub struct BridgeWeight(PhantomData); impl WeightInfo for BridgeWeight { /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(60), added: 2535, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, /// mode: MaxEncodedLen) /// /// Storage: System Account (r:1 w:1) @@ -69,10 +69,10 @@ impl WeightInfo for BridgeWeight { /// MaxEncodedLen) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `534` - // Estimated: `5106` - // Minimum execution time: 48_239 nanoseconds. - Weight::from_parts(50_579_000, 5106) + // Measured: `275` + // Estimated: `5111` + // Minimum execution time: 43_031 nanoseconds. + Weight::from_parts(44_527_000, 5111) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -82,7 +82,7 @@ impl WeightInfo for BridgeWeight { impl WeightInfo for () { /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) /// - /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(60), added: 2535, + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, /// mode: MaxEncodedLen) /// /// Storage: System Account (r:1 w:1) @@ -91,10 +91,10 @@ impl WeightInfo for () { /// MaxEncodedLen) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `534` - // Estimated: `5106` - // Minimum execution time: 48_239 nanoseconds. - Weight::from_parts(50_579_000, 5106) + // Measured: `275` + // Estimated: `5111` + // Minimum execution time: 43_031 nanoseconds. + Weight::from_parts(44_527_000, 5111) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/bridges/primitives/header-chain/src/justification.rs b/bridges/primitives/header-chain/src/justification.rs index 1e34f365621..88dac0acf9f 100644 --- a/bridges/primitives/header-chain/src/justification.rs +++ b/bridges/primitives/header-chain/src/justification.rs @@ -135,7 +135,7 @@ pub fn decode_justification_target( } /// Verify and optimize given justification by removing unknown and duplicate votes. -pub fn optimize_justification( +pub fn verify_and_optimize_justification( finalized_target: (Header::Hash, Header::Number), authorities_set_id: SetId, authorities_set: &VoterSet, diff --git a/bridges/primitives/header-chain/tests/justification.rs b/bridges/primitives/header-chain/tests/justification.rs index f01f4ea2f10..52fa33ae974 100644 --- a/bridges/primitives/header-chain/tests/justification.rs +++ b/bridges/primitives/header-chain/tests/justification.rs @@ -17,7 +17,8 @@ //! Tests for Grandpa Justification code. use bp_header_chain::justification::{ - optimize_justification, required_justification_precommits, verify_justification, Error, + required_justification_precommits, verify_and_optimize_justification, verify_justification, + Error, }; use bp_test_utils::*; @@ -199,7 +200,7 @@ fn optimizer_does_noting_with_minimal_justification() { let justification = make_default_justification::(&test_header(1)); let num_precommits_before = justification.commit.precommits.len(); - let justification = optimize_justification::( + let justification = verify_and_optimize_justification::( header_id::(1), TEST_GRANDPA_SET_ID, &voter_set(), @@ -222,7 +223,7 @@ fn unknown_authority_votes_are_removed_by_optimizer() { )); let num_precommits_before = justification.commit.precommits.len(); - let justification = optimize_justification::( + let justification = verify_and_optimize_justification::( header_id::(1), TEST_GRANDPA_SET_ID, &voter_set(), @@ -243,7 +244,7 @@ fn duplicate_authority_votes_are_removed_by_optimizer() { .push(justification.commit.precommits.first().cloned().unwrap()); let num_precommits_before = justification.commit.precommits.len(); - let justification = optimize_justification::( + let justification = verify_and_optimize_justification::( header_id::(1), TEST_GRANDPA_SET_ID, &voter_set(), @@ -266,7 +267,7 @@ fn redundant_authority_votes_are_removed_by_optimizer() { )); let num_precommits_before = justification.commit.precommits.len(); - let justification = optimize_justification::( + let justification = verify_and_optimize_justification::( header_id::(1), TEST_GRANDPA_SET_ID, &voter_set(), diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 7479811a57d..ee91361a4e2 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -7,6 +7,8 @@ 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.1.1", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies diff --git a/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs index 70a91ee941a..fb350958415 100644 --- a/bridges/primitives/relayers/src/lib.rs +++ b/bridges/primitives/relayers/src/lib.rs @@ -20,46 +20,95 @@ #![cfg_attr(not(feature = "std"), no_std)] use bp_messages::LaneId; -use bp_runtime::StorageDoubleMapKeyProvider; +use bp_runtime::{ChainId, StorageDoubleMapKeyProvider}; use frame_support::{Blake2_128Concat, Identity}; +use scale_info::TypeInfo; use sp_runtime::{ - codec::{Codec, Decode, Encode, EncodeLike}, + codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}, traits::AccountIdConversion, + TypeId, }; use sp_std::{fmt::Debug, marker::PhantomData}; +/// The owner of the sovereign account that should pay the rewards. +/// +/// Each of the 2 final points connected by a bridge owns a sovereign account at each end of the +/// bridge. So here, at this end of the bridge there can be 2 sovereign accounts that pay rewards. +#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub enum RewardsAccountOwner { + /// The sovereign account of the final chain on this end of the bridge. + ThisChain, + /// The sovereign account of the final chain on the other end of the bridge. + BridgedChain, +} + +/// Structure used to identify the account that pays a reward to the relayer. +/// +/// A bridge connects 2 bridge ends. Each one is located on a separate relay chain. The bridge ends +/// can be the final destinations of the bridge, or they can be intermediary points +/// (e.g. a bridge hub) used to forward messages between pairs of parachains on the bridged relay +/// chains. A pair of such parachains is connected using a bridge lane. Each of the 2 final +/// destinations of a bridge lane must have a sovereign account at each end of the bridge and each +/// of the sovereign accounts will pay rewards for different operations. So we need multiple +/// parameters to identify the account that pays a reward to the relayer. +#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub struct RewardsAccountParams { + lane_id: LaneId, + bridged_chain_id: ChainId, + owner: RewardsAccountOwner, +} + +impl RewardsAccountParams { + /// Create a new instance of `RewardsAccountParams`. + pub const fn new( + lane_id: LaneId, + bridged_chain_id: ChainId, + owner: RewardsAccountOwner, + ) -> Self { + Self { lane_id, bridged_chain_id, owner } + } +} + +impl TypeId for RewardsAccountParams { + const TYPE_ID: [u8; 4] = *b"brap"; +} + /// Reward payment procedure. pub trait PaymentProcedure { /// Error that may be returned by the procedure. type Error: Debug; - /// Pay reward to the relayer for serving given message lane. - fn pay_reward(relayer: &Relayer, lane_id: LaneId, reward: Reward) -> Result<(), Self::Error>; + /// Pay reward to the relayer from the account with provided params. + fn pay_reward( + relayer: &Relayer, + rewards_account_params: RewardsAccountParams, + reward: Reward, + ) -> Result<(), Self::Error>; } impl PaymentProcedure for () { type Error = &'static str; - fn pay_reward(_: &Relayer, _: LaneId, _: Reward) -> Result<(), Self::Error> { + fn pay_reward(_: &Relayer, _: RewardsAccountParams, _: Reward) -> Result<(), Self::Error> { Ok(()) } } /// Reward payment procedure that does `balances::transfer` call from the account, derived from -/// given lane. -pub struct PayLaneRewardFromAccount(PhantomData<(T, Relayer)>); +/// given params. +pub struct PayRewardFromAccount(PhantomData<(T, Relayer)>); -impl PayLaneRewardFromAccount +impl PayRewardFromAccount where Relayer: Decode + Encode, { - /// Return account that pay rewards for serving given lane. - pub fn lane_rewards_account(lane_id: LaneId) -> Relayer { - lane_id.into_sub_account_truncating(b"bridge-lane") + /// Return account that pays rewards based on the provided parameters. + pub fn rewards_account(params: RewardsAccountParams) -> Relayer { + params.into_sub_account_truncating(b"rewards-account") } } -impl PaymentProcedure for PayLaneRewardFromAccount +impl PaymentProcedure for PayRewardFromAccount where T: frame_support::traits::fungible::Transfer, Relayer: Decode + Encode, @@ -68,10 +117,11 @@ where fn pay_reward( relayer: &Relayer, - lane_id: LaneId, + rewards_account_params: RewardsAccountParams, reward: T::Balance, ) -> Result<(), Self::Error> { - T::transfer(&Self::lane_rewards_account(lane_id), relayer, reward, false).map(drop) + T::transfer(&Self::rewards_account(rewards_account_params), relayer, reward, false) + .map(drop) } } @@ -89,26 +139,58 @@ where type Hasher1 = Blake2_128Concat; type Key1 = AccountId; type Hasher2 = Identity; - type Key2 = LaneId; + type Key2 = RewardsAccountParams; type Value = Reward; } #[cfg(test)] mod tests { use super::*; + use bp_messages::LaneId; use sp_runtime::testing::H256; #[test] - fn lanes_are_using_different_accounts() { + fn different_lanes_are_using_different_accounts() { + assert_eq!( + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::ThisChain + )), + hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + .into(), + ); + + assert_eq!( + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 1]), + *b"test", + RewardsAccountOwner::ThisChain + )), + hex_literal::hex!("62726170000000017465737400726577617264732d6163636f756e7400000000") + .into(), + ); + } + + #[test] + fn different_directions_are_using_different_accounts() { assert_eq!( - PayLaneRewardFromAccount::<(), H256>::lane_rewards_account(LaneId([0, 0, 0, 0])), - hex_literal::hex!("626c616e000000006272696467652d6c616e6500000000000000000000000000") + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::ThisChain + )), + hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") .into(), ); assert_eq!( - PayLaneRewardFromAccount::<(), H256>::lane_rewards_account(LaneId([0, 0, 0, 1])), - hex_literal::hex!("626c616e000000016272696467652d6c616e6500000000000000000000000000") + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::BridgedChain + )), + hex_literal::hex!("62726170000000007465737401726577617264732d6163636f756e7400000000") .into(), ); } diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index c8829a508d9..3cd2fdd35ca 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -24,7 +24,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -trie-db = { version = "0.25.1", default-features = false } +trie-db = { version = "0.26.0", default-features = false } [dev-dependencies] hex-literal = "0.3" diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 0121b4ab84e..2d29b5aff0a 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -74,6 +74,12 @@ pub const POLKADOT_CHAIN_ID: ChainId = *b"pdot"; /// Bridge-with-Kusama instance id. pub const KUSAMA_CHAIN_ID: ChainId = *b"ksma"; +/// Bridge-with-Westend instance id. +pub const WESTEND_CHAIN_ID: ChainId = *b"wend"; + +/// Bridge-with-Westend instance id. +pub const WESTMINT_CHAIN_ID: ChainId = *b"wmnt"; + /// Bridge-with-Rococo instance id. pub const ROCOCO_CHAIN_ID: ChainId = *b"roco"; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index c768477c8bb..f45d27b2ce9 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -426,7 +426,6 @@ parameter_types! { // TODO:check-parameter - setup initial values https://github.com/paritytech/parity-bridges-common/issues/1677 pub storage DeliveryRewardInBalance: u64 = 1_000_000; - pub storage ConfirmationRewardInBalance: u64 = 100_000; } /// Add parachain bridge pallet to track Wococo bridge hub parachain @@ -479,8 +478,8 @@ impl pallet_bridge_messages::Config for Run type LaneMessageVerifier = bridge_hub_rococo_config::ToBridgeHubWococoMessageVerifier; type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, + WithBridgeHubWococoMessagesInstance, DeliveryRewardInBalance, - ConfirmationRewardInBalance, >; type SourceHeaderChain = SourceHeaderChainAdapter; @@ -515,8 +514,8 @@ impl pallet_bridge_messages::Config for Run type LaneMessageVerifier = bridge_hub_wococo_config::ToBridgeHubRococoMessageVerifier; type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, + WithBridgeHubRococoMessagesInstance, DeliveryRewardInBalance, - ConfirmationRewardInBalance, >; type SourceHeaderChain = SourceHeaderChainAdapter; @@ -532,7 +531,7 @@ impl pallet_bridge_relayers::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reward = Balance; type PaymentProcedure = - bp_relayers::PayLaneRewardFromAccount, AccountId>; + bp_relayers::PayRewardFromAccount, AccountId>; type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; }