diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index 953da9f4f0..f5ed359a60 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -87,9 +87,14 @@ pub const WITH_KUSAMA_GRANDPA_PALLET_NAME: &str = "BridgeKusamaGrandpa"; /// Name of the With-Kusama messages pallet instance that is deployed at bridged chains. pub const WITH_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessages"; +/// Name of the transaction payment pallet at the Kusama runtime. +pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment"; + /// Name of the DOT->KSM conversion rate stored in the Kusama runtime. pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = "PolkadotToKusamaConversionRate"; +/// Name of the Polkadot fee multiplier parameter, stored in the Polkadot runtime. +pub const POLKADOT_FEE_MULTIPLIER_PARAMETER_NAME: &str = "PolkadotFeeMultiplier"; /// Name of the `KusamaFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized"; diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index 02c201b720..2983e7f2ce 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -87,9 +87,14 @@ pub const WITH_POLKADOT_GRANDPA_PALLET_NAME: &str = "BridgePolkadotGrandpa"; /// Name of the With-Polkadot messages pallet instance that is deployed at bridged chains. pub const WITH_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotMessages"; -/// Name of the KSM->DOT conversion rate stored in the Polkadot runtime. +/// Name of the transaction payment pallet at the Polkadot runtime. +pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment"; + +/// Name of the KSM->DOT conversion rate parameter, stored in the Polkadot runtime. pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = "KusamaToPolkadotConversionRate"; +/// Name of the Kusama fee multiplier parameter, stored in the Polkadot runtime. +pub const KUSAMA_FEE_MULTIPLIER_PARAMETER_NAME: &str = "KusamaFeeMultiplier"; /// Name of the `PolkadotFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized"; diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index c01e7bb305..f69afca4c0 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -22,7 +22,7 @@ use codec::Encode; use frame_support::{RuntimeDebug, StorageHasher}; use sp_core::{hash::H256, storage::StorageKey}; use sp_io::hashing::blake2_256; -use sp_std::{convert::TryFrom, vec::Vec}; +use sp_std::{convert::TryFrom, vec, vec::Vec}; pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, @@ -229,7 +229,7 @@ pub fn storage_map_final_key( /// This is how a storage key of storage parameter (`parameter_types! { storage Param: bool = false; /// }`) is computed. /// -/// Copied from `frame_support::parameter_types` macro +/// Copied from `frame_support::parameter_types` macro. pub fn storage_parameter_key(parameter_name: &str) -> StorageKey { let mut buffer = Vec::with_capacity(1 + parameter_name.len() + 1); buffer.push(b':'); @@ -238,6 +238,20 @@ pub fn storage_parameter_key(parameter_name: &str) -> StorageKey { StorageKey(sp_io::hashing::twox_128(&buffer).to_vec()) } +/// This is how a storage key of storage value is computed. +/// +/// Copied from `frame_support::storage::storage_prefix`. +pub fn storage_value_key(pallet_prefix: &str, value_name: &str) -> StorageKey { + let pallet_hash = sp_io::hashing::twox_128(pallet_prefix.as_bytes()); + let storage_hash = sp_io::hashing::twox_128(value_name.as_bytes()); + + let mut final_key = vec![0u8; 32]; + final_key[..16].copy_from_slice(&pallet_hash); + final_key[16..].copy_from_slice(&storage_hash); + + StorageKey(final_key) +} + #[cfg(test)] mod tests { use super::*; @@ -249,4 +263,17 @@ mod tests { StorageKey(hex_literal::hex!("58942375551bb0af1682f72786b59d04").to_vec()), ); } + + #[test] + fn storage_value_key_works() { + assert_eq!( + storage_value_key("PalletTransactionPayment", "NextFeeMultiplier"), + StorageKey( + hex_literal::hex!( + "f0e954dfcca51a255ab12c60c789256a3f2edf3bdf381debe331ab7446addfdc" + ) + .to_vec() + ), + ); + } } diff --git a/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs b/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs index 82a3206b0d..5c0b91d8ff 100644 --- a/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs +++ b/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs @@ -48,6 +48,16 @@ impl SubstrateMessageLane for KusamaMessagesToPolkadot { const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = Some(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME); + const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_polkadot::KUSAMA_FEE_MULTIPLIER_PARAMETER_NAME); + const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_kusama::POLKADOT_FEE_MULTIPLIER_PARAMETER_NAME); + + const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_kusama::TRANSACTION_PAYMENT_PALLET_NAME); + const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_polkadot::TRANSACTION_PAYMENT_PALLET_NAME); + type SourceChain = Kusama; type TargetChain = Polkadot; diff --git a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs index a496602943..906141e2f2 100644 --- a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs +++ b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs @@ -38,6 +38,11 @@ impl SubstrateMessageLane for MillauMessagesToRialto { 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; diff --git a/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs b/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs index 5eeb0df3f1..65b1ce9b06 100644 --- a/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs +++ b/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs @@ -48,6 +48,16 @@ impl SubstrateMessageLane for PolkadotMessagesToKusama { const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = Some(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME); + const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_kusama::POLKADOT_FEE_MULTIPLIER_PARAMETER_NAME); + const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_polkadot::KUSAMA_FEE_MULTIPLIER_PARAMETER_NAME); + + const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_polkadot::TRANSACTION_PAYMENT_PALLET_NAME); + const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_kusama::TRANSACTION_PAYMENT_PALLET_NAME); + type SourceChain = Polkadot; type TargetChain = Kusama; diff --git a/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs b/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs index 4c7ad8e621..4a570050f4 100644 --- a/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs +++ b/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs @@ -38,6 +38,11 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { 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; diff --git a/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs b/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs index a85789bb1b..48e41d02da 100644 --- a/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs +++ b/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs @@ -42,6 +42,11 @@ impl SubstrateMessageLane for RococoMessagesToWococo { 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 = Rococo; type TargetChain = Wococo; diff --git a/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs b/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs index 7c599e4139..33d7d9adfc 100644 --- a/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs +++ b/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs @@ -43,6 +43,11 @@ impl SubstrateMessageLane for WococoMessagesToRococo { 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 = Wococo; type TargetChain = Rococo; diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index 5733e398f3..482aa8d947 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -47,6 +47,7 @@ bp-millau = { path = "../../primitives/chain-millau" } bp-rialto = { path = "../../primitives/chain-rialto" } bp-rococo = { path = "../../primitives/chain-rococo" } bp-wococo = { path = "../../primitives/chain-wococo" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } relay-rococo-client = { path = "../client-rococo" } relay-wococo-client = { path = "../client-wococo" } rialto-runtime = { path = "../../bin/rialto/runtime" } diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages_lane.rs index 380d1c9624..a88b9441cd 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_lane.rs @@ -43,19 +43,37 @@ 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 name. + /// 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 name. + /// 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; /// Messages from the `SourceChain` are dispatched on this chain. diff --git a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs b/bridges/relays/lib-substrate-relay/src/messages_metrics.rs index 00686ac4fd..9e303cebc1 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_metrics.rs @@ -34,6 +34,9 @@ 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 { @@ -53,6 +56,15 @@ pub struct StandaloneMessagesMetrics { /// Target tokens to source tokens conversion rate metric. This rate is stored by the source /// chain. pub target_to_source_conversion_rate: Option>, + + /// Actual source chain fee multiplier. + pub source_fee_multiplier: Option>, + /// Source chain fee multiplier, stored at the target chain. + pub source_fee_multiplier_at_target: Option>, + /// Actual target chain fee multiplier. + pub target_fee_multiplier: Option>, + /// Target chain fee multiplier, stored at the target chain. + pub target_fee_multiplier_at_source: Option>, } impl StandaloneMessagesMetrics { @@ -66,6 +78,10 @@ impl StandaloneMessagesMetrics { 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, } } @@ -86,6 +102,18 @@ impl StandaloneMessagesMetrics { 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) } @@ -144,7 +172,7 @@ pub fn standalone_metrics( .map(|key| { FloatStorageValueMetric::new( FixedU128OrOne::default(), - target_client, + target_client.clone(), key, format!( "{}_{}_to_{}_conversion_rate", @@ -167,7 +195,7 @@ pub fn standalone_metrics( .map(|key| { FloatStorageValueMetric::new( FixedU128OrOne::default(), - source_client, + source_client.clone(), key, format!( "{}_{}_to_{}_conversion_rate", @@ -185,6 +213,68 @@ pub fn standalone_metrics( .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))?, }) } @@ -286,6 +376,8 @@ 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; #[async_std::test] async fn target_to_source_conversion_rate_works() { @@ -302,4 +394,12 @@ 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::::storage_value_final_key().to_vec()), + ); + } }