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:
Svyatoslav Nikolsky
2022-03-14 16:36:58 +03:00
committed by Bastian Köcher
parent 7b7b8baa60
commit ed2a3082ef
15 changed files with 361 additions and 129 deletions
@@ -18,7 +18,7 @@
use crate::{
swap_account_id, target_account_at_this_chain, BridgedAccountIdOf, BridgedAccountPublicOf,
BridgedAccountSignatureOf, BridgedBalanceOf, Call, Pallet, ThisChainBalance,
BridgedAccountSignatureOf, BridgedBalanceOf, Call, Origin, Pallet, ThisChainBalance,
TokenSwapCreationOf, TokenSwapOf,
};
@@ -43,6 +43,7 @@ pub trait Config<I: 'static>: crate::Config<I> {
benchmarks_instance_pallet! {
where_clause {
where
Origin<T, I>: Into<T::Origin>,
BridgedAccountPublicOf<T, I>: Decode + Parameter,
BridgedAccountSignatureOf<T, I>: Decode,
}
+78 -26
View File
@@ -70,16 +70,18 @@ use bp_runtime::{messages::DispatchFeePayment, ChainId};
use bp_token_swap::{
RawBridgedTransferCall, TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType,
};
use codec::Encode;
use codec::{Decode, Encode};
use frame_support::{
fail,
traits::{Currency, ExistenceRequirement},
weights::PostDispatchInfo,
RuntimeDebug,
};
use scale_info::TypeInfo;
use sp_core::H256;
use sp_io::hashing::blake2_256;
use sp_runtime::traits::{Convert, Saturating};
use sp_std::boxed::Box;
use sp_std::{boxed::Box, marker::PhantomData};
use weights::WeightInfo;
pub use weights_ext::WeightInfoExt;
@@ -95,6 +97,24 @@ pub mod weights_ext;
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]
#[allow(clippy::unused_unit)]
#[frame_support::pallet]
@@ -123,6 +143,7 @@ pub mod pallet {
type OutboundMessageLaneId: Get<LaneId>;
/// Messages bridge with Bridged chain.
type MessagesBridge: MessagesBridge<
Self::Origin,
Self::AccountId,
<Self::ThisCurrency as Currency<Self::AccountId>>::Balance,
MessagePayloadOf<Self, I>,
@@ -189,6 +210,7 @@ pub mod pallet {
impl<T: Config<I>, I: 'static> Pallet<T, I>
where
BridgedAccountPublicOf<T, I>: Parameter,
Origin<T, I>: Into<T::Origin>,
{
/// 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
// the transaction submitter to ensure it is valid.
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(),
bp_message_dispatch::MessagePayload {
spec_version: bridged_chain_spec_version,
@@ -513,6 +539,10 @@ pub mod pallet {
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.
#[pallet::storage]
pub type PendingSwaps<T: Config<I>, I: 'static = ()> =
@@ -685,7 +715,7 @@ mod tests {
fn start_test_swap() {
assert_ok!(Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(TokenSwapCreation {
target_public_at_bridged_chain: bridged_chain_account_public(),
@@ -710,7 +740,7 @@ mod tests {
run_test(|| {
assert_noop!(
Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT + 1),
mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1),
test_swap(),
Box::new(test_swap_creation()),
),
@@ -726,7 +756,7 @@ mod tests {
swap.source_balance_at_this_chain = ExistentialDeposit::get() - 1;
assert_noop!(
Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
swap,
Box::new(test_swap_creation()),
),
@@ -742,7 +772,7 @@ mod tests {
swap.source_balance_at_this_chain = THIS_CHAIN_ACCOUNT_BALANCE + 1;
assert_noop!(
Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
swap,
Box::new(test_swap_creation()),
),
@@ -760,7 +790,7 @@ mod tests {
swap_creation.bridged_currency_transfer = transfer;
assert_noop!(
Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(swap_creation),
),
@@ -773,14 +803,14 @@ mod tests {
fn create_swap_fails_if_swap_is_active() {
run_test(|| {
assert_ok!(Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(test_swap_creation()),
));
assert_noop!(
Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(test_swap_creation()),
),
@@ -795,7 +825,7 @@ mod tests {
frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER + 1);
assert_noop!(
Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(test_swap_creation()),
),
@@ -809,7 +839,7 @@ mod tests {
run_test(|| {
frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER);
assert_ok!(Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(test_swap_creation()),
));
@@ -823,7 +853,7 @@ mod tests {
frame_system::Pallet::<TestRuntime>::reset_events();
assert_ok!(Pallet::<TestRuntime>::create_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap(),
Box::new(test_swap_creation()),
));
@@ -855,7 +885,7 @@ mod tests {
run_test(|| {
assert_noop!(
Pallet::<TestRuntime>::claim_swap(
Origin::signed(
mock::Origin::signed(
1 + target_account_at_this_chain::<TestRuntime, ()>(&test_swap())
),
test_swap(),
@@ -872,7 +902,9 @@ mod tests {
assert_noop!(
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(),
),
Error::<TestRuntime, ()>::SwapIsPending
@@ -887,7 +919,9 @@ mod tests {
assert_noop!(
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(),
),
Error::<TestRuntime, ()>::SwapIsFailed
@@ -900,7 +934,9 @@ mod tests {
run_test(|| {
assert_noop!(
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(),
),
Error::<TestRuntime, ()>::SwapIsInactive
@@ -916,7 +952,9 @@ mod tests {
assert_noop!(
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(),
),
Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
@@ -934,7 +972,9 @@ mod tests {
assert_noop!(
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(),
),
Error::<TestRuntime, ()>::SwapIsTemporaryLocked
@@ -952,7 +992,7 @@ mod tests {
frame_system::Pallet::<TestRuntime>::reset_events();
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(),
));
@@ -988,7 +1028,7 @@ mod tests {
assert_noop!(
Pallet::<TestRuntime>::cancel_swap(
Origin::signed(THIS_CHAIN_ACCOUNT + 1),
mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1),
test_swap()
),
Error::<TestRuntime, ()>::MismatchedSwapSourceOrigin
@@ -1002,7 +1042,10 @@ mod tests {
start_test_swap();
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
);
});
@@ -1015,7 +1058,10 @@ mod tests {
receive_test_swap_confirmation(true);
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
);
});
@@ -1025,7 +1071,10 @@ mod tests {
fn cancel_swap_fails_if_swap_is_inactive() {
run_test(|| {
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
);
});
@@ -1042,7 +1091,10 @@ mod tests {
);
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
);
});
@@ -1058,7 +1110,7 @@ mod tests {
frame_system::Pallet::<TestRuntime>::reset_events();
assert_ok!(Pallet::<TestRuntime>::cancel_swap(
Origin::signed(THIS_CHAIN_ACCOUNT),
mock::Origin::signed(THIS_CHAIN_ACCOUNT),
test_swap()
));
+9 -4
View File
@@ -56,7 +56,7 @@ frame_support::construct_runtime! {
{
System: frame_system::{Pallet, Call, Config, Storage, 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;
impl MessagesBridge<AccountId, Balance, MessagePayloadOf<TestRuntime, ()>> for TestMessagesBridge {
impl MessagesBridge<Origin, AccountId, Balance, MessagePayloadOf<TestRuntime, ()>>
for TestMessagesBridge
{
type Error = ();
fn send_message(
sender: frame_system::RawOrigin<AccountId>,
sender: Origin,
lane: LaneId,
message: MessagePayloadOf<TestRuntime, ()>,
delivery_and_dispatch_fee: Balance,
) -> Result<SendMessageArtifacts, Self::Error> {
assert_ne!(sender, frame_system::RawOrigin::Signed(THIS_CHAIN_ACCOUNT));
assert_eq!(lane, OutboundMessageLaneId::get());
assert_eq!(delivery_and_dispatch_fee, SWAP_DELIVERY_AND_DISPATCH_FEE);
match sender.caller {
OriginCaller::TokenSwap(_) => (),
_ => panic!("unexpected origin"),
}
match message.call[0] {
OK_TRANSFER_CALL => Ok(SendMessageArtifacts { nonce: MESSAGE_NONCE, weight: 0 }),
BAD_TRANSFER_CALL => Err(()),