Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xcm queue paused and resume #1737

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
6 changes: 5 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions modules/transaction-pause/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub mod module {
pallet_name_bytes: Vec<u8>,
function_name_bytes: Vec<u8>,
},
XcmPaused,
XcmUnPaused,
}

/// The paused transaction map
Expand All @@ -81,6 +83,10 @@ pub mod module {
#[pallet::getter(fn paused_transactions)]
pub type PausedTransactions<T: Config> = StorageMap<_, Twox64Concat, (Vec<u8>, Vec<u8>), (), OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn xcm_paused)]
pub type XcmPaused<T: Config> = StorageValue<_, bool, ValueQuery>;

#[pallet::pallet]
pub struct Pallet<T>(_);

Expand Down Expand Up @@ -129,6 +135,22 @@ pub mod module {
};
Ok(())
}

#[pallet::weight(T::WeightInfo::pause_transaction())]
pub fn pause_xcm(origin: OriginFor<T>) -> DispatchResult {
T::UpdateOrigin::ensure_origin(origin)?;
XcmPaused::<T>::set(true);
Self::deposit_event(Event::XcmPaused);
Ok(())
}

#[pallet::weight(T::WeightInfo::pause_transaction())]
pub fn unpause_xcm(origin: OriginFor<T>) -> DispatchResult {
T::UpdateOrigin::ensure_origin(origin)?;
XcmPaused::<T>::set(false);
Self::deposit_event(Event::XcmUnPaused);
Ok(())
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions runtime/acala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,10 +1366,10 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type Event = Event;
type OnValidationData = ();
type SelfParaId = ParachainInfo;
type DmpMessageHandler = DmpQueue;
type DmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, DmpQueue>;
type ReservedDmpWeight = ReservedDmpWeight;
type OutboundXcmpMessageSource = XcmpQueue;
type XcmpMessageHandler = XcmpQueue;
type XcmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, XcmpQueue>;
type ReservedXcmpWeight = ReservedXcmpWeight;
}

Expand Down
6 changes: 6 additions & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false }

polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.13", default-features = false }
cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.13", default-features = false }
cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.13", default-features = false }

orml-oracle = { path = "../../orml/oracle", default-features = false }
Expand All @@ -35,6 +37,7 @@ primitives = { package = "acala-primitives", path = "../../primitives", default-

module-prices = { path = "../../modules/prices", default-features = false }
module-transaction-payment = { path = "../../modules/transaction-payment", default-features = false }
module-transaction-pause = { path = "../../modules/transaction-pause", default-features = false }
module-nft = { path = "../../modules/nft", default-features = false }
module-dex = { path = "../../modules/dex", default-features = false }

Expand Down Expand Up @@ -77,6 +80,8 @@ std = [
"sp-runtime/std",
"sp-std/std",

"polkadot-core-primitives/std",
"cumulus-primitives-core/std",
"cumulus-pallet-parachain-system/std",

"orml-oracle/std",
Expand All @@ -89,6 +94,7 @@ std = [
"primitives/std",
"module-prices/std",
"module-transaction-payment/std",
"module-transaction-pause/std",
"module-nft/std",
"module-dex/std",

Expand Down
45 changes: 45 additions & 0 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ pub use xcm::latest::prelude::*;
pub use xcm_builder::TakeRevenue;
pub use xcm_executor::{traits::DropAssets, Assets};

use cumulus_primitives_core::relay_chain::v1::Id;
use cumulus_primitives_core::{DmpMessageHandler, XcmpMessageHandler};
/// Block number type used by the relay chain.
pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;

pub type TimeStampedPrice = orml_oracle::TimestampedValue<Price, primitives::Moment>;

// Priority of unsigned transactions
Expand Down Expand Up @@ -420,6 +425,46 @@ where
}
}

/// XcmMessageHandler of `DmpMessageHandler` and `XcmpMessageHandler` implementations.
/// if xcm is paused, the `max_weight` of each handle method is set to `0`.
///
/// Parameters type:
/// - `A`: `DmpMessageHandler` or `XcmpMessageHandler`
pub struct XcmMessageHandlerOrPaused<Runtime, A>(PhantomData<(Runtime, A)>);

impl<Runtime, A> DmpMessageHandler for XcmMessageHandlerOrPaused<Runtime, A>
where
Runtime: module_transaction_pause::Config,
A: DmpMessageHandler,
{
fn handle_dmp_messages(iter: impl Iterator<Item = (RelayChainBlockNumber, Vec<u8>)>, max_weight: Weight) -> Weight {
let xcm_paused: bool = module_transaction_pause::Pallet::<Runtime>::xcm_paused();
if xcm_paused {
A::handle_dmp_messages(iter, 0)
} else {
A::handle_dmp_messages(iter, max_weight)
}
}
}

impl<Runtime, A> XcmpMessageHandler for XcmMessageHandlerOrPaused<Runtime, A>
where
Runtime: module_transaction_pause::Config,
A: XcmpMessageHandler,
{
fn handle_xcmp_messages<'a, I: Iterator<Item = (Id, BlockNumber, &'a [u8])>>(
iter: I,
max_weight: Weight,
) -> Weight {
let xcm_paused: bool = module_transaction_pause::Pallet::<Runtime>::xcm_paused();
if xcm_paused {
A::handle_xcmp_messages(iter, 0)
} else {
A::handle_xcmp_messages(iter, max_weight)
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
5 changes: 3 additions & 2 deletions runtime/integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ orml-unknown-tokens = { path = "../../orml/unknown-tokens" }
orml-xcm = { path = "../../orml/xcm" }

module-transaction-payment = { path = "../../modules/transaction-payment" }
module-transaction-pause = { path = "../../modules/transaction-pause" }
module-asset-registry = { path = "../../modules/asset-registry" }
module-auction-manager = { path = "../../modules/auction-manager" }
module-cdp-engine = { path = "../../modules/cdp-engine" }
Expand Down Expand Up @@ -131,12 +132,12 @@ polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch =
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.13" }
kusama-runtime = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.13" }

xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", rev = "4d3bb9dd4fa2cd554a9970ffff816d9346269eaa" }
xcm-emulator = { git = "https://github.com/zqhxuyuan/xcm-simulator", branch = "handler" }

acala-service = { path = "../../node/service", features = ["with-all-runtime"] }

[features]
default = ["std"]
default = ["std", "with-karura-runtime"]
no_std = []
with-mandala-runtime = [
"acala-service/with-mandala-runtime",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,3 +768,112 @@ fn sibling_trap_assets_works() {
);
});
}

#[test]
fn dmp_queue_pause_resume_works() {
Karura::execute_with(|| {
assert_ok!(module_transaction_pause::Pallet::<Runtime>::pause_xcm(Origin::root()));
assert!(module_transaction_pause::Pallet::<Runtime>::xcm_paused());
});

let fee: u128 = 128_000_000;

KusamaNet::execute_with(|| {
assert_ok!(kusama_runtime::XcmPallet::reserve_transfer_assets(
kusama_runtime::Origin::signed(ALICE.into()),
Box::new(Parachain(2000).into().into()),
Box::new(
Junction::AccountId32 {
id: BOB,
network: NetworkId::Any
}
.into()
.into()
),
Box::new((Here, dollar(KSM)).into()),
0
));
});

Karura::execute_with(|| {
// the first message is not processed but remain in dmq-queue
assert!(module_transaction_pause::Pallet::<Runtime>::xcm_paused());
// Bob balance is 0 as the xcm message not executed
assert_eq!(Tokens::free_balance(KSM, &AccountId::from(BOB)), 0);

// resume the dmp-queue working
assert_ok!(module_transaction_pause::Pallet::<Runtime>::unpause_xcm(Origin::root()));
assert!(!module_transaction_pause::Pallet::<Runtime>::xcm_paused());
});

// the empty body implementation here is used to trigger send downward message to parachain,
// the previous message in the queue storage will be [first executed](https://github.com/paritytech/cumulus/blob/polkadot-v0.9.13/pallets/dmp-queue/src/lib.rs#L270).
// then the second message executed which is also get from storage by runtime.dmq_contents().
KusamaNet::execute_with(|| {});

Karura::execute_with(|| {
assert!(!module_transaction_pause::Pallet::<Runtime>::xcm_paused());
assert_eq!(
Tokens::free_balance(KSM, &AccountId::from(BOB)),
2 * dollar(KSM) - fee * 2
);
});
}

#[test]
fn xcmp_queue_pause_resume_works() {
fn karura_reserve_account() -> AccountId {
use sp_runtime::traits::AccountIdConversion;
polkadot_parachain::primitives::Sibling::from(2000).into_account()
}
Karura::execute_with(|| {
assert_ok!(Tokens::deposit(BNC, &AccountId::from(ALICE), 100 * dollar(BNC)));
});

Sibling::execute_with(|| {
assert_ok!(Tokens::deposit(BNC, &karura_reserve_account(), 100 * dollar(BNC)));
assert_ok!(module_transaction_pause::Pallet::<Runtime>::pause_xcm(Origin::root()));
assert!(module_transaction_pause::Pallet::<Runtime>::xcm_paused());
});

Karura::execute_with(|| {
assert_ok!(XTokens::transfer(
Origin::signed(ALICE.into()),
BNC,
10 * dollar(BNC),
Box::new(
MultiLocation::new(
1,
X2(
Parachain(2001),
Junction::AccountId32 {
network: NetworkId::Any,
id: BOB.into(),
}
)
)
.into()
),
1_000_000_000,
));

assert_eq!(Tokens::free_balance(BNC, &AccountId::from(ALICE)), 90 * dollar(BNC));
});

Sibling::execute_with(|| {
assert_eq!(Tokens::free_balance(BNC, &karura_reserve_account()), 100 * dollar(BNC));
assert_eq!(Tokens::free_balance(BNC, &AccountId::from(BOB)), 0);

// resume the dmp-queue working
assert_ok!(module_transaction_pause::Pallet::<Runtime>::unpause_xcm(Origin::root()));
assert!(!module_transaction_pause::Pallet::<Runtime>::xcm_paused());

assert_eq!(Tokens::free_balance(BNC, &karura_reserve_account()), 100 * dollar(BNC));
assert_eq!(Tokens::free_balance(BNC, &AccountId::from(BOB)), 0);
});

Sibling::execute_with(|| {
assert_eq!(Tokens::free_balance(BNC, &karura_reserve_account()), 90 * dollar(BNC));
assert_eq!(Tokens::free_balance(BNC, &AccountId::from(BOB)), 9_989_760_000_000);
});
}
4 changes: 4 additions & 0 deletions runtime/integration-tests/src/relaychain/kusama_test_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ decl_test_parachain! {
pub struct Karura {
Runtime = Runtime,
Origin = Origin,
XcmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, XcmpQueue>,
DmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, DmpQueue>,
new_ext = para_ext(2000),
}
}
Expand All @@ -48,6 +50,8 @@ decl_test_parachain! {
pub struct Sibling {
Runtime = Runtime,
Origin = Origin,
XcmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, XcmpQueue>,
DmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, DmpQueue>,
new_ext = para_ext(2001),
}
}
Expand Down
12 changes: 6 additions & 6 deletions runtime/integration-tests/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ mod karura_imports {
constants::parachains, create_x2_parachain_multilocation, get_all_module_accounts, AcalaOracle, AccountId,
AssetRegistry, AuctionManager, Authority, AuthoritysOriginId, Balance, Balances, BlockNumber, Call, CdpEngine,
CdpTreasury, CreateClassDeposit, CreateTokenDeposit, Currencies, CurrencyId, CurrencyIdConvert,
DataDepositPerByte, DefaultExchangeRate, Dex, EmergencyShutdown, Event, EvmAccounts, ExistentialDeposits,
FeePoolSize, FinancialCouncil, Get, GetNativeCurrencyId, HomaLite, Honzon, IdleScheduler, KarPerSecond,
KaruraFoundationAccounts, KsmPerSecond, KusdPerSecond, Loans, MaxTipsOfPriority, MinimumDebitValue,
MultiLocation, NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin, OriginCaller,
ParachainAccount, ParachainInfo, ParachainSystem, PolkadotXcm, Proxy, ProxyType, Ratio,
DataDepositPerByte, DefaultExchangeRate, Dex, DmpQueue, EmergencyShutdown, Event, EvmAccounts,
ExistentialDeposits, FeePoolSize, FinancialCouncil, Get, GetNativeCurrencyId, HomaLite, Honzon, IdleScheduler,
KarPerSecond, KaruraFoundationAccounts, KsmPerSecond, KusdPerSecond, Loans, MaxTipsOfPriority,
MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin,
OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, PolkadotXcm, Proxy, ProxyType, Ratio,
RelayChainBlockNumberProvider, RelayChainSovereignSubAccount, Runtime, Scheduler, Session, SessionManager,
SevenDays, SwapBalanceThreshold, System, Timestamp, TipPerWeightStep, TokenSymbol, Tokens, TreasuryPalletId,
Utility, Vesting, XTokens, XcmConfig, XcmExecutor, XcmUnbondFee, EVM, NFT,
Utility, Vesting, XTokens, XcmConfig, XcmExecutor, XcmUnbondFee, XcmpQueue, EVM, NFT,
};
pub use primitives::TradingPair;
pub use runtime_common::{calculate_asset_ratio, cent, dollar, millicent, KAR, KSM, KUSD, LKSM};
Expand Down
4 changes: 2 additions & 2 deletions runtime/karura/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1381,10 +1381,10 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type Event = Event;
type OnValidationData = ();
type SelfParaId = ParachainInfo;
type DmpMessageHandler = DmpQueue;
type DmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, DmpQueue>;
type ReservedDmpWeight = ReservedDmpWeight;
type OutboundXcmpMessageSource = XcmpQueue;
type XcmpMessageHandler = XcmpQueue;
type XcmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, XcmpQueue>;
type ReservedXcmpWeight = ReservedXcmpWeight;
}

Expand Down
4 changes: 2 additions & 2 deletions runtime/mandala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1598,10 +1598,10 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type Event = Event;
type OnValidationData = ();
type SelfParaId = ParachainInfo;
type DmpMessageHandler = DmpQueue;
type DmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, DmpQueue>;
type ReservedDmpWeight = ReservedDmpWeight;
type OutboundXcmpMessageSource = XcmpQueue;
type XcmpMessageHandler = XcmpQueue;
type XcmpMessageHandler = runtime_common::XcmMessageHandlerOrPaused<Runtime, XcmpQueue>;
type ReservedXcmpWeight = ReservedXcmpWeight;
}

Expand Down