mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 23:31:07 +00:00
Remove message fee + message send calls (#1642)
* remove message fee * it is compiling! * fixes + fmt * more cleanup * more cleanup * restore MessageDeliveryAndDispatchPayment since we'll need relayer rewards * started rational relayer removal * more removal * removed estimate fee subcommand * remove DispatchFeePayment * more removals * removed conversion rates && some metrics * - unneeded associated type * - OutboundMessageFee * fix benchmarks compilation * fmt * test + fix benchmarks * fix send message * clippy
This commit is contained in:
committed by
Bastian Köcher
parent
1217b2cf80
commit
8c845602cf
@@ -32,18 +32,8 @@ pub mod rialto_messages;
|
||||
pub mod rialto_parachain_messages;
|
||||
pub mod xcm_config;
|
||||
|
||||
use crate::{
|
||||
rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge},
|
||||
rialto_parachain_messages::{
|
||||
ToRialtoParachainMessagePayload, WithRialtoParachainMessageBridge,
|
||||
},
|
||||
};
|
||||
|
||||
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
|
||||
use bp_runtime::{HeaderId, HeaderIdProvider};
|
||||
use bridge_runtime_common::messages::{
|
||||
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
|
||||
};
|
||||
use codec::Decode;
|
||||
use pallet_grandpa::{
|
||||
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
|
||||
@@ -57,7 +47,7 @@ use sp_runtime::{
|
||||
create_runtime_str, generic, impl_opaque_keys,
|
||||
traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perquintill,
|
||||
ApplyExtrinsicResult, FixedPointNumber, Perquintill,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
#[cfg(feature = "std")]
|
||||
@@ -476,9 +466,6 @@ parameter_types! {
|
||||
bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce =
|
||||
bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
|
||||
// `IdentityFee` is used by Millau => we may use weight directly
|
||||
pub const GetDeliveryConfirmationTransactionFee: Balance =
|
||||
bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() as _;
|
||||
pub const RootAccountForPayments: Option<AccountId> = None;
|
||||
pub const RialtoChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
|
||||
pub const RialtoParachainChainId: bp_runtime::ChainId = bp_runtime::RIALTO_PARACHAIN_CHAIN_ID;
|
||||
@@ -490,17 +477,14 @@ pub type WithRialtoMessagesInstance = ();
|
||||
impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
|
||||
type Parameter = rialto_messages::MillauToRialtoMessagesParameter;
|
||||
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
|
||||
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
|
||||
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
|
||||
|
||||
type MaximalOutboundPayloadSize = crate::rialto_messages::ToRialtoMaximalOutboundPayloadSize;
|
||||
type OutboundPayload = crate::rialto_messages::ToRialtoMessagePayload;
|
||||
type OutboundMessageFee = Balance;
|
||||
|
||||
type InboundPayload = crate::rialto_messages::FromRialtoMessagePayload;
|
||||
type InboundMessageFee = bp_rialto::Balance;
|
||||
type InboundRelayer = bp_rialto::AccountId;
|
||||
|
||||
type TargetHeaderChain = crate::rialto_messages::Rialto;
|
||||
@@ -509,7 +493,6 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
|
||||
pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
|
||||
Runtime,
|
||||
WithRialtoMessagesInstance,
|
||||
GetDeliveryConfirmationTransactionFee,
|
||||
>;
|
||||
type OnMessageAccepted = ();
|
||||
type OnDeliveryConfirmed = ();
|
||||
@@ -525,7 +508,6 @@ pub type WithRialtoParachainMessagesInstance = pallet_bridge_messages::Instance1
|
||||
impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
|
||||
type Parameter = rialto_parachain_messages::MillauToRialtoParachainMessagesParameter;
|
||||
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
|
||||
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
|
||||
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
|
||||
@@ -533,10 +515,8 @@ impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Run
|
||||
type MaximalOutboundPayloadSize =
|
||||
crate::rialto_parachain_messages::ToRialtoParachainMaximalOutboundPayloadSize;
|
||||
type OutboundPayload = crate::rialto_parachain_messages::ToRialtoParachainMessagePayload;
|
||||
type OutboundMessageFee = Balance;
|
||||
|
||||
type InboundPayload = crate::rialto_parachain_messages::FromRialtoParachainMessagePayload;
|
||||
type InboundMessageFee = bp_rialto_parachain::Balance;
|
||||
type InboundRelayer = bp_rialto_parachain::AccountId;
|
||||
|
||||
type TargetHeaderChain = crate::rialto_parachain_messages::RialtoParachain;
|
||||
@@ -545,7 +525,6 @@ impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Run
|
||||
pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
|
||||
Runtime,
|
||||
WithRialtoParachainMessagesInstance,
|
||||
GetDeliveryConfirmationTransactionFee,
|
||||
>;
|
||||
type OnMessageAccepted = ();
|
||||
type OnDeliveryConfirmed = ();
|
||||
@@ -941,24 +920,12 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_rialto::ToRialtoOutboundLaneApi<Block, Balance, ToRialtoMessagePayload> for Runtime {
|
||||
fn estimate_message_delivery_and_dispatch_fee(
|
||||
_lane_id: bp_messages::LaneId,
|
||||
payload: ToRialtoMessagePayload,
|
||||
rialto_to_this_conversion_rate: Option<FixedU128>,
|
||||
) -> Option<Balance> {
|
||||
estimate_message_dispatch_and_delivery_fee::<WithRialtoMessageBridge>(
|
||||
&payload,
|
||||
WithRialtoMessageBridge::RELAYER_FEE_PERCENT,
|
||||
rialto_to_this_conversion_rate,
|
||||
).ok()
|
||||
}
|
||||
|
||||
impl bp_rialto::ToRialtoOutboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
begin: bp_messages::MessageNonce,
|
||||
end: bp_messages::MessageNonce,
|
||||
) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
|
||||
) -> Vec<bp_messages::OutboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::outbound_message_details::<
|
||||
Runtime,
|
||||
WithRialtoMessagesInstance,
|
||||
@@ -966,10 +933,10 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_rialto::FromRialtoInboundLaneApi<Block, bp_rialto::Balance> for Runtime {
|
||||
impl bp_rialto::FromRialtoInboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_rialto::Balance>)>,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
|
||||
) -> Vec<bp_messages::InboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::inbound_message_details::<
|
||||
Runtime,
|
||||
@@ -978,24 +945,12 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_rialto_parachain::ToRialtoParachainOutboundLaneApi<Block, Balance, ToRialtoParachainMessagePayload> for Runtime {
|
||||
fn estimate_message_delivery_and_dispatch_fee(
|
||||
_lane_id: bp_messages::LaneId,
|
||||
payload: ToRialtoParachainMessagePayload,
|
||||
rialto_parachain_to_this_conversion_rate: Option<FixedU128>,
|
||||
) -> Option<Balance> {
|
||||
estimate_message_dispatch_and_delivery_fee::<WithRialtoParachainMessageBridge>(
|
||||
&payload,
|
||||
WithRialtoParachainMessageBridge::RELAYER_FEE_PERCENT,
|
||||
rialto_parachain_to_this_conversion_rate,
|
||||
).ok()
|
||||
}
|
||||
|
||||
impl bp_rialto_parachain::ToRialtoParachainOutboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
begin: bp_messages::MessageNonce,
|
||||
end: bp_messages::MessageNonce,
|
||||
) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
|
||||
) -> Vec<bp_messages::OutboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::outbound_message_details::<
|
||||
Runtime,
|
||||
WithRialtoParachainMessagesInstance,
|
||||
@@ -1003,10 +958,10 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_rialto_parachain::FromRialtoParachainInboundLaneApi<Block, bp_rialto_parachain::Balance> for Runtime {
|
||||
impl bp_rialto_parachain::FromRialtoParachainInboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_rialto_parachain::Balance>)>,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
|
||||
) -> Vec<bp_messages::InboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::inbound_message_details::<
|
||||
Runtime,
|
||||
@@ -1060,13 +1015,11 @@ impl_runtime_apis! {
|
||||
let mut batches = Vec::<BenchmarkBatch>::new();
|
||||
let params = (&config, &whitelist);
|
||||
|
||||
use bridge_runtime_common::messages_benchmarking::{prepare_message_delivery_proof, prepare_message_proof, prepare_outbound_message};
|
||||
use bridge_runtime_common::messages;
|
||||
use bridge_runtime_common::messages_benchmarking::{prepare_message_delivery_proof, prepare_message_proof};
|
||||
use pallet_bridge_messages::benchmarking::{
|
||||
Pallet as MessagesBench,
|
||||
Config as MessagesConfig,
|
||||
MessageDeliveryProofParams,
|
||||
MessageParams,
|
||||
MessageProofParams,
|
||||
};
|
||||
use pallet_bridge_parachains::benchmarking::{
|
||||
@@ -1076,18 +1029,10 @@ impl_runtime_apis! {
|
||||
use rialto_messages::WithRialtoMessageBridge;
|
||||
|
||||
impl MessagesConfig<WithRialtoMessagesInstance> for Runtime {
|
||||
fn maximal_message_size() -> u32 {
|
||||
messages::source::maximal_message_size::<WithRialtoMessageBridge>()
|
||||
}
|
||||
|
||||
fn bridged_relayer_id() -> Self::InboundRelayer {
|
||||
[0u8; 32].into()
|
||||
}
|
||||
|
||||
fn account_balance(account: &Self::AccountId) -> Self::OutboundMessageFee {
|
||||
pallet_balances::Pallet::<Runtime>::free_balance(account)
|
||||
}
|
||||
|
||||
fn endow_account(account: &Self::AccountId) {
|
||||
pallet_balances::Pallet::<Runtime>::make_free_balance_be(
|
||||
account,
|
||||
@@ -1095,12 +1040,6 @@ impl_runtime_apis! {
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_outbound_message(
|
||||
params: MessageParams<Self::AccountId>,
|
||||
) -> (rialto_messages::ToRialtoMessagePayload, Balance) {
|
||||
(prepare_outbound_message::<WithRialtoMessageBridge>(params), Self::message_fee())
|
||||
}
|
||||
|
||||
fn prepare_message_proof(
|
||||
params: MessageProofParams,
|
||||
) -> (rialto_messages::FromRialtoMessagesProof, Weight) {
|
||||
|
||||
@@ -21,35 +21,20 @@ use crate::{OriginCaller, RialtoGrandpaInstance, Runtime, RuntimeCall, RuntimeOr
|
||||
use bp_messages::{
|
||||
source_chain::TargetHeaderChain,
|
||||
target_chain::{ProvedMessages, SourceHeaderChain},
|
||||
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
||||
InboundLaneData, LaneId, Message, MessageNonce,
|
||||
};
|
||||
use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID};
|
||||
use bridge_runtime_common::messages::{
|
||||
self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
|
||||
use sp_std::convert::TryFrom;
|
||||
use bridge_runtime_common::messages::{self, MessageBridge};
|
||||
use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
|
||||
|
||||
/// Default lane that is used to send messages to Rialto.
|
||||
pub const DEFAULT_XCM_LANE_TO_RIALTO: LaneId = [0, 0, 0, 0];
|
||||
/// Initial value of `RialtoToMillauConversionRate` parameter.
|
||||
pub const INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE: FixedU128 =
|
||||
FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Initial value of `RialtoFeeMultiplier` parameter.
|
||||
pub const INITIAL_RIALTO_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual
|
||||
/// tests, confirming that we don't break encoding somewhere between.
|
||||
pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::xcm_config::BASE_XCM_WEIGHT;
|
||||
|
||||
parameter_types! {
|
||||
/// Rialto to Millau conversion rate. Initially we treat both tokens as equal.
|
||||
pub storage RialtoToMillauConversionRate: FixedU128 = INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE;
|
||||
/// Fee multiplier value at Rialto chain.
|
||||
pub storage RialtoFeeMultiplier: FixedU128 = INITIAL_RIALTO_FEE_MULTIPLIER;
|
||||
/// Weight credit for our test messages.
|
||||
///
|
||||
/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
@@ -91,7 +76,6 @@ pub type ToRialtoMaximalOutboundPayloadSize =
|
||||
pub struct WithRialtoMessageBridge;
|
||||
|
||||
impl MessageBridge for WithRialtoMessageBridge {
|
||||
const RELAYER_FEE_PERCENT: u32 = 10;
|
||||
const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
|
||||
const BRIDGED_CHAIN_ID: ChainId = RIALTO_CHAIN_ID;
|
||||
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME;
|
||||
@@ -100,16 +84,6 @@ impl MessageBridge for WithRialtoMessageBridge {
|
||||
type BridgedChain = Rialto;
|
||||
type BridgedHeaderChain =
|
||||
pallet_bridge_grandpa::GrandpaChainHeaders<Runtime, RialtoGrandpaInstance>;
|
||||
|
||||
fn bridged_balance_to_this_balance(
|
||||
bridged_balance: bp_rialto::Balance,
|
||||
bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> bp_millau::Balance {
|
||||
let conversion_rate = bridged_to_this_conversion_rate_override
|
||||
.unwrap_or_else(RialtoToMillauConversionRate::get);
|
||||
bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
|
||||
.unwrap_or(bp_millau::Balance::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
/// Millau chain from message lane point of view.
|
||||
@@ -123,12 +97,6 @@ impl messages::UnderlyingChainProvider for Millau {
|
||||
impl messages::ThisChainWithMessages for Millau {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
|
||||
bp_millau::AccountId,
|
||||
{ bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
|
||||
{ bp_rialto::EXTRA_STORAGE_PROOF_SIZE },
|
||||
{ bp_millau::TX_EXTRA_BYTES },
|
||||
>;
|
||||
|
||||
fn is_message_accepted(send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
|
||||
let here_location =
|
||||
@@ -153,21 +121,6 @@ impl messages::ThisChainWithMessages for Millau {
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
MessageNonce::MAX
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
|
||||
// `transaction` may represent transaction from the future, when multiplier value will
|
||||
// be larger, so let's use slightly increased value
|
||||
let multiplier = FixedU128::saturating_from_rational(110, 100)
|
||||
.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rialto chain from message lane point of view.
|
||||
@@ -182,45 +135,6 @@ impl messages::BridgedChainWithMessages for Rialto {
|
||||
fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn estimate_delivery_transaction(
|
||||
message_payload: &[u8],
|
||||
include_pay_dispatch_fee_cost: bool,
|
||||
message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight> {
|
||||
let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
|
||||
let extra_bytes_in_payload = message_payload_len
|
||||
.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
|
||||
|
||||
MessageTransaction {
|
||||
dispatch_weight: bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
|
||||
.saturating_mul(extra_bytes_in_payload as u64)
|
||||
.saturating_add(bp_rialto::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
|
||||
.saturating_sub(if include_pay_dispatch_fee_cost {
|
||||
Weight::from_ref_time(0)
|
||||
} else {
|
||||
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT
|
||||
})
|
||||
.saturating_add(message_dispatch_weight),
|
||||
size: message_payload_len
|
||||
.saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE)
|
||||
.saturating_add(bp_rialto::TX_EXTRA_BYTES),
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_rialto::Balance {
|
||||
// we don't have a direct access to the value of multiplier at Rialto chain
|
||||
// => it is a messages module parameter
|
||||
let multiplier = RialtoFeeMultiplier::get();
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_rialto::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetHeaderChain<ToRialtoMessagePayload, bp_millau::AccountId> for Rialto {
|
||||
@@ -242,7 +156,7 @@ impl TargetHeaderChain<ToRialtoMessagePayload, bp_millau::AccountId> for Rialto
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
|
||||
impl SourceHeaderChain for Rialto {
|
||||
type Error = &'static str;
|
||||
// The proof is:
|
||||
// - hash of the header this proof has been created with;
|
||||
@@ -254,28 +168,12 @@ impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
|
||||
fn verify_messages_proof(
|
||||
proof: Self::MessagesProof,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<bp_rialto::Balance>>, Self::Error> {
|
||||
) -> Result<ProvedMessages<Message>, Self::Error> {
|
||||
messages::target::verify_messages_proof::<WithRialtoMessageBridge>(proof, messages_count)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Millau -> Rialto message lane pallet parameters.
|
||||
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||
pub enum MillauToRialtoMessagesParameter {
|
||||
/// The conversion formula we use is: `MillauTokens = RialtoTokens * conversion_rate`.
|
||||
RialtoToMillauConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl MessagesParameter for MillauToRialtoMessagesParameter {
|
||||
fn save(&self) {
|
||||
match *self {
|
||||
MillauToRialtoMessagesParameter::RialtoToMillauConversionRate(ref conversion_rate) =>
|
||||
RialtoToMillauConversionRate::set(conversion_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -295,13 +193,7 @@ mod tests {
|
||||
fn ensure_millau_message_lane_weights_are_correct() {
|
||||
type Weights = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
|
||||
|
||||
pallet_bridge_messages::ensure_weights_are_correct::<Weights>(
|
||||
bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
|
||||
bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
|
||||
bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
|
||||
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
|
||||
DbWeight::get(),
|
||||
);
|
||||
pallet_bridge_messages::ensure_weights_are_correct::<Weights>();
|
||||
|
||||
let max_incoming_message_proof_size = bp_rialto::EXTRA_STORAGE_PROOF_SIZE.saturating_add(
|
||||
messages::target::maximal_incoming_message_size(bp_millau::Millau::max_extrinsic_size()),
|
||||
@@ -366,13 +258,5 @@ mod tests {
|
||||
bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME,
|
||||
},
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
RialtoToMillauConversionRate::key().to_vec(),
|
||||
bp_runtime::storage_parameter_key(
|
||||
bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME
|
||||
)
|
||||
.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,11 @@ use crate::{Runtime, RuntimeCall, RuntimeOrigin, WithRialtoParachainsInstance};
|
||||
use bp_messages::{
|
||||
source_chain::TargetHeaderChain,
|
||||
target_chain::{ProvedMessages, SourceHeaderChain},
|
||||
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
||||
InboundLaneData, LaneId, Message, MessageNonce,
|
||||
};
|
||||
use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID};
|
||||
use bridge_runtime_common::messages::{
|
||||
self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
|
||||
use sp_std::convert::TryFrom;
|
||||
use bridge_runtime_common::messages::{self, MessageBridge};
|
||||
use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
|
||||
|
||||
/// Default lane that is used to send messages to Rialto parachain.
|
||||
pub const DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN: LaneId = [0, 0, 0, 0];
|
||||
@@ -40,18 +34,7 @@ pub const DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN: LaneId = [0, 0, 0, 0];
|
||||
/// tests, confirming that we don't break encoding somewhere between.
|
||||
pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::xcm_config::BASE_XCM_WEIGHT;
|
||||
|
||||
/// Initial value of `RialtoParachainToMillauConversionRate` parameter.
|
||||
pub const INITIAL_RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE: FixedU128 =
|
||||
FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Initial value of `RialtoParachainFeeMultiplier` parameter.
|
||||
pub const INITIAL_RIALTO_PARACHAIN_FEE_MULTIPLIER: FixedU128 =
|
||||
FixedU128::from_inner(FixedU128::DIV);
|
||||
|
||||
parameter_types! {
|
||||
/// RialtoParachain to Millau conversion rate. Initially we treat both tokens as equal.
|
||||
pub storage RialtoParachainToMillauConversionRate: FixedU128 = INITIAL_RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE;
|
||||
/// Fee multiplier value at RialtoParachain chain.
|
||||
pub storage RialtoParachainFeeMultiplier: FixedU128 = INITIAL_RIALTO_PARACHAIN_FEE_MULTIPLIER;
|
||||
/// Weight credit for our test messages.
|
||||
///
|
||||
/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
@@ -95,7 +78,6 @@ pub type ToRialtoParachainMaximalOutboundPayloadSize =
|
||||
pub struct WithRialtoParachainMessageBridge;
|
||||
|
||||
impl MessageBridge for WithRialtoParachainMessageBridge {
|
||||
const RELAYER_FEE_PERCENT: u32 = 10;
|
||||
const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
|
||||
const BRIDGED_CHAIN_ID: ChainId = RIALTO_PARACHAIN_CHAIN_ID;
|
||||
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME;
|
||||
@@ -107,16 +89,6 @@ impl MessageBridge for WithRialtoParachainMessageBridge {
|
||||
WithRialtoParachainsInstance,
|
||||
bp_rialto_parachain::RialtoParachain,
|
||||
>;
|
||||
|
||||
fn bridged_balance_to_this_balance(
|
||||
bridged_balance: bp_rialto_parachain::Balance,
|
||||
bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> bp_millau::Balance {
|
||||
let conversion_rate = bridged_to_this_conversion_rate_override
|
||||
.unwrap_or_else(RialtoParachainToMillauConversionRate::get);
|
||||
bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
|
||||
.unwrap_or(bp_millau::Balance::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
/// Millau chain from message lane point of view.
|
||||
@@ -130,12 +102,6 @@ impl messages::UnderlyingChainProvider for Millau {
|
||||
impl messages::ThisChainWithMessages for Millau {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
|
||||
bp_rialto_parachain::AccountId,
|
||||
{ bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
|
||||
{ bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE },
|
||||
{ bp_millau::TX_EXTRA_BYTES },
|
||||
>;
|
||||
|
||||
fn is_message_accepted(_send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
|
||||
*lane == DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN || *lane == [0, 0, 0, 1]
|
||||
@@ -144,21 +110,6 @@ impl messages::ThisChainWithMessages for Millau {
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
MessageNonce::MAX
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
|
||||
// `transaction` may represent transaction from the future, when multiplier value will
|
||||
// be larger, so let's use slightly increased value
|
||||
let multiplier = FixedU128::saturating_from_rational(110, 100)
|
||||
.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// RialtoParachain chain from message lane point of view.
|
||||
@@ -173,49 +124,6 @@ impl messages::BridgedChainWithMessages for RialtoParachain {
|
||||
fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn estimate_delivery_transaction(
|
||||
message_payload: &[u8],
|
||||
include_pay_dispatch_fee_cost: bool,
|
||||
message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight> {
|
||||
let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
|
||||
let extra_bytes_in_payload = message_payload_len
|
||||
.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
|
||||
|
||||
MessageTransaction {
|
||||
dispatch_weight: bp_rialto_parachain::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
|
||||
.saturating_mul(extra_bytes_in_payload as _)
|
||||
.saturating_add(bp_rialto_parachain::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
|
||||
.saturating_sub(if include_pay_dispatch_fee_cost {
|
||||
Weight::from_ref_time(0)
|
||||
} else {
|
||||
bp_rialto_parachain::PAY_INBOUND_DISPATCH_FEE_WEIGHT
|
||||
})
|
||||
.saturating_add(message_dispatch_weight),
|
||||
size: message_payload_len
|
||||
.saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE)
|
||||
.saturating_add(bp_rialto_parachain::TX_EXTRA_BYTES),
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_payment(
|
||||
transaction: MessageTransaction<Weight>,
|
||||
) -> bp_rialto_parachain::Balance {
|
||||
// we don't have a direct access to the value of multiplier at RialtoParachain chain
|
||||
// => it is a messages module parameter
|
||||
let multiplier = RialtoParachainFeeMultiplier::get();
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_rialto_parachain::BlockWeights::get()
|
||||
.get(DispatchClass::Normal)
|
||||
.base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetHeaderChain<ToRialtoParachainMessagePayload, bp_millau::AccountId> for RialtoParachain {
|
||||
@@ -237,7 +145,7 @@ impl TargetHeaderChain<ToRialtoParachainMessagePayload, bp_millau::AccountId> fo
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceHeaderChain<bp_rialto_parachain::Balance> for RialtoParachain {
|
||||
impl SourceHeaderChain for RialtoParachain {
|
||||
type Error = &'static str;
|
||||
// The proof is:
|
||||
// - hash of the header this proof has been created with;
|
||||
@@ -249,7 +157,7 @@ impl SourceHeaderChain<bp_rialto_parachain::Balance> for RialtoParachain {
|
||||
fn verify_messages_proof(
|
||||
proof: Self::MessagesProof,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<bp_rialto_parachain::Balance>>, Self::Error> {
|
||||
) -> Result<ProvedMessages<Message>, Self::Error> {
|
||||
messages::target::verify_messages_proof::<WithRialtoParachainMessageBridge>(
|
||||
proof,
|
||||
messages_count,
|
||||
@@ -257,20 +165,3 @@ impl SourceHeaderChain<bp_rialto_parachain::Balance> for RialtoParachain {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Millau -> RialtoParachain message lane pallet parameters.
|
||||
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||
pub enum MillauToRialtoParachainMessagesParameter {
|
||||
/// The conversion formula we use is: `MillauTokens = RialtoParachainTokens * conversion_rate`.
|
||||
RialtoParachainToMillauConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl MessagesParameter for MillauToRialtoParachainMessagesParameter {
|
||||
fn save(&self) {
|
||||
match *self {
|
||||
MillauToRialtoParachainMessagesParameter::RialtoParachainToMillauConversionRate(
|
||||
ref conversion_rate,
|
||||
) => RialtoParachainToMillauConversionRate::set(conversion_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ mod tests {
|
||||
fn xcm_messages_are_sent_using_bridge_router() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let xcm: Xcm<()> = vec![Instruction::Trap(42)].into();
|
||||
let expected_fee = MultiAssets::from((Here, 4_259_858_152_u64));
|
||||
let expected_fee = MultiAssets::from((Here, 1_000_000_u128));
|
||||
let expected_hash =
|
||||
([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256);
|
||||
|
||||
@@ -305,7 +305,7 @@ mod tests {
|
||||
|
||||
let mut incoming_message = DispatchMessage {
|
||||
key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
|
||||
data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 },
|
||||
data: DispatchMessageData { payload: Ok((location, xcm).into()) },
|
||||
};
|
||||
|
||||
let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message);
|
||||
|
||||
@@ -26,14 +26,9 @@
|
||||
#[cfg(feature = "std")]
|
||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
|
||||
use crate::millau_messages::{
|
||||
ToMillauMessagePayload, WithMillauMessageBridge, DEFAULT_XCM_LANE_TO_MILLAU,
|
||||
};
|
||||
use crate::millau_messages::{WithMillauMessageBridge, DEFAULT_XCM_LANE_TO_MILLAU};
|
||||
|
||||
use bridge_runtime_common::messages::{
|
||||
source::{estimate_message_dispatch_and_delivery_fee, XcmBridge, XcmBridgeAdapter},
|
||||
MessageBridge,
|
||||
};
|
||||
use bridge_runtime_common::messages::source::{XcmBridge, XcmBridgeAdapter};
|
||||
use cumulus_pallet_parachain_system::AnyRelayNumber;
|
||||
use sp_api::impl_runtime_apis;
|
||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
||||
@@ -41,7 +36,7 @@ use sp_runtime::{
|
||||
create_runtime_str, generic, impl_opaque_keys,
|
||||
traits::{AccountIdLookup, Block as BlockT},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedU128,
|
||||
ApplyExtrinsicResult,
|
||||
};
|
||||
|
||||
use sp_std::prelude::*;
|
||||
@@ -557,9 +552,6 @@ parameter_types! {
|
||||
bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce =
|
||||
bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
|
||||
// `IdentityFee` is used by Rialto => we may use weight directly
|
||||
pub const GetDeliveryConfirmationTransactionFee: Balance =
|
||||
bp_rialto_parachain::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() as _;
|
||||
pub const RootAccountForPayments: Option<AccountId> = None;
|
||||
pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
|
||||
}
|
||||
@@ -570,17 +562,14 @@ pub type WithMillauMessagesInstance = ();
|
||||
impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
|
||||
type Parameter = millau_messages::RialtoParachainToMillauMessagesParameter;
|
||||
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
|
||||
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
|
||||
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
|
||||
|
||||
type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize;
|
||||
type OutboundPayload = crate::millau_messages::ToMillauMessagePayload;
|
||||
type OutboundMessageFee = Balance;
|
||||
|
||||
type InboundPayload = crate::millau_messages::FromMillauMessagePayload;
|
||||
type InboundMessageFee = bp_millau::Balance;
|
||||
type InboundRelayer = bp_millau::AccountId;
|
||||
|
||||
type TargetHeaderChain = crate::millau_messages::Millau;
|
||||
@@ -589,7 +578,6 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
|
||||
pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
|
||||
Runtime,
|
||||
WithMillauMessagesInstance,
|
||||
GetDeliveryConfirmationTransactionFee,
|
||||
>;
|
||||
type OnMessageAccepted = ();
|
||||
type OnDeliveryConfirmed = ();
|
||||
@@ -748,24 +736,12 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_millau::ToMillauOutboundLaneApi<Block, Balance, ToMillauMessagePayload> for Runtime {
|
||||
fn estimate_message_delivery_and_dispatch_fee(
|
||||
_lane_id: bp_messages::LaneId,
|
||||
payload: ToMillauMessagePayload,
|
||||
millau_to_this_conversion_rate: Option<FixedU128>,
|
||||
) -> Option<Balance> {
|
||||
estimate_message_dispatch_and_delivery_fee::<WithMillauMessageBridge>(
|
||||
&payload,
|
||||
WithMillauMessageBridge::RELAYER_FEE_PERCENT,
|
||||
millau_to_this_conversion_rate,
|
||||
).ok()
|
||||
}
|
||||
|
||||
impl bp_millau::ToMillauOutboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
begin: bp_messages::MessageNonce,
|
||||
end: bp_messages::MessageNonce,
|
||||
) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
|
||||
) -> Vec<bp_messages::OutboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::outbound_message_details::<
|
||||
Runtime,
|
||||
WithMillauMessagesInstance,
|
||||
@@ -773,10 +749,10 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_millau::FromMillauInboundLaneApi<Block, bp_millau::Balance> for Runtime {
|
||||
impl bp_millau::FromMillauInboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_millau::Balance>)>,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
|
||||
) -> Vec<bp_messages::InboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::inbound_message_details::<
|
||||
Runtime,
|
||||
@@ -882,7 +858,7 @@ mod tests {
|
||||
let xcm: Xcm<()> = vec![Instruction::Trap(42)].into();
|
||||
|
||||
let send_result = send_xcm::<XcmRouter>(dest.into(), xcm);
|
||||
let expected_fee = MultiAssets::from((Here, Fungibility::Fungible(4_259_858_152_u128)));
|
||||
let expected_fee = MultiAssets::from((Here, Fungibility::Fungible(1_000_000_u128)));
|
||||
let expected_hash =
|
||||
([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256);
|
||||
assert_eq!(send_result, Ok((expected_hash, expected_fee)),);
|
||||
@@ -906,7 +882,7 @@ mod tests {
|
||||
|
||||
let mut incoming_message = DispatchMessage {
|
||||
key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
|
||||
data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 },
|
||||
data: DispatchMessageData { payload: Ok((location, xcm).into()) },
|
||||
};
|
||||
|
||||
let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message);
|
||||
|
||||
@@ -24,35 +24,20 @@ use crate::{MillauGrandpaInstance, OriginCaller, Runtime, RuntimeCall, RuntimeOr
|
||||
use bp_messages::{
|
||||
source_chain::TargetHeaderChain,
|
||||
target_chain::{ProvedMessages, SourceHeaderChain},
|
||||
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
||||
InboundLaneData, LaneId, Message, MessageNonce,
|
||||
};
|
||||
use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID};
|
||||
use bridge_runtime_common::messages::{
|
||||
self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
|
||||
use sp_std::convert::TryFrom;
|
||||
use bridge_runtime_common::messages::{self, MessageBridge};
|
||||
use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
|
||||
|
||||
/// Default lane that is used to send messages to Millau.
|
||||
pub const DEFAULT_XCM_LANE_TO_MILLAU: LaneId = [0, 0, 0, 0];
|
||||
/// Initial value of `MillauToRialtoParachainConversionRate` parameter.
|
||||
pub const INITIAL_MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE: FixedU128 =
|
||||
FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Initial value of `MillauFeeMultiplier` parameter.
|
||||
pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual
|
||||
/// tests, confirming that we don't break encoding somewhere between.
|
||||
pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::BASE_XCM_WEIGHT;
|
||||
|
||||
parameter_types! {
|
||||
/// Millau to RialtoParachain conversion rate. Initially we treat both tokens as equal.
|
||||
pub storage MillauToRialtoParachainConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE;
|
||||
/// Fee multiplier value at Millau chain.
|
||||
pub storage MillauFeeMultiplier: FixedU128 = INITIAL_MILLAU_FEE_MULTIPLIER;
|
||||
/// Weight credit for our test messages.
|
||||
///
|
||||
/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
@@ -94,7 +79,6 @@ pub type ToMillauMaximalOutboundPayloadSize =
|
||||
pub struct WithMillauMessageBridge;
|
||||
|
||||
impl MessageBridge for WithMillauMessageBridge {
|
||||
const RELAYER_FEE_PERCENT: u32 = 10;
|
||||
const THIS_CHAIN_ID: ChainId = RIALTO_PARACHAIN_CHAIN_ID;
|
||||
const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
|
||||
const BRIDGED_MESSAGES_PALLET_NAME: &'static str =
|
||||
@@ -104,16 +88,6 @@ impl MessageBridge for WithMillauMessageBridge {
|
||||
type BridgedChain = Millau;
|
||||
type BridgedHeaderChain =
|
||||
pallet_bridge_grandpa::GrandpaChainHeaders<Runtime, MillauGrandpaInstance>;
|
||||
|
||||
fn bridged_balance_to_this_balance(
|
||||
bridged_balance: bp_millau::Balance,
|
||||
bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> bp_rialto_parachain::Balance {
|
||||
let conversion_rate = bridged_to_this_conversion_rate_override
|
||||
.unwrap_or_else(MillauToRialtoParachainConversionRate::get);
|
||||
bp_rialto_parachain::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
|
||||
.unwrap_or(bp_rialto_parachain::Balance::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
/// RialtoParachain chain from message lane point of view.
|
||||
@@ -127,12 +101,6 @@ impl messages::UnderlyingChainProvider for RialtoParachain {
|
||||
impl messages::ThisChainWithMessages for RialtoParachain {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
|
||||
bp_rialto_parachain::AccountId,
|
||||
{ bp_rialto_parachain::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
|
||||
{ bp_millau::EXTRA_STORAGE_PROOF_SIZE },
|
||||
{ bp_rialto_parachain::TX_EXTRA_BYTES },
|
||||
>;
|
||||
|
||||
fn is_message_accepted(send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
|
||||
let here_location = xcm::v3::MultiLocation::from(crate::UniversalLocation::get());
|
||||
@@ -156,25 +124,6 @@ impl messages::ThisChainWithMessages for RialtoParachain {
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
MessageNonce::MAX
|
||||
}
|
||||
|
||||
fn transaction_payment(
|
||||
transaction: MessageTransaction<Weight>,
|
||||
) -> bp_rialto_parachain::Balance {
|
||||
// `transaction` may represent transaction from the future, when multiplier value will
|
||||
// be larger, so let's use slightly increased value
|
||||
let multiplier = FixedU128::saturating_from_rational(110, 100)
|
||||
.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_rialto_parachain::BlockWeights::get()
|
||||
.get(DispatchClass::Normal)
|
||||
.base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Millau chain from message lane point of view.
|
||||
@@ -189,45 +138,6 @@ impl messages::BridgedChainWithMessages for Millau {
|
||||
fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn estimate_delivery_transaction(
|
||||
message_payload: &[u8],
|
||||
include_pay_dispatch_fee_cost: bool,
|
||||
message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight> {
|
||||
let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
|
||||
let extra_bytes_in_payload = message_payload_len
|
||||
.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
|
||||
|
||||
MessageTransaction {
|
||||
dispatch_weight: bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
|
||||
.saturating_mul(extra_bytes_in_payload as u64)
|
||||
.saturating_add(bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
|
||||
.saturating_sub(if include_pay_dispatch_fee_cost {
|
||||
Weight::from_ref_time(0)
|
||||
} else {
|
||||
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT
|
||||
})
|
||||
.saturating_add(message_dispatch_weight),
|
||||
size: message_payload_len
|
||||
.saturating_add(bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE)
|
||||
.saturating_add(bp_millau::TX_EXTRA_BYTES),
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
|
||||
// we don't have a direct access to the value of multiplier at Millau chain
|
||||
// => it is a messages module parameter
|
||||
let multiplier = MillauFeeMultiplier::get();
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto_parachain::AccountId> for Millau {
|
||||
@@ -249,7 +159,7 @@ impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto_parachain::AccountId> f
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceHeaderChain<bp_millau::Balance> for Millau {
|
||||
impl SourceHeaderChain for Millau {
|
||||
type Error = &'static str;
|
||||
// The proof is:
|
||||
// - hash of the header this proof has been created with;
|
||||
@@ -261,25 +171,8 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
|
||||
fn verify_messages_proof(
|
||||
proof: Self::MessagesProof,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
|
||||
) -> Result<ProvedMessages<Message>, Self::Error> {
|
||||
messages::target::verify_messages_proof::<WithMillauMessageBridge>(proof, messages_count)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// RialtoParachain -> Millau message lane pallet parameters.
|
||||
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||
pub enum RialtoParachainToMillauMessagesParameter {
|
||||
/// The conversion formula we use is: `RialtoParachainTokens = MillauTokens * conversion_rate`.
|
||||
MillauToRialtoParachainConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl MessagesParameter for RialtoParachainToMillauMessagesParameter {
|
||||
fn save(&self) {
|
||||
match *self {
|
||||
RialtoParachainToMillauMessagesParameter::MillauToRialtoParachainConversionRate(
|
||||
ref conversion_rate,
|
||||
) => MillauToRialtoParachainConversionRate::set(conversion_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,13 +32,8 @@ pub mod millau_messages;
|
||||
pub mod parachains;
|
||||
pub mod xcm_config;
|
||||
|
||||
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
|
||||
|
||||
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
|
||||
use bp_runtime::{HeaderId, HeaderIdProvider};
|
||||
use bridge_runtime_common::messages::{
|
||||
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
|
||||
};
|
||||
use pallet_grandpa::{
|
||||
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
|
||||
};
|
||||
@@ -54,7 +49,7 @@ use sp_runtime::{
|
||||
create_runtime_str, generic, impl_opaque_keys,
|
||||
traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perquintill,
|
||||
ApplyExtrinsicResult, FixedPointNumber, Perquintill,
|
||||
};
|
||||
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
#[cfg(feature = "std")]
|
||||
@@ -445,9 +440,6 @@ parameter_types! {
|
||||
bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce =
|
||||
bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
|
||||
// `IdentityFee` is used by Rialto => we may use weight directly
|
||||
pub const GetDeliveryConfirmationTransactionFee: Balance =
|
||||
bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() as _;
|
||||
pub const RootAccountForPayments: Option<AccountId> = None;
|
||||
pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
|
||||
}
|
||||
@@ -458,17 +450,14 @@ pub type WithMillauMessagesInstance = ();
|
||||
impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
|
||||
type Parameter = millau_messages::RialtoToMillauMessagesParameter;
|
||||
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
|
||||
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
|
||||
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
|
||||
|
||||
type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize;
|
||||
type OutboundPayload = crate::millau_messages::ToMillauMessagePayload;
|
||||
type OutboundMessageFee = Balance;
|
||||
|
||||
type InboundPayload = crate::millau_messages::FromMillauMessagePayload;
|
||||
type InboundMessageFee = bp_millau::Balance;
|
||||
type InboundRelayer = bp_millau::AccountId;
|
||||
|
||||
type TargetHeaderChain = crate::millau_messages::Millau;
|
||||
@@ -477,7 +466,6 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
|
||||
pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
|
||||
Runtime,
|
||||
WithMillauMessagesInstance,
|
||||
GetDeliveryConfirmationTransactionFee,
|
||||
>;
|
||||
type OnMessageAccepted = ();
|
||||
type OnDeliveryConfirmed = ();
|
||||
@@ -958,24 +946,12 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_millau::ToMillauOutboundLaneApi<Block, Balance, ToMillauMessagePayload> for Runtime {
|
||||
fn estimate_message_delivery_and_dispatch_fee(
|
||||
_lane_id: bp_messages::LaneId,
|
||||
payload: ToMillauMessagePayload,
|
||||
millau_to_this_conversion_rate: Option<FixedU128>,
|
||||
) -> Option<Balance> {
|
||||
estimate_message_dispatch_and_delivery_fee::<WithMillauMessageBridge>(
|
||||
&payload,
|
||||
WithMillauMessageBridge::RELAYER_FEE_PERCENT,
|
||||
millau_to_this_conversion_rate,
|
||||
).ok()
|
||||
}
|
||||
|
||||
impl bp_millau::ToMillauOutboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
begin: bp_messages::MessageNonce,
|
||||
end: bp_messages::MessageNonce,
|
||||
) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
|
||||
) -> Vec<bp_messages::OutboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::outbound_message_details::<
|
||||
Runtime,
|
||||
WithMillauMessagesInstance,
|
||||
@@ -983,10 +959,10 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl bp_millau::FromMillauInboundLaneApi<Block, bp_millau::Balance> for Runtime {
|
||||
impl bp_millau::FromMillauInboundLaneApi<Block> for Runtime {
|
||||
fn message_details(
|
||||
lane: bp_messages::LaneId,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_millau::Balance>)>,
|
||||
messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
|
||||
) -> Vec<bp_messages::InboundMessageDetails> {
|
||||
bridge_runtime_common::messages_api::inbound_message_details::<
|
||||
Runtime,
|
||||
|
||||
@@ -21,33 +21,18 @@ use crate::{MillauGrandpaInstance, OriginCaller, Runtime, RuntimeCall, RuntimeOr
|
||||
use bp_messages::{
|
||||
source_chain::TargetHeaderChain,
|
||||
target_chain::{ProvedMessages, SourceHeaderChain},
|
||||
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
||||
InboundLaneData, LaneId, Message, MessageNonce,
|
||||
};
|
||||
use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID};
|
||||
use bridge_runtime_common::messages::{
|
||||
self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
|
||||
use sp_std::convert::TryFrom;
|
||||
use bridge_runtime_common::messages::{self, MessageBridge};
|
||||
use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
|
||||
|
||||
/// Initial value of `MillauToRialtoConversionRate` parameter.
|
||||
pub const INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE: FixedU128 =
|
||||
FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Initial value of `MillauFeeMultiplier` parameter.
|
||||
pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
|
||||
/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual
|
||||
/// tests, confirming that we don't break encoding somewhere between.
|
||||
pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::xcm_config::BASE_XCM_WEIGHT;
|
||||
|
||||
parameter_types! {
|
||||
/// Millau to Rialto conversion rate. Initially we treat both tokens as equal.
|
||||
pub storage MillauToRialtoConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE;
|
||||
/// Fee multiplier value at Millau chain.
|
||||
pub storage MillauFeeMultiplier: FixedU128 = INITIAL_MILLAU_FEE_MULTIPLIER;
|
||||
/// Weight credit for our test messages.
|
||||
///
|
||||
/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
|
||||
@@ -89,7 +74,6 @@ pub type ToMillauMaximalOutboundPayloadSize =
|
||||
pub struct WithMillauMessageBridge;
|
||||
|
||||
impl MessageBridge for WithMillauMessageBridge {
|
||||
const RELAYER_FEE_PERCENT: u32 = 10;
|
||||
const THIS_CHAIN_ID: ChainId = RIALTO_CHAIN_ID;
|
||||
const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
|
||||
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME;
|
||||
@@ -98,16 +82,6 @@ impl MessageBridge for WithMillauMessageBridge {
|
||||
type BridgedChain = Millau;
|
||||
type BridgedHeaderChain =
|
||||
pallet_bridge_grandpa::GrandpaChainHeaders<Runtime, MillauGrandpaInstance>;
|
||||
|
||||
fn bridged_balance_to_this_balance(
|
||||
bridged_balance: bp_millau::Balance,
|
||||
bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> bp_rialto::Balance {
|
||||
let conversion_rate = bridged_to_this_conversion_rate_override
|
||||
.unwrap_or_else(MillauToRialtoConversionRate::get);
|
||||
bp_rialto::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
|
||||
.unwrap_or(bp_rialto::Balance::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rialto chain from message lane point of view.
|
||||
@@ -121,12 +95,6 @@ impl messages::UnderlyingChainProvider for Rialto {
|
||||
impl messages::ThisChainWithMessages for Rialto {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
|
||||
bp_rialto::AccountId,
|
||||
{ bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
|
||||
{ bp_millau::EXTRA_STORAGE_PROOF_SIZE },
|
||||
{ bp_rialto::TX_EXTRA_BYTES },
|
||||
>;
|
||||
|
||||
fn is_message_accepted(send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
|
||||
let here_location =
|
||||
@@ -151,21 +119,6 @@ impl messages::ThisChainWithMessages for Rialto {
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
MessageNonce::MAX
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_rialto::Balance {
|
||||
// `transaction` may represent transaction from the future, when multiplier value will
|
||||
// be larger, so let's use slightly increased value
|
||||
let multiplier = FixedU128::saturating_from_rational(110, 100)
|
||||
.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_rialto::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Millau chain from message lane point of view.
|
||||
@@ -180,45 +133,6 @@ impl messages::BridgedChainWithMessages for Millau {
|
||||
fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn estimate_delivery_transaction(
|
||||
message_payload: &[u8],
|
||||
include_pay_dispatch_fee_cost: bool,
|
||||
message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight> {
|
||||
let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
|
||||
let extra_bytes_in_payload = message_payload_len
|
||||
.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
|
||||
|
||||
MessageTransaction {
|
||||
dispatch_weight: bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
|
||||
.saturating_mul(extra_bytes_in_payload as u64)
|
||||
.saturating_add(bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
|
||||
.saturating_sub(if include_pay_dispatch_fee_cost {
|
||||
Weight::from_ref_time(0)
|
||||
} else {
|
||||
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT
|
||||
})
|
||||
.saturating_add(message_dispatch_weight),
|
||||
size: message_payload_len
|
||||
.saturating_add(bp_rialto::EXTRA_STORAGE_PROOF_SIZE)
|
||||
.saturating_add(bp_millau::TX_EXTRA_BYTES),
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
|
||||
// we don't have a direct access to the value of multiplier at Millau chain
|
||||
// => it is a messages module parameter
|
||||
let multiplier = MillauFeeMultiplier::get();
|
||||
// in our testnets, both per-byte fee and weight-to-fee are 1:1
|
||||
messages::transaction_payment(
|
||||
bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
|
||||
1,
|
||||
multiplier,
|
||||
|weight| weight.ref_time() as _,
|
||||
transaction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto::AccountId> for Millau {
|
||||
@@ -240,7 +154,7 @@ impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto::AccountId> for Millau
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceHeaderChain<bp_millau::Balance> for Millau {
|
||||
impl SourceHeaderChain for Millau {
|
||||
type Error = &'static str;
|
||||
// The proof is:
|
||||
// - hash of the header this proof has been created with;
|
||||
@@ -252,28 +166,12 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
|
||||
fn verify_messages_proof(
|
||||
proof: Self::MessagesProof,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
|
||||
) -> Result<ProvedMessages<Message>, Self::Error> {
|
||||
messages::target::verify_messages_proof::<WithMillauMessageBridge>(proof, messages_count)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rialto -> Millau message lane pallet parameters.
|
||||
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||
pub enum RialtoToMillauMessagesParameter {
|
||||
/// The conversion formula we use is: `RialtoTokens = MillauTokens * conversion_rate`.
|
||||
MillauToRialtoConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl MessagesParameter for RialtoToMillauMessagesParameter {
|
||||
fn save(&self) {
|
||||
match *self {
|
||||
RialtoToMillauMessagesParameter::MillauToRialtoConversionRate(ref conversion_rate) =>
|
||||
MillauToRialtoConversionRate::set(conversion_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -291,13 +189,7 @@ mod tests {
|
||||
fn ensure_rialto_message_lane_weights_are_correct() {
|
||||
type Weights = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
|
||||
|
||||
pallet_bridge_messages::ensure_weights_are_correct::<Weights>(
|
||||
bp_rialto::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
|
||||
bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
|
||||
bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
|
||||
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
|
||||
DbWeight::get(),
|
||||
);
|
||||
pallet_bridge_messages::ensure_weights_are_correct::<Weights>();
|
||||
|
||||
let max_incoming_message_proof_size = bp_millau::EXTRA_STORAGE_PROOF_SIZE.saturating_add(
|
||||
messages::target::maximal_incoming_message_size(bp_rialto::Rialto::max_extrinsic_size()),
|
||||
@@ -362,13 +254,5 @@ mod tests {
|
||||
bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME,
|
||||
},
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
MillauToRialtoConversionRate::key().to_vec(),
|
||||
bp_runtime::storage_parameter_key(
|
||||
bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME
|
||||
)
|
||||
.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ mod tests {
|
||||
let xcm: Xcm<()> = vec![Instruction::Trap(42)].into();
|
||||
|
||||
let send_result = send_xcm::<XcmRouter>(dest.into(), xcm);
|
||||
let expected_fee = MultiAssets::from((Here, 4_259_858_152_u128));
|
||||
let expected_fee = MultiAssets::from((Here, 1_000_000_u128));
|
||||
let expected_hash =
|
||||
([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256);
|
||||
assert_eq!(send_result, Ok((expected_hash, expected_fee)),);
|
||||
@@ -262,7 +262,7 @@ mod tests {
|
||||
|
||||
let mut incoming_message = DispatchMessage {
|
||||
key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
|
||||
data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 },
|
||||
data: DispatchMessageData { payload: Ok((location, xcm).into()) },
|
||||
};
|
||||
|
||||
let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message);
|
||||
|
||||
@@ -88,10 +88,8 @@ macro_rules! assert_bridge_messages_pallet_types(
|
||||
use static_assertions::assert_type_eq_all;
|
||||
|
||||
assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload);
|
||||
assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundMessageFee, BalanceOf<ThisChain<$bridge>>);
|
||||
|
||||
assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, FromBridgedChainMessagePayload<CallOf<ThisChain<$bridge>>>);
|
||||
assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundMessageFee, BalanceOf<BridgedChain<$bridge>>);
|
||||
assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundRelayer, AccountIdOf<BridgedChain<$bridge>>);
|
||||
|
||||
assert_type_eq_all!(<$r as MessagesConfig<$i>>::TargetHeaderChain, BridgedChain<$bridge>);
|
||||
|
||||
@@ -24,26 +24,19 @@ use bp_header_chain::{HeaderChain, HeaderChainError};
|
||||
use bp_messages::{
|
||||
source_chain::LaneMessageVerifier,
|
||||
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
|
||||
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||
InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData,
|
||||
};
|
||||
use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Size, StorageProofChecker};
|
||||
use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
|
||||
use codec::{Decode, DecodeLimit, Encode};
|
||||
use frame_support::{traits::Get, weights::Weight, RuntimeDebug};
|
||||
use hash_db::Hasher;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{
|
||||
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul},
|
||||
FixedPointNumber, FixedPointOperand, FixedU128,
|
||||
};
|
||||
use sp_std::{convert::TryFrom, fmt::Debug, marker::PhantomData, vec::Vec};
|
||||
use sp_trie::StorageProof;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
/// Bidirectional message bridge.
|
||||
pub trait MessageBridge {
|
||||
/// Relayer interest (in percents).
|
||||
const RELAYER_FEE_PERCENT: u32;
|
||||
|
||||
/// Identifier of this chain.
|
||||
const THIS_CHAIN_ID: ChainId;
|
||||
/// Identifier of the Bridged chain.
|
||||
@@ -59,60 +52,6 @@ pub trait MessageBridge {
|
||||
type BridgedChain: BridgedChainWithMessages;
|
||||
/// Bridged header chain.
|
||||
type BridgedHeaderChain: HeaderChain<UnderlyingChainOf<Self::BridgedChain>>;
|
||||
|
||||
/// Convert Bridged chain balance into This chain balance.
|
||||
fn bridged_balance_to_this_balance(
|
||||
bridged_balance: BalanceOf<BridgedChain<Self>>,
|
||||
bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> BalanceOf<ThisChain<Self>>;
|
||||
}
|
||||
|
||||
/// Message related transaction parameters estimation.
|
||||
#[derive(RuntimeDebug)]
|
||||
pub struct MessageTransaction<Weight> {
|
||||
/// The estimated dispatch weight of the transaction.
|
||||
pub dispatch_weight: Weight,
|
||||
/// The estimated size of the encoded transaction.
|
||||
pub size: u32,
|
||||
}
|
||||
|
||||
/// Helper trait for estimating the size and weight of a single message delivery confirmation
|
||||
/// transaction.
|
||||
pub trait ConfirmationTransactionEstimation<Weight> {
|
||||
// Estimate size and weight of single message delivery confirmation transaction.
|
||||
fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight>;
|
||||
}
|
||||
|
||||
/// Default implementation for `ConfirmationTransactionEstimation`.
|
||||
pub struct BasicConfirmationTransactionEstimation<
|
||||
AccountId: MaxEncodedLen,
|
||||
const MAX_CONFIRMATION_TX_WEIGHT: u64,
|
||||
const EXTRA_STORAGE_PROOF_SIZE: u32,
|
||||
const TX_EXTRA_BYTES: u32,
|
||||
>(PhantomData<AccountId>);
|
||||
|
||||
impl<
|
||||
AccountId: MaxEncodedLen,
|
||||
const MAX_CONFIRMATION_TX_WEIGHT: u64,
|
||||
const EXTRA_STORAGE_PROOF_SIZE: u32,
|
||||
const TX_EXTRA_BYTES: u32,
|
||||
> ConfirmationTransactionEstimation<Weight>
|
||||
for BasicConfirmationTransactionEstimation<
|
||||
AccountId,
|
||||
MAX_CONFIRMATION_TX_WEIGHT,
|
||||
EXTRA_STORAGE_PROOF_SIZE,
|
||||
TX_EXTRA_BYTES,
|
||||
>
|
||||
{
|
||||
fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> {
|
||||
let inbound_data_size = InboundLaneData::<AccountId>::encoded_size_hint_u32(1, 1);
|
||||
MessageTransaction {
|
||||
dispatch_weight: Weight::from_ref_time(MAX_CONFIRMATION_TX_WEIGHT),
|
||||
size: inbound_data_size
|
||||
.saturating_add(EXTRA_STORAGE_PROOF_SIZE)
|
||||
.saturating_add(TX_EXTRA_BYTES),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that provides the type of the underlying chain.
|
||||
@@ -127,9 +66,6 @@ pub trait ThisChainWithMessages: UnderlyingChainProvider {
|
||||
type RuntimeOrigin;
|
||||
/// Call type on the chain.
|
||||
type RuntimeCall: Encode + Decode;
|
||||
/// Helper for estimating the size and weight of a single message delivery confirmation
|
||||
/// transaction at this chain.
|
||||
type ConfirmationTransactionEstimation: ConfirmationTransactionEstimation<Weight>;
|
||||
|
||||
/// Do we accept message sent by given origin to given lane?
|
||||
fn is_message_accepted(origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool;
|
||||
@@ -138,14 +74,6 @@ pub trait ThisChainWithMessages: UnderlyingChainProvider {
|
||||
///
|
||||
/// Any messages over this limit, will be rejected.
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce;
|
||||
|
||||
/// Estimate size and weight of single message delivery confirmation transaction at This chain.
|
||||
fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> {
|
||||
Self::ConfirmationTransactionEstimation::estimate_delivery_confirmation_transaction()
|
||||
}
|
||||
|
||||
/// Returns minimal transaction fee that must be paid for given transaction at This chain.
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self>;
|
||||
}
|
||||
|
||||
/// Bridged chain that has `pallet-bridge-messages` module.
|
||||
@@ -153,17 +81,6 @@ pub trait BridgedChainWithMessages: UnderlyingChainProvider {
|
||||
/// Returns `true` if message dispatch weight is withing expected limits. `false` means
|
||||
/// that the message is too heavy to be sent over the bridge and shall be rejected.
|
||||
fn verify_dispatch_weight(message_payload: &[u8]) -> bool;
|
||||
|
||||
/// Estimate size and weight of single message delivery transaction at the Bridged chain.
|
||||
fn estimate_delivery_transaction(
|
||||
message_payload: &[u8],
|
||||
include_pay_dispatch_fee_cost: bool,
|
||||
message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight>;
|
||||
|
||||
/// Returns minimal transaction fee that must be paid for given transaction at the Bridged
|
||||
/// chain.
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self>;
|
||||
}
|
||||
|
||||
/// This chain in context of message bridge.
|
||||
@@ -188,33 +105,6 @@ pub type CallOf<C> = <C as ThisChainWithMessages>::RuntimeCall;
|
||||
/// Raw storage proof type (just raw trie nodes).
|
||||
pub type RawStorageProof = Vec<Vec<u8>>;
|
||||
|
||||
/// Compute fee of transaction at runtime where regular transaction payment pallet is being used.
|
||||
///
|
||||
/// The value of `multiplier` parameter is the expected value of
|
||||
/// `pallet_transaction_payment::NextFeeMultiplier` at the moment when transaction is submitted. If
|
||||
/// you're charging this payment in advance (and that's what happens with delivery and confirmation
|
||||
/// transaction in this crate), then there's a chance that the actual fee will be larger than what
|
||||
/// is paid in advance. So the value must be chosen carefully.
|
||||
pub fn transaction_payment<Balance: AtLeast32BitUnsigned + FixedPointOperand>(
|
||||
base_extrinsic_weight: Weight,
|
||||
per_byte_fee: Balance,
|
||||
multiplier: FixedU128,
|
||||
weight_to_fee: impl Fn(Weight) -> Balance,
|
||||
transaction: MessageTransaction<Weight>,
|
||||
) -> Balance {
|
||||
// base fee is charged for every tx
|
||||
let base_fee = weight_to_fee(base_extrinsic_weight);
|
||||
|
||||
// non-adjustable per-byte fee
|
||||
let len_fee = per_byte_fee.saturating_mul(Balance::from(transaction.size));
|
||||
|
||||
// the adjustable part of the fee
|
||||
let unadjusted_weight_fee = weight_to_fee(transaction.dispatch_weight);
|
||||
let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
|
||||
|
||||
base_fee.saturating_add(len_fee).saturating_add(adjusted_weight_fee)
|
||||
}
|
||||
|
||||
/// Sub-module that is declaring types required for processing This -> Bridged chain messages.
|
||||
pub mod source {
|
||||
use super::*;
|
||||
@@ -286,15 +176,9 @@ pub mod source {
|
||||
pub const TOO_MANY_PENDING_MESSAGES: &str = "Too many pending messages at the lane.";
|
||||
/// The error message returned from LaneMessageVerifier when call origin is mismatch.
|
||||
pub const BAD_ORIGIN: &str = "Unable to match the source origin to expected target origin.";
|
||||
/// The error message returned from LaneMessageVerifier when the message fee is too low.
|
||||
pub const TOO_LOW_FEE: &str = "Provided fee is below minimal threshold required by the lane.";
|
||||
|
||||
impl<B>
|
||||
LaneMessageVerifier<
|
||||
OriginOf<ThisChain<B>>,
|
||||
FromThisChainMessagePayload,
|
||||
BalanceOf<ThisChain<B>>,
|
||||
> for FromThisChainMessageVerifier<B>
|
||||
impl<B> LaneMessageVerifier<OriginOf<ThisChain<B>>, FromThisChainMessagePayload>
|
||||
for FromThisChainMessageVerifier<B>
|
||||
where
|
||||
B: MessageBridge,
|
||||
// matches requirements from the `frame_system::Config::Origin`
|
||||
@@ -306,10 +190,9 @@ pub mod source {
|
||||
|
||||
fn verify_message(
|
||||
submitter: &OriginOf<ThisChain<B>>,
|
||||
delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
|
||||
lane: &LaneId,
|
||||
lane_outbound_data: &OutboundLaneData,
|
||||
payload: &FromThisChainMessagePayload,
|
||||
_payload: &FromThisChainMessagePayload,
|
||||
) -> Result<(), Self::Error> {
|
||||
// reject message if lane is blocked
|
||||
if !ThisChain::<B>::is_message_accepted(submitter, lane) {
|
||||
@@ -325,17 +208,6 @@ pub mod source {
|
||||
return Err(TOO_MANY_PENDING_MESSAGES)
|
||||
}
|
||||
|
||||
let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::<B>(
|
||||
payload,
|
||||
B::RELAYER_FEE_PERCENT,
|
||||
None,
|
||||
)?;
|
||||
|
||||
// compare with actual fee paid
|
||||
if *delivery_and_dispatch_fee < minimal_fee_in_this_tokens {
|
||||
return Err(TOO_LOW_FEE)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -376,52 +248,6 @@ pub mod source {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Estimate delivery and dispatch fee that must be paid for delivering a message to the Bridged
|
||||
/// chain.
|
||||
///
|
||||
/// The fee is paid in This chain Balance, but we use Bridged chain balance to avoid additional
|
||||
/// conversions. Returns `None` if overflow has happened.
|
||||
pub fn estimate_message_dispatch_and_delivery_fee<B: MessageBridge>(
|
||||
payload: &FromThisChainMessagePayload,
|
||||
relayer_fee_percent: u32,
|
||||
bridged_to_this_conversion_rate: Option<FixedU128>,
|
||||
) -> Result<BalanceOf<ThisChain<B>>, &'static str> {
|
||||
// the fee (in Bridged tokens) of all transactions that are made on the Bridged chain
|
||||
//
|
||||
// if we're going to pay dispatch fee at the target chain, then we don't include weight
|
||||
// of the message dispatch in the delivery transaction cost
|
||||
let delivery_transaction = BridgedChain::<B>::estimate_delivery_transaction(
|
||||
&payload.encode(),
|
||||
true,
|
||||
Weight::zero(),
|
||||
);
|
||||
let delivery_transaction_fee = BridgedChain::<B>::transaction_payment(delivery_transaction);
|
||||
|
||||
// the fee (in This tokens) of all transactions that are made on This chain
|
||||
let confirmation_transaction = ThisChain::<B>::estimate_delivery_confirmation_transaction();
|
||||
let confirmation_transaction_fee =
|
||||
ThisChain::<B>::transaction_payment(confirmation_transaction);
|
||||
|
||||
// minimal fee (in This tokens) is a sum of all required fees
|
||||
let minimal_fee = B::bridged_balance_to_this_balance(
|
||||
delivery_transaction_fee,
|
||||
bridged_to_this_conversion_rate,
|
||||
)
|
||||
.checked_add(&confirmation_transaction_fee);
|
||||
|
||||
// before returning, add extra fee that is paid to the relayer (relayer interest)
|
||||
minimal_fee
|
||||
.and_then(|fee|
|
||||
// having message with fee that is near the `Balance::MAX_VALUE` of the chain is
|
||||
// unlikely and should be treated as an error
|
||||
// => let's do multiplication first
|
||||
fee
|
||||
.checked_mul(&relayer_fee_percent.into())
|
||||
.and_then(|interest| interest.checked_div(&100u32.into()))
|
||||
.and_then(|interest| fee.checked_add(&interest)))
|
||||
.ok_or("Overflow when computing minimal required message delivery and dispatch fee")
|
||||
}
|
||||
|
||||
/// Verify proof of This -> Bridged chain messages delivery.
|
||||
///
|
||||
/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged
|
||||
@@ -462,7 +288,6 @@ pub mod source {
|
||||
/// Runtime message sender adapter.
|
||||
type MessageSender: bp_messages::source_chain::MessagesBridge<
|
||||
OriginOf<ThisChain<Self::MessageBridge>>,
|
||||
BalanceOf<ThisChain<Self::MessageBridge>>,
|
||||
FromThisChainMessagePayload,
|
||||
>;
|
||||
|
||||
@@ -484,7 +309,7 @@ pub mod source {
|
||||
BalanceOf<ThisChain<T::MessageBridge>>: Into<Fungibility>,
|
||||
OriginOf<ThisChain<T::MessageBridge>>: From<pallet_xcm::Origin>,
|
||||
{
|
||||
type Ticket = (BalanceOf<ThisChain<T::MessageBridge>>, FromThisChainMessagePayload);
|
||||
type Ticket = FromThisChainMessagePayload;
|
||||
|
||||
fn validate(
|
||||
dest: &mut Option<MultiLocation>,
|
||||
@@ -499,39 +324,22 @@ pub mod source {
|
||||
let route = T::build_destination();
|
||||
let msg = (route, msg.take().ok_or(SendError::MissingArgument)?).encode();
|
||||
|
||||
let fee = estimate_message_dispatch_and_delivery_fee::<T::MessageBridge>(
|
||||
&msg,
|
||||
T::MessageBridge::RELAYER_FEE_PERCENT,
|
||||
None,
|
||||
);
|
||||
let fee = match fee {
|
||||
Ok(fee) => fee,
|
||||
Err(e) => {
|
||||
log::trace!(
|
||||
target: "runtime::bridge",
|
||||
"Failed to comupte fee for XCM message to {:?}: {:?}",
|
||||
T::MessageBridge::BRIDGED_CHAIN_ID,
|
||||
e,
|
||||
);
|
||||
*dest = Some(d);
|
||||
return Err(SendError::Transport(e))
|
||||
},
|
||||
};
|
||||
let fee_assets = MultiAssets::from((Here, fee));
|
||||
// let's just take fixed (out of thin air) fee per message in our test bridges
|
||||
// (this code won't be used in production anyway)
|
||||
let fee_assets = MultiAssets::from((Here, 1_000_000_u128));
|
||||
|
||||
Ok(((fee, msg), fee_assets))
|
||||
Ok((msg, fee_assets))
|
||||
}
|
||||
|
||||
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||
use bp_messages::source_chain::MessagesBridge;
|
||||
|
||||
let lane = T::xcm_lane();
|
||||
let (fee, msg) = ticket;
|
||||
let msg = ticket;
|
||||
let result = T::MessageSender::send_message(
|
||||
pallet_xcm::Origin::from(MultiLocation::from(T::universal_location())).into(),
|
||||
lane,
|
||||
msg,
|
||||
fee,
|
||||
);
|
||||
result
|
||||
.map(|artifacts| {
|
||||
@@ -633,7 +441,7 @@ pub mod target {
|
||||
}
|
||||
|
||||
impl<B: MessageBridge, XcmExecutor, XcmWeigher, WeightCredit>
|
||||
MessageDispatch<AccountIdOf<ThisChain<B>>, BalanceOf<BridgedChain<B>>>
|
||||
MessageDispatch<AccountIdOf<ThisChain<B>>>
|
||||
for FromBridgedChainMessageDispatch<B, XcmExecutor, XcmWeigher, WeightCredit>
|
||||
where
|
||||
XcmExecutor: xcm::v3::ExecuteXcm<CallOf<ThisChain<B>>>,
|
||||
@@ -643,7 +451,7 @@ pub mod target {
|
||||
type DispatchPayload = FromBridgedChainMessagePayload<CallOf<ThisChain<B>>>;
|
||||
|
||||
fn dispatch_weight(
|
||||
message: &mut DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
|
||||
message: &mut DispatchMessage<Self::DispatchPayload>,
|
||||
) -> frame_support::weights::Weight {
|
||||
match message.data.payload {
|
||||
Ok(ref mut payload) => {
|
||||
@@ -673,7 +481,7 @@ pub mod target {
|
||||
|
||||
fn dispatch(
|
||||
_relayer_account: &AccountIdOf<ThisChain<B>>,
|
||||
message: DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
|
||||
message: DispatchMessage<Self::DispatchPayload>,
|
||||
) -> MessageDispatchResult {
|
||||
let message_id = (message.key.lane_id, message.key.nonce);
|
||||
let do_dispatch = move || -> sp_std::result::Result<Outcome, codec::Error> {
|
||||
@@ -738,7 +546,7 @@ pub mod target {
|
||||
pub fn verify_messages_proof<B: MessageBridge>(
|
||||
proof: FromBridgedChainMessagesProof<HashOf<BridgedChain<B>>>,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, MessageProofError> {
|
||||
) -> Result<ProvedMessages<Message>, MessageProofError> {
|
||||
let FromBridgedChainMessagesProof {
|
||||
bridged_header_hash,
|
||||
storage_proof,
|
||||
@@ -779,11 +587,9 @@ pub mod target {
|
||||
let raw_message_data = parser
|
||||
.read_raw_message(&message_key)
|
||||
.ok_or(MessageProofError::MissingRequiredMessage)?;
|
||||
let message_data = MessageData::<BalanceOf<BridgedChain<B>>>::decode(
|
||||
&mut &raw_message_data[..],
|
||||
)
|
||||
.map_err(|_| MessageProofError::FailedToDecodeMessage)?;
|
||||
messages.push(Message { key: message_key, data: message_data });
|
||||
let payload = MessagePayload::decode(&mut &raw_message_data[..])
|
||||
.map_err(|_| MessageProofError::FailedToDecodeMessage)?;
|
||||
messages.push(Message { key: message_key, payload });
|
||||
}
|
||||
|
||||
// Now let's check if proof contains outbound lane state proof. It is optional, so
|
||||
@@ -885,11 +691,6 @@ mod tests {
|
||||
use sp_runtime::traits::{BlakeTwo256, Header as _};
|
||||
use std::cell::RefCell;
|
||||
|
||||
const DELIVERY_TRANSACTION_WEIGHT: Weight = Weight::from_ref_time(100);
|
||||
const DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT: u64 = 100;
|
||||
const THIS_CHAIN_WEIGHT_TO_BALANCE_RATE: u32 = 2;
|
||||
const BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE: u32 = 4;
|
||||
const BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE: u32 = 6;
|
||||
const BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT: usize = 5;
|
||||
const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: usize = 2048;
|
||||
const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024;
|
||||
@@ -900,7 +701,6 @@ mod tests {
|
||||
struct OnThisChainBridge;
|
||||
|
||||
impl MessageBridge for OnThisChainBridge {
|
||||
const RELAYER_FEE_PERCENT: u32 = 10;
|
||||
const THIS_CHAIN_ID: ChainId = *b"this";
|
||||
const BRIDGED_CHAIN_ID: ChainId = *b"brdg";
|
||||
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
|
||||
@@ -908,16 +708,6 @@ mod tests {
|
||||
type ThisChain = ThisChain;
|
||||
type BridgedChain = BridgedChain;
|
||||
type BridgedHeaderChain = BridgedHeaderChain;
|
||||
|
||||
fn bridged_balance_to_this_balance(
|
||||
bridged_balance: BridgedChainBalance,
|
||||
bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> ThisChainBalance {
|
||||
let conversion_rate = bridged_to_this_conversion_rate_override
|
||||
.map(|r| r.to_float() as u32)
|
||||
.unwrap_or(BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE);
|
||||
bridged_balance as ThisChainBalance * conversion_rate as ThisChainBalance
|
||||
}
|
||||
}
|
||||
|
||||
/// Bridge that is deployed on BridgedChain and allows sending/receiving messages to/from
|
||||
@@ -926,7 +716,6 @@ mod tests {
|
||||
struct OnBridgedChainBridge;
|
||||
|
||||
impl MessageBridge for OnBridgedChainBridge {
|
||||
const RELAYER_FEE_PERCENT: u32 = 20;
|
||||
const THIS_CHAIN_ID: ChainId = *b"brdg";
|
||||
const BRIDGED_CHAIN_ID: ChainId = *b"this";
|
||||
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
|
||||
@@ -934,13 +723,6 @@ mod tests {
|
||||
type ThisChain = BridgedChain;
|
||||
type BridgedChain = ThisChain;
|
||||
type BridgedHeaderChain = ThisHeaderChain;
|
||||
|
||||
fn bridged_balance_to_this_balance(
|
||||
_this_balance: ThisChainBalance,
|
||||
_bridged_to_this_conversion_rate_override: Option<FixedU128>,
|
||||
) -> BridgedChainBalance {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -989,6 +771,7 @@ mod tests {
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
|
||||
}
|
||||
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
@@ -1003,12 +786,6 @@ mod tests {
|
||||
impl ThisChainWithMessages for ThisChain {
|
||||
type RuntimeOrigin = ThisChainOrigin;
|
||||
type RuntimeCall = ThisChainCall;
|
||||
type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
|
||||
ThisChainAccountId,
|
||||
{ DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT },
|
||||
0,
|
||||
0,
|
||||
>;
|
||||
|
||||
fn is_message_accepted(_send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
|
||||
lane == TEST_LANE_ID
|
||||
@@ -1017,31 +794,12 @@ mod tests {
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
|
||||
transaction
|
||||
.dispatch_weight
|
||||
.saturating_mul(THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u64)
|
||||
.ref_time() as _
|
||||
}
|
||||
}
|
||||
|
||||
impl BridgedChainWithMessages for ThisChain {
|
||||
fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn estimate_delivery_transaction(
|
||||
_message_payload: &[u8],
|
||||
_include_pay_dispatch_fee_cost: bool,
|
||||
_message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn transaction_payment(_transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
struct BridgedUnderlyingChain;
|
||||
@@ -1078,8 +836,6 @@ mod tests {
|
||||
impl ThisChainWithMessages for BridgedChain {
|
||||
type RuntimeOrigin = BridgedChainOrigin;
|
||||
type RuntimeCall = BridgedChainCall;
|
||||
type ConfirmationTransactionEstimation =
|
||||
BasicConfirmationTransactionEstimation<BridgedChainAccountId, 0, 0, 0>;
|
||||
|
||||
fn is_message_accepted(_send_origin: &Self::RuntimeOrigin, _lane: &LaneId) -> bool {
|
||||
unreachable!()
|
||||
@@ -1088,10 +844,6 @@ mod tests {
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn transaction_payment(_transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl BridgedChainWithMessages for BridgedChain {
|
||||
@@ -1099,24 +851,6 @@ mod tests {
|
||||
message_payload.len() >= BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT &&
|
||||
message_payload.len() <= BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
|
||||
}
|
||||
|
||||
fn estimate_delivery_transaction(
|
||||
_message_payload: &[u8],
|
||||
_include_pay_dispatch_fee_cost: bool,
|
||||
message_dispatch_weight: Weight,
|
||||
) -> MessageTransaction<Weight> {
|
||||
MessageTransaction {
|
||||
dispatch_weight: DELIVERY_TRANSACTION_WEIGHT + message_dispatch_weight,
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
|
||||
transaction
|
||||
.dispatch_weight
|
||||
.saturating_mul(BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u64)
|
||||
.ref_time() as _
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@@ -1152,50 +886,11 @@ mod tests {
|
||||
vec![42]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_fee_is_checked_by_verifier() {
|
||||
const EXPECTED_MINIMAL_FEE: u32 = 2860;
|
||||
|
||||
// payload of the This -> Bridged chain message
|
||||
let payload = regular_outbound_message_payload();
|
||||
|
||||
// let's check if estimation matching hardcoded value
|
||||
assert_eq!(
|
||||
source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
|
||||
&payload,
|
||||
OnThisChainBridge::RELAYER_FEE_PERCENT,
|
||||
None,
|
||||
),
|
||||
Ok(EXPECTED_MINIMAL_FEE),
|
||||
);
|
||||
|
||||
// and now check that the verifier checks the fee
|
||||
assert_eq!(
|
||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||
&1,
|
||||
TEST_LANE_ID,
|
||||
&test_lane_outbound_data(),
|
||||
&payload,
|
||||
),
|
||||
Err(source::TOO_LOW_FEE)
|
||||
);
|
||||
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||
&1_000_000,
|
||||
TEST_LANE_ID,
|
||||
&test_lane_outbound_data(),
|
||||
&payload,
|
||||
)
|
||||
.is_ok(),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_is_rejected_when_sent_using_disabled_lane() {
|
||||
assert_eq!(
|
||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||
&1_000_000,
|
||||
b"dsbl",
|
||||
&test_lane_outbound_data(),
|
||||
®ular_outbound_message_payload(),
|
||||
@@ -1209,7 +904,6 @@ mod tests {
|
||||
assert_eq!(
|
||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||
&1_000_000,
|
||||
TEST_LANE_ID,
|
||||
&OutboundLaneData {
|
||||
latest_received_nonce: 100,
|
||||
@@ -1267,7 +961,7 @@ mod tests {
|
||||
fn using_messages_proof<R>(
|
||||
nonces_end: MessageNonce,
|
||||
outbound_lane_data: Option<OutboundLaneData>,
|
||||
encode_message: impl Fn(MessageNonce, &MessageData<BridgedChainBalance>) -> Option<Vec<u8>>,
|
||||
encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option<Vec<u8>>,
|
||||
encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec<u8>,
|
||||
test: impl Fn(target::FromBridgedChainMessagesProof<H256>) -> R,
|
||||
) -> R {
|
||||
@@ -1366,10 +1060,9 @@ mod tests {
|
||||
|n, m| {
|
||||
let mut m = m.encode();
|
||||
if n == 5 {
|
||||
m = MessageData { fee: 0, payload: vec![0u8; 42] }.encode();
|
||||
m.truncate(2);
|
||||
m = vec![42]
|
||||
}
|
||||
Some(m.encode())
|
||||
Some(m)
|
||||
},
|
||||
encode_lane_data,
|
||||
|proof| target::verify_messages_proof::<OnThisChainBridge>(proof, 10),
|
||||
@@ -1464,7 +1157,7 @@ mod tests {
|
||||
}),
|
||||
messages: vec![Message {
|
||||
key: MessageKey { lane_id: *TEST_LANE_ID, nonce: 1 },
|
||||
data: MessageData { payload: vec![42], fee: 0 },
|
||||
payload: vec![42],
|
||||
}],
|
||||
},
|
||||
)]
|
||||
@@ -1483,53 +1176,4 @@ mod tests {
|
||||
Err(target::MessageProofError::MessagesCountMismatch),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_payment_works_with_zero_multiplier() {
|
||||
use sp_runtime::traits::Zero;
|
||||
|
||||
assert_eq!(
|
||||
transaction_payment(
|
||||
Weight::from_ref_time(100),
|
||||
10,
|
||||
FixedU128::zero(),
|
||||
|weight| weight.ref_time(),
|
||||
MessageTransaction { size: 50, dispatch_weight: Weight::from_ref_time(777) },
|
||||
),
|
||||
100 + 50 * 10,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_payment_works_with_non_zero_multiplier() {
|
||||
use sp_runtime::traits::One;
|
||||
|
||||
assert_eq!(
|
||||
transaction_payment::<u64>(
|
||||
Weight::from_ref_time(100),
|
||||
10,
|
||||
FixedU128::one(),
|
||||
|weight| weight.ref_time(),
|
||||
MessageTransaction { size: 50, dispatch_weight: Weight::from_ref_time(777) },
|
||||
),
|
||||
100 + 50 * 10 + 777,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_rate_override_works() {
|
||||
let payload = regular_outbound_message_payload();
|
||||
let regular_fee = source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
|
||||
&payload,
|
||||
OnThisChainBridge::RELAYER_FEE_PERCENT,
|
||||
None,
|
||||
);
|
||||
let overrided_fee = source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
|
||||
&payload,
|
||||
OnThisChainBridge::RELAYER_FEE_PERCENT,
|
||||
Some(FixedU128::from_float((BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE * 2) as f64)),
|
||||
);
|
||||
|
||||
assert!(regular_fee < overrided_fee);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn outbound_message_details<Runtime, MessagesPalletInstance>(
|
||||
lane: LaneId,
|
||||
begin: MessageNonce,
|
||||
end: MessageNonce,
|
||||
) -> Vec<OutboundMessageDetails<Runtime::OutboundMessageFee>>
|
||||
) -> Vec<OutboundMessageDetails>
|
||||
where
|
||||
Runtime: pallet_bridge_messages::Config<MessagesPalletInstance>,
|
||||
MessagesPalletInstance: 'static,
|
||||
@@ -40,10 +40,7 @@ where
|
||||
// dispatch message weight is always zero at the source chain, since we're paying for
|
||||
// dispatch at the target chain
|
||||
dispatch_weight: frame_support::weights::Weight::zero(),
|
||||
size: message_data.payload.len() as _,
|
||||
delivery_and_dispatch_fee: message_data.fee,
|
||||
// we're delivering XCM messages here, so fee is always paid at the target chain
|
||||
dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtTargetChain,
|
||||
size: message_data.len() as _,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -52,7 +49,7 @@ where
|
||||
/// Implementation of the `To*InboundLaneApi::message_details`.
|
||||
pub fn inbound_message_details<Runtime, MessagesPalletInstance>(
|
||||
lane: LaneId,
|
||||
messages: Vec<(MessagePayload, OutboundMessageDetails<Runtime::InboundMessageFee>)>,
|
||||
messages: Vec<(MessagePayload, OutboundMessageDetails)>,
|
||||
) -> Vec<InboundMessageDetails>
|
||||
where
|
||||
Runtime: pallet_bridge_messages::Config<MessagesPalletInstance>,
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
use crate::{
|
||||
messages::{
|
||||
source::{FromBridgedChainMessagesDeliveryProof, FromThisChainMessagePayload},
|
||||
target::FromBridgedChainMessagesProof,
|
||||
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||
AccountIdOf, BalanceOf, BridgedChain, CallOf, HashOf, MessageBridge, ThisChain,
|
||||
},
|
||||
messages_generation::{
|
||||
@@ -34,25 +33,12 @@ use bp_messages::storage_keys;
|
||||
use bp_runtime::{record_all_trie_keys, StorageProofSize};
|
||||
use codec::Encode;
|
||||
use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
|
||||
use pallet_bridge_messages::benchmarking::{
|
||||
MessageDeliveryProofParams, MessageParams, MessageProofParams,
|
||||
};
|
||||
use pallet_bridge_messages::benchmarking::{MessageDeliveryProofParams, MessageProofParams};
|
||||
use sp_core::Hasher;
|
||||
use sp_runtime::traits::{Header, MaybeSerializeDeserialize, Zero};
|
||||
use sp_std::{fmt::Debug, prelude::*};
|
||||
use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut};
|
||||
|
||||
/// Prepare outbound message for the `send_message` call.
|
||||
pub fn prepare_outbound_message<B>(
|
||||
params: MessageParams<AccountIdOf<ThisChain<B>>>,
|
||||
) -> FromThisChainMessagePayload
|
||||
where
|
||||
B: MessageBridge,
|
||||
BalanceOf<ThisChain<B>>: From<u64>,
|
||||
{
|
||||
vec![0; params.size as usize]
|
||||
}
|
||||
|
||||
/// Prepare proof of messages for the `receive_messages_proof` call.
|
||||
///
|
||||
/// In addition to returning valid messages proof, environment is prepared to verify this message
|
||||
|
||||
@@ -31,7 +31,6 @@ use sp_runtime::transaction_validity::TransactionValidity;
|
||||
impl<
|
||||
BridgedHeaderHash,
|
||||
SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain<
|
||||
<T as Config<I>>::InboundMessageFee,
|
||||
MessagesProof = FromBridgedChainMessagesProof<BridgedHeaderHash>,
|
||||
>,
|
||||
TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain<
|
||||
|
||||
@@ -18,23 +18,19 @@
|
||||
|
||||
#![cfg(any(feature = "runtime-benchmarks", test))]
|
||||
|
||||
use crate::messages::{BalanceOf, BridgedChain, HashOf, HasherOf, MessageBridge, RawStorageProof};
|
||||
use crate::messages::{BridgedChain, HashOf, HasherOf, MessageBridge, RawStorageProof};
|
||||
|
||||
use bp_messages::{
|
||||
storage_keys, LaneId, MessageData, MessageKey, MessageNonce, MessagePayload, OutboundLaneData,
|
||||
storage_keys, LaneId, MessageKey, MessageNonce, MessagePayload, OutboundLaneData,
|
||||
};
|
||||
use bp_runtime::{record_all_trie_keys, StorageProofSize};
|
||||
use codec::Encode;
|
||||
use sp_core::Hasher;
|
||||
use sp_runtime::traits::Zero;
|
||||
use sp_std::{ops::RangeInclusive, prelude::*};
|
||||
use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut};
|
||||
|
||||
/// Simple and correct message data encode function.
|
||||
pub(crate) fn encode_all_messages<B: Encode>(
|
||||
_: MessageNonce,
|
||||
m: &MessageData<B>,
|
||||
) -> Option<Vec<u8>> {
|
||||
pub(crate) fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option<Vec<u8>> {
|
||||
Some(m.encode())
|
||||
}
|
||||
|
||||
@@ -52,7 +48,7 @@ pub(crate) fn prepare_messages_storage_proof<B>(
|
||||
outbound_lane_data: Option<OutboundLaneData>,
|
||||
size: StorageProofSize,
|
||||
message_payload: MessagePayload,
|
||||
encode_message: impl Fn(MessageNonce, &MessageData<BalanceOf<BridgedChain<B>>>) -> Option<Vec<u8>>,
|
||||
encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option<Vec<u8>>,
|
||||
encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec<u8>,
|
||||
) -> (HashOf<BridgedChain<B>>, RawStorageProof)
|
||||
where
|
||||
@@ -71,12 +67,8 @@ where
|
||||
// insert messages
|
||||
for nonce in message_nonces {
|
||||
let message_key = MessageKey { lane_id: lane, nonce };
|
||||
let message_data = MessageData {
|
||||
fee: BalanceOf::<BridgedChain<B>>::zero(),
|
||||
payload: message_payload.clone(),
|
||||
};
|
||||
let message_data = match encode_message(nonce, &message_data) {
|
||||
Some(message_data) => message_data,
|
||||
let message_payload = match encode_message(nonce, &message_payload) {
|
||||
Some(message_payload) => message_payload,
|
||||
None => continue,
|
||||
};
|
||||
let storage_key = storage_keys::message_key(
|
||||
@@ -85,7 +77,7 @@ where
|
||||
message_key.nonce,
|
||||
)
|
||||
.0;
|
||||
trie.insert(&storage_key, &message_data)
|
||||
trie.insert(&storage_key, &message_payload)
|
||||
.map_err(|_| "TrieMut::insert has failed")
|
||||
.expect("TrieMut::insert should not fail in benchmarks");
|
||||
storage_keys.push(storage_key);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Autogenerated weights for `pallet_bridge_grandpa`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-10-04, STEPS: 50, REPEAT: 20
|
||||
//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
|
||||
//! LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
||||
//! CHAIN: Some("dev"), DB CACHE: 1024
|
||||
@@ -59,9 +59,9 @@ pub trait WeightInfo {
|
||||
pub struct BridgeWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
fn submit_finality_proof(p: u32, v: u32) -> Weight {
|
||||
Weight::from_ref_time(105_417_000 as u64)
|
||||
.saturating_add(Weight::from_ref_time(40_923_000 as u64).saturating_mul(p as u64))
|
||||
.saturating_add(Weight::from_ref_time(1_691_000 as u64).saturating_mul(v as u64))
|
||||
Weight::from_ref_time(198_274_668 as u64)
|
||||
.saturating_add(Weight::from_ref_time(39_830_948 as u64).saturating_mul(p as u64))
|
||||
.saturating_add(Weight::from_ref_time(1_535_681 as u64).saturating_mul(v as u64))
|
||||
.saturating_add(T::DbWeight::get().reads(7 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(6 as u64))
|
||||
}
|
||||
@@ -70,9 +70,9 @@ impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn submit_finality_proof(p: u32, v: u32) -> Weight {
|
||||
Weight::from_ref_time(105_417_000 as u64)
|
||||
.saturating_add(Weight::from_ref_time(40_923_000 as u64).saturating_mul(p as u64))
|
||||
.saturating_add(Weight::from_ref_time(1_691_000 as u64).saturating_mul(v as u64))
|
||||
Weight::from_ref_time(198_274_668 as u64)
|
||||
.saturating_add(Weight::from_ref_time(39_830_948 as u64).saturating_mul(p as u64))
|
||||
.saturating_add(Weight::from_ref_time(1_535_681 as u64).saturating_mul(v as u64))
|
||||
.saturating_add(RocksDbWeight::get().reads(7 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(6 as u64))
|
||||
}
|
||||
|
||||
@@ -18,35 +18,25 @@
|
||||
|
||||
use crate::{
|
||||
inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane,
|
||||
outbound_lane::ReceivalConfirmationResult, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call,
|
||||
OutboundLanes, OutboundMessages,
|
||||
weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call, OutboundLanes,
|
||||
};
|
||||
|
||||
use bp_messages::{
|
||||
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages,
|
||||
InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||
UnrewardedRelayer, UnrewardedRelayersState,
|
||||
InboundLaneData, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer,
|
||||
UnrewardedRelayersState,
|
||||
};
|
||||
use bp_runtime::{messages::DispatchFeePayment, StorageProofSize};
|
||||
use bp_runtime::StorageProofSize;
|
||||
use frame_benchmarking::{account, benchmarks_instance_pallet};
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use frame_support::weights::Weight;
|
||||
use frame_system::RawOrigin;
|
||||
use sp_std::{collections::vec_deque::VecDeque, convert::TryInto, ops::RangeInclusive, prelude::*};
|
||||
use sp_std::{ops::RangeInclusive, prelude::*};
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
/// Pallet we're benchmarking here.
|
||||
pub struct Pallet<T: Config<I>, I: 'static>(crate::Pallet<T, I>);
|
||||
|
||||
/// Benchmark-specific message parameters.
|
||||
#[derive(Debug)]
|
||||
pub struct MessageParams<ThisAccountId> {
|
||||
/// Size of the message payload.
|
||||
pub size: u32,
|
||||
/// Message sender account.
|
||||
pub sender_account: ThisAccountId,
|
||||
}
|
||||
|
||||
/// Benchmark-specific message proof parameters.
|
||||
#[derive(Debug)]
|
||||
pub struct MessageProofParams {
|
||||
@@ -58,8 +48,6 @@ pub struct MessageProofParams {
|
||||
pub outbound_lane_data: Option<OutboundLaneData>,
|
||||
/// Proof size requirements.
|
||||
pub size: StorageProofSize,
|
||||
/// Where the fee for dispatching message is paid?
|
||||
pub dispatch_fee_payment: DispatchFeePayment,
|
||||
}
|
||||
|
||||
/// Benchmark-specific message delivery proof parameters.
|
||||
@@ -79,29 +67,14 @@ pub trait Config<I: 'static>: crate::Config<I> {
|
||||
fn bench_lane_id() -> LaneId {
|
||||
Default::default()
|
||||
}
|
||||
/// Get maximal size of the message payload.
|
||||
fn maximal_message_size() -> u32;
|
||||
/// Return id of relayer account at the bridged chain.
|
||||
fn bridged_relayer_id() -> Self::InboundRelayer;
|
||||
/// Return balance of given account.
|
||||
fn account_balance(account: &Self::AccountId) -> Self::OutboundMessageFee;
|
||||
/// Create given account and give it enough balance for test purposes.
|
||||
fn endow_account(account: &Self::AccountId);
|
||||
/// Fee paid by submitter for single message delivery.
|
||||
fn message_fee() -> Self::OutboundMessageFee {
|
||||
100_000_000_000_000.into()
|
||||
}
|
||||
/// Prepare message to send over lane.
|
||||
fn prepare_outbound_message(
|
||||
params: MessageParams<Self::AccountId>,
|
||||
) -> (Self::OutboundPayload, Self::OutboundMessageFee);
|
||||
/// Prepare messages proof to receive by the module.
|
||||
fn prepare_message_proof(
|
||||
params: MessageProofParams,
|
||||
) -> (
|
||||
<Self::SourceHeaderChain as SourceHeaderChain<Self::InboundMessageFee>>::MessagesProof,
|
||||
Weight,
|
||||
);
|
||||
) -> (<Self::SourceHeaderChain as SourceHeaderChain>::MessagesProof, Weight);
|
||||
/// Prepare messages delivery proof to receive by the module.
|
||||
fn prepare_message_delivery_proof(
|
||||
params: MessageDeliveryProofParams<Self::AccountId>,
|
||||
@@ -115,156 +88,6 @@ benchmarks_instance_pallet! {
|
||||
// Benchmarks that are used directly by the runtime.
|
||||
//
|
||||
|
||||
// Benchmark `send_message` extrinsic with the worst possible conditions:
|
||||
// * outbound lane already has state, so it needs to be read and decoded;
|
||||
// * relayers fund account does not exists (in practice it needs to exist in production environment);
|
||||
// * maximal number of messages is being pruned during the call;
|
||||
// * message size is minimal for the target chain.
|
||||
//
|
||||
// Result of this benchmark is used as a base weight for `send_message` call. Then the 'message weight'
|
||||
// (estimated using `send_half_maximal_message_worst_case` and `send_maximal_message_worst_case`) is
|
||||
// added.
|
||||
send_minimal_message_worst_case {
|
||||
let lane_id = T::bench_lane_id();
|
||||
let sender = account("sender", 0, SEED);
|
||||
T::endow_account(&sender);
|
||||
|
||||
// 'send' messages that are to be pruned when our message is sent
|
||||
for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() {
|
||||
send_regular_message::<T, I>();
|
||||
}
|
||||
confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
|
||||
|
||||
let (payload, fee) = T::prepare_outbound_message(MessageParams {
|
||||
size: 0,
|
||||
sender_account: sender.clone(),
|
||||
});
|
||||
}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::OutboundLanes::<T, I>::get(&T::bench_lane_id()).latest_generated_nonce,
|
||||
T::MaxMessagesToPruneAtOnce::get() + 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `send_message` extrinsic with the worst possible conditions:
|
||||
// * outbound lane already has state, so it needs to be read and decoded;
|
||||
// * relayers fund account does not exists (in practice it needs to exist in production environment);
|
||||
// * maximal number of messages is being pruned during the call;
|
||||
// * message size is 1KB.
|
||||
//
|
||||
// With single KB of message size, the weight of the call is increased (roughly) by
|
||||
// `(send_16_kb_message_worst_case - send_1_kb_message_worst_case) / 15`.
|
||||
send_1_kb_message_worst_case {
|
||||
let lane_id = T::bench_lane_id();
|
||||
let sender = account("sender", 0, SEED);
|
||||
T::endow_account(&sender);
|
||||
|
||||
// 'send' messages that are to be pruned when our message is sent
|
||||
for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() {
|
||||
send_regular_message::<T, I>();
|
||||
}
|
||||
confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
|
||||
|
||||
let size = 1024;
|
||||
assert!(
|
||||
T::maximal_message_size() > size,
|
||||
"This benchmark can only be used with runtime that accepts 1KB messages",
|
||||
);
|
||||
|
||||
let (payload, fee) = T::prepare_outbound_message(MessageParams {
|
||||
size,
|
||||
sender_account: sender.clone(),
|
||||
});
|
||||
}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::OutboundLanes::<T, I>::get(&T::bench_lane_id()).latest_generated_nonce,
|
||||
T::MaxMessagesToPruneAtOnce::get() + 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `send_message` extrinsic with the worst possible conditions:
|
||||
// * outbound lane already has state, so it needs to be read and decoded;
|
||||
// * relayers fund account does not exists (in practice it needs to exist in production environment);
|
||||
// * maximal number of messages is being pruned during the call;
|
||||
// * message size is 16KB.
|
||||
//
|
||||
// With single KB of message size, the weight of the call is increased (roughly) by
|
||||
// `(send_16_kb_message_worst_case - send_1_kb_message_worst_case) / 15`.
|
||||
send_16_kb_message_worst_case {
|
||||
let lane_id = T::bench_lane_id();
|
||||
let sender = account("sender", 0, SEED);
|
||||
T::endow_account(&sender);
|
||||
|
||||
// 'send' messages that are to be pruned when our message is sent
|
||||
for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() {
|
||||
send_regular_message::<T, I>();
|
||||
}
|
||||
confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
|
||||
|
||||
let size = 16 * 1024;
|
||||
assert!(
|
||||
T::maximal_message_size() > size,
|
||||
"This benchmark can only be used with runtime that accepts 16KB messages",
|
||||
);
|
||||
|
||||
let (payload, fee) = T::prepare_outbound_message(MessageParams {
|
||||
size,
|
||||
sender_account: sender.clone(),
|
||||
});
|
||||
}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
|
||||
verify {
|
||||
assert_eq!(
|
||||
crate::OutboundLanes::<T, I>::get(&T::bench_lane_id()).latest_generated_nonce,
|
||||
T::MaxMessagesToPruneAtOnce::get() + 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `increase_message_fee` with following conditions:
|
||||
// * message has maximal message;
|
||||
// * submitter account is killed because its balance is less than ED after payment.
|
||||
//
|
||||
// Result of this benchmark is directly used by weight formula of the call.
|
||||
maximal_increase_message_fee {
|
||||
let sender = account("sender", 42, SEED);
|
||||
T::endow_account(&sender);
|
||||
|
||||
let additional_fee = T::account_balance(&sender);
|
||||
let lane_id = T::bench_lane_id();
|
||||
let nonce = 1;
|
||||
|
||||
send_regular_message_with_payload::<T, I>(vec![42u8; T::maximal_message_size() as _]);
|
||||
}: increase_message_fee(RawOrigin::Signed(sender.clone()), lane_id, nonce, additional_fee)
|
||||
verify {
|
||||
assert_eq!(
|
||||
OutboundMessages::<T, I>::get(MessageKey { lane_id, nonce }).unwrap().fee,
|
||||
T::message_fee() + additional_fee,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `increase_message_fee` with following conditions:
|
||||
// * message size varies from minimal to maximal;
|
||||
// * submitter account is killed because its balance is less than ED after payment.
|
||||
increase_message_fee {
|
||||
let i in 0..T::maximal_message_size().try_into().unwrap_or_default();
|
||||
|
||||
let sender = account("sender", 42, SEED);
|
||||
T::endow_account(&sender);
|
||||
|
||||
let additional_fee = T::account_balance(&sender);
|
||||
let lane_id = T::bench_lane_id();
|
||||
let nonce = 1;
|
||||
|
||||
send_regular_message_with_payload::<T, I>(vec![42u8; i as _]);
|
||||
}: increase_message_fee(RawOrigin::Signed(sender.clone()), lane_id, nonce, additional_fee)
|
||||
verify {
|
||||
assert_eq!(
|
||||
OutboundMessages::<T, I>::get(MessageKey { lane_id, nonce }).unwrap().fee,
|
||||
T::message_fee() + additional_fee,
|
||||
);
|
||||
}
|
||||
|
||||
// Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions:
|
||||
// * proof does not include outbound lane state proof;
|
||||
// * inbound lane already has state, so it needs to be read and decoded;
|
||||
@@ -286,7 +109,6 @@ benchmarks_instance_pallet! {
|
||||
message_nonces: 21..=21,
|
||||
outbound_lane_data: None,
|
||||
size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
|
||||
verify {
|
||||
@@ -321,7 +143,6 @@ benchmarks_instance_pallet! {
|
||||
message_nonces: 21..=22,
|
||||
outbound_lane_data: None,
|
||||
size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 2, dispatch_weight)
|
||||
verify {
|
||||
@@ -360,7 +181,6 @@ benchmarks_instance_pallet! {
|
||||
latest_generated_nonce: 21,
|
||||
}),
|
||||
size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
|
||||
verify {
|
||||
@@ -392,7 +212,6 @@ benchmarks_instance_pallet! {
|
||||
message_nonces: 21..=21,
|
||||
outbound_lane_data: None,
|
||||
size: StorageProofSize::HasExtraNodes(1024),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
|
||||
verify {
|
||||
@@ -427,7 +246,6 @@ benchmarks_instance_pallet! {
|
||||
message_nonces: 21..=21,
|
||||
outbound_lane_data: None,
|
||||
size: StorageProofSize::HasExtraNodes(16 * 1024),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
|
||||
verify {
|
||||
@@ -461,7 +279,6 @@ benchmarks_instance_pallet! {
|
||||
message_nonces: 21..=21,
|
||||
outbound_lane_data: None,
|
||||
size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
});
|
||||
}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
|
||||
verify {
|
||||
@@ -479,7 +296,6 @@ benchmarks_instance_pallet! {
|
||||
// This is base benchmark for all other confirmations delivery benchmarks.
|
||||
receive_delivery_proof_for_single_message {
|
||||
let relayer_id: T::AccountId = account("relayer", 0, SEED);
|
||||
let relayer_balance = T::account_balance(&relayer_id);
|
||||
|
||||
// send message that we're going to confirm
|
||||
send_regular_message::<T, I>();
|
||||
@@ -515,7 +331,6 @@ benchmarks_instance_pallet! {
|
||||
// - weight(receive_delivery_proof_for_single_message)`.
|
||||
receive_delivery_proof_for_two_messages_by_single_relayer {
|
||||
let relayer_id: T::AccountId = account("relayer", 0, SEED);
|
||||
let relayer_balance = T::account_balance(&relayer_id);
|
||||
|
||||
// send message that we're going to confirm
|
||||
send_regular_message::<T, I>();
|
||||
@@ -554,9 +369,7 @@ benchmarks_instance_pallet! {
|
||||
// - weight(receive_delivery_proof_for_two_messages_by_single_relayer)`.
|
||||
receive_delivery_proof_for_two_messages_by_two_relayers {
|
||||
let relayer1_id: T::AccountId = account("relayer1", 1, SEED);
|
||||
let relayer1_balance = T::account_balance(&relayer1_id);
|
||||
let relayer2_id: T::AccountId = account("relayer2", 2, SEED);
|
||||
let relayer2_balance = T::account_balance(&relayer2_id);
|
||||
|
||||
// send message that we're going to confirm
|
||||
send_regular_message::<T, I>();
|
||||
@@ -593,28 +406,7 @@ benchmarks_instance_pallet! {
|
||||
|
||||
fn send_regular_message<T: Config<I>, I: 'static>() {
|
||||
let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
|
||||
outbound_lane.send_message(MessageData { payload: vec![], fee: T::message_fee() });
|
||||
}
|
||||
|
||||
fn send_regular_message_with_payload<T: Config<I>, I: 'static>(payload: Vec<u8>) {
|
||||
let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
|
||||
outbound_lane.send_message(MessageData { payload, fee: T::message_fee() });
|
||||
}
|
||||
|
||||
fn confirm_message_delivery<T: Config<I>, I: 'static>(nonce: MessageNonce) {
|
||||
let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
|
||||
let latest_received_nonce = outbound_lane.data().latest_received_nonce;
|
||||
let mut relayers = VecDeque::with_capacity((nonce - latest_received_nonce) as usize);
|
||||
for nonce in latest_received_nonce + 1..=nonce {
|
||||
relayers.push_back(UnrewardedRelayer {
|
||||
relayer: (),
|
||||
messages: DeliveredMessages::new(nonce, true),
|
||||
});
|
||||
}
|
||||
assert!(matches!(
|
||||
outbound_lane.confirm_delivery(nonce - latest_received_nonce, nonce, &relayers),
|
||||
ReceivalConfirmationResult::ConfirmedMessages(_),
|
||||
));
|
||||
outbound_lane.send_message(vec![]);
|
||||
}
|
||||
|
||||
fn receive_messages<T: Config<I>, I: 'static>(nonce: MessageNonce) {
|
||||
|
||||
@@ -31,8 +31,6 @@ use sp_std::prelude::PartialEq;
|
||||
|
||||
/// Inbound lane storage.
|
||||
pub trait InboundLaneStorage {
|
||||
/// Delivery and dispatch fee type on source chain.
|
||||
type MessageFee;
|
||||
/// Id of relayer on source chain.
|
||||
type Relayer: Clone + PartialEq;
|
||||
|
||||
@@ -183,12 +181,12 @@ impl<S: InboundLaneStorage> InboundLane<S> {
|
||||
}
|
||||
|
||||
/// Receive new message.
|
||||
pub fn receive_message<P: MessageDispatch<AccountId, S::MessageFee>, AccountId>(
|
||||
pub fn receive_message<P: MessageDispatch<AccountId>, AccountId>(
|
||||
&mut self,
|
||||
relayer_at_bridged_chain: &S::Relayer,
|
||||
relayer_at_this_chain: &AccountId,
|
||||
nonce: MessageNonce,
|
||||
message_data: DispatchMessageData<P::DispatchPayload, S::MessageFee>,
|
||||
message_data: DispatchMessageData<P::DispatchPayload>,
|
||||
) -> ReceivalResult {
|
||||
let mut data = self.storage.data();
|
||||
let is_correct_message = nonce == data.last_delivered_nonce() + 1;
|
||||
@@ -242,9 +240,9 @@ mod tests {
|
||||
use crate::{
|
||||
inbound_lane,
|
||||
mock::{
|
||||
dispatch_result, message_data, run_test, unrewarded_relayer, TestMessageDispatch,
|
||||
TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B,
|
||||
TEST_RELAYER_C,
|
||||
dispatch_result, inbound_message_data, run_test, unrewarded_relayer,
|
||||
TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A,
|
||||
TEST_RELAYER_B, TEST_RELAYER_C,
|
||||
},
|
||||
RuntimeInboundLaneStorage,
|
||||
};
|
||||
@@ -258,7 +256,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
nonce,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -386,7 +384,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
10,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::InvalidNonce
|
||||
);
|
||||
@@ -406,7 +404,7 @@ mod tests {
|
||||
&(TEST_RELAYER_A + current_nonce),
|
||||
&(TEST_RELAYER_A + current_nonce),
|
||||
current_nonce,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -417,7 +415,7 @@ mod tests {
|
||||
&(TEST_RELAYER_A + max_nonce + 1),
|
||||
&(TEST_RELAYER_A + max_nonce + 1),
|
||||
max_nonce + 1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::TooManyUnrewardedRelayers,
|
||||
);
|
||||
@@ -427,7 +425,7 @@ mod tests {
|
||||
&(TEST_RELAYER_A + max_nonce),
|
||||
&(TEST_RELAYER_A + max_nonce),
|
||||
max_nonce + 1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::TooManyUnrewardedRelayers,
|
||||
);
|
||||
@@ -445,7 +443,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
current_nonce,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -456,7 +454,7 @@ mod tests {
|
||||
&TEST_RELAYER_B,
|
||||
&TEST_RELAYER_B,
|
||||
max_nonce + 1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::TooManyUnconfirmedMessages,
|
||||
);
|
||||
@@ -466,7 +464,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
max_nonce + 1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::TooManyUnconfirmedMessages,
|
||||
);
|
||||
@@ -482,7 +480,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -491,7 +489,7 @@ mod tests {
|
||||
&TEST_RELAYER_B,
|
||||
&TEST_RELAYER_B,
|
||||
2,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -500,7 +498,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
3,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -524,7 +522,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(0))
|
||||
);
|
||||
@@ -533,7 +531,7 @@ mod tests {
|
||||
&TEST_RELAYER_B,
|
||||
&TEST_RELAYER_B,
|
||||
1,
|
||||
message_data(REGULAR_PAYLOAD).into()
|
||||
inbound_message_data(REGULAR_PAYLOAD)
|
||||
),
|
||||
ReceivalResult::InvalidNonce,
|
||||
);
|
||||
@@ -560,7 +558,7 @@ mod tests {
|
||||
&TEST_RELAYER_A,
|
||||
&TEST_RELAYER_A,
|
||||
1,
|
||||
message_data(payload).into()
|
||||
inbound_message_data(payload)
|
||||
),
|
||||
ReceivalResult::Dispatched(dispatch_result(1))
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#![allow(clippy::unused_unit)]
|
||||
|
||||
pub use inbound_lane::StoredInboundLaneData;
|
||||
pub use outbound_lane::StoredMessageData;
|
||||
pub use outbound_lane::StoredMessagePayload;
|
||||
pub use weights::WeightInfo;
|
||||
pub use weights_ext::{
|
||||
ensure_able_to_receive_confirmation, ensure_able_to_receive_message,
|
||||
@@ -59,17 +59,16 @@ use bp_messages::{
|
||||
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
|
||||
},
|
||||
total_unrewarded_messages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId,
|
||||
MessageData, MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData,
|
||||
OutboundMessageDetails, Parameter as MessagesParameter, UnrewardedRelayer,
|
||||
UnrewardedRelayersState,
|
||||
MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData,
|
||||
OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState,
|
||||
};
|
||||
use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, Size};
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get};
|
||||
use num_traits::{SaturatingAdd, Zero};
|
||||
use num_traits::Zero;
|
||||
use sp_std::{
|
||||
cell::RefCell, cmp::PartialOrd, collections::vec_deque::VecDeque, marker::PhantomData,
|
||||
ops::RangeInclusive, prelude::*,
|
||||
cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
mod inbound_lane;
|
||||
@@ -108,11 +107,6 @@ pub mod pallet {
|
||||
/// Gets the chain id value from the instance.
|
||||
#[pallet::constant]
|
||||
type BridgedChainId: Get<ChainId>;
|
||||
/// Pallet parameter that is opaque to the pallet itself, but may be used by the runtime
|
||||
/// for integrating the pallet.
|
||||
///
|
||||
/// All pallet parameters may only be updated either by the root, or by the pallet owner.
|
||||
type Parameter: MessagesParameter;
|
||||
|
||||
/// Maximal number of messages that may be pruned during maintenance. Maintenance occurs
|
||||
/// whenever new message is sent. The reason is that if you want to use lane, you should
|
||||
@@ -142,25 +136,14 @@ pub mod pallet {
|
||||
/// these messages are from different lanes.
|
||||
type MaxUnconfirmedMessagesAtInboundLane: Get<MessageNonce>;
|
||||
|
||||
/// Maximal size of the outbound payload.
|
||||
/// Maximal encoded size of the outbound payload.
|
||||
#[pallet::constant]
|
||||
type MaximalOutboundPayloadSize: Get<u32>;
|
||||
/// Payload type of outbound messages. This payload is dispatched on the bridged chain.
|
||||
type OutboundPayload: Parameter + Size;
|
||||
/// Message fee type of outbound messages. This fee is paid on this chain.
|
||||
type OutboundMessageFee: Default
|
||||
+ From<u64>
|
||||
+ PartialOrd
|
||||
+ Parameter
|
||||
+ SaturatingAdd
|
||||
+ Zero
|
||||
+ Copy
|
||||
+ MaxEncodedLen;
|
||||
|
||||
/// Payload type of inbound messages. This payload is dispatched on this chain.
|
||||
type InboundPayload: Decode;
|
||||
/// Message fee type of inbound messages. This fee is paid on the bridged chain.
|
||||
type InboundMessageFee: Decode + Zero;
|
||||
/// Identifier of relayer that deliver messages to this chain. Relayer reward is paid on the
|
||||
/// bridged chain.
|
||||
type InboundRelayer: Parameter + MaxEncodedLen;
|
||||
@@ -170,16 +153,11 @@ pub mod pallet {
|
||||
/// Target header chain.
|
||||
type TargetHeaderChain: TargetHeaderChain<Self::OutboundPayload, Self::AccountId>;
|
||||
/// Message payload verifier.
|
||||
type LaneMessageVerifier: LaneMessageVerifier<
|
||||
Self::RuntimeOrigin,
|
||||
Self::OutboundPayload,
|
||||
Self::OutboundMessageFee,
|
||||
>;
|
||||
type LaneMessageVerifier: LaneMessageVerifier<Self::RuntimeOrigin, Self::OutboundPayload>;
|
||||
/// Message delivery payment.
|
||||
type MessageDeliveryAndDispatchPayment: MessageDeliveryAndDispatchPayment<
|
||||
Self::RuntimeOrigin,
|
||||
Self::AccountId,
|
||||
Self::OutboundMessageFee,
|
||||
>;
|
||||
/// Handler for accepted messages.
|
||||
type OnMessageAccepted: OnMessageAccepted;
|
||||
@@ -189,19 +167,17 @@ pub mod pallet {
|
||||
// Types that are used by inbound_lane (on target chain).
|
||||
|
||||
/// Source header chain, as it is represented on target chain.
|
||||
type SourceHeaderChain: SourceHeaderChain<Self::InboundMessageFee>;
|
||||
type SourceHeaderChain: SourceHeaderChain;
|
||||
/// Message dispatch.
|
||||
type MessageDispatch: MessageDispatch<
|
||||
Self::AccountId,
|
||||
Self::InboundMessageFee,
|
||||
DispatchPayload = Self::InboundPayload,
|
||||
>;
|
||||
}
|
||||
|
||||
/// Shortcut to messages proof type for Config.
|
||||
type MessagesProofOf<T, I> = <<T as Config<I>>::SourceHeaderChain as SourceHeaderChain<
|
||||
<T as Config<I>>::InboundMessageFee,
|
||||
>>::MessagesProof;
|
||||
type MessagesProofOf<T, I> =
|
||||
<<T as Config<I>>::SourceHeaderChain as SourceHeaderChain>::MessagesProof;
|
||||
/// Shortcut to messages delivery proof type for Config.
|
||||
type MessagesDeliveryProofOf<T, I> =
|
||||
<<T as Config<I>>::TargetHeaderChain as TargetHeaderChain<
|
||||
@@ -241,101 +217,6 @@ pub mod pallet {
|
||||
<Self as OwnedBridgeModule<_>>::set_operating_mode(origin, operating_mode)
|
||||
}
|
||||
|
||||
/// Update pallet parameter.
|
||||
///
|
||||
/// May only be called either by root, or by `PalletOwner`.
|
||||
///
|
||||
/// The weight is: single read for permissions check + 2 writes for parameter value and
|
||||
/// event.
|
||||
#[pallet::weight((T::DbWeight::get().reads_writes(1, 2), DispatchClass::Operational))]
|
||||
pub fn update_pallet_parameter(
|
||||
origin: OriginFor<T>,
|
||||
parameter: T::Parameter,
|
||||
) -> DispatchResult {
|
||||
Self::ensure_owner_or_root(origin)?;
|
||||
parameter.save();
|
||||
Self::deposit_event(Event::ParameterUpdated { parameter });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send message over lane.
|
||||
#[pallet::weight(T::WeightInfo::send_message_weight(payload, T::DbWeight::get()))]
|
||||
pub fn send_message(
|
||||
origin: OriginFor<T>,
|
||||
lane_id: LaneId,
|
||||
payload: T::OutboundPayload,
|
||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
crate::send_message::<T, I>(origin, lane_id, payload, delivery_and_dispatch_fee).map(
|
||||
|sent_message| PostDispatchInfo {
|
||||
actual_weight: Some(sent_message.weight),
|
||||
pays_fee: Pays::Yes,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Pay additional fee for the message.
|
||||
#[pallet::weight(T::WeightInfo::maximal_increase_message_fee())]
|
||||
pub fn increase_message_fee(
|
||||
origin: OriginFor<T>,
|
||||
lane_id: LaneId,
|
||||
nonce: MessageNonce,
|
||||
additional_fee: T::OutboundMessageFee,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
Self::ensure_not_halted().map_err(Error::<T, I>::BridgeModule)?;
|
||||
// if someone tries to pay for already-delivered message, we're rejecting this intention
|
||||
// (otherwise this additional fee will be locked forever in relayers fund)
|
||||
//
|
||||
// if someone tries to pay for not-yet-sent message, we're rejecting this intention, or
|
||||
// we're risking to have mess in the storage
|
||||
let lane = outbound_lane::<T, I>(lane_id);
|
||||
ensure!(
|
||||
nonce > lane.data().latest_received_nonce,
|
||||
Error::<T, I>::MessageIsAlreadyDelivered
|
||||
);
|
||||
ensure!(
|
||||
nonce <= lane.data().latest_generated_nonce,
|
||||
Error::<T, I>::MessageIsNotYetSent
|
||||
);
|
||||
|
||||
// withdraw additional fee from submitter
|
||||
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
|
||||
&origin,
|
||||
&additional_fee,
|
||||
)
|
||||
.map_err(|err| {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"Submitter can't pay additional fee {:?} for the message {:?}/{:?}: {:?}",
|
||||
additional_fee,
|
||||
lane_id,
|
||||
nonce,
|
||||
err,
|
||||
);
|
||||
|
||||
Error::<T, I>::FailedToWithdrawMessageFee
|
||||
})?;
|
||||
|
||||
// and finally update fee in the storage
|
||||
let message_key = MessageKey { lane_id, nonce };
|
||||
let message_size = OutboundMessages::<T, I>::mutate(message_key, |message_data| {
|
||||
// saturating_add is fine here - overflow here means that someone controls all
|
||||
// chain funds, which shouldn't ever happen + `pay_delivery_and_dispatch_fee`
|
||||
// above will fail before we reach here
|
||||
let message_data = message_data.as_mut().expect(
|
||||
"the message is sent and not yet delivered; so it is in the storage; qed",
|
||||
);
|
||||
message_data.fee = message_data.fee.saturating_add(&additional_fee);
|
||||
message_data.payload.len()
|
||||
});
|
||||
|
||||
// compute actual dispatch weight that depends on the stored message size
|
||||
let actual_weight = T::WeightInfo::maximal_increase_message_fee()
|
||||
.min(T::WeightInfo::increase_message_fee(message_size as _));
|
||||
|
||||
Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes })
|
||||
}
|
||||
|
||||
/// Receive messages proof from bridged chain.
|
||||
///
|
||||
/// The weight of the call assumes that the transaction always brings outbound lane
|
||||
@@ -378,7 +259,6 @@ pub mod pallet {
|
||||
// verify messages proof && convert proof into messages
|
||||
let messages = verify_and_decode_messages_proof::<
|
||||
T::SourceHeaderChain,
|
||||
T::InboundMessageFee,
|
||||
T::InboundPayload,
|
||||
>(proof, messages_count)
|
||||
.map_err(|err| {
|
||||
@@ -636,8 +516,6 @@ pub mod pallet {
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config<I>, I: 'static = ()> {
|
||||
/// Pallet parameter has been updated.
|
||||
ParameterUpdated { parameter: T::Parameter },
|
||||
/// Message has been accepted and is waiting to be delivered.
|
||||
MessageAccepted { lane_id: LaneId, nonce: MessageNonce },
|
||||
/// Messages in the inclusive range have been delivered to the bridged chain.
|
||||
@@ -709,7 +587,7 @@ pub mod pallet {
|
||||
/// All queued outbound messages.
|
||||
#[pallet::storage]
|
||||
pub type OutboundMessages<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Blake2_128Concat, MessageKey, StoredMessageData<T, I>>;
|
||||
StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload<T, I>>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
|
||||
@@ -744,10 +622,7 @@ pub mod pallet {
|
||||
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
/// Get stored data of the outbound message with given nonce.
|
||||
pub fn outbound_message_data(
|
||||
lane: LaneId,
|
||||
nonce: MessageNonce,
|
||||
) -> Option<MessageData<T::OutboundMessageFee>> {
|
||||
pub fn outbound_message_data(lane: LaneId, nonce: MessageNonce) -> Option<MessagePayload> {
|
||||
OutboundMessages::<T, I>::get(MessageKey { lane_id: lane, nonce }).map(Into::into)
|
||||
}
|
||||
|
||||
@@ -755,12 +630,11 @@ pub mod pallet {
|
||||
pub fn inbound_message_data(
|
||||
lane: LaneId,
|
||||
payload: MessagePayload,
|
||||
outbound_details: OutboundMessageDetails<T::InboundMessageFee>,
|
||||
outbound_details: OutboundMessageDetails,
|
||||
) -> InboundMessageDetails {
|
||||
let mut dispatch_message = DispatchMessage {
|
||||
key: MessageKey { lane_id: lane, nonce: outbound_details.nonce },
|
||||
data: MessageData { payload, fee: outbound_details.delivery_and_dispatch_fee }
|
||||
.into(),
|
||||
data: payload.into(),
|
||||
};
|
||||
InboundMessageDetails {
|
||||
dispatch_weight: T::MessageDispatch::dispatch_weight(&mut dispatch_message),
|
||||
@@ -769,12 +643,8 @@ pub mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I>
|
||||
bp_messages::source_chain::MessagesBridge<
|
||||
T::RuntimeOrigin,
|
||||
T::OutboundMessageFee,
|
||||
T::OutboundPayload,
|
||||
> for Pallet<T, I>
|
||||
impl<T, I> bp_messages::source_chain::MessagesBridge<T::RuntimeOrigin, T::OutboundPayload>
|
||||
for Pallet<T, I>
|
||||
where
|
||||
T: Config<I>,
|
||||
I: 'static,
|
||||
@@ -785,9 +655,8 @@ where
|
||||
sender: T::RuntimeOrigin,
|
||||
lane: LaneId,
|
||||
message: T::OutboundPayload,
|
||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||
) -> Result<SendMessageArtifacts, Self::Error> {
|
||||
crate::send_message::<T, I>(sender, lane, message, delivery_and_dispatch_fee)
|
||||
crate::send_message::<T, I>(sender, lane, message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,21 +665,14 @@ fn send_message<T: Config<I>, I: 'static>(
|
||||
submitter: T::RuntimeOrigin,
|
||||
lane_id: LaneId,
|
||||
payload: T::OutboundPayload,
|
||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||
) -> sp_std::result::Result<
|
||||
SendMessageArtifacts,
|
||||
sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>,
|
||||
> {
|
||||
ensure_normal_operating_mode::<T, I>()?;
|
||||
|
||||
// the most lightweigh check is the message size check
|
||||
ensure!(
|
||||
payload.size() <= T::MaximalOutboundPayloadSize::get(),
|
||||
Error::<T, I>::MessageIsTooLarge,
|
||||
);
|
||||
|
||||
// initially, actual (post-dispatch) weight is equal to pre-dispatch weight
|
||||
let mut actual_weight = T::WeightInfo::send_message_weight(&payload, T::DbWeight::get());
|
||||
let mut actual_weight = frame_support::weights::Weight::zero(); // TODO (https://github.com/paritytech/parity-bridges-common/issues/1647): remove this
|
||||
|
||||
// let's first check if message can be delivered to target chain
|
||||
T::TargetHeaderChain::verify_message(&payload).map_err(|err| {
|
||||
@@ -826,46 +688,28 @@ fn send_message<T: Config<I>, I: 'static>(
|
||||
|
||||
// now let's enforce any additional lane rules
|
||||
let mut lane = outbound_lane::<T, I>(lane_id);
|
||||
T::LaneMessageVerifier::verify_message(
|
||||
&submitter,
|
||||
&delivery_and_dispatch_fee,
|
||||
&lane_id,
|
||||
&lane.data(),
|
||||
&payload,
|
||||
)
|
||||
.map_err(|err| {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"Message to lane {:?} is rejected by lane verifier: {:?}",
|
||||
lane_id,
|
||||
err,
|
||||
);
|
||||
T::LaneMessageVerifier::verify_message(&submitter, &lane_id, &lane.data(), &payload).map_err(
|
||||
|err| {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"Message to lane {:?} is rejected by lane verifier: {:?}",
|
||||
lane_id,
|
||||
err,
|
||||
);
|
||||
|
||||
Error::<T, I>::MessageRejectedByLaneVerifier
|
||||
})?;
|
||||
|
||||
// let's withdraw delivery and dispatch fee from submitter
|
||||
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
|
||||
&submitter,
|
||||
&delivery_and_dispatch_fee,
|
||||
)
|
||||
.map_err(|err| {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"Message to lane {:?} is rejected because submitter is unable to pay fee {:?}: {:?}",
|
||||
lane_id,
|
||||
delivery_and_dispatch_fee,
|
||||
err,
|
||||
);
|
||||
|
||||
Error::<T, I>::FailedToWithdrawMessageFee
|
||||
})?;
|
||||
Error::<T, I>::MessageRejectedByLaneVerifier
|
||||
},
|
||||
)?;
|
||||
|
||||
// finally, save message in outbound storage and emit event
|
||||
let encoded_payload = payload.encode();
|
||||
let encoded_payload_len = encoded_payload.len();
|
||||
let nonce =
|
||||
lane.send_message(MessageData { payload: encoded_payload, fee: delivery_and_dispatch_fee });
|
||||
ensure!(
|
||||
encoded_payload_len <= T::MaximalOutboundPayloadSize::get() as usize,
|
||||
Error::<T, I>::MessageIsTooLarge
|
||||
);
|
||||
let nonce = lane.send_message(encoded_payload);
|
||||
|
||||
// Guaranteed to be called outside only when the message is accepted.
|
||||
// We assume that the maximum weight call back used is `single_message_callback_overhead`, so do
|
||||
// not perform complex db operation in callback. If you want to, put these magic logic in
|
||||
@@ -920,32 +764,26 @@ fn send_message<T: Config<I>, I: 'static>(
|
||||
Ok(SendMessageArtifacts { nonce, weight: actual_weight })
|
||||
}
|
||||
|
||||
/// Calculate the relayers rewards
|
||||
/// Calculate the number of messages that the relayers have delivered.
|
||||
pub fn calc_relayers_rewards<T, I>(
|
||||
lane_id: LaneId,
|
||||
messages_relayers: VecDeque<UnrewardedRelayer<T::AccountId>>,
|
||||
received_range: &RangeInclusive<MessageNonce>,
|
||||
) -> RelayersRewards<T::AccountId, T::OutboundMessageFee>
|
||||
) -> RelayersRewards<T::AccountId>
|
||||
where
|
||||
T: frame_system::Config + crate::Config<I>,
|
||||
I: 'static,
|
||||
{
|
||||
// remember to reward relayers that have delivered messages
|
||||
// this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain
|
||||
let mut relayers_rewards: RelayersRewards<_, T::OutboundMessageFee> = RelayersRewards::new();
|
||||
let mut relayers_rewards = RelayersRewards::new();
|
||||
for entry in messages_relayers {
|
||||
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());
|
||||
|
||||
// loop won't proceed if current entry is ahead of received range (begin > end).
|
||||
// this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged chain
|
||||
let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default();
|
||||
for nonce in nonce_begin..=nonce_end {
|
||||
let key = MessageKey { lane_id, nonce };
|
||||
let message_data = OutboundMessages::<T, I>::get(key)
|
||||
.expect("message was just confirmed; we never prune unconfirmed messages; qed");
|
||||
relayer_reward.reward = relayer_reward.reward.saturating_add(&message_data.fee);
|
||||
relayer_reward.messages += 1;
|
||||
if nonce_end >= nonce_begin {
|
||||
*relayers_rewards.entry(entry.relayer).or_default() += nonce_end - nonce_begin + 1;
|
||||
}
|
||||
}
|
||||
relayers_rewards
|
||||
@@ -995,7 +833,6 @@ struct RuntimeInboundLaneStorage<T: Config<I>, I: 'static = ()> {
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage<T, I> {
|
||||
type MessageFee = T::InboundMessageFee;
|
||||
type Relayer = T::InboundRelayer;
|
||||
|
||||
fn id(&self) -> LaneId {
|
||||
@@ -1041,8 +878,6 @@ struct RuntimeOutboundLaneStorage<T, I = ()> {
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage<T, I> {
|
||||
type MessageFee = T::OutboundMessageFee;
|
||||
|
||||
fn id(&self) -> LaneId {
|
||||
self.lane_id
|
||||
}
|
||||
@@ -1056,17 +891,20 @@ impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn message(&self, nonce: &MessageNonce) -> Option<MessageData<T::OutboundMessageFee>> {
|
||||
fn message(&self, nonce: &MessageNonce) -> Option<MessagePayload> {
|
||||
OutboundMessages::<T, I>::get(MessageKey { lane_id: self.lane_id, nonce: *nonce })
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn save_message(
|
||||
&mut self,
|
||||
nonce: MessageNonce,
|
||||
mesage_data: MessageData<T::OutboundMessageFee>,
|
||||
) {
|
||||
OutboundMessages::<T, I>::insert(MessageKey { lane_id: self.lane_id, nonce }, mesage_data);
|
||||
fn save_message(&mut self, nonce: MessageNonce, message_payload: MessagePayload) {
|
||||
OutboundMessages::<T, I>::insert(
|
||||
MessageKey { lane_id: self.lane_id, nonce },
|
||||
StoredMessagePayload::<T, I>::try_from(message_payload).expect(
|
||||
"save_message is called after all checks in send_message; \
|
||||
send_message checks message size; \
|
||||
qed",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn remove_message(&mut self, nonce: &MessageNonce) {
|
||||
@@ -1075,10 +913,10 @@ impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag
|
||||
}
|
||||
|
||||
/// Verify messages proof and return proved messages with decoded payload.
|
||||
fn verify_and_decode_messages_proof<Chain: SourceHeaderChain<Fee>, Fee, DispatchPayload: Decode>(
|
||||
fn verify_and_decode_messages_proof<Chain: SourceHeaderChain, DispatchPayload: Decode>(
|
||||
proof: Chain::MessagesProof,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<DispatchMessage<DispatchPayload, Fee>>, Chain::Error> {
|
||||
) -> Result<ProvedMessages<DispatchMessage<DispatchPayload>>, Chain::Error> {
|
||||
// `receive_messages_proof` weight formula and `MaxUnconfirmedMessagesAtInboundLane` check
|
||||
// guarantees that the `message_count` is sane and Vec<Message> may be allocated.
|
||||
// (tx with too many messages will either be rejected from the pool, or will fail earlier)
|
||||
@@ -1102,12 +940,12 @@ fn verify_and_decode_messages_proof<Chain: SourceHeaderChain<Fee>, Fee, Dispatch
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
message, message_payload, run_test, unrewarded_relayer, Balance, RuntimeEvent as TestEvent,
|
||||
message, message_payload, run_test, unrewarded_relayer, RuntimeEvent as TestEvent,
|
||||
RuntimeOrigin, TestMessageDeliveryAndDispatchPayment, TestMessagesDeliveryProof,
|
||||
TestMessagesParameter, TestMessagesProof, TestOnDeliveryConfirmed1,
|
||||
TestOnDeliveryConfirmed2, TestOnMessageAccepted, TestRuntime, TokenConversionRate,
|
||||
MAX_OUTBOUND_PAYLOAD_SIZE, PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID,
|
||||
TEST_RELAYER_A, TEST_RELAYER_B,
|
||||
TestMessagesProof, TestOnDeliveryConfirmed1, TestOnDeliveryConfirmed2,
|
||||
TestOnMessageAccepted, TestRuntime, MAX_OUTBOUND_PAYLOAD_SIZE,
|
||||
PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A,
|
||||
TEST_RELAYER_B,
|
||||
};
|
||||
use bp_messages::{UnrewardedRelayer, UnrewardedRelayersState};
|
||||
use bp_test_utils::generate_owned_bridge_module_tests;
|
||||
@@ -1146,15 +984,13 @@ mod tests {
|
||||
|
||||
let message_nonce =
|
||||
outbound_lane::<TestRuntime, ()>(TEST_LANE_ID).data().latest_generated_nonce + 1;
|
||||
let weight = Pallet::<TestRuntime>::send_message(
|
||||
let weight = send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
REGULAR_PAYLOAD.declared_weight.ref_time(),
|
||||
)
|
||||
.expect("send_message has failed")
|
||||
.actual_weight
|
||||
.expect("send_message always returns Some");
|
||||
.weight;
|
||||
|
||||
// check event with assigned nonce
|
||||
assert_eq!(
|
||||
@@ -1169,12 +1005,6 @@ mod tests {
|
||||
}],
|
||||
);
|
||||
|
||||
// check that fee has been withdrawn from submitter
|
||||
assert!(TestMessageDeliveryAndDispatchPayment::is_fee_paid(
|
||||
1,
|
||||
REGULAR_PAYLOAD.declared_weight.ref_time()
|
||||
));
|
||||
|
||||
weight
|
||||
}
|
||||
|
||||
@@ -1217,102 +1047,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pallet_parameter_may_be_updated_by_root() {
|
||||
run_test(|| {
|
||||
get_ready_for_events();
|
||||
|
||||
let parameter = TestMessagesParameter::TokenConversionRate(10.into());
|
||||
assert_ok!(Pallet::<TestRuntime>::update_pallet_parameter(
|
||||
RuntimeOrigin::root(),
|
||||
parameter.clone(),
|
||||
));
|
||||
|
||||
assert_eq!(TokenConversionRate::get(), 10.into());
|
||||
assert_eq!(
|
||||
System::<TestRuntime>::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: TestEvent::Messages(Event::ParameterUpdated { parameter }),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pallet_parameter_may_be_updated_by_owner() {
|
||||
run_test(|| {
|
||||
PalletOwner::<TestRuntime>::put(2);
|
||||
get_ready_for_events();
|
||||
|
||||
let parameter = TestMessagesParameter::TokenConversionRate(10.into());
|
||||
assert_ok!(Pallet::<TestRuntime>::update_pallet_parameter(
|
||||
RuntimeOrigin::signed(2),
|
||||
parameter.clone(),
|
||||
));
|
||||
|
||||
assert_eq!(TokenConversionRate::get(), 10.into());
|
||||
assert_eq!(
|
||||
System::<TestRuntime>::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: TestEvent::Messages(Event::ParameterUpdated { parameter }),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pallet_parameter_cant_be_updated_by_arbitrary_submitter() {
|
||||
run_test(|| {
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::update_pallet_parameter(
|
||||
RuntimeOrigin::signed(2),
|
||||
TestMessagesParameter::TokenConversionRate(10.into()),
|
||||
),
|
||||
DispatchError::BadOrigin,
|
||||
);
|
||||
|
||||
PalletOwner::<TestRuntime>::put(2);
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::update_pallet_parameter(
|
||||
RuntimeOrigin::signed(1),
|
||||
TestMessagesParameter::TokenConversionRate(10.into()),
|
||||
),
|
||||
DispatchError::BadOrigin,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fixed_u128_works_as_i_think() {
|
||||
// this test is here just to be sure that conversion rate may be represented with FixedU128
|
||||
run_test(|| {
|
||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
||||
|
||||
// 1:1 conversion that we use by default for testnets
|
||||
let rialto_token = 1u64;
|
||||
let rialto_token_in_millau_tokens =
|
||||
TokenConversionRate::get().saturating_mul_int(rialto_token);
|
||||
assert_eq!(rialto_token_in_millau_tokens, 1);
|
||||
|
||||
// let's say conversion rate is 1:1.7
|
||||
let conversion_rate = FixedU128::saturating_from_rational(170, 100);
|
||||
let rialto_tokens = 100u64;
|
||||
let rialto_tokens_in_millau_tokens = conversion_rate.saturating_mul_int(rialto_tokens);
|
||||
assert_eq!(rialto_tokens_in_millau_tokens, 170);
|
||||
|
||||
// let's say conversion rate is 1:0.25
|
||||
let conversion_rate = FixedU128::saturating_from_rational(25, 100);
|
||||
let rialto_tokens = 100u64;
|
||||
let rialto_tokens_in_millau_tokens = conversion_rate.saturating_mul_int(rialto_tokens);
|
||||
assert_eq!(rialto_tokens_in_millau_tokens, 25);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pallet_rejects_transactions_if_halted() {
|
||||
run_test(|| {
|
||||
@@ -1324,25 +1058,14 @@ mod tests {
|
||||
));
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::send_message(
|
||||
send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
REGULAR_PAYLOAD.declared_weight.ref_time(),
|
||||
),
|
||||
Error::<TestRuntime, ()>::NotOperatingNormally,
|
||||
);
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
1,
|
||||
),
|
||||
Error::<TestRuntime, ()>::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted),
|
||||
);
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::receive_messages_proof(
|
||||
RuntimeOrigin::signed(1),
|
||||
@@ -1389,22 +1112,14 @@ mod tests {
|
||||
);
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::send_message(
|
||||
send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
REGULAR_PAYLOAD.declared_weight.ref_time(),
|
||||
),
|
||||
Error::<TestRuntime, ()>::NotOperatingNormally,
|
||||
);
|
||||
|
||||
assert_ok!(Pallet::<TestRuntime>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
1,
|
||||
));
|
||||
|
||||
assert_ok!(Pallet::<TestRuntime>::receive_messages_proof(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_RELAYER_A,
|
||||
@@ -1451,25 +1166,23 @@ mod tests {
|
||||
.extra
|
||||
.extend_from_slice(&[0u8; MAX_OUTBOUND_PAYLOAD_SIZE as usize]);
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::send_message(
|
||||
send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
message_payload.clone(),
|
||||
Balance::MAX,
|
||||
),
|
||||
Error::<TestRuntime, ()>::MessageIsTooLarge,
|
||||
);
|
||||
|
||||
// let's check that we're able to send `MAX_OUTBOUND_PAYLOAD_SIZE` messages
|
||||
while message_payload.size() > MAX_OUTBOUND_PAYLOAD_SIZE {
|
||||
while message_payload.encoded_size() as u32 > MAX_OUTBOUND_PAYLOAD_SIZE {
|
||||
message_payload.extra.pop();
|
||||
}
|
||||
assert_eq!(message_payload.size(), MAX_OUTBOUND_PAYLOAD_SIZE);
|
||||
assert_ok!(Pallet::<TestRuntime>::send_message(
|
||||
assert_eq!(message_payload.encoded_size() as u32, MAX_OUTBOUND_PAYLOAD_SIZE);
|
||||
assert_ok!(send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
message_payload,
|
||||
Balance::MAX,
|
||||
),);
|
||||
})
|
||||
}
|
||||
@@ -1479,11 +1192,10 @@ mod tests {
|
||||
run_test(|| {
|
||||
// messages with this payload are rejected by target chain verifier
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::send_message(
|
||||
send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
PAYLOAD_REJECTED_BY_TARGET_CHAIN,
|
||||
PAYLOAD_REJECTED_BY_TARGET_CHAIN.declared_weight.ref_time(),
|
||||
),
|
||||
Error::<TestRuntime, ()>::MessageRejectedByChainVerifier,
|
||||
);
|
||||
@@ -1494,34 +1206,15 @@ mod tests {
|
||||
fn lane_verifier_rejects_invalid_message_in_send_message() {
|
||||
run_test(|| {
|
||||
// messages with zero fee are rejected by lane verifier
|
||||
let mut message = REGULAR_PAYLOAD;
|
||||
message.reject_by_lane_verifier = true;
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::send_message(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
0
|
||||
),
|
||||
send_message::<TestRuntime, ()>(RuntimeOrigin::signed(1), TEST_LANE_ID, message,),
|
||||
Error::<TestRuntime, ()>::MessageRejectedByLaneVerifier,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_send_fails_if_submitter_cant_pay_message_fee() {
|
||||
run_test(|| {
|
||||
TestMessageDeliveryAndDispatchPayment::reject_payments();
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::send_message(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
REGULAR_PAYLOAD.declared_weight.ref_time(),
|
||||
),
|
||||
Error::<TestRuntime, ()>::FailedToWithdrawMessageFee,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn receive_messages_proof_works() {
|
||||
run_test(|| {
|
||||
@@ -1665,17 +1358,15 @@ mod tests {
|
||||
#[test]
|
||||
fn receive_messages_delivery_proof_rewards_relayers() {
|
||||
run_test(|| {
|
||||
assert_ok!(Pallet::<TestRuntime>::send_message(
|
||||
assert_ok!(send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
1000,
|
||||
));
|
||||
assert_ok!(Pallet::<TestRuntime>::send_message(
|
||||
assert_ok!(send_message::<TestRuntime, ()>(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
REGULAR_PAYLOAD,
|
||||
2000,
|
||||
));
|
||||
|
||||
// this reports delivery of message 1 => reward is paid to TEST_RELAYER_A
|
||||
@@ -1697,8 +1388,8 @@ mod tests {
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1000));
|
||||
assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 2000));
|
||||
assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1));
|
||||
assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 1));
|
||||
|
||||
// this reports delivery of both message 1 and message 2 => reward is paid only to
|
||||
// TEST_RELAYER_B
|
||||
@@ -1723,8 +1414,8 @@ mod tests {
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1000));
|
||||
assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 2000));
|
||||
assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1));
|
||||
assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1829,7 +1520,7 @@ mod tests {
|
||||
fn receive_messages_accepts_single_message_with_invalid_payload() {
|
||||
run_test(|| {
|
||||
let mut invalid_message = message(1, REGULAR_PAYLOAD);
|
||||
invalid_message.data.payload = Vec::new();
|
||||
invalid_message.payload = Vec::new();
|
||||
|
||||
assert_ok!(Pallet::<TestRuntime, ()>::receive_messages_proof(
|
||||
RuntimeOrigin::signed(1),
|
||||
@@ -1848,7 +1539,7 @@ mod tests {
|
||||
fn receive_messages_accepts_batch_with_message_with_invalid_payload() {
|
||||
run_test(|| {
|
||||
let mut invalid_message = message(2, REGULAR_PAYLOAD);
|
||||
invalid_message.data.payload = Vec::new();
|
||||
invalid_message.payload = Vec::new();
|
||||
|
||||
assert_ok!(Pallet::<TestRuntime, ()>::receive_messages_proof(
|
||||
RuntimeOrigin::signed(1),
|
||||
@@ -1884,73 +1575,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn increase_message_fee_fails_if_message_is_already_delivered() {
|
||||
run_test(|| {
|
||||
send_regular_message();
|
||||
receive_messages_delivery_proof();
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime, ()>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
100,
|
||||
),
|
||||
Error::<TestRuntime, ()>::MessageIsAlreadyDelivered,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn increase_message_fee_fails_if_message_is_not_yet_sent() {
|
||||
run_test(|| {
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime, ()>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
100,
|
||||
),
|
||||
Error::<TestRuntime, ()>::MessageIsNotYetSent,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn increase_message_fee_fails_if_submitter_cant_pay_additional_fee() {
|
||||
run_test(|| {
|
||||
send_regular_message();
|
||||
|
||||
TestMessageDeliveryAndDispatchPayment::reject_payments();
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime, ()>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
100,
|
||||
),
|
||||
Error::<TestRuntime, ()>::FailedToWithdrawMessageFee,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn increase_message_fee_succeeds() {
|
||||
run_test(|| {
|
||||
send_regular_message();
|
||||
|
||||
assert_ok!(Pallet::<TestRuntime, ()>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
100,
|
||||
),);
|
||||
assert!(TestMessageDeliveryAndDispatchPayment::is_fee_paid(1, 100));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weight_refund_from_receive_messages_proof_works() {
|
||||
run_test(|| {
|
||||
@@ -2187,101 +1811,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn increase_message_fee_weight_depends_on_message_size() {
|
||||
run_test(|| {
|
||||
let mut small_payload = message_payload(0, 100);
|
||||
let mut large_payload = message_payload(1, 100);
|
||||
small_payload.extra = vec![1; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 10];
|
||||
large_payload.extra = vec![2; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 5];
|
||||
|
||||
assert_ok!(Pallet::<TestRuntime>::send_message(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
small_payload,
|
||||
100,
|
||||
));
|
||||
assert_ok!(Pallet::<TestRuntime>::send_message(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
large_payload,
|
||||
100,
|
||||
));
|
||||
|
||||
let small_weight = Pallet::<TestRuntime>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
1,
|
||||
1,
|
||||
)
|
||||
.expect("increase_message_fee has failed")
|
||||
.actual_weight
|
||||
.expect("increase_message_fee always returns Some");
|
||||
|
||||
let large_weight = Pallet::<TestRuntime>::increase_message_fee(
|
||||
RuntimeOrigin::signed(1),
|
||||
TEST_LANE_ID,
|
||||
2,
|
||||
1,
|
||||
)
|
||||
.expect("increase_message_fee has failed")
|
||||
.actual_weight
|
||||
.expect("increase_message_fee always returns Some");
|
||||
|
||||
assert!(
|
||||
large_weight.ref_time() > small_weight.ref_time(),
|
||||
"Actual post-dispatch weigth for larger message {} must be larger than {} for small message",
|
||||
large_weight,
|
||||
small_weight,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weight_is_refunded_for_messages_that_are_not_pruned() {
|
||||
run_test(|| {
|
||||
// send first MAX messages - no messages are pruned
|
||||
let max_messages_to_prune = crate::mock::MaxMessagesToPruneAtOnce::get();
|
||||
let when_zero_messages_are_pruned = send_regular_message();
|
||||
let mut delivered_messages = DeliveredMessages::new(1, true);
|
||||
for _ in 1..max_messages_to_prune {
|
||||
assert_eq!(send_regular_message(), when_zero_messages_are_pruned);
|
||||
delivered_messages.note_dispatched_message(true);
|
||||
}
|
||||
|
||||
// confirm delivery of all sent messages
|
||||
assert_ok!(Pallet::<TestRuntime>::receive_messages_delivery_proof(
|
||||
RuntimeOrigin::signed(1),
|
||||
TestMessagesDeliveryProof(Ok((
|
||||
TEST_LANE_ID,
|
||||
InboundLaneData {
|
||||
last_confirmed_nonce: 1,
|
||||
relayers: vec![UnrewardedRelayer {
|
||||
relayer: 0,
|
||||
messages: delivered_messages,
|
||||
}]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
))),
|
||||
UnrewardedRelayersState {
|
||||
unrewarded_relayer_entries: 1,
|
||||
total_messages: max_messages_to_prune,
|
||||
last_delivered_nonce: max_messages_to_prune,
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
|
||||
// when next message is sent, MAX messages are pruned
|
||||
let weight_when_max_messages_are_pruned = send_regular_message();
|
||||
assert_eq!(
|
||||
weight_when_max_messages_are_pruned,
|
||||
when_zero_messages_are_pruned +
|
||||
crate::mock::DbWeight::get().writes(max_messages_to_prune),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_accepted_callbacks_are_called() {
|
||||
run_test(|| {
|
||||
@@ -2302,27 +1831,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_accepted_refunds_non_zero_weight() {
|
||||
run_test(|| {
|
||||
TestOnMessageAccepted::set_consumed_weight_per_message(
|
||||
crate::mock::DbWeight::get().writes(1),
|
||||
);
|
||||
let actual_callback_weight = send_regular_message();
|
||||
let pre_dispatch_weight = <TestRuntime as Config>::WeightInfo::send_message_weight(
|
||||
®ULAR_PAYLOAD,
|
||||
crate::mock::DbWeight::get(),
|
||||
);
|
||||
let prune_weight = crate::mock::DbWeight::get()
|
||||
.writes(<TestRuntime as Config>::MaxMessagesToPruneAtOnce::get());
|
||||
|
||||
assert_eq!(
|
||||
pre_dispatch_weight.saturating_sub(actual_callback_weight),
|
||||
crate::mock::DbWeight::get().reads(1).saturating_add(prune_weight)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_keys_computed_properly() {
|
||||
assert_eq!(
|
||||
@@ -2360,9 +1868,6 @@ mod tests {
|
||||
nonce: 0,
|
||||
dispatch_weight: Weight::from_ref_time(0),
|
||||
size: 0,
|
||||
delivery_and_dispatch_fee: 0,
|
||||
dispatch_fee_payment:
|
||||
bp_runtime::messages::DispatchFeePayment::AtTargetChain,
|
||||
},
|
||||
),
|
||||
InboundMessageDetails { dispatch_weight: REGULAR_PAYLOAD.declared_weight },
|
||||
|
||||
@@ -26,10 +26,11 @@ use bp_messages::{
|
||||
OnMessageAccepted, TargetHeaderChain,
|
||||
},
|
||||
target_chain::{
|
||||
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
|
||||
DispatchMessage, DispatchMessageData, MessageDispatch, ProvedLaneMessages, ProvedMessages,
|
||||
SourceHeaderChain,
|
||||
},
|
||||
DeliveredMessages, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce,
|
||||
OutboundLaneData, Parameter as MessagesParameter, UnrewardedRelayer,
|
||||
DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload,
|
||||
OutboundLaneData, UnrewardedRelayer,
|
||||
};
|
||||
use bp_runtime::{messages::MessageDispatchResult, Size};
|
||||
use codec::{Decode, Encode};
|
||||
@@ -42,7 +43,7 @@ use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header as SubstrateHeader,
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
FixedU128, Perbill,
|
||||
Perbill,
|
||||
};
|
||||
use std::{
|
||||
collections::{BTreeMap, VecDeque},
|
||||
@@ -55,6 +56,8 @@ pub type Balance = u64;
|
||||
pub struct TestPayload {
|
||||
/// Field that may be used to identify messages.
|
||||
pub id: u64,
|
||||
/// Reject this message by lane verifier?
|
||||
pub reject_by_lane_verifier: bool,
|
||||
/// Dispatch weight that is declared by the message sender.
|
||||
pub declared_weight: Weight,
|
||||
/// Message dispatch result.
|
||||
@@ -140,38 +143,20 @@ parameter_types! {
|
||||
pub const MaxMessagesToPruneAtOnce: u64 = 10;
|
||||
pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16;
|
||||
pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32;
|
||||
pub storage TokenConversionRate: FixedU128 = 1.into();
|
||||
pub const TestBridgedChainId: bp_runtime::ChainId = *b"test";
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||
pub enum TestMessagesParameter {
|
||||
TokenConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl MessagesParameter for TestMessagesParameter {
|
||||
fn save(&self) {
|
||||
match *self {
|
||||
TestMessagesParameter::TokenConversionRate(conversion_rate) =>
|
||||
TokenConversionRate::set(&conversion_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = ();
|
||||
type Parameter = TestMessagesParameter;
|
||||
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
|
||||
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
|
||||
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
|
||||
|
||||
type MaximalOutboundPayloadSize = frame_support::traits::ConstU32<MAX_OUTBOUND_PAYLOAD_SIZE>;
|
||||
type OutboundPayload = TestPayload;
|
||||
type OutboundMessageFee = TestMessageFee;
|
||||
|
||||
type InboundPayload = TestPayload;
|
||||
type InboundMessageFee = TestMessageFee;
|
||||
type InboundRelayer = TestRelayer;
|
||||
|
||||
type TargetHeaderChain = TestTargetHeaderChain;
|
||||
@@ -219,7 +204,7 @@ pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50);
|
||||
pub const PAYLOAD_REJECTED_BY_TARGET_CHAIN: TestPayload = message_payload(1, 50);
|
||||
|
||||
/// Vec of proved messages, grouped by lane.
|
||||
pub type MessagesByLaneVec = Vec<(LaneId, ProvedLaneMessages<Message<TestMessageFee>>)>;
|
||||
pub type MessagesByLaneVec = Vec<(LaneId, ProvedLaneMessages<Message>)>;
|
||||
|
||||
/// Test messages proof.
|
||||
#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
|
||||
@@ -233,14 +218,12 @@ impl Size for TestMessagesProof {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Result<Vec<Message<TestMessageFee>>, ()>> for TestMessagesProof {
|
||||
fn from(result: Result<Vec<Message<TestMessageFee>>, ()>) -> Self {
|
||||
impl From<Result<Vec<Message>, ()>> for TestMessagesProof {
|
||||
fn from(result: Result<Vec<Message>, ()>) -> Self {
|
||||
Self {
|
||||
result: result.map(|messages| {
|
||||
let mut messages_by_lane: BTreeMap<
|
||||
LaneId,
|
||||
ProvedLaneMessages<Message<TestMessageFee>>,
|
||||
> = BTreeMap::new();
|
||||
let mut messages_by_lane: BTreeMap<LaneId, ProvedLaneMessages<Message>> =
|
||||
BTreeMap::new();
|
||||
for message in messages {
|
||||
messages_by_lane.entry(message.key.lane_id).or_default().messages.push(message);
|
||||
}
|
||||
@@ -288,17 +271,16 @@ impl TargetHeaderChain<TestPayload, TestRelayer> for TestTargetHeaderChain {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TestLaneMessageVerifier;
|
||||
|
||||
impl LaneMessageVerifier<RuntimeOrigin, TestPayload, TestMessageFee> for TestLaneMessageVerifier {
|
||||
impl LaneMessageVerifier<RuntimeOrigin, TestPayload> for TestLaneMessageVerifier {
|
||||
type Error = &'static str;
|
||||
|
||||
fn verify_message(
|
||||
_submitter: &RuntimeOrigin,
|
||||
delivery_and_dispatch_fee: &TestMessageFee,
|
||||
_lane: &LaneId,
|
||||
_lane_outbound_data: &OutboundLaneData,
|
||||
_payload: &TestPayload,
|
||||
payload: &TestPayload,
|
||||
) -> Result<(), Self::Error> {
|
||||
if *delivery_and_dispatch_fee != 0 {
|
||||
if !payload.reject_by_lane_verifier {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TEST_ERROR)
|
||||
@@ -311,18 +293,6 @@ impl LaneMessageVerifier<RuntimeOrigin, TestPayload, TestMessageFee> for TestLan
|
||||
pub struct TestMessageDeliveryAndDispatchPayment;
|
||||
|
||||
impl TestMessageDeliveryAndDispatchPayment {
|
||||
/// Reject all payments.
|
||||
pub fn reject_payments() {
|
||||
frame_support::storage::unhashed::put(b":reject-message-fee:", &true);
|
||||
}
|
||||
|
||||
/// Returns true if given fee has been paid by given submitter.
|
||||
pub fn is_fee_paid(submitter: AccountId, fee: TestMessageFee) -> bool {
|
||||
let raw_origin: Result<frame_system::RawOrigin<_>, _> =
|
||||
RuntimeOrigin::signed(submitter).into();
|
||||
frame_support::storage::unhashed::get(b":message-fee:") == Some((raw_origin.unwrap(), fee))
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@@ -331,34 +301,21 @@ impl TestMessageDeliveryAndDispatchPayment {
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageDeliveryAndDispatchPayment<RuntimeOrigin, AccountId, TestMessageFee>
|
||||
impl MessageDeliveryAndDispatchPayment<RuntimeOrigin, AccountId>
|
||||
for TestMessageDeliveryAndDispatchPayment
|
||||
{
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
submitter: &RuntimeOrigin,
|
||||
fee: &TestMessageFee,
|
||||
) -> Result<(), Self::Error> {
|
||||
if frame_support::storage::unhashed::get(b":reject-message-fee:") == Some(true) {
|
||||
return Err(TEST_ERROR)
|
||||
}
|
||||
|
||||
let raw_origin: Result<frame_system::RawOrigin<_>, _> = submitter.clone().into();
|
||||
frame_support::storage::unhashed::put(b":message-fee:", &(raw_origin.unwrap(), fee));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pay_relayers_rewards(
|
||||
lane_id: LaneId,
|
||||
_lane_id: LaneId,
|
||||
message_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
|
||||
_confirmation_relayer: &AccountId,
|
||||
received_range: &RangeInclusive<MessageNonce>,
|
||||
) {
|
||||
let relayers_rewards =
|
||||
calc_relayers_rewards::<TestRuntime, ()>(lane_id, message_relayers, received_range);
|
||||
calc_relayers_rewards::<TestRuntime, ()>(message_relayers, received_range);
|
||||
for (relayer, reward) in &relayers_rewards {
|
||||
let key = (b":relayer-reward:", relayer, reward.reward).encode();
|
||||
let key = (b":relayer-reward:", relayer, reward).encode();
|
||||
frame_support::storage::unhashed::put(&key, &true);
|
||||
}
|
||||
}
|
||||
@@ -450,7 +407,7 @@ impl OnDeliveryConfirmed for TestOnDeliveryConfirmed2 {
|
||||
#[derive(Debug)]
|
||||
pub struct TestSourceHeaderChain;
|
||||
|
||||
impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
|
||||
impl SourceHeaderChain for TestSourceHeaderChain {
|
||||
type Error = &'static str;
|
||||
|
||||
type MessagesProof = TestMessagesProof;
|
||||
@@ -458,7 +415,7 @@ impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
|
||||
fn verify_messages_proof(
|
||||
proof: Self::MessagesProof,
|
||||
_messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<TestMessageFee>>, Self::Error> {
|
||||
) -> Result<ProvedMessages<Message>, Self::Error> {
|
||||
proof.result.map(|proof| proof.into_iter().collect()).map_err(|_| TEST_ERROR)
|
||||
}
|
||||
}
|
||||
@@ -467,10 +424,10 @@ impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
|
||||
#[derive(Debug)]
|
||||
pub struct TestMessageDispatch;
|
||||
|
||||
impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
|
||||
impl MessageDispatch<AccountId> for TestMessageDispatch {
|
||||
type DispatchPayload = TestPayload;
|
||||
|
||||
fn dispatch_weight(message: &mut DispatchMessage<TestPayload, TestMessageFee>) -> Weight {
|
||||
fn dispatch_weight(message: &mut DispatchMessage<TestPayload>) -> Weight {
|
||||
match message.data.payload.as_ref() {
|
||||
Ok(payload) => payload.declared_weight,
|
||||
Err(_) => Weight::from_ref_time(0),
|
||||
@@ -479,7 +436,7 @@ impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
|
||||
|
||||
fn dispatch(
|
||||
_relayer_account: &AccountId,
|
||||
message: DispatchMessage<TestPayload, TestMessageFee>,
|
||||
message: DispatchMessage<TestPayload>,
|
||||
) -> MessageDispatchResult {
|
||||
match message.data.payload.as_ref() {
|
||||
Ok(payload) => payload.dispatch_result.clone(),
|
||||
@@ -489,25 +446,31 @@ impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
|
||||
}
|
||||
|
||||
/// Return test lane message with given nonce and payload.
|
||||
pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message<TestMessageFee> {
|
||||
Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, data: message_data(payload) }
|
||||
pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message {
|
||||
Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, payload: payload.encode() }
|
||||
}
|
||||
|
||||
/// Return valid outbound message data, constructed from given payload.
|
||||
pub fn outbound_message_data(payload: TestPayload) -> MessagePayload {
|
||||
payload.encode()
|
||||
}
|
||||
|
||||
/// Return valid inbound (dispatch) message data, constructed from given payload.
|
||||
pub fn inbound_message_data(payload: TestPayload) -> DispatchMessageData<TestPayload> {
|
||||
DispatchMessageData { payload: Ok(payload) }
|
||||
}
|
||||
|
||||
/// Constructs message payload using given arguments and zero unspent weight.
|
||||
pub const fn message_payload(id: u64, declared_weight: u64) -> TestPayload {
|
||||
TestPayload {
|
||||
id,
|
||||
reject_by_lane_verifier: false,
|
||||
declared_weight: Weight::from_ref_time(declared_weight),
|
||||
dispatch_result: dispatch_result(0),
|
||||
extra: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return message data with valid fee for given payload.
|
||||
pub fn message_data(payload: TestPayload) -> MessageData<TestMessageFee> {
|
||||
MessageData { payload: payload.encode(), fee: 1 }
|
||||
}
|
||||
|
||||
/// Returns message dispatch result with given unspent weight.
|
||||
pub const fn dispatch_result(unspent_weight: u64) -> MessageDispatchResult {
|
||||
MessageDispatchResult {
|
||||
|
||||
@@ -20,19 +20,14 @@ use crate::Config;
|
||||
|
||||
use bitvec::prelude::*;
|
||||
use bp_messages::{
|
||||
DeliveredMessages, DispatchResultsBitVec, LaneId, MessageData, MessageNonce, OutboundLaneData,
|
||||
UnrewardedRelayer,
|
||||
DeliveredMessages, DispatchResultsBitVec, LaneId, MessageNonce, MessagePayload,
|
||||
OutboundLaneData, UnrewardedRelayer,
|
||||
};
|
||||
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
|
||||
use frame_support::{traits::Get, RuntimeDebug};
|
||||
use scale_info::{Type, TypeInfo};
|
||||
use frame_support::{BoundedVec, RuntimeDebug};
|
||||
use sp_std::collections::vec_deque::VecDeque;
|
||||
|
||||
/// Outbound lane storage.
|
||||
pub trait OutboundLaneStorage {
|
||||
/// Delivery and dispatch fee type on source chain.
|
||||
type MessageFee;
|
||||
|
||||
/// Lane id.
|
||||
fn id(&self) -> LaneId;
|
||||
/// Get lane data from the storage.
|
||||
@@ -41,64 +36,15 @@ pub trait OutboundLaneStorage {
|
||||
fn set_data(&mut self, data: OutboundLaneData);
|
||||
/// Returns saved outbound message payload.
|
||||
#[cfg(test)]
|
||||
fn message(&self, nonce: &MessageNonce) -> Option<MessageData<Self::MessageFee>>;
|
||||
fn message(&self, nonce: &MessageNonce) -> Option<MessagePayload>;
|
||||
/// Save outbound message in the storage.
|
||||
fn save_message(&mut self, nonce: MessageNonce, message_data: MessageData<Self::MessageFee>);
|
||||
fn save_message(&mut self, nonce: MessageNonce, message_payload: MessagePayload);
|
||||
/// Remove outbound message from the storage.
|
||||
fn remove_message(&mut self, nonce: &MessageNonce);
|
||||
}
|
||||
|
||||
/// Outbound message data wrapper that implements `MaxEncodedLen`.
|
||||
///
|
||||
/// We have already had `MaxEncodedLen`-like functionality before, but its usage has
|
||||
/// been localized and we haven't been passing it everywhere. This wrapper allows us
|
||||
/// to avoid passing these generic bounds all over the code.
|
||||
///
|
||||
/// The encoding of this type matches encoding of the corresponding `MessageData`.
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)]
|
||||
pub struct StoredMessageData<T: Config<I>, I: 'static>(pub MessageData<T::OutboundMessageFee>);
|
||||
|
||||
impl<T: Config<I>, I: 'static> sp_std::ops::Deref for StoredMessageData<T, I> {
|
||||
type Target = MessageData<T::OutboundMessageFee>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> sp_std::ops::DerefMut for StoredMessageData<T, I> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> From<StoredMessageData<T, I>>
|
||||
for MessageData<T::OutboundMessageFee>
|
||||
{
|
||||
fn from(data: StoredMessageData<T, I>) -> Self {
|
||||
data.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> TypeInfo for StoredMessageData<T, I> {
|
||||
type Identity = Self;
|
||||
|
||||
fn type_info() -> Type {
|
||||
MessageData::<T::OutboundMessageFee>::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> EncodeLike<StoredMessageData<T, I>>
|
||||
for MessageData<T::OutboundMessageFee>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> MaxEncodedLen for StoredMessageData<T, I> {
|
||||
fn max_encoded_len() -> usize {
|
||||
T::OutboundMessageFee::max_encoded_len()
|
||||
.saturating_add(T::MaximalOutboundPayloadSize::get() as usize)
|
||||
}
|
||||
}
|
||||
pub type StoredMessagePayload<T, I> = BoundedVec<u8, <T as Config<I>>::MaximalOutboundPayloadSize>;
|
||||
|
||||
/// Result of messages receival confirmation.
|
||||
#[derive(RuntimeDebug, PartialEq, Eq)]
|
||||
@@ -143,12 +89,12 @@ impl<S: OutboundLaneStorage> OutboundLane<S> {
|
||||
/// Send message over lane.
|
||||
///
|
||||
/// Returns new message nonce.
|
||||
pub fn send_message(&mut self, message_data: MessageData<S::MessageFee>) -> MessageNonce {
|
||||
pub fn send_message(&mut self, message_payload: MessagePayload) -> MessageNonce {
|
||||
let mut data = self.storage.data();
|
||||
let nonce = data.latest_generated_nonce + 1;
|
||||
data.latest_generated_nonce = nonce;
|
||||
|
||||
self.storage.save_message(nonce, message_data);
|
||||
self.storage.save_message(nonce, message_payload);
|
||||
self.storage.set_data(data);
|
||||
|
||||
nonce
|
||||
@@ -295,8 +241,8 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
mock::{
|
||||
message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, REGULAR_PAYLOAD,
|
||||
TEST_LANE_ID,
|
||||
outbound_message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime,
|
||||
REGULAR_PAYLOAD, TEST_LANE_ID,
|
||||
},
|
||||
outbound_lane,
|
||||
};
|
||||
@@ -324,9 +270,9 @@ mod tests {
|
||||
) -> ReceivalConfirmationResult {
|
||||
run_test(|| {
|
||||
let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
assert_eq!(lane.storage.data().latest_generated_nonce, 3);
|
||||
assert_eq!(lane.storage.data().latest_received_nonce, 0);
|
||||
let result = lane.confirm_delivery(3, latest_received_nonce, relayers);
|
||||
@@ -341,7 +287,7 @@ mod tests {
|
||||
run_test(|| {
|
||||
let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
assert_eq!(lane.storage.data().latest_generated_nonce, 0);
|
||||
assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 1);
|
||||
assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1);
|
||||
assert!(lane.storage.message(&1).is_some());
|
||||
assert_eq!(lane.storage.data().latest_generated_nonce, 1);
|
||||
});
|
||||
@@ -351,9 +297,9 @@ mod tests {
|
||||
fn confirm_delivery_works() {
|
||||
run_test(|| {
|
||||
let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 1);
|
||||
assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 2);
|
||||
assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 3);
|
||||
assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1);
|
||||
assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2);
|
||||
assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3);
|
||||
assert_eq!(lane.storage.data().latest_generated_nonce, 3);
|
||||
assert_eq!(lane.storage.data().latest_received_nonce, 0);
|
||||
assert_eq!(
|
||||
@@ -369,9 +315,9 @@ mod tests {
|
||||
fn confirm_delivery_rejects_nonce_lesser_than_latest_received() {
|
||||
run_test(|| {
|
||||
let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
assert_eq!(lane.storage.data().latest_generated_nonce, 3);
|
||||
assert_eq!(lane.storage.data().latest_received_nonce, 0);
|
||||
assert_eq!(
|
||||
@@ -470,9 +416,9 @@ mod tests {
|
||||
assert_eq!(lane.prune_messages(100), 0);
|
||||
assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1);
|
||||
// when nothing is confirmed, nothing is pruned
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
assert_eq!(lane.prune_messages(100), 0);
|
||||
assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1);
|
||||
// after confirmation, some messages are received
|
||||
@@ -496,9 +442,9 @@ mod tests {
|
||||
fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() {
|
||||
run_test(|| {
|
||||
let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
|
||||
assert_eq!(
|
||||
lane.confirm_delivery(0, 3, &unrewarded_relayers(1..=3)),
|
||||
ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected(3),
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Autogenerated weights for `pallet_bridge_messages`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-10-17, STEPS: 50, REPEAT: 20
|
||||
//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
|
||||
//! LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
||||
//! CHAIN: Some("dev"), DB CACHE: 1024
|
||||
@@ -50,11 +50,6 @@ use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for `pallet_bridge_messages`.
|
||||
pub trait WeightInfo {
|
||||
fn send_minimal_message_worst_case() -> Weight;
|
||||
fn send_1_kb_message_worst_case() -> Weight;
|
||||
fn send_16_kb_message_worst_case() -> Weight;
|
||||
fn maximal_increase_message_fee() -> Weight;
|
||||
fn increase_message_fee(i: u32) -> Weight;
|
||||
fn receive_single_message_proof() -> Weight;
|
||||
fn receive_two_messages_proof() -> Weight;
|
||||
fn receive_single_message_proof_with_outbound_lane_state() -> Weight;
|
||||
@@ -71,150 +66,98 @@ pub trait WeightInfo {
|
||||
/// 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> {
|
||||
fn send_minimal_message_worst_case() -> Weight {
|
||||
Weight::from_ref_time(61_807_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(10 as u64))
|
||||
}
|
||||
fn send_1_kb_message_worst_case() -> Weight {
|
||||
Weight::from_ref_time(65_074_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(10 as u64))
|
||||
}
|
||||
fn send_16_kb_message_worst_case() -> Weight {
|
||||
Weight::from_ref_time(73_584_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(10 as u64))
|
||||
}
|
||||
fn maximal_increase_message_fee() -> Weight {
|
||||
Weight::from_ref_time(2_522_629_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn increase_message_fee(i: u32) -> Weight {
|
||||
Weight::from_ref_time(27_072_000 as u64)
|
||||
.saturating_add(Weight::from_ref_time(892 as u64).saturating_mul(i as u64))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn receive_single_message_proof() -> Weight {
|
||||
Weight::from_ref_time(49_628_000 as u64)
|
||||
Weight::from_ref_time(50_596_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_two_messages_proof() -> Weight {
|
||||
Weight::from_ref_time(61_514_000 as u64)
|
||||
Weight::from_ref_time(77_041_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
|
||||
Weight::from_ref_time(65_960_000 as u64)
|
||||
Weight::from_ref_time(58_331_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_single_message_proof_1_kb() -> Weight {
|
||||
Weight::from_ref_time(48_009_000 as u64)
|
||||
Weight::from_ref_time(48_061_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn receive_single_message_proof_16_kb() -> Weight {
|
||||
Weight::from_ref_time(100_439_000 as u64)
|
||||
Weight::from_ref_time(101_601_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn receive_single_prepaid_message_proof() -> Weight {
|
||||
Weight::from_ref_time(50_463_000 as u64)
|
||||
Weight::from_ref_time(49_646_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_delivery_proof_for_single_message() -> Weight {
|
||||
Weight::from_ref_time(57_383_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
Weight::from_ref_time(55_108_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
|
||||
Weight::from_ref_time(62_003_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
Weight::from_ref_time(53_917_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
|
||||
Weight::from_ref_time(64_401_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(7 as u64))
|
||||
Weight::from_ref_time(57_335_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn send_minimal_message_worst_case() -> Weight {
|
||||
Weight::from_ref_time(61_807_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(10 as u64))
|
||||
}
|
||||
fn send_1_kb_message_worst_case() -> Weight {
|
||||
Weight::from_ref_time(65_074_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(10 as u64))
|
||||
}
|
||||
fn send_16_kb_message_worst_case() -> Weight {
|
||||
Weight::from_ref_time(73_584_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(10 as u64))
|
||||
}
|
||||
fn maximal_increase_message_fee() -> Weight {
|
||||
Weight::from_ref_time(2_522_629_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn increase_message_fee(i: u32) -> Weight {
|
||||
Weight::from_ref_time(27_072_000 as u64)
|
||||
.saturating_add(Weight::from_ref_time(892 as u64).saturating_mul(i as u64))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn receive_single_message_proof() -> Weight {
|
||||
Weight::from_ref_time(49_628_000 as u64)
|
||||
Weight::from_ref_time(50_596_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_two_messages_proof() -> Weight {
|
||||
Weight::from_ref_time(61_514_000 as u64)
|
||||
Weight::from_ref_time(77_041_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
|
||||
Weight::from_ref_time(65_960_000 as u64)
|
||||
Weight::from_ref_time(58_331_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_single_message_proof_1_kb() -> Weight {
|
||||
Weight::from_ref_time(48_009_000 as u64)
|
||||
Weight::from_ref_time(48_061_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn receive_single_message_proof_16_kb() -> Weight {
|
||||
Weight::from_ref_time(100_439_000 as u64)
|
||||
Weight::from_ref_time(101_601_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as u64))
|
||||
}
|
||||
fn receive_single_prepaid_message_proof() -> Weight {
|
||||
Weight::from_ref_time(50_463_000 as u64)
|
||||
Weight::from_ref_time(49_646_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_delivery_proof_for_single_message() -> Weight {
|
||||
Weight::from_ref_time(57_383_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as u64))
|
||||
Weight::from_ref_time(55_108_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
|
||||
Weight::from_ref_time(62_003_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(6 as u64))
|
||||
Weight::from_ref_time(53_917_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
|
||||
Weight::from_ref_time(64_401_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(7 as u64))
|
||||
Weight::from_ref_time(57_335_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as u64))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,82 +35,16 @@ const SIGNED_EXTENSIONS_SIZE: u32 = 1024;
|
||||
pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024;
|
||||
|
||||
/// Ensure that weights from `WeightInfoExt` implementation are looking correct.
|
||||
pub fn ensure_weights_are_correct<W: WeightInfoExt>(
|
||||
expected_default_message_delivery_tx_weight: Weight,
|
||||
expected_additional_byte_delivery_weight: Weight,
|
||||
expected_messages_delivery_confirmation_tx_weight: Weight,
|
||||
expected_pay_inbound_dispatch_fee_weight: Weight,
|
||||
db_weight: RuntimeDbWeight,
|
||||
) {
|
||||
// verify `send_message` weight components
|
||||
assert_ne!(W::send_message_overhead(), Weight::zero());
|
||||
assert_ne!(W::send_message_size_overhead(0), Weight::zero());
|
||||
|
||||
pub fn ensure_weights_are_correct<W: WeightInfoExt>() {
|
||||
// verify `receive_messages_proof` weight components
|
||||
assert_ne!(W::receive_messages_proof_overhead(), Weight::zero());
|
||||
assert_ne!(W::receive_messages_proof_messages_overhead(1), Weight::zero());
|
||||
assert_ne!(W::receive_messages_proof_outbound_lane_state_overhead(), Weight::zero());
|
||||
assert_ne!(W::storage_proof_size_overhead(1), Weight::zero());
|
||||
|
||||
// verify that the hardcoded value covers `receive_messages_proof` weight
|
||||
let actual_single_regular_message_delivery_tx_weight = W::receive_messages_proof_weight(
|
||||
&PreComputedSize(
|
||||
(EXPECTED_DEFAULT_MESSAGE_LENGTH + W::expected_extra_storage_proof_size()) as usize,
|
||||
),
|
||||
1,
|
||||
Weight::zero(),
|
||||
);
|
||||
assert!(
|
||||
actual_single_regular_message_delivery_tx_weight
|
||||
.all_lte(expected_default_message_delivery_tx_weight),
|
||||
"Default message delivery transaction weight {} is larger than expected weight {}",
|
||||
actual_single_regular_message_delivery_tx_weight,
|
||||
expected_default_message_delivery_tx_weight,
|
||||
);
|
||||
|
||||
// verify that hardcoded value covers additional byte length of `receive_messages_proof` weight
|
||||
let actual_additional_byte_delivery_weight = W::storage_proof_size_overhead(1);
|
||||
assert!(
|
||||
actual_additional_byte_delivery_weight.all_lte(expected_additional_byte_delivery_weight),
|
||||
"Single additional byte delivery weight {} is larger than expected weight {}",
|
||||
actual_additional_byte_delivery_weight,
|
||||
expected_additional_byte_delivery_weight,
|
||||
);
|
||||
|
||||
// verify `receive_messages_delivery_proof` weight components
|
||||
assert_ne!(W::receive_messages_delivery_proof_overhead(), Weight::zero());
|
||||
assert_ne!(W::storage_proof_size_overhead(1), Weight::zero());
|
||||
|
||||
// `receive_messages_delivery_proof_messages_overhead` and
|
||||
// `receive_messages_delivery_proof_relayers_overhead` may return zero if rewards are not paid
|
||||
// during confirmations delivery, so we're not checking it here
|
||||
|
||||
// verify that the hardcoded value covers `receive_messages_delivery_proof` weight
|
||||
let actual_messages_delivery_confirmation_tx_weight = W::receive_messages_delivery_proof_weight(
|
||||
&PreComputedSize(W::expected_extra_storage_proof_size() as usize),
|
||||
&UnrewardedRelayersState {
|
||||
unrewarded_relayer_entries: 1,
|
||||
total_messages: 1,
|
||||
..Default::default()
|
||||
},
|
||||
db_weight,
|
||||
);
|
||||
assert!(
|
||||
actual_messages_delivery_confirmation_tx_weight
|
||||
.all_lte(expected_messages_delivery_confirmation_tx_weight),
|
||||
"Messages delivery confirmation transaction weight {} is larger than expected weight {}",
|
||||
actual_messages_delivery_confirmation_tx_weight,
|
||||
expected_messages_delivery_confirmation_tx_weight,
|
||||
);
|
||||
|
||||
// verify pay-dispatch-fee overhead for inbound messages
|
||||
let actual_pay_inbound_dispatch_fee_weight = W::pay_inbound_dispatch_fee_overhead();
|
||||
assert!(
|
||||
actual_pay_inbound_dispatch_fee_weight.all_lte(expected_pay_inbound_dispatch_fee_weight),
|
||||
"Weight {} of pay-dispatch-fee overhead for inbound messages is larger than expected weight {}",
|
||||
actual_pay_inbound_dispatch_fee_weight,
|
||||
expected_pay_inbound_dispatch_fee_weight,
|
||||
);
|
||||
}
|
||||
|
||||
/// Ensure that we're able to receive maximal (by-size and by-weight) message from other chain.
|
||||
@@ -198,17 +132,6 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
|
||||
// Functions that are directly mapped to extrinsics weights.
|
||||
|
||||
/// Weight of message send extrinsic.
|
||||
fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight {
|
||||
let transaction_overhead = Self::send_message_overhead();
|
||||
let message_size_overhead = Self::send_message_size_overhead(message.size());
|
||||
let call_back_overhead = Self::single_message_callback_overhead(db_weight);
|
||||
|
||||
transaction_overhead
|
||||
.saturating_add(message_size_overhead)
|
||||
.saturating_add(call_back_overhead)
|
||||
}
|
||||
|
||||
/// Weight of message delivery extrinsic.
|
||||
fn receive_messages_proof_weight(
|
||||
proof: &impl Size,
|
||||
@@ -274,20 +197,6 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
|
||||
// Functions that are used by extrinsics weights formulas.
|
||||
|
||||
/// Returns weight of message send transaction (`send_message`).
|
||||
fn send_message_overhead() -> Weight {
|
||||
Self::send_minimal_message_worst_case()
|
||||
}
|
||||
|
||||
/// Returns weight that needs to be accounted when message of given size is sent
|
||||
/// (`send_message`).
|
||||
fn send_message_size_overhead(message_size: u32) -> Weight {
|
||||
let message_size_in_kb = (1024u64 + message_size as u64) / 1024;
|
||||
let single_kb_weight =
|
||||
(Self::send_16_kb_message_worst_case() - Self::send_1_kb_message_worst_case()) / 15;
|
||||
message_size_in_kb * single_kb_weight
|
||||
}
|
||||
|
||||
/// Returns weight overhead of message delivery transaction (`receive_messages_proof`).
|
||||
fn receive_messages_proof_overhead() -> Weight {
|
||||
let weight_of_two_messages_and_two_tx_overheads =
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Autogenerated weights for `pallet_bridge_parachains`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-10-04, STEPS: 50, REPEAT: 20
|
||||
//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
|
||||
//! LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
||||
//! CHAIN: Some("dev"), DB CACHE: 1024
|
||||
@@ -61,19 +61,19 @@ pub trait WeightInfo {
|
||||
pub struct BridgeWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight {
|
||||
Weight::from_ref_time(0 as u64)
|
||||
.saturating_add(Weight::from_ref_time(24_869_000 as u64).saturating_mul(p as u64))
|
||||
Weight::from_ref_time(51_173_000 as u64)
|
||||
.saturating_add(Weight::from_ref_time(24_495_968 as u64).saturating_mul(p as u64))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as u64))
|
||||
.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(p as u64)))
|
||||
.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(p as u64)))
|
||||
}
|
||||
fn submit_parachain_heads_with_1kb_proof() -> Weight {
|
||||
Weight::from_ref_time(56_262_000 as u64)
|
||||
Weight::from_ref_time(58_175_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
fn submit_parachain_heads_with_16kb_proof() -> Weight {
|
||||
Weight::from_ref_time(105_189_000 as u64)
|
||||
Weight::from_ref_time(101_796_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
@@ -82,19 +82,19 @@ impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight {
|
||||
Weight::from_ref_time(0 as u64)
|
||||
.saturating_add(Weight::from_ref_time(24_869_000 as u64).saturating_mul(p as u64))
|
||||
Weight::from_ref_time(51_173_000 as u64)
|
||||
.saturating_add(Weight::from_ref_time(24_495_968 as u64).saturating_mul(p as u64))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as u64))
|
||||
.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(p as u64)))
|
||||
.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(p as u64)))
|
||||
}
|
||||
fn submit_parachain_heads_with_1kb_proof() -> Weight {
|
||||
Weight::from_ref_time(56_262_000 as u64)
|
||||
Weight::from_ref_time(58_175_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as u64))
|
||||
}
|
||||
fn submit_parachain_heads_with_16kb_proof() -> Weight {
|
||||
Weight::from_ref_time(105_189_000 as u64)
|
||||
Weight::from_ref_time(101_796_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as u64))
|
||||
}
|
||||
|
||||
@@ -97,17 +97,14 @@ parameter_types! {
|
||||
impl pallet_bridge_messages::Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = ();
|
||||
type Parameter = ();
|
||||
type MaxMessagesToPruneAtOnce = frame_support::traits::ConstU64<0>;
|
||||
type MaxUnrewardedRelayerEntriesAtInboundLane = frame_support::traits::ConstU64<8>;
|
||||
type MaxUnconfirmedMessagesAtInboundLane = frame_support::traits::ConstU64<8>;
|
||||
|
||||
type MaximalOutboundPayloadSize = frame_support::traits::ConstU32<1024>;
|
||||
type OutboundPayload = ();
|
||||
type OutboundMessageFee = Balance;
|
||||
|
||||
type InboundPayload = ();
|
||||
type InboundMessageFee = Balance;
|
||||
type InboundRelayer = AccountId;
|
||||
|
||||
type TargetHeaderChain = ForbidOutboundMessages;
|
||||
|
||||
@@ -20,43 +20,31 @@
|
||||
use crate::{Config, RelayerRewards};
|
||||
|
||||
use bp_messages::source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards};
|
||||
use frame_support::{sp_runtime::SaturatedConversion, traits::Get};
|
||||
use sp_arithmetic::traits::{Saturating, Zero};
|
||||
use frame_support::sp_runtime::SaturatedConversion;
|
||||
use sp_arithmetic::traits::{Saturating, UniqueSaturatedFrom, Zero};
|
||||
use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive};
|
||||
|
||||
/// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism
|
||||
/// for the messages pallet.
|
||||
pub struct MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance, GetConfirmationFee>(
|
||||
PhantomData<(T, MessagesInstance, GetConfirmationFee)>,
|
||||
pub struct MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance>(
|
||||
PhantomData<(T, MessagesInstance)>,
|
||||
);
|
||||
|
||||
impl<T, MessagesInstance, GetConfirmationFee>
|
||||
MessageDeliveryAndDispatchPayment<T::RuntimeOrigin, T::AccountId, T::Reward>
|
||||
for MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance, GetConfirmationFee>
|
||||
impl<T, MessagesInstance> MessageDeliveryAndDispatchPayment<T::RuntimeOrigin, T::AccountId>
|
||||
for MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance>
|
||||
where
|
||||
T: Config + pallet_bridge_messages::Config<MessagesInstance, OutboundMessageFee = T::Reward>,
|
||||
T: Config + pallet_bridge_messages::Config<MessagesInstance>,
|
||||
MessagesInstance: 'static,
|
||||
GetConfirmationFee: Get<T::Reward>,
|
||||
{
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
_submitter: &T::RuntimeOrigin,
|
||||
_fee: &T::Reward,
|
||||
) -> Result<(), Self::Error> {
|
||||
// nothing shall happen here, because XCM deals with fee payment (planned to be burnt?
|
||||
// or transferred to the treasury?)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pay_relayers_rewards(
|
||||
lane_id: bp_messages::LaneId,
|
||||
_lane_id: bp_messages::LaneId,
|
||||
messages_relayers: VecDeque<bp_messages::UnrewardedRelayer<T::AccountId>>,
|
||||
confirmation_relayer: &T::AccountId,
|
||||
received_range: &RangeInclusive<bp_messages::MessageNonce>,
|
||||
) {
|
||||
let relayers_rewards = pallet_bridge_messages::calc_relayers_rewards::<T, MessagesInstance>(
|
||||
lane_id,
|
||||
messages_relayers,
|
||||
received_range,
|
||||
);
|
||||
@@ -64,7 +52,10 @@ where
|
||||
register_relayers_rewards::<T>(
|
||||
confirmation_relayer,
|
||||
relayers_rewards,
|
||||
GetConfirmationFee::get(),
|
||||
// TODO (https://github.com/paritytech/parity-bridges-common/issues/1318): this shall be fixed
|
||||
// in some way. ATM the future of the `register_relayers_rewards` is not yet known
|
||||
100_000_u32.into(),
|
||||
10_000_u32.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -72,13 +63,17 @@ where
|
||||
// Update rewards to given relayers, optionally rewarding confirmation relayer.
|
||||
fn register_relayers_rewards<T: Config>(
|
||||
confirmation_relayer: &T::AccountId,
|
||||
relayers_rewards: RelayersRewards<T::AccountId, T::Reward>,
|
||||
relayers_rewards: RelayersRewards<T::AccountId>,
|
||||
delivery_fee: T::Reward,
|
||||
confirmation_fee: T::Reward,
|
||||
) {
|
||||
// reward every relayer except `confirmation_relayer`
|
||||
let mut confirmation_relayer_reward = T::Reward::zero();
|
||||
for (relayer, reward) in relayers_rewards {
|
||||
let mut relayer_reward = reward.reward;
|
||||
for (relayer, messages) in relayers_rewards {
|
||||
// sane runtime configurations guarantee that the number of messages will be below
|
||||
// `u32::MAX`
|
||||
let mut relayer_reward =
|
||||
T::Reward::unique_saturated_from(messages).saturating_mul(delivery_fee);
|
||||
|
||||
if relayer != *confirmation_relayer {
|
||||
// If delivery confirmation is submitted by other relayer, let's deduct confirmation fee
|
||||
@@ -87,12 +82,11 @@ fn register_relayers_rewards<T: Config>(
|
||||
// If confirmation fee has been increased (or if it was the only component of message
|
||||
// fee), then messages relayer may receive zero reward.
|
||||
let mut confirmation_reward =
|
||||
T::Reward::saturated_from(reward.messages).saturating_mul(confirmation_fee);
|
||||
T::Reward::saturated_from(messages).saturating_mul(confirmation_fee);
|
||||
confirmation_reward = sp_std::cmp::min(confirmation_reward, relayer_reward);
|
||||
relayer_reward = relayer_reward.saturating_sub(confirmation_reward);
|
||||
confirmation_relayer_reward =
|
||||
confirmation_relayer_reward.saturating_add(confirmation_reward);
|
||||
|
||||
register_relayer_reward::<T>(&relayer, relayer_reward);
|
||||
} else {
|
||||
// If delivery confirmation is submitted by this relayer, let's add confirmation fee
|
||||
@@ -134,32 +128,27 @@ mod tests {
|
||||
const RELAYER_2: AccountId = 2;
|
||||
const RELAYER_3: AccountId = 3;
|
||||
|
||||
fn relayers_rewards() -> RelayersRewards<AccountId, Balance> {
|
||||
vec![
|
||||
(RELAYER_1, bp_messages::source_chain::RelayerRewards { reward: 100, messages: 2 }),
|
||||
(RELAYER_2, bp_messages::source_chain::RelayerRewards { reward: 100, messages: 3 }),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
fn relayers_rewards() -> RelayersRewards<AccountId> {
|
||||
vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
|
||||
run_test(|| {
|
||||
register_relayers_rewards::<TestRuntime>(&RELAYER_2, relayers_rewards(), 10);
|
||||
register_relayers_rewards::<TestRuntime>(&RELAYER_2, relayers_rewards(), 50, 10);
|
||||
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_1), Some(80));
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(120));
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(170));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn confirmation_relayer_is_rewarded_if_it_has_not_delivered_any_delivered_messages() {
|
||||
run_test(|| {
|
||||
register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 10);
|
||||
register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 50, 10);
|
||||
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_1), Some(80));
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(70));
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(120));
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_3), Some(50));
|
||||
});
|
||||
}
|
||||
@@ -167,11 +156,11 @@ mod tests {
|
||||
#[test]
|
||||
fn only_confirmation_relayer_is_rewarded_if_confirmation_fee_has_significantly_increased() {
|
||||
run_test(|| {
|
||||
register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 1000);
|
||||
register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 50, 1000);
|
||||
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_1), None);
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), None);
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_3), Some(200));
|
||||
assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_3), Some(250));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Autogenerated weights for `pallet_bridge_relayers`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-10-04, STEPS: 50, REPEAT: 20
|
||||
//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
|
||||
//! LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
||||
//! CHAIN: Some("dev"), DB CACHE: 1024
|
||||
@@ -59,7 +59,7 @@ pub trait WeightInfo {
|
||||
pub struct BridgeWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
fn claim_rewards() -> Weight {
|
||||
Weight::from_ref_time(55_856_000 as u64)
|
||||
Weight::from_ref_time(59_334_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as u64))
|
||||
}
|
||||
@@ -68,7 +68,7 @@ impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn claim_rewards() -> Weight {
|
||||
Weight::from_ref_time(55_856_000 as u64)
|
||||
Weight::from_ref_time(59_334_000 as u64)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as u64))
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@ use bp_runtime::{
|
||||
use frame_support::{
|
||||
dispatch::DispatchClass,
|
||||
parameter_types,
|
||||
sp_runtime::{FixedU128, MultiAddress, MultiSigner},
|
||||
sp_runtime::{MultiAddress, MultiSigner},
|
||||
weights::{
|
||||
constants::ExtrinsicBaseWeight, WeightToFeeCoefficient, WeightToFeeCoefficients,
|
||||
WeightToFeePolynomial,
|
||||
},
|
||||
Parameter, RuntimeDebug,
|
||||
RuntimeDebug,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
|
||||
@@ -27,16 +27,14 @@ pub use bp_bridge_hub_rococo::{
|
||||
account_info_storage_key, AccountId, AccountPublic, AccountSigner, Address, Balance,
|
||||
BlockLength, BlockNumber, BlockWeights, Hash, Hasher, Hashing, Header, Index, Nonce,
|
||||
SS58Prefix, Signature, SignedBlock, SignedExtensions, UncheckedExtrinsic, WeightToFee,
|
||||
ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT, DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
|
||||
EXTRA_STORAGE_PROOF_SIZE, MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
|
||||
MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
|
||||
PAY_INBOUND_DISPATCH_FEE_WEIGHT, TX_EXTRA_BYTES,
|
||||
TX_EXTRA_BYTES,
|
||||
};
|
||||
use bp_messages::*;
|
||||
use bp_runtime::{
|
||||
decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, Parachain,
|
||||
};
|
||||
use frame_support::{dispatch::DispatchClass, sp_runtime::FixedU128, Parameter, RuntimeDebug};
|
||||
use frame_support::{dispatch::DispatchClass, RuntimeDebug};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// BridgeHubWococo parachain.
|
||||
|
||||
@@ -27,14 +27,14 @@ use bp_runtime::{decl_bridge_runtime_apis, Chain};
|
||||
use frame_support::{
|
||||
dispatch::DispatchClass,
|
||||
weights::{constants::WEIGHT_PER_SECOND, IdentityFee, Weight},
|
||||
Parameter, RuntimeDebug,
|
||||
RuntimeDebug,
|
||||
};
|
||||
use frame_system::limits;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::{storage::StateVersion, Hasher as HasherT};
|
||||
use sp_runtime::{
|
||||
traits::{IdentifyAccount, Verify},
|
||||
FixedU128, MultiSignature, MultiSigner, Perbill,
|
||||
MultiSignature, MultiSigner, Perbill,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration};
|
||||
@@ -69,38 +69,6 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128;
|
||||
/// Maximal number of unconfirmed messages in Millau confirmation transaction.
|
||||
pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128;
|
||||
|
||||
/// Weight of single regular message delivery transaction on Millau chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
|
||||
|
||||
/// Increase of delivery transaction weight on Millau chain with every additional message byte.
|
||||
///
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on Millau chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
|
||||
Weight::from_ref_time(2_000_000_000);
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Millau chain.
|
||||
///
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(700_000_000);
|
||||
|
||||
/// The target length of a session (how often authorities change) on Millau measured in of number of
|
||||
/// blocks.
|
||||
///
|
||||
@@ -237,13 +205,4 @@ pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages";
|
||||
/// Name of the transaction payment pallet at the Millau runtime.
|
||||
pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment";
|
||||
|
||||
/// Name of the Rialto->Millau (actually DOT->KSM) conversion rate stored in the Millau runtime.
|
||||
pub const RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = "RialtoToMillauConversionRate";
|
||||
/// Name of the RialtoParachain->Millau (actually DOT->KSM) conversion rate stored in the Millau
|
||||
/// runtime.
|
||||
pub const RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str =
|
||||
"RialtoParachainToMillauConversionRate";
|
||||
/// Name of the RialtoParachain fee multiplier parameter, stored in the Millau runtime.
|
||||
pub const RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME: &str = "RialtoParachainFeeMultiplier";
|
||||
|
||||
decl_bridge_runtime_apis!(millau);
|
||||
|
||||
@@ -25,13 +25,13 @@ use bp_runtime::{decl_bridge_runtime_apis, Chain, Parachain};
|
||||
use frame_support::{
|
||||
dispatch::DispatchClass,
|
||||
weights::{constants::WEIGHT_PER_SECOND, IdentityFee, Weight},
|
||||
Parameter, RuntimeDebug,
|
||||
RuntimeDebug,
|
||||
};
|
||||
use frame_system::limits;
|
||||
use sp_core::Hasher as HasherT;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||
FixedU128, MultiSignature, MultiSigner, Perbill,
|
||||
MultiSignature, MultiSigner, Perbill,
|
||||
};
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
@@ -66,39 +66,6 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024;
|
||||
/// Maximal number of unconfirmed messages in Rialto confirmation transaction.
|
||||
pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024;
|
||||
|
||||
/// Weight of single regular message delivery transaction on RialtoParachain chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
|
||||
|
||||
/// Increase of delivery transaction weight on RialtoParachain chain with every additional message
|
||||
/// byte.
|
||||
///
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on RialtoParachain chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
|
||||
Weight::from_ref_time(2_000_000_000);
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Rialto chain.
|
||||
///
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(600_000_000);
|
||||
|
||||
/// Block number type used in Rialto.
|
||||
pub type BlockNumber = u32;
|
||||
|
||||
@@ -176,11 +143,4 @@ pub const WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME: &str = "BridgeRialtoParach
|
||||
/// Name of the transaction payment pallet at the Rialto parachain runtime.
|
||||
pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment";
|
||||
|
||||
/// Name of the Millau->RialtoParachain (actually KSM->DOT) conversion rate stored in the Rialto
|
||||
/// parachain runtime.
|
||||
pub const MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME: &str =
|
||||
"MillauToRialtoParachainConversionRate";
|
||||
/// Name of the Millau fee multiplier parameter, stored in the Rialto parachain runtime.
|
||||
pub const MILLAU_FEE_MULTIPLIER_PARAMETER_NAME: &str = "MillauFeeMultiplier";
|
||||
|
||||
decl_bridge_runtime_apis!(rialto_parachain);
|
||||
|
||||
@@ -25,13 +25,13 @@ use bp_runtime::{decl_bridge_runtime_apis, Chain};
|
||||
use frame_support::{
|
||||
dispatch::DispatchClass,
|
||||
weights::{constants::WEIGHT_PER_SECOND, IdentityFee, Weight},
|
||||
Parameter, RuntimeDebug,
|
||||
RuntimeDebug,
|
||||
};
|
||||
use frame_system::limits;
|
||||
use sp_core::Hasher as HasherT;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||
FixedU128, MultiSignature, MultiSigner, Perbill,
|
||||
MultiSignature, MultiSigner, Perbill,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
@@ -60,38 +60,6 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024;
|
||||
/// Maximal number of unconfirmed messages in Rialto confirmation transaction.
|
||||
pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024;
|
||||
|
||||
/// Weight of single regular message delivery transaction on Rialto chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
|
||||
|
||||
/// Increase of delivery transaction weight on Rialto chain with every additional message byte.
|
||||
///
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on Rialto chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
|
||||
Weight::from_ref_time(2_000_000_000);
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Rialto chain.
|
||||
///
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(700_000_000);
|
||||
|
||||
/// The target length of a session (how often authorities change) on Rialto measured in of number of
|
||||
/// blocks.
|
||||
///
|
||||
@@ -203,9 +171,6 @@ pub const WITH_RIALTO_MESSAGES_PALLET_NAME: &str = "BridgeRialtoMessages";
|
||||
/// Name of the With-Rialto parachains bridge pallet instance that is deployed at bridged chains.
|
||||
pub const WITH_RIALTO_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeRialtoParachains";
|
||||
|
||||
/// Name of the Millau->Rialto (actually KSM->DOT) conversion rate stored in the Rialto runtime.
|
||||
pub const MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME: &str = "MillauToRialtoConversionRate";
|
||||
|
||||
/// Name of the parachain registrar pallet in the Rialto runtime.
|
||||
pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar";
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
[package]
|
||||
name = "bp-statemine"
|
||||
description = "Primitives of Statemine runtime."
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Bridge Dependencies
|
||||
|
||||
bp-polkadot-core = { path = "../polkadot-core", default-features = false }
|
||||
|
||||
# Substrate Based Dependencies
|
||||
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"bp-polkadot-core/std",
|
||||
"sp-version/std",
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
// 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_attr(not(feature = "std"), no_std)]
|
||||
// RuntimeApi generated functions
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
pub use bp_polkadot_core::*;
|
||||
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
/// Statemine Chain.
|
||||
pub type Statemine = PolkadotLike;
|
||||
|
||||
/// Known Statemine runtime version.
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: sp_version::create_runtime_str!("statemine"),
|
||||
impl_name: sp_version::create_runtime_str!("statemine"),
|
||||
authoring_version: 1,
|
||||
spec_version: 9300,
|
||||
impl_version: 0,
|
||||
apis: sp_version::create_apis_vec![[]],
|
||||
transaction_version: 8,
|
||||
state_version: 1,
|
||||
};
|
||||
@@ -21,7 +21,7 @@
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use bitvec::prelude::*;
|
||||
use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, OperatingMode};
|
||||
use bp_runtime::{BasicOperatingMode, OperatingMode};
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_support::RuntimeDebug;
|
||||
use scale_info::TypeInfo;
|
||||
@@ -65,16 +65,6 @@ impl OperatingMode for MessagesOperatingMode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Messages pallet parameter.
|
||||
pub trait Parameter: frame_support::Parameter {
|
||||
/// Save parameter value in the runtime storage.
|
||||
fn save(&self);
|
||||
}
|
||||
|
||||
impl Parameter for () {
|
||||
fn save(&self) {}
|
||||
}
|
||||
|
||||
/// Lane identifier.
|
||||
pub type LaneId = [u8; 4];
|
||||
|
||||
@@ -96,22 +86,13 @@ pub struct MessageKey {
|
||||
pub nonce: MessageNonce,
|
||||
}
|
||||
|
||||
/// Message data as it is stored in the storage.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct MessageData<Fee> {
|
||||
/// Message payload.
|
||||
pub payload: MessagePayload,
|
||||
/// Message delivery and dispatch fee, paid by the submitter.
|
||||
pub fee: Fee,
|
||||
}
|
||||
|
||||
/// Message as it is stored in the storage.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct Message<Fee> {
|
||||
pub struct Message {
|
||||
/// Message key.
|
||||
pub key: MessageKey,
|
||||
/// Message data.
|
||||
pub data: MessageData<Fee>,
|
||||
/// Message payload.
|
||||
pub payload: MessagePayload,
|
||||
}
|
||||
|
||||
/// Inbound lane data.
|
||||
@@ -198,7 +179,7 @@ impl<RelayerId> InboundLaneData<RelayerId> {
|
||||
|
||||
/// Outbound message details, returned by runtime APIs.
|
||||
#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)]
|
||||
pub struct OutboundMessageDetails<OutboundMessageFee> {
|
||||
pub struct OutboundMessageDetails {
|
||||
/// Nonce assigned to the message.
|
||||
pub nonce: MessageNonce,
|
||||
/// Message dispatch weight.
|
||||
@@ -208,10 +189,6 @@ pub struct OutboundMessageDetails<OutboundMessageFee> {
|
||||
pub dispatch_weight: Weight,
|
||||
/// Size of the encoded message.
|
||||
pub size: u32,
|
||||
/// Delivery+dispatch fee paid by the message submitter at the source chain.
|
||||
pub delivery_and_dispatch_fee: OutboundMessageFee,
|
||||
/// Where the fee for dispatching message is paid?
|
||||
pub dispatch_fee_payment: DispatchFeePayment,
|
||||
}
|
||||
|
||||
/// Inbound message details, returned by runtime APIs.
|
||||
|
||||
@@ -27,17 +27,8 @@ use sp_std::{
|
||||
ops::RangeInclusive,
|
||||
};
|
||||
|
||||
/// Relayers rewards, grouped by relayer account id.
|
||||
pub type RelayersRewards<AccountId, Balance> = BTreeMap<AccountId, RelayerRewards<Balance>>;
|
||||
|
||||
/// Single relayer rewards.
|
||||
#[derive(RuntimeDebug, Default)]
|
||||
pub struct RelayerRewards<Balance> {
|
||||
/// Total rewards that are to be paid to the relayer.
|
||||
pub reward: Balance,
|
||||
/// Total number of messages relayed by this relayer.
|
||||
pub messages: MessageNonce,
|
||||
}
|
||||
/// Number of messages, delivered by relayers.
|
||||
pub type RelayersRewards<AccountId> = BTreeMap<AccountId, MessageNonce>;
|
||||
|
||||
/// Target chain API. Used by source chain to verify target chain proofs.
|
||||
///
|
||||
@@ -83,7 +74,7 @@ pub trait TargetHeaderChain<Payload, AccountId> {
|
||||
/// Lane3 until some block, ...), then it may be built using this verifier.
|
||||
///
|
||||
/// Any fee requirements should also be enforced here.
|
||||
pub trait LaneMessageVerifier<SenderOrigin, Payload, Fee> {
|
||||
pub trait LaneMessageVerifier<SenderOrigin, Payload> {
|
||||
/// Error type.
|
||||
type Error: Debug + Into<&'static str>;
|
||||
|
||||
@@ -91,7 +82,6 @@ pub trait LaneMessageVerifier<SenderOrigin, Payload, Fee> {
|
||||
/// lane.
|
||||
fn verify_message(
|
||||
submitter: &SenderOrigin,
|
||||
delivery_and_dispatch_fee: &Fee,
|
||||
lane: &LaneId,
|
||||
outbound_data: &OutboundLaneData,
|
||||
payload: &Payload,
|
||||
@@ -107,21 +97,10 @@ pub trait LaneMessageVerifier<SenderOrigin, Payload, Fee> {
|
||||
/// 3) message-dispatch fee. It is paid by relayer for processing message by target chain;
|
||||
/// 4) message-receiving-delivery-transaction-fee. It is submitted to the source node
|
||||
/// by relayer.
|
||||
///
|
||||
/// So to be sure that any non-altruist relayer would agree to deliver message, submitter
|
||||
/// should set `delivery_and_dispatch_fee` to at least (equivalent of): sum of fees from (2)
|
||||
/// to (4) above, plus some interest for the relayer.
|
||||
pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> {
|
||||
pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId> {
|
||||
/// Error type.
|
||||
type Error: Debug + Into<&'static str>;
|
||||
|
||||
/// Withhold/write-off delivery_and_dispatch_fee from submitter account to
|
||||
/// some relayers-fund account.
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
submitter: &SenderOrigin,
|
||||
fee: &Balance,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Pay rewards for delivering messages to the given relayers.
|
||||
///
|
||||
/// The implementation may also choose to pay reward to the `confirmation_relayer`, which is
|
||||
@@ -134,18 +113,9 @@ pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> {
|
||||
);
|
||||
}
|
||||
|
||||
impl<SenderOrigin, AccountId, Balance>
|
||||
MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> for ()
|
||||
{
|
||||
impl<SenderOrigin, AccountId> MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId> for () {
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
_submitter: &SenderOrigin,
|
||||
_fee: &Balance,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pay_relayers_rewards(
|
||||
_lane_id: LaneId,
|
||||
_messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
|
||||
@@ -165,7 +135,7 @@ pub struct SendMessageArtifacts {
|
||||
}
|
||||
|
||||
/// Messages bridge API to be used from other pallets.
|
||||
pub trait MessagesBridge<SenderOrigin, Balance, Payload> {
|
||||
pub trait MessagesBridge<SenderOrigin, Payload> {
|
||||
/// Error type.
|
||||
type Error: Debug;
|
||||
|
||||
@@ -176,7 +146,6 @@ pub trait MessagesBridge<SenderOrigin, Balance, Payload> {
|
||||
sender: SenderOrigin,
|
||||
lane: LaneId,
|
||||
message: Payload,
|
||||
delivery_and_dispatch_fee: Balance,
|
||||
) -> Result<SendMessageArtifacts, Self::Error>;
|
||||
}
|
||||
|
||||
@@ -184,16 +153,13 @@ pub trait MessagesBridge<SenderOrigin, Balance, Payload> {
|
||||
#[derive(Eq, RuntimeDebug, PartialEq)]
|
||||
pub struct NoopMessagesBridge;
|
||||
|
||||
impl<SenderOrigin, Balance, Payload> MessagesBridge<SenderOrigin, Balance, Payload>
|
||||
for NoopMessagesBridge
|
||||
{
|
||||
impl<SenderOrigin, Payload> MessagesBridge<SenderOrigin, Payload> for NoopMessagesBridge {
|
||||
type Error = &'static str;
|
||||
|
||||
fn send_message(
|
||||
_sender: SenderOrigin,
|
||||
_lane: LaneId,
|
||||
_message: Payload,
|
||||
_delivery_and_dispatch_fee: Balance,
|
||||
) -> Result<SendMessageArtifacts, Self::Error> {
|
||||
Ok(SendMessageArtifacts { nonce: 0, weight: Weight::zero() })
|
||||
}
|
||||
@@ -266,14 +232,11 @@ impl<Payload, AccountId> TargetHeaderChain<Payload, AccountId> for ForbidOutboun
|
||||
}
|
||||
}
|
||||
|
||||
impl<SenderOrigin, Payload, Fee> LaneMessageVerifier<SenderOrigin, Payload, Fee>
|
||||
for ForbidOutboundMessages
|
||||
{
|
||||
impl<SenderOrigin, Payload> LaneMessageVerifier<SenderOrigin, Payload> for ForbidOutboundMessages {
|
||||
type Error = &'static str;
|
||||
|
||||
fn verify_message(
|
||||
_submitter: &SenderOrigin,
|
||||
_delivery_and_dispatch_fee: &Fee,
|
||||
_lane: &LaneId,
|
||||
_outbound_data: &OutboundLaneData,
|
||||
_payload: &Payload,
|
||||
@@ -282,18 +245,11 @@ impl<SenderOrigin, Payload, Fee> LaneMessageVerifier<SenderOrigin, Payload, Fee>
|
||||
}
|
||||
}
|
||||
|
||||
impl<SenderOrigin, AccountId, Balance>
|
||||
MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> for ForbidOutboundMessages
|
||||
impl<SenderOrigin, AccountId> MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId>
|
||||
for ForbidOutboundMessages
|
||||
{
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
_submitter: &SenderOrigin,
|
||||
_fee: &Balance,
|
||||
) -> Result<(), Self::Error> {
|
||||
Err(ALL_OUTBOUND_MESSAGES_REJECTED)
|
||||
}
|
||||
|
||||
fn pay_relayers_rewards(
|
||||
_lane_id: LaneId,
|
||||
_messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Primitives of messages module, that are used on the target chain.
|
||||
|
||||
use crate::{LaneId, Message, MessageData, MessageKey, OutboundLaneData};
|
||||
use crate::{LaneId, Message, MessageKey, MessagePayload, OutboundLaneData};
|
||||
|
||||
use bp_runtime::{messages::MessageDispatchResult, Size};
|
||||
use codec::{Decode, Encode, Error as CodecError};
|
||||
@@ -38,20 +38,18 @@ pub struct ProvedLaneMessages<Message> {
|
||||
|
||||
/// Message data with decoded dispatch payload.
|
||||
#[derive(RuntimeDebug)]
|
||||
pub struct DispatchMessageData<DispatchPayload, Fee> {
|
||||
pub struct DispatchMessageData<DispatchPayload> {
|
||||
/// Result of dispatch payload decoding.
|
||||
pub payload: Result<DispatchPayload, CodecError>,
|
||||
/// Message delivery and dispatch fee, paid by the submitter.
|
||||
pub fee: Fee,
|
||||
}
|
||||
|
||||
/// Message with decoded dispatch payload.
|
||||
#[derive(RuntimeDebug)]
|
||||
pub struct DispatchMessage<DispatchPayload, Fee> {
|
||||
pub struct DispatchMessage<DispatchPayload> {
|
||||
/// Message key.
|
||||
pub key: MessageKey,
|
||||
/// Message data with decoded dispatch payload.
|
||||
pub data: DispatchMessageData<DispatchPayload, Fee>,
|
||||
pub data: DispatchMessageData<DispatchPayload>,
|
||||
}
|
||||
|
||||
/// Source chain API. Used by target chain, to verify source chain proofs.
|
||||
@@ -59,7 +57,7 @@ pub struct DispatchMessage<DispatchPayload, Fee> {
|
||||
/// All implementations of this trait should only work with finalized data that
|
||||
/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane
|
||||
/// that's stuck) and/or processing messages without paying fees.
|
||||
pub trait SourceHeaderChain<Fee> {
|
||||
pub trait SourceHeaderChain {
|
||||
/// Error type.
|
||||
type Error: Debug + Into<&'static str>;
|
||||
|
||||
@@ -81,11 +79,11 @@ pub trait SourceHeaderChain<Fee> {
|
||||
fn verify_messages_proof(
|
||||
proof: Self::MessagesProof,
|
||||
messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<Fee>>, Self::Error>;
|
||||
) -> Result<ProvedMessages<Message>, Self::Error>;
|
||||
}
|
||||
|
||||
/// Called when inbound message is received.
|
||||
pub trait MessageDispatch<AccountId, Fee> {
|
||||
pub trait MessageDispatch<AccountId> {
|
||||
/// Decoded message payload type. Valid message may contain invalid payload. In this case
|
||||
/// message is delivered, but dispatch fails. Therefore, two separate types of payload
|
||||
/// (opaque `MessagePayload` used in delivery and this `DispatchPayload` used in dispatch).
|
||||
@@ -96,7 +94,7 @@ pub trait MessageDispatch<AccountId, Fee> {
|
||||
/// This function must return correct upper bound of dispatch weight. The return value
|
||||
/// of this function is expected to match return value of the corresponding
|
||||
/// `From<Chain>InboundLaneApi::message_details().dispatch_weight` call.
|
||||
fn dispatch_weight(message: &mut DispatchMessage<Self::DispatchPayload, Fee>) -> Weight;
|
||||
fn dispatch_weight(message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight;
|
||||
|
||||
/// Called when inbound message is received.
|
||||
///
|
||||
@@ -107,7 +105,7 @@ pub trait MessageDispatch<AccountId, Fee> {
|
||||
/// it must be paid inside this method to the `relayer_account`.
|
||||
fn dispatch(
|
||||
relayer_account: &AccountId,
|
||||
message: DispatchMessage<Self::DispatchPayload, Fee>,
|
||||
message: DispatchMessage<Self::DispatchPayload>,
|
||||
) -> MessageDispatchResult;
|
||||
}
|
||||
|
||||
@@ -117,20 +115,15 @@ impl<Message> Default for ProvedLaneMessages<Message> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<DispatchPayload: Decode, Fee> From<Message<Fee>> for DispatchMessage<DispatchPayload, Fee> {
|
||||
fn from(message: Message<Fee>) -> Self {
|
||||
DispatchMessage { key: message.key, data: message.data.into() }
|
||||
impl<DispatchPayload: Decode> From<Message> for DispatchMessage<DispatchPayload> {
|
||||
fn from(message: Message) -> Self {
|
||||
DispatchMessage { key: message.key, data: message.payload.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DispatchPayload: Decode, Fee> From<MessageData<Fee>>
|
||||
for DispatchMessageData<DispatchPayload, Fee>
|
||||
{
|
||||
fn from(data: MessageData<Fee>) -> Self {
|
||||
DispatchMessageData {
|
||||
payload: DispatchPayload::decode(&mut &data.payload[..]),
|
||||
fee: data.fee,
|
||||
}
|
||||
impl<DispatchPayload: Decode> From<MessagePayload> for DispatchMessageData<DispatchPayload> {
|
||||
fn from(payload: MessagePayload) -> Self {
|
||||
DispatchMessageData { payload: DispatchPayload::decode(&mut &payload[..]) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,29 +135,26 @@ pub struct ForbidInboundMessages;
|
||||
const ALL_INBOUND_MESSAGES_REJECTED: &str =
|
||||
"This chain is configured to reject all inbound messages";
|
||||
|
||||
impl<Fee> SourceHeaderChain<Fee> for ForbidInboundMessages {
|
||||
impl SourceHeaderChain for ForbidInboundMessages {
|
||||
type Error = &'static str;
|
||||
type MessagesProof = ();
|
||||
|
||||
fn verify_messages_proof(
|
||||
_proof: Self::MessagesProof,
|
||||
_messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<Fee>>, Self::Error> {
|
||||
) -> Result<ProvedMessages<Message>, Self::Error> {
|
||||
Err(ALL_INBOUND_MESSAGES_REJECTED)
|
||||
}
|
||||
}
|
||||
|
||||
impl<AccountId, Fee> MessageDispatch<AccountId, Fee> for ForbidInboundMessages {
|
||||
impl<AccountId> MessageDispatch<AccountId> for ForbidInboundMessages {
|
||||
type DispatchPayload = ();
|
||||
|
||||
fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload, Fee>) -> Weight {
|
||||
fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight {
|
||||
Weight::MAX
|
||||
}
|
||||
|
||||
fn dispatch(
|
||||
_: &AccountId,
|
||||
_: DispatchMessage<Self::DispatchPayload, Fee>,
|
||||
) -> MessageDispatchResult {
|
||||
fn dispatch(_: &AccountId, _: DispatchMessage<Self::DispatchPayload>) -> MessageDispatchResult {
|
||||
MessageDispatchResult {
|
||||
dispatch_result: false,
|
||||
unspent_weight: Weight::zero(),
|
||||
|
||||
@@ -126,49 +126,12 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128;
|
||||
/// Maximal number of unconfirmed messages at inbound lane.
|
||||
pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 8192;
|
||||
|
||||
// One important thing about weight-related constants here is that actually we may have
|
||||
// different weights on different Polkadot-like chains. But now all deployments are
|
||||
// almost the same, so we're exporting constants from this crate.
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on Polkadot-like chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
|
||||
Weight::from_ref_time(2_000_000_000);
|
||||
|
||||
/// Increase of delivery transaction weight on Polkadot-like chain with every additional message
|
||||
/// byte.
|
||||
///
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
|
||||
|
||||
/// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded
|
||||
/// call itself.
|
||||
///
|
||||
/// Can be computed by subtracting encoded call size from raw transaction size.
|
||||
pub const TX_EXTRA_BYTES: u32 = 256;
|
||||
|
||||
/// Weight of single regular message delivery transaction on Polkadot-like chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Polkadot-like chain.
|
||||
///
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(600_000_000);
|
||||
|
||||
/// Re-export `time_units` to make usage easier.
|
||||
pub use time_units::*;
|
||||
|
||||
|
||||
@@ -300,21 +300,7 @@ macro_rules! decl_bridge_messages_runtime_apis {
|
||||
///
|
||||
/// This API is implemented by runtimes that are receiving messages from this chain, not by this
|
||||
/// chain's runtime itself.
|
||||
pub trait [<To $chain:camel OutboundLaneApi>]<OutboundMessageFee: Parameter, OutboundPayload: Parameter> {
|
||||
/// Estimate message delivery and dispatch fee that needs to be paid by the sender on
|
||||
/// this chain.
|
||||
///
|
||||
/// Returns `None` if message is too expensive to be sent to this chain from the bridged chain.
|
||||
///
|
||||
/// Please keep in mind that this method returns the lowest message fee required for message
|
||||
/// to be accepted to the lane. It may be a good idea to pay a bit over this price to account
|
||||
/// for future exchange rate changes and guarantee that relayer would deliver your message
|
||||
/// to the target chain.
|
||||
fn estimate_message_delivery_and_dispatch_fee(
|
||||
lane_id: LaneId,
|
||||
payload: OutboundPayload,
|
||||
[<$chain:lower _to_this_conversion_rate>]: Option<FixedU128>,
|
||||
) -> Option<OutboundMessageFee>;
|
||||
pub trait [<To $chain:camel OutboundLaneApi>] {
|
||||
/// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all
|
||||
/// messages in given inclusive range.
|
||||
///
|
||||
@@ -324,7 +310,7 @@ macro_rules! decl_bridge_messages_runtime_apis {
|
||||
lane: LaneId,
|
||||
begin: MessageNonce,
|
||||
end: MessageNonce,
|
||||
) -> Vec<OutboundMessageDetails<OutboundMessageFee>>;
|
||||
) -> Vec<OutboundMessageDetails>;
|
||||
}
|
||||
|
||||
/// Inbound message lane API for messages sent by this chain.
|
||||
@@ -334,11 +320,11 @@ macro_rules! decl_bridge_messages_runtime_apis {
|
||||
///
|
||||
/// Entries of the resulting vector are matching entries of the `messages` vector. Entries of the
|
||||
/// `messages` vector may (and need to) be read using `To<ThisChain>OutboundLaneApi::message_details`.
|
||||
pub trait [<From $chain:camel InboundLaneApi>]<InboundMessageFee: Parameter> {
|
||||
pub trait [<From $chain:camel InboundLaneApi>] {
|
||||
/// Return details of given inbound messages.
|
||||
fn message_details(
|
||||
lane: LaneId,
|
||||
messages: Vec<(MessagePayload, OutboundMessageDetails<InboundMessageFee>)>,
|
||||
messages: Vec<(MessagePayload, OutboundMessageDetails)>,
|
||||
) -> Vec<InboundMessageDetails>;
|
||||
}
|
||||
}
|
||||
@@ -346,7 +332,7 @@ macro_rules! decl_bridge_messages_runtime_apis {
|
||||
|
||||
pub use [<$chain _messages_api>]::*;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Convenience macro that declares bridge finality runtime apis, bridge messages runtime apis
|
||||
|
||||
@@ -20,20 +20,6 @@ use codec::{Decode, Encode};
|
||||
use frame_support::{weights::Weight, RuntimeDebug};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// Where message dispatch fee is paid?
|
||||
#[derive(Encode, Decode, RuntimeDebug, Clone, Copy, PartialEq, Eq, TypeInfo)]
|
||||
pub enum DispatchFeePayment {
|
||||
/// The dispatch fee is paid at the source chain.
|
||||
AtSourceChain,
|
||||
/// The dispatch fee is paid at the target chain.
|
||||
///
|
||||
/// The fee will be paid right before the message is dispatched. So in case of any other
|
||||
/// issues (like invalid call encoding, invalid signature, ...) the dispatch module won't
|
||||
/// do any direct transfers. Instead, it'll return fee related to this message dispatch to the
|
||||
/// relayer.
|
||||
AtTargetChain,
|
||||
}
|
||||
|
||||
/// Message dispatch result.
|
||||
#[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)]
|
||||
pub struct MessageDispatchResult {
|
||||
|
||||
@@ -30,7 +30,6 @@ bp-rialto = { path = "../../primitives/chain-rialto" }
|
||||
bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" }
|
||||
bp-rococo = { path = "../../primitives/chain-rococo" }
|
||||
bp-runtime = { path = "../../primitives/runtime" }
|
||||
bp-statemine = { path = "../../primitives/chain-statemine" }
|
||||
bp-westend = { path = "../../primitives/chain-westend" }
|
||||
bp-wococo = { path = "../../primitives/chain-wococo" }
|
||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||
@@ -45,7 +44,6 @@ relay-rialto-parachain-client = { path = "../client-rialto-parachain" }
|
||||
relay-bridge-hub-rococo-client = { path = "../client-bridge-hub-rococo" }
|
||||
relay-bridge-hub-wococo-client = { path = "../client-bridge-hub-wococo" }
|
||||
relay-rococo-client = { path = "../client-rococo" }
|
||||
relay-statemine-client = { path = "../client-statemine" }
|
||||
relay-substrate-client = { path = "../client-substrate" }
|
||||
relay-utils = { path = "../utils" }
|
||||
relay-westend-client = { path = "../client-westend" }
|
||||
|
||||
-14
@@ -18,7 +18,6 @@
|
||||
|
||||
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
|
||||
use bp_messages::Weight;
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_bridge_hub_rococo_client::BridgeHubRococo;
|
||||
use relay_bridge_hub_wococo_client::BridgeHubWococo;
|
||||
use substrate_relay_helper::messages_lane::SubstrateMessageLane;
|
||||
@@ -55,15 +54,6 @@ substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_buil
|
||||
pub struct BridgeHubRococoMessagesToBridgeHubWococoMessageLane;
|
||||
|
||||
impl SubstrateMessageLane for BridgeHubRococoMessagesToBridgeHubWococoMessageLane {
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
|
||||
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
|
||||
type SourceChain = BridgeHubRococo;
|
||||
type TargetChain = BridgeHubWococo;
|
||||
|
||||
@@ -71,8 +61,4 @@ impl SubstrateMessageLane for BridgeHubRococoMessagesToBridgeHubWococoMessageLan
|
||||
BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesProofCallBuilder;
|
||||
type ReceiveMessagesDeliveryProofCallBuilder =
|
||||
BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesDeliveryProofCallBuilder;
|
||||
|
||||
type TargetToSourceChainConversionRateUpdateBuilder = ();
|
||||
|
||||
type RelayStrategy = MixStrategy;
|
||||
}
|
||||
|
||||
-14
@@ -18,7 +18,6 @@
|
||||
|
||||
use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
|
||||
use bp_messages::Weight;
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_bridge_hub_rococo_client::BridgeHubRococo;
|
||||
use relay_bridge_hub_wococo_client::BridgeHubWococo;
|
||||
use substrate_relay_helper::messages_lane::SubstrateMessageLane;
|
||||
@@ -55,15 +54,6 @@ substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_buil
|
||||
pub struct BridgeHubWococoMessagesToBridgeHubRococoMessageLane;
|
||||
|
||||
impl SubstrateMessageLane for BridgeHubWococoMessagesToBridgeHubRococoMessageLane {
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
|
||||
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
|
||||
type SourceChain = BridgeHubWococo;
|
||||
type TargetChain = BridgeHubRococo;
|
||||
|
||||
@@ -71,8 +61,4 @@ impl SubstrateMessageLane for BridgeHubWococoMessagesToBridgeHubRococoMessageLan
|
||||
BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesProofCallBuilder;
|
||||
type ReceiveMessagesDeliveryProofCallBuilder =
|
||||
BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesDeliveryProofCallBuilder;
|
||||
|
||||
type TargetToSourceChainConversionRateUpdateBuilder = ();
|
||||
|
||||
type RelayStrategy = MixStrategy;
|
||||
}
|
||||
|
||||
@@ -16,16 +16,10 @@
|
||||
|
||||
//! Millau chain specification for CLI.
|
||||
|
||||
use crate::cli::{
|
||||
bridge,
|
||||
encode_message::{CliEncodeMessage, RawMessage},
|
||||
CliChain,
|
||||
};
|
||||
use bp_messages::LaneId;
|
||||
use crate::cli::{bridge, encode_message::CliEncodeMessage, CliChain};
|
||||
use bp_rialto_parachain::RIALTO_PARACHAIN_ID;
|
||||
use bp_runtime::EncodedOrDecodedCall;
|
||||
use relay_millau_client::Millau;
|
||||
use relay_substrate_client::BalanceOf;
|
||||
use sp_version::RuntimeVersion;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
@@ -56,37 +50,6 @@ impl CliEncodeMessage for Millau {
|
||||
})
|
||||
.into())
|
||||
}
|
||||
|
||||
fn encode_send_message_call(
|
||||
lane: LaneId,
|
||||
payload: RawMessage,
|
||||
fee: BalanceOf<Self>,
|
||||
bridge_instance_index: u8,
|
||||
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
|
||||
Ok(match bridge_instance_index {
|
||||
bridge::MILLAU_TO_RIALTO_INDEX => millau_runtime::RuntimeCall::BridgeRialtoMessages(
|
||||
millau_runtime::MessagesCall::send_message {
|
||||
lane_id: lane,
|
||||
payload,
|
||||
delivery_and_dispatch_fee: fee,
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
bridge::MILLAU_TO_RIALTO_PARACHAIN_INDEX =>
|
||||
millau_runtime::RuntimeCall::BridgeRialtoParachainMessages(
|
||||
millau_runtime::MessagesCall::send_message {
|
||||
lane_id: lane,
|
||||
payload,
|
||||
delivery_and_dispatch_fee: fee,
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CliChain for Millau {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
//! Millau-to-Rialto messages sync entrypoint.
|
||||
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_millau_client::Millau;
|
||||
use relay_rialto_client::Rialto;
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
@@ -27,25 +26,8 @@ use substrate_relay_helper::messages_lane::{
|
||||
/// Description of Millau -> Rialto messages bridge.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MillauMessagesToRialto;
|
||||
substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
|
||||
Millau,
|
||||
MillauMessagesToRialtoUpdateConversionRateCallBuilder,
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WithRialtoMessagesInstance,
|
||||
millau_runtime::rialto_messages::MillauToRialtoMessagesParameter::RialtoToMillauConversionRate
|
||||
);
|
||||
|
||||
impl SubstrateMessageLane for MillauMessagesToRialto {
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME);
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
|
||||
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
|
||||
type SourceChain = Millau;
|
||||
type TargetChain = Rialto;
|
||||
|
||||
@@ -59,9 +41,4 @@ impl SubstrateMessageLane for MillauMessagesToRialto {
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WithRialtoMessagesInstance,
|
||||
>;
|
||||
|
||||
type TargetToSourceChainConversionRateUpdateBuilder =
|
||||
MillauMessagesToRialtoUpdateConversionRateCallBuilder;
|
||||
|
||||
type RelayStrategy = MixStrategy;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
//! Millau-to-RialtoParachain messages sync entrypoint.
|
||||
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_millau_client::Millau;
|
||||
use relay_rialto_parachain_client::RialtoParachain;
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
@@ -27,30 +26,8 @@ use substrate_relay_helper::messages_lane::{
|
||||
/// Description of Millau -> RialtoParachain messages bridge.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MillauMessagesToRialtoParachain;
|
||||
substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
|
||||
Millau,
|
||||
MillauMessagesToRialtoParachainUpdateConversionRateCallBuilder,
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WithRialtoParachainMessagesInstance,
|
||||
millau_runtime::rialto_parachain_messages::MillauToRialtoParachainMessagesParameter::RialtoParachainToMillauConversionRate
|
||||
);
|
||||
|
||||
impl SubstrateMessageLane for MillauMessagesToRialtoParachain {
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_rialto_parachain::MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME);
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_millau::RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
|
||||
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_rialto_parachain::MILLAU_FEE_MULTIPLIER_PARAMETER_NAME);
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_millau::RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME);
|
||||
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
|
||||
Some(bp_millau::TRANSACTION_PAYMENT_PALLET_NAME);
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
|
||||
Some(bp_rialto_parachain::TRANSACTION_PAYMENT_PALLET_NAME);
|
||||
|
||||
type SourceChain = Millau;
|
||||
type TargetChain = RialtoParachain;
|
||||
|
||||
@@ -64,9 +41,4 @@ impl SubstrateMessageLane for MillauMessagesToRialtoParachain {
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WithRialtoParachainMessagesInstance,
|
||||
>;
|
||||
|
||||
type TargetToSourceChainConversionRateUpdateBuilder =
|
||||
MillauMessagesToRialtoParachainUpdateConversionRateCallBuilder;
|
||||
|
||||
type RelayStrategy = MixStrategy;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ mod millau;
|
||||
mod rialto;
|
||||
mod rialto_parachain;
|
||||
mod rococo;
|
||||
mod statemine;
|
||||
mod westend;
|
||||
mod wococo;
|
||||
|
||||
|
||||
@@ -16,15 +16,9 @@
|
||||
|
||||
//! Rialto chain specification for CLI.
|
||||
|
||||
use crate::cli::{
|
||||
bridge,
|
||||
encode_message::{CliEncodeMessage, RawMessage},
|
||||
CliChain,
|
||||
};
|
||||
use bp_messages::LaneId;
|
||||
use crate::cli::{bridge, encode_message::CliEncodeMessage, CliChain};
|
||||
use bp_runtime::EncodedOrDecodedCall;
|
||||
use relay_rialto_client::Rialto;
|
||||
use relay_substrate_client::BalanceOf;
|
||||
use sp_version::RuntimeVersion;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
@@ -48,28 +42,6 @@ impl CliEncodeMessage for Rialto {
|
||||
})
|
||||
.into())
|
||||
}
|
||||
|
||||
fn encode_send_message_call(
|
||||
lane: LaneId,
|
||||
payload: RawMessage,
|
||||
fee: BalanceOf<Self>,
|
||||
bridge_instance_index: u8,
|
||||
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
|
||||
Ok(match bridge_instance_index {
|
||||
bridge::RIALTO_TO_MILLAU_INDEX => rialto_runtime::RuntimeCall::BridgeMillauMessages(
|
||||
rialto_runtime::MessagesCall::send_message {
|
||||
lane_id: lane,
|
||||
payload,
|
||||
delivery_and_dispatch_fee: fee,
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CliChain for Rialto {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
//! Rialto-to-Millau messages sync entrypoint.
|
||||
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_millau_client::Millau;
|
||||
use relay_rialto_client::Rialto;
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
@@ -27,25 +26,8 @@ use substrate_relay_helper::messages_lane::{
|
||||
/// Description of Rialto -> Millau messages bridge.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RialtoMessagesToMillau;
|
||||
substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
|
||||
Rialto,
|
||||
RialtoMessagesToMillauUpdateConversionRateCallBuilder,
|
||||
rialto_runtime::Runtime,
|
||||
rialto_runtime::WithMillauMessagesInstance,
|
||||
rialto_runtime::millau_messages::RialtoToMillauMessagesParameter::MillauToRialtoConversionRate
|
||||
);
|
||||
|
||||
impl SubstrateMessageLane for RialtoMessagesToMillau {
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME);
|
||||
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
|
||||
|
||||
type SourceChain = Rialto;
|
||||
type TargetChain = Millau;
|
||||
|
||||
@@ -59,9 +41,4 @@ impl SubstrateMessageLane for RialtoMessagesToMillau {
|
||||
rialto_runtime::Runtime,
|
||||
rialto_runtime::WithMillauMessagesInstance,
|
||||
>;
|
||||
|
||||
type TargetToSourceChainConversionRateUpdateBuilder =
|
||||
RialtoMessagesToMillauUpdateConversionRateCallBuilder;
|
||||
|
||||
type RelayStrategy = MixStrategy;
|
||||
}
|
||||
|
||||
@@ -16,15 +16,9 @@
|
||||
|
||||
//! Rialto parachain specification for CLI.
|
||||
|
||||
use crate::cli::{
|
||||
bridge,
|
||||
encode_message::{CliEncodeMessage, RawMessage},
|
||||
CliChain,
|
||||
};
|
||||
use bp_messages::LaneId;
|
||||
use crate::cli::{bridge, encode_message::CliEncodeMessage, CliChain};
|
||||
use bp_runtime::EncodedOrDecodedCall;
|
||||
use relay_rialto_parachain_client::RialtoParachain;
|
||||
use relay_substrate_client::BalanceOf;
|
||||
use sp_version::RuntimeVersion;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
@@ -50,29 +44,6 @@ impl CliEncodeMessage for RialtoParachain {
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
||||
fn encode_send_message_call(
|
||||
lane: LaneId,
|
||||
payload: RawMessage,
|
||||
fee: BalanceOf<Self>,
|
||||
bridge_instance_index: u8,
|
||||
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
|
||||
Ok(match bridge_instance_index {
|
||||
bridge::RIALTO_PARACHAIN_TO_MILLAU_INDEX =>
|
||||
rialto_parachain_runtime::RuntimeCall::BridgeMillauMessages(
|
||||
rialto_parachain_runtime::MessagesCall::send_message {
|
||||
lane_id: lane,
|
||||
payload,
|
||||
delivery_and_dispatch_fee: fee,
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CliChain for RialtoParachain {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
//! RialtoParachain-to-Millau messages sync entrypoint.
|
||||
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_millau_client::Millau;
|
||||
use relay_rialto_parachain_client::RialtoParachain;
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
@@ -27,30 +26,8 @@ use substrate_relay_helper::messages_lane::{
|
||||
/// Description of RialtoParachain -> Millau messages bridge.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RialtoParachainMessagesToMillau;
|
||||
substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
|
||||
RialtoParachain,
|
||||
RialtoParachainMessagesToMillauUpdateConversionRateCallBuilder,
|
||||
rialto_parachain_runtime::Runtime,
|
||||
rialto_parachain_runtime::WithMillauMessagesInstance,
|
||||
rialto_parachain_runtime::millau_messages::RialtoParachainToMillauMessagesParameter::MillauToRialtoParachainConversionRate
|
||||
);
|
||||
|
||||
impl SubstrateMessageLane for RialtoParachainMessagesToMillau {
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_millau::RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_rialto_parachain::MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME);
|
||||
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_millau::RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME);
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
|
||||
Some(bp_rialto_parachain::MILLAU_FEE_MULTIPLIER_PARAMETER_NAME);
|
||||
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
|
||||
Some(bp_rialto_parachain::TRANSACTION_PAYMENT_PALLET_NAME);
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
|
||||
Some(bp_millau::TRANSACTION_PAYMENT_PALLET_NAME);
|
||||
|
||||
type SourceChain = RialtoParachain;
|
||||
type TargetChain = Millau;
|
||||
|
||||
@@ -64,9 +41,4 @@ impl SubstrateMessageLane for RialtoParachainMessagesToMillau {
|
||||
rialto_parachain_runtime::Runtime,
|
||||
rialto_parachain_runtime::WithMillauMessagesInstance,
|
||||
>;
|
||||
|
||||
type TargetToSourceChainConversionRateUpdateBuilder =
|
||||
RialtoParachainMessagesToMillauUpdateConversionRateCallBuilder;
|
||||
|
||||
type RelayStrategy = MixStrategy;
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Statemine chain specification for CLI.
|
||||
|
||||
use crate::cli::CliChain;
|
||||
use relay_statemine_client::Statemine;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
impl CliChain for Statemine {
|
||||
const RUNTIME_VERSION: Option<RuntimeVersion> = Some(bp_statemine::VERSION);
|
||||
|
||||
type KeyPair = sp_core::sr25519::Pair;
|
||||
|
||||
fn ss58_format() -> u16 {
|
||||
sp_core::crypto::Ss58AddressFormat::from(
|
||||
sp_core::crypto::Ss58AddressFormatRegistry::KusamaAccount,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::cli::CliChain;
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
|
||||
use parachains_relay::ParachainsPipeline;
|
||||
use relay_substrate_client::{AccountKeyPairOf, Chain, ChainWithTransactions, RelayChain};
|
||||
@@ -46,7 +45,7 @@ impl FullBridge {
|
||||
Self::MillauToRialtoParachain => MILLAU_TO_RIALTO_PARACHAIN_INDEX,
|
||||
Self::RialtoParachainToMillau => RIALTO_PARACHAIN_TO_MILLAU_INDEX,
|
||||
Self::BridgeHubRococoToBridgeHubWococo | Self::BridgeHubWococoToBridgeHubRococo =>
|
||||
unimplemented!("TODO: (bridge_instance_index) do we need it or refactor or remove?"),
|
||||
unimplemented!("Relay doesn't support send-message subcommand on bridge hubs"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,9 +101,5 @@ pub trait MessagesCliBridge: CliBridgeBase {
|
||||
/// defined bridge.
|
||||
const ESTIMATE_MESSAGE_FEE_METHOD: &'static str;
|
||||
/// The Source -> Destination messages synchronization pipeline.
|
||||
type MessagesLane: SubstrateMessageLane<
|
||||
SourceChain = Self::Source,
|
||||
TargetChain = Self::Target,
|
||||
RelayStrategy = MixStrategy,
|
||||
>;
|
||||
type MessagesLane: SubstrateMessageLane<SourceChain = Self::Source, TargetChain = Self::Target>;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::cli::{ExplicitOrMaximal, HexBytes};
|
||||
use bp_messages::LaneId;
|
||||
use bp_runtime::EncodedOrDecodedCall;
|
||||
use codec::Encode;
|
||||
use relay_substrate_client::Chain;
|
||||
use structopt::StructOpt;
|
||||
|
||||
@@ -47,14 +47,6 @@ pub trait CliEncodeMessage: Chain {
|
||||
message: xcm::VersionedXcm<()>,
|
||||
bridge_instance_index: u8,
|
||||
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
|
||||
|
||||
/// Encode a send message call of the bridge-messages pallet.
|
||||
fn encode_send_message_call(
|
||||
lane: LaneId,
|
||||
message: RawMessage,
|
||||
fee: Self::Balance,
|
||||
bridge_instance_index: u8,
|
||||
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
|
||||
}
|
||||
|
||||
/// Encode message payload passed through CLI flags.
|
||||
@@ -63,15 +55,36 @@ pub(crate) fn encode_message<Source: Chain, Target: Chain>(
|
||||
) -> anyhow::Result<RawMessage> {
|
||||
Ok(match message {
|
||||
Message::Raw { ref data } => data.0.clone(),
|
||||
Message::Sized { ref size } => match *size {
|
||||
ExplicitOrMaximal::Explicit(size) => vec![42; size as usize],
|
||||
ExplicitOrMaximal::Maximal => {
|
||||
let maximal_size = compute_maximal_message_size(
|
||||
Message::Sized { ref size } => {
|
||||
let expected_xcm_size = match *size {
|
||||
ExplicitOrMaximal::Explicit(size) => size,
|
||||
ExplicitOrMaximal::Maximal => compute_maximal_message_size(
|
||||
Source::max_extrinsic_size(),
|
||||
Target::max_extrinsic_size(),
|
||||
),
|
||||
};
|
||||
|
||||
// there's no way to craft XCM of the given size - we'll be using `ExpectPallet`
|
||||
// instruction, which has byte vector inside
|
||||
let mut current_vec_size = expected_xcm_size;
|
||||
let xcm = loop {
|
||||
let xcm = xcm::VersionedXcm::<()>::V3(
|
||||
vec![xcm::v3::Instruction::ExpectPallet {
|
||||
index: 0,
|
||||
name: vec![42; current_vec_size as usize],
|
||||
module_name: vec![],
|
||||
crate_major: 0,
|
||||
min_crate_minor: 0,
|
||||
}]
|
||||
.into(),
|
||||
);
|
||||
vec![42; maximal_size as usize]
|
||||
},
|
||||
if xcm.encode().len() <= expected_xcm_size as usize {
|
||||
break xcm
|
||||
}
|
||||
|
||||
current_vec_size -= 1;
|
||||
};
|
||||
xcm.encode()
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -95,3 +108,38 @@ pub(crate) fn compute_maximal_message_size(
|
||||
maximal_message_size
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::send_message::decode_xcm;
|
||||
use bp_runtime::Chain;
|
||||
use relay_millau_client::Millau;
|
||||
use relay_rialto_client::Rialto;
|
||||
|
||||
#[test]
|
||||
fn encode_explicit_size_message_works() {
|
||||
let msg = encode_message::<Rialto, Millau>(&Message::Sized {
|
||||
size: ExplicitOrMaximal::Explicit(100),
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(msg.len(), 100);
|
||||
// check that it decodes to valid xcm
|
||||
let _ = decode_xcm(msg).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_maximal_size_message_works() {
|
||||
let maximal_size = compute_maximal_message_size(
|
||||
Rialto::max_extrinsic_size(),
|
||||
Millau::max_extrinsic_size(),
|
||||
);
|
||||
|
||||
let msg =
|
||||
encode_message::<Rialto, Millau>(&Message::Sized { size: ExplicitOrMaximal::Maximal })
|
||||
.unwrap();
|
||||
assert_eq!(msg.len(), maximal_size as usize);
|
||||
// check that it decodes to valid xcm
|
||||
let _ = decode_xcm(msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::{
|
||||
chains::{
|
||||
millau_headers_to_rialto::MillauToRialtoCliBridge,
|
||||
millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge,
|
||||
rialto_headers_to_millau::RialtoToMillauCliBridge,
|
||||
rialto_parachains_to_millau::RialtoParachainToMillauCliBridge,
|
||||
},
|
||||
cli::{
|
||||
bridge::{FullBridge, MessagesCliBridge},
|
||||
chain_schema::*,
|
||||
relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
Balance, HexBytes, HexLaneId,
|
||||
},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use bp_runtime::BalanceOf;
|
||||
use codec::{Decode, Encode};
|
||||
use relay_substrate_client::{Chain, ChainBase};
|
||||
use sp_runtime::FixedU128;
|
||||
use std::fmt::Display;
|
||||
use structopt::StructOpt;
|
||||
use strum::VariantNames;
|
||||
use substrate_relay_helper::helpers::tokens_conversion_rate_from_metrics;
|
||||
|
||||
/// Estimate Delivery & Dispatch Fee command.
|
||||
#[derive(StructOpt, Debug, PartialEq)]
|
||||
pub struct EstimateFee {
|
||||
/// A bridge instance to encode call for.
|
||||
#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
|
||||
bridge: FullBridge,
|
||||
#[structopt(flatten)]
|
||||
source: SourceConnectionParams,
|
||||
/// Hex-encoded id of lane that will be delivering the message.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
lane: HexLaneId,
|
||||
/// A way to override conversion rate between bridge tokens.
|
||||
///
|
||||
/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
|
||||
/// your message won't be relayed.
|
||||
#[structopt(long)]
|
||||
conversion_rate_override: Option<ConversionRateOverride>,
|
||||
/// Payload to send over the bridge.
|
||||
#[structopt(flatten)]
|
||||
payload: crate::cli::encode_message::Message,
|
||||
}
|
||||
|
||||
/// A way to override conversion rate between bridge tokens.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ConversionRateOverride {
|
||||
/// The actual conversion rate is computed in the same way how rate metric works.
|
||||
Metric,
|
||||
/// The actual conversion rate is specified explicitly.
|
||||
Explicit(f64),
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ConversionRateOverride {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.to_lowercase() == "metric" {
|
||||
return Ok(ConversionRateOverride::Metric)
|
||||
}
|
||||
|
||||
f64::from_str(s)
|
||||
.map(ConversionRateOverride::Explicit)
|
||||
.map_err(|e| format!("Failed to parse '{e:?}'. Expected 'metric' or explicit value"))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
trait FeeEstimator: MessagesCliBridge
|
||||
where
|
||||
<Self::Source as ChainBase>::Balance: Display + Into<u128>,
|
||||
{
|
||||
async fn estimate_fee(data: EstimateFee) -> anyhow::Result<()> {
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let lane = data.lane.into();
|
||||
let payload =
|
||||
crate::cli::encode_message::encode_message::<Self::Source, Self::Target>(&data.payload)
|
||||
.map_err(|e| anyhow::format_err!("{:?}", e))?;
|
||||
|
||||
let fee = estimate_message_delivery_and_dispatch_fee::<Self::Source, Self::Target, _>(
|
||||
&source_client,
|
||||
data.conversion_rate_override,
|
||||
Self::ESTIMATE_MESSAGE_FEE_METHOD,
|
||||
lane,
|
||||
&payload,
|
||||
)
|
||||
.await?;
|
||||
|
||||
log::info!(target: "bridge", "Fee: {:?}", Balance(fee.into()));
|
||||
println!("{fee}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FeeEstimator for MillauToRialtoCliBridge {}
|
||||
impl FeeEstimator for RialtoToMillauCliBridge {}
|
||||
impl FeeEstimator for MillauToRialtoParachainCliBridge {}
|
||||
impl FeeEstimator for RialtoParachainToMillauCliBridge {}
|
||||
|
||||
impl EstimateFee {
|
||||
/// Run the command.
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
match self.bridge {
|
||||
FullBridge::MillauToRialto => MillauToRialtoCliBridge::estimate_fee(self),
|
||||
FullBridge::RialtoToMillau => RialtoToMillauCliBridge::estimate_fee(self),
|
||||
FullBridge::MillauToRialtoParachain =>
|
||||
MillauToRialtoParachainCliBridge::estimate_fee(self),
|
||||
FullBridge::RialtoParachainToMillau =>
|
||||
RialtoParachainToMillauCliBridge::estimate_fee(self),
|
||||
FullBridge::BridgeHubRococoToBridgeHubWococo |
|
||||
FullBridge::BridgeHubWococoToBridgeHubRococo =>
|
||||
unimplemented!("TODO: (EstimateFee) do we need it or refactor or remove?"),
|
||||
}
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// The caller may provide target to source tokens conversion rate override to use in fee
|
||||
/// computation.
|
||||
pub(crate) async fn estimate_message_delivery_and_dispatch_fee<
|
||||
Source: Chain,
|
||||
Target: Chain,
|
||||
P: Clone + Encode,
|
||||
>(
|
||||
client: &relay_substrate_client::Client<Source>,
|
||||
conversion_rate_override: Option<ConversionRateOverride>,
|
||||
estimate_fee_method: &str,
|
||||
lane: bp_messages::LaneId,
|
||||
payload: &P,
|
||||
) -> anyhow::Result<BalanceOf<Source>> {
|
||||
// actual conversion rate CAN be lesser than the rate stored in the runtime. So we may try to
|
||||
// pay lesser fee for the message delivery. But in this case, message may be rejected by the
|
||||
// lane. So we MUST use the larger of two fees - one computed with stored fee and the one
|
||||
// computed with actual fee.
|
||||
|
||||
let conversion_rate_override =
|
||||
match (conversion_rate_override, Source::TOKEN_ID, Target::TOKEN_ID) {
|
||||
(Some(ConversionRateOverride::Explicit(v)), _, _) => {
|
||||
let conversion_rate_override = FixedU128::from_float(v);
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"{} -> {} conversion rate override: {:?} (explicit)",
|
||||
Target::NAME,
|
||||
Source::NAME,
|
||||
conversion_rate_override.to_float(),
|
||||
);
|
||||
Some(conversion_rate_override)
|
||||
},
|
||||
(
|
||||
Some(ConversionRateOverride::Metric),
|
||||
Some(source_token_id),
|
||||
Some(target_token_id),
|
||||
) => {
|
||||
let conversion_rate_override =
|
||||
tokens_conversion_rate_from_metrics(target_token_id, source_token_id).await?;
|
||||
// So we have current actual conversion rate and rate that is stored in the runtime.
|
||||
// And we may simply choose the maximal of these. But what if right now there's
|
||||
// rate update transaction on the way, that is updating rate to 10 seconds old
|
||||
// actual rate, which is bigger than the current rate? Then our message will be
|
||||
// rejected.
|
||||
//
|
||||
// So let's increase the actual rate by the same value that the conversion rate
|
||||
// updater is using.
|
||||
let increased_conversion_rate_override = FixedU128::from_float(
|
||||
conversion_rate_override * (1.0 + CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO),
|
||||
);
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"{} -> {} conversion rate override: {} (value from metric - {})",
|
||||
Target::NAME,
|
||||
Source::NAME,
|
||||
increased_conversion_rate_override.to_float(),
|
||||
conversion_rate_override,
|
||||
);
|
||||
Some(increased_conversion_rate_override)
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let without_override = do_estimate_message_delivery_and_dispatch_fee(
|
||||
client,
|
||||
estimate_fee_method,
|
||||
lane,
|
||||
payload,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let with_override = do_estimate_message_delivery_and_dispatch_fee(
|
||||
client,
|
||||
estimate_fee_method,
|
||||
lane,
|
||||
payload,
|
||||
conversion_rate_override,
|
||||
)
|
||||
.await?;
|
||||
let maximal_fee = std::cmp::max(without_override, with_override);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Estimated message fee: {:?} = max of {:?} (without rate override) and {:?} (with override to {:?})",
|
||||
maximal_fee,
|
||||
without_override,
|
||||
with_override,
|
||||
conversion_rate_override,
|
||||
);
|
||||
|
||||
Ok(maximal_fee)
|
||||
}
|
||||
|
||||
/// Estimate message delivery and dispatch fee with given conversion rate override.
|
||||
async fn do_estimate_message_delivery_and_dispatch_fee<Source: Chain, P: Encode>(
|
||||
client: &relay_substrate_client::Client<Source>,
|
||||
estimate_fee_method: &str,
|
||||
lane: bp_messages::LaneId,
|
||||
payload: &P,
|
||||
conversion_rate_override: Option<FixedU128>,
|
||||
) -> anyhow::Result<BalanceOf<Source>> {
|
||||
let encoded_response = client
|
||||
.state_call(
|
||||
estimate_fee_method.into(),
|
||||
(lane, payload, conversion_rate_override).encode().into(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let decoded_response: Option<BalanceOf<Source>> = Decode::decode(&mut &encoded_response.0[..])
|
||||
.map_err(relay_substrate_client::Error::ResponseParseFailed)?;
|
||||
let fee = decoded_response.ok_or_else(|| {
|
||||
anyhow::format_err!("Unable to decode fee from: {:?}", HexBytes(encoded_response.to_vec()))
|
||||
})?;
|
||||
Ok(fee)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_parse_cli_options() {
|
||||
// when
|
||||
let res = EstimateFee::from_iter(vec![
|
||||
"estimate_fee",
|
||||
"rialto-to-millau",
|
||||
"--source-port",
|
||||
"1234",
|
||||
"--conversion-rate-override",
|
||||
"42.5",
|
||||
"raw",
|
||||
"1234",
|
||||
]);
|
||||
|
||||
// then
|
||||
assert_eq!(
|
||||
res,
|
||||
EstimateFee {
|
||||
bridge: FullBridge::RialtoToMillau,
|
||||
lane: HexLaneId([0, 0, 0, 0]),
|
||||
conversion_rate_override: Some(ConversionRateOverride::Explicit(42.5)),
|
||||
source: SourceConnectionParams {
|
||||
source_host: "127.0.0.1".into(),
|
||||
source_port: 1234,
|
||||
source_secure: false,
|
||||
source_runtime_version: SourceRuntimeVersionParams {
|
||||
source_version_mode: RuntimeVersionType::Bundle,
|
||||
source_spec_version: None,
|
||||
source_transaction_version: None,
|
||||
}
|
||||
},
|
||||
payload: crate::cli::encode_message::Message::Raw {
|
||||
data: HexBytes(vec![0x12, 0x34])
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ use bp_messages::LaneId;
|
||||
|
||||
pub(crate) mod bridge;
|
||||
pub(crate) mod encode_message;
|
||||
pub(crate) mod estimate_fee;
|
||||
pub(crate) mod send_message;
|
||||
|
||||
mod chain_schema;
|
||||
@@ -74,8 +73,6 @@ pub enum Command {
|
||||
/// The message is being sent to the source chain, delivered to the target chain and dispatched
|
||||
/// there.
|
||||
SendMessage(send_message::SendMessage),
|
||||
/// Estimate Delivery and Dispatch Fee required for message submission to messages pallet.
|
||||
EstimateFee(estimate_fee::EstimateFee),
|
||||
/// Resubmit transactions with increased tip if they are stalled.
|
||||
ResubmitTransactions(resubmit_transactions::ResubmitTransactions),
|
||||
/// Register parachain.
|
||||
@@ -111,7 +108,6 @@ impl Command {
|
||||
Self::RelayHeadersAndMessages(arg) => arg.run().await?,
|
||||
Self::InitBridge(arg) => arg.run().await?,
|
||||
Self::SendMessage(arg) => arg.run().await?,
|
||||
Self::EstimateFee(arg) => arg.run().await?,
|
||||
Self::ResubmitTransactions(arg) => arg.run().await?,
|
||||
Self::RegisterParachain(arg) => arg.run().await?,
|
||||
Self::RelayParachains(arg) => arg.run().await?,
|
||||
|
||||
@@ -31,7 +31,6 @@ mod relay_to_parachain;
|
||||
use async_trait::async_trait;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use structopt::StructOpt;
|
||||
use strum::VariantNames;
|
||||
|
||||
use futures::{FutureExt, TryFutureExt};
|
||||
use relay_to_parachain::*;
|
||||
@@ -50,40 +49,27 @@ use crate::{
|
||||
RelayToRelayHeadersCliBridge,
|
||||
},
|
||||
chain_schema::*,
|
||||
relay_messages::RelayerMode,
|
||||
CliChain, HexLaneId, PrometheusParams,
|
||||
},
|
||||
declare_chain_cli_schema,
|
||||
};
|
||||
use bp_messages::LaneId;
|
||||
use bp_runtime::{BalanceOf, BlockNumberOf};
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithTransactions, Client,
|
||||
};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::Pair;
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::MessagesRelayParams, messages_metrics::StandaloneMessagesMetrics,
|
||||
on_demand::OnDemandRelay, TaggedAccount, TransactionParams,
|
||||
messages_lane::MessagesRelayParams, on_demand::OnDemandRelay, TaggedAccount, TransactionParams,
|
||||
};
|
||||
|
||||
/// Maximal allowed conversion rate error ratio (abs(real - stored) / stored) that we allow.
|
||||
///
|
||||
/// If it is zero, then transaction will be submitted every time we see difference between
|
||||
/// stored and real conversion rates. If it is large enough (e.g. > than 10 percents, which is 0.1),
|
||||
/// then rational relayers may stop relaying messages because they were submitted using
|
||||
/// lesser conversion rate.
|
||||
pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05;
|
||||
|
||||
/// Parameters that have the same names across all bridges.
|
||||
#[derive(Debug, PartialEq, StructOpt)]
|
||||
pub struct HeadersAndMessagesSharedParams {
|
||||
/// Hex-encoded lane identifiers that should be served by the complex relay.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
pub lane: Vec<HexLaneId>,
|
||||
#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
|
||||
pub relayer_mode: RelayerMode,
|
||||
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
|
||||
/// are relayed.
|
||||
#[structopt(long)]
|
||||
@@ -101,8 +87,6 @@ pub struct Full2WayBridgeCommonParams<
|
||||
pub right: BridgeEndCommonParams<Right>,
|
||||
|
||||
pub metrics_params: MetricsParams,
|
||||
pub left_to_right_metrics: StandaloneMessagesMetrics<Left, Right>,
|
||||
pub right_to_left_metrics: StandaloneMessagesMetrics<Right, Left>,
|
||||
}
|
||||
|
||||
impl<Left: ChainWithTransactions + CliChain, Right: ChainWithTransactions + CliChain>
|
||||
@@ -116,19 +100,8 @@ impl<Left: ChainWithTransactions + CliChain, Right: ChainWithTransactions + CliC
|
||||
// Create metrics registry.
|
||||
let metrics_params = shared.prometheus_params.clone().into();
|
||||
let metrics_params = relay_utils::relay_metrics(metrics_params).into_params();
|
||||
let left_to_right_metrics = substrate_relay_helper::messages_metrics::standalone_metrics::<
|
||||
L2R::MessagesLane,
|
||||
>(left.client.clone(), right.client.clone())?;
|
||||
let right_to_left_metrics = left_to_right_metrics.clone().reverse();
|
||||
|
||||
Ok(Self {
|
||||
shared,
|
||||
left,
|
||||
right,
|
||||
metrics_params,
|
||||
left_to_right_metrics,
|
||||
right_to_left_metrics,
|
||||
})
|
||||
Ok(Self { shared, left, right, metrics_params })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,11 +119,9 @@ struct FullBridge<
|
||||
Target: ChainWithTransactions + CliChain,
|
||||
Bridge: MessagesCliBridge<Source = Source, Target = Target>,
|
||||
> {
|
||||
shared: &'a HeadersAndMessagesSharedParams,
|
||||
source: &'a mut BridgeEndCommonParams<Source>,
|
||||
target: &'a mut BridgeEndCommonParams<Target>,
|
||||
metrics_params: &'a MetricsParams,
|
||||
metrics: &'a StandaloneMessagesMetrics<Source, Target>,
|
||||
_phantom_data: PhantomData<Bridge>,
|
||||
}
|
||||
|
||||
@@ -166,55 +137,11 @@ where
|
||||
BalanceOf<Source>: TryFrom<BalanceOf<Target>> + Into<u128>,
|
||||
{
|
||||
fn new(
|
||||
shared: &'a HeadersAndMessagesSharedParams,
|
||||
source: &'a mut BridgeEndCommonParams<Source>,
|
||||
target: &'a mut BridgeEndCommonParams<Target>,
|
||||
metrics_params: &'a MetricsParams,
|
||||
metrics: &'a StandaloneMessagesMetrics<Source, Target>,
|
||||
) -> Self {
|
||||
Self { shared, source, target, metrics_params, metrics, _phantom_data: Default::default() }
|
||||
}
|
||||
|
||||
fn start_conversion_rate_update_loop(&mut self) -> anyhow::Result<()> {
|
||||
if let Some(ref messages_pallet_owner) = self.source.messages_pallet_owner {
|
||||
let format_err = || {
|
||||
anyhow::format_err!(
|
||||
"Cannon run conversion rate updater: {} -> {}",
|
||||
Target::NAME,
|
||||
Source::NAME
|
||||
)
|
||||
};
|
||||
substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::<
|
||||
Bridge::MessagesLane,
|
||||
>(
|
||||
self.source.client.clone(),
|
||||
TransactionParams {
|
||||
signer: messages_pallet_owner.clone(),
|
||||
mortality: self.source.transactions_mortality,
|
||||
},
|
||||
self.metrics
|
||||
.target_to_source_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
self.metrics
|
||||
.target_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
self.metrics
|
||||
.source_to_base_conversion_rate
|
||||
.as_ref()
|
||||
.ok_or_else(format_err)?
|
||||
.shared_value_ref(),
|
||||
CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
|
||||
);
|
||||
self.source.accounts.push(TaggedAccount::MessagesPalletOwner {
|
||||
id: messages_pallet_owner.public().into(),
|
||||
bridged_chain: Target::NAME.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
Self { source, target, metrics_params, _phantom_data: Default::default() }
|
||||
}
|
||||
|
||||
fn messages_relay_params(
|
||||
@@ -223,9 +150,6 @@ where
|
||||
target_to_source_headers_relay: Arc<dyn OnDemandRelay<BlockNumberOf<Target>>>,
|
||||
lane_id: LaneId,
|
||||
) -> MessagesRelayParams<Bridge::MessagesLane> {
|
||||
let relayer_mode = self.shared.relayer_mode.into();
|
||||
let relay_strategy = MixStrategy::new(relayer_mode);
|
||||
|
||||
MessagesRelayParams {
|
||||
source_client: self.source.client.clone(),
|
||||
source_transaction_params: TransactionParams {
|
||||
@@ -241,8 +165,6 @@ where
|
||||
target_to_source_headers_relay: Some(target_to_source_headers_relay),
|
||||
lane_id,
|
||||
metrics_params: self.metrics_params.clone().disable(),
|
||||
standalone_metrics: Some(self.metrics.clone()),
|
||||
relay_strategy,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,22 +236,18 @@ where
|
||||
fn left_to_right(&mut self) -> FullBridge<Self::Left, Self::Right, Self::L2R> {
|
||||
let common = self.mut_base().mut_common();
|
||||
FullBridge::<_, _, Self::L2R>::new(
|
||||
&common.shared,
|
||||
&mut common.left,
|
||||
&mut common.right,
|
||||
&common.metrics_params,
|
||||
&common.left_to_right_metrics,
|
||||
)
|
||||
}
|
||||
|
||||
fn right_to_left(&mut self) -> FullBridge<Self::Right, Self::Left, Self::R2L> {
|
||||
let common = self.mut_base().mut_common();
|
||||
FullBridge::<_, _, Self::R2L>::new(
|
||||
&common.shared,
|
||||
&mut common.right,
|
||||
&mut common.left,
|
||||
&common.metrics_params,
|
||||
&common.right_to_left_metrics,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -347,10 +265,6 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
// start conversion rate update loops for left/right chains
|
||||
self.left_to_right().start_conversion_rate_update_loop()?;
|
||||
self.right_to_left().start_conversion_rate_update_loop()?;
|
||||
|
||||
// start on-demand header relays
|
||||
let (left_to_right_on_demand_headers, right_to_left_on_demand_headers) =
|
||||
self.mut_base().start_on_demand_headers_relayers().await?;
|
||||
@@ -528,7 +442,6 @@ mod tests {
|
||||
HexLaneId([0x00, 0x00, 0x00, 0x00]),
|
||||
HexLaneId([0x73, 0x77, 0x61, 0x70])
|
||||
],
|
||||
relayer_mode: RelayerMode::Rational,
|
||||
only_mandatory_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
@@ -641,7 +554,6 @@ mod tests {
|
||||
MillauRialtoParachainHeadersAndMessages {
|
||||
shared: HeadersAndMessagesSharedParams {
|
||||
lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
|
||||
relayer_mode: RelayerMode::Rational,
|
||||
only_mandatory_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use async_trait::async_trait;
|
||||
use sp_core::Pair;
|
||||
use structopt::StructOpt;
|
||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||
use strum::VariantNames;
|
||||
|
||||
use crate::chains::{
|
||||
bridge_hub_rococo_messages_to_bridge_hub_wococo::BridgeHubRococoToBridgeHubWococoMessagesCliBridge,
|
||||
@@ -27,32 +27,11 @@ use crate::chains::{
|
||||
rialto_headers_to_millau::RialtoToMillauCliBridge,
|
||||
rialto_parachains_to_millau::RialtoParachainToMillauCliBridge,
|
||||
};
|
||||
use messages_relay::relay_strategy::MixStrategy;
|
||||
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, BalanceOf, ChainWithTransactions};
|
||||
use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams};
|
||||
|
||||
use crate::cli::{bridge::*, chain_schema::*, CliChain, HexLaneId, PrometheusParams};
|
||||
|
||||
/// Relayer operating mode.
|
||||
#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq)]
|
||||
#[strum(serialize_all = "kebab_case")]
|
||||
pub enum RelayerMode {
|
||||
/// The relayer doesn't care about rewards.
|
||||
Altruistic,
|
||||
/// The relayer will deliver all messages and confirmations as long as he's not losing any
|
||||
/// funds.
|
||||
Rational,
|
||||
}
|
||||
|
||||
impl From<RelayerMode> for messages_relay::message_lane_loop::RelayerMode {
|
||||
fn from(mode: RelayerMode) -> Self {
|
||||
match mode {
|
||||
RelayerMode::Altruistic => Self::Altruistic,
|
||||
RelayerMode::Rational => Self::Rational,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start messages relayer process.
|
||||
#[derive(StructOpt)]
|
||||
pub struct RelayMessages {
|
||||
@@ -62,8 +41,6 @@ pub struct RelayMessages {
|
||||
/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
lane: HexLaneId,
|
||||
#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
|
||||
relayer_mode: RelayerMode,
|
||||
#[structopt(flatten)]
|
||||
source: SourceConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
@@ -91,8 +68,6 @@ where
|
||||
let target_client = data.target.into_client::<Self::Target>().await?;
|
||||
let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
|
||||
let target_transactions_mortality = data.target_sign.transactions_mortality()?;
|
||||
let relayer_mode = data.relayer_mode.into();
|
||||
let relay_strategy = MixStrategy::new(relayer_mode);
|
||||
|
||||
substrate_relay_helper::messages_lane::run::<Self::MessagesLane>(MessagesRelayParams {
|
||||
source_client,
|
||||
@@ -109,8 +84,6 @@ where
|
||||
target_to_source_headers_relay: None,
|
||||
lane_id: data.lane.into(),
|
||||
metrics_params: data.prometheus_params.into(),
|
||||
standalone_metrics: None,
|
||||
relay_strategy,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
@@ -142,43 +115,3 @@ impl RelayMessages {
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_use_rational_relayer_mode_by_default() {
|
||||
assert_eq!(
|
||||
RelayMessages::from_iter(vec![
|
||||
"relay-messages",
|
||||
"rialto-to-millau",
|
||||
"--source-port=0",
|
||||
"--source-signer=//Alice",
|
||||
"--target-port=0",
|
||||
"--target-signer=//Alice",
|
||||
"--lane=00000000",
|
||||
])
|
||||
.relayer_mode,
|
||||
RelayerMode::Rational,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_accept_altruistic_relayer_mode() {
|
||||
assert_eq!(
|
||||
RelayMessages::from_iter(vec![
|
||||
"relay-messages",
|
||||
"rialto-to-millau",
|
||||
"--source-port=0",
|
||||
"--source-signer=//Alice",
|
||||
"--target-port=0",
|
||||
"--target-signer=//Alice",
|
||||
"--lane=00000000",
|
||||
"--relayer-mode=altruistic",
|
||||
])
|
||||
.relayer_mode,
|
||||
RelayerMode::Altruistic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ use crate::{
|
||||
bridge::{FullBridge, MessagesCliBridge},
|
||||
chain_schema::*,
|
||||
encode_message::{self, CliEncodeMessage, RawMessage},
|
||||
estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride},
|
||||
Balance, CliChain, HexLaneId,
|
||||
CliChain,
|
||||
},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
@@ -35,30 +34,11 @@ use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, Chain, ChainBase, ChainWithTransactions, SignParam,
|
||||
UnsignedTransaction,
|
||||
};
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_core::Pair;
|
||||
use sp_runtime::AccountId32;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::fmt::Display;
|
||||
use structopt::StructOpt;
|
||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||
|
||||
/// Relayer operating mode.
|
||||
#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq)]
|
||||
#[strum(serialize_all = "kebab_case")]
|
||||
pub enum DispatchFeePayment {
|
||||
/// The dispatch fee is paid at the source chain.
|
||||
AtSourceChain,
|
||||
/// The dispatch fee is paid at the target chain.
|
||||
AtTargetChain,
|
||||
}
|
||||
|
||||
impl From<DispatchFeePayment> for bp_runtime::messages::DispatchFeePayment {
|
||||
fn from(dispatch_fee_payment: DispatchFeePayment) -> Self {
|
||||
match dispatch_fee_payment {
|
||||
DispatchFeePayment::AtSourceChain => Self::AtSourceChain,
|
||||
DispatchFeePayment::AtTargetChain => Self::AtTargetChain,
|
||||
}
|
||||
}
|
||||
}
|
||||
use strum::VariantNames;
|
||||
|
||||
/// Send bridge message.
|
||||
#[derive(StructOpt)]
|
||||
@@ -70,23 +50,6 @@ pub struct SendMessage {
|
||||
source: SourceConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
source_sign: SourceSigningParams,
|
||||
/// Send message using XCM pallet instead. By default message is sent using
|
||||
/// bridge messages pallet.
|
||||
#[structopt(long)]
|
||||
use_xcm_pallet: bool,
|
||||
/// Hex-encoded lane id. Defaults to `00000000`.
|
||||
#[structopt(long, default_value = "00000000")]
|
||||
lane: HexLaneId,
|
||||
/// A way to override conversion rate between bridge tokens.
|
||||
///
|
||||
/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
|
||||
/// your message won't be relayed.
|
||||
#[structopt(long)]
|
||||
conversion_rate_override: Option<ConversionRateOverride>,
|
||||
/// Delivery and dispatch fee in source chain base currency units. If not passed, determined
|
||||
/// automatically.
|
||||
#[structopt(long)]
|
||||
fee: Option<Balance>,
|
||||
/// Message type.
|
||||
#[structopt(subcommand)]
|
||||
message: crate::cli::encode_message::Message,
|
||||
@@ -111,53 +74,14 @@ where
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let source_sign = data.source_sign.to_keypair::<Self::Source>()?;
|
||||
|
||||
let lane = data.lane.clone().into();
|
||||
let conversion_rate_override = data.conversion_rate_override;
|
||||
let fee = match data.fee {
|
||||
Some(fee) => fee,
|
||||
None => Balance(
|
||||
estimate_message_delivery_and_dispatch_fee::<Self::Source, Self::Target, _>(
|
||||
&source_client,
|
||||
conversion_rate_override,
|
||||
Self::ESTIMATE_MESSAGE_FEE_METHOD,
|
||||
lane,
|
||||
&payload,
|
||||
)
|
||||
.await?
|
||||
.into(),
|
||||
),
|
||||
};
|
||||
let payload_len = payload.encoded_size();
|
||||
let send_message_call = if data.use_xcm_pallet {
|
||||
Self::Source::encode_send_xcm(
|
||||
decode_xcm(payload)?,
|
||||
data.bridge.bridge_instance_index(),
|
||||
)?
|
||||
} else {
|
||||
Self::Source::encode_send_message_call(
|
||||
data.lane.0,
|
||||
payload,
|
||||
fee.cast().into(),
|
||||
data.bridge.bridge_instance_index(),
|
||||
)?
|
||||
};
|
||||
let send_message_call = Self::Source::encode_send_xcm(
|
||||
decode_xcm(payload)?,
|
||||
data.bridge.bridge_instance_index(),
|
||||
)?;
|
||||
|
||||
let source_genesis_hash = *source_client.genesis_hash();
|
||||
let (spec_version, transaction_version) = source_client.simple_runtime_version().await?;
|
||||
let estimated_transaction_fee = source_client
|
||||
.estimate_extrinsic_fee(Bytes(
|
||||
Self::Source::sign_transaction(
|
||||
SignParam {
|
||||
spec_version,
|
||||
transaction_version,
|
||||
genesis_hash: source_genesis_hash,
|
||||
signer: source_sign.clone(),
|
||||
},
|
||||
UnsignedTransaction::new(send_message_call.clone(), 0),
|
||||
)?
|
||||
.encode(),
|
||||
))
|
||||
.await?;
|
||||
source_client
|
||||
.submit_signed_extrinsic(
|
||||
source_sign.public().into(),
|
||||
@@ -171,22 +95,10 @@ where
|
||||
let unsigned = UnsignedTransaction::new(send_message_call, transaction_nonce);
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Sending message to {}. Lane: {:?}. Size: {}. Fee: {}",
|
||||
"Sending message to {}. Size: {}",
|
||||
Self::Target::NAME,
|
||||
lane,
|
||||
payload_len,
|
||||
fee,
|
||||
);
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"The source account ({:?}) balance will be reduced by (at most) {} (message fee)
|
||||
+ {} (tx fee ) = {} {} tokens", AccountId32::from(source_sign.public()),
|
||||
fee.0,
|
||||
estimated_transaction_fee.inclusion_fee(),
|
||||
fee.0.saturating_add(estimated_transaction_fee.inclusion_fee().into()),
|
||||
Self::Source::NAME,
|
||||
);
|
||||
|
||||
Ok(unsigned)
|
||||
},
|
||||
)
|
||||
@@ -223,7 +135,7 @@ impl SendMessage {
|
||||
}
|
||||
|
||||
/// Decode SCALE encoded raw XCM message.
|
||||
fn decode_xcm(message: RawMessage) -> anyhow::Result<xcm::VersionedXcm<()>> {
|
||||
pub(crate) fn decode_xcm(message: RawMessage) -> anyhow::Result<xcm::VersionedXcm<()>> {
|
||||
Decode::decode(&mut &message[..])
|
||||
.map_err(|e| anyhow::format_err!("Failed to decode XCM program: {:?}", e))
|
||||
}
|
||||
@@ -243,8 +155,6 @@ mod tests {
|
||||
"1234",
|
||||
"--source-signer",
|
||||
"//Alice",
|
||||
"--conversion-rate-override",
|
||||
"0.75",
|
||||
"raw",
|
||||
"dead",
|
||||
]);
|
||||
@@ -253,10 +163,6 @@ mod tests {
|
||||
assert_eq!(send_message.bridge, FullBridge::RialtoToMillau);
|
||||
assert_eq!(send_message.source.source_port, 1234);
|
||||
assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into()));
|
||||
assert_eq!(
|
||||
send_message.conversion_rate_override,
|
||||
Some(ConversionRateOverride::Explicit(0.75))
|
||||
);
|
||||
assert_eq!(
|
||||
send_message.message,
|
||||
crate::cli::encode_message::Message::Raw { data: HexBytes(vec![0xDE, 0xAD]) }
|
||||
@@ -273,8 +179,6 @@ mod tests {
|
||||
"1234",
|
||||
"--source-signer",
|
||||
"//Alice",
|
||||
"--conversion-rate-override",
|
||||
"metric",
|
||||
"sized",
|
||||
"max",
|
||||
]);
|
||||
@@ -283,7 +187,6 @@ mod tests {
|
||||
assert_eq!(send_message.bridge, FullBridge::RialtoToMillau);
|
||||
assert_eq!(send_message.source.source_port, 1234);
|
||||
assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into()));
|
||||
assert_eq!(send_message.conversion_rate_override, Some(ConversionRateOverride::Metric));
|
||||
assert_eq!(
|
||||
send_message.message,
|
||||
crate::cli::encode_message::Message::Sized { size: ExplicitOrMaximal::Maximal }
|
||||
|
||||
@@ -60,7 +60,6 @@ impl Chain for BridgeHubRococo {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_bridge_hub_rococo::BEST_FINALIZED_BRIDGE_HUB_ROCOCO_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_bridge_hub_rococo::SignedBlock;
|
||||
type Call = runtime::Call;
|
||||
@@ -126,8 +125,6 @@ impl ChainWithMessages for BridgeHubRococo {
|
||||
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_bridge_hub_rococo::FROM_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
|
||||
bp_bridge_hub_rococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
|
||||
bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
|
||||
|
||||
@@ -60,7 +60,6 @@ impl Chain for BridgeHubWococo {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_bridge_hub_wococo::BEST_FINALIZED_BRIDGE_HUB_WOCOCO_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_bridge_hub_wococo::SignedBlock;
|
||||
type Call = runtime::Call;
|
||||
@@ -126,8 +125,6 @@ impl ChainWithMessages for BridgeHubWococo {
|
||||
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_bridge_hub_wococo::FROM_BRIDGE_HUB_WOCOCO_MESSAGE_DETAILS_METHOD;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
|
||||
bp_bridge_hub_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
|
||||
bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
|
||||
|
||||
@@ -54,7 +54,6 @@ impl Chain for Kusama {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_kusama::SignedBlock;
|
||||
type Call = ();
|
||||
|
||||
@@ -65,8 +65,6 @@ impl ChainWithMessages for Millau {
|
||||
bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD;
|
||||
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_millau::FROM_MILLAU_MESSAGE_DETAILS_METHOD;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
|
||||
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
|
||||
bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
|
||||
@@ -82,7 +80,6 @@ impl Chain for Millau {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = millau_runtime::SignedBlock;
|
||||
type Call = millau_runtime::RuntimeCall;
|
||||
|
||||
@@ -54,7 +54,6 @@ impl Chain for Polkadot {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_polkadot::SignedBlock;
|
||||
type Call = ();
|
||||
|
||||
@@ -62,7 +62,6 @@ impl Chain for RialtoParachain {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_rialto_parachain::BEST_FINALIZED_RIALTO_PARACHAIN_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = rialto_parachain_runtime::SignedBlock;
|
||||
type Call = rialto_parachain_runtime::RuntimeCall;
|
||||
@@ -86,8 +85,6 @@ impl ChainWithMessages for RialtoParachain {
|
||||
bp_rialto_parachain::TO_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD;
|
||||
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_rialto_parachain::FROM_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
|
||||
bp_rialto_parachain::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
|
||||
bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
|
||||
@@ -157,7 +154,7 @@ impl ChainWithTransactions for RialtoParachain {
|
||||
}
|
||||
|
||||
fn parse_transaction(_tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self>> {
|
||||
unimplemented!("TODO")
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ impl Chain for Rialto {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = rialto_runtime::SignedBlock;
|
||||
type Call = rialto_runtime::RuntimeCall;
|
||||
@@ -85,8 +84,6 @@ impl ChainWithMessages for Rialto {
|
||||
bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD;
|
||||
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_rialto::FROM_RIALTO_MESSAGE_DETAILS_METHOD;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
|
||||
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
|
||||
bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
|
||||
|
||||
@@ -57,7 +57,6 @@ impl Chain for Rococo {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_rococo::SignedBlock;
|
||||
type Call = ();
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
[package]
|
||||
name = "relay-statemine-client"
|
||||
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" }
|
||||
relay-substrate-client = { path = "../client-substrate" }
|
||||
relay-utils = { path = "../utils" }
|
||||
scale-info = { version = "2.1.1", features = ["derive"] }
|
||||
|
||||
# Bridge dependencies
|
||||
|
||||
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
|
||||
bp-statemine = { path = "../../primitives/chain-statemine" }
|
||||
|
||||
# Substrate Dependencies
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -1,112 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Types used to connect to the Statemine chain.
|
||||
|
||||
use codec::Encode;
|
||||
use frame_support::weights::Weight;
|
||||
use relay_substrate_client::{
|
||||
Chain, ChainBase, ChainWithTransactions, Error as SubstrateError, SignParam,
|
||||
UnsignedTransaction,
|
||||
};
|
||||
use sp_core::Pair;
|
||||
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod runtime;
|
||||
|
||||
/// Statemine chain definition
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Statemine;
|
||||
|
||||
impl ChainBase for Statemine {
|
||||
type BlockNumber = bp_statemine::BlockNumber;
|
||||
type Hash = bp_statemine::Hash;
|
||||
type Hasher = bp_statemine::Hasher;
|
||||
type Header = bp_statemine::Header;
|
||||
|
||||
type AccountId = bp_statemine::AccountId;
|
||||
type Balance = bp_statemine::Balance;
|
||||
type Index = bp_statemine::Nonce;
|
||||
type Signature = bp_statemine::Signature;
|
||||
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
bp_statemine::Statemine::max_extrinsic_size()
|
||||
}
|
||||
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
bp_statemine::Statemine::max_extrinsic_weight()
|
||||
}
|
||||
}
|
||||
|
||||
impl Chain for Statemine {
|
||||
const NAME: &'static str = "Statemine";
|
||||
const TOKEN_ID: Option<&'static str> = Some("kusama");
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "<unused>";
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_statemine::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_statemine::SignedBlock;
|
||||
type Call = runtime::Call;
|
||||
}
|
||||
|
||||
impl ChainWithTransactions for Statemine {
|
||||
type AccountKeyPair = sp_core::sr25519::Pair;
|
||||
type SignedTransaction = runtime::UncheckedExtrinsic;
|
||||
|
||||
fn sign_transaction(
|
||||
param: SignParam<Self>,
|
||||
unsigned: UnsignedTransaction<Self>,
|
||||
) -> Result<Self::SignedTransaction, SubstrateError> {
|
||||
let raw_payload = SignedPayload::new(
|
||||
unsigned.call.clone(),
|
||||
bp_statemine::SignedExtensions::new(
|
||||
param.spec_version,
|
||||
param.transaction_version,
|
||||
unsigned.era,
|
||||
param.genesis_hash,
|
||||
unsigned.nonce,
|
||||
unsigned.tip,
|
||||
),
|
||||
)
|
||||
.expect("SignedExtension never fails.");
|
||||
let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload));
|
||||
let signer: sp_runtime::MultiSigner = param.signer.public().into();
|
||||
let (call, extra, _) = raw_payload.deconstruct();
|
||||
|
||||
Ok(runtime::UncheckedExtrinsic::new_signed(
|
||||
call,
|
||||
signer.into_account().into(),
|
||||
signature.into(),
|
||||
extra,
|
||||
))
|
||||
}
|
||||
|
||||
fn is_signed(tx: &Self::SignedTransaction) -> bool {
|
||||
tx.signature.is_some()
|
||||
}
|
||||
|
||||
fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool {
|
||||
tx.signature
|
||||
.as_ref()
|
||||
.map(|(address, _, _)| *address == bp_statemine::Address::Id(signer.public().into()))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn parse_transaction(_tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self>> {
|
||||
unimplemented!("not used on Statemine")
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Types that are specific to the Statemine runtime.
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::FixedU128;
|
||||
|
||||
/// Unchecked Statemine extrinsic.
|
||||
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
|
||||
|
||||
/// Statemine Runtime `Call` enum.
|
||||
///
|
||||
/// The enum represents a subset of possible `Call`s we can send to Statemine chain.
|
||||
/// Ideally this code would be auto-generated from metadata, because we want to
|
||||
/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
|
||||
///
|
||||
/// All entries here (like pretty much in the entire file) must be kept in sync with Statemine
|
||||
/// `construct_runtime`, so that we maintain SCALE-compatibility.
|
||||
///
|
||||
/// See: [link](https://github.com/paritytech/cumulus/blob/master/parachains/runtimes/assets/statemine/src/lib.rs)
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
|
||||
pub enum Call {
|
||||
/// With-Statemint bridge pallet.
|
||||
// TODO (https://github.com/paritytech/parity-bridges-common/issues/1626):
|
||||
// must be updated when we'll make appropriate changes in the Statemine runtime
|
||||
#[codec(index = 42)]
|
||||
WithStatemintBridgePallet(WithStatemintBridgePalletCall),
|
||||
}
|
||||
|
||||
/// Calls of the with-Statemint bridge pallet.
|
||||
// TODO (https://github.com/paritytech/parity-bridges-common/issues/1626):
|
||||
// must be updated when we'll make appropriate changes in the Statemine runtime
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum WithStatemintBridgePalletCall {
|
||||
#[codec(index = 42)]
|
||||
update_dot_to_ksm_conversion_rate(FixedU128),
|
||||
}
|
||||
|
||||
impl sp_runtime::traits::Dispatchable for Call {
|
||||
type RuntimeOrigin = ();
|
||||
type Config = ();
|
||||
type Info = ();
|
||||
type PostInfo = ();
|
||||
|
||||
fn dispatch(
|
||||
self,
|
||||
_origin: Self::RuntimeOrigin,
|
||||
) -> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
|
||||
unimplemented!("The Call is not expected to be dispatched.")
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ use bp_runtime::{
|
||||
Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEra, TransactionEraOf,
|
||||
};
|
||||
use codec::{Codec, Encode};
|
||||
use frame_support::weights::{Weight, WeightToFee};
|
||||
use frame_support::weights::WeightToFee;
|
||||
use jsonrpsee::core::{DeserializeOwned, Serialize};
|
||||
use num_traits::Zero;
|
||||
use sc_transaction_pool_api::TransactionStatus;
|
||||
@@ -52,8 +52,6 @@ pub trait Chain: ChainBase + Clone {
|
||||
/// How often blocks are produced on that chain. It's suggested to set this value
|
||||
/// to match the block time of the chain.
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration;
|
||||
/// Maximal expected storage proof overhead (in bytes).
|
||||
const STORAGE_PROOF_OVERHEAD: u32;
|
||||
|
||||
/// Block type.
|
||||
type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>;
|
||||
@@ -106,10 +104,6 @@ pub trait ChainWithMessages: Chain {
|
||||
/// The method is provided by the runtime that is bridged with this `ChainWithMessages`.
|
||||
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str;
|
||||
|
||||
/// Additional weight of the dispatch fee payment if dispatch is paid at the target chain
|
||||
/// and this `ChainWithMessages` is the target chain.
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight;
|
||||
|
||||
/// Maximal number of unrewarded relayers in a single confirmation transaction at this
|
||||
/// `ChainWithMessages`.
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce;
|
||||
|
||||
@@ -17,7 +17,5 @@
|
||||
//! Contains several Substrate-specific metrics that may be exposed by relay.
|
||||
|
||||
pub use float_storage_value::{FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric};
|
||||
pub use storage_proof_overhead::StorageProofOverheadMetric;
|
||||
|
||||
mod float_storage_value;
|
||||
mod storage_proof_overhead;
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::{chain::Chain, client::Client, error::Error};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use relay_utils::metrics::{
|
||||
metric_name, register, Gauge, Metric, PrometheusError, Registry, StandaloneMetric, U64,
|
||||
};
|
||||
use sp_core::storage::StorageKey;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_storage::well_known_keys::CODE;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Storage proof overhead update interval (in blocks).
|
||||
const UPDATE_INTERVAL_IN_BLOCKS: u32 = 100;
|
||||
|
||||
/// Metric that represents extra size of storage proof as unsigned integer gauge.
|
||||
///
|
||||
/// There's one thing to keep in mind when using this metric: the overhead may be slightly
|
||||
/// different for other values, but this metric gives a good estimation.
|
||||
#[derive(Debug)]
|
||||
pub struct StorageProofOverheadMetric<C: Chain> {
|
||||
client: Client<C>,
|
||||
metric: Gauge<U64>,
|
||||
}
|
||||
|
||||
impl<C: Chain> Clone for StorageProofOverheadMetric<C> {
|
||||
fn clone(&self) -> Self {
|
||||
StorageProofOverheadMetric { client: self.client.clone(), metric: self.metric.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Chain> StorageProofOverheadMetric<C> {
|
||||
/// Create new metric instance with given name and help.
|
||||
pub fn new(client: Client<C>, name: String, help: String) -> Result<Self, PrometheusError> {
|
||||
Ok(StorageProofOverheadMetric {
|
||||
client,
|
||||
metric: Gauge::new(metric_name(None, &name), help)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns approximate storage proof size overhead.
|
||||
async fn compute_storage_proof_overhead(&self) -> Result<usize, Error> {
|
||||
let best_header_hash = self.client.best_finalized_header_hash().await?;
|
||||
let best_header = self.client.header_by_hash(best_header_hash).await?;
|
||||
|
||||
let storage_proof = self
|
||||
.client
|
||||
.prove_storage(vec![StorageKey(CODE.to_vec())], best_header_hash)
|
||||
.await?;
|
||||
let storage_proof_size: usize = storage_proof.iter_nodes().map(|n| n.len()).sum();
|
||||
|
||||
let storage_value_reader = bp_runtime::StorageProofChecker::<C::Hasher>::new(
|
||||
*best_header.state_root(),
|
||||
storage_proof,
|
||||
)
|
||||
.map_err(Error::StorageProofError)?;
|
||||
let maybe_encoded_storage_value =
|
||||
storage_value_reader.read_value(CODE).map_err(Error::StorageProofError)?;
|
||||
let encoded_storage_value_size =
|
||||
maybe_encoded_storage_value.ok_or(Error::MissingMandatoryStorageValue)?.len();
|
||||
|
||||
Ok(storage_proof_size - encoded_storage_value_size)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Chain> Metric for StorageProofOverheadMetric<C> {
|
||||
fn register(&self, registry: &Registry) -> Result<(), PrometheusError> {
|
||||
register(self.metric.clone(), registry).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: Chain> StandaloneMetric for StorageProofOverheadMetric<C> {
|
||||
fn update_interval(&self) -> Duration {
|
||||
C::AVERAGE_BLOCK_INTERVAL * UPDATE_INTERVAL_IN_BLOCKS
|
||||
}
|
||||
|
||||
async fn update(&self) {
|
||||
relay_utils::metrics::set_gauge_value(
|
||||
&self.metric,
|
||||
self.compute_storage_proof_overhead()
|
||||
.await
|
||||
.map(|overhead| Some(overhead as u64)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ impl Chain for TestChain {
|
||||
const TOKEN_ID: Option<&'static str> = None;
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod";
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = 0;
|
||||
|
||||
type SignedBlock = sp_runtime::generic::SignedBlock<
|
||||
sp_runtime::generic::Block<Self::Header, sp_runtime::OpaqueExtrinsic>,
|
||||
|
||||
@@ -57,7 +57,6 @@ impl Chain for Westend {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_westend::SignedBlock;
|
||||
type Call = ();
|
||||
@@ -114,7 +113,6 @@ impl Chain for Westmint {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_westend::BEST_FINALIZED_WESTMINT_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_westend::SignedBlock;
|
||||
type Call = ();
|
||||
|
||||
@@ -57,7 +57,6 @@ impl Chain for Wococo {
|
||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
|
||||
bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD;
|
||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
|
||||
const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE;
|
||||
|
||||
type SignedBlock = bp_wococo::SignedBlock;
|
||||
type Call = ();
|
||||
|
||||
@@ -1,439 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Tools for updating conversion rate that is stored in the runtime storage.
|
||||
|
||||
use crate::{messages_lane::SubstrateMessageLane, TransactionParams};
|
||||
|
||||
use relay_substrate_client::{
|
||||
transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, CallOf, Chain, ChainWithTransactions,
|
||||
Client, SignParam, TransactionEra, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::metrics::F64SharedRef;
|
||||
use sp_core::Pair;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// Duration between updater iterations.
|
||||
const SLEEP_DURATION: Duration = Duration::from_secs(60);
|
||||
|
||||
/// Duration which will almost never expire. Since changing conversion rate may require manual
|
||||
/// intervention (e.g. if call is made through `multisig` pallet), we don't want relayer to
|
||||
/// resubmit transaction often.
|
||||
const ALMOST_NEVER_DURATION: Duration = Duration::from_secs(60 * 60 * 24 * 30);
|
||||
|
||||
/// Update-conversion-rate transaction status.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum TransactionStatus {
|
||||
/// We have not submitted any transaction recently.
|
||||
Idle,
|
||||
/// We have recently submitted transaction that should update conversion rate.
|
||||
Submitted(Instant, f64),
|
||||
}
|
||||
|
||||
/// Different ways of building 'update conversion rate' calls.
|
||||
pub trait UpdateConversionRateCallBuilder<C: Chain> {
|
||||
/// Given conversion rate, build call that updates conversion rate in given chain runtime
|
||||
/// storage.
|
||||
fn build_update_conversion_rate_call(conversion_rate: f64) -> anyhow::Result<CallOf<C>>;
|
||||
}
|
||||
|
||||
impl<C: Chain> UpdateConversionRateCallBuilder<C> for () {
|
||||
fn build_update_conversion_rate_call(_conversion_rate: f64) -> anyhow::Result<CallOf<C>> {
|
||||
Err(anyhow::format_err!("Conversion rate update is not supported at {}", C::NAME))
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro that generates `UpdateConversionRateCallBuilder` implementation for the case when
|
||||
/// you have a direct access to the source chain runtime.
|
||||
#[rustfmt::skip]
|
||||
#[macro_export]
|
||||
macro_rules! generate_direct_update_conversion_rate_call_builder {
|
||||
(
|
||||
$source_chain:ident,
|
||||
$mocked_builder:ident,
|
||||
$runtime:ty,
|
||||
$instance:ty,
|
||||
$parameter:path
|
||||
) => {
|
||||
pub struct $mocked_builder;
|
||||
|
||||
impl $crate::conversion_rate_update::UpdateConversionRateCallBuilder<$source_chain>
|
||||
for $mocked_builder
|
||||
{
|
||||
fn build_update_conversion_rate_call(
|
||||
conversion_rate: f64,
|
||||
) -> anyhow::Result<relay_substrate_client::CallOf<$source_chain>> {
|
||||
Ok(pallet_bridge_messages::Call::update_pallet_parameter::<$runtime, $instance> {
|
||||
parameter: $parameter(sp_runtime::FixedU128::from_float(conversion_rate)),
|
||||
}.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Macro that generates `UpdateConversionRateCallBuilder` implementation for the case when
|
||||
/// you only have an access to the mocked version of source chain runtime. In this case you
|
||||
/// should provide "name" of the call variant for the bridge messages calls, the "name" of
|
||||
/// the variant for the `update_pallet_parameter` call within that first option and the name
|
||||
/// of the conversion rate parameter itself.
|
||||
#[rustfmt::skip]
|
||||
#[macro_export]
|
||||
macro_rules! generate_mocked_update_conversion_rate_call_builder {
|
||||
(
|
||||
$source_chain:ident,
|
||||
$mocked_builder:ident,
|
||||
$bridge_messages:path,
|
||||
$update_pallet_parameter:path,
|
||||
$parameter:path
|
||||
) => {
|
||||
pub struct $mocked_builder;
|
||||
|
||||
impl $crate::conversion_rate_update::UpdateConversionRateCallBuilder<$source_chain>
|
||||
for $mocked_builder
|
||||
{
|
||||
fn build_update_conversion_rate_call(
|
||||
conversion_rate: f64,
|
||||
) -> anyhow::Result<relay_substrate_client::CallOf<$source_chain>> {
|
||||
Ok($bridge_messages($update_pallet_parameter($parameter(
|
||||
sp_runtime::FixedU128::from_float(conversion_rate),
|
||||
))))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Run infinite conversion rate updater loop.
|
||||
///
|
||||
/// The loop is maintaining the Left -> Right conversion rate, used as `RightTokens = LeftTokens *
|
||||
/// Rate`.
|
||||
pub fn run_conversion_rate_update_loop<Lane>(
|
||||
client: Client<Lane::SourceChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<Lane::SourceChain>>,
|
||||
left_to_right_stored_conversion_rate: F64SharedRef,
|
||||
left_to_base_conversion_rate: F64SharedRef,
|
||||
right_to_base_conversion_rate: F64SharedRef,
|
||||
max_difference_ratio: f64,
|
||||
) where
|
||||
Lane: SubstrateMessageLane,
|
||||
Lane::SourceChain: ChainWithTransactions,
|
||||
AccountIdOf<Lane::SourceChain>: From<<AccountKeyPairOf<Lane::SourceChain> as Pair>::Public>,
|
||||
{
|
||||
let stall_timeout = transaction_stall_timeout(
|
||||
transaction_params.mortality,
|
||||
Lane::SourceChain::AVERAGE_BLOCK_INTERVAL,
|
||||
ALMOST_NEVER_DURATION,
|
||||
);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Starting {} -> {} conversion rate (on {}) update loop. Stall timeout: {}s",
|
||||
Lane::TargetChain::NAME,
|
||||
Lane::SourceChain::NAME,
|
||||
Lane::SourceChain::NAME,
|
||||
stall_timeout.as_secs(),
|
||||
);
|
||||
|
||||
async_std::task::spawn(async move {
|
||||
let mut transaction_status = TransactionStatus::Idle;
|
||||
loop {
|
||||
async_std::task::sleep(SLEEP_DURATION).await;
|
||||
let maybe_new_conversion_rate = maybe_select_new_conversion_rate(
|
||||
stall_timeout,
|
||||
&mut transaction_status,
|
||||
&left_to_right_stored_conversion_rate,
|
||||
&left_to_base_conversion_rate,
|
||||
&right_to_base_conversion_rate,
|
||||
max_difference_ratio,
|
||||
)
|
||||
.await;
|
||||
if let Some((prev_conversion_rate, new_conversion_rate)) = maybe_new_conversion_rate {
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Going to update {} -> {} (on {}) conversion rate to {}.",
|
||||
Lane::TargetChain::NAME,
|
||||
Lane::SourceChain::NAME,
|
||||
Lane::SourceChain::NAME,
|
||||
new_conversion_rate,
|
||||
);
|
||||
|
||||
let result = update_target_to_source_conversion_rate::<Lane>(
|
||||
client.clone(),
|
||||
transaction_params.clone(),
|
||||
new_conversion_rate,
|
||||
)
|
||||
.await;
|
||||
match result {
|
||||
Ok(()) => {
|
||||
transaction_status =
|
||||
TransactionStatus::Submitted(Instant::now(), prev_conversion_rate);
|
||||
},
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Failed to submit conversion rate update transaction: {:?}",
|
||||
error,
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Select new conversion rate to submit to the node.
|
||||
async fn maybe_select_new_conversion_rate(
|
||||
stall_timeout: Duration,
|
||||
transaction_status: &mut TransactionStatus,
|
||||
left_to_right_stored_conversion_rate: &F64SharedRef,
|
||||
left_to_base_conversion_rate: &F64SharedRef,
|
||||
right_to_base_conversion_rate: &F64SharedRef,
|
||||
max_difference_ratio: f64,
|
||||
) -> Option<(f64, f64)> {
|
||||
let left_to_right_stored_conversion_rate =
|
||||
(*left_to_right_stored_conversion_rate.read().await)?;
|
||||
match *transaction_status {
|
||||
TransactionStatus::Idle => (),
|
||||
TransactionStatus::Submitted(submitted_at, _)
|
||||
if Instant::now() - submitted_at > stall_timeout =>
|
||||
{
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Conversion rate update transaction has been lost and loop stalled. Restarting",
|
||||
);
|
||||
|
||||
// we assume that our transaction has been lost
|
||||
*transaction_status = TransactionStatus::Idle;
|
||||
},
|
||||
TransactionStatus::Submitted(_, previous_left_to_right_stored_conversion_rate) => {
|
||||
// we can't compare float values from different sources directly, so we only care
|
||||
// whether the stored rate has been changed or not. If it has been changed, then we
|
||||
// assume that our proposal has been accepted.
|
||||
//
|
||||
// float comparison is ok here, because we compare same-origin (stored in runtime
|
||||
// storage) values and if they are different, it means that the value has actually been
|
||||
// updated
|
||||
#[allow(clippy::float_cmp)]
|
||||
if previous_left_to_right_stored_conversion_rate == left_to_right_stored_conversion_rate
|
||||
{
|
||||
// the rate has not been changed => we won't submit any transactions until it is
|
||||
// accepted, or the rate is changed by someone else
|
||||
return None
|
||||
}
|
||||
|
||||
*transaction_status = TransactionStatus::Idle;
|
||||
},
|
||||
}
|
||||
|
||||
let left_to_base_conversion_rate = (*left_to_base_conversion_rate.read().await)?;
|
||||
let right_to_base_conversion_rate = (*right_to_base_conversion_rate.read().await)?;
|
||||
let actual_left_to_right_conversion_rate =
|
||||
left_to_base_conversion_rate / right_to_base_conversion_rate;
|
||||
|
||||
let rate_difference =
|
||||
(actual_left_to_right_conversion_rate - left_to_right_stored_conversion_rate).abs();
|
||||
let rate_difference_ratio = rate_difference / left_to_right_stored_conversion_rate;
|
||||
if rate_difference_ratio < max_difference_ratio {
|
||||
return None
|
||||
}
|
||||
|
||||
Some((left_to_right_stored_conversion_rate, actual_left_to_right_conversion_rate))
|
||||
}
|
||||
|
||||
/// Update Target -> Source tokens conversion rate, stored in the Source runtime storage.
|
||||
pub async fn update_target_to_source_conversion_rate<Lane>(
|
||||
client: Client<Lane::SourceChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<Lane::SourceChain>>,
|
||||
updated_rate: f64,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
Lane: SubstrateMessageLane,
|
||||
Lane::SourceChain: ChainWithTransactions,
|
||||
AccountIdOf<Lane::SourceChain>: From<<AccountKeyPairOf<Lane::SourceChain> as Pair>::Public>,
|
||||
{
|
||||
let genesis_hash = *client.genesis_hash();
|
||||
let signer_id = transaction_params.signer.public().into();
|
||||
let (spec_version, transaction_version) = client.simple_runtime_version().await?;
|
||||
let call =
|
||||
Lane::TargetToSourceChainConversionRateUpdateBuilder::build_update_conversion_rate_call(
|
||||
updated_rate,
|
||||
)?;
|
||||
client
|
||||
.submit_signed_extrinsic(
|
||||
signer_id,
|
||||
SignParam::<Lane::SourceChain> {
|
||||
spec_version,
|
||||
transaction_version,
|
||||
genesis_hash,
|
||||
signer: transaction_params.signer,
|
||||
},
|
||||
move |best_block_id, transaction_nonce| {
|
||||
Ok(UnsignedTransaction::new(call.into(), transaction_nonce)
|
||||
.era(TransactionEra::new(best_block_id, transaction_params.mortality)))
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map(drop)
|
||||
.map_err(|err| anyhow::format_err!("{:?}", err))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use async_std::sync::{Arc, RwLock};
|
||||
|
||||
const TEST_STALL_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
fn test_maybe_select_new_conversion_rate(
|
||||
mut transaction_status: TransactionStatus,
|
||||
stored_conversion_rate: Option<f64>,
|
||||
left_to_base_conversion_rate: Option<f64>,
|
||||
right_to_base_conversion_rate: Option<f64>,
|
||||
max_difference_ratio: f64,
|
||||
) -> (Option<(f64, f64)>, TransactionStatus) {
|
||||
let stored_conversion_rate = Arc::new(RwLock::new(stored_conversion_rate));
|
||||
let left_to_base_conversion_rate = Arc::new(RwLock::new(left_to_base_conversion_rate));
|
||||
let right_to_base_conversion_rate = Arc::new(RwLock::new(right_to_base_conversion_rate));
|
||||
let result = async_std::task::block_on(maybe_select_new_conversion_rate(
|
||||
TEST_STALL_TIMEOUT,
|
||||
&mut transaction_status,
|
||||
&stored_conversion_rate,
|
||||
&left_to_base_conversion_rate,
|
||||
&right_to_base_conversion_rate,
|
||||
max_difference_ratio,
|
||||
));
|
||||
(result, transaction_status)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rate_is_not_updated_when_transaction_is_submitted() {
|
||||
let status = TransactionStatus::Submitted(Instant::now(), 10.0);
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(status, Some(10.0), Some(1.0), Some(1.0), 0.0),
|
||||
(None, status),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_state_is_changed_to_idle_when_stored_rate_shanges() {
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(
|
||||
TransactionStatus::Submitted(Instant::now(), 1.0),
|
||||
Some(10.0),
|
||||
Some(1.0),
|
||||
Some(1.0),
|
||||
100.0
|
||||
),
|
||||
(None, TransactionStatus::Idle),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_is_not_submitted_when_left_to_base_rate_is_unknown() {
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(
|
||||
TransactionStatus::Idle,
|
||||
Some(10.0),
|
||||
None,
|
||||
Some(1.0),
|
||||
0.0
|
||||
),
|
||||
(None, TransactionStatus::Idle),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_is_not_submitted_when_right_to_base_rate_is_unknown() {
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(
|
||||
TransactionStatus::Idle,
|
||||
Some(10.0),
|
||||
Some(1.0),
|
||||
None,
|
||||
0.0
|
||||
),
|
||||
(None, TransactionStatus::Idle),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_is_not_submitted_when_stored_rate_is_unknown() {
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(
|
||||
TransactionStatus::Idle,
|
||||
None,
|
||||
Some(1.0),
|
||||
Some(1.0),
|
||||
0.0
|
||||
),
|
||||
(None, TransactionStatus::Idle),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_is_not_submitted_when_difference_is_below_threshold() {
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(
|
||||
TransactionStatus::Idle,
|
||||
Some(1.0),
|
||||
Some(1.0),
|
||||
Some(1.01),
|
||||
0.02
|
||||
),
|
||||
(None, TransactionStatus::Idle),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_is_submitted_when_difference_is_above_threshold() {
|
||||
let left_to_right_stored_conversion_rate = 1.0;
|
||||
let left_to_base_conversion_rate = 18f64;
|
||||
let right_to_base_conversion_rate = 180f64;
|
||||
|
||||
assert!(left_to_base_conversion_rate < right_to_base_conversion_rate);
|
||||
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(
|
||||
TransactionStatus::Idle,
|
||||
Some(left_to_right_stored_conversion_rate),
|
||||
Some(left_to_base_conversion_rate),
|
||||
Some(right_to_base_conversion_rate),
|
||||
0.02
|
||||
),
|
||||
(
|
||||
Some((
|
||||
left_to_right_stored_conversion_rate,
|
||||
left_to_base_conversion_rate / right_to_base_conversion_rate,
|
||||
)),
|
||||
TransactionStatus::Idle
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_expires() {
|
||||
let status = TransactionStatus::Submitted(Instant::now() - TEST_STALL_TIMEOUT / 2, 10.0);
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(status, Some(10.0), Some(1.0), Some(1.0), 0.0),
|
||||
(None, status),
|
||||
);
|
||||
|
||||
let status = TransactionStatus::Submitted(Instant::now() - TEST_STALL_TIMEOUT * 2, 10.0);
|
||||
assert_eq!(
|
||||
test_maybe_select_new_conversion_rate(status, Some(10.0), Some(1.0), Some(1.0), 0.0),
|
||||
(Some((10.0, 1.0)), TransactionStatus::Idle),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Substrate relay helpers
|
||||
|
||||
use relay_utils::metrics::{FloatJsonValueMetric, PrometheusError, StandaloneMetric};
|
||||
|
||||
/// Creates standalone token price metric.
|
||||
pub fn token_price_metric(token_id: &str) -> Result<FloatJsonValueMetric, PrometheusError> {
|
||||
FloatJsonValueMetric::new(
|
||||
format!("https://api.coingecko.com/api/v3/simple/price?ids={token_id}&vs_currencies=btc"),
|
||||
format!("$.{token_id}.btc"),
|
||||
format!("{}_to_base_conversion_rate", token_id.replace('-', "_")),
|
||||
format!("Rate used to convert from {} to some BASE tokens", token_id.to_uppercase()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute conversion rate between two tokens immediately, without spawning any metrics.
|
||||
///
|
||||
/// Returned rate may be used in expression: `from_tokens * rate -> to_tokens`.
|
||||
pub async fn tokens_conversion_rate_from_metrics(
|
||||
from_token_id: &str,
|
||||
to_token_id: &str,
|
||||
) -> anyhow::Result<f64> {
|
||||
let from_token_metric = token_price_metric(from_token_id)?;
|
||||
from_token_metric.update().await;
|
||||
let to_token_metric = token_price_metric(to_token_id)?;
|
||||
to_token_metric.update().await;
|
||||
|
||||
let from_token_value = *from_token_metric.shared_value_ref().read().await;
|
||||
let to_token_value = *to_token_metric.shared_value_ref().read().await;
|
||||
// `FloatJsonValueMetric` guarantees that the value is positive && normal, so no additional
|
||||
// checks required here
|
||||
match (from_token_value, to_token_value) {
|
||||
(Some(from_token_value), Some(to_token_value)) =>
|
||||
Ok(tokens_conversion_rate(from_token_value, to_token_value)),
|
||||
_ => Err(anyhow::format_err!(
|
||||
"Failed to compute conversion rate from {} to {}",
|
||||
from_token_id,
|
||||
to_token_id,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute conversion rate between two tokens, given token prices.
|
||||
///
|
||||
/// Returned rate may be used in expression: `from_tokens * rate -> to_tokens`.
|
||||
///
|
||||
/// Both prices are assumed to be normal and non-negative.
|
||||
pub fn tokens_conversion_rate(from_token_value: f64, to_token_value: f64) -> f64 {
|
||||
from_token_value / to_token_value
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn rialto_to_millau_conversion_rate_is_correct() {
|
||||
let rialto_price = 18.18;
|
||||
let millau_price = 136.35;
|
||||
assert!(rialto_price < millau_price);
|
||||
|
||||
let conversion_rate = tokens_conversion_rate(rialto_price, millau_price);
|
||||
let rialto_amount = 100.0;
|
||||
let millau_amount = rialto_amount * conversion_rate;
|
||||
assert!(
|
||||
rialto_amount > millau_amount,
|
||||
"{} RLT * {} = {} MLU",
|
||||
rialto_amount,
|
||||
conversion_rate,
|
||||
millau_amount,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn millau_to_rialto_conversion_rate_is_correct() {
|
||||
let rialto_price = 18.18;
|
||||
let millau_price = 136.35;
|
||||
assert!(rialto_price < millau_price);
|
||||
|
||||
let conversion_rate = tokens_conversion_rate(millau_price, rialto_price);
|
||||
let millau_amount = 100.0;
|
||||
let rialto_amount = millau_amount * conversion_rate;
|
||||
assert!(
|
||||
rialto_amount > millau_amount,
|
||||
"{} MLU * {} = {} RLT",
|
||||
millau_amount,
|
||||
conversion_rate,
|
||||
rialto_amount,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,8 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod conversion_rate_update;
|
||||
pub mod error;
|
||||
pub mod finality;
|
||||
pub mod helpers;
|
||||
pub mod messages_lane;
|
||||
pub mod messages_metrics;
|
||||
pub mod messages_source;
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
//! Tools for supporting message lanes between two Substrate-based chains.
|
||||
|
||||
use crate::{
|
||||
conversion_rate_update::UpdateConversionRateCallBuilder,
|
||||
messages_metrics::StandaloneMessagesMetrics,
|
||||
messages_source::{SubstrateMessagesProof, SubstrateMessagesSource},
|
||||
messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget},
|
||||
on_demand::OnDemandRelay,
|
||||
@@ -33,49 +31,21 @@ use bridge_runtime_common::messages::{
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
|
||||
use messages_relay::{message_lane::MessageLane, relay_strategy::RelayStrategy};
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig};
|
||||
use relay_substrate_client::{
|
||||
transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain,
|
||||
ChainWithMessages, ChainWithTransactions, Client, HashOf,
|
||||
};
|
||||
use relay_utils::{metrics::MetricsParams, STALL_TIMEOUT};
|
||||
use relay_utils::{
|
||||
metrics::{GlobalMetrics, MetricsParams, StandaloneMetric},
|
||||
STALL_TIMEOUT,
|
||||
};
|
||||
use sp_core::Pair;
|
||||
use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
|
||||
|
||||
/// Substrate -> Substrate messages synchronization pipeline.
|
||||
pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync {
|
||||
/// Name of the source -> target tokens conversion rate parameter.
|
||||
///
|
||||
/// The parameter is stored at the target chain and the storage key is computed using
|
||||
/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
|
||||
/// to be 1.
|
||||
const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>;
|
||||
/// Name of the target -> source tokens conversion rate parameter.
|
||||
///
|
||||
/// The parameter is stored at the source chain and the storage key is computed using
|
||||
/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
|
||||
/// to be 1.
|
||||
const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>;
|
||||
|
||||
/// Name of the source chain fee multiplier parameter.
|
||||
///
|
||||
/// The parameter is stored at the target chain and the storage key is computed using
|
||||
/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
|
||||
/// to be 1.
|
||||
const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str>;
|
||||
/// Name of the target chain fee multiplier parameter.
|
||||
///
|
||||
/// The parameter is stored at the source chain and the storage key is computed using
|
||||
/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
|
||||
/// to be 1.
|
||||
const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str>;
|
||||
|
||||
/// Name of the transaction payment pallet, deployed at the source chain.
|
||||
const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str>;
|
||||
/// Name of the transaction payment pallet, deployed at the target chain.
|
||||
const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str>;
|
||||
|
||||
/// Messages of this chain are relayed to the `TargetChain`.
|
||||
type SourceChain: ChainWithMessages + ChainWithTransactions;
|
||||
/// Messages from the `SourceChain` are dispatched on this chain.
|
||||
@@ -85,16 +55,6 @@ pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync {
|
||||
type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder<Self>;
|
||||
/// How receive messages delivery proof call is built?
|
||||
type ReceiveMessagesDeliveryProofCallBuilder: ReceiveMessagesDeliveryProofCallBuilder<Self>;
|
||||
|
||||
/// `TargetChain` tokens to `SourceChain` tokens conversion rate update builder.
|
||||
///
|
||||
/// If not applicable to this bridge, you may use `()` here.
|
||||
type TargetToSourceChainConversionRateUpdateBuilder: UpdateConversionRateCallBuilder<
|
||||
Self::SourceChain,
|
||||
>;
|
||||
|
||||
/// Message relay strategy.
|
||||
type RelayStrategy: RelayStrategy;
|
||||
}
|
||||
|
||||
/// Adapter that allows all `SubstrateMessageLane` to act as `MessageLane`.
|
||||
@@ -138,10 +98,6 @@ pub struct MessagesRelayParams<P: SubstrateMessageLane> {
|
||||
pub lane_id: LaneId,
|
||||
/// Metrics parameters.
|
||||
pub metrics_params: MetricsParams,
|
||||
/// Pre-registered standalone metrics.
|
||||
pub standalone_metrics: Option<StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>>,
|
||||
/// Relay strategy.
|
||||
pub relay_strategy: P::RelayStrategy,
|
||||
}
|
||||
|
||||
/// Run Substrate-to-Substrate messages sync loop.
|
||||
@@ -170,13 +126,6 @@ where
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
|
||||
|
||||
let standalone_metrics = params.standalone_metrics.map(Ok).unwrap_or_else(|| {
|
||||
crate::messages_metrics::standalone_metrics::<P>(
|
||||
source_client.clone(),
|
||||
target_client.clone(),
|
||||
)
|
||||
})?;
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Starting {} -> {} messages relay.\n\t\
|
||||
@@ -220,7 +169,6 @@ where
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
relay_strategy: params.relay_strategy,
|
||||
},
|
||||
},
|
||||
SubstrateMessagesSource::<P>::new(
|
||||
@@ -236,10 +184,12 @@ where
|
||||
params.lane_id,
|
||||
relayer_id_at_source,
|
||||
params.target_transaction_params,
|
||||
standalone_metrics.clone(),
|
||||
params.source_to_target_headers_relay,
|
||||
),
|
||||
standalone_metrics.register_and_spawn(params.metrics_params)?,
|
||||
{
|
||||
GlobalMetrics::new()?.register_and_spawn(¶ms.metrics_params.registry)?;
|
||||
params.metrics_params
|
||||
},
|
||||
futures::future::pending(),
|
||||
)
|
||||
.await
|
||||
@@ -271,7 +221,6 @@ where
|
||||
R: BridgeMessagesConfig<I, InboundRelayer = AccountIdOf<P::SourceChain>>,
|
||||
I: 'static,
|
||||
R::SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain<
|
||||
R::InboundMessageFee,
|
||||
MessagesProof = FromBridgedChainMessagesProof<HashOf<P::SourceChain>>,
|
||||
>,
|
||||
CallOf<P::TargetChain>: From<BridgeMessagesCall<R, I>> + GetDispatchInfo,
|
||||
|
||||
@@ -16,260 +16,20 @@
|
||||
|
||||
//! Tools for supporting message lanes between two Substrate-based chains.
|
||||
|
||||
use crate::{helpers::tokens_conversion_rate, messages_lane::SubstrateMessageLane, TaggedAccount};
|
||||
use crate::TaggedAccount;
|
||||
|
||||
use codec::Decode;
|
||||
use frame_system::AccountInfo;
|
||||
use pallet_balances::AccountData;
|
||||
use relay_substrate_client::{
|
||||
metrics::{
|
||||
FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric, StorageProofOverheadMetric,
|
||||
},
|
||||
metrics::{FloatStorageValue, FloatStorageValueMetric},
|
||||
AccountIdOf, BalanceOf, Chain, ChainWithBalances, Client, Error as SubstrateError, IndexOf,
|
||||
};
|
||||
use relay_utils::metrics::{
|
||||
FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric,
|
||||
};
|
||||
use relay_utils::metrics::{MetricsParams, StandaloneMetric};
|
||||
use sp_core::storage::StorageData;
|
||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
||||
use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
|
||||
|
||||
/// Name of the `NextFeeMultiplier` storage value within the transaction payment pallet.
|
||||
const NEXT_FEE_MULTIPLIER_VALUE_NAME: &str = "NextFeeMultiplier";
|
||||
|
||||
/// Shared references to the standalone metrics of the message lane relay loop.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandaloneMessagesMetrics<SC: Chain, TC: Chain> {
|
||||
/// Global metrics.
|
||||
pub global: GlobalMetrics,
|
||||
/// Storage chain proof overhead metric.
|
||||
pub source_storage_proof_overhead: StorageProofOverheadMetric<SC>,
|
||||
/// Target chain proof overhead metric.
|
||||
pub target_storage_proof_overhead: StorageProofOverheadMetric<TC>,
|
||||
/// Source tokens to base conversion rate metric.
|
||||
pub source_to_base_conversion_rate: Option<FloatJsonValueMetric>,
|
||||
/// Target tokens to base conversion rate metric.
|
||||
pub target_to_base_conversion_rate: Option<FloatJsonValueMetric>,
|
||||
/// Source tokens to target tokens conversion rate metric. This rate is stored by the target
|
||||
/// chain.
|
||||
pub source_to_target_conversion_rate: Option<FloatStorageValueMetric<TC, FixedU128OrOne>>,
|
||||
/// Target tokens to source tokens conversion rate metric. This rate is stored by the source
|
||||
/// chain.
|
||||
pub target_to_source_conversion_rate: Option<FloatStorageValueMetric<SC, FixedU128OrOne>>,
|
||||
|
||||
/// Actual source chain fee multiplier.
|
||||
pub source_fee_multiplier: Option<FloatStorageValueMetric<SC, FixedU128OrOne>>,
|
||||
/// Source chain fee multiplier, stored at the target chain.
|
||||
pub source_fee_multiplier_at_target: Option<FloatStorageValueMetric<TC, FixedU128OrOne>>,
|
||||
/// Actual target chain fee multiplier.
|
||||
pub target_fee_multiplier: Option<FloatStorageValueMetric<TC, FixedU128OrOne>>,
|
||||
/// Target chain fee multiplier, stored at the target chain.
|
||||
pub target_fee_multiplier_at_source: Option<FloatStorageValueMetric<SC, FixedU128OrOne>>,
|
||||
}
|
||||
|
||||
impl<SC: Chain, TC: Chain> StandaloneMessagesMetrics<SC, TC> {
|
||||
/// Swap source and target sides.
|
||||
pub fn reverse(self) -> StandaloneMessagesMetrics<TC, SC> {
|
||||
StandaloneMessagesMetrics {
|
||||
global: self.global,
|
||||
source_storage_proof_overhead: self.target_storage_proof_overhead,
|
||||
target_storage_proof_overhead: self.source_storage_proof_overhead,
|
||||
source_to_base_conversion_rate: self.target_to_base_conversion_rate,
|
||||
target_to_base_conversion_rate: self.source_to_base_conversion_rate,
|
||||
source_to_target_conversion_rate: self.target_to_source_conversion_rate,
|
||||
target_to_source_conversion_rate: self.source_to_target_conversion_rate,
|
||||
source_fee_multiplier: self.target_fee_multiplier,
|
||||
source_fee_multiplier_at_target: self.target_fee_multiplier_at_source,
|
||||
target_fee_multiplier: self.source_fee_multiplier,
|
||||
target_fee_multiplier_at_source: self.source_fee_multiplier_at_target,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register all metrics in the registry.
|
||||
pub fn register_and_spawn(
|
||||
self,
|
||||
metrics: MetricsParams,
|
||||
) -> Result<MetricsParams, PrometheusError> {
|
||||
self.global.register_and_spawn(&metrics.registry)?;
|
||||
self.source_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
|
||||
self.target_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
|
||||
if let Some(m) = self.source_to_base_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_to_base_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_to_source_conversion_rate {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.source_fee_multiplier {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.source_fee_multiplier_at_target {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_fee_multiplier {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
if let Some(m) = self.target_fee_multiplier_at_source {
|
||||
m.register_and_spawn(&metrics.registry)?;
|
||||
}
|
||||
Ok(metrics)
|
||||
}
|
||||
|
||||
/// Return conversion rate from target to source tokens.
|
||||
pub async fn target_to_source_conversion_rate(&self) -> Option<f64> {
|
||||
let from_token_value =
|
||||
(*self.target_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await)?;
|
||||
let to_token_value =
|
||||
(*self.source_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await)?;
|
||||
Some(tokens_conversion_rate(from_token_value, to_token_value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create symmetric standalone metrics for the message lane relay loop.
|
||||
///
|
||||
/// All metrics returned by this function are exposed by loops that are serving given lane (`P`)
|
||||
/// and by loops that are serving reverse lane (`P` with swapped `TargetChain` and `SourceChain`).
|
||||
/// We assume that either conversion rate parameters have values in the storage, or they are
|
||||
/// initialized with 1:1.
|
||||
pub fn standalone_metrics<P: SubstrateMessageLane>(
|
||||
source_client: Client<P::SourceChain>,
|
||||
target_client: Client<P::TargetChain>,
|
||||
) -> anyhow::Result<StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>> {
|
||||
Ok(StandaloneMessagesMetrics {
|
||||
global: GlobalMetrics::new()?,
|
||||
source_storage_proof_overhead: StorageProofOverheadMetric::new(
|
||||
source_client.clone(),
|
||||
format!("{}_storage_proof_overhead", P::SourceChain::NAME.to_lowercase()),
|
||||
format!("{} storage proof overhead", P::SourceChain::NAME),
|
||||
)?,
|
||||
target_storage_proof_overhead: StorageProofOverheadMetric::new(
|
||||
target_client.clone(),
|
||||
format!("{}_storage_proof_overhead", P::TargetChain::NAME.to_lowercase()),
|
||||
format!("{} storage proof overhead", P::TargetChain::NAME),
|
||||
)?,
|
||||
source_to_base_conversion_rate: P::SourceChain::TOKEN_ID
|
||||
.map(|source_chain_token_id| {
|
||||
crate::helpers::token_price_metric(source_chain_token_id).map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_to_base_conversion_rate: P::TargetChain::TOKEN_ID
|
||||
.map(|target_chain_token_id| {
|
||||
crate::helpers::token_price_metric(target_chain_token_id).map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
source_to_target_conversion_rate: P::SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME
|
||||
.map(bp_runtime::storage_parameter_key)
|
||||
.map(|key| {
|
||||
FloatStorageValueMetric::new(
|
||||
FixedU128OrOne::default(),
|
||||
target_client.clone(),
|
||||
key,
|
||||
format!(
|
||||
"{}_{}_to_{}_conversion_rate",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME
|
||||
),
|
||||
format!(
|
||||
"{} to {} tokens conversion rate (used by {})",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
P::TargetChain::NAME
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_to_source_conversion_rate: P::TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME
|
||||
.map(bp_runtime::storage_parameter_key)
|
||||
.map(|key| {
|
||||
FloatStorageValueMetric::new(
|
||||
FixedU128OrOne::default(),
|
||||
source_client.clone(),
|
||||
key,
|
||||
format!(
|
||||
"{}_{}_to_{}_conversion_rate",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME
|
||||
),
|
||||
format!(
|
||||
"{} to {} tokens conversion rate (used by {})",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
P::SourceChain::NAME
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
source_fee_multiplier: P::AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME
|
||||
.map(|pallet| bp_runtime::storage_value_key(pallet, NEXT_FEE_MULTIPLIER_VALUE_NAME))
|
||||
.map(|key| {
|
||||
log::trace!(target: "bridge", "{}_fee_multiplier", P::SourceChain::NAME);
|
||||
FloatStorageValueMetric::new(
|
||||
FixedU128OrOne::default(),
|
||||
source_client.clone(),
|
||||
key,
|
||||
format!("{}_fee_multiplier", P::SourceChain::NAME,),
|
||||
format!("{} fee multiplier", P::SourceChain::NAME,),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
source_fee_multiplier_at_target: P::SOURCE_FEE_MULTIPLIER_PARAMETER_NAME
|
||||
.map(bp_runtime::storage_parameter_key)
|
||||
.map(|key| {
|
||||
FloatStorageValueMetric::new(
|
||||
FixedU128OrOne::default(),
|
||||
target_client.clone(),
|
||||
key,
|
||||
format!("{}_{}_fee_multiplier", P::TargetChain::NAME, P::SourceChain::NAME,),
|
||||
format!(
|
||||
"{} fee multiplier stored at {}",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_fee_multiplier: P::AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME
|
||||
.map(|pallet| bp_runtime::storage_value_key(pallet, NEXT_FEE_MULTIPLIER_VALUE_NAME))
|
||||
.map(|key| {
|
||||
log::trace!(target: "bridge", "{}_fee_multiplier", P::TargetChain::NAME);
|
||||
FloatStorageValueMetric::new(
|
||||
FixedU128OrOne::default(),
|
||||
target_client,
|
||||
key,
|
||||
format!("{}_fee_multiplier", P::TargetChain::NAME,),
|
||||
format!("{} fee multiplier", P::TargetChain::NAME,),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
target_fee_multiplier_at_source: P::TARGET_FEE_MULTIPLIER_PARAMETER_NAME
|
||||
.map(bp_runtime::storage_parameter_key)
|
||||
.map(|key| {
|
||||
FloatStorageValueMetric::new(
|
||||
FixedU128OrOne::default(),
|
||||
source_client,
|
||||
key,
|
||||
format!("{}_{}_fee_multiplier", P::SourceChain::NAME, P::TargetChain::NAME,),
|
||||
format!(
|
||||
"{} fee multiplier stored at {}",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
),
|
||||
)
|
||||
.map(Some)
|
||||
})
|
||||
.unwrap_or(Ok(None))?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Add relay accounts balance metrics.
|
||||
pub async fn add_relay_balances_metrics<C: ChainWithBalances>(
|
||||
client: Client<C>,
|
||||
@@ -359,9 +119,6 @@ fn convert_to_token_balance(balance: u128, token_decimals: u32) -> FixedU128 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use frame_support::storage::generator::StorageValue;
|
||||
use sp_core::storage::StorageKey;
|
||||
|
||||
#[test]
|
||||
fn token_decimals_used_properly() {
|
||||
let plancks = 425_000_000_000;
|
||||
@@ -369,12 +126,4 @@ mod tests {
|
||||
let dots = convert_to_token_balance(plancks, token_decimals);
|
||||
assert_eq!(dots, FixedU128::saturating_from_rational(425, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn next_fee_multiplier_storage_key_is_correct() {
|
||||
assert_eq!(
|
||||
bp_runtime::storage_value_key("TransactionPayment", NEXT_FEE_MULTIPLIER_VALUE_NAME),
|
||||
StorageKey(pallet_transaction_payment::NextFeeMultiplier::<rialto_runtime::Runtime>::storage_value_final_key().to_vec()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,11 @@ use async_std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{
|
||||
storage_keys::{operating_mode_key, outbound_lane_data_key},
|
||||
InboundMessageDetails, LaneId, MessageData, MessageNonce, MessagePayload,
|
||||
MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState,
|
||||
};
|
||||
use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, HeaderIdProvider};
|
||||
use bridge_runtime_common::messages::{
|
||||
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||
InboundMessageDetails, LaneId, MessageNonce, MessagePayload, MessagesOperatingMode,
|
||||
OutboundLaneData, OutboundMessageDetails,
|
||||
};
|
||||
use bp_runtime::{BasicOperatingMode, HeaderIdProvider};
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::{
|
||||
@@ -47,11 +45,11 @@ use messages_relay::{
|
||||
SourceClientState,
|
||||
},
|
||||
};
|
||||
use num_traits::{Bounded, Zero};
|
||||
use num_traits::Zero;
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages,
|
||||
ChainWithTransactions, Client, Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam,
|
||||
TransactionEra, TransactionTracker, UnsignedTransaction,
|
||||
AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages, Client,
|
||||
Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra,
|
||||
TransactionTracker, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||
use sp_core::{Bytes, Pair};
|
||||
@@ -62,7 +60,7 @@ use std::ops::RangeInclusive;
|
||||
/// required to submit to the target node: cumulative dispatch weight of bundled messages and
|
||||
/// the proof itself.
|
||||
pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<HashOf<C>>);
|
||||
type MessagesToRefine<'a, Balance> = Vec<(MessagePayload, &'a mut OutboundMessageDetails<Balance>)>;
|
||||
type MessagesToRefine<'a> = Vec<(MessagePayload, &'a mut OutboundMessageDetails)>;
|
||||
|
||||
/// Substrate client as Substrate messages source.
|
||||
pub struct SubstrateMessagesSource<P: SubstrateMessageLane> {
|
||||
@@ -207,9 +205,7 @@ where
|
||||
// prepare arguments of the inbound message details call (if we need it)
|
||||
let mut msgs_to_refine = vec![];
|
||||
for out_msg_details in out_msgs_details.iter_mut() {
|
||||
if out_msg_details.dispatch_fee_payment != DispatchFeePayment::AtTargetChain {
|
||||
continue
|
||||
}
|
||||
// in our current strategy all messages are supposed to be paid at the target chain
|
||||
|
||||
// for pay-at-target messages we may want to ask target chain for
|
||||
// refined dispatch weight
|
||||
@@ -218,7 +214,7 @@ where
|
||||
&self.lane_id,
|
||||
out_msg_details.nonce,
|
||||
);
|
||||
let msg_data: MessageData<BalanceOf<P::SourceChain>> =
|
||||
let msg_payload: MessagePayload =
|
||||
self.source_client.storage_value(msg_key, Some(id.1)).await?.ok_or_else(|| {
|
||||
SubstrateError::Custom(format!(
|
||||
"Message to {} {:?}/{} is missing from runtime the storage of {} at {:?}",
|
||||
@@ -230,7 +226,7 @@ where
|
||||
))
|
||||
})?;
|
||||
|
||||
msgs_to_refine.push((msg_data.payload, out_msg_details));
|
||||
msgs_to_refine.push((msg_payload, out_msg_details));
|
||||
}
|
||||
|
||||
for mut msgs_to_refine_batch in
|
||||
@@ -277,8 +273,7 @@ where
|
||||
MessageDetails {
|
||||
dispatch_weight: out_msg_details.dispatch_weight,
|
||||
size: out_msg_details.size as _,
|
||||
reward: out_msg_details.delivery_and_dispatch_fee,
|
||||
dispatch_fee_payment: out_msg_details.dispatch_fee_payment,
|
||||
reward: Zero::zero(),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -370,39 +365,6 @@ where
|
||||
target_to_source_headers_relay.require_more_headers(id.0).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn estimate_confirmation_transaction(
|
||||
&self,
|
||||
) -> <MessageLaneAdapter<P> as MessageLane>::SourceChainBalance {
|
||||
let runtime_version = match self.source_client.runtime_version().await {
|
||||
Ok(v) => v,
|
||||
Err(_) => return BalanceOf::<P::SourceChain>::max_value(),
|
||||
};
|
||||
async {
|
||||
let dummy_tx = P::SourceChain::sign_transaction(
|
||||
SignParam::<P::SourceChain> {
|
||||
spec_version: runtime_version.spec_version,
|
||||
transaction_version: runtime_version.transaction_version,
|
||||
genesis_hash: *self.source_client.genesis_hash(),
|
||||
signer: self.transaction_params.signer.clone(),
|
||||
},
|
||||
make_messages_delivery_proof_transaction::<P>(
|
||||
&self.transaction_params,
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Zero::zero(),
|
||||
prepare_dummy_messages_delivery_proof::<P::SourceChain, P::TargetChain>(),
|
||||
false,
|
||||
)?,
|
||||
)?
|
||||
.encode();
|
||||
self.source_client
|
||||
.estimate_extrinsic_fee(Bytes(dummy_tx))
|
||||
.await
|
||||
.map(|fee| fee.inclusion_fee())
|
||||
}
|
||||
.await
|
||||
.unwrap_or_else(|_| BalanceOf::<P::SourceChain>::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that the messages pallet at source chain is active.
|
||||
@@ -441,30 +403,6 @@ fn make_messages_delivery_proof_transaction<P: SubstrateMessageLane>(
|
||||
.era(TransactionEra::new(source_best_block_id, source_transaction_params.mortality)))
|
||||
}
|
||||
|
||||
/// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction.
|
||||
///
|
||||
/// We don't care about proof actually being the valid proof, because its validity doesn't
|
||||
/// affect the call weight - we only care about its size.
|
||||
fn prepare_dummy_messages_delivery_proof<SC: Chain, TC: Chain>(
|
||||
) -> SubstrateMessagesDeliveryProof<TC> {
|
||||
let single_message_confirmation_size =
|
||||
bp_messages::InboundLaneData::<()>::encoded_size_hint_u32(1, 1);
|
||||
let proof_size = TC::STORAGE_PROOF_OVERHEAD.saturating_add(single_message_confirmation_size);
|
||||
(
|
||||
UnrewardedRelayersState {
|
||||
unrewarded_relayer_entries: 1,
|
||||
messages_in_oldest_entry: 1,
|
||||
total_messages: 1,
|
||||
last_delivered_nonce: 1,
|
||||
},
|
||||
FromBridgedChainMessagesDeliveryProof {
|
||||
bridged_header_hash: Default::default(),
|
||||
storage_proof: vec![vec![0; proof_size as usize]],
|
||||
lane: Default::default(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Read best blocks from given client.
|
||||
///
|
||||
/// This function assumes that the chain that is followed by the `self_client` has
|
||||
@@ -552,7 +490,7 @@ where
|
||||
}
|
||||
|
||||
fn validate_out_msgs_details<C: Chain>(
|
||||
out_msgs_details: &[OutboundMessageDetails<C::Balance>],
|
||||
out_msgs_details: &[OutboundMessageDetails],
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
) -> Result<(), SubstrateError> {
|
||||
let make_missing_nonce_error = |expected_nonce| {
|
||||
@@ -601,8 +539,8 @@ fn validate_out_msgs_details<C: Chain>(
|
||||
|
||||
fn split_msgs_to_refine<Source: Chain + ChainWithMessages, Target: Chain>(
|
||||
lane_id: LaneId,
|
||||
msgs_to_refine: MessagesToRefine<Source::Balance>,
|
||||
) -> Result<Vec<MessagesToRefine<Source::Balance>>, SubstrateError> {
|
||||
msgs_to_refine: MessagesToRefine,
|
||||
) -> Result<Vec<MessagesToRefine>, SubstrateError> {
|
||||
let max_batch_size = Target::max_extrinsic_size() as usize;
|
||||
let mut batches = vec![];
|
||||
|
||||
@@ -635,23 +573,20 @@ fn split_msgs_to_refine<Source: Chain + ChainWithMessages, Target: Chain>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bp_runtime::{messages::DispatchFeePayment, Chain as ChainBase};
|
||||
use codec::MaxEncodedLen;
|
||||
use bp_runtime::Chain as ChainBase;
|
||||
use relay_rialto_client::Rialto;
|
||||
use relay_rococo_client::Rococo;
|
||||
use relay_wococo_client::Wococo;
|
||||
|
||||
fn message_details_from_rpc(
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
) -> Vec<OutboundMessageDetails<bp_wococo::Balance>> {
|
||||
) -> Vec<OutboundMessageDetails> {
|
||||
nonces
|
||||
.into_iter()
|
||||
.map(|nonce| bp_messages::OutboundMessageDetails {
|
||||
nonce,
|
||||
dispatch_weight: Weight::zero(),
|
||||
size: 0,
|
||||
delivery_and_dispatch_fee: 0,
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -704,31 +639,16 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prepare_dummy_messages_delivery_proof_works() {
|
||||
let expected_minimal_size =
|
||||
bp_wococo::AccountId::max_encoded_len() as u32 + Rococo::STORAGE_PROOF_OVERHEAD;
|
||||
let dummy_proof = prepare_dummy_messages_delivery_proof::<Wococo, Rococo>();
|
||||
assert!(
|
||||
dummy_proof.1.encode().len() as u32 > expected_minimal_size,
|
||||
"Expected proof size at least {}. Got: {}",
|
||||
expected_minimal_size,
|
||||
dummy_proof.1.encode().len(),
|
||||
);
|
||||
}
|
||||
|
||||
fn check_split_msgs_to_refine(
|
||||
payload_sizes: Vec<usize>,
|
||||
expected_batches: Result<Vec<usize>, ()>,
|
||||
) {
|
||||
let mut out_msgs_details = vec![];
|
||||
for (idx, _) in payload_sizes.iter().enumerate() {
|
||||
out_msgs_details.push(OutboundMessageDetails::<BalanceOf<Rialto>> {
|
||||
out_msgs_details.push(OutboundMessageDetails {
|
||||
nonce: idx as MessageNonce,
|
||||
dispatch_weight: Weight::zero(),
|
||||
size: 0,
|
||||
delivery_and_dispatch_fee: 0,
|
||||
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
use crate::{
|
||||
messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane},
|
||||
messages_metrics::StandaloneMessagesMetrics,
|
||||
messages_source::{ensure_messages_pallet_active, read_client_state, SubstrateMessagesProof},
|
||||
on_demand::OnDemandRelay,
|
||||
TransactionParams,
|
||||
@@ -32,24 +31,18 @@ use bp_messages::{
|
||||
storage_keys::inbound_lane_data_key, total_unrewarded_messages, InboundLaneData, LaneId,
|
||||
MessageNonce, UnrewardedRelayersState,
|
||||
};
|
||||
use bridge_runtime_common::messages::{
|
||||
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_support::weights::{Weight, WeightToFee};
|
||||
use bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof;
|
||||
use messages_relay::{
|
||||
message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf},
|
||||
message_lane_loop::{NoncesSubmitArtifacts, TargetClient, TargetClientState},
|
||||
};
|
||||
use num_traits::{Bounded, Zero};
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages,
|
||||
ChainWithTransactions, Client, Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam,
|
||||
TransactionEra, TransactionTracker, UnsignedTransaction, WeightToFeeOf,
|
||||
AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages, Client,
|
||||
Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra,
|
||||
TransactionTracker, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
|
||||
use relay_utils::relay_loop::Client as RelayClient;
|
||||
use sp_core::Pair;
|
||||
use std::{collections::VecDeque, convert::TryFrom, ops::RangeInclusive};
|
||||
|
||||
/// Message receiving proof returned by the target Substrate node.
|
||||
@@ -63,7 +56,6 @@ pub struct SubstrateMessagesTarget<P: SubstrateMessageLane> {
|
||||
lane_id: LaneId,
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
|
||||
metric_values: StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>,
|
||||
source_to_target_headers_relay: Option<Arc<dyn OnDemandRelay<BlockNumberOf<P::SourceChain>>>>,
|
||||
}
|
||||
|
||||
@@ -75,7 +67,6 @@ impl<P: SubstrateMessageLane> SubstrateMessagesTarget<P> {
|
||||
lane_id: LaneId,
|
||||
relayer_id_at_source: AccountIdOf<P::SourceChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
|
||||
metric_values: StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>,
|
||||
source_to_target_headers_relay: Option<
|
||||
Arc<dyn OnDemandRelay<BlockNumberOf<P::SourceChain>>>,
|
||||
>,
|
||||
@@ -86,7 +77,6 @@ impl<P: SubstrateMessageLane> SubstrateMessagesTarget<P> {
|
||||
lane_id,
|
||||
relayer_id_at_source,
|
||||
transaction_params,
|
||||
metric_values,
|
||||
source_to_target_headers_relay,
|
||||
}
|
||||
}
|
||||
@@ -121,7 +111,6 @@ impl<P: SubstrateMessageLane> Clone for SubstrateMessagesTarget<P> {
|
||||
lane_id: self.lane_id,
|
||||
relayer_id_at_source: self.relayer_id_at_source.clone(),
|
||||
transaction_params: self.transaction_params.clone(),
|
||||
metric_values: self.metric_values.clone(),
|
||||
source_to_target_headers_relay: self.source_to_target_headers_relay.clone(),
|
||||
}
|
||||
}
|
||||
@@ -283,142 +272,6 @@ where
|
||||
source_to_target_headers_relay.require_more_headers(id.0).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn estimate_delivery_transaction_in_source_tokens(
|
||||
&self,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
total_prepaid_nonces: MessageNonce,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> Result<<MessageLaneAdapter<P> as MessageLane>::SourceChainBalance, SubstrateError> {
|
||||
let conversion_rate =
|
||||
self.metric_values.target_to_source_conversion_rate().await.ok_or_else(|| {
|
||||
SubstrateError::Custom(format!(
|
||||
"Failed to compute conversion rate from {} to {}",
|
||||
P::TargetChain::NAME,
|
||||
P::SourceChain::NAME,
|
||||
))
|
||||
})?;
|
||||
|
||||
let (spec_version, transaction_version) =
|
||||
self.target_client.simple_runtime_version().await?;
|
||||
// Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight.
|
||||
let delivery_tx = P::TargetChain::sign_transaction(
|
||||
SignParam {
|
||||
spec_version,
|
||||
transaction_version,
|
||||
genesis_hash: Default::default(),
|
||||
signer: self.transaction_params.signer.clone(),
|
||||
},
|
||||
make_messages_delivery_transaction::<P>(
|
||||
&self.transaction_params,
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Zero::zero(),
|
||||
self.relayer_id_at_source.clone(),
|
||||
nonces.clone(),
|
||||
prepare_dummy_messages_proof::<P::SourceChain>(
|
||||
nonces.clone(),
|
||||
total_dispatch_weight,
|
||||
total_size,
|
||||
),
|
||||
false,
|
||||
)?,
|
||||
)?
|
||||
.encode();
|
||||
let delivery_tx_fee = self.target_client.estimate_extrinsic_fee(Bytes(delivery_tx)).await?;
|
||||
let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee();
|
||||
|
||||
// The pre-dispatch cost of delivery transaction includes additional fee to cover dispatch
|
||||
// fee payment (Currency::transfer in regular deployment). But if message dispatch has
|
||||
// already been paid at the Source chain, the delivery transaction will refund relayer with
|
||||
// this additional cost. But `estimate_extrinsic_fee` obviously just returns pre-dispatch
|
||||
// cost of the transaction. So if transaction delivers prepaid message, then it may happen
|
||||
// that pre-dispatch cost is larger than reward and `Rational` relayer will refuse to
|
||||
// deliver this message.
|
||||
//
|
||||
// The most obvious solution would be to deduct total weight of dispatch fee payments from
|
||||
// the `total_dispatch_weight` and use regular `estimate_extrinsic_fee` call. But what if
|
||||
// `total_dispatch_weight` is less than total dispatch fee payments weight? Weight is
|
||||
// strictly positive, so we can't use this option.
|
||||
//
|
||||
// Instead we'll be directly using `WeightToFee` and `NextFeeMultiplier` of the Target
|
||||
// chain. This requires more knowledge of the Target chain, but seems there's no better way
|
||||
// to solve this now.
|
||||
let expected_refund_in_target_tokens = if total_prepaid_nonces != 0 {
|
||||
const WEIGHT_DIFFERENCE: Weight = Weight::from_ref_time(100);
|
||||
|
||||
let (spec_version, transaction_version) =
|
||||
self.target_client.simple_runtime_version().await?;
|
||||
let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE);
|
||||
let dummy_tx = P::TargetChain::sign_transaction(
|
||||
SignParam {
|
||||
spec_version,
|
||||
transaction_version,
|
||||
genesis_hash: Default::default(),
|
||||
signer: self.transaction_params.signer.clone(),
|
||||
},
|
||||
make_messages_delivery_transaction::<P>(
|
||||
&self.transaction_params,
|
||||
HeaderId(Default::default(), Default::default()),
|
||||
Zero::zero(),
|
||||
self.relayer_id_at_source.clone(),
|
||||
nonces.clone(),
|
||||
prepare_dummy_messages_proof::<P::SourceChain>(
|
||||
nonces.clone(),
|
||||
larger_dispatch_weight,
|
||||
total_size,
|
||||
),
|
||||
false,
|
||||
)?,
|
||||
)?
|
||||
.encode();
|
||||
let larger_delivery_tx_fee =
|
||||
self.target_client.estimate_extrinsic_fee(Bytes(dummy_tx)).await?;
|
||||
|
||||
compute_prepaid_messages_refund::<P::TargetChain>(
|
||||
total_prepaid_nonces,
|
||||
compute_fee_multiplier::<P::TargetChain>(
|
||||
delivery_tx_fee.adjusted_weight_fee,
|
||||
total_dispatch_weight,
|
||||
larger_delivery_tx_fee.adjusted_weight_fee,
|
||||
larger_dispatch_weight,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Zero::zero()
|
||||
};
|
||||
|
||||
let delivery_fee_in_source_tokens =
|
||||
convert_target_tokens_to_source_tokens::<P::SourceChain, P::TargetChain>(
|
||||
FixedU128::from_float(conversion_rate),
|
||||
inclusion_fee_in_target_tokens.saturating_sub(expected_refund_in_target_tokens),
|
||||
);
|
||||
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Estimated {} -> {} messages delivery transaction.\n\t\
|
||||
Total nonces: {:?}\n\t\
|
||||
Prepaid messages: {}\n\t\
|
||||
Total messages size: {}\n\t\
|
||||
Total messages dispatch weight: {}\n\t\
|
||||
Inclusion fee (in {1} tokens): {:?}\n\t\
|
||||
Expected refund (in {1} tokens): {:?}\n\t\
|
||||
{1} -> {0} conversion rate: {:?}\n\t\
|
||||
Expected delivery tx fee (in {0} tokens): {:?}",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
nonces,
|
||||
total_prepaid_nonces,
|
||||
total_size,
|
||||
total_dispatch_weight,
|
||||
inclusion_fee_in_target_tokens,
|
||||
expected_refund_in_target_tokens,
|
||||
conversion_rate,
|
||||
delivery_fee_in_source_tokens,
|
||||
);
|
||||
|
||||
Ok(delivery_fee_in_source_tokens)
|
||||
}
|
||||
}
|
||||
|
||||
/// Make messages delivery transaction from given proof.
|
||||
@@ -443,153 +296,3 @@ fn make_messages_delivery_transaction<P: SubstrateMessageLane>(
|
||||
Ok(UnsignedTransaction::new(call.into(), transaction_nonce)
|
||||
.era(TransactionEra::new(target_best_block_id, target_transaction_params.mortality)))
|
||||
}
|
||||
|
||||
/// Prepare 'dummy' messages proof that will compose the delivery transaction.
|
||||
///
|
||||
/// We don't care about proof actually being the valid proof, because its validity doesn't
|
||||
/// affect the call weight - we only care about its size.
|
||||
fn prepare_dummy_messages_proof<SC: Chain>(
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> SubstrateMessagesProof<SC> {
|
||||
(
|
||||
total_dispatch_weight,
|
||||
FromBridgedChainMessagesProof {
|
||||
bridged_header_hash: Default::default(),
|
||||
storage_proof: vec![vec![
|
||||
0;
|
||||
SC::STORAGE_PROOF_OVERHEAD.saturating_add(total_size) as usize
|
||||
]],
|
||||
lane: Default::default(),
|
||||
nonces_start: *nonces.start(),
|
||||
nonces_end: *nonces.end(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Given delivery transaction fee in target chain tokens and conversion rate to the source
|
||||
/// chain tokens, compute transaction cost in source chain tokens.
|
||||
fn convert_target_tokens_to_source_tokens<SC: Chain, TC: Chain>(
|
||||
target_to_source_conversion_rate: FixedU128,
|
||||
target_transaction_fee: TC::Balance,
|
||||
) -> SC::Balance
|
||||
where
|
||||
SC::Balance: TryFrom<TC::Balance>,
|
||||
{
|
||||
SC::Balance::try_from(
|
||||
target_to_source_conversion_rate.saturating_mul_int(target_transaction_fee),
|
||||
)
|
||||
.unwrap_or_else(|_| SC::Balance::max_value())
|
||||
}
|
||||
|
||||
/// Compute fee multiplier that is used by the chain, given a couple of fees for transactions
|
||||
/// that are only differ in dispatch weights.
|
||||
///
|
||||
/// This function assumes that standard transaction payment pallet is used by the chain.
|
||||
/// The only fee component that depends on dispatch weight is the `adjusted_weight_fee`.
|
||||
///
|
||||
/// **WARNING**: this functions will only be accurate if weight-to-fee conversion function
|
||||
/// is linear. For non-linear polynomials the error will grow with `weight_difference` growth.
|
||||
/// So better to use smaller differences.
|
||||
fn compute_fee_multiplier<C: ChainWithMessages>(
|
||||
smaller_adjusted_weight_fee: BalanceOf<C>,
|
||||
smaller_tx_weight: Weight,
|
||||
larger_adjusted_weight_fee: BalanceOf<C>,
|
||||
larger_tx_weight: Weight,
|
||||
) -> FixedU128 {
|
||||
let adjusted_weight_fee_difference =
|
||||
larger_adjusted_weight_fee.saturating_sub(smaller_adjusted_weight_fee);
|
||||
let smaller_tx_unadjusted_weight_fee = WeightToFeeOf::<C>::weight_to_fee(&smaller_tx_weight);
|
||||
let larger_tx_unadjusted_weight_fee = WeightToFeeOf::<C>::weight_to_fee(&larger_tx_weight);
|
||||
FixedU128::saturating_from_rational(
|
||||
adjusted_weight_fee_difference,
|
||||
larger_tx_unadjusted_weight_fee.saturating_sub(smaller_tx_unadjusted_weight_fee),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute fee that will be refunded to the relayer because dispatch of `total_prepaid_nonces`
|
||||
/// messages has been paid at the source chain.
|
||||
fn compute_prepaid_messages_refund<C: ChainWithMessages>(
|
||||
total_prepaid_nonces: MessageNonce,
|
||||
fee_multiplier: FixedU128,
|
||||
) -> BalanceOf<C> {
|
||||
fee_multiplier.saturating_mul_int(WeightToFeeOf::<C>::weight_to_fee(
|
||||
&C::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN.saturating_mul(total_prepaid_nonces),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use relay_rialto_client::Rialto;
|
||||
use relay_rococo_client::Rococo;
|
||||
use relay_wococo_client::Wococo;
|
||||
|
||||
#[test]
|
||||
fn prepare_dummy_messages_proof_works() {
|
||||
const DISPATCH_WEIGHT: Weight = Weight::from_ref_time(1_000_000);
|
||||
const SIZE: u32 = 1_000;
|
||||
let dummy_proof = prepare_dummy_messages_proof::<Rococo>(1..=10, DISPATCH_WEIGHT, SIZE);
|
||||
assert_eq!(dummy_proof.0, DISPATCH_WEIGHT);
|
||||
assert!(
|
||||
dummy_proof.1.encode().len() as u32 > SIZE,
|
||||
"Expected proof size at least {}. Got: {}",
|
||||
SIZE,
|
||||
dummy_proof.1.encode().len(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_target_tokens_to_source_tokens_works() {
|
||||
assert_eq!(
|
||||
convert_target_tokens_to_source_tokens::<Rococo, Wococo>((150, 100).into(), 1_000),
|
||||
1_500
|
||||
);
|
||||
assert_eq!(
|
||||
convert_target_tokens_to_source_tokens::<Rococo, Wococo>((50, 100).into(), 1_000),
|
||||
500
|
||||
);
|
||||
assert_eq!(
|
||||
convert_target_tokens_to_source_tokens::<Rococo, Wococo>((100, 100).into(), 1_000),
|
||||
1_000
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_fee_multiplier_returns_sane_results() {
|
||||
let multiplier: FixedU128 =
|
||||
bp_rialto::WeightToFee::weight_to_fee(&Weight::from_ref_time(1)).into();
|
||||
|
||||
let smaller_weight = 1_000_000;
|
||||
let smaller_adjusted_weight_fee = multiplier.saturating_mul_int(
|
||||
WeightToFeeOf::<Rialto>::weight_to_fee(&Weight::from_ref_time(smaller_weight)),
|
||||
);
|
||||
|
||||
let larger_weight = smaller_weight + 200_000;
|
||||
let larger_adjusted_weight_fee = multiplier.saturating_mul_int(
|
||||
WeightToFeeOf::<Rialto>::weight_to_fee(&Weight::from_ref_time(larger_weight)),
|
||||
);
|
||||
assert_eq!(
|
||||
compute_fee_multiplier::<Rialto>(
|
||||
smaller_adjusted_weight_fee,
|
||||
Weight::from_ref_time(smaller_weight),
|
||||
larger_adjusted_weight_fee,
|
||||
Weight::from_ref_time(larger_weight),
|
||||
),
|
||||
multiplier,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_prepaid_messages_refund_returns_sane_results() {
|
||||
assert!(
|
||||
compute_prepaid_messages_refund::<Rialto>(
|
||||
10,
|
||||
FixedU128::saturating_from_rational(110, 100),
|
||||
) > Rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN
|
||||
.saturating_mul(10u64)
|
||||
.ref_time() as _
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ mod metrics;
|
||||
|
||||
pub mod message_lane;
|
||||
pub mod message_lane_loop;
|
||||
pub mod relay_strategy;
|
||||
|
||||
mod message_race_delivery;
|
||||
mod message_race_limits;
|
||||
mod message_race_loop;
|
||||
mod message_race_receiving;
|
||||
mod message_race_strategy;
|
||||
|
||||
@@ -30,7 +30,6 @@ use async_trait::async_trait;
|
||||
use futures::{channel::mpsc::unbounded, future::FutureExt, stream::StreamExt};
|
||||
|
||||
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight};
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
use relay_utils::{
|
||||
interval, metrics::MetricsParams, process_future_result, relay_loop::Client as RelayClient,
|
||||
retry_backoff, FailedClient, TransactionTracker,
|
||||
@@ -41,12 +40,11 @@ use crate::{
|
||||
message_race_delivery::run as run_message_delivery_race,
|
||||
message_race_receiving::run as run_message_receiving_race,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
relay_strategy::RelayStrategy,
|
||||
};
|
||||
|
||||
/// Message lane loop configuration params.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Params<Strategy: RelayStrategy> {
|
||||
pub struct Params {
|
||||
/// Id of lane this loop is servicing.
|
||||
pub lane: LaneId,
|
||||
/// Interval at which we ask target node about its updates.
|
||||
@@ -56,22 +54,12 @@ pub struct Params<Strategy: RelayStrategy> {
|
||||
/// Delay between moments when connection error happens and our reconnect attempt.
|
||||
pub reconnect_delay: Duration,
|
||||
/// Message delivery race parameters.
|
||||
pub delivery_params: MessageDeliveryParams<Strategy>,
|
||||
}
|
||||
|
||||
/// Relayer operating mode.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RelayerMode {
|
||||
/// The relayer doesn't care about rewards.
|
||||
Altruistic,
|
||||
/// The relayer will deliver all messages and confirmations as long as he's not losing any
|
||||
/// funds.
|
||||
Rational,
|
||||
pub delivery_params: MessageDeliveryParams,
|
||||
}
|
||||
|
||||
/// Message delivery race parameters.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MessageDeliveryParams<Strategy: RelayStrategy> {
|
||||
pub struct MessageDeliveryParams {
|
||||
/// Maximal number of unconfirmed relayer entries at the inbound lane. If there's that number
|
||||
/// of entries in the `InboundLaneData::relayers` set, all new messages will be rejected until
|
||||
/// reward payment will be proved (by including outbound lane state to the message delivery
|
||||
@@ -87,8 +75,6 @@ pub struct MessageDeliveryParams<Strategy: RelayStrategy> {
|
||||
pub max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal cumulative size of relayed messages in single delivery transaction.
|
||||
pub max_messages_size_in_single_batch: u32,
|
||||
/// Relay strategy
|
||||
pub relay_strategy: Strategy,
|
||||
}
|
||||
|
||||
/// Message details.
|
||||
@@ -100,8 +86,6 @@ pub struct MessageDetails<SourceChainBalance> {
|
||||
pub size: u32,
|
||||
/// The relayer reward paid in the source chain tokens.
|
||||
pub reward: SourceChainBalance,
|
||||
/// Where the fee for dispatching message is paid?
|
||||
pub dispatch_fee_payment: DispatchFeePayment,
|
||||
}
|
||||
|
||||
/// Messages details map.
|
||||
@@ -173,9 +157,6 @@ pub trait SourceClient<P: MessageLane>: RelayClient {
|
||||
|
||||
/// We need given finalized target header on source to continue synchronization.
|
||||
async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<P>);
|
||||
|
||||
/// Estimate cost of single message confirmation transaction in source chain tokens.
|
||||
async fn estimate_confirmation_transaction(&self) -> P::SourceChainBalance;
|
||||
}
|
||||
|
||||
/// Target client trait.
|
||||
@@ -221,18 +202,6 @@ pub trait TargetClient<P: MessageLane>: RelayClient {
|
||||
|
||||
/// We need given finalized source header on target to continue synchronization.
|
||||
async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<P>);
|
||||
|
||||
/// Estimate cost of messages delivery transaction in source chain tokens.
|
||||
///
|
||||
/// Please keep in mind that the returned cost must be converted to the source chain
|
||||
/// tokens, even though the transaction fee will be paid in the target chain tokens.
|
||||
async fn estimate_delivery_transaction_in_source_tokens(
|
||||
&self,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
total_prepaid_nonces: MessageNonce,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> Result<P::SourceChainBalance, Self::Error>;
|
||||
}
|
||||
|
||||
/// State of the client.
|
||||
@@ -272,8 +241,8 @@ pub fn metrics_prefix<P: MessageLane>(lane: &LaneId) -> String {
|
||||
}
|
||||
|
||||
/// Run message lane service loop.
|
||||
pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
params: Params<Strategy>,
|
||||
pub async fn run<P: MessageLane>(
|
||||
params: Params,
|
||||
source_client: impl SourceClient<P>,
|
||||
target_client: impl TargetClient<P>,
|
||||
metrics_params: MetricsParams,
|
||||
@@ -283,11 +252,7 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
relay_utils::relay_loop(source_client, target_client)
|
||||
.reconnect_delay(params.reconnect_delay)
|
||||
.with_metrics(metrics_params)
|
||||
.loop_metric(MessageLaneLoopMetrics::new(
|
||||
Some(&metrics_prefix::<P>(¶ms.lane)),
|
||||
P::SOURCE_NAME,
|
||||
P::TARGET_NAME,
|
||||
)?)?
|
||||
.loop_metric(MessageLaneLoopMetrics::new(Some(&metrics_prefix::<P>(¶ms.lane)))?)?
|
||||
.expose()
|
||||
.await?
|
||||
.run(metrics_prefix::<P>(¶ms.lane), move |source_client, target_client, metrics| {
|
||||
@@ -304,13 +269,8 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
|
||||
/// Run one-way message delivery loop until connection with target or source node is lost, or exit
|
||||
/// signal is received.
|
||||
async fn run_until_connection_lost<
|
||||
P: MessageLane,
|
||||
Strategy: RelayStrategy,
|
||||
SC: SourceClient<P>,
|
||||
TC: TargetClient<P>,
|
||||
>(
|
||||
params: Params<Strategy>,
|
||||
async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: TargetClient<P>>(
|
||||
params: Params,
|
||||
source_client: SC,
|
||||
target_client: TC,
|
||||
metrics_msg: Option<MessageLaneLoopMetrics>,
|
||||
@@ -477,17 +437,12 @@ pub(crate) mod tests {
|
||||
|
||||
use relay_utils::{HeaderId, MaybeConnectionError, TrackedTransactionStatus};
|
||||
|
||||
use crate::relay_strategy::AltruisticStrategy;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn header_id(number: TestSourceHeaderNumber) -> TestSourceHeaderId {
|
||||
HeaderId(number, number)
|
||||
}
|
||||
|
||||
pub const CONFIRMATION_TRANSACTION_COST: TestSourceChainBalance = 1;
|
||||
pub const BASE_MESSAGE_DELIVERY_TRANSACTION_COST: TestSourceChainBalance = 1;
|
||||
|
||||
pub type TestSourceChainBalance = u64;
|
||||
pub type TestSourceHeaderId = HeaderId<TestSourceHeaderNumber, TestSourceHeaderHash>;
|
||||
pub type TestTargetHeaderId = HeaderId<TestTargetHeaderNumber, TestTargetHeaderHash>;
|
||||
@@ -681,7 +636,6 @@ pub(crate) mod tests {
|
||||
dispatch_weight: Weight::from_ref_time(1),
|
||||
size: 1,
|
||||
reward: 1,
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -737,10 +691,6 @@ pub(crate) mod tests {
|
||||
(self.tick)(&mut data);
|
||||
(self.post_tick)(&mut data);
|
||||
}
|
||||
|
||||
async fn estimate_confirmation_transaction(&self) -> TestSourceChainBalance {
|
||||
CONFIRMATION_TRANSACTION_COST
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -871,20 +821,6 @@ pub(crate) mod tests {
|
||||
(self.tick)(&mut data);
|
||||
(self.post_tick)(&mut data);
|
||||
}
|
||||
|
||||
async fn estimate_delivery_transaction_in_source_tokens(
|
||||
&self,
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
_total_prepaid_nonces: MessageNonce,
|
||||
total_dispatch_weight: Weight,
|
||||
total_size: u32,
|
||||
) -> Result<TestSourceChainBalance, TestError> {
|
||||
Ok((Weight::from_ref_time(BASE_MESSAGE_DELIVERY_TRANSACTION_COST) *
|
||||
(nonces.end() - nonces.start() + 1) +
|
||||
total_dispatch_weight +
|
||||
Weight::from_ref_time(total_size as u64))
|
||||
.ref_time())
|
||||
}
|
||||
}
|
||||
|
||||
fn run_loop_test(
|
||||
@@ -920,7 +856,6 @@ pub(crate) mod tests {
|
||||
max_messages_in_single_batch: 4,
|
||||
max_messages_weight_in_single_batch: Weight::from_ref_time(4),
|
||||
max_messages_size_in_single_batch: 4,
|
||||
relay_strategy: AltruisticStrategy,
|
||||
},
|
||||
},
|
||||
source_client,
|
||||
|
||||
@@ -28,23 +28,23 @@ use crate::{
|
||||
SourceClient as MessageLaneSourceClient, SourceClientState,
|
||||
TargetClient as MessageLaneTargetClient, TargetClientState,
|
||||
},
|
||||
message_race_limits::{MessageRaceLimits, RelayMessagesBatchReference},
|
||||
message_race_loop::{
|
||||
MessageRace, NoncesRange, RaceState, RaceStrategy, SourceClient, SourceClientNonces,
|
||||
TargetClient, TargetClientNonces,
|
||||
},
|
||||
message_race_strategy::BasicStrategy,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
relay_strategy::{EnforcementStrategy, RelayMessagesBatchReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// Run message delivery race.
|
||||
pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
pub async fn run<P: MessageLane>(
|
||||
source_client: impl MessageLaneSourceClient<P>,
|
||||
source_state_updates: impl FusedStream<Item = SourceClientState<P>>,
|
||||
target_client: impl MessageLaneTargetClient<P>,
|
||||
target_state_updates: impl FusedStream<Item = TargetClientState<P>>,
|
||||
metrics_msg: Option<MessageLaneLoopMetrics>,
|
||||
params: MessageDeliveryParams<Strategy>,
|
||||
params: MessageDeliveryParams,
|
||||
) -> Result<(), FailedClient> {
|
||||
crate::message_race_loop::run(
|
||||
MessageDeliveryRaceSource {
|
||||
@@ -59,7 +59,7 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
_phantom: Default::default(),
|
||||
},
|
||||
target_state_updates,
|
||||
MessageDeliveryStrategy::<P, Strategy, _, _> {
|
||||
MessageDeliveryStrategy::<P, _, _> {
|
||||
lane_source_client: source_client,
|
||||
lane_target_client: target_client,
|
||||
max_unrewarded_relayer_entries_at_target: params
|
||||
@@ -68,7 +68,6 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
|
||||
max_messages_in_single_batch: params.max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch: params.max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch: params.max_messages_size_in_single_batch,
|
||||
relay_strategy: params.relay_strategy,
|
||||
latest_confirmed_nonces_at_source: VecDeque::new(),
|
||||
target_nonces: None,
|
||||
strategy: BasicStrategy::new(),
|
||||
@@ -231,7 +230,7 @@ struct DeliveryRaceTargetNoncesData {
|
||||
}
|
||||
|
||||
/// Messages delivery strategy.
|
||||
struct MessageDeliveryStrategy<P: MessageLane, Strategy: RelayStrategy, SC, TC> {
|
||||
struct MessageDeliveryStrategy<P: MessageLane, SC, TC> {
|
||||
/// The client that is connected to the message lane source node.
|
||||
lane_source_client: SC,
|
||||
/// The client that is connected to the message lane target node.
|
||||
@@ -246,8 +245,6 @@ struct MessageDeliveryStrategy<P: MessageLane, Strategy: RelayStrategy, SC, TC>
|
||||
max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal messages size in the single delivery transaction.
|
||||
max_messages_size_in_single_batch: u32,
|
||||
/// Relayer operating mode.
|
||||
relay_strategy: Strategy,
|
||||
/// Latest confirmed nonces at the source client + the header id where we have first met this
|
||||
/// nonce.
|
||||
latest_confirmed_nonces_at_source: VecDeque<(SourceHeaderIdOf<P>, MessageNonce)>,
|
||||
@@ -268,9 +265,7 @@ type MessageDeliveryStrategyBase<P> = BasicStrategy<
|
||||
<P as MessageLane>::MessagesProof,
|
||||
>;
|
||||
|
||||
impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> std::fmt::Debug
|
||||
for MessageDeliveryStrategy<P, Strategy, SC, TC>
|
||||
{
|
||||
impl<P: MessageLane, SC, TC> std::fmt::Debug for MessageDeliveryStrategy<P, SC, TC> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fmt.debug_struct("MessageDeliveryStrategy")
|
||||
.field(
|
||||
@@ -288,7 +283,7 @@ impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> std::fmt::Debug
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> MessageDeliveryStrategy<P, Strategy, SC, TC> {
|
||||
impl<P: MessageLane, SC, TC> MessageDeliveryStrategy<P, SC, TC> {
|
||||
/// Returns total weight of all undelivered messages.
|
||||
fn total_queued_dispatch_weight(&self) -> Weight {
|
||||
self.strategy
|
||||
@@ -300,9 +295,8 @@ impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> MessageDeliveryStrategy<P,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<P, Strategy: RelayStrategy, SC, TC>
|
||||
RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessagesProof>
|
||||
for MessageDeliveryStrategy<P, Strategy, SC, TC>
|
||||
impl<P, SC, TC> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessagesProof>
|
||||
for MessageDeliveryStrategy<P, SC, TC>
|
||||
where
|
||||
P: MessageLane,
|
||||
SC: MessageLaneSourceClient<P>,
|
||||
@@ -524,8 +518,7 @@ where
|
||||
metrics: self.metrics_msg.clone(),
|
||||
};
|
||||
|
||||
let mut strategy = EnforcementStrategy::new(self.relay_strategy.clone());
|
||||
let range_end = strategy.decide(reference).await?;
|
||||
let range_end = MessageRaceLimits::decide(reference).await?;
|
||||
|
||||
let range_begin = source_queue[0].1.begin();
|
||||
let selected_nonces = range_begin..=range_end;
|
||||
@@ -562,38 +555,27 @@ impl<SourceChainBalance: std::fmt::Debug> NoncesRange for MessageDetailsMap<Sour
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
|
||||
use crate::{
|
||||
message_lane_loop::{
|
||||
tests::{
|
||||
header_id, TestMessageLane, TestMessagesProof, TestSourceChainBalance,
|
||||
TestSourceClient, TestSourceHeaderId, TestTargetClient, TestTargetHeaderId,
|
||||
BASE_MESSAGE_DELIVERY_TRANSACTION_COST, CONFIRMATION_TRANSACTION_COST,
|
||||
},
|
||||
MessageDetails, RelayerMode,
|
||||
use crate::message_lane_loop::{
|
||||
tests::{
|
||||
header_id, TestMessageLane, TestMessagesProof, TestSourceChainBalance,
|
||||
TestSourceClient, TestSourceHeaderId, TestTargetClient, TestTargetHeaderId,
|
||||
},
|
||||
relay_strategy::MixStrategy,
|
||||
MessageDetails,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
const DEFAULT_DISPATCH_WEIGHT: Weight = Weight::from_ref_time(1);
|
||||
const DEFAULT_SIZE: u32 = 1;
|
||||
const DEFAULT_REWARD: TestSourceChainBalance = CONFIRMATION_TRANSACTION_COST +
|
||||
BASE_MESSAGE_DELIVERY_TRANSACTION_COST +
|
||||
DEFAULT_DISPATCH_WEIGHT.ref_time() +
|
||||
(DEFAULT_SIZE as TestSourceChainBalance);
|
||||
|
||||
type TestRaceState = RaceState<TestSourceHeaderId, TestTargetHeaderId, TestMessagesProof>;
|
||||
type TestStrategy =
|
||||
MessageDeliveryStrategy<TestMessageLane, MixStrategy, TestSourceClient, TestTargetClient>;
|
||||
MessageDeliveryStrategy<TestMessageLane, TestSourceClient, TestTargetClient>;
|
||||
|
||||
fn source_nonces(
|
||||
new_nonces: RangeInclusive<MessageNonce>,
|
||||
confirmed_nonce: MessageNonce,
|
||||
reward: TestSourceChainBalance,
|
||||
dispatch_fee_payment: DispatchFeePayment,
|
||||
) -> SourceClientNonces<MessageDetailsMap<TestSourceChainBalance>> {
|
||||
SourceClientNonces {
|
||||
new_nonces: new_nonces
|
||||
@@ -605,7 +587,6 @@ mod tests {
|
||||
dispatch_weight: DEFAULT_DISPATCH_WEIGHT,
|
||||
size: DEFAULT_SIZE,
|
||||
reward,
|
||||
dispatch_fee_payment,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -648,13 +629,11 @@ mod tests {
|
||||
},
|
||||
}),
|
||||
strategy: BasicStrategy::new(),
|
||||
relay_strategy: MixStrategy::new(RelayerMode::Altruistic),
|
||||
};
|
||||
|
||||
race_strategy.strategy.source_nonces_updated(
|
||||
header_id(1),
|
||||
source_nonces(20..=23, 19, DEFAULT_REWARD, DispatchFeePayment::AtSourceChain),
|
||||
);
|
||||
race_strategy
|
||||
.strategy
|
||||
.source_nonces_updated(header_id(1), source_nonces(20..=23, 19, 0));
|
||||
|
||||
let target_nonces = TargetClientNonces { latest_nonce: 19, nonces_data: () };
|
||||
race_strategy
|
||||
@@ -687,7 +666,6 @@ mod tests {
|
||||
dispatch_weight: Weight::from_ref_time(idx),
|
||||
size: idx as _,
|
||||
reward: idx as _,
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -978,83 +956,6 @@ mod tests {
|
||||
assert_eq!(strategy.required_source_header_at_target(&header_id(1)), Some(header_id(2)));
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn rational_relayer_is_delivering_messages_if_cost_is_equal_to_reward() {
|
||||
let (state, mut strategy) = prepare_strategy();
|
||||
strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
|
||||
|
||||
// so now we have:
|
||||
// - 20..=23 with reward = cost
|
||||
// => strategy shall select all 20..=23
|
||||
assert_eq!(
|
||||
strategy.select_nonces_to_deliver(state).await,
|
||||
Some(((20..=23), proof_parameters(false, 4)))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn rational_relayer_is_not_delivering_messages_if_cost_is_larger_than_reward() {
|
||||
let (mut state, mut strategy) = prepare_strategy();
|
||||
let nonces = source_nonces(
|
||||
24..=25,
|
||||
19,
|
||||
DEFAULT_REWARD - BASE_MESSAGE_DELIVERY_TRANSACTION_COST,
|
||||
DispatchFeePayment::AtSourceChain,
|
||||
);
|
||||
strategy.strategy.source_nonces_updated(header_id(2), nonces);
|
||||
state.best_finalized_source_header_id_at_best_target = Some(header_id(2));
|
||||
strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
|
||||
|
||||
// so now we have:
|
||||
// - 20..=23 with reward = cost
|
||||
// - 24..=25 with reward less than cost
|
||||
// => strategy shall only select 20..=23
|
||||
assert_eq!(
|
||||
strategy.select_nonces_to_deliver(state).await,
|
||||
Some(((20..=23), proof_parameters(false, 4)))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn rational_relayer_is_delivering_unpaid_messages() {
|
||||
async fn test_with_dispatch_fee_payment(
|
||||
dispatch_fee_payment: DispatchFeePayment,
|
||||
) -> Option<(RangeInclusive<MessageNonce>, MessageProofParameters)> {
|
||||
let (mut state, mut strategy) = prepare_strategy();
|
||||
let nonces = source_nonces(
|
||||
24..=24,
|
||||
19,
|
||||
DEFAULT_REWARD - DEFAULT_DISPATCH_WEIGHT.ref_time(),
|
||||
dispatch_fee_payment,
|
||||
);
|
||||
strategy.strategy.source_nonces_updated(header_id(2), nonces);
|
||||
state.best_finalized_source_header_id_at_best_target = Some(header_id(2));
|
||||
strategy.max_unrewarded_relayer_entries_at_target = 100;
|
||||
strategy.max_unconfirmed_nonces_at_target = 100;
|
||||
strategy.max_messages_in_single_batch = 100;
|
||||
strategy.max_messages_weight_in_single_batch = Weight::from_ref_time(100);
|
||||
strategy.max_messages_size_in_single_batch = 100;
|
||||
strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
|
||||
|
||||
// so now we have:
|
||||
// - 20..=23 with reward = cost
|
||||
// - 24..=24 with reward less than cost, but we're deducting `DEFAULT_DISPATCH_WEIGHT`
|
||||
// from the cost, so it should be fine;
|
||||
// => when MSG#24 fee is paid at the target chain, strategy shall select all 20..=24
|
||||
// => when MSG#25 fee is paid at the source chain, strategy shall only select 20..=23
|
||||
strategy.select_nonces_to_deliver(state).await
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
test_with_dispatch_fee_payment(DispatchFeePayment::AtTargetChain).await,
|
||||
Some(((20..=24), proof_parameters(false, 5)))
|
||||
);
|
||||
assert_eq!(
|
||||
test_with_dispatch_fee_payment(DispatchFeePayment::AtSourceChain).await,
|
||||
Some(((20..=23), proof_parameters(false, 4)))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn relayer_uses_flattened_view_of_the_source_queue_to_select_nonces() {
|
||||
// Real scenario that has happened on test deployments:
|
||||
@@ -1066,7 +967,7 @@ mod tests {
|
||||
// This was happening because selector (`select_nonces_for_delivery_transaction`) has been
|
||||
// called for every `source_queue` entry separately without preserving any context.
|
||||
let (mut state, mut strategy) = prepare_strategy();
|
||||
let nonces = source_nonces(24..=25, 19, DEFAULT_REWARD, DispatchFeePayment::AtSourceChain);
|
||||
let nonces = source_nonces(24..=25, 19, 0);
|
||||
strategy.strategy.source_nonces_updated(header_id(2), nonces);
|
||||
strategy.max_unrewarded_relayer_entries_at_target = 100;
|
||||
strategy.max_unconfirmed_nonces_at_target = 100;
|
||||
|
||||
+61
-85
@@ -17,43 +17,88 @@
|
||||
//! enforcement strategy
|
||||
|
||||
use num_traits::Zero;
|
||||
use std::ops::Range;
|
||||
|
||||
use bp_messages::{MessageNonce, Weight};
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
MessageDetails, SourceClient as MessageLaneSourceClient,
|
||||
MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient,
|
||||
TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
message_race_loop::NoncesRange,
|
||||
relay_strategy::{RelayMessagesBatchReference, RelayReference, RelayStrategy},
|
||||
message_race_strategy::SourceRangesQueue,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
};
|
||||
|
||||
/// Do hard check and run soft check strategy
|
||||
/// Reference data for participating in relay
|
||||
pub struct RelayReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Messages size summary
|
||||
pub selected_size: u32,
|
||||
|
||||
/// Hard check begin nonce
|
||||
pub hard_selected_begin_nonce: MessageNonce,
|
||||
|
||||
/// Index by all ready nonces
|
||||
pub index: usize,
|
||||
/// Current nonce
|
||||
pub nonce: MessageNonce,
|
||||
/// Current nonce details
|
||||
pub details: MessageDetails<P::SourceChainBalance>,
|
||||
}
|
||||
|
||||
/// Relay reference data
|
||||
pub struct RelayMessagesBatchReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// Maximal number of relayed messages in single delivery transaction.
|
||||
pub max_messages_in_this_batch: MessageNonce,
|
||||
/// Maximal cumulative dispatch weight of relayed messages in single delivery transaction.
|
||||
pub max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal cumulative size of relayed messages in single delivery transaction.
|
||||
pub max_messages_size_in_single_batch: u32,
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Source queue.
|
||||
pub nonces_queue: SourceRangesQueue<
|
||||
P::SourceHeaderHash,
|
||||
P::SourceHeaderNumber,
|
||||
MessageDetailsMap<P::SourceChainBalance>,
|
||||
>,
|
||||
/// Source queue range
|
||||
pub nonces_queue_range: Range<usize>,
|
||||
}
|
||||
|
||||
/// Limits of the message race transactions.
|
||||
#[derive(Clone)]
|
||||
pub struct EnforcementStrategy<Strategy: RelayStrategy> {
|
||||
strategy: Strategy,
|
||||
}
|
||||
pub struct MessageRaceLimits;
|
||||
|
||||
impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
pub fn new(strategy: Strategy) -> Self {
|
||||
Self { strategy }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
impl MessageRaceLimits {
|
||||
pub async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: RelayMessagesBatchReference<P, SourceClient, TargetClient>,
|
||||
) -> Option<MessageNonce> {
|
||||
let mut hard_selected_count = 0;
|
||||
let mut soft_selected_count = 0;
|
||||
|
||||
let mut selected_weight = Weight::zero();
|
||||
let mut selected_count: MessageNonce = 0;
|
||||
@@ -67,17 +112,9 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
lane_target_client: reference.lane_target_client.clone(),
|
||||
metrics: reference.metrics.clone(),
|
||||
|
||||
selected_reward: P::SourceChainBalance::zero(),
|
||||
selected_cost: P::SourceChainBalance::zero(),
|
||||
selected_size: 0,
|
||||
|
||||
total_reward: P::SourceChainBalance::zero(),
|
||||
total_confirmations_cost: P::SourceChainBalance::zero(),
|
||||
total_cost: P::SourceChainBalance::zero(),
|
||||
|
||||
hard_selected_begin_nonce,
|
||||
selected_prepaid_nonces: 0,
|
||||
selected_unpaid_weight: Weight::zero(),
|
||||
|
||||
index: 0,
|
||||
nonce: 0,
|
||||
@@ -85,7 +122,6 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
dispatch_weight: Weight::zero(),
|
||||
size: 0,
|
||||
reward: P::SourceChainBalance::zero(),
|
||||
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -148,74 +184,14 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
|
||||
}
|
||||
relay_reference.selected_size = new_selected_size;
|
||||
|
||||
// If dispatch fee has been paid at the source chain, it means that it is **relayer**
|
||||
// who's paying for dispatch at the target chain AND reward must cover this dispatch
|
||||
// fee.
|
||||
//
|
||||
// If dispatch fee is paid at the target chain, it means that it'll be withdrawn from
|
||||
// the dispatch origin account AND reward is not covering this fee.
|
||||
//
|
||||
// So in the latter case we're not adding the dispatch weight to the delivery
|
||||
// transaction weight.
|
||||
let mut new_selected_prepaid_nonces = relay_reference.selected_prepaid_nonces;
|
||||
let new_selected_unpaid_weight = match details.dispatch_fee_payment {
|
||||
DispatchFeePayment::AtSourceChain => {
|
||||
new_selected_prepaid_nonces += 1;
|
||||
relay_reference.selected_unpaid_weight.saturating_add(details.dispatch_weight)
|
||||
},
|
||||
DispatchFeePayment::AtTargetChain => relay_reference.selected_unpaid_weight,
|
||||
};
|
||||
relay_reference.selected_prepaid_nonces = new_selected_prepaid_nonces;
|
||||
relay_reference.selected_unpaid_weight = new_selected_unpaid_weight;
|
||||
|
||||
// now the message has passed all 'strong' checks, and we CAN deliver it. But do we WANT
|
||||
// to deliver it? It depends on the relayer strategy.
|
||||
if self.strategy.decide(&mut relay_reference).await {
|
||||
soft_selected_count = index + 1;
|
||||
}
|
||||
|
||||
hard_selected_count = index + 1;
|
||||
selected_weight = new_selected_weight;
|
||||
selected_count = new_selected_count;
|
||||
}
|
||||
|
||||
if hard_selected_count != soft_selected_count {
|
||||
let hard_selected_end_nonce =
|
||||
hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
|
||||
let soft_selected_begin_nonce = hard_selected_begin_nonce;
|
||||
let soft_selected_end_nonce =
|
||||
soft_selected_begin_nonce + soft_selected_count as MessageNonce - 1;
|
||||
log::warn!(
|
||||
target: "bridge",
|
||||
"Relayer may deliver nonces [{:?}; {:?}], but because of its strategy it has selected \
|
||||
nonces [{:?}; {:?}].",
|
||||
hard_selected_begin_nonce,
|
||||
hard_selected_end_nonce,
|
||||
soft_selected_begin_nonce,
|
||||
soft_selected_end_nonce,
|
||||
);
|
||||
|
||||
hard_selected_count = soft_selected_count;
|
||||
}
|
||||
|
||||
if hard_selected_count != 0 {
|
||||
if relay_reference.selected_reward != P::SourceChainBalance::zero() &&
|
||||
relay_reference.selected_cost != P::SourceChainBalance::zero()
|
||||
{
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Expected reward from delivering nonces [{:?}; {:?}] is: {:?} - {:?} = {:?}",
|
||||
hard_selected_begin_nonce,
|
||||
hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1,
|
||||
&relay_reference.selected_reward,
|
||||
&relay_reference.selected_cost,
|
||||
relay_reference.selected_reward - relay_reference.selected_cost,
|
||||
);
|
||||
}
|
||||
|
||||
let selected_max_nonce =
|
||||
hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
|
||||
self.strategy.on_final_decision(&relay_reference);
|
||||
Some(selected_max_nonce)
|
||||
} else {
|
||||
None
|
||||
@@ -24,7 +24,7 @@ use crate::{
|
||||
use bp_messages::MessageNonce;
|
||||
use finality_relay::SyncLoopMetrics;
|
||||
use relay_utils::metrics::{
|
||||
metric_name, register, Counter, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
|
||||
metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
|
||||
};
|
||||
|
||||
/// Message lane relay metrics.
|
||||
@@ -39,17 +39,11 @@ pub struct MessageLaneLoopMetrics {
|
||||
/// Lane state nonces: "source_latest_generated", "source_latest_confirmed",
|
||||
/// "target_latest_received", "target_latest_confirmed".
|
||||
lane_state_nonces: GaugeVec<U64>,
|
||||
/// Count of unprofitable message delivery transactions that we have submitted so far.
|
||||
unprofitable_delivery_transactions: Counter<U64>,
|
||||
}
|
||||
|
||||
impl MessageLaneLoopMetrics {
|
||||
/// Create and register messages loop metrics.
|
||||
pub fn new(
|
||||
prefix: Option<&str>,
|
||||
source_name: &str,
|
||||
target_name: &str,
|
||||
) -> Result<Self, PrometheusError> {
|
||||
pub fn new(prefix: Option<&str>) -> Result<Self, PrometheusError> {
|
||||
Ok(MessageLaneLoopMetrics {
|
||||
source_to_target_finality_metrics: SyncLoopMetrics::new(
|
||||
prefix,
|
||||
@@ -65,13 +59,6 @@ impl MessageLaneLoopMetrics {
|
||||
Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"),
|
||||
&["type"],
|
||||
)?,
|
||||
unprofitable_delivery_transactions: Counter::new(
|
||||
metric_name(prefix, "unprofitable_delivery_transactions"),
|
||||
format!(
|
||||
"Count of unprofitable message delivery transactions from {} to {}",
|
||||
source_name, target_name
|
||||
),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -140,11 +127,6 @@ impl MessageLaneLoopMetrics {
|
||||
.with_label_values(&["target_latest_confirmed"])
|
||||
.set(target_latest_confirmed_nonce);
|
||||
}
|
||||
|
||||
/// Note unprofitable delivery transaction.
|
||||
pub fn note_unprofitable_delivery_transactions(&self) {
|
||||
self.unprofitable_delivery_transactions.inc()
|
||||
}
|
||||
}
|
||||
|
||||
impl Metric for MessageLaneLoopMetrics {
|
||||
@@ -152,7 +134,6 @@ impl Metric for MessageLaneLoopMetrics {
|
||||
self.source_to_target_finality_metrics.register(registry)?;
|
||||
self.target_to_source_finality_metrics.register(registry)?;
|
||||
register(self.lane_state_nonces.clone(), registry)?;
|
||||
register(self.unprofitable_delivery_transactions.clone(), registry)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Altruistic relay strategy
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
SourceClient as MessageLaneSourceClient, TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
relay_strategy::{RelayReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// The relayer doesn't care about rewards.
|
||||
#[derive(Clone)]
|
||||
pub struct AltruisticStrategy;
|
||||
|
||||
#[async_trait]
|
||||
impl RelayStrategy for AltruisticStrategy {
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool {
|
||||
// We don't care about costs and rewards, but we want to report unprofitable transactions.
|
||||
if let Err(e) = reference.update_cost_and_reward().await {
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Failed to update transaction cost and reward: {:?}. \
|
||||
The `unprofitable_delivery_transactions` metric will be inaccurate",
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
) {
|
||||
if let Some(ref metrics) = reference.metrics {
|
||||
if !reference.is_profitable() {
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"The relayer has submitted unprofitable {} -> {} message delivery transaction \
|
||||
with {} messages: total cost = {:?}, total reward = {:?}",
|
||||
P::SOURCE_NAME,
|
||||
P::TARGET_NAME,
|
||||
reference.index + 1,
|
||||
reference.total_cost,
|
||||
reference.total_reward,
|
||||
);
|
||||
|
||||
metrics.note_unprofitable_delivery_transactions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Adapter for using `enum RelayerMode` in a context which requires `RelayStrategy`.
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
RelayerMode, SourceClient as MessageLaneSourceClient,
|
||||
TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
relay_strategy::{AltruisticStrategy, RationalStrategy, RelayReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// `RelayerMode` adapter.
|
||||
#[derive(Clone)]
|
||||
pub struct MixStrategy {
|
||||
relayer_mode: RelayerMode,
|
||||
}
|
||||
|
||||
impl MixStrategy {
|
||||
/// Create mix strategy instance
|
||||
pub fn new(relayer_mode: RelayerMode) -> Self {
|
||||
Self { relayer_mode }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RelayStrategy for MixStrategy {
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool {
|
||||
match self.relayer_mode {
|
||||
RelayerMode::Altruistic => AltruisticStrategy.decide(reference).await,
|
||||
RelayerMode::Rational => RationalStrategy.decide(reference).await,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
) {
|
||||
match self.relayer_mode {
|
||||
RelayerMode::Altruistic => AltruisticStrategy.on_final_decision(reference),
|
||||
RelayerMode::Rational => RationalStrategy.on_final_decision(reference),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Relayer strategy
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_messages::{MessageNonce, Weight};
|
||||
use sp_arithmetic::traits::Saturating;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient,
|
||||
TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
message_race_strategy::SourceRangesQueue,
|
||||
metrics::MessageLaneLoopMetrics,
|
||||
};
|
||||
|
||||
pub(crate) use self::enforcement_strategy::*;
|
||||
pub use self::{altruistic_strategy::*, mix_strategy::*, rational_strategy::*};
|
||||
|
||||
mod altruistic_strategy;
|
||||
mod enforcement_strategy;
|
||||
mod mix_strategy;
|
||||
mod rational_strategy;
|
||||
|
||||
/// Relayer strategy trait
|
||||
#[async_trait]
|
||||
pub trait RelayStrategy: 'static + Clone + Send + Sync {
|
||||
/// The relayer decide how to process nonce by reference.
|
||||
/// From given set of source nonces, that are ready to be delivered, select nonces
|
||||
/// to fit into single delivery transaction.
|
||||
///
|
||||
/// The function returns last nonce that must be delivered to the target chain.
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool;
|
||||
|
||||
/// Notification that the following maximal nonce has been selected for the delivery.
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
);
|
||||
}
|
||||
|
||||
/// Total cost of mesage delivery and confirmation.
|
||||
struct MessagesDeliveryCost<SourceChainBalance> {
|
||||
/// Cost of message delivery transaction.
|
||||
pub delivery_transaction_cost: SourceChainBalance,
|
||||
/// Cost of confirmation delivery transaction.
|
||||
pub confirmation_transaction_cost: SourceChainBalance,
|
||||
}
|
||||
|
||||
/// Reference data for participating in relay
|
||||
pub struct RelayReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Current block reward summary
|
||||
pub selected_reward: P::SourceChainBalance,
|
||||
/// Current block cost summary
|
||||
pub selected_cost: P::SourceChainBalance,
|
||||
/// Messages size summary
|
||||
pub selected_size: u32,
|
||||
|
||||
/// Current block reward summary
|
||||
pub total_reward: P::SourceChainBalance,
|
||||
/// All confirmations cost
|
||||
pub total_confirmations_cost: P::SourceChainBalance,
|
||||
/// Current block cost summary
|
||||
pub total_cost: P::SourceChainBalance,
|
||||
|
||||
/// Hard check begin nonce
|
||||
pub hard_selected_begin_nonce: MessageNonce,
|
||||
/// Count prepaid nonces
|
||||
pub selected_prepaid_nonces: MessageNonce,
|
||||
/// Unpaid nonces weight summary
|
||||
pub selected_unpaid_weight: Weight,
|
||||
|
||||
/// Index by all ready nonces
|
||||
pub index: usize,
|
||||
/// Current nonce
|
||||
pub nonce: MessageNonce,
|
||||
/// Current nonce details
|
||||
pub details: MessageDetails<P::SourceChainBalance>,
|
||||
}
|
||||
|
||||
impl<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> RelayReference<P, SourceClient, TargetClient>
|
||||
{
|
||||
/// Returns whether the current `RelayReference` is profitable.
|
||||
pub fn is_profitable(&self) -> bool {
|
||||
self.total_reward >= self.total_cost
|
||||
}
|
||||
|
||||
async fn estimate_messages_delivery_cost(
|
||||
&self,
|
||||
) -> Result<MessagesDeliveryCost<P::SourceChainBalance>, TargetClient::Error> {
|
||||
// technically, multiple confirmations will be delivered in a single transaction,
|
||||
// meaning less loses for relayer. But here we don't know the final relayer yet, so
|
||||
// we're adding a separate transaction for every message. Normally, this cost is covered
|
||||
// by the message sender. Probably reconsider this?
|
||||
let confirmation_transaction_cost =
|
||||
self.lane_source_client.estimate_confirmation_transaction().await;
|
||||
|
||||
let delivery_transaction_cost = self
|
||||
.lane_target_client
|
||||
.estimate_delivery_transaction_in_source_tokens(
|
||||
self.hard_selected_begin_nonce..=
|
||||
(self.hard_selected_begin_nonce + self.index as MessageNonce),
|
||||
self.selected_prepaid_nonces,
|
||||
self.selected_unpaid_weight,
|
||||
self.selected_size,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost })
|
||||
}
|
||||
|
||||
async fn update_cost_and_reward(&mut self) -> Result<(), TargetClient::Error> {
|
||||
let prev_is_profitable = self.is_profitable();
|
||||
let prev_total_cost = self.total_cost;
|
||||
let prev_total_reward = self.total_reward;
|
||||
|
||||
let MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost } =
|
||||
self.estimate_messages_delivery_cost().await?;
|
||||
self.total_confirmations_cost =
|
||||
self.total_confirmations_cost.saturating_add(confirmation_transaction_cost);
|
||||
self.total_reward = self.total_reward.saturating_add(self.details.reward);
|
||||
self.total_cost = self.total_confirmations_cost.saturating_add(delivery_transaction_cost);
|
||||
|
||||
if prev_is_profitable && !self.is_profitable() {
|
||||
// if it is the first message that makes reward less than cost, let's log it
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it larger than \
|
||||
total reward {:?}->{:?}",
|
||||
self.nonce,
|
||||
self.details.reward,
|
||||
prev_total_cost,
|
||||
self.total_cost,
|
||||
prev_total_reward,
|
||||
self.total_reward,
|
||||
);
|
||||
} else if !prev_is_profitable && self.is_profitable() {
|
||||
// if this message makes batch profitable again, let's log it
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it less than or \
|
||||
equal to the total reward {:?}->{:?} (again)",
|
||||
self.nonce,
|
||||
self.details.reward,
|
||||
prev_total_cost,
|
||||
self.total_cost,
|
||||
prev_total_reward,
|
||||
self.total_reward,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Relay reference data
|
||||
pub struct RelayMessagesBatchReference<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
> {
|
||||
/// Maximal number of relayed messages in single delivery transaction.
|
||||
pub max_messages_in_this_batch: MessageNonce,
|
||||
/// Maximal cumulative dispatch weight of relayed messages in single delivery transaction.
|
||||
pub max_messages_weight_in_single_batch: Weight,
|
||||
/// Maximal cumulative size of relayed messages in single delivery transaction.
|
||||
pub max_messages_size_in_single_batch: u32,
|
||||
/// The client that is connected to the message lane source node.
|
||||
pub lane_source_client: SourceClient,
|
||||
/// The client that is connected to the message lane target node.
|
||||
pub lane_target_client: TargetClient,
|
||||
/// Metrics reference.
|
||||
pub metrics: Option<MessageLaneLoopMetrics>,
|
||||
/// Source queue.
|
||||
pub nonces_queue: SourceRangesQueue<
|
||||
P::SourceHeaderHash,
|
||||
P::SourceHeaderNumber,
|
||||
MessageDetailsMap<P::SourceChainBalance>,
|
||||
>,
|
||||
/// Source queue range
|
||||
pub nonces_queue_range: Range<usize>,
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Rational relay strategy
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
message_lane::MessageLane,
|
||||
message_lane_loop::{
|
||||
SourceClient as MessageLaneSourceClient, TargetClient as MessageLaneTargetClient,
|
||||
},
|
||||
relay_strategy::{RelayReference, RelayStrategy},
|
||||
};
|
||||
|
||||
/// The relayer will deliver all messages and confirmations as long as he's not losing any
|
||||
/// funds.
|
||||
#[derive(Clone)]
|
||||
pub struct RationalStrategy;
|
||||
|
||||
#[async_trait]
|
||||
impl RelayStrategy for RationalStrategy {
|
||||
async fn decide<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&mut self,
|
||||
reference: &mut RelayReference<P, SourceClient, TargetClient>,
|
||||
) -> bool {
|
||||
if let Err(e) = reference.update_cost_and_reward().await {
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Failed to update transaction cost and reward: {:?}. No nonces selected for delivery",
|
||||
e,
|
||||
);
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Rational relayer never wants to lose his funds.
|
||||
if reference.is_profitable() {
|
||||
reference.selected_reward = reference.total_reward;
|
||||
reference.selected_cost = reference.total_cost;
|
||||
return true
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn on_final_decision<
|
||||
P: MessageLane,
|
||||
SourceClient: MessageLaneSourceClient<P>,
|
||||
TargetClient: MessageLaneTargetClient<P>,
|
||||
>(
|
||||
&self,
|
||||
_reference: &RelayReference<P, SourceClient, TargetClient>,
|
||||
) {
|
||||
// rational relayer would never submit unprofitable transactions, so we don't need to do
|
||||
// anything here
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user