Dynamic fees for bridges-v1 (#2294)

* impl backpressure in the XcmBlobHaulerAdapter

* LocalXcmQueueManager + more adapters

* OnMessageDelviered callback

* forbid mesage delivery transactions when the channel between target bridge hub and target asset hub is suspended

* pallet-xcm-bridge-hub-router

* removed commented code

* improvements and tests for palle-xcm-bridge-router

* use LocalXcmChannel in XcmBlobMessageDispatch

* new tests for logic changes in messages pallet

* tests for LocalXcmQueueSuspender

* tests for LocalXcmQueueMessageProcessor

* tests for new logic in the XcmBlobHaulerAdapter

* fix other tests in the bridge-runtime-common

* extension_reject_call_when_dispatcher_is_inactive

* benchmarks for pallet-xcm-bridge-hub-router

* get rid of redundant storage value

* add new pallet to verify-pallets-build.sh

* fixing spellcheck, clippy and rustdoc

* trigger CI

* Revert "trigger CI"

This reverts commit 48f1ba032334e3c6d8470436483736988aa060ac.

* change log target for xcm bridge router pallet

* Update modules/xcm-bridge-hub-router/src/lib.rs

Co-authored-by: Branislav Kontur <bkontur@gmail.com>

* use saturated_len where possible

* fmt

* (Suggestion) Ability to externalize configuration for `ExporterFor` (#2313)

* Ability to externalize configuration for `ExporterFor`
(Replaced `BridgedNetworkId/SiblingBridgeHubLocation` with `Bridges: ExporterFor`)

* Fix millau

* Compile fix

* Return back `BridgedNetworkId` but as optional filter

* Replaced `BaseFee` with fees from inner `Bridges: ExporterFor`

* typo

* Clippy

* Rename LocalXcmChannel to XcmChannelStatusProvider (#2319)

* Rename LocalXcmChannel to XcmChannelStatusProvider

* fmt

* added/fixed some docs

* Dynamic fees v1: report congestion status to sending chain (#2318)

* report congestion status: changes at the sending chain

* OnMessagesDelivered is back

* report congestion status: changes at the bridge hub

* moer logging

* fix? benchmarks

* spelling

* tests for XcmBlobHaulerAdapter and LocalXcmQueueManager

* tests for messages pallet

* fix typo

* rustdoc

* Update modules/messages/src/lib.rs

* apply review suggestions

* ".git/.scripts/commands/fmt/fmt.sh"

* Added `XcmBridgeHubRouterCall::report_bridge_status` encodings for AHK/P (#2350)

* Added `XcmBridgeHubRouterCall::report_bridge_status` encodings for AHK/P

* Spellcheck

* Added const for `XcmBridgeHubRouterTransactCallMaxWeight`

* Cargo.lock

* Introduced base delivery fee constants

* Congestion messages as Optional to turn on/off `supports_congestion_detection`

* Spellcheck

* Ability to externalize dest for benchmarks

* Ability to externalize dest for benchmarks

---------

Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: command-bot <>
This commit is contained in:
Svyatoslav Nikolsky
2023-08-16 16:49:11 +03:00
committed by Bastian Köcher
parent dc8aa5df7d
commit 31a6cbeafb
30 changed files with 2031 additions and 71 deletions
+73 -8
View File
@@ -53,7 +53,8 @@ use crate::{
use bp_messages::{
source_chain::{
DeliveryConfirmationPayments, LaneMessageVerifier, SendMessageArtifacts, TargetHeaderChain,
DeliveryConfirmationPayments, LaneMessageVerifier, OnMessagesDelivered,
SendMessageArtifacts, TargetHeaderChain,
},
target_chain::{
DeliveryPayments, DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages,
@@ -63,7 +64,9 @@ use bp_messages::{
MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails,
UnrewardedRelayersState, VerificationError,
};
use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, PreComputedSize, Size};
use bp_runtime::{
BasicOperatingMode, ChainId, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, Size,
};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get, DefaultNoBound};
use sp_runtime::traits::UniqueSaturatedFrom;
@@ -156,6 +159,8 @@ pub mod pallet {
type LaneMessageVerifier: LaneMessageVerifier<Self::OutboundPayload>;
/// Delivery confirmation payments.
type DeliveryConfirmationPayments: DeliveryConfirmationPayments<Self::AccountId>;
/// Delivery confirmation callback.
type OnMessagesDelivered: OnMessagesDelivered;
// Types that are used by inbound_lane (on target chain).
@@ -281,6 +286,9 @@ pub mod pallet {
Error::<T, I>::TooManyMessagesInTheProof
);
// if message dispatcher is currently inactive, we won't accept any messages
ensure!(T::MessageDispatch::is_active(), Error::<T, I>::MessageDispatchInactive);
// why do we need to know the weight of this (`receive_messages_proof`) call? Because
// we may want to return some funds for not-dispatching (or partially dispatching) some
// messages to the call origin (relayer). And this is done by returning actual weight
@@ -487,6 +495,12 @@ pub mod pallet {
lane_id,
);
// notify others about messages delivery
T::OnMessagesDelivered::on_messages_delivered(
lane_id,
lane.data().queued_messages().saturating_len(),
);
// because of lags, the inbound lane state (`lane_data`) may have entries for
// already rewarded relayers and messages (if all entries are duplicated, then
// this transaction must be filtered out by our signed extension)
@@ -518,6 +532,8 @@ pub mod pallet {
NotOperatingNormally,
/// The outbound lane is inactive.
InactiveOutboundLane,
/// The inbound message dispatcher is inactive.
MessageDispatchInactive,
/// Message has been treated as invalid by chain verifier.
MessageRejectedByChainVerifier(VerificationError),
/// Message has been treated as invalid by lane verifier.
@@ -580,6 +596,25 @@ pub mod pallet {
MaxValues = MaybeOutboundLanesCount<T, I>,
>;
/// Map of lane id => is congested signal sent. It is managed by the
/// `bridge_runtime_common::LocalXcmQueueManager`.
///
/// **bridges-v1**: this map is a temporary hack and will be dropped in the `v2`. We can emulate
/// a storage map using `sp_io::unhashed` storage functions, but then benchmarks are not
/// accounting its `proof_size`, so it is missing from the final weights. So we need to make it
/// a map inside some pallet. We could use a simply value instead of map here, because
/// in `v1` we'll only have a single lane. But in the case of adding another lane before `v2`,
/// it'll be easier to deal with the isolated storage map instead.
#[pallet::storage]
pub type OutboundLanesCongestedSignals<T: Config<I>, I: 'static = ()> = StorageMap<
Hasher = Blake2_128Concat,
Key = LaneId,
Value = bool,
QueryKind = ValueQuery,
OnEmpty = GetDefault,
MaxValues = MaybeOutboundLanesCount<T, I>,
>;
/// All queued outbound messages.
#[pallet::storage]
pub type OutboundMessages<T: Config<I>, I: 'static = ()> =
@@ -627,6 +662,11 @@ pub mod pallet {
}
}
/// Return outbound lane data.
pub fn outbound_lane_data(lane: LaneId) -> OutboundLaneData {
OutboundLanes::<T, I>::get(lane)
}
/// Return inbound lane data.
pub fn inbound_lane_data(lane: LaneId) -> InboundLaneData<T::InboundRelayer> {
InboundLanes::<T, I>::get(lane).0
@@ -703,6 +743,9 @@ fn send_message<T: Config<I>, I: 'static>(
.send_message(encoded_payload)
.map_err(Error::<T, I>::MessageRejectedByPallet)?;
// return number of messages in the queue to let sender know about its state
let enqueued_messages = lane.data().queued_messages().saturating_len();
log::trace!(
target: LOG_TARGET,
"Accepted message {} to lane {:?}. Message size: {:?}",
@@ -713,7 +756,7 @@ fn send_message<T: Config<I>, I: 'static>(
Pallet::<T, I>::deposit_event(Event::MessageAccepted { lane_id, nonce });
Ok(SendMessageArtifacts { nonce })
Ok(SendMessageArtifacts { nonce, enqueued_messages })
}
/// Ensure that the pallet is in normal operational mode.
@@ -881,8 +924,9 @@ mod tests {
mock::{
inbound_unrewarded_relayers_state, message, message_payload, run_test,
unrewarded_relayer, AccountId, DbWeight, RuntimeEvent as TestEvent, RuntimeOrigin,
TestDeliveryConfirmationPayments, TestDeliveryPayments, TestMessagesDeliveryProof,
TestMessagesProof, TestRelayer, TestRuntime, TestWeightInfo, MAX_OUTBOUND_PAYLOAD_SIZE,
TestDeliveryConfirmationPayments, TestDeliveryPayments, TestMessageDispatch,
TestMessagesDeliveryProof, TestMessagesProof, TestOnMessagesDelivered, TestRelayer,
TestRuntime, TestWeightInfo, MAX_OUTBOUND_PAYLOAD_SIZE,
PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_LANE_ID_2,
TEST_LANE_ID_3, TEST_RELAYER_A, TEST_RELAYER_B,
},
@@ -908,10 +952,12 @@ mod tests {
fn send_regular_message() {
get_ready_for_events();
let message_nonce =
outbound_lane::<TestRuntime, ()>(TEST_LANE_ID).data().latest_generated_nonce + 1;
send_message::<TestRuntime, ()>(TEST_LANE_ID, REGULAR_PAYLOAD)
let outbound_lane = outbound_lane::<TestRuntime, ()>(TEST_LANE_ID);
let message_nonce = outbound_lane.data().latest_generated_nonce + 1;
let prev_enqueud_messages = outbound_lane.data().queued_messages().saturating_len();
let artifacts = send_message::<TestRuntime, ()>(TEST_LANE_ID, REGULAR_PAYLOAD)
.expect("send_message has failed");
assert_eq!(artifacts.enqueued_messages, prev_enqueud_messages + 1);
// check event with assigned nonce
assert_eq!(
@@ -1201,6 +1247,23 @@ mod tests {
});
}
#[test]
fn receive_messages_fails_if_dispatcher_is_inactive() {
run_test(|| {
TestMessageDispatch::deactivate();
assert_noop!(
Pallet::<TestRuntime>::receive_messages_proof(
RuntimeOrigin::signed(1),
TEST_RELAYER_A,
Ok(vec![message(1, REGULAR_PAYLOAD)]).into(),
1,
REGULAR_PAYLOAD.declared_weight,
),
Error::<TestRuntime, ()>::MessageDispatchInactive,
);
});
}
#[test]
fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enough() {
run_test(|| {
@@ -1304,6 +1367,7 @@ mod tests {
);
assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1));
assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1));
assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 1)));
// this reports delivery of both message 1 and message 2 => reward is paid only to
// TEST_RELAYER_B
@@ -1346,6 +1410,7 @@ mod tests {
);
assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1));
assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1));
assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 0)));
});
}