mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Support dedicated lanes for pallets (#962)
* pass call origin to the message verifier * is_outbound_lane_enabled -> is_message_accepted * trait SenderOrigin * only accept messages from token swap pallet to token swap lane * tests for edge cases of pay_delivery_and_dispatch_fee * fixed origin verification * fmt * fix benchmarks compilation * fix TODO with None account and non-zero message fee (already covered by tests) * revert cargo fmt changes temporarily
This commit is contained in:
committed by
Bastian Köcher
parent
7b7b8baa60
commit
ed2a3082ef
@@ -456,10 +456,9 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
|
|||||||
type MessageDeliveryAndDispatchPayment =
|
type MessageDeliveryAndDispatchPayment =
|
||||||
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
|
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
|
||||||
Runtime,
|
Runtime,
|
||||||
(),
|
WithRialtoMessagesInstance,
|
||||||
pallet_balances::Pallet<Runtime>,
|
pallet_balances::Pallet<Runtime>,
|
||||||
GetDeliveryConfirmationTransactionFee,
|
GetDeliveryConfirmationTransactionFee,
|
||||||
RootAccountForPayments,
|
|
||||||
>;
|
>;
|
||||||
type OnMessageAccepted = ();
|
type OnMessageAccepted = ();
|
||||||
type OnDeliveryConfirmed =
|
type OnDeliveryConfirmed =
|
||||||
@@ -525,7 +524,7 @@ construct_runtime!(
|
|||||||
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
|
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
|
||||||
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
|
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
|
||||||
BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
|
BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
|
||||||
BridgeRialtoTokenSwap: pallet_bridge_token_swap::{Pallet, Call, Storage, Event<T>},
|
BridgeRialtoTokenSwap: pallet_bridge_token_swap::{Pallet, Call, Storage, Event<T>, Origin<T>},
|
||||||
|
|
||||||
// Westend bridge modules.
|
// Westend bridge modules.
|
||||||
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
|
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use crate::Runtime;
|
use crate::Runtime;
|
||||||
|
|
||||||
use bp_messages::{
|
use bp_messages::{
|
||||||
source_chain::TargetHeaderChain,
|
source_chain::{SenderOrigin, TargetHeaderChain},
|
||||||
target_chain::{ProvedMessages, SourceHeaderChain},
|
target_chain::{ProvedMessages, SourceHeaderChain},
|
||||||
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
||||||
};
|
};
|
||||||
@@ -116,12 +116,23 @@ impl messages::ChainWithMessages for Millau {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl messages::ThisChainWithMessages for Millau {
|
impl messages::ThisChainWithMessages for Millau {
|
||||||
|
type Origin = crate::Origin;
|
||||||
type Call = crate::Call;
|
type Call = crate::Call;
|
||||||
|
|
||||||
fn is_outbound_lane_enabled(lane: &LaneId) -> bool {
|
fn is_message_accepted(send_origin: &Self::Origin, lane: &LaneId) -> bool {
|
||||||
*lane == [0, 0, 0, 0] ||
|
// lanes 0x00000000 && 0x00000001 are accepting any paid messages, while
|
||||||
*lane == [0, 0, 0, 1] ||
|
// `TokenSwapMessageLane` only accepts messages from token swap pallet
|
||||||
*lane == crate::TokenSwapMessagesLane::get()
|
let token_swap_dedicated_lane = crate::TokenSwapMessagesLane::get();
|
||||||
|
match *lane {
|
||||||
|
[0, 0, 0, 0] | [0, 0, 0, 1] => send_origin.linked_account().is_some(),
|
||||||
|
_ if *lane == token_swap_dedicated_lane => matches!(
|
||||||
|
send_origin.caller,
|
||||||
|
crate::OriginCaller::BridgeRialtoTokenSwap(
|
||||||
|
pallet_bridge_token_swap::RawOrigin::TokenSwap { .. }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||||
@@ -277,6 +288,25 @@ impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SenderOrigin<crate::AccountId> for crate::Origin {
|
||||||
|
fn linked_account(&self) -> Option<crate::AccountId> {
|
||||||
|
match self.caller {
|
||||||
|
crate::OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) =>
|
||||||
|
Some(submitter.clone()),
|
||||||
|
crate::OriginCaller::system(frame_system::RawOrigin::Root) |
|
||||||
|
crate::OriginCaller::system(frame_system::RawOrigin::None) =>
|
||||||
|
crate::RootAccountForPayments::get(),
|
||||||
|
crate::OriginCaller::BridgeRialtoTokenSwap(
|
||||||
|
pallet_bridge_token_swap::RawOrigin::TokenSwap {
|
||||||
|
ref swap_account_at_this_chain,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => Some(swap_account_at_this_chain.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Millau -> Rialto message lane pallet parameters.
|
/// Millau -> Rialto message lane pallet parameters.
|
||||||
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||||
pub enum MillauToRialtoMessagesParameter {
|
pub enum MillauToRialtoMessagesParameter {
|
||||||
|
|||||||
@@ -457,10 +457,9 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
|
|||||||
type MessageDeliveryAndDispatchPayment =
|
type MessageDeliveryAndDispatchPayment =
|
||||||
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
|
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
|
||||||
Runtime,
|
Runtime,
|
||||||
(),
|
WithMillauMessagesInstance,
|
||||||
pallet_balances::Pallet<Runtime>,
|
pallet_balances::Pallet<Runtime>,
|
||||||
GetDeliveryConfirmationTransactionFee,
|
GetDeliveryConfirmationTransactionFee,
|
||||||
RootAccountForPayments,
|
|
||||||
>;
|
>;
|
||||||
type OnMessageAccepted = ();
|
type OnMessageAccepted = ();
|
||||||
type OnDeliveryConfirmed = ();
|
type OnDeliveryConfirmed = ();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use crate::Runtime;
|
use crate::Runtime;
|
||||||
|
|
||||||
use bp_messages::{
|
use bp_messages::{
|
||||||
source_chain::TargetHeaderChain,
|
source_chain::{SenderOrigin, TargetHeaderChain},
|
||||||
target_chain::{ProvedMessages, SourceHeaderChain},
|
target_chain::{ProvedMessages, SourceHeaderChain},
|
||||||
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
|
||||||
};
|
};
|
||||||
@@ -116,10 +116,11 @@ impl messages::ChainWithMessages for Rialto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl messages::ThisChainWithMessages for Rialto {
|
impl messages::ThisChainWithMessages for Rialto {
|
||||||
|
type Origin = crate::Origin;
|
||||||
type Call = crate::Call;
|
type Call = crate::Call;
|
||||||
|
|
||||||
fn is_outbound_lane_enabled(lane: &LaneId) -> bool {
|
fn is_message_accepted(send_origin: &Self::Origin, lane: &LaneId) -> bool {
|
||||||
*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1]
|
send_origin.linked_account().is_some() && (*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||||
@@ -275,6 +276,19 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SenderOrigin<crate::AccountId> for crate::Origin {
|
||||||
|
fn linked_account(&self) -> Option<crate::AccountId> {
|
||||||
|
match self.caller {
|
||||||
|
crate::OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) =>
|
||||||
|
Some(submitter.clone()),
|
||||||
|
crate::OriginCaller::system(frame_system::RawOrigin::Root) |
|
||||||
|
crate::OriginCaller::system(frame_system::RawOrigin::None) =>
|
||||||
|
crate::RootAccountForPayments::get(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Rialto -> Millau message lane pallet parameters.
|
/// Rialto -> Millau message lane pallet parameters.
|
||||||
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
|
||||||
pub enum RialtoToMillauMessagesParameter {
|
pub enum RialtoToMillauMessagesParameter {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ pallet-bridge-messages = { path = "../../modules/messages", default-features = f
|
|||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
|
|
||||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
||||||
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
@@ -45,6 +45,7 @@ std = [
|
|||||||
"bp-runtime/std",
|
"bp-runtime/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
"frame-system/std",
|
||||||
"hash-db/std",
|
"hash-db/std",
|
||||||
"pallet-bridge-dispatch/std",
|
"pallet-bridge-dispatch/std",
|
||||||
"pallet-bridge-grandpa/std",
|
"pallet-bridge-grandpa/std",
|
||||||
@@ -60,7 +61,6 @@ std = [
|
|||||||
]
|
]
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
"ed25519-dalek/u64_backend",
|
"ed25519-dalek/u64_backend",
|
||||||
"frame-system",
|
|
||||||
"pallet-balances",
|
"pallet-balances",
|
||||||
"pallet-bridge-grandpa/runtime-benchmarks",
|
"pallet-bridge-grandpa/runtime-benchmarks",
|
||||||
"pallet-bridge-messages/runtime-benchmarks",
|
"pallet-bridge-messages/runtime-benchmarks",
|
||||||
@@ -68,6 +68,5 @@ runtime-benchmarks = [
|
|||||||
"sp-version",
|
"sp-version",
|
||||||
]
|
]
|
||||||
integrity-test = [
|
integrity-test = [
|
||||||
"frame-system",
|
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -62,8 +62,11 @@ corresponding chain. There is single exception, though (it may be changed in the
|
|||||||
|
|
||||||
This trait represents this chain from bridge point of view. Let's review every method of this trait:
|
This trait represents this chain from bridge point of view. Let's review every method of this trait:
|
||||||
|
|
||||||
- `ThisChainWithMessages::is_outbound_lane_enabled`: is used to check whether given lane accepts
|
- `ThisChainWithMessages::is_message_accepted`: is used to check whether given lane accepts
|
||||||
outbound messages.
|
messages. The send-message origin is passed to the function, so you may e.g. verify that only
|
||||||
|
given pallet is able to send messages over selected lane. **IMPORTANT**: if you assume that the
|
||||||
|
message must be paid by the sender, you must ensure that the sender origin has linked the account
|
||||||
|
for paying message delivery and dispatch fee.
|
||||||
|
|
||||||
- `ThisChainWithMessages::maximal_pending_messages_at_outbound_lane`: you should return maximal
|
- `ThisChainWithMessages::maximal_pending_messages_at_outbound_lane`: you should return maximal
|
||||||
number of pending (undelivered) messages from this function. Returning small values would require
|
number of pending (undelivered) messages from this function. Returning small values would require
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
use bp_message_dispatch::MessageDispatch as _;
|
use bp_message_dispatch::MessageDispatch as _;
|
||||||
use bp_messages::{
|
use bp_messages::{
|
||||||
source_chain::{LaneMessageVerifier, Sender},
|
source_chain::LaneMessageVerifier,
|
||||||
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
|
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
|
||||||
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||||
};
|
};
|
||||||
@@ -111,11 +111,13 @@ pub struct MessageTransaction<Weight> {
|
|||||||
|
|
||||||
/// This chain that has `pallet-bridge-messages` and `dispatch` modules.
|
/// This chain that has `pallet-bridge-messages` and `dispatch` modules.
|
||||||
pub trait ThisChainWithMessages: ChainWithMessages {
|
pub trait ThisChainWithMessages: ChainWithMessages {
|
||||||
|
/// Call origin on the chain.
|
||||||
|
type Origin;
|
||||||
/// Call type on the chain.
|
/// Call type on the chain.
|
||||||
type Call: Encode + Decode;
|
type Call: Encode + Decode;
|
||||||
|
|
||||||
/// Are we accepting any messages to the given lane?
|
/// Do we accept message sent by given origin to given lane?
|
||||||
fn is_outbound_lane_enabled(lane: &LaneId) -> bool;
|
fn is_message_accepted(origin: &Self::Origin, lane: &LaneId) -> bool;
|
||||||
|
|
||||||
/// Maximal number of pending (not yet delivered) messages at This chain.
|
/// Maximal number of pending (not yet delivered) messages at This chain.
|
||||||
///
|
///
|
||||||
@@ -173,6 +175,8 @@ pub type SignatureOf<C> = <C as ChainWithMessages>::Signature;
|
|||||||
pub type WeightOf<C> = <C as ChainWithMessages>::Weight;
|
pub type WeightOf<C> = <C as ChainWithMessages>::Weight;
|
||||||
/// Type of balances that is used on the chain.
|
/// Type of balances that is used on the chain.
|
||||||
pub type BalanceOf<C> = <C as ChainWithMessages>::Balance;
|
pub type BalanceOf<C> = <C as ChainWithMessages>::Balance;
|
||||||
|
/// Type of origin that is used on the chain.
|
||||||
|
pub type OriginOf<C> = <C as ThisChainWithMessages>::Origin;
|
||||||
/// Type of call that is used on this chain.
|
/// Type of call that is used on this chain.
|
||||||
pub type CallOf<C> = <C as ThisChainWithMessages>::Call;
|
pub type CallOf<C> = <C as ThisChainWithMessages>::Call;
|
||||||
|
|
||||||
@@ -270,7 +274,8 @@ pub mod source {
|
|||||||
pub struct FromThisChainMessageVerifier<B>(PhantomData<B>);
|
pub struct FromThisChainMessageVerifier<B>(PhantomData<B>);
|
||||||
|
|
||||||
/// The error message returned from LaneMessageVerifier when outbound lane is disabled.
|
/// The error message returned from LaneMessageVerifier when outbound lane is disabled.
|
||||||
pub const OUTBOUND_LANE_DISABLED: &str = "The outbound message lane is disabled.";
|
pub const MESSAGE_REJECTED_BY_OUTBOUND_LANE: &str =
|
||||||
|
"The outbound message lane has rejected the message.";
|
||||||
/// The error message returned from LaneMessageVerifier when too many pending messages at the
|
/// The error message returned from LaneMessageVerifier when too many pending messages at the
|
||||||
/// lane.
|
/// lane.
|
||||||
pub const TOO_MANY_PENDING_MESSAGES: &str = "Too many pending messages at the lane.";
|
pub const TOO_MANY_PENDING_MESSAGES: &str = "Too many pending messages at the lane.";
|
||||||
@@ -281,26 +286,30 @@ pub mod source {
|
|||||||
|
|
||||||
impl<B>
|
impl<B>
|
||||||
LaneMessageVerifier<
|
LaneMessageVerifier<
|
||||||
|
OriginOf<ThisChain<B>>,
|
||||||
AccountIdOf<ThisChain<B>>,
|
AccountIdOf<ThisChain<B>>,
|
||||||
FromThisChainMessagePayload<B>,
|
FromThisChainMessagePayload<B>,
|
||||||
BalanceOf<ThisChain<B>>,
|
BalanceOf<ThisChain<B>>,
|
||||||
> for FromThisChainMessageVerifier<B>
|
> for FromThisChainMessageVerifier<B>
|
||||||
where
|
where
|
||||||
B: MessageBridge,
|
B: MessageBridge,
|
||||||
|
// matches requirements from the `frame_system::Config::Origin`
|
||||||
|
OriginOf<ThisChain<B>>: Clone
|
||||||
|
+ Into<Result<frame_system::RawOrigin<AccountIdOf<ThisChain<B>>>, OriginOf<ThisChain<B>>>>,
|
||||||
AccountIdOf<ThisChain<B>>: PartialEq + Clone,
|
AccountIdOf<ThisChain<B>>: PartialEq + Clone,
|
||||||
{
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn verify_message(
|
fn verify_message(
|
||||||
submitter: &Sender<AccountIdOf<ThisChain<B>>>,
|
submitter: &OriginOf<ThisChain<B>>,
|
||||||
delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
|
delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
|
||||||
lane: &LaneId,
|
lane: &LaneId,
|
||||||
lane_outbound_data: &OutboundLaneData,
|
lane_outbound_data: &OutboundLaneData,
|
||||||
payload: &FromThisChainMessagePayload<B>,
|
payload: &FromThisChainMessagePayload<B>,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
// reject message if lane is blocked
|
// reject message if lane is blocked
|
||||||
if !ThisChain::<B>::is_outbound_lane_enabled(lane) {
|
if !ThisChain::<B>::is_message_accepted(submitter, lane) {
|
||||||
return Err(OUTBOUND_LANE_DISABLED)
|
return Err(MESSAGE_REJECTED_BY_OUTBOUND_LANE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reject message if there are too many pending messages at this lane
|
// reject message if there are too many pending messages at this lane
|
||||||
@@ -314,8 +323,23 @@ pub mod source {
|
|||||||
|
|
||||||
// Do the dispatch-specific check. We assume that the target chain uses
|
// Do the dispatch-specific check. We assume that the target chain uses
|
||||||
// `Dispatch`, so we verify the message accordingly.
|
// `Dispatch`, so we verify the message accordingly.
|
||||||
pallet_bridge_dispatch::verify_message_origin(submitter, payload)
|
let raw_origin_or_err: Result<
|
||||||
.map_err(|_| BAD_ORIGIN)?;
|
frame_system::RawOrigin<AccountIdOf<ThisChain<B>>>,
|
||||||
|
OriginOf<ThisChain<B>>,
|
||||||
|
> = submitter.clone().into();
|
||||||
|
match raw_origin_or_err {
|
||||||
|
Ok(raw_origin) =>
|
||||||
|
pallet_bridge_dispatch::verify_message_origin(&raw_origin, payload)
|
||||||
|
.map(drop)
|
||||||
|
.map_err(|_| BAD_ORIGIN)?,
|
||||||
|
Err(_) => {
|
||||||
|
// so what it means that we've failed to convert origin to the
|
||||||
|
// `frame_system::RawOrigin`? now it means that the custom pallet origin has
|
||||||
|
// been used to send the message. Do we need to verify it? The answer is no,
|
||||||
|
// because pallet may craft any origin (e.g. root) && we can't verify whether it
|
||||||
|
// is valid, or not.
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::<B>(
|
let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::<B>(
|
||||||
payload,
|
payload,
|
||||||
@@ -854,6 +878,18 @@ mod tests {
|
|||||||
#[codec(index = 84)]
|
#[codec(index = 84)]
|
||||||
Mint,
|
Mint,
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct ThisChainOrigin(Result<frame_system::RawOrigin<ThisChainAccountId>, ()>);
|
||||||
|
|
||||||
|
impl From<ThisChainOrigin>
|
||||||
|
for Result<frame_system::RawOrigin<ThisChainAccountId>, ThisChainOrigin>
|
||||||
|
{
|
||||||
|
fn from(
|
||||||
|
origin: ThisChainOrigin,
|
||||||
|
) -> Result<frame_system::RawOrigin<ThisChainAccountId>, ThisChainOrigin> {
|
||||||
|
origin.clone().0.map_err(|_| origin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Decode, Encode)]
|
#[derive(Debug, PartialEq, Decode, Encode)]
|
||||||
struct BridgedChainAccountId(u32);
|
struct BridgedChainAccountId(u32);
|
||||||
@@ -863,6 +899,18 @@ mod tests {
|
|||||||
struct BridgedChainSignature(u32);
|
struct BridgedChainSignature(u32);
|
||||||
#[derive(Debug, PartialEq, Decode, Encode)]
|
#[derive(Debug, PartialEq, Decode, Encode)]
|
||||||
enum BridgedChainCall {}
|
enum BridgedChainCall {}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct BridgedChainOrigin;
|
||||||
|
|
||||||
|
impl From<BridgedChainOrigin>
|
||||||
|
for Result<frame_system::RawOrigin<BridgedChainAccountId>, BridgedChainOrigin>
|
||||||
|
{
|
||||||
|
fn from(
|
||||||
|
_origin: BridgedChainOrigin,
|
||||||
|
) -> Result<frame_system::RawOrigin<BridgedChainAccountId>, BridgedChainOrigin> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_wrapped_balance {
|
macro_rules! impl_wrapped_balance {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
@@ -940,9 +988,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ThisChainWithMessages for ThisChain {
|
impl ThisChainWithMessages for ThisChain {
|
||||||
|
type Origin = ThisChainOrigin;
|
||||||
type Call = ThisChainCall;
|
type Call = ThisChainCall;
|
||||||
|
|
||||||
fn is_outbound_lane_enabled(lane: &LaneId) -> bool {
|
fn is_message_accepted(_send_origin: &Self::Origin, lane: &LaneId) -> bool {
|
||||||
lane == TEST_LANE_ID
|
lane == TEST_LANE_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,9 +1049,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ThisChainWithMessages for BridgedChain {
|
impl ThisChainWithMessages for BridgedChain {
|
||||||
|
type Origin = BridgedChainOrigin;
|
||||||
type Call = BridgedChainCall;
|
type Call = BridgedChainCall;
|
||||||
|
|
||||||
fn is_outbound_lane_enabled(_lane: &LaneId) -> bool {
|
fn is_message_accepted(_send_origin: &Self::Origin, _lane: &LaneId) -> bool {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,7 +1191,7 @@ mod tests {
|
|||||||
// and now check that the verifier checks the fee
|
// and now check that the verifier checks the fee
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Root,
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||||
&ThisChainBalance(1),
|
&ThisChainBalance(1),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1150,7 +1200,7 @@ mod tests {
|
|||||||
Err(source::TOO_LOW_FEE)
|
Err(source::TOO_LOW_FEE)
|
||||||
);
|
);
|
||||||
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Root,
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1173,7 +1223,7 @@ mod tests {
|
|||||||
// and now check that the verifier checks the fee
|
// and now check that the verifier checks the fee
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Signed(ThisChainAccountId(0)),
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(0)))),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1183,7 +1233,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::None,
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::None)),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1192,7 +1242,7 @@ mod tests {
|
|||||||
Err(source::BAD_ORIGIN)
|
Err(source::BAD_ORIGIN)
|
||||||
);
|
);
|
||||||
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Root,
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1215,7 +1265,7 @@ mod tests {
|
|||||||
// and now check that the verifier checks the fee
|
// and now check that the verifier checks the fee
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Signed(ThisChainAccountId(0)),
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(0)))),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1224,7 +1274,7 @@ mod tests {
|
|||||||
Err(source::BAD_ORIGIN)
|
Err(source::BAD_ORIGIN)
|
||||||
);
|
);
|
||||||
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Signed(ThisChainAccountId(1)),
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(1)))),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
@@ -1237,13 +1287,13 @@ mod tests {
|
|||||||
fn message_is_rejected_when_sent_using_disabled_lane() {
|
fn message_is_rejected_when_sent_using_disabled_lane() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Root,
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
b"dsbl",
|
b"dsbl",
|
||||||
&test_lane_outbound_data(),
|
&test_lane_outbound_data(),
|
||||||
®ular_outbound_message_payload(),
|
®ular_outbound_message_payload(),
|
||||||
),
|
),
|
||||||
Err(source::OUTBOUND_LANE_DISABLED)
|
Err(source::MESSAGE_REJECTED_BY_OUTBOUND_LANE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1251,7 +1301,7 @@ mod tests {
|
|||||||
fn message_is_rejected_when_there_are_too_many_pending_messages_at_outbound_lane() {
|
fn message_is_rejected_when_there_are_too_many_pending_messages_at_outbound_lane() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
&Sender::Root,
|
&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
|
||||||
&ThisChainBalance(1_000_000),
|
&ThisChainBalance(1_000_000),
|
||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
&OutboundLaneData {
|
&OutboundLaneData {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
use crate::OutboundMessages;
|
use crate::OutboundMessages;
|
||||||
|
|
||||||
use bp_messages::{
|
use bp_messages::{
|
||||||
source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards, Sender},
|
source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards, SenderOrigin},
|
||||||
LaneId, MessageKey, MessageNonce, UnrewardedRelayer,
|
LaneId, MessageKey, MessageNonce, UnrewardedRelayer,
|
||||||
};
|
};
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
@@ -31,6 +31,10 @@ use num_traits::{SaturatingAdd, Zero};
|
|||||||
use sp_runtime::traits::Saturating;
|
use sp_runtime::traits::Saturating;
|
||||||
use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, ops::RangeInclusive};
|
use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, ops::RangeInclusive};
|
||||||
|
|
||||||
|
/// Error that occurs when message fee is non-zero, but payer is not defined.
|
||||||
|
const NON_ZERO_MESSAGE_FEE_CANT_BE_PAID_BY_NONE: &str =
|
||||||
|
"Non-zero message fee can't be paid by <None>";
|
||||||
|
|
||||||
/// Instant message payments made in given currency.
|
/// Instant message payments made in given currency.
|
||||||
///
|
///
|
||||||
/// The balance is initially reserved in a special `relayers-fund` account, and transferred
|
/// The balance is initially reserved in a special `relayers-fund` account, and transferred
|
||||||
@@ -44,42 +48,50 @@ use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, ops::RangeInclusive};
|
|||||||
/// to the relayer account.
|
/// to the relayer account.
|
||||||
/// NOTE It's within relayer's interest to keep their balance above ED as well, to make sure they
|
/// NOTE It's within relayer's interest to keep their balance above ED as well, to make sure they
|
||||||
/// can receive the payment.
|
/// can receive the payment.
|
||||||
pub struct InstantCurrencyPayments<T, I, Currency, GetConfirmationFee, RootAccount> {
|
pub struct InstantCurrencyPayments<T, I, Currency, GetConfirmationFee> {
|
||||||
_phantom: sp_std::marker::PhantomData<(T, I, Currency, GetConfirmationFee, RootAccount)>,
|
_phantom: sp_std::marker::PhantomData<(T, I, Currency, GetConfirmationFee)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, I, Currency, GetConfirmationFee, RootAccount>
|
impl<T, I, Currency, GetConfirmationFee>
|
||||||
MessageDeliveryAndDispatchPayment<T::AccountId, Currency::Balance>
|
MessageDeliveryAndDispatchPayment<T::Origin, T::AccountId, Currency::Balance>
|
||||||
for InstantCurrencyPayments<T, I, Currency, GetConfirmationFee, RootAccount>
|
for InstantCurrencyPayments<T, I, Currency, GetConfirmationFee>
|
||||||
where
|
where
|
||||||
T: frame_system::Config + crate::Config<I>,
|
T: frame_system::Config + crate::Config<I>,
|
||||||
I: 'static,
|
I: 'static,
|
||||||
|
T::Origin: SenderOrigin<T::AccountId>,
|
||||||
Currency: CurrencyT<T::AccountId, Balance = T::OutboundMessageFee>,
|
Currency: CurrencyT<T::AccountId, Balance = T::OutboundMessageFee>,
|
||||||
Currency::Balance: From<MessageNonce>,
|
Currency::Balance: From<MessageNonce>,
|
||||||
GetConfirmationFee: Get<Currency::Balance>,
|
GetConfirmationFee: Get<Currency::Balance>,
|
||||||
RootAccount: Get<Option<T::AccountId>>,
|
|
||||||
{
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn pay_delivery_and_dispatch_fee(
|
fn pay_delivery_and_dispatch_fee(
|
||||||
submitter: &Sender<T::AccountId>,
|
submitter: &T::Origin,
|
||||||
fee: &Currency::Balance,
|
fee: &Currency::Balance,
|
||||||
relayer_fund_account: &T::AccountId,
|
relayer_fund_account: &T::AccountId,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
|
let submitter_account = match submitter.linked_account() {
|
||||||
|
Some(submitter_account) => submitter_account,
|
||||||
|
None if !fee.is_zero() => {
|
||||||
|
// if we'll accept some message that has declared that the `fee` has been paid but
|
||||||
|
// it isn't actually paid, then it'll lead to problems with delivery confirmation
|
||||||
|
// payments (see `pay_relayer_rewards` && `confirmation_relayer` in particular)
|
||||||
|
return Err(NON_ZERO_MESSAGE_FEE_CANT_BE_PAID_BY_NONE)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
// message lane verifier has accepted the message before, so this message
|
||||||
|
// is unpaid **by design**
|
||||||
|
// => let's just do nothing
|
||||||
|
return Ok(())
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if !frame_system::Pallet::<T>::account_exists(relayer_fund_account) {
|
if !frame_system::Pallet::<T>::account_exists(relayer_fund_account) {
|
||||||
return Err("The relayer fund account must exist for the message lanes pallet to work correctly.");
|
return Err("The relayer fund account must exist for the message lanes pallet to work correctly.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_account = RootAccount::get();
|
|
||||||
let account = match submitter {
|
|
||||||
Sender::Signed(submitter) => submitter,
|
|
||||||
Sender::Root | Sender::None => root_account
|
|
||||||
.as_ref()
|
|
||||||
.ok_or("Sending messages using Root or None origin is disallowed.")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Currency::transfer(
|
Currency::transfer(
|
||||||
account,
|
&submitter_account,
|
||||||
relayer_fund_account,
|
relayer_fund_account,
|
||||||
*fee,
|
*fee,
|
||||||
// it's fine for the submitter to go below Existential Deposit and die.
|
// it's fine for the submitter to go below Existential Deposit and die.
|
||||||
@@ -226,7 +238,9 @@ fn pay_relayer_reward<Currency, AccountId>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mock::{run_test, AccountId as TestAccountId, Balance as TestBalance, TestRuntime};
|
use crate::mock::{
|
||||||
|
run_test, AccountId as TestAccountId, Balance as TestBalance, Origin, TestRuntime,
|
||||||
|
};
|
||||||
use bp_messages::source_chain::RelayerRewards;
|
use bp_messages::source_chain::RelayerRewards;
|
||||||
|
|
||||||
type Balances = pallet_balances::Pallet<TestRuntime>;
|
type Balances = pallet_balances::Pallet<TestRuntime>;
|
||||||
@@ -245,6 +259,48 @@ mod tests {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pay_delivery_and_dispatch_fee_fails_on_non_zero_fee_and_unknown_payer() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
const GetConfirmationFee: TestBalance = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
run_test(|| {
|
||||||
|
let result = InstantCurrencyPayments::<
|
||||||
|
TestRuntime,
|
||||||
|
(),
|
||||||
|
Balances,
|
||||||
|
GetConfirmationFee,
|
||||||
|
>::pay_delivery_and_dispatch_fee(
|
||||||
|
&Origin::root(),
|
||||||
|
&100,
|
||||||
|
&RELAYERS_FUND_ACCOUNT,
|
||||||
|
);
|
||||||
|
assert_eq!(result, Err(NON_ZERO_MESSAGE_FEE_CANT_BE_PAID_BY_NONE));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pay_delivery_and_dispatch_succeeds_on_zero_fee_and_unknown_payer() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
const GetConfirmationFee: TestBalance = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
run_test(|| {
|
||||||
|
let result = InstantCurrencyPayments::<
|
||||||
|
TestRuntime,
|
||||||
|
(),
|
||||||
|
Balances,
|
||||||
|
GetConfirmationFee,
|
||||||
|
>::pay_delivery_and_dispatch_fee(
|
||||||
|
&Origin::root(),
|
||||||
|
&0,
|
||||||
|
&RELAYERS_FUND_ACCOUNT,
|
||||||
|
);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
|
fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
|
|||||||
@@ -170,12 +170,14 @@ pub mod pallet {
|
|||||||
type TargetHeaderChain: TargetHeaderChain<Self::OutboundPayload, Self::AccountId>;
|
type TargetHeaderChain: TargetHeaderChain<Self::OutboundPayload, Self::AccountId>;
|
||||||
/// Message payload verifier.
|
/// Message payload verifier.
|
||||||
type LaneMessageVerifier: LaneMessageVerifier<
|
type LaneMessageVerifier: LaneMessageVerifier<
|
||||||
|
Self::Origin,
|
||||||
Self::AccountId,
|
Self::AccountId,
|
||||||
Self::OutboundPayload,
|
Self::OutboundPayload,
|
||||||
Self::OutboundMessageFee,
|
Self::OutboundMessageFee,
|
||||||
>;
|
>;
|
||||||
/// Message delivery payment.
|
/// Message delivery payment.
|
||||||
type MessageDeliveryAndDispatchPayment: MessageDeliveryAndDispatchPayment<
|
type MessageDeliveryAndDispatchPayment: MessageDeliveryAndDispatchPayment<
|
||||||
|
Self::Origin,
|
||||||
Self::AccountId,
|
Self::AccountId,
|
||||||
Self::OutboundMessageFee,
|
Self::OutboundMessageFee,
|
||||||
>;
|
>;
|
||||||
@@ -276,16 +278,12 @@ pub mod pallet {
|
|||||||
payload: T::OutboundPayload,
|
payload: T::OutboundPayload,
|
||||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||||
) -> DispatchResultWithPostInfo {
|
) -> DispatchResultWithPostInfo {
|
||||||
crate::send_message::<T, I>(
|
crate::send_message::<T, I>(origin, lane_id, payload, delivery_and_dispatch_fee).map(
|
||||||
origin.into().map_err(|_| BadOrigin)?,
|
|sent_message| PostDispatchInfo {
|
||||||
lane_id,
|
actual_weight: Some(sent_message.weight),
|
||||||
payload,
|
pays_fee: Pays::Yes,
|
||||||
delivery_and_dispatch_fee,
|
},
|
||||||
)
|
)
|
||||||
.map(|sent_message| PostDispatchInfo {
|
|
||||||
actual_weight: Some(sent_message.weight),
|
|
||||||
pays_fee: Pays::Yes,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pay additional fee for the message.
|
/// Pay additional fee for the message.
|
||||||
@@ -313,17 +311,15 @@ pub mod pallet {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// withdraw additional fee from submitter
|
// withdraw additional fee from submitter
|
||||||
let submitter = origin.into().map_err(|_| BadOrigin)?;
|
|
||||||
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
|
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
|
||||||
&submitter,
|
&origin,
|
||||||
&additional_fee,
|
&additional_fee,
|
||||||
&relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>(),
|
&relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>(),
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "runtime::bridge-messages",
|
target: "runtime::bridge-messages",
|
||||||
"Submitter {:?} can't pay additional fee {:?} for the message {:?}/{:?} to {:?}: {:?}",
|
"Submitter can't pay additional fee {:?} for the message {:?}/{:?} to {:?}: {:?}",
|
||||||
submitter,
|
|
||||||
additional_fee,
|
additional_fee,
|
||||||
lane_id,
|
lane_id,
|
||||||
nonce,
|
nonce,
|
||||||
@@ -780,6 +776,7 @@ pub fn relayer_fund_account_id<AccountId, AccountIdConverter: Convert<H256, Acco
|
|||||||
|
|
||||||
impl<T, I>
|
impl<T, I>
|
||||||
bp_messages::source_chain::MessagesBridge<
|
bp_messages::source_chain::MessagesBridge<
|
||||||
|
T::Origin,
|
||||||
T::AccountId,
|
T::AccountId,
|
||||||
T::OutboundMessageFee,
|
T::OutboundMessageFee,
|
||||||
T::OutboundPayload,
|
T::OutboundPayload,
|
||||||
@@ -791,7 +788,7 @@ where
|
|||||||
type Error = sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>;
|
type Error = sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>;
|
||||||
|
|
||||||
fn send_message(
|
fn send_message(
|
||||||
sender: bp_messages::source_chain::Sender<T::AccountId>,
|
sender: T::Origin,
|
||||||
lane: LaneId,
|
lane: LaneId,
|
||||||
message: T::OutboundPayload,
|
message: T::OutboundPayload,
|
||||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||||
@@ -802,7 +799,7 @@ where
|
|||||||
|
|
||||||
/// Function that actually sends message.
|
/// Function that actually sends message.
|
||||||
fn send_message<T: Config<I>, I: 'static>(
|
fn send_message<T: Config<I>, I: 'static>(
|
||||||
submitter: bp_messages::source_chain::Sender<T::AccountId>,
|
submitter: T::Origin,
|
||||||
lane_id: LaneId,
|
lane_id: LaneId,
|
||||||
payload: T::OutboundPayload,
|
payload: T::OutboundPayload,
|
||||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||||
@@ -856,9 +853,8 @@ fn send_message<T: Config<I>, I: 'static>(
|
|||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "runtime::bridge-messages",
|
target: "runtime::bridge-messages",
|
||||||
"Message to lane {:?} is rejected because submitter {:?} is unable to pay fee {:?}: {:?}",
|
"Message to lane {:?} is rejected because submitter is unable to pay fee {:?}: {:?}",
|
||||||
lane_id,
|
lane_id,
|
||||||
submitter,
|
|
||||||
delivery_and_dispatch_fee,
|
delivery_and_dispatch_fee,
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use bitvec::prelude::*;
|
|||||||
use bp_messages::{
|
use bp_messages::{
|
||||||
source_chain::{
|
source_chain::{
|
||||||
LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed,
|
LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed,
|
||||||
OnMessageAccepted, Sender, TargetHeaderChain,
|
OnMessageAccepted, SenderOrigin, TargetHeaderChain,
|
||||||
},
|
},
|
||||||
target_chain::{
|
target_chain::{
|
||||||
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
|
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
|
||||||
@@ -194,6 +194,16 @@ impl Config for TestRuntime {
|
|||||||
type BridgedChainId = TestBridgedChainId;
|
type BridgedChainId = TestBridgedChainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SenderOrigin<AccountId> for Origin {
|
||||||
|
fn linked_account(&self) -> Option<AccountId> {
|
||||||
|
match self.caller {
|
||||||
|
OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) =>
|
||||||
|
Some(submitter.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Size for TestPayload {
|
impl Size for TestPayload {
|
||||||
fn size_hint(&self) -> u32 {
|
fn size_hint(&self) -> u32 {
|
||||||
16 + self.extra.len() as u32
|
16 + self.extra.len() as u32
|
||||||
@@ -294,11 +304,13 @@ impl TargetHeaderChain<TestPayload, TestRelayer> for TestTargetHeaderChain {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TestLaneMessageVerifier;
|
pub struct TestLaneMessageVerifier;
|
||||||
|
|
||||||
impl LaneMessageVerifier<AccountId, TestPayload, TestMessageFee> for TestLaneMessageVerifier {
|
impl LaneMessageVerifier<Origin, AccountId, TestPayload, TestMessageFee>
|
||||||
|
for TestLaneMessageVerifier
|
||||||
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn verify_message(
|
fn verify_message(
|
||||||
_submitter: &Sender<AccountId>,
|
_submitter: &Origin,
|
||||||
delivery_and_dispatch_fee: &TestMessageFee,
|
delivery_and_dispatch_fee: &TestMessageFee,
|
||||||
_lane: &LaneId,
|
_lane: &LaneId,
|
||||||
_lane_outbound_data: &OutboundLaneData,
|
_lane_outbound_data: &OutboundLaneData,
|
||||||
@@ -324,8 +336,8 @@ impl TestMessageDeliveryAndDispatchPayment {
|
|||||||
|
|
||||||
/// Returns true if given fee has been paid by given submitter.
|
/// Returns true if given fee has been paid by given submitter.
|
||||||
pub fn is_fee_paid(submitter: AccountId, fee: TestMessageFee) -> bool {
|
pub fn is_fee_paid(submitter: AccountId, fee: TestMessageFee) -> bool {
|
||||||
frame_support::storage::unhashed::get(b":message-fee:") ==
|
let raw_origin: Result<frame_system::RawOrigin<_>, _> = Origin::signed(submitter).into();
|
||||||
Some((Sender::Signed(submitter), fee))
|
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
|
/// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is
|
||||||
@@ -336,13 +348,13 @@ impl TestMessageDeliveryAndDispatchPayment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee>
|
impl MessageDeliveryAndDispatchPayment<Origin, AccountId, TestMessageFee>
|
||||||
for TestMessageDeliveryAndDispatchPayment
|
for TestMessageDeliveryAndDispatchPayment
|
||||||
{
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn pay_delivery_and_dispatch_fee(
|
fn pay_delivery_and_dispatch_fee(
|
||||||
submitter: &Sender<AccountId>,
|
submitter: &Origin,
|
||||||
fee: &TestMessageFee,
|
fee: &TestMessageFee,
|
||||||
_relayer_fund_account: &AccountId,
|
_relayer_fund_account: &AccountId,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
@@ -350,7 +362,8 @@ impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee>
|
|||||||
return Err(TEST_ERROR)
|
return Err(TEST_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_support::storage::unhashed::put(b":message-fee:", &(submitter, fee));
|
let raw_origin: Result<frame_system::RawOrigin<_>, _> = submitter.clone().into();
|
||||||
|
frame_support::storage::unhashed::put(b":message-fee:", &(raw_origin.unwrap(), fee));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
swap_account_id, target_account_at_this_chain, BridgedAccountIdOf, BridgedAccountPublicOf,
|
swap_account_id, target_account_at_this_chain, BridgedAccountIdOf, BridgedAccountPublicOf,
|
||||||
BridgedAccountSignatureOf, BridgedBalanceOf, Call, Pallet, ThisChainBalance,
|
BridgedAccountSignatureOf, BridgedBalanceOf, Call, Origin, Pallet, ThisChainBalance,
|
||||||
TokenSwapCreationOf, TokenSwapOf,
|
TokenSwapCreationOf, TokenSwapOf,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@ pub trait Config<I: 'static>: crate::Config<I> {
|
|||||||
benchmarks_instance_pallet! {
|
benchmarks_instance_pallet! {
|
||||||
where_clause {
|
where_clause {
|
||||||
where
|
where
|
||||||
|
Origin<T, I>: Into<T::Origin>,
|
||||||
BridgedAccountPublicOf<T, I>: Decode + Parameter,
|
BridgedAccountPublicOf<T, I>: Decode + Parameter,
|
||||||
BridgedAccountSignatureOf<T, I>: Decode,
|
BridgedAccountSignatureOf<T, I>: Decode,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,16 +70,18 @@ use bp_runtime::{messages::DispatchFeePayment, ChainId};
|
|||||||
use bp_token_swap::{
|
use bp_token_swap::{
|
||||||
RawBridgedTransferCall, TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType,
|
RawBridgedTransferCall, TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType,
|
||||||
};
|
};
|
||||||
use codec::Encode;
|
use codec::{Decode, Encode};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
fail,
|
fail,
|
||||||
traits::{Currency, ExistenceRequirement},
|
traits::{Currency, ExistenceRequirement},
|
||||||
weights::PostDispatchInfo,
|
weights::PostDispatchInfo,
|
||||||
|
RuntimeDebug,
|
||||||
};
|
};
|
||||||
|
use scale_info::TypeInfo;
|
||||||
use sp_core::H256;
|
use sp_core::H256;
|
||||||
use sp_io::hashing::blake2_256;
|
use sp_io::hashing::blake2_256;
|
||||||
use sp_runtime::traits::{Convert, Saturating};
|
use sp_runtime::traits::{Convert, Saturating};
|
||||||
use sp_std::boxed::Box;
|
use sp_std::{boxed::Box, marker::PhantomData};
|
||||||
use weights::WeightInfo;
|
use weights::WeightInfo;
|
||||||
|
|
||||||
pub use weights_ext::WeightInfoExt;
|
pub use weights_ext::WeightInfoExt;
|
||||||
@@ -95,6 +97,24 @@ pub mod weights_ext;
|
|||||||
|
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
|
/// Name of the `PendingSwaps` storage map.
|
||||||
|
pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps";
|
||||||
|
|
||||||
|
/// Origin for the token swap pallet.
|
||||||
|
#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)]
|
||||||
|
pub enum RawOrigin<AccountId, I> {
|
||||||
|
/// The call is originated by the token swap account.
|
||||||
|
TokenSwap {
|
||||||
|
/// Id of the account that has started the swap.
|
||||||
|
source_account_at_this_chain: AccountId,
|
||||||
|
/// Id of the account that holds the funds during this swap. The message fee is paid from
|
||||||
|
/// this account funds.
|
||||||
|
swap_account_at_this_chain: AccountId,
|
||||||
|
},
|
||||||
|
/// Dummy to manage the fact we have instancing.
|
||||||
|
_Phantom(PhantomData<I>),
|
||||||
|
}
|
||||||
|
|
||||||
// comes from #[pallet::event]
|
// comes from #[pallet::event]
|
||||||
#[allow(clippy::unused_unit)]
|
#[allow(clippy::unused_unit)]
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
@@ -123,6 +143,7 @@ pub mod pallet {
|
|||||||
type OutboundMessageLaneId: Get<LaneId>;
|
type OutboundMessageLaneId: Get<LaneId>;
|
||||||
/// Messages bridge with Bridged chain.
|
/// Messages bridge with Bridged chain.
|
||||||
type MessagesBridge: MessagesBridge<
|
type MessagesBridge: MessagesBridge<
|
||||||
|
Self::Origin,
|
||||||
Self::AccountId,
|
Self::AccountId,
|
||||||
<Self::ThisCurrency as Currency<Self::AccountId>>::Balance,
|
<Self::ThisCurrency as Currency<Self::AccountId>>::Balance,
|
||||||
MessagePayloadOf<Self, I>,
|
MessagePayloadOf<Self, I>,
|
||||||
@@ -189,6 +210,7 @@ pub mod pallet {
|
|||||||
impl<T: Config<I>, I: 'static> Pallet<T, I>
|
impl<T: Config<I>, I: 'static> Pallet<T, I>
|
||||||
where
|
where
|
||||||
BridgedAccountPublicOf<T, I>: Parameter,
|
BridgedAccountPublicOf<T, I>: Parameter,
|
||||||
|
Origin<T, I>: Into<T::Origin>,
|
||||||
{
|
{
|
||||||
/// Start token swap procedure.
|
/// Start token swap procedure.
|
||||||
///
|
///
|
||||||
@@ -310,7 +332,11 @@ pub mod pallet {
|
|||||||
// `Currency::transfer` call on the bridged chain, but no checks are made - it is
|
// `Currency::transfer` call on the bridged chain, but no checks are made - it is
|
||||||
// the transaction submitter to ensure it is valid.
|
// the transaction submitter to ensure it is valid.
|
||||||
let send_message_result = T::MessagesBridge::send_message(
|
let send_message_result = T::MessagesBridge::send_message(
|
||||||
bp_messages::source_chain::Sender::from(Some(swap_account.clone())),
|
RawOrigin::TokenSwap {
|
||||||
|
source_account_at_this_chain: swap.source_account_at_this_chain.clone(),
|
||||||
|
swap_account_at_this_chain: swap_account.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
T::OutboundMessageLaneId::get(),
|
T::OutboundMessageLaneId::get(),
|
||||||
bp_message_dispatch::MessagePayload {
|
bp_message_dispatch::MessagePayload {
|
||||||
spec_version: bridged_chain_spec_version,
|
spec_version: bridged_chain_spec_version,
|
||||||
@@ -513,6 +539,10 @@ pub mod pallet {
|
|||||||
InvalidClaimant,
|
InvalidClaimant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Origin for the token swap pallet.
|
||||||
|
#[pallet::origin]
|
||||||
|
pub type Origin<T, I = ()> = RawOrigin<<T as frame_system::Config>::AccountId, I>;
|
||||||
|
|
||||||
/// Pending token swaps states.
|
/// Pending token swaps states.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
pub type PendingSwaps<T: Config<I>, I: 'static = ()> =
|
pub type PendingSwaps<T: Config<I>, I: 'static = ()> =
|
||||||
@@ -685,7 +715,7 @@ mod tests {
|
|||||||
|
|
||||||
fn start_test_swap() {
|
fn start_test_swap() {
|
||||||
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(TokenSwapCreation {
|
Box::new(TokenSwapCreation {
|
||||||
target_public_at_bridged_chain: bridged_chain_account_public(),
|
target_public_at_bridged_chain: bridged_chain_account_public(),
|
||||||
@@ -710,7 +740,7 @@ mod tests {
|
|||||||
run_test(|| {
|
run_test(|| {
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::create_swap(
|
Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT + 1),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
),
|
),
|
||||||
@@ -726,7 +756,7 @@ mod tests {
|
|||||||
swap.source_balance_at_this_chain = ExistentialDeposit::get() - 1;
|
swap.source_balance_at_this_chain = ExistentialDeposit::get() - 1;
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::create_swap(
|
Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
swap,
|
swap,
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
),
|
),
|
||||||
@@ -742,7 +772,7 @@ mod tests {
|
|||||||
swap.source_balance_at_this_chain = THIS_CHAIN_ACCOUNT_BALANCE + 1;
|
swap.source_balance_at_this_chain = THIS_CHAIN_ACCOUNT_BALANCE + 1;
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::create_swap(
|
Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
swap,
|
swap,
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
),
|
),
|
||||||
@@ -760,7 +790,7 @@ mod tests {
|
|||||||
swap_creation.bridged_currency_transfer = transfer;
|
swap_creation.bridged_currency_transfer = transfer;
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::create_swap(
|
Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(swap_creation),
|
Box::new(swap_creation),
|
||||||
),
|
),
|
||||||
@@ -773,14 +803,14 @@ mod tests {
|
|||||||
fn create_swap_fails_if_swap_is_active() {
|
fn create_swap_fails_if_swap_is_active() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::create_swap(
|
Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
),
|
),
|
||||||
@@ -795,7 +825,7 @@ mod tests {
|
|||||||
frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER + 1);
|
frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER + 1);
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::create_swap(
|
Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
),
|
),
|
||||||
@@ -809,7 +839,7 @@ mod tests {
|
|||||||
run_test(|| {
|
run_test(|| {
|
||||||
frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER);
|
frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER);
|
||||||
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
));
|
));
|
||||||
@@ -823,7 +853,7 @@ mod tests {
|
|||||||
frame_system::Pallet::<TestRuntime>::reset_events();
|
frame_system::Pallet::<TestRuntime>::reset_events();
|
||||||
|
|
||||||
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
assert_ok!(Pallet::<TestRuntime>::create_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
Box::new(test_swap_creation()),
|
Box::new(test_swap_creation()),
|
||||||
));
|
));
|
||||||
@@ -855,7 +885,7 @@ mod tests {
|
|||||||
run_test(|| {
|
run_test(|| {
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::claim_swap(
|
Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(
|
mock::Origin::signed(
|
||||||
1 + target_account_at_this_chain::<TestRuntime, ()>(&test_swap())
|
1 + target_account_at_this_chain::<TestRuntime, ()>(&test_swap())
|
||||||
),
|
),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
@@ -872,7 +902,9 @@ mod tests {
|
|||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::claim_swap(
|
Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
|
||||||
|
&test_swap()
|
||||||
|
)),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsPending
|
Error::<TestRuntime, ()>::SwapIsPending
|
||||||
@@ -887,7 +919,9 @@ mod tests {
|
|||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::claim_swap(
|
Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
|
||||||
|
&test_swap()
|
||||||
|
)),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsFailed
|
Error::<TestRuntime, ()>::SwapIsFailed
|
||||||
@@ -900,7 +934,9 @@ mod tests {
|
|||||||
run_test(|| {
|
run_test(|| {
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::claim_swap(
|
Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
|
||||||
|
&test_swap()
|
||||||
|
)),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsInactive
|
Error::<TestRuntime, ()>::SwapIsInactive
|
||||||
@@ -916,7 +952,9 @@ mod tests {
|
|||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::claim_swap(
|
Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
|
||||||
|
&test_swap()
|
||||||
|
)),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
|
Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
|
||||||
@@ -934,7 +972,9 @@ mod tests {
|
|||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::claim_swap(
|
Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
|
||||||
|
&test_swap()
|
||||||
|
)),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsTemporaryLocked
|
Error::<TestRuntime, ()>::SwapIsTemporaryLocked
|
||||||
@@ -952,7 +992,7 @@ mod tests {
|
|||||||
frame_system::Pallet::<TestRuntime>::reset_events();
|
frame_system::Pallet::<TestRuntime>::reset_events();
|
||||||
|
|
||||||
assert_ok!(Pallet::<TestRuntime>::claim_swap(
|
assert_ok!(Pallet::<TestRuntime>::claim_swap(
|
||||||
Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
||||||
test_swap(),
|
test_swap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -988,7 +1028,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::cancel_swap(
|
Pallet::<TestRuntime>::cancel_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT + 1),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1),
|
||||||
test_swap()
|
test_swap()
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::MismatchedSwapSourceOrigin
|
Error::<TestRuntime, ()>::MismatchedSwapSourceOrigin
|
||||||
@@ -1002,7 +1042,10 @@ mod tests {
|
|||||||
start_test_swap();
|
start_test_swap();
|
||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::cancel_swap(Origin::signed(THIS_CHAIN_ACCOUNT), test_swap()),
|
Pallet::<TestRuntime>::cancel_swap(
|
||||||
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
|
test_swap()
|
||||||
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsPending
|
Error::<TestRuntime, ()>::SwapIsPending
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1015,7 +1058,10 @@ mod tests {
|
|||||||
receive_test_swap_confirmation(true);
|
receive_test_swap_confirmation(true);
|
||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::cancel_swap(Origin::signed(THIS_CHAIN_ACCOUNT), test_swap()),
|
Pallet::<TestRuntime>::cancel_swap(
|
||||||
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
|
test_swap()
|
||||||
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsConfirmed
|
Error::<TestRuntime, ()>::SwapIsConfirmed
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1025,7 +1071,10 @@ mod tests {
|
|||||||
fn cancel_swap_fails_if_swap_is_inactive() {
|
fn cancel_swap_fails_if_swap_is_inactive() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::cancel_swap(Origin::signed(THIS_CHAIN_ACCOUNT), test_swap()),
|
Pallet::<TestRuntime>::cancel_swap(
|
||||||
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
|
test_swap()
|
||||||
|
),
|
||||||
Error::<TestRuntime, ()>::SwapIsInactive
|
Error::<TestRuntime, ()>::SwapIsInactive
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1042,7 +1091,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
Pallet::<TestRuntime>::cancel_swap(Origin::signed(THIS_CHAIN_ACCOUNT), test_swap()),
|
Pallet::<TestRuntime>::cancel_swap(
|
||||||
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
|
test_swap()
|
||||||
|
),
|
||||||
Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
|
Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1058,7 +1110,7 @@ mod tests {
|
|||||||
frame_system::Pallet::<TestRuntime>::reset_events();
|
frame_system::Pallet::<TestRuntime>::reset_events();
|
||||||
|
|
||||||
assert_ok!(Pallet::<TestRuntime>::cancel_swap(
|
assert_ok!(Pallet::<TestRuntime>::cancel_swap(
|
||||||
Origin::signed(THIS_CHAIN_ACCOUNT),
|
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
|
||||||
test_swap()
|
test_swap()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ frame_support::construct_runtime! {
|
|||||||
{
|
{
|
||||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||||
Balances: pallet_balances::{Pallet, Call, Event<T>},
|
Balances: pallet_balances::{Pallet, Call, Event<T>},
|
||||||
TokenSwap: pallet_bridge_token_swap::{Pallet, Call, Event<T>},
|
TokenSwap: pallet_bridge_token_swap::{Pallet, Call, Event<T>, Origin<T>},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,18 +154,23 @@ impl bp_runtime::Chain for BridgedChain {
|
|||||||
|
|
||||||
pub struct TestMessagesBridge;
|
pub struct TestMessagesBridge;
|
||||||
|
|
||||||
impl MessagesBridge<AccountId, Balance, MessagePayloadOf<TestRuntime, ()>> for TestMessagesBridge {
|
impl MessagesBridge<Origin, AccountId, Balance, MessagePayloadOf<TestRuntime, ()>>
|
||||||
|
for TestMessagesBridge
|
||||||
|
{
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn send_message(
|
fn send_message(
|
||||||
sender: frame_system::RawOrigin<AccountId>,
|
sender: Origin,
|
||||||
lane: LaneId,
|
lane: LaneId,
|
||||||
message: MessagePayloadOf<TestRuntime, ()>,
|
message: MessagePayloadOf<TestRuntime, ()>,
|
||||||
delivery_and_dispatch_fee: Balance,
|
delivery_and_dispatch_fee: Balance,
|
||||||
) -> Result<SendMessageArtifacts, Self::Error> {
|
) -> Result<SendMessageArtifacts, Self::Error> {
|
||||||
assert_ne!(sender, frame_system::RawOrigin::Signed(THIS_CHAIN_ACCOUNT));
|
|
||||||
assert_eq!(lane, OutboundMessageLaneId::get());
|
assert_eq!(lane, OutboundMessageLaneId::get());
|
||||||
assert_eq!(delivery_and_dispatch_fee, SWAP_DELIVERY_AND_DISPATCH_FEE);
|
assert_eq!(delivery_and_dispatch_fee, SWAP_DELIVERY_AND_DISPATCH_FEE);
|
||||||
|
match sender.caller {
|
||||||
|
OriginCaller::TokenSwap(_) => (),
|
||||||
|
_ => panic!("unexpected origin"),
|
||||||
|
}
|
||||||
match message.call[0] {
|
match message.call[0] {
|
||||||
OK_TRANSFER_CALL => Ok(SendMessageArtifacts { nonce: MESSAGE_NONCE, weight: 0 }),
|
OK_TRANSFER_CALL => Ok(SendMessageArtifacts { nonce: MESSAGE_NONCE, weight: 0 }),
|
||||||
BAD_TRANSFER_CALL => Err(()),
|
BAD_TRANSFER_CALL => Err(()),
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ hex-literal = "0.3"
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
|
"bitvec/std",
|
||||||
"bp-runtime/std",
|
"bp-runtime/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
|||||||
@@ -28,7 +28,21 @@ use sp_std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// The sender of the message on the source chain.
|
/// The sender of the message on the source chain.
|
||||||
pub type Sender<AccountId> = frame_system::RawOrigin<AccountId>;
|
pub trait SenderOrigin<AccountId> {
|
||||||
|
/// Return id of the account that is sending this message.
|
||||||
|
///
|
||||||
|
/// In regular messages configuration, when regular message is sent you'll always get `Some(_)`
|
||||||
|
/// from this call. This is the account that is paying send costs. However, there are some
|
||||||
|
/// examples when `None` may be returned from the call:
|
||||||
|
///
|
||||||
|
/// - if the send-message call origin is either `frame_system::RawOrigin::Root` or
|
||||||
|
/// `frame_system::RawOrigin::None` and your configuration forbids such messages;
|
||||||
|
/// - if your configuration allows 'unpaid' messages sent by pallets. Then the pallet may just
|
||||||
|
/// use its own defined origin (not linked to any account) and the message will be accepted.
|
||||||
|
/// This may be useful for pallets that are sending important system-wide information (like
|
||||||
|
/// update of runtime version).
|
||||||
|
fn linked_account(&self) -> Option<AccountId>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Relayers rewards, grouped by relayer account id.
|
/// Relayers rewards, grouped by relayer account id.
|
||||||
pub type RelayersRewards<AccountId, Balance> = BTreeMap<AccountId, RelayerRewards<Balance>>;
|
pub type RelayersRewards<AccountId, Balance> = BTreeMap<AccountId, RelayerRewards<Balance>>;
|
||||||
@@ -82,14 +96,14 @@ pub trait TargetHeaderChain<Payload, AccountId> {
|
|||||||
/// Lane3 until some block, ...), then it may be built using this verifier.
|
/// Lane3 until some block, ...), then it may be built using this verifier.
|
||||||
///
|
///
|
||||||
/// Any fee requirements should also be enforced here.
|
/// Any fee requirements should also be enforced here.
|
||||||
pub trait LaneMessageVerifier<Submitter, Payload, Fee> {
|
pub trait LaneMessageVerifier<SenderOrigin, Submitter, Payload, Fee> {
|
||||||
/// Error type.
|
/// Error type.
|
||||||
type Error: Debug + Into<&'static str>;
|
type Error: Debug + Into<&'static str>;
|
||||||
|
|
||||||
/// Verify message payload and return Ok(()) if message is valid and allowed to be sent over the
|
/// Verify message payload and return Ok(()) if message is valid and allowed to be sent over the
|
||||||
/// lane.
|
/// lane.
|
||||||
fn verify_message(
|
fn verify_message(
|
||||||
submitter: &Sender<Submitter>,
|
submitter: &SenderOrigin,
|
||||||
delivery_and_dispatch_fee: &Fee,
|
delivery_and_dispatch_fee: &Fee,
|
||||||
lane: &LaneId,
|
lane: &LaneId,
|
||||||
outbound_data: &OutboundLaneData,
|
outbound_data: &OutboundLaneData,
|
||||||
@@ -110,14 +124,14 @@ pub trait LaneMessageVerifier<Submitter, Payload, Fee> {
|
|||||||
/// So to be sure that any non-altruist relayer would agree to deliver message, submitter
|
/// 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)
|
/// 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.
|
/// to (4) above, plus some interest for the relayer.
|
||||||
pub trait MessageDeliveryAndDispatchPayment<AccountId, Balance> {
|
pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> {
|
||||||
/// Error type.
|
/// Error type.
|
||||||
type Error: Debug + Into<&'static str>;
|
type Error: Debug + Into<&'static str>;
|
||||||
|
|
||||||
/// Withhold/write-off delivery_and_dispatch_fee from submitter account to
|
/// Withhold/write-off delivery_and_dispatch_fee from submitter account to
|
||||||
/// some relayers-fund account.
|
/// some relayers-fund account.
|
||||||
fn pay_delivery_and_dispatch_fee(
|
fn pay_delivery_and_dispatch_fee(
|
||||||
submitter: &Sender<AccountId>,
|
submitter: &SenderOrigin,
|
||||||
fee: &Balance,
|
fee: &Balance,
|
||||||
relayer_fund_account: &AccountId,
|
relayer_fund_account: &AccountId,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
@@ -145,7 +159,7 @@ pub struct SendMessageArtifacts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Messages bridge API to be used from other pallets.
|
/// Messages bridge API to be used from other pallets.
|
||||||
pub trait MessagesBridge<AccountId, Balance, Payload> {
|
pub trait MessagesBridge<SenderOrigin, AccountId, Balance, Payload> {
|
||||||
/// Error type.
|
/// Error type.
|
||||||
type Error: Debug;
|
type Error: Debug;
|
||||||
|
|
||||||
@@ -153,7 +167,7 @@ pub trait MessagesBridge<AccountId, Balance, Payload> {
|
|||||||
///
|
///
|
||||||
/// Returns unique message nonce or error if send has failed.
|
/// Returns unique message nonce or error if send has failed.
|
||||||
fn send_message(
|
fn send_message(
|
||||||
sender: Sender<AccountId>,
|
sender: SenderOrigin,
|
||||||
lane: LaneId,
|
lane: LaneId,
|
||||||
message: Payload,
|
message: Payload,
|
||||||
delivery_and_dispatch_fee: Balance,
|
delivery_and_dispatch_fee: Balance,
|
||||||
@@ -164,13 +178,13 @@ pub trait MessagesBridge<AccountId, Balance, Payload> {
|
|||||||
#[derive(RuntimeDebug, PartialEq)]
|
#[derive(RuntimeDebug, PartialEq)]
|
||||||
pub struct NoopMessagesBridge;
|
pub struct NoopMessagesBridge;
|
||||||
|
|
||||||
impl<AccountId, Balance, Payload> MessagesBridge<AccountId, Balance, Payload>
|
impl<SenderOrigin, AccountId, Balance, Payload>
|
||||||
for NoopMessagesBridge
|
MessagesBridge<SenderOrigin, AccountId, Balance, Payload> for NoopMessagesBridge
|
||||||
{
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn send_message(
|
fn send_message(
|
||||||
_sender: Sender<AccountId>,
|
_sender: SenderOrigin,
|
||||||
_lane: LaneId,
|
_lane: LaneId,
|
||||||
_message: Payload,
|
_message: Payload,
|
||||||
_delivery_and_dispatch_fee: Balance,
|
_delivery_and_dispatch_fee: Balance,
|
||||||
@@ -245,13 +259,13 @@ impl<Payload, AccountId> TargetHeaderChain<Payload, AccountId> for ForbidOutboun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Submitter, Payload, Fee> LaneMessageVerifier<Submitter, Payload, Fee>
|
impl<SenderOrigin, Submitter, Payload, Fee>
|
||||||
for ForbidOutboundMessages
|
LaneMessageVerifier<SenderOrigin, Submitter, Payload, Fee> for ForbidOutboundMessages
|
||||||
{
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn verify_message(
|
fn verify_message(
|
||||||
_submitter: &Sender<Submitter>,
|
_submitter: &SenderOrigin,
|
||||||
_delivery_and_dispatch_fee: &Fee,
|
_delivery_and_dispatch_fee: &Fee,
|
||||||
_lane: &LaneId,
|
_lane: &LaneId,
|
||||||
_outbound_data: &OutboundLaneData,
|
_outbound_data: &OutboundLaneData,
|
||||||
@@ -261,13 +275,13 @@ impl<Submitter, Payload, Fee> LaneMessageVerifier<Submitter, Payload, Fee>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId, Balance> MessageDeliveryAndDispatchPayment<AccountId, Balance>
|
impl<SenderOrigin, AccountId, Balance>
|
||||||
for ForbidOutboundMessages
|
MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> for ForbidOutboundMessages
|
||||||
{
|
{
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn pay_delivery_and_dispatch_fee(
|
fn pay_delivery_and_dispatch_fee(
|
||||||
_submitter: &Sender<AccountId>,
|
_submitter: &SenderOrigin,
|
||||||
_fee: &Balance,
|
_fee: &Balance,
|
||||||
_relayer_fund_account: &AccountId,
|
_relayer_fund_account: &AccountId,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
|
|||||||
Reference in New Issue
Block a user