Message lane pallet parameters + updatable conversion rate (#728)

* message lane pallet parameters

* updated comment

* Update modules/message-lane/src/lib.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* fmt

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
Svyatoslav Nikolsky
2021-02-18 10:15:12 +03:00
committed by Bastian Köcher
parent e8b5a53eed
commit 1bf2eb1ab5
7 changed files with 211 additions and 14 deletions
+1
View File
@@ -336,6 +336,7 @@ impl pallet_message_lane::Config for Runtime {
type Event = Event; type Event = Event;
// TODO: https://github.com/paritytech/parity-bridges-common/issues/390 // TODO: https://github.com/paritytech/parity-bridges-common/issues/390
type WeightInfo = pallet_message_lane::weights::RialtoWeight<Runtime>; type WeightInfo = pallet_message_lane::weights::RialtoWeight<Runtime>;
type Parameter = rialto_messages::MillauToRialtoMessageLaneParameter;
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
@@ -21,17 +21,25 @@ use crate::Runtime;
use bp_message_lane::{ use bp_message_lane::{
source_chain::TargetHeaderChain, source_chain::TargetHeaderChain,
target_chain::{ProvedMessages, SourceHeaderChain}, target_chain::{ProvedMessages, SourceHeaderChain},
InboundLaneData, LaneId, Message, MessageNonce, InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessageLaneParameter,
}; };
use bp_runtime::{InstanceId, RIALTO_BRIDGE_INSTANCE}; use bp_runtime::{InstanceId, RIALTO_BRIDGE_INSTANCE};
use bridge_runtime_common::messages::{self, ChainWithMessageLanes, MessageBridge}; use bridge_runtime_common::messages::{self, ChainWithMessageLanes, MessageBridge};
use codec::{Decode, Encode};
use frame_support::{ use frame_support::{
parameter_types,
weights::{DispatchClass, Weight, WeightToFeePolynomial}, weights::{DispatchClass, Weight, WeightToFeePolynomial},
RuntimeDebug, RuntimeDebug,
}; };
use sp_core::storage::StorageKey; use sp_core::storage::StorageKey;
use sp_runtime::{FixedPointNumber, FixedU128};
use sp_std::{convert::TryFrom, ops::RangeInclusive}; use sp_std::{convert::TryFrom, ops::RangeInclusive};
parameter_types! {
/// Rialto to Millau conversion rate. Initially we treat both tokens as equal.
storage RialtoToMillauConversionRate: FixedU128 = 1.into();
}
/// Storage key of the Millau -> Rialto message in the runtime storage. /// Storage key of the Millau -> Rialto message in the runtime storage.
pub fn message_key(lane: &LaneId, nonce: MessageNonce) -> StorageKey { pub fn message_key(lane: &LaneId, nonce: MessageNonce) -> StorageKey {
pallet_message_lane::storage_keys::message_key::<Runtime, <Millau as ChainWithMessageLanes>::MessageLaneInstance>( pallet_message_lane::storage_keys::message_key::<Runtime, <Millau as ChainWithMessageLanes>::MessageLaneInstance>(
@@ -145,8 +153,8 @@ impl MessageBridge for WithRialtoMessageBridge {
} }
fn bridged_balance_to_this_balance(bridged_balance: bp_rialto::Balance) -> bp_millau::Balance { fn bridged_balance_to_this_balance(bridged_balance: bp_rialto::Balance) -> bp_millau::Balance {
// 1:1 conversion that will probably change in the future bp_millau::Balance::try_from(RialtoToMillauConversionRate::get().saturating_mul_int(bridged_balance))
bridged_balance as _ .unwrap_or(bp_millau::Balance::MAX)
} }
} }
@@ -227,3 +235,20 @@ impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
messages::target::verify_messages_proof::<WithRialtoMessageBridge, Runtime>(proof, messages_count) messages::target::verify_messages_proof::<WithRialtoMessageBridge, Runtime>(proof, messages_count)
} }
} }
/// Millau -> Rialto message lane pallet parameters.
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum MillauToRialtoMessageLaneParameter {
/// The conversion formula we use is: `MillauTokens = RialtoTokens * conversion_rate`.
RialtoToMillauConversionRate(FixedU128),
}
impl MessageLaneParameter for MillauToRialtoMessageLaneParameter {
fn save(&self) {
match *self {
MillauToRialtoMessageLaneParameter::RialtoToMillauConversionRate(ref conversion_rate) => {
RialtoToMillauConversionRate::set(conversion_rate)
}
}
}
}
+1
View File
@@ -443,6 +443,7 @@ pub(crate) type WithMillauMessageLaneInstance = pallet_message_lane::DefaultInst
impl pallet_message_lane::Config for Runtime { impl pallet_message_lane::Config for Runtime {
type Event = Event; type Event = Event;
type WeightInfo = pallet_message_lane::weights::RialtoWeight<Runtime>; type WeightInfo = pallet_message_lane::weights::RialtoWeight<Runtime>;
type Parameter = millau_messages::RialtoToMillauMessageLaneParameter;
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
@@ -21,17 +21,25 @@ use crate::Runtime;
use bp_message_lane::{ use bp_message_lane::{
source_chain::TargetHeaderChain, source_chain::TargetHeaderChain,
target_chain::{ProvedMessages, SourceHeaderChain}, target_chain::{ProvedMessages, SourceHeaderChain},
InboundLaneData, LaneId, Message, MessageNonce, InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessageLaneParameter,
}; };
use bp_runtime::{InstanceId, MILLAU_BRIDGE_INSTANCE}; use bp_runtime::{InstanceId, MILLAU_BRIDGE_INSTANCE};
use bridge_runtime_common::messages::{self, ChainWithMessageLanes, MessageBridge}; use bridge_runtime_common::messages::{self, ChainWithMessageLanes, MessageBridge};
use codec::{Decode, Encode};
use frame_support::{ use frame_support::{
parameter_types,
weights::{DispatchClass, Weight, WeightToFeePolynomial}, weights::{DispatchClass, Weight, WeightToFeePolynomial},
RuntimeDebug, RuntimeDebug,
}; };
use sp_core::storage::StorageKey; use sp_core::storage::StorageKey;
use sp_runtime::{FixedPointNumber, FixedU128};
use sp_std::{convert::TryFrom, ops::RangeInclusive}; use sp_std::{convert::TryFrom, ops::RangeInclusive};
parameter_types! {
/// Millau to Rialto conversion rate. Initially we treat both tokens as equal.
storage MillauToRialtoConversionRate: FixedU128 = 1.into();
}
/// Storage key of the Rialto -> Millau message in the runtime storage. /// Storage key of the Rialto -> Millau message in the runtime storage.
pub fn message_key(lane: &LaneId, nonce: MessageNonce) -> StorageKey { pub fn message_key(lane: &LaneId, nonce: MessageNonce) -> StorageKey {
pallet_message_lane::storage_keys::message_key::<Runtime, <Rialto as ChainWithMessageLanes>::MessageLaneInstance>( pallet_message_lane::storage_keys::message_key::<Runtime, <Rialto as ChainWithMessageLanes>::MessageLaneInstance>(
@@ -145,8 +153,8 @@ impl MessageBridge for WithMillauMessageBridge {
} }
fn bridged_balance_to_this_balance(bridged_balance: bp_millau::Balance) -> bp_rialto::Balance { fn bridged_balance_to_this_balance(bridged_balance: bp_millau::Balance) -> bp_rialto::Balance {
// 1:1 conversion that will probably change in the future bp_rialto::Balance::try_from(MillauToRialtoConversionRate::get().saturating_mul_int(bridged_balance))
bridged_balance as _ .unwrap_or(bp_rialto::Balance::MAX)
} }
} }
@@ -227,3 +235,20 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
messages::target::verify_messages_proof::<WithMillauMessageBridge, Runtime>(proof, messages_count) messages::target::verify_messages_proof::<WithMillauMessageBridge, Runtime>(proof, messages_count)
} }
} }
/// Rialto -> Millau message lane pallet parameters.
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum RialtoToMillauMessageLaneParameter {
/// The conversion formula we use is: `RialtoTokens = MillauTokens * conversion_rate`.
MillauToRialtoConversionRate(FixedU128),
}
impl MessageLaneParameter for RialtoToMillauMessageLaneParameter {
fn save(&self) {
match *self {
RialtoToMillauMessageLaneParameter::MillauToRialtoConversionRate(ref conversion_rate) => {
MillauToRialtoConversionRate::set(conversion_rate)
}
}
}
}
+128 -7
View File
@@ -48,7 +48,7 @@ use bp_message_lane::{
source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, RelayersRewards, TargetHeaderChain}, source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, RelayersRewards, TargetHeaderChain},
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain}, target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain},
total_unrewarded_messages, InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, MessagePayload, total_unrewarded_messages, InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, MessagePayload,
OutboundLaneData, UnrewardedRelayersState, OutboundLaneData, Parameter as MessageLaneParameter, UnrewardedRelayersState,
}; };
use bp_runtime::Size; use bp_runtime::Size;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
@@ -84,6 +84,12 @@ pub trait Config<I = DefaultInstance>: frame_system::Config {
type Event: From<Event<Self, I>> + Into<<Self as frame_system::Config>::Event>; type Event: From<Event<Self, I>> + Into<<Self as frame_system::Config>::Event>;
/// Benchmarks results from runtime we're plugged into. /// Benchmarks results from runtime we're plugged into.
type WeightInfo: WeightInfoExt; type WeightInfo: WeightInfoExt;
/// 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: MessageLaneParameter;
/// Maximal number of messages that may be pruned during maintenance. Maintenance occurs /// 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 /// whenever new message is sent. The reason is that if you want to use lane, you should
/// be ready to pay for its maintenance. /// be ready to pay for its maintenance.
@@ -211,9 +217,13 @@ decl_storage! {
} }
decl_event!( decl_event!(
pub enum Event<T, I = DefaultInstance> where pub enum Event<T, I = DefaultInstance>
<T as frame_system::Config>::AccountId, where
AccountId = <T as frame_system::Config>::AccountId,
Parameter = <T as Config<I>>::Parameter,
{ {
/// Pallet parameter has been updated.
ParameterUpdated(Parameter),
/// Message has been accepted and is waiting to be delivered. /// Message has been accepted and is waiting to be delivered.
MessageAccepted(LaneId, MessageNonce), MessageAccepted(LaneId, MessageNonce),
/// Messages in the inclusive range have been delivered and processed by the bridged chain. /// Messages in the inclusive range have been delivered and processed by the bridged chain.
@@ -274,6 +284,18 @@ decl_module! {
frame_support::debug::info!("Resuming pallet operations."); frame_support::debug::info!("Resuming pallet operations.");
} }
/// Update pallet parameter.
///
/// May only be called either by root, or by `ModuleOwner`.
///
/// The weight is: single read for permissions check + 2 writes for parameter value and event.
#[weight = (T::DbWeight::get().reads_writes(1, 2), DispatchClass::Operational)]
pub fn update_pallet_parameter(origin, parameter: T::Parameter) {
ensure_owner_or_root::<T, I>(origin)?;
parameter.save();
Self::deposit_event(RawEvent::ParameterUpdated(parameter));
}
/// Send message over lane. /// Send message over lane.
#[weight = T::WeightInfo::send_message_weight(payload)] #[weight = T::WeightInfo::send_message_weight(payload)]
pub fn send_message( pub fn send_message(
@@ -821,9 +843,9 @@ fn verify_and_decode_messages_proof<Chain: SourceHeaderChain<Fee>, Fee, Dispatch
mod tests { mod tests {
use super::*; use super::*;
use crate::mock::{ use crate::mock::{
message, run_test, Event as TestEvent, Origin, TestMessageDeliveryAndDispatchPayment, message, run_test, Event as TestEvent, Origin, TestMessageDeliveryAndDispatchPayment, TestMessageLaneParameter,
TestMessagesDeliveryProof, TestMessagesProof, TestPayload, TestRuntime, PAYLOAD_REJECTED_BY_TARGET_CHAIN, TestMessagesDeliveryProof, TestMessagesProof, TestPayload, TestRuntime, TokenConversionRate,
REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B,
}; };
use bp_message_lane::UnrewardedRelayersState; use bp_message_lane::UnrewardedRelayersState;
use frame_support::{assert_noop, assert_ok}; use frame_support::{assert_noop, assert_ok};
@@ -831,9 +853,13 @@ mod tests {
use hex_literal::hex; use hex_literal::hex;
use sp_runtime::DispatchError; use sp_runtime::DispatchError;
fn send_regular_message() { fn get_ready_for_events() {
System::<TestRuntime>::set_block_number(1); System::<TestRuntime>::set_block_number(1);
System::<TestRuntime>::reset_events(); System::<TestRuntime>::reset_events();
}
fn send_regular_message() {
get_ready_for_events();
assert_ok!(Module::<TestRuntime>::send_message( assert_ok!(Module::<TestRuntime>::send_message(
Origin::signed(1), Origin::signed(1),
@@ -940,6 +966,101 @@ mod tests {
}); });
} }
#[test]
fn pallet_parameter_may_be_updated_by_root() {
run_test(|| {
get_ready_for_events();
let parameter = TestMessageLaneParameter::TokenConversionRate(10.into());
assert_ok!(Module::<TestRuntime>::update_pallet_parameter(
Origin::root(),
parameter.clone(),
));
assert_eq!(TokenConversionRate::get(), 10.into());
assert_eq!(
System::<TestRuntime>::events(),
vec![EventRecord {
phase: Phase::Initialization,
event: TestEvent::pallet_message_lane(RawEvent::ParameterUpdated(parameter)),
topics: vec![],
}],
);
});
}
#[test]
fn pallet_parameter_may_be_updated_by_owner() {
run_test(|| {
ModuleOwner::<TestRuntime>::put(2);
get_ready_for_events();
let parameter = TestMessageLaneParameter::TokenConversionRate(10.into());
assert_ok!(Module::<TestRuntime>::update_pallet_parameter(
Origin::signed(2),
parameter.clone(),
));
assert_eq!(TokenConversionRate::get(), 10.into());
assert_eq!(
System::<TestRuntime>::events(),
vec![EventRecord {
phase: Phase::Initialization,
event: TestEvent::pallet_message_lane(RawEvent::ParameterUpdated(parameter)),
topics: vec![],
}],
);
});
}
#[test]
fn pallet_parameter_cant_be_updated_by_arbitrary_submitter() {
run_test(|| {
assert_noop!(
Module::<TestRuntime>::update_pallet_parameter(
Origin::signed(2),
TestMessageLaneParameter::TokenConversionRate(10.into()),
),
DispatchError::BadOrigin,
);
ModuleOwner::<TestRuntime>::put(2);
assert_noop!(
Module::<TestRuntime>::update_pallet_parameter(
Origin::signed(1),
TestMessageLaneParameter::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] #[test]
fn pallet_rejects_transactions_if_halted() { fn pallet_rejects_transactions_if_halted() {
run_test(|| { run_test(|| {
+19 -1
View File
@@ -25,6 +25,7 @@ use bp_message_lane::{
}, },
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain}, target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain},
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
Parameter as MessageLaneParameter,
}; };
use bp_runtime::Size; use bp_runtime::Size;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
@@ -33,7 +34,7 @@ use sp_core::H256;
use sp_runtime::{ use sp_runtime::{
testing::Header as SubstrateHeader, testing::Header as SubstrateHeader,
traits::{BlakeTwo256, IdentityLookup}, traits::{BlakeTwo256, IdentityLookup},
Perbill, FixedU128, Perbill,
}; };
use std::collections::BTreeMap; use std::collections::BTreeMap;
@@ -119,11 +120,28 @@ parameter_types! {
pub const MaxMessagesToPruneAtOnce: u64 = 10; pub const MaxMessagesToPruneAtOnce: u64 = 10;
pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16; pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16;
pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32; pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32;
pub storage TokenConversionRate: FixedU128 = 1.into();
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum TestMessageLaneParameter {
TokenConversionRate(FixedU128),
}
impl MessageLaneParameter for TestMessageLaneParameter {
fn save(&self) {
match *self {
TestMessageLaneParameter::TokenConversionRate(conversion_rate) => {
TokenConversionRate::set(&conversion_rate)
}
}
}
} }
impl Config for TestRuntime { impl Config for TestRuntime {
type Event = Event; type Event = Event;
type WeightInfo = (); type WeightInfo = ();
type Parameter = TestMessageLaneParameter;
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
@@ -32,6 +32,12 @@ pub mod target_chain;
// Weight is reexported to avoid additional frame-support dependencies in message-lane related crates. // Weight is reexported to avoid additional frame-support dependencies in message-lane related crates.
pub use frame_support::weights::Weight; pub use frame_support::weights::Weight;
/// Message lane pallet parameter.
pub trait Parameter: frame_support::Parameter {
/// Save parameter value in the runtime storage.
fn save(&self);
}
/// Lane identifier. /// Lane identifier.
pub type LaneId = [u8; 4]; pub type LaneId = [u8; 4];