mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-21 15:35:42 +00:00
Bridges subtree sync (#3022)
* Squashed 'bridges/' changes from edf33a2c85..277f0d5496 277f0d5496 Dynamic fees for bridges-v1 (#2294) b1c51f7dd2 Finality loop refactoring (#2357) 620db2b10f Add equivocation detector crate and implement clients (#2348) (#2353) 3fe4b13eb4 Add basic equivocation detection pipeline schema (#2338) (#2341) git-subtree-dir: bridges git-subtree-split: 277f0d54961c800b231d8123c6445f378b1deb89 * [dynfees] Rococo/Wococo does not need congestion and dynamic fees (for now) * Fix * ".git/.scripts/commands/fmt/fmt.sh" * Forgotten bridges/Cargo.lock --------- Co-authored-by: command-bot <>
This commit is contained in:
@@ -40,10 +40,10 @@ pub use storage_types::StoredAuthoritySet;
|
||||
|
||||
use bp_header_chain::{
|
||||
justification::GrandpaJustification, AuthoritySet, ChainWithGrandpa, GrandpaConsensusLogReader,
|
||||
HeaderChain, HeaderGrandpaInfo, InitializationData, StoredHeaderData, StoredHeaderDataBuilder,
|
||||
HeaderChain, InitializationData, StoredHeaderData, StoredHeaderDataBuilder,
|
||||
StoredHeaderGrandpaInfo,
|
||||
};
|
||||
use bp_runtime::{BlockNumberOf, HashOf, HasherOf, HeaderId, HeaderOf, OwnedBridgeModule};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use frame_support::{dispatch::PostDispatchInfo, ensure, DefaultNoBound};
|
||||
use sp_runtime::{
|
||||
traits::{Header as HeaderT, Zero},
|
||||
@@ -241,9 +241,9 @@ pub mod pallet {
|
||||
Self::deposit_event(Event::UpdatedBestFinalizedHeader {
|
||||
number,
|
||||
hash,
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification,
|
||||
authority_set: maybe_new_authority_set,
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification,
|
||||
new_verification_context: maybe_new_authority_set,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -411,7 +411,7 @@ pub mod pallet {
|
||||
number: BridgedBlockNumber<T, I>,
|
||||
hash: BridgedBlockHash<T, I>,
|
||||
/// The Grandpa info associated to the new best finalized header.
|
||||
grandpa_info: HeaderGrandpaInfo<BridgedHeader<T, I>>,
|
||||
grandpa_info: StoredHeaderGrandpaInfo<BridgedHeader<T, I>>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -505,14 +505,9 @@ pub mod pallet {
|
||||
) -> Result<(), sp_runtime::DispatchError> {
|
||||
use bp_header_chain::justification::verify_justification;
|
||||
|
||||
let voter_set =
|
||||
VoterSet::new(authority_set.authorities).ok_or(<Error<T, I>>::InvalidAuthoritySet)?;
|
||||
let set_id = authority_set.set_id;
|
||||
|
||||
Ok(verify_justification::<BridgedHeader<T, I>>(
|
||||
(hash, number),
|
||||
set_id,
|
||||
&voter_set,
|
||||
&authority_set.try_into().map_err(|_| <Error<T, I>>::InvalidAuthoritySet)?,
|
||||
justification,
|
||||
)
|
||||
.map_err(|e| {
|
||||
@@ -617,7 +612,7 @@ where
|
||||
<T as frame_system::Config>::RuntimeEvent: TryInto<Event<T, I>>,
|
||||
{
|
||||
/// Get the GRANDPA justifications accepted in the current block.
|
||||
pub fn synced_headers_grandpa_info() -> Vec<HeaderGrandpaInfo<BridgedHeader<T, I>>> {
|
||||
pub fn synced_headers_grandpa_info() -> Vec<StoredHeaderGrandpaInfo<BridgedHeader<T, I>>> {
|
||||
frame_system::Pallet::<T>::read_events_no_consensus()
|
||||
.filter_map(|event| {
|
||||
if let Event::<T, I>::UpdatedBestFinalizedHeader { grandpa_info, .. } =
|
||||
@@ -934,9 +929,9 @@ mod tests {
|
||||
event: TestEvent::Grandpa(Event::UpdatedBestFinalizedHeader {
|
||||
number: *header.number(),
|
||||
hash: header.hash(),
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification: justification.clone(),
|
||||
authority_set: None,
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification.clone(),
|
||||
new_verification_context: None,
|
||||
},
|
||||
}),
|
||||
topics: vec![],
|
||||
@@ -944,7 +939,10 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
Pallet::<TestRuntime>::synced_headers_grandpa_info(),
|
||||
vec![HeaderGrandpaInfo { justification, authority_set: None }]
|
||||
vec![StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification,
|
||||
new_verification_context: None
|
||||
}]
|
||||
);
|
||||
})
|
||||
}
|
||||
@@ -1075,9 +1073,11 @@ mod tests {
|
||||
event: TestEvent::Grandpa(Event::UpdatedBestFinalizedHeader {
|
||||
number: *header.number(),
|
||||
hash: header.hash(),
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification: justification.clone(),
|
||||
authority_set: Some(<CurrentAuthoritySet<TestRuntime>>::get().into()),
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification.clone(),
|
||||
new_verification_context: Some(
|
||||
<CurrentAuthoritySet<TestRuntime>>::get().into()
|
||||
),
|
||||
},
|
||||
}),
|
||||
topics: vec![],
|
||||
@@ -1085,9 +1085,11 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
Pallet::<TestRuntime>::synced_headers_grandpa_info(),
|
||||
vec![HeaderGrandpaInfo {
|
||||
justification,
|
||||
authority_set: Some(<CurrentAuthoritySet<TestRuntime>>::get().into()),
|
||||
vec![StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification,
|
||||
new_verification_context: Some(
|
||||
<CurrentAuthoritySet<TestRuntime>>::get().into()
|
||||
),
|
||||
}]
|
||||
);
|
||||
})
|
||||
|
||||
@@ -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)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ use crate::Config;
|
||||
|
||||
use bp_messages::{
|
||||
calc_relayers_rewards,
|
||||
source_chain::{DeliveryConfirmationPayments, LaneMessageVerifier, TargetHeaderChain},
|
||||
source_chain::{
|
||||
DeliveryConfirmationPayments, LaneMessageVerifier, OnMessagesDelivered, TargetHeaderChain,
|
||||
},
|
||||
target_chain::{
|
||||
DeliveryPayments, DispatchMessage, DispatchMessageData, MessageDispatch,
|
||||
ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
|
||||
@@ -161,6 +163,7 @@ impl Config for TestRuntime {
|
||||
type TargetHeaderChain = TestTargetHeaderChain;
|
||||
type LaneMessageVerifier = TestLaneMessageVerifier;
|
||||
type DeliveryConfirmationPayments = TestDeliveryConfirmationPayments;
|
||||
type OnMessagesDelivered = TestOnMessagesDelivered;
|
||||
|
||||
type SourceHeaderChain = TestSourceHeaderChain;
|
||||
type MessageDispatch = TestMessageDispatch;
|
||||
@@ -402,14 +405,26 @@ impl SourceHeaderChain for TestSourceHeaderChain {
|
||||
}
|
||||
}
|
||||
|
||||
/// Source header chain that is used in tests.
|
||||
/// Test message dispatcher.
|
||||
#[derive(Debug)]
|
||||
pub struct TestMessageDispatch;
|
||||
|
||||
impl TestMessageDispatch {
|
||||
pub fn deactivate() {
|
||||
frame_support::storage::unhashed::put(b"TestMessageDispatch.IsCongested", &true)
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageDispatch for TestMessageDispatch {
|
||||
type DispatchPayload = TestPayload;
|
||||
type DispatchLevelResult = TestDispatchLevelResult;
|
||||
|
||||
fn is_active() -> bool {
|
||||
!frame_support::storage::unhashed::get_or_default::<bool>(
|
||||
b"TestMessageDispatch.IsCongested",
|
||||
)
|
||||
}
|
||||
|
||||
fn dispatch_weight(message: &mut DispatchMessage<TestPayload>) -> Weight {
|
||||
match message.data.payload.as_ref() {
|
||||
Ok(payload) => payload.declared_weight,
|
||||
@@ -427,6 +442,24 @@ impl MessageDispatch for TestMessageDispatch {
|
||||
}
|
||||
}
|
||||
|
||||
/// Test callback, called during message delivery confirmation transaction.
|
||||
pub struct TestOnMessagesDelivered;
|
||||
|
||||
impl TestOnMessagesDelivered {
|
||||
pub fn call_arguments() -> Option<(LaneId, MessageNonce)> {
|
||||
frame_support::storage::unhashed::get(b"TestOnMessagesDelivered.OnMessagesDelivered")
|
||||
}
|
||||
}
|
||||
|
||||
impl OnMessagesDelivered for TestOnMessagesDelivered {
|
||||
fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) {
|
||||
frame_support::storage::unhashed::put(
|
||||
b"TestOnMessagesDelivered.OnMessagesDelivered",
|
||||
&(lane, enqueued_messages),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return test lane message with given nonce and payload.
|
||||
pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message {
|
||||
Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, payload: payload.encode() }
|
||||
|
||||
@@ -697,7 +697,7 @@ pub(crate) mod tests {
|
||||
use bp_test_utils::prepare_parachain_heads_proof;
|
||||
use codec::Encode;
|
||||
|
||||
use bp_header_chain::{justification::GrandpaJustification, HeaderGrandpaInfo};
|
||||
use bp_header_chain::{justification::GrandpaJustification, StoredHeaderGrandpaInfo};
|
||||
use bp_parachains::{
|
||||
BestParaHeadHash, BridgeParachainCall, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider,
|
||||
};
|
||||
@@ -1036,9 +1036,9 @@ pub(crate) mod tests {
|
||||
pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
|
||||
number: 1,
|
||||
hash: relay_1_hash,
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification,
|
||||
authority_set: None,
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification,
|
||||
new_verification_context: None,
|
||||
},
|
||||
}
|
||||
),
|
||||
@@ -1177,9 +1177,9 @@ pub(crate) mod tests {
|
||||
pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
|
||||
number: 1,
|
||||
hash: relay_1_hash,
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification,
|
||||
authority_set: None,
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification,
|
||||
new_verification_context: None,
|
||||
}
|
||||
}
|
||||
),
|
||||
@@ -1230,9 +1230,9 @@ pub(crate) mod tests {
|
||||
pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
|
||||
number: 1,
|
||||
hash: relay_1_hash,
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification: justification.clone(),
|
||||
authority_set: None,
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification.clone(),
|
||||
new_verification_context: None,
|
||||
}
|
||||
}
|
||||
),
|
||||
@@ -1271,9 +1271,9 @@ pub(crate) mod tests {
|
||||
pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
|
||||
number: 1,
|
||||
hash: relay_1_hash,
|
||||
grandpa_info: HeaderGrandpaInfo {
|
||||
justification,
|
||||
authority_set: None,
|
||||
grandpa_info: StoredHeaderGrandpaInfo {
|
||||
finality_proof: justification,
|
||||
new_verification_context: None,
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
[package]
|
||||
name = "pallet-xcm-bridge-hub-router"
|
||||
description = "Bridge hub interface for sibling/parent chains with dynamic fees support."
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false }
|
||||
log = { version = "0.4.19", default-features = false }
|
||||
scale-info = { version = "2.8.0", default-features = false, features = ["bit-vec", "derive", "serde"] }
|
||||
|
||||
# Bridge dependencies
|
||||
|
||||
bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false }
|
||||
|
||||
# Substrate Dependencies
|
||||
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
# Polkadot Dependencies
|
||||
|
||||
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
|
||||
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"bp-xcm-bridge-hub-router/std",
|
||||
"codec/std",
|
||||
"frame-benchmarking/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"log/std",
|
||||
"scale-info/std",
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
"xcm/std",
|
||||
"xcm-builder/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-support/try-runtime",
|
||||
"frame-system/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! XCM bridge hub router pallet benchmarks.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use crate::{Bridge, Call};
|
||||
|
||||
use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR};
|
||||
use frame_benchmarking::benchmarks_instance_pallet;
|
||||
use frame_support::{
|
||||
dispatch::UnfilteredDispatchable,
|
||||
traits::{EnsureOrigin, Get, Hooks},
|
||||
};
|
||||
use sp_runtime::traits::Zero;
|
||||
use xcm::prelude::*;
|
||||
|
||||
/// Pallet we're benchmarking here.
|
||||
pub struct Pallet<T: Config<I>, I: 'static = ()>(crate::Pallet<T, I>);
|
||||
|
||||
/// Trait that must be implemented by runtime to be able to benchmark pallet properly.
|
||||
pub trait Config<I: 'static>: crate::Config<I> {
|
||||
/// Fill up queue so it becomes congested.
|
||||
fn make_congested();
|
||||
|
||||
/// Returns destination which is valid for this router instance.
|
||||
/// (Needs to pass `T::Bridges`)
|
||||
/// Make sure that `SendXcm` will pass.
|
||||
fn ensure_bridged_target_destination() -> MultiLocation {
|
||||
MultiLocation::new(
|
||||
Self::UniversalLocation::get().len() as u8,
|
||||
X1(GlobalConsensus(Self::BridgedNetworkId::get().unwrap())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
benchmarks_instance_pallet! {
|
||||
on_initialize_when_non_congested {
|
||||
Bridge::<T, I>::put(BridgeState {
|
||||
is_congested: false,
|
||||
delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR,
|
||||
});
|
||||
}: {
|
||||
crate::Pallet::<T, I>::on_initialize(Zero::zero())
|
||||
}
|
||||
|
||||
on_initialize_when_congested {
|
||||
Bridge::<T, I>::put(BridgeState {
|
||||
is_congested: false,
|
||||
delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR,
|
||||
});
|
||||
T::make_congested();
|
||||
}: {
|
||||
crate::Pallet::<T, I>::on_initialize(Zero::zero())
|
||||
}
|
||||
|
||||
report_bridge_status {
|
||||
Bridge::<T, I>::put(BridgeState::default());
|
||||
|
||||
let origin: T::RuntimeOrigin = T::BridgeHubOrigin::try_successful_origin().expect("expected valid BridgeHubOrigin");
|
||||
let bridge_id = Default::default();
|
||||
let is_congested = true;
|
||||
|
||||
let call = Call::<T, I>::report_bridge_status { bridge_id, is_congested };
|
||||
}: { call.dispatch_bypass_filter(origin)? }
|
||||
verify {
|
||||
assert!(Bridge::<T, I>::get().is_congested);
|
||||
}
|
||||
|
||||
send_message {
|
||||
// make local queue congested, because it means additional db write
|
||||
T::make_congested();
|
||||
|
||||
let dest = T::ensure_bridged_target_destination();
|
||||
let xcm = sp_std::vec![].into();
|
||||
}: {
|
||||
send_xcm::<crate::Pallet<T, I>>(dest, xcm).expect("message is sent")
|
||||
}
|
||||
verify {
|
||||
assert!(Bridge::<T, I>::get().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Pallet that may be used instead of `SovereignPaidRemoteExporter` in the XCM router
|
||||
//! configuration. The main thing that the pallet offers is the dynamic message fee,
|
||||
//! that is computed based on the bridge queues state. It starts exponentially increasing
|
||||
//! if the queue between this chain and the sibling/child bridge hub is congested.
|
||||
//!
|
||||
//! All other bridge hub queues offer some backpressure mechanisms. So if at least one
|
||||
//! of all queues is congested, it will eventually lead to the growth of the queue at
|
||||
//! this chain.
|
||||
//!
|
||||
//! **A note on terminology**: when we mention the bridge hub here, we mean the chain that
|
||||
//! has the messages pallet deployed (`pallet-bridge-grandpa`, `pallet-bridge-messages`,
|
||||
//! `pallet-xcm-bridge-hub`, ...). It may be the system bridge hub parachain or any other
|
||||
//! chain.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use bp_xcm_bridge_hub_router::{
|
||||
BridgeState, XcmChannelStatusProvider, MINIMAL_DELIVERY_FEE_FACTOR,
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_support::traits::Get;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{FixedPointNumber, FixedU128, Saturating};
|
||||
use xcm::prelude::*;
|
||||
use xcm_builder::{ExporterFor, SovereignPaidRemoteExporter};
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
pub mod benchmarking;
|
||||
pub mod weights;
|
||||
|
||||
mod mock;
|
||||
|
||||
/// The factor that is used to increase current message fee factor when bridge experiencing
|
||||
/// some lags.
|
||||
const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05
|
||||
/// The factor that is used to increase current message fee factor for every sent kilobyte.
|
||||
const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001
|
||||
|
||||
/// Maximal size of the XCM message that may be sent over bridge.
|
||||
///
|
||||
/// This should be less than the maximal size, allowed by the messages pallet, because
|
||||
/// the message itself is wrapped in other structs and is double encoded.
|
||||
pub const HARD_MESSAGE_SIZE_LIMIT: u32 = 32 * 1024;
|
||||
|
||||
/// The target that will be used when publishing logs related to this pallet.
|
||||
///
|
||||
/// This doesn't match the pattern used by other bridge pallets (`runtime::bridge-*`). But this
|
||||
/// pallet has significant differences with those pallets. The main one is that is intended to
|
||||
/// be deployed at sending chains. Other bridge pallets are likely to be deployed at the separate
|
||||
/// bridge hub parachain.
|
||||
pub const LOG_TARGET: &str = "xcm::bridge-hub-router";
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config<I: 'static = ()>: frame_system::Config {
|
||||
/// Benchmarks results from runtime we're plugged into.
|
||||
type WeightInfo: WeightInfo;
|
||||
|
||||
/// Universal location of this runtime.
|
||||
type UniversalLocation: Get<InteriorMultiLocation>;
|
||||
/// The bridged network that this config is for if specified.
|
||||
/// Also used for filtering `Bridges` by `BridgedNetworkId`.
|
||||
/// If not specified, allows all networks pass through.
|
||||
type BridgedNetworkId: Get<Option<NetworkId>>;
|
||||
/// Configuration for supported **bridged networks/locations** with **bridge location** and
|
||||
/// **possible fee**. Allows to externalize better control over allowed **bridged
|
||||
/// networks/locations**.
|
||||
type Bridges: ExporterFor;
|
||||
|
||||
/// Origin of the sibling bridge hub that is allowed to report bridge status.
|
||||
type BridgeHubOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
/// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location.
|
||||
type ToBridgeHubSender: SendXcm;
|
||||
/// Underlying channel with the sibling bridge hub. It must match the channel, used
|
||||
/// by the `Self::ToBridgeHubSender`.
|
||||
type WithBridgeHubChannel: XcmChannelStatusProvider;
|
||||
|
||||
/// Additional fee that is paid for every byte of the outbound message.
|
||||
type ByteFee: Get<u128>;
|
||||
/// Asset that is used to paid bridge fee.
|
||||
type FeeAsset: Get<AssetId>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
|
||||
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
|
||||
// TODO: make sure that `WithBridgeHubChannel::is_congested` returns true if either
|
||||
// of XCM channels (outbound/inbound) is suspended. Because if outbound is suspended
|
||||
// that is definitely congestion. If inbound is suspended, then we are not able to
|
||||
// receive the "report_bridge_status" signal (that maybe sent by the bridge hub).
|
||||
|
||||
// if the channel with sibling/child bridge hub is suspended, we don't change
|
||||
// anything
|
||||
if T::WithBridgeHubChannel::is_congested() {
|
||||
return T::WeightInfo::on_initialize_when_congested()
|
||||
}
|
||||
|
||||
// if bridge has reported congestion, we don't change anything
|
||||
let mut bridge = Self::bridge();
|
||||
if bridge.is_congested {
|
||||
return T::WeightInfo::on_initialize_when_congested()
|
||||
}
|
||||
|
||||
// if fee factor is already minimal, we don't change anything
|
||||
if bridge.delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR {
|
||||
return T::WeightInfo::on_initialize_when_congested()
|
||||
}
|
||||
|
||||
let previous_factor = bridge.delivery_fee_factor;
|
||||
bridge.delivery_fee_factor =
|
||||
MINIMAL_DELIVERY_FEE_FACTOR.max(bridge.delivery_fee_factor / EXPONENTIAL_FEE_BASE);
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Bridge queue is uncongested. Decreased fee factor from {} to {}",
|
||||
previous_factor,
|
||||
bridge.delivery_fee_factor,
|
||||
);
|
||||
|
||||
Bridge::<T, I>::put(bridge);
|
||||
T::WeightInfo::on_initialize_when_non_congested()
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
/// Notification about congested bridge queue.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::report_bridge_status())]
|
||||
pub fn report_bridge_status(
|
||||
origin: OriginFor<T>,
|
||||
// this argument is not currently used, but to ease future migration, we'll keep it
|
||||
// here
|
||||
bridge_id: H256,
|
||||
is_congested: bool,
|
||||
) -> DispatchResult {
|
||||
let _ = T::BridgeHubOrigin::ensure_origin(origin)?;
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Received bridge status from {:?}: congested = {}",
|
||||
bridge_id,
|
||||
is_congested,
|
||||
);
|
||||
|
||||
Bridge::<T, I>::mutate(|bridge| {
|
||||
bridge.is_congested = is_congested;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Bridge that we are using.
|
||||
///
|
||||
/// **bridges-v1** assumptions: all outbound messages through this router are using single lane
|
||||
/// and to single remote consensus. If there is some other remote consensus that uses the same
|
||||
/// bridge hub, the separate pallet instance shall be used, In `v2` we'll have all required
|
||||
/// primitives (lane-id aka bridge-id, derived from XCM locations) to support multiple bridges
|
||||
/// by the same pallet instance.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn bridge)]
|
||||
pub type Bridge<T: Config<I>, I: 'static = ()> = StorageValue<_, BridgeState, ValueQuery>;
|
||||
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
/// Called when new message is sent (queued to local outbound XCM queue) over the bridge.
|
||||
pub(crate) fn on_message_sent_to_bridge(message_size: u32) {
|
||||
let _ = Bridge::<T, I>::try_mutate(|bridge| {
|
||||
let is_channel_with_bridge_hub_congested = T::WithBridgeHubChannel::is_congested();
|
||||
let is_bridge_congested = bridge.is_congested;
|
||||
|
||||
// if outbound queue is not congested AND bridge has not reported congestion, do
|
||||
// nothing
|
||||
if !is_channel_with_bridge_hub_congested && !is_bridge_congested {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// ok - we need to increase the fee factor, let's do that
|
||||
let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024))
|
||||
.saturating_mul(MESSAGE_SIZE_FEE_BASE);
|
||||
let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor);
|
||||
let previous_factor = bridge.delivery_fee_factor;
|
||||
bridge.delivery_fee_factor =
|
||||
bridge.delivery_fee_factor.saturating_mul(total_factor);
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Bridge channel is congested. Increased fee factor from {} to {}",
|
||||
previous_factor,
|
||||
bridge.delivery_fee_factor,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// We'll be using `SovereignPaidRemoteExporter` to send remote messages over the sibling/child
|
||||
/// bridge hub.
|
||||
type ViaBridgeHubExporter<T, I> = SovereignPaidRemoteExporter<
|
||||
Pallet<T, I>,
|
||||
<T as Config<I>>::ToBridgeHubSender,
|
||||
<T as Config<I>>::UniversalLocation,
|
||||
>;
|
||||
|
||||
// This pallet acts as the `ExporterFor` for the `SovereignPaidRemoteExporter` to compute
|
||||
// message fee using fee factor.
|
||||
impl<T: Config<I>, I: 'static> ExporterFor for Pallet<T, I> {
|
||||
fn exporter_for(
|
||||
network: &NetworkId,
|
||||
remote_location: &InteriorMultiLocation,
|
||||
message: &Xcm<()>,
|
||||
) -> Option<(MultiLocation, Option<MultiAsset>)> {
|
||||
// ensure that the message is sent to the expected bridged network (if specified).
|
||||
if let Some(bridged_network) = T::BridgedNetworkId::get() {
|
||||
if *network != bridged_network {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"Router with bridged_network_id {:?} does not support bridging to network {:?}!",
|
||||
bridged_network,
|
||||
network,
|
||||
);
|
||||
return None
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the message is sent to the expected bridged network and location.
|
||||
let Some((bridge_hub_location, maybe_payment)) =
|
||||
T::Bridges::exporter_for(network, remote_location, message)
|
||||
else {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"Router with bridged_network_id {:?} does not support bridging to network {:?} and remote_location {:?}!",
|
||||
T::BridgedNetworkId::get(),
|
||||
network,
|
||||
remote_location,
|
||||
);
|
||||
return None
|
||||
};
|
||||
|
||||
// take `base_fee` from `T::Brides`, but it has to be the same `T::FeeAsset`
|
||||
let base_fee = match maybe_payment {
|
||||
Some(payment) => match payment {
|
||||
MultiAsset { fun: Fungible(amount), id } if id.eq(&T::FeeAsset::get()) => amount,
|
||||
invalid_asset => {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"Router with bridged_network_id {:?} is configured for `T::FeeAsset` {:?} which is not \
|
||||
compatible with {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!",
|
||||
T::BridgedNetworkId::get(),
|
||||
T::FeeAsset::get(),
|
||||
invalid_asset,
|
||||
bridge_hub_location,
|
||||
network,
|
||||
remote_location,
|
||||
);
|
||||
return None
|
||||
},
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
|
||||
// compute fee amount. Keep in mind that this is only the bridge fee. The fee for sending
|
||||
// message from this chain to child/sibling bridge hub is determined by the
|
||||
// `Config::ToBridgeHubSender`
|
||||
let message_size = message.encoded_size();
|
||||
let message_fee = (message_size as u128).saturating_mul(T::ByteFee::get());
|
||||
let fee_sum = base_fee.saturating_add(message_fee);
|
||||
let fee_factor = Self::bridge().delivery_fee_factor;
|
||||
let fee = fee_factor.saturating_mul_int(fee_sum);
|
||||
|
||||
let fee = if fee > 0 { Some((T::FeeAsset::get(), fee).into()) } else { None };
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Going to send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}",
|
||||
(network, remote_location),
|
||||
message_size,
|
||||
fee,
|
||||
fee_factor
|
||||
);
|
||||
|
||||
Some((bridge_hub_location, fee))
|
||||
}
|
||||
}
|
||||
|
||||
// This pallet acts as the `SendXcm` to the sibling/child bridge hub instead of regular
|
||||
// XCMP/DMP transport. This allows injecting dynamic message fees into XCM programs that
|
||||
// are going to the bridged network.
|
||||
impl<T: Config<I>, I: 'static> SendXcm for Pallet<T, I> {
|
||||
type Ticket = (u32, <T::ToBridgeHubSender as SendXcm>::Ticket);
|
||||
|
||||
fn validate(
|
||||
dest: &mut Option<MultiLocation>,
|
||||
xcm: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<Self::Ticket> {
|
||||
// we won't have an access to `dest` and `xcm` in the `delvier` method, so precompute
|
||||
// everything required here
|
||||
let message_size = xcm
|
||||
.as_ref()
|
||||
.map(|xcm| xcm.encoded_size() as _)
|
||||
.ok_or(SendError::MissingArgument)?;
|
||||
|
||||
// bridge doesn't support oversized/overweight messages now. So it is better to drop such
|
||||
// messages here than at the bridge hub. Let's check the message size.
|
||||
if message_size > HARD_MESSAGE_SIZE_LIMIT {
|
||||
return Err(SendError::ExceedsMaxMessageSize)
|
||||
}
|
||||
|
||||
// just use exporter to validate destination and insert instructions to pay message fee
|
||||
// at the sibling/child bridge hub
|
||||
//
|
||||
// the cost will include both cost of: (1) to-sibling bridg hub delivery (returned by
|
||||
// the `Config::ToBridgeHubSender`) and (2) to-bridged bridge hub delivery (returned by
|
||||
// `Self::exporter_for`)
|
||||
ViaBridgeHubExporter::<T, I>::validate(dest, xcm)
|
||||
.map(|(ticket, cost)| ((message_size, ticket), cost))
|
||||
}
|
||||
|
||||
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||
// use router to enqueue message to the sibling/child bridge hub. This also should handle
|
||||
// payment for passing through this queue.
|
||||
let (message_size, ticket) = ticket;
|
||||
let xcm_hash = ViaBridgeHubExporter::<T, I>::deliver(ticket)?;
|
||||
|
||||
// increase delivery fee factor if required
|
||||
Self::on_message_sent_to_bridge(message_size);
|
||||
|
||||
Ok(xcm_hash)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use mock::*;
|
||||
|
||||
use frame_support::traits::Hooks;
|
||||
use sp_runtime::traits::One;
|
||||
|
||||
fn congested_bridge(delivery_fee_factor: FixedU128) -> BridgeState {
|
||||
BridgeState { is_congested: true, delivery_fee_factor }
|
||||
}
|
||||
|
||||
fn uncongested_bridge(delivery_fee_factor: FixedU128) -> BridgeState {
|
||||
BridgeState { is_congested: false, delivery_fee_factor }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initial_fee_factor_is_one() {
|
||||
run_test(|| {
|
||||
assert_eq!(
|
||||
Bridge::<TestRuntime, ()>::get(),
|
||||
uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fee_factor_is_not_decreased_from_on_initialize_when_xcm_channel_is_congested() {
|
||||
run_test(|| {
|
||||
Bridge::<TestRuntime, ()>::put(uncongested_bridge(FixedU128::from_rational(125, 100)));
|
||||
TestWithBridgeHubChannel::make_congested();
|
||||
|
||||
// it should not decrease, because xcm channel is congested
|
||||
let old_bridge = XcmBridgeHubRouter::bridge();
|
||||
XcmBridgeHubRouter::on_initialize(One::one());
|
||||
assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fee_factor_is_not_decreased_from_on_initialize_when_bridge_has_reported_congestion() {
|
||||
run_test(|| {
|
||||
Bridge::<TestRuntime, ()>::put(congested_bridge(FixedU128::from_rational(125, 100)));
|
||||
|
||||
// it should not decrease, because bridge congested
|
||||
let old_bridge = XcmBridgeHubRouter::bridge();
|
||||
XcmBridgeHubRouter::on_initialize(One::one());
|
||||
assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() {
|
||||
run_test(|| {
|
||||
Bridge::<TestRuntime, ()>::put(uncongested_bridge(FixedU128::from_rational(125, 100)));
|
||||
|
||||
// it shold eventually decreased to one
|
||||
while XcmBridgeHubRouter::bridge().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR {
|
||||
XcmBridgeHubRouter::on_initialize(One::one());
|
||||
}
|
||||
|
||||
// verify that it doesn't decreases anymore
|
||||
XcmBridgeHubRouter::on_initialize(One::one());
|
||||
assert_eq!(
|
||||
XcmBridgeHubRouter::bridge(),
|
||||
uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_applicable_if_destination_is_within_other_network() {
|
||||
run_test(|| {
|
||||
assert_eq!(
|
||||
send_xcm::<XcmBridgeHubRouter>(
|
||||
MultiLocation::new(2, X2(GlobalConsensus(Rococo), Parachain(1000))),
|
||||
vec![].into(),
|
||||
),
|
||||
Err(SendError::NotApplicable),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exceeds_max_message_size_if_size_is_above_hard_limit() {
|
||||
run_test(|| {
|
||||
assert_eq!(
|
||||
send_xcm::<XcmBridgeHubRouter>(
|
||||
MultiLocation::new(2, X2(GlobalConsensus(Rococo), Parachain(1000))),
|
||||
vec![ClearOrigin; HARD_MESSAGE_SIZE_LIMIT as usize].into(),
|
||||
),
|
||||
Err(SendError::ExceedsMaxMessageSize),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_proper_delivery_price() {
|
||||
run_test(|| {
|
||||
let dest = MultiLocation::new(2, X1(GlobalConsensus(BridgedNetworkId::get())));
|
||||
let xcm: Xcm<()> = vec![ClearOrigin].into();
|
||||
let msg_size = xcm.encoded_size();
|
||||
|
||||
// initially the base fee is used: `BASE_FEE + BYTE_FEE * msg_size + HRMP_FEE`
|
||||
let expected_fee = BASE_FEE + BYTE_FEE * (msg_size as u128) + HRMP_FEE;
|
||||
assert_eq!(
|
||||
XcmBridgeHubRouter::validate(&mut Some(dest), &mut Some(xcm.clone()))
|
||||
.unwrap()
|
||||
.1
|
||||
.get(0),
|
||||
Some(&(BridgeFeeAsset::get(), expected_fee).into()),
|
||||
);
|
||||
|
||||
// but when factor is larger than one, it increases the fee, so it becomes:
|
||||
// `(BASE_FEE + BYTE_FEE * msg_size) * F + HRMP_FEE`
|
||||
let factor = FixedU128::from_rational(125, 100);
|
||||
Bridge::<TestRuntime, ()>::put(uncongested_bridge(factor));
|
||||
let expected_fee =
|
||||
(FixedU128::saturating_from_integer(BASE_FEE + BYTE_FEE * (msg_size as u128)) *
|
||||
factor)
|
||||
.into_inner() / FixedU128::DIV +
|
||||
HRMP_FEE;
|
||||
assert_eq!(
|
||||
XcmBridgeHubRouter::validate(&mut Some(dest), &mut Some(xcm)).unwrap().1.get(0),
|
||||
Some(&(BridgeFeeAsset::get(), expected_fee).into()),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sent_message_doesnt_increase_factor_if_xcm_channel_is_uncongested() {
|
||||
run_test(|| {
|
||||
let old_bridge = XcmBridgeHubRouter::bridge();
|
||||
assert_eq!(
|
||||
send_xcm::<XcmBridgeHubRouter>(
|
||||
MultiLocation::new(
|
||||
2,
|
||||
X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000))
|
||||
),
|
||||
vec![ClearOrigin].into(),
|
||||
)
|
||||
.map(drop),
|
||||
Ok(()),
|
||||
);
|
||||
|
||||
assert!(TestToBridgeHubSender::is_message_sent());
|
||||
assert_eq!(old_bridge, XcmBridgeHubRouter::bridge());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sent_message_increases_factor_if_xcm_channel_is_congested() {
|
||||
run_test(|| {
|
||||
TestWithBridgeHubChannel::make_congested();
|
||||
|
||||
let old_bridge = XcmBridgeHubRouter::bridge();
|
||||
assert_eq!(
|
||||
send_xcm::<XcmBridgeHubRouter>(
|
||||
MultiLocation::new(
|
||||
2,
|
||||
X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000))
|
||||
),
|
||||
vec![ClearOrigin].into(),
|
||||
)
|
||||
.map(drop),
|
||||
Ok(()),
|
||||
);
|
||||
|
||||
assert!(TestToBridgeHubSender::is_message_sent());
|
||||
assert!(
|
||||
old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sent_message_increases_factor_if_bridge_has_reported_congestion() {
|
||||
run_test(|| {
|
||||
Bridge::<TestRuntime, ()>::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR));
|
||||
|
||||
let old_bridge = XcmBridgeHubRouter::bridge();
|
||||
assert_eq!(
|
||||
send_xcm::<XcmBridgeHubRouter>(
|
||||
MultiLocation::new(
|
||||
2,
|
||||
X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000))
|
||||
),
|
||||
vec![ClearOrigin].into(),
|
||||
)
|
||||
.map(drop),
|
||||
Ok(()),
|
||||
);
|
||||
|
||||
assert!(TestToBridgeHubSender::is_message_sent());
|
||||
assert!(
|
||||
old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate as pallet_xcm_bridge_hub_router;
|
||||
|
||||
use bp_xcm_bridge_hub_router::XcmChannelStatusProvider;
|
||||
use frame_support::{construct_runtime, parameter_types};
|
||||
use frame_system::EnsureRoot;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, ConstU128, IdentityLookup},
|
||||
BuildStorage,
|
||||
};
|
||||
use xcm::prelude::*;
|
||||
use xcm_builder::NetworkExportTable;
|
||||
|
||||
pub type AccountId = u64;
|
||||
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
||||
|
||||
/// HRMP fee.
|
||||
pub const HRMP_FEE: u128 = 500;
|
||||
/// Base bridge fee.
|
||||
pub const BASE_FEE: u128 = 1_000_000;
|
||||
/// Byte bridge fee.
|
||||
pub const BYTE_FEE: u128 = 1_000;
|
||||
|
||||
construct_runtime! {
|
||||
pub enum TestRuntime
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
XcmBridgeHubRouter: pallet_xcm_bridge_hub_router::{Pallet, Storage},
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub ThisNetworkId: NetworkId = Polkadot;
|
||||
pub BridgedNetworkId: NetworkId = Kusama;
|
||||
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ThisNetworkId::get()), Parachain(1000));
|
||||
pub SiblingBridgeHubLocation: MultiLocation = ParentThen(X1(Parachain(1002))).into();
|
||||
pub BridgeFeeAsset: AssetId = MultiLocation::parent().into();
|
||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
||||
= vec![(BridgedNetworkId::get(), SiblingBridgeHubLocation::get(), Some((BridgeFeeAsset::get(), BASE_FEE).into()))];
|
||||
}
|
||||
|
||||
impl frame_system::Config for TestRuntime {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type Nonce = u64;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type Block = Block;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BlockHashCount = frame_support::traits::ConstU64<250>;
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = ();
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type SystemWeightInfo = ();
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime {
|
||||
type WeightInfo = ();
|
||||
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type BridgedNetworkId = BridgedNetworkId;
|
||||
type Bridges = NetworkExportTable<BridgeTable>;
|
||||
|
||||
type BridgeHubOrigin = EnsureRoot<AccountId>;
|
||||
type ToBridgeHubSender = TestToBridgeHubSender;
|
||||
type WithBridgeHubChannel = TestWithBridgeHubChannel;
|
||||
|
||||
type ByteFee = ConstU128<BYTE_FEE>;
|
||||
type FeeAsset = BridgeFeeAsset;
|
||||
}
|
||||
|
||||
pub struct TestToBridgeHubSender;
|
||||
|
||||
impl TestToBridgeHubSender {
|
||||
pub fn is_message_sent() -> bool {
|
||||
frame_support::storage::unhashed::get_or_default(b"TestToBridgeHubSender.Sent")
|
||||
}
|
||||
}
|
||||
|
||||
impl SendXcm for TestToBridgeHubSender {
|
||||
type Ticket = ();
|
||||
|
||||
fn validate(
|
||||
_destination: &mut Option<MultiLocation>,
|
||||
_message: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<Self::Ticket> {
|
||||
Ok(((), (BridgeFeeAsset::get(), HRMP_FEE).into()))
|
||||
}
|
||||
|
||||
fn deliver(_ticket: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||
frame_support::storage::unhashed::put(b"TestToBridgeHubSender.Sent", &true);
|
||||
Ok([0u8; 32])
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestWithBridgeHubChannel;
|
||||
|
||||
impl TestWithBridgeHubChannel {
|
||||
pub fn make_congested() {
|
||||
frame_support::storage::unhashed::put(b"TestWithBridgeHubChannel.Congested", &true);
|
||||
}
|
||||
}
|
||||
|
||||
impl XcmChannelStatusProvider for TestWithBridgeHubChannel {
|
||||
fn is_congested() -> bool {
|
||||
frame_support::storage::unhashed::get_or_default(b"TestWithBridgeHubChannel.Congested")
|
||||
}
|
||||
}
|
||||
|
||||
/// Return test externalities to use in tests.
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let t = frame_system::GenesisConfig::<TestRuntime>::default().build_storage().unwrap();
|
||||
sp_io::TestExternalities::new(t)
|
||||
}
|
||||
|
||||
/// Run pallet test.
|
||||
pub fn run_test<T>(test: impl FnOnce() -> T) -> T {
|
||||
new_test_ext().execute_with(|| test())
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Autogenerated weights for pallet_xcm_bridge_hub_router
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-08-03, 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`
|
||||
//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// target/release/millau-bridge-node
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=pallet_xcm_bridge_hub_router
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=Compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./modules/xcm-bridge-hub-router/src/weights.rs
|
||||
// --template=./.maintain/bridge-weight-template.hbs
|
||||
|
||||
#![allow(clippy::all)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use frame_support::{
|
||||
traits::Get,
|
||||
weights::{constants::RocksDbWeight, Weight},
|
||||
};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_xcm_bridge_hub_router.
|
||||
pub trait WeightInfo {
|
||||
fn on_initialize_when_non_congested() -> Weight;
|
||||
fn on_initialize_when_congested() -> Weight;
|
||||
fn report_bridge_status() -> Weight;
|
||||
fn send_message() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets.
|
||||
///
|
||||
/// Those weights are test only and must never be used in production.
|
||||
pub struct BridgeWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
///
|
||||
/// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765`
|
||||
/// (r:1 w:0)
|
||||
///
|
||||
/// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1
|
||||
/// w:0)
|
||||
fn on_initialize_when_non_congested() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `53`
|
||||
// Estimated: `3518`
|
||||
// Minimum execution time: 11_934 nanoseconds.
|
||||
Weight::from_parts(12_201_000, 3518)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
///
|
||||
/// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765`
|
||||
/// (r:1 w:0)
|
||||
///
|
||||
/// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1
|
||||
/// w:0)
|
||||
fn on_initialize_when_congested() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `94`
|
||||
// Estimated: `3559`
|
||||
// Minimum execution time: 9_010 nanoseconds.
|
||||
Weight::from_parts(9_594_000, 3559)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
fn report_bridge_status() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `53`
|
||||
// Estimated: `1502`
|
||||
// Minimum execution time: 10_427 nanoseconds.
|
||||
Weight::from_parts(10_682_000, 1502)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
///
|
||||
/// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765`
|
||||
/// (r:1 w:0)
|
||||
///
|
||||
/// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1
|
||||
/// w:0)
|
||||
fn send_message() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `52`
|
||||
// Estimated: `3517`
|
||||
// Minimum execution time: 19_709 nanoseconds.
|
||||
Weight::from_parts(20_110_000, 3517)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
///
|
||||
/// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765`
|
||||
/// (r:1 w:0)
|
||||
///
|
||||
/// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1
|
||||
/// w:0)
|
||||
fn on_initialize_when_non_congested() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `53`
|
||||
// Estimated: `3518`
|
||||
// Minimum execution time: 11_934 nanoseconds.
|
||||
Weight::from_parts(12_201_000, 3518)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
///
|
||||
/// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765`
|
||||
/// (r:1 w:0)
|
||||
///
|
||||
/// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1
|
||||
/// w:0)
|
||||
fn on_initialize_when_congested() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `94`
|
||||
// Estimated: `3559`
|
||||
// Minimum execution time: 9_010 nanoseconds.
|
||||
Weight::from_parts(9_594_000, 3559)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
fn report_bridge_status() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `53`
|
||||
// Estimated: `1502`
|
||||
// Minimum execution time: 10_427 nanoseconds.
|
||||
Weight::from_parts(10_682_000, 1502)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1)
|
||||
///
|
||||
/// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added:
|
||||
/// 512, mode: `MaxEncodedLen`)
|
||||
///
|
||||
/// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765`
|
||||
/// (r:1 w:0)
|
||||
///
|
||||
/// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1
|
||||
/// w:0)
|
||||
fn send_message() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `52`
|
||||
// Estimated: `3517`
|
||||
// Minimum execution time: 19_709 nanoseconds.
|
||||
Weight::from_parts(20_110_000, 3517)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user