diff --git a/Cargo.lock b/Cargo.lock index 91eec15396d43..40758ed9f715a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,6 +1779,7 @@ dependencies = [ "serde", "sp-core", "sp-io", + "sp-runtime", "sp-std 14.0.0", ] diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index eca558b6e2b4c..cc76404c5ace7 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -131,7 +131,7 @@ fn receive_messages, I: 'static>(nonce: MessageNonce) { state: LaneState::Opened, relayers: vec![UnrewardedRelayer { relayer: T::bridged_relayer_id(), - messages: DeliveredMessages::new(nonce), + messages: DeliveredMessages::new(nonce, 1), }] .into(), last_confirmed_nonce: 0, @@ -368,7 +368,7 @@ mod benchmarks { state: LaneState::Opened, relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), - messages: DeliveredMessages::new(1), + messages: DeliveredMessages::new(1, 1), }] .into_iter() .collect(), @@ -412,7 +412,7 @@ mod benchmarks { total_messages: 2, last_delivered_nonce: 2, }; - let mut delivered_messages = DeliveredMessages::new(1); + let mut delivered_messages = DeliveredMessages::new(1, 1); delivered_messages.note_dispatched_message(); let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), @@ -472,11 +472,11 @@ mod benchmarks { relayers: vec![ UnrewardedRelayer { relayer: relayer1_id.clone(), - messages: DeliveredMessages::new(1), + messages: DeliveredMessages::new(1, 1), }, UnrewardedRelayer { relayer: relayer2_id.clone(), - messages: DeliveredMessages::new(2), + messages: DeliveredMessages::new(2, 1), }, ] .into_iter() diff --git a/bridges/modules/messages/src/call_ext.rs b/bridges/modules/messages/src/call_ext.rs index 15e6c910d5ca3..4ea708af5549f 100644 --- a/bridges/modules/messages/src/call_ext.rs +++ b/bridges/modules/messages/src/call_ext.rs @@ -260,7 +260,11 @@ mod tests { for n in 0..BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), - messages: DeliveredMessages { begin: n + 1, end: n + 1 }, + messages: DeliveredMessages { + begin: n + 1, + end: n + 1, + relayer_reward_per_message: 0, + }, }); } InboundLanes::::insert(test_lane_id(), inbound_lane_state); @@ -273,6 +277,7 @@ mod tests { messages: DeliveredMessages { begin: 1, end: BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + relayer_reward_per_message: 0, }, }); InboundLanes::::insert(test_lane_id(), inbound_lane_state); diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 65240feb7194a..1698643134530 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -21,7 +21,7 @@ use crate::{BridgedChainOf, Config}; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, LaneState, MessageKey, - MessageNonce, OutboundLaneData, ReceptionResult, UnrewardedRelayer, + MessageNonce, OutboundLaneData, ReceptionResult, RelayerRewardAtSource, UnrewardedRelayer, }; use bp_runtime::AccountIdOf; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; @@ -186,6 +186,7 @@ impl InboundLane { relayer_at_bridged_chain: &S::Relayer, nonce: MessageNonce, message_data: DispatchMessageData, + relayer_reward_per_message: RelayerRewardAtSource, ) -> ReceptionResult { let mut data = self.storage.data(); if Some(nonce) != data.last_delivered_nonce().checked_add(1) { @@ -211,13 +212,16 @@ impl InboundLane { // now let's update inbound lane storage match data.relayers.back_mut() { - Some(entry) if entry.relayer == *relayer_at_bridged_chain => { + Some(entry) + if entry.relayer == *relayer_at_bridged_chain && + entry.messages.relayer_reward_per_message == relayer_reward_per_message => + { entry.messages.note_dispatched_message(); }, _ => { data.relayers.push_back(UnrewardedRelayer { relayer: relayer_at_bridged_chain.clone(), - messages: DeliveredMessages::new(nonce), + messages: DeliveredMessages::new(nonce, relayer_reward_per_message), }); }, }; @@ -246,7 +250,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, nonce, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -373,7 +378,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, 10, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::InvalidNonce ); @@ -391,7 +397,8 @@ mod tests { lane.receive_message::( &(TEST_RELAYER_A + current_nonce), current_nonce, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -401,7 +408,8 @@ mod tests { lane.receive_message::( &(TEST_RELAYER_A + max_nonce + 1), max_nonce + 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::TooManyUnrewardedRelayers, ); @@ -410,7 +418,8 @@ mod tests { lane.receive_message::( &(TEST_RELAYER_A + max_nonce), max_nonce + 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::TooManyUnrewardedRelayers, ); @@ -427,7 +436,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, current_nonce, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -437,7 +447,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_B, max_nonce + 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::TooManyUnconfirmedMessages, ); @@ -446,7 +457,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, max_nonce + 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::TooManyUnconfirmedMessages, ); @@ -461,7 +473,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -469,7 +482,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_B, 2, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -477,7 +491,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, 3, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -492,6 +507,52 @@ mod tests { }); } + #[test] + fn separate_relayer_entry_is_created_when_same_relayer_wants_different_reward() { + run_test(|| { + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + 1, + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, + ), + ReceptionResult::Dispatched(dispatch_result(0)) + ); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + 2, + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE + 1, + ), + ReceptionResult::Dispatched(dispatch_result(0)) + ); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + 3, + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE + 1, + ), + ReceptionResult::Dispatched(dispatch_result(0)) + ); + + let mut unrewarded_relayer_with_larger_reward = + unrewarded_relayer(2, 3, TEST_RELAYER_A); + unrewarded_relayer_with_larger_reward.messages.relayer_reward_per_message = + RELAYER_REWARD_PER_MESSAGE + 1; + assert_eq!( + lane.storage.data().relayers, + vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer_with_larger_reward, + ] + ); + }); + } + #[test] fn rejects_same_message_from_two_different_relayers() { run_test(|| { @@ -500,7 +561,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(0)) ); @@ -508,7 +570,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_B, 1, - inbound_message_data(REGULAR_PAYLOAD) + inbound_message_data(REGULAR_PAYLOAD), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::InvalidNonce, ); @@ -534,7 +597,8 @@ mod tests { lane.receive_message::( &TEST_RELAYER_A, 1, - inbound_message_data(payload) + inbound_message_data(payload), + RELAYER_REWARD_PER_MESSAGE, ), ReceptionResult::Dispatched(dispatch_result(1)) ); diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 4cdfbb6c97e6b..437204832623d 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -60,9 +60,9 @@ use bp_messages::{ DeliveryPayments, DispatchMessage, FromBridgedChainMessagesProof, MessageDispatch, ProvedLaneMessages, ProvedMessages, }, - ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, - MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, - OutboundMessageDetails, UnrewardedRelayersState, VerificationError, + ChainWithMessages, InboundLaneData, InboundMessageDetails, LaneId, MessageKey, MessageNonce, + MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, + UnrewardedRelayersState, VerificationError, }; use bp_runtime::{ AccountIdOf, BasicOperatingMode, HashOf, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, @@ -268,6 +268,11 @@ pub mod pallet { } } + // compute the per-message reward that is paid at the bridged (source) chain to relayer + // that has delivered message + let relayer_reward_per_message = + T::DeliveryPayments::relayer_reward_per_message(lane_id, &relayer_id_at_this_chain); + let mut messages_received_status = ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); for mut message in lane_data.messages { @@ -294,6 +299,7 @@ pub mod pallet { &relayer_id_at_bridged_chain, message.key.nonce, message.data, + relayer_reward_per_message, ); // note that we're returning unspent weight to relayer even if message has been @@ -320,6 +326,7 @@ pub mod pallet { // let's now deal with relayer payments T::DeliveryPayments::pay_reward( + lane_id, relayer_id_at_this_chain, total_messages, valid_messages, @@ -381,12 +388,12 @@ pub mod pallet { ) .map_err(Error::::ReceptionConfirmation)?; - if let Some(confirmed_messages) = confirmed_messages { + if let Some(received_range) = confirmed_messages { // emit 'delivered' event - let received_range = confirmed_messages.begin..=confirmed_messages.end; Self::deposit_event(Event::MessagesDelivered { lane_id, - messages: confirmed_messages, + messages_begin: *received_range.start(), + messages_end: *received_range.end(), }); // if some new messages have been confirmed, reward relayers @@ -452,8 +459,10 @@ pub mod pallet { MessagesDelivered { /// Lane for which the delivery has been confirmed. lane_id: LaneId, - /// Delivered messages. - messages: DeliveredMessages, + /// Nonce of the first delivered message. + messages_begin: MessageNonce, + /// Nonce of the last delivered message. + messages_end: MessageNonce, }, } diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index f71240ab7c703..fc97992dd8b29 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -19,9 +19,9 @@ use crate::{Config, LOG_TARGET}; use bp_messages::{ - ChainWithMessages, DeliveredMessages, LaneId, LaneState, MessageNonce, OutboundLaneData, - UnrewardedRelayer, + ChainWithMessages, LaneId, LaneState, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; +use bp_runtime::RangeInclusiveExt; use codec::{Decode, Encode}; use frame_support::{traits::Get, BoundedVec, PalletError}; use scale_info::TypeInfo; @@ -133,19 +133,21 @@ impl OutboundLane { max_allowed_messages: MessageNonce, latest_delivered_nonce: MessageNonce, relayers: &VecDeque>, - ) -> Result, ReceptionConfirmationError> { + ) -> Result< + Option>, + crate::outbound_lane::ReceptionConfirmationError, + > { let mut data = self.storage.data(); - let confirmed_messages = DeliveredMessages { - begin: data.latest_received_nonce.saturating_add(1), - end: latest_delivered_nonce, - }; - if confirmed_messages.total_messages() == 0 { + let confirmed_messages = + data.latest_received_nonce.saturating_add(1)..=latest_delivered_nonce; + let confirmed_messages_count = confirmed_messages.saturating_len(); + if confirmed_messages_count == 0 { return Ok(None) } - if confirmed_messages.end > data.latest_generated_nonce { + if *confirmed_messages.end() > data.latest_generated_nonce { return Err(ReceptionConfirmationError::FailedToConfirmFutureMessages) } - if confirmed_messages.total_messages() > max_allowed_messages { + if confirmed_messages_count > max_allowed_messages { // that the relayer has declared correct number of messages that the proof contains (it // is checked outside of the function). But it may happen (but only if this/bridged // chain storage is corrupted, though) that the actual number of confirmed messages if @@ -154,20 +156,20 @@ impl OutboundLane { log::trace!( target: LOG_TARGET, "Messages delivery proof contains too many messages to confirm: {} vs declared {}", - confirmed_messages.total_messages(), + confirmed_messages_count, max_allowed_messages, ); return Err(ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected) } - ensure_unrewarded_relayers_are_correct(confirmed_messages.end, relayers)?; + ensure_unrewarded_relayers_are_correct(*confirmed_messages.end(), relayers)?; // prune all confirmed messages - for nonce in confirmed_messages.begin..=confirmed_messages.end { + for nonce in *confirmed_messages.start()..=*confirmed_messages.end() { self.storage.remove_message(&nonce); } - data.latest_received_nonce = confirmed_messages.end; + data.latest_received_nonce = *confirmed_messages.end(); data.oldest_unpruned_nonce = data.latest_received_nonce.saturating_add(1); self.storage.set_data(data); @@ -239,14 +241,10 @@ mod tests { .collect() } - fn delivered_messages(nonces: RangeInclusive) -> DeliveredMessages { - DeliveredMessages { begin: *nonces.start(), end: *nonces.end() } - } - fn assert_3_messages_confirmation_fails( latest_received_nonce: MessageNonce, relayers: &VecDeque>, - ) -> Result, ReceptionConfirmationError> { + ) -> Result>, ReceptionConfirmationError> { run_test(|| { let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -282,10 +280,7 @@ mod tests { assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 0); assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - assert_eq!( - lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), - Ok(Some(delivered_messages(1..=3))), - ); + assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(Some(1..=3)),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); @@ -303,18 +298,12 @@ mod tests { assert_eq!(lane.storage.data().latest_received_nonce, 0); assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - assert_eq!( - lane.confirm_delivery(3, 2, &unrewarded_relayers(1..=2)), - Ok(Some(delivered_messages(1..=2))), - ); + assert_eq!(lane.confirm_delivery(3, 2, &unrewarded_relayers(1..=2)), Ok(Some(1..=2)),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 2); assert_eq!(lane.storage.data().oldest_unpruned_nonce, 3); - assert_eq!( - lane.confirm_delivery(3, 3, &unrewarded_relayers(3..=3)), - Ok(Some(delivered_messages(3..=3))), - ); + assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(3..=3)), Ok(Some(3..=3)),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); @@ -331,10 +320,7 @@ mod tests { assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 0); assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - assert_eq!( - lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), - Ok(Some(delivered_messages(1..=3))), - ); + assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(Some(1..=3)),); assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); @@ -416,10 +402,7 @@ mod tests { lane.confirm_delivery(2, 3, &unrewarded_relayers(1..=3)), Err(ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected), ); - assert_eq!( - lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), - Ok(Some(delivered_messages(1..=3))), - ); + assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(Some(1..=3)),); }); } } diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index c7a115e3c1a60..51bbc6408031d 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -27,7 +27,7 @@ use crate::{ use bp_header_chain::{ChainWithGrandpa, StoredHeaderData}; use bp_messages::{ - calc_relayers_rewards, + calc_relayers_rewards_at_source, source_chain::{ DeliveryConfirmationPayments, FromBridgedChainMessagesDeliveryProof, OnMessagesDelivered, }, @@ -36,7 +36,8 @@ use bp_messages::{ MessageDispatch, }, ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, LaneState, Message, MessageKey, - MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, + MessageNonce, OutboundLaneData, RelayerRewardAtSource, UnrewardedRelayer, + UnrewardedRelayersState, }; use bp_runtime::{ messages::MessageDispatchResult, Chain, ChainId, Size, UnverifiedStorageProofParams, @@ -258,6 +259,9 @@ pub const TEST_RELAYER_B: AccountId = 101; /// Account id of additional test relayer - C. pub const TEST_RELAYER_C: AccountId = 102; +/// Reward that is paid for delivering single message. +pub const RELAYER_REWARD_PER_MESSAGE: Balance = 77; + /// Lane that we're using in tests. pub fn test_lane_id() -> LaneId { LaneId::new(1, 2) @@ -284,7 +288,7 @@ impl TestDeliveryPayments { /// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is /// cleared after the call. pub fn is_reward_paid(relayer: AccountId) -> bool { - let key = (b":delivery-relayer-reward:", relayer).encode(); + let key = (b":delivery-relayer-relayer_reward_per_message:", relayer).encode(); frame_support::storage::unhashed::take::(&key).is_some() } } @@ -292,13 +296,18 @@ impl TestDeliveryPayments { impl DeliveryPayments for TestDeliveryPayments { type Error = &'static str; + fn relayer_reward_per_message(_lane_id: LaneId, _relayer: &AccountId) -> RelayerRewardAtSource { + RELAYER_REWARD_PER_MESSAGE + } + fn pay_reward( + _lane_id: LaneId, relayer: AccountId, _total_messages: MessageNonce, _valid_messages: MessageNonce, _actual_weight: Weight, ) { - let key = (b":delivery-relayer-reward:", relayer).encode(); + let key = (b":delivery-relayer-relayer_reward_per_message:", relayer).encode(); frame_support::storage::unhashed::put(&key, &true); } } @@ -311,7 +320,7 @@ impl TestDeliveryConfirmationPayments { /// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is /// cleared after the call. pub fn is_reward_paid(relayer: AccountId, fee: TestMessageFee) -> bool { - let key = (b":relayer-reward:", relayer, fee).encode(); + let key = (b":relayer-relayer_reward_per_message:", relayer, fee).encode(); frame_support::storage::unhashed::take::(&key).is_some() } } @@ -325,10 +334,14 @@ impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayment _confirmation_relayer: &AccountId, received_range: &RangeInclusive, ) -> MessageNonce { - let relayers_rewards = calc_relayers_rewards(messages_relayers, received_range); + let relayers_rewards = calc_relayers_rewards_at_source::( + messages_relayers, + received_range, + |messages, relayer_reward_per_message| messages * relayer_reward_per_message, + ); let rewarded_relayers = relayers_rewards.len(); for (relayer, reward) in &relayers_rewards { - let key = (b":relayer-reward:", relayer, reward).encode(); + let key = (b":relayer-relayer_reward_per_message:", relayer, reward).encode(); frame_support::storage::unhashed::put(&key, &true); } @@ -445,7 +458,14 @@ pub fn unrewarded_relayer( end: MessageNonce, relayer: TestRelayer, ) -> UnrewardedRelayer { - UnrewardedRelayer { relayer, messages: DeliveredMessages { begin, end } } + UnrewardedRelayer { + relayer, + messages: DeliveredMessages { + begin, + end, + relayer_reward_per_message: RELAYER_REWARD_PER_MESSAGE, + }, + } } /// Returns unrewarded relayers state at given lane. diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 01e069fabfae4..97abc2f8a9f98 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -86,7 +86,7 @@ fn receive_messages_delivery_proof() { last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, - messages: DeliveredMessages::new(1), + messages: DeliveredMessages::new(1, 0), }] .into(), }, @@ -105,7 +105,8 @@ fn receive_messages_delivery_proof() { phase: Phase::Initialization, event: TestEvent::Messages(Event::MessagesDelivered { lane_id: test_lane_id(), - messages: DeliveredMessages::new(1), + messages_begin: 1, + messages_end: 1, }), topics: vec![], }], @@ -259,6 +260,15 @@ fn receive_messages_proof_works() { .last_delivered_nonce(), 1 ); + assert_eq!( + InboundLanes::::get(test_lane_id()) + .unwrap() + .0 + .relayers + .front() + .map(|r| r.messages.relayer_reward_per_message), + Some(RELAYER_REWARD_PER_MESSAGE), + ); assert!(TestDeliveryPayments::is_reward_paid(1)); }); @@ -536,8 +546,14 @@ fn receive_messages_delivery_proof_rewards_relayers() { }, ) ); - assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); - assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); + assert!(TestDeliveryConfirmationPayments::is_reward_paid( + TEST_RELAYER_A, + RELAYER_REWARD_PER_MESSAGE + )); + assert!(!TestDeliveryConfirmationPayments::is_reward_paid( + TEST_RELAYER_B, + RELAYER_REWARD_PER_MESSAGE + )); // this reports delivery of both message 1 and message 2 => reward is paid only to // TEST_RELAYER_B @@ -577,8 +593,14 @@ fn receive_messages_delivery_proof_rewards_relayers() { }, ) ); - assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); - assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); + assert!(!TestDeliveryConfirmationPayments::is_reward_paid( + TEST_RELAYER_A, + RELAYER_REWARD_PER_MESSAGE + )); + assert!(TestDeliveryConfirmationPayments::is_reward_paid( + TEST_RELAYER_B, + RELAYER_REWARD_PER_MESSAGE + )); assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((test_lane_id(), 0))); }); } @@ -834,7 +856,11 @@ fn proof_size_refund_from_receive_messages_proof_works() { relayers: vec![ UnrewardedRelayer { relayer: 42, - messages: DeliveredMessages { begin: 0, end: 100 } + messages: DeliveredMessages { + begin: 0, + end: 100, + relayer_reward_per_message: 0 + } }; max_entries ] @@ -863,7 +889,11 @@ fn proof_size_refund_from_receive_messages_proof_works() { relayers: vec![ UnrewardedRelayer { relayer: 42, - messages: DeliveredMessages { begin: 0, end: 100 } + messages: DeliveredMessages { + begin: 0, + end: 100, + relayer_reward_per_message: 0 + } }; max_entries - 1 ] @@ -976,7 +1006,7 @@ fn test_bridge_messages_call_is_correctly_defined() { last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, - messages: DeliveredMessages::new(1), + messages: DeliveredMessages::new(1, 0), }] .into(), }, @@ -1037,7 +1067,10 @@ generate_owned_bridge_module_tests!( #[test] fn inbound_storage_extra_proof_size_bytes_works() { fn relayer_entry() -> UnrewardedRelayer { - UnrewardedRelayer { relayer: 42u64, messages: DeliveredMessages { begin: 0, end: 100 } } + UnrewardedRelayer { + relayer: 42u64, + messages: DeliveredMessages { begin: 0, end: 100, relayer_reward_per_message: 0 }, + } } fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { @@ -1132,7 +1165,7 @@ fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, - messages: DeliveredMessages::new(1), + messages: DeliveredMessages::new(1, 0), }] .into(), }, diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index 0a284447fc37c..7c78579281bad 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -2322,7 +2322,11 @@ mod tests { last_confirmed_nonce: 0, relayers: vec![UnrewardedRelayer { relayer: relayer_account_at_bridged_chain(), - messages: DeliveredMessages { begin: 1, end: best_delivered_message }, + messages: DeliveredMessages { + begin: 1, + end: best_delivered_message, + relayer_reward_per_message: 0, + }, }] .into(), ..Default::default() diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index d91817d2f2377..7ef0bb2b1f3d5 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -79,6 +79,9 @@ pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; /// Maximal extrinsic size at the `BridgedChain`. pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; +/// Maximal reward that may be paid to relayer for delivering a single message. +pub const MAX_REWARD_PER_MESSAGE: ThisChainBalance = 100_000; + /// Underlying chain of `ThisChain`. pub struct ThisUnderlyingChain; @@ -252,6 +255,13 @@ impl pallet_bridge_parachains::Config for TestRuntime { type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight; } +pub type TestDeliveryConfirmationPaymentsAdapter = + pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + TestRuntime, + (), + ConstU64, + >; + impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; @@ -261,11 +271,7 @@ impl pallet_bridge_messages::Config for TestRuntime { type InboundPayload = Vec; type DeliveryPayments = (); - type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< - TestRuntime, - (), - ConstU64<100_000>, - >; + type DeliveryConfirmationPayments = TestDeliveryConfirmationPaymentsAdapter; type OnMessagesDelivered = (); type MessageDispatch = DummyMessageDispatch; @@ -363,9 +369,18 @@ impl MessageDispatch for DummyMessageDispatch { } } +/// Lane identifier used in tests. +pub fn test_lane_id() -> LaneId { + LaneId::new(1, 2) +} + /// Reward account params that we are using in tests. pub fn test_reward_account_param() -> RewardsAccountParams { - RewardsAccountParams::new(LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain) + RewardsAccountParams::new( + test_lane_id(), + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::BridgedChain, + ) } /// Return test externalities to use in tests. diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index 3693793a3e5ca..9f069edc94736 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -24,78 +24,75 @@ use bp_messages::{ }; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::Chain; -use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; -use sp_arithmetic::traits::{Saturating, Zero}; +use frame_support::traits::Get; +use sp_arithmetic::traits::{Saturating, UniqueSaturatedFrom}; +use sp_runtime::traits::UniqueSaturatedInto; 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, MI, DeliveryReward)>, +/// +/// This adapter assumes 1:1 mapping of `RelayerRewardAtSource` to `T::Reward`. The reward for +/// delivering a single message, will never be larger than the `MaxRewardPerMessage`. +/// +/// We assume that the confirmation transaction cost is refunded by the signed extension, +/// implemented by the pallet. So we do not reward confirmation relayer additionally here. +pub struct DeliveryConfirmationPaymentsAdapter( + PhantomData<(T, MI, MaxRewardPerMessage)>, ); -impl DeliveryConfirmationPayments - for DeliveryConfirmationPaymentsAdapter +impl DeliveryConfirmationPayments + for DeliveryConfirmationPaymentsAdapter where T: Config + pallet_bridge_messages::Config, MI: 'static, - DeliveryReward: Get, + MaxRewardPerMessage: Get, { type Error = &'static str; fn pay_reward( lane_id: LaneId, messages_relayers: VecDeque>, - confirmation_relayer: &T::AccountId, + _confirmation_relayer: &T::AccountId, received_range: &RangeInclusive, ) -> MessageNonce { let relayers_rewards = - bp_messages::calc_relayers_rewards::(messages_relayers, received_range); + bp_messages::calc_relayers_rewards_at_source::( + messages_relayers, + received_range, + |messages, relayer_reward_per_message| { + let relayer_reward_per_message = sp_std::cmp::min( + MaxRewardPerMessage::get(), + relayer_reward_per_message.unique_saturated_into(), + ); + + T::Reward::unique_saturated_from(messages) + .saturating_mul(relayer_reward_per_message) + }, + ); let rewarded_relayers = relayers_rewards.len(); register_relayers_rewards::( - confirmation_relayer, relayers_rewards, RewardsAccountParams::new( lane_id, T::BridgedChain::ID, RewardsAccountOwner::BridgedChain, ), - DeliveryReward::get(), ); rewarded_relayers as _ } } -// Update rewards to given relayers, optionally rewarding confirmation relayer. +/// Register relayer rewards for delivering messages. fn register_relayers_rewards( - confirmation_relayer: &T::AccountId, - relayers_rewards: RelayersRewards, - lane_id: RewardsAccountParams, - delivery_fee: T::Reward, + relayers_rewards: RelayersRewards, + reward_account: RewardsAccountParams, ) { - // 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 relayer_reward = T::Reward::saturated_from(messages).saturating_mul(delivery_fee); - - if relayer != *confirmation_relayer { - Pallet::::register_relayer_reward(lane_id, &relayer, relayer_reward); - } else { - confirmation_relayer_reward = - confirmation_relayer_reward.saturating_add(relayer_reward); - } + for (relayer, relayer_reward) in relayers_rewards { + Pallet::::register_relayer_reward(reward_account, &relayer, relayer_reward); } - - // finally - pay reward to confirmation relayer - Pallet::::register_relayer_reward( - lane_id, - confirmation_relayer, - confirmation_relayer_reward, - ); } #[cfg(test)] @@ -107,52 +104,51 @@ mod tests { const RELAYER_2: ThisChainAccountId = 2; const RELAYER_3: ThisChainAccountId = 3; - fn relayers_rewards() -> RelayersRewards { + fn relayers_rewards() -> RelayersRewards { vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect() } #[test] - fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() { + fn register_relayers_rewards_works() { run_test(|| { register_relayers_rewards::( - &RELAYER_2, relayers_rewards(), test_reward_account_param(), - 50, ); assert_eq!( RelayerRewards::::get(RELAYER_1, test_reward_account_param()), - Some(100) + Some(2) ); assert_eq!( RelayerRewards::::get(RELAYER_2, test_reward_account_param()), - Some(150) + Some(3) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_3, test_reward_account_param()), + None ); }); } #[test] - fn confirmation_relayer_is_not_rewarded_if_it_has_not_delivered_any_messages() { + fn reward_per_message_is_never_larger_than_max_reward_per_message() { run_test(|| { - register_relayers_rewards::( - &RELAYER_3, - relayers_rewards(), - test_reward_account_param(), - 50, + let mut delivered_messages = + bp_messages::DeliveredMessages::new(1, MAX_REWARD_PER_MESSAGE + 1); + delivered_messages.note_dispatched_message(); + + TestDeliveryConfirmationPaymentsAdapter::pay_reward( + test_lane_id(), + vec![bp_messages::UnrewardedRelayer { relayer: 42, messages: delivered_messages }] + .into(), + &43, + &(1..=2), ); assert_eq!( - RelayerRewards::::get(RELAYER_1, test_reward_account_param()), - Some(100) - ); - assert_eq!( - RelayerRewards::::get(RELAYER_2, test_reward_account_param()), - Some(150) - ); - assert_eq!( - RelayerRewards::::get(RELAYER_3, test_reward_account_param()), - None + RelayerRewards::::get(42, test_reward_account_param()), + Some(MAX_REWARD_PER_MESSAGE * 2), ); }); } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index a9cce3c5ecba6..6fffdac5cd22c 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -26,6 +26,7 @@ frame-support = { path = "../../../substrate/frame/support", default-features = sp-core = { path = "../../../substrate/primitives/core", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } [dev-dependencies] hex = "0.4" @@ -42,5 +43,6 @@ std = [ "serde/std", "sp-core/std", "sp-io/std", + "sp-runtime/std", "sp-std/std" ] diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 37dc61e8b4837..c5b581d07107e 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -24,7 +24,7 @@ use bp_runtime::{ messages::MessageDispatchResult, BasicOperatingMode, Chain, OperatingMode, RangeInclusiveExt, StorageProofError, UnderlyingChainOf, UnderlyingChainProvider, }; -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Compact, Decode, Encode, MaxEncodedLen}; use frame_support::PalletError; // Weight is reexported to avoid additional frame-support dependencies in related crates. pub use frame_support::weights::Weight; @@ -33,6 +33,7 @@ use serde::{Deserialize, Serialize}; use source_chain::RelayersRewards; use sp_core::{RuntimeDebug, TypeId, H256}; use sp_io::hashing::blake2_256; +use sp_runtime::traits::{Saturating, Zero}; use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; pub use call_info::{ @@ -369,6 +370,8 @@ impl InboundLaneData { { relayers_entries .checked_mul(UnrewardedRelayer::::max_encoded_len())? + .checked_add(Compact::(relayers_entries as u32).encoded_size())? + .checked_add(LaneState::max_encoded_len())? .checked_add(MessageNonce::max_encoded_len()) } @@ -483,6 +486,17 @@ pub enum ReceptionResult { TooManyUnconfirmedMessages, } +/// Type of reward that needs to be paid at the source chain for delivering messages to the +/// target chain. It does not necessary mapped 1:1 onto source chain tokens (or whatever is +/// used to pay rewards there). The `DeliveryConfirmationPayments` implementation decides how +/// to map it and what actual reward the relayer would receive. +/// +/// Why our code is not generic over this type? That's mostly because we are using single +/// `pallet-bridge-relayers` instance to register rewards for all bridges. Those bridges +/// may be connected to chains, using different `Balance` types. Why not to use encoded version? +/// Because we need to order relayers by the reward they get for delivering a single message. +pub type RelayerRewardAtSource = u64; + /// Delivered messages with their dispatch result. #[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct DeliveredMessages { @@ -490,13 +504,17 @@ pub struct DeliveredMessages { pub begin: MessageNonce, /// Nonce of the last message that has been delivered (inclusive). pub end: MessageNonce, + /// Reward that needs to be paid at the source chain (during confirmation transaction) + /// for **every delivered message** in the `begin..=end` range. If reward has been paid + /// at the target chain or if no rewards assumed, it may be zero. + pub relayer_reward_per_message: RelayerRewardAtSource, } impl DeliveredMessages { /// Create new `DeliveredMessages` struct that confirms delivery of single nonce with given /// dispatch result. - pub fn new(nonce: MessageNonce) -> Self { - DeliveredMessages { begin: nonce, end: nonce } + pub fn new(nonce: MessageNonce, relayer_reward_per_message: RelayerRewardAtSource) -> Self { + DeliveredMessages { begin: nonce, end: nonce, relayer_reward_per_message } } /// Return total count of delivered messages. @@ -598,23 +616,44 @@ impl OutboundLaneData { } } -/// Calculate the number of messages that the relayers have delivered. -pub fn calc_relayers_rewards( +/// Calculate the total relayer reward that need to be paid at the source chain. +/// +/// The `compute_reward` assumed to be a function that maps the `RelayerRewardAtSource` onto +/// real reward that is paid to relayer. This function needs to compute and return +/// the total reward for delivering given number of messages to the target (bridged) +/// chain by relayer that has agreed to work for given reward. +pub fn calc_relayers_rewards_at_source( messages_relayers: VecDeque>, received_range: &RangeInclusive, -) -> RelayersRewards + compute_reward: impl Fn(MessageNonce, RelayerRewardAtSource) -> Reward, +) -> RelayersRewards where AccountId: sp_std::cmp::Ord, + Reward: Copy + Saturating + Zero, { // remember to reward relayers that have delivered messages // this loop is bounded by `T::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` on the bridged chain - let mut relayers_rewards = RelayersRewards::new(); + let mut relayers_rewards: RelayersRewards<_, Reward> = RelayersRewards::new(); for entry in messages_relayers { + // if relayer does not expect any reward, do nothing + if entry.messages.relayer_reward_per_message == 0 { + continue + } + + // if we have already paid reward for delivering those messages, do nothing let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start()); let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end()); - if nonce_end >= nonce_begin { - *relayers_rewards.entry(entry.relayer).or_default() += nonce_end - nonce_begin + 1; + let new_confirmations = nonce_begin..=nonce_end; + let new_confirmations_count = new_confirmations.saturating_len(); + if new_confirmations_count == 0 { + continue } + + // compute and update reward in the rewards map + let new_reward = + compute_reward(new_confirmations_count, entry.messages.relayer_reward_per_message); + let total_relayer_reward = relayers_rewards.entry(entry.relayer).or_insert_with(Zero::zero); + *total_relayer_reward = total_relayer_reward.saturating_add(new_reward); } relayers_rewards } @@ -659,10 +698,10 @@ mod tests { let lane_data = InboundLaneData { state: LaneState::Opened, relayers: vec![ - UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) }, + UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0, 0) }, UnrewardedRelayer { relayer: 2, - messages: DeliveredMessages::new(MessageNonce::MAX), + messages: DeliveredMessages::new(MessageNonce::MAX, 0), }, ] .into_iter() @@ -689,7 +728,7 @@ mod tests { relayers: (1u8..=relayer_entries) .map(|i| UnrewardedRelayer { relayer: i, - messages: DeliveredMessages::new(i as _), + messages: DeliveredMessages::new(i as _, 0u64), }) .collect(), last_confirmed_nonce: messages_count as _, @@ -706,7 +745,8 @@ mod tests { #[test] fn contains_result_works() { - let delivered_messages = DeliveredMessages { begin: 100, end: 150 }; + let delivered_messages = + DeliveredMessages { begin: 100, end: 150, relayer_reward_per_message: 0 }; assert!(!delivered_messages.contains_message(99)); assert!(delivered_messages.contains_message(100)); @@ -761,4 +801,29 @@ mod tests { LaneId::new(Either::Three(1, 2, 3), Either::One(4)), ); } + + #[test] + fn calc_relayers_rewards_at_source_works() { + assert_eq!( + calc_relayers_rewards_at_source::( + vec![ + // relayer that wants zero reward => no payments expected + UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(1, 0) }, + // relayer wants reward => payment is expected + UnrewardedRelayer { relayer: 2, messages: DeliveredMessages::new(2, 77) }, + // relayer that we met before and he wants reward => payment is expected + UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(3, 42) }, + // relayer that we met before and he wants reward => payment is expected + UnrewardedRelayer { relayer: 2, messages: DeliveredMessages::new(4, 33) }, + // relayers that deliver messages out of range + UnrewardedRelayer { relayer: 2, messages: DeliveredMessages::new(0, 33) }, + UnrewardedRelayer { relayer: 2, messages: DeliveredMessages::new(5, 33) }, + ] + .into(), + &(1..=4), + |_, relayer_reward_per_message| relayer_reward_per_message, + ), + vec![(1, 42), (2, 110)].into_iter().collect(), + ); + } } diff --git a/bridges/primitives/messages/src/source_chain.rs b/bridges/primitives/messages/src/source_chain.rs index 881052b8277a3..45192308db75e 100644 --- a/bridges/primitives/messages/src/source_chain.rs +++ b/bridges/primitives/messages/src/source_chain.rs @@ -54,8 +54,8 @@ impl Size for FromBridgedChainMessagesDeliveryProof = BTreeMap; +/// Rewards that need to be paid to relayers. +pub type RelayersRewards = BTreeMap; /// Manages payments that are happening at the source chain during delivery confirmation /// transaction. diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs index dbc3209a6fb60..bbef990c2c454 100644 --- a/bridges/primitives/messages/src/target_chain.rs +++ b/bridges/primitives/messages/src/target_chain.rs @@ -16,7 +16,10 @@ //! 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, + RelayerRewardAtSource, +}; use bp_runtime::{messages::MessageDispatchResult, Size, UnverifiedStorageProof}; use codec::{Decode, Encode, Error as CodecError}; @@ -125,6 +128,14 @@ pub trait DeliveryPayments { /// Error type. type Error: Debug + Into<&'static str>; + /// Returns current reward that needs be paid at the bridged (source) chain for delivering + /// single message at given lane by given relayer. This value is a part of message delivery + /// proof, so it will eventually be reported to the source chain. + /// + /// Keep in mind that it is not necessary a real reward that will be paid. See + /// [`crate::RelayerRewardAtSource`] for more details. + fn relayer_reward_per_message(lane: LaneId, relayer: &AccountId) -> RelayerRewardAtSource; + /// Pay rewards for delivering messages to the given relayer. /// /// This method is called during message delivery transaction which has been submitted @@ -132,6 +143,7 @@ pub trait DeliveryPayments { /// `valid_messages` have been accepted. The post-dispatch transaction weight is the /// `actual_weight`. fn pay_reward( + lane_id: LaneId, relayer: AccountId, total_messages: MessageNonce, valid_messages: MessageNonce, @@ -160,7 +172,12 @@ impl From for DispatchMessageData DeliveryPayments for () { type Error = &'static str; + fn relayer_reward_per_message(_lane: LaneId, _relayer: &AccountId) -> RelayerRewardAtSource { + 0 + } + fn pay_reward( + _lane_id: LaneId, _relayer: AccountId, _total_messages: MessageNonce, _valid_messages: MessageNonce,