diff --git a/Cargo.lock b/Cargo.lock
index effe0f2a34..1c46f4669b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -634,7 +634,7 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
[[package]]
name = "async-backing-primitives"
version = "0.9.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"sp-api",
"sp-consensus-slots",
@@ -6004,21 +6004,6 @@ dependencies = [
"syn 2.0.66",
]
-[[package]]
-name = "manual-xcm-rpc"
-version = "0.1.0"
-dependencies = [
- "cumulus-primitives-core",
- "flume 0.10.14",
- "futures 0.3.30",
- "hex-literal 0.3.4",
- "jsonrpsee",
- "parity-scale-codec",
- "staging-xcm",
- "tokio",
- "xcm-primitives 0.1.1",
-]
-
[[package]]
name = "maplit"
version = "1.0.2"
@@ -6548,6 +6533,21 @@ dependencies = [
"sp-runtime",
]
+[[package]]
+name = "moonbeam-dev-rpc"
+version = "0.1.0"
+dependencies = [
+ "cumulus-primitives-core",
+ "flume 0.10.14",
+ "futures 0.3.30",
+ "hex-literal 0.3.4",
+ "jsonrpsee",
+ "parity-scale-codec",
+ "staging-xcm",
+ "tokio",
+ "xcm-primitives 0.1.1",
+]
+
[[package]]
name = "moonbeam-evm-tracer"
version = "0.1.0"
@@ -6843,6 +6843,7 @@ dependencies = [
"pallet-collective",
"pallet-conviction-voting",
"pallet-crowdloan-rewards",
+ "pallet-emergency-para-xcm",
"pallet-erc20-xcm-bridge",
"pallet-ethereum",
"pallet-ethereum-xcm",
@@ -7057,11 +7058,11 @@ dependencies = [
"jsonrpsee",
"libsecp256k1",
"log",
- "manual-xcm-rpc",
"maplit",
"moonbase-runtime",
"moonbeam-cli-opt",
"moonbeam-core-primitives",
+ "moonbeam-dev-rpc",
"moonbeam-finality-rpc",
"moonbeam-primitives-ext",
"moonbeam-relay-encoder",
@@ -7252,6 +7253,7 @@ dependencies = [
"pallet-collective",
"pallet-conviction-voting",
"pallet-crowdloan-rewards",
+ "pallet-emergency-para-xcm",
"pallet-erc20-xcm-bridge",
"pallet-ethereum",
"pallet-ethereum-xcm",
@@ -7652,7 +7654,7 @@ dependencies = [
[[package]]
name = "nimbus-consensus"
version = "0.9.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"async-backing-primitives",
"async-trait",
@@ -7692,7 +7694,7 @@ dependencies = [
[[package]]
name = "nimbus-primitives"
version = "0.9.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"async-trait",
"frame-benchmarking",
@@ -8268,7 +8270,7 @@ dependencies = [
[[package]]
name = "pallet-async-backing"
version = "0.9.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"cumulus-pallet-parachain-system",
"cumulus-primitives-core",
@@ -8288,7 +8290,7 @@ dependencies = [
[[package]]
name = "pallet-author-inherent"
version = "0.9.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"frame-benchmarking",
"frame-support",
@@ -8307,7 +8309,7 @@ dependencies = [
[[package]]
name = "pallet-author-mapping"
version = "2.0.5"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"frame-benchmarking",
"frame-support",
@@ -8326,7 +8328,7 @@ dependencies = [
[[package]]
name = "pallet-author-slot-filter"
version = "0.9.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"frame-benchmarking",
"frame-support",
@@ -8687,7 +8689,7 @@ dependencies = [
[[package]]
name = "pallet-emergency-para-xcm"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"cumulus-pallet-parachain-system",
"cumulus-primitives-core",
@@ -9403,7 +9405,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-xcm"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"cumulus-primitives-core",
"evm",
@@ -9655,7 +9657,7 @@ dependencies = [
[[package]]
name = "pallet-maintenance-mode"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"cumulus-primitives-core",
"frame-support",
@@ -9708,7 +9710,7 @@ dependencies = [
[[package]]
name = "pallet-migrations"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"frame-benchmarking",
"frame-support",
@@ -10045,7 +10047,7 @@ dependencies = [
[[package]]
name = "pallet-randomness"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"environmental",
"frame-benchmarking",
@@ -10123,7 +10125,7 @@ dependencies = [
[[package]]
name = "pallet-relay-storage-roots"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"cumulus-pallet-parachain-system",
"cumulus-primitives-core",
@@ -14900,7 +14902,7 @@ dependencies = [
[[package]]
name = "session-keys-primitives"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"async-trait",
"frame-support",
@@ -18636,7 +18638,7 @@ dependencies = [
[[package]]
name = "xcm-primitives"
version = "0.1.0"
-source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972"
+source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6"
dependencies = [
"frame-support",
"impl-trait-for-tuples",
diff --git a/Cargo.toml b/Cargo.toml
index 0578bfc1bf..269ca779ef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,8 +2,8 @@
exclude = ["bin/utils/moonkey"]
members = [
"bin/utils/moonkey",
+ "client/rpc/dev",
"client/rpc/finality",
- "client/rpc/manual-xcm",
"client/vrf",
"node",
"node/cli",
@@ -117,8 +117,8 @@ moonbeam-cli = { path = "node/cli", default-features = false }
moonbeam-cli-opt = { path = "node/cli-opt", default-features = false }
moonbeam-service = { path = "node/service", default-features = false }
-manual-xcm-rpc = { path = "client/rpc/manual-xcm" }
moonbeam-client-evm-tracing = { path = "client/evm-tracing" }
+moonbeam-dev-rpc = { path = "client/rpc/dev" }
moonbeam-finality-rpc = { path = "client/rpc/finality" }
moonbeam-rpc-core-debug = { path = "client/rpc-core/debug" }
moonbeam-rpc-core-trace = { path = "client/rpc-core/trace" }
diff --git a/client/rpc/manual-xcm/Cargo.toml b/client/rpc/dev/Cargo.toml
similarity index 96%
rename from client/rpc/manual-xcm/Cargo.toml
rename to client/rpc/dev/Cargo.toml
index 010bdd1669..87558951a0 100644
--- a/client/rpc/manual-xcm/Cargo.toml
+++ b/client/rpc/dev/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "manual-xcm-rpc"
+name = "moonbeam-dev-rpc"
authors = { workspace = true }
edition = "2021"
homepage = "https://moonbeam.network"
diff --git a/client/rpc/manual-xcm/src/lib.rs b/client/rpc/dev/src/lib.rs
similarity index 90%
rename from client/rpc/manual-xcm/src/lib.rs
rename to client/rpc/dev/src/lib.rs
index bc65717144..6ac9725ecc 100644
--- a/client/rpc/manual-xcm/src/lib.rs
+++ b/client/rpc/dev/src/lib.rs
@@ -13,6 +13,7 @@
// You should have received a copy of the GNU General Public License
// along with Moonbeam. If not, see .
+
use cumulus_primitives_core::ParaId;
use cumulus_primitives_core::XcmpMessageFormat;
use jsonrpsee::{
@@ -28,12 +29,10 @@ use xcm::opaque::lts::Weight;
use xcm::v4::prelude::*;
use xcm_primitives::DEFAULT_PROOF_SIZE;
-/// This RPC interface is used to manually submit XCM messages that will be injected into a
-/// parachain-enabled runtime. This allows testing XCM logic in a controlled way in integration
-/// tests.
+/// This RPC interface is used to provide methods in dev mode only
#[rpc(server)]
#[jsonrpsee::core::async_trait]
-pub trait ManualXcmApi {
+pub trait DevApi {
/// Inject a downward xcm message - A message that comes from the relay chain.
/// You may provide an arbitrary message, or if you provide an emtpy byte array,
/// Then a default message (DOT transfer down to ALITH) will be injected
@@ -53,15 +52,20 @@ pub trait ManualXcmApi {
/// transfer of the sending paraId's native token will be injected.
#[method(name = "xcm_injectHrmpMessage")]
async fn inject_hrmp_message(&self, sender: ParaId, message: Vec) -> RpcResult<()>;
+
+ /// Skip N relay blocks, for testing purposes
+ #[method(name = "test_skipRelayBlocks")]
+ async fn skip_relay_blocks(&self, n: u32) -> RpcResult<()>;
}
-pub struct ManualXcm {
+pub struct DevRpc {
pub downward_message_channel: flume::Sender>,
pub hrmp_message_channel: flume::Sender<(ParaId, Vec)>,
+ pub additional_relay_offset: std::sync::Arc,
}
#[jsonrpsee::core::async_trait]
-impl ManualXcmApiServer for ManualXcm {
+impl DevApiServer for DevRpc {
async fn inject_downward_message(&self, msg: Vec) -> RpcResult<()> {
let downward_message_channel = self.downward_message_channel.clone();
// If no message is supplied, inject a default one.
@@ -148,6 +152,12 @@ impl ManualXcmApiServer for ManualXcm {
Ok(())
}
+
+ async fn skip_relay_blocks(&self, n: u32) -> RpcResult<()> {
+ self.additional_relay_offset
+ .fetch_add(n, std::sync::atomic::Ordering::SeqCst);
+ Ok(())
+ }
}
// This bit cribbed from frontier.
diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml
index 84ceec9b91..9f3a354009 100644
--- a/node/service/Cargo.toml
+++ b/node/service/Cargo.toml
@@ -28,7 +28,7 @@ tokio = { workspace = true, features = ["macros", "sync"] }
trie-root = { workspace = true }
# Moonbeam
-manual-xcm-rpc = { workspace = true }
+moonbeam-dev-rpc = { workspace = true }
moonbeam-cli-opt = { workspace = true }
moonbeam-core-primitives = { workspace = true }
moonbeam-finality-rpc = { workspace = true }
diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs
index e9ffe93663..5c15b886fc 100644
--- a/node/service/src/lib.rs
+++ b/node/service/src/lib.rs
@@ -774,7 +774,7 @@ where
fee_history_cache: fee_history_cache.clone(),
network: network.clone(),
sync: sync.clone(),
- xcm_senders: None,
+ dev_rpc_data: None,
block_data_cache: block_data_cache.clone(),
overrides: overrides.clone(),
forced_parent_hashes,
@@ -1204,7 +1204,7 @@ where
let overrides = Arc::new(StorageOverrideHandler::new(client.clone()));
let fee_history_limit = rpc_config.fee_history_limit;
let mut command_sink = None;
- let mut xcm_senders = None;
+ let mut dev_rpc_data = None;
let collator = config.role.is_authority();
if collator {
@@ -1269,7 +1269,12 @@ where
// Create channels for mocked XCM messages.
let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::>(100);
let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec)>(100);
- xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
+ let additional_relay_offset = Arc::new(std::sync::atomic::AtomicU32::new(0));
+ dev_rpc_data = Some((
+ downward_xcm_sender,
+ hrmp_xcm_sender,
+ additional_relay_offset.clone(),
+ ));
let client_clone = client.clone();
let keystore_clone = keystore_container.keystore().clone();
@@ -1304,6 +1309,7 @@ where
let maybe_current_para_head = client_set_aside_for_cidp.expect_header(block);
let downward_xcm_receiver = downward_xcm_receiver.clone();
let hrmp_xcm_receiver = hrmp_xcm_receiver.clone();
+ let additional_relay_offset = additional_relay_offset.clone();
let client_for_xcm = client_set_aside_for_cidp.clone();
async move {
@@ -1324,7 +1330,8 @@ where
let mocked_parachain = MockValidationDataInherentDataProvider {
current_para_block,
current_para_block_head,
- relay_offset: 1000,
+ relay_offset: 1000
+ + additional_relay_offset.load(std::sync::atomic::Ordering::SeqCst),
relay_blocks_per_para_block: 2,
// TODO: Recheck
para_blocks_per_relay_epoch: 10,
@@ -1440,7 +1447,7 @@ where
fee_history_cache: fee_history_cache.clone(),
network: network.clone(),
sync: sync.clone(),
- xcm_senders: xcm_senders.clone(),
+ dev_rpc_data: dev_rpc_data.clone(),
overrides: overrides.clone(),
block_data_cache: block_data_cache.clone(),
forced_parent_hashes: None,
diff --git a/node/service/src/rpc.rs b/node/service/src/rpc.rs
index 9ab4095fc0..92043cd9cf 100644
--- a/node/service/src/rpc.rs
+++ b/node/service/src/rpc.rs
@@ -130,7 +130,11 @@ pub struct FullDeps {
/// Fee history cache.
pub fee_history_cache: FeeHistoryCache,
/// Channels for manual xcm messages (downward, hrmp)
- pub xcm_senders: Option<(flume::Sender>, flume::Sender<(ParaId, Vec)>)>,
+ pub dev_rpc_data: Option<(
+ flume::Sender>,
+ flume::Sender<(ParaId, Vec)>,
+ Arc,
+ )>,
/// Ethereum data access overrides.
pub overrides: Arc>,
/// Cache for Ethereum block data.
@@ -173,7 +177,7 @@ where
Eth, EthApiServer, EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, Net,
NetApiServer, Web3, Web3ApiServer,
};
- use manual_xcm_rpc::{ManualXcm, ManualXcmApiServer};
+ use moonbeam_dev_rpc::{DevApiServer, DevRpc};
use moonbeam_finality_rpc::{MoonbeamFinality, MoonbeamFinalityApiServer};
use moonbeam_rpc_debug::{Debug, DebugServer};
use moonbeam_rpc_trace::{Trace, TraceServer};
@@ -198,7 +202,7 @@ where
max_past_logs,
fee_history_limit,
fee_history_cache,
- xcm_senders,
+ dev_rpc_data,
overrides,
block_data_cache,
forced_parent_hashes,
@@ -318,11 +322,14 @@ where
)?;
};
- if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
+ if let Some((downward_message_channel, hrmp_message_channel, additional_relay_offset)) =
+ dev_rpc_data
+ {
io.merge(
- ManualXcm {
+ DevRpc {
downward_message_channel,
hrmp_message_channel,
+ additional_relay_offset,
}
.into_rpc(),
)?;
diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs
index 6a591538cd..06b3a46cf8 100644
--- a/runtime/moonbase/src/lib.rs
+++ b/runtime/moonbase/src/lib.rs
@@ -760,7 +760,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type SelfParaId = ParachainInfo;
type ReservedDmpWeight = ReservedDmpWeight;
type OutboundXcmpMessageSource = XcmpQueue;
- type XcmpMessageHandler = EmergencyParaXcm;
+ type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = EmergencyParaXcm;
type ConsensusHook = ConsensusHookWrapperForRelayTimestamp;
diff --git a/runtime/moonbase/src/xcm_config.rs b/runtime/moonbase/src/xcm_config.rs
index 2141cefdcb..0dc065c641 100644
--- a/runtime/moonbase/src/xcm_config.rs
+++ b/runtime/moonbase/src/xcm_config.rs
@@ -459,17 +459,24 @@ impl pallet_message_queue::Config for Runtime {
type IdleMaxServiceWeight = MessageQueueServiceWeight;
}
+pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse<
+ EnsureRoot,
+ pallet_collective::EnsureProportionAtLeast,
+>;
+
+pub type ResumeXcmOrigin = EitherOfDiverse<
+ EnsureRoot,
+ pallet_collective::EnsureProportionAtLeast,
+>;
+
impl pallet_emergency_para_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type CheckAssociatedRelayNumber =
cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling);
- type XcmpMessageHandler = XcmpQueue;
type PausedThreshold = ConstU32<300>;
- type FastAuthorizeUpgradeOrigin =
- pallet_collective::EnsureProportionAtLeast;
- type PausedToNormalOrigin =
- pallet_collective::EnsureProportionAtLeast;
+ type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin;
+ type PausedToNormalOrigin = ResumeXcmOrigin;
}
// Our AssetType. For now we only handle Xcm Assets
diff --git a/runtime/moonbeam/Cargo.toml b/runtime/moonbeam/Cargo.toml
index 66c4d19981..77aedbefcb 100644
--- a/runtime/moonbeam/Cargo.toml
+++ b/runtime/moonbeam/Cargo.toml
@@ -32,6 +32,7 @@ moonbeam-xcm-benchmarks = { workspace = true }
pallet-asset-manager = { workspace = true }
pallet-author-mapping = { workspace = true }
pallet-crowdloan-rewards = { workspace = true }
+pallet-emergency-para-xcm = { workspace = true }
pallet-erc20-xcm-bridge = { workspace = true }
pallet-ethereum-xcm = { workspace = true }
pallet-evm-chain-id = { workspace = true }
@@ -233,6 +234,7 @@ std = [
"pallet-collective/std",
"pallet-conviction-voting/std",
"pallet-crowdloan-rewards/std",
+ "pallet-emergency-para-xcm/std",
"pallet-erc20-xcm-bridge/std",
"pallet-evm-chain-id/std",
"pallet-ethereum-xcm/std",
diff --git a/runtime/moonbeam/src/lib.rs b/runtime/moonbeam/src/lib.rs
index 551e4f965c..ec0bfebc2c 100644
--- a/runtime/moonbeam/src/lib.rs
+++ b/runtime/moonbeam/src/lib.rs
@@ -21,8 +21,8 @@
//! * Moonbeam tokenomics
#![cfg_attr(not(feature = "std"), no_std)]
-// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
-#![recursion_limit = "256"]
+// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512.
+#![recursion_limit = "512"]
// Make the WASM binary available.
#[cfg(feature = "std")]
@@ -710,8 +710,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type OutboundXcmpMessageSource = XcmpQueue;
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
- type CheckAssociatedRelayNumber =
- cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
+ type CheckAssociatedRelayNumber = EmergencyParaXcm;
type ConsensusHook = ConsensusHookWrapperForRelayTimestamp;
type DmpQueue = frame_support::traits::EnqueueWithOrigin;
type WeightInfo = moonbeam_weights::cumulus_pallet_parachain_system::WeightInfo;
@@ -1454,6 +1453,7 @@ construct_runtime! {
Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 110,
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 111,
EvmForeignAssets: pallet_moonbeam_foreign_assets::{Pallet, Call, Storage, Event} = 114,
+ EmergencyParaXcm: pallet_emergency_para_xcm::{Pallet, Call, Storage, Event} = 116,
// Utils
RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 112,
diff --git a/runtime/moonbeam/src/xcm_config.rs b/runtime/moonbeam/src/xcm_config.rs
index 9e8ea4cd57..e87500a227 100644
--- a/runtime/moonbeam/src/xcm_config.rs
+++ b/runtime/moonbeam/src/xcm_config.rs
@@ -18,9 +18,10 @@
//!
use super::{
- governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees, Erc20XcmBridge,
- MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime,
- RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
+ governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees,
+ EmergencyParaXcm, Erc20XcmBridge, MaintenanceMode, MessageQueue, OpenTechCommitteeInstance,
+ ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights,
+ RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
};
use frame_support::{
@@ -442,11 +443,31 @@ impl pallet_message_queue::Config for Runtime {
// The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
type QueueChangeHandler = NarrowOriginToSibling;
// NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins
- type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling);
+ type QueuePausedQuery = EmergencyParaXcm;
type WeightInfo = moonbeam_weights::pallet_message_queue::WeightInfo;
type IdleMaxServiceWeight = MessageQueueServiceWeight;
}
+pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse<
+ EnsureRoot,
+ pallet_collective::EnsureProportionAtLeast,
+>;
+
+pub type ResumeXcmOrigin = EitherOfDiverse<
+ EnsureRoot,
+ pallet_collective::EnsureProportionAtLeast,
+>;
+
+impl pallet_emergency_para_xcm::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type CheckAssociatedRelayNumber =
+ cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
+ type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling);
+ type PausedThreshold = ConstU32<300>;
+ type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin;
+ type PausedToNormalOrigin = ResumeXcmOrigin;
+}
+
// Our AssetType. For now we only handle Xcm Assets
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub enum AssetType {
diff --git a/runtime/moonriver/Cargo.toml b/runtime/moonriver/Cargo.toml
index 1bf5e5c6a4..6f7fd19d11 100644
--- a/runtime/moonriver/Cargo.toml
+++ b/runtime/moonriver/Cargo.toml
@@ -32,6 +32,7 @@ moonbeam-xcm-benchmarks = { workspace = true }
pallet-asset-manager = { workspace = true }
pallet-author-mapping = { workspace = true }
pallet-crowdloan-rewards = { workspace = true }
+pallet-emergency-para-xcm = { workspace = true }
pallet-erc20-xcm-bridge = { workspace = true }
pallet-ethereum-xcm = { workspace = true }
pallet-evm-chain-id = { workspace = true }
@@ -234,6 +235,7 @@ std = [
"pallet-collective/std",
"pallet-conviction-voting/std",
"pallet-crowdloan-rewards/std",
+ "pallet-emergency-para-xcm/std",
"pallet-erc20-xcm-bridge/std",
"pallet-evm-chain-id/std",
"pallet-ethereum-xcm/std",
diff --git a/runtime/moonriver/src/lib.rs b/runtime/moonriver/src/lib.rs
index f1975cbc68..305273a80d 100644
--- a/runtime/moonriver/src/lib.rs
+++ b/runtime/moonriver/src/lib.rs
@@ -21,8 +21,8 @@
//! * Moonriver tokenomics
#![cfg_attr(not(feature = "std"), no_std)]
-// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
-#![recursion_limit = "256"]
+// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512.
+#![recursion_limit = "512"]
// Make the WASM binary available.
#[cfg(feature = "std")]
@@ -746,8 +746,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type OutboundXcmpMessageSource = XcmpQueue;
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
- type CheckAssociatedRelayNumber =
- cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
+ type CheckAssociatedRelayNumber = EmergencyParaXcm;
type ConsensusHook = ConsensusHookWrapperForRelayTimestamp;
type DmpQueue = frame_support::traits::EnqueueWithOrigin;
type WeightInfo = moonriver_weights::cumulus_pallet_parachain_system::WeightInfo;
@@ -1457,6 +1456,7 @@ construct_runtime! {
Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 110,
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 111,
EvmForeignAssets: pallet_moonbeam_foreign_assets::{Pallet, Call, Storage, Event} = 114,
+ EmergencyParaXcm: pallet_emergency_para_xcm::{Pallet, Call, Storage, Event} = 116,
// Utils
RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 112,
diff --git a/runtime/moonriver/src/xcm_config.rs b/runtime/moonriver/src/xcm_config.rs
index 26f8d83eb2..9ebce3cd75 100644
--- a/runtime/moonriver/src/xcm_config.rs
+++ b/runtime/moonriver/src/xcm_config.rs
@@ -18,9 +18,10 @@
//!
use super::{
- governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees, Erc20XcmBridge,
- MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime,
- RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
+ governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees,
+ EmergencyParaXcm, Erc20XcmBridge, MaintenanceMode, MessageQueue, OpenTechCommitteeInstance,
+ ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights,
+ RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
};
use frame_support::{
@@ -450,11 +451,31 @@ impl pallet_message_queue::Config for Runtime {
// The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
type QueueChangeHandler = NarrowOriginToSibling;
// NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins
- type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling);
+ type QueuePausedQuery = EmergencyParaXcm;
type WeightInfo = moonriver_weights::pallet_message_queue::WeightInfo;
type IdleMaxServiceWeight = MessageQueueServiceWeight;
}
+pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse<
+ EnsureRoot,
+ pallet_collective::EnsureProportionAtLeast,
+>;
+
+pub type ResumeXcmOrigin = EitherOfDiverse<
+ EnsureRoot,
+ pallet_collective::EnsureProportionAtLeast,
+>;
+
+impl pallet_emergency_para_xcm::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type CheckAssociatedRelayNumber =
+ cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
+ type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling);
+ type PausedThreshold = ConstU32<300>;
+ type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin;
+ type PausedToNormalOrigin = ResumeXcmOrigin;
+}
+
// Our AssetType. For now we only handle Xcm Assets
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub enum AssetType {
diff --git a/test/suites/dev/moonbase/test-xcm-v4/test-auto-pause-xcm.ts b/test/suites/dev/moonbase/test-xcm-v4/test-auto-pause-xcm.ts
new file mode 100644
index 0000000000..29c91c0b37
--- /dev/null
+++ b/test/suites/dev/moonbase/test-xcm-v4/test-auto-pause-xcm.ts
@@ -0,0 +1,146 @@
+import "@moonbeam-network/api-augment";
+import { beforeAll, customDevRpcRequest, describeSuite, expect } from "@moonwall/cli";
+
+import { KeyringPair } from "@polkadot/keyring/types";
+import { generateKeyringPair } from "@moonwall/util";
+import {
+ XcmFragment,
+ RawXcmMessage,
+ sovereignAccountOfSibling,
+ injectHrmpMessage,
+} from "../../../../helpers/xcm.js";
+
+const foreign_para_id = 2000;
+
+describeSuite({
+ id: "D014134",
+ title: "Auto-pause XCM",
+ foundationMethods: "dev",
+ testCases: ({ context, it, log }) => {
+ let transferredBalance: bigint;
+ let sovereignAddress: string;
+ let random: KeyringPair;
+ let balancesPalletIndex: number;
+
+ beforeAll(async () => {
+ random = generateKeyringPair();
+ sovereignAddress = sovereignAccountOfSibling(context, 2000);
+ transferredBalance = 1_000_000_000_000_000n;
+
+ await context.createBlock(
+ context.polkadotJs().tx.balances.transferAllowDeath(sovereignAddress, transferredBalance),
+ { allowFailures: false }
+ );
+
+ const balance = (
+ await context.polkadotJs().query.system.account(sovereignAddress)
+ ).data.free.toBigInt();
+ expect(balance).to.eq(transferredBalance);
+
+ const metadata = await context.polkadotJs().rpc.state.getMetadata();
+ balancesPalletIndex = metadata.asLatest.pallets
+ .find(({ name }) => name.toString() == "Balances")!
+ .index.toNumber();
+ });
+
+ it({
+ id: "T01",
+ title: "Should automatically pause xcm when block production is stuck",
+ test: async function () {
+ await context.createBlock();
+
+ // XCM Mode should be equal to Normal
+ expect((await context.polkadotJs().query.emergencyParaXcm.mode()).isNormal).to.be.true;
+
+ // Create a dummy xcm message to test auto-pause
+ const xcmMessage = new XcmFragment({
+ assets: [
+ {
+ multilocation: {
+ parents: 0,
+ interior: {
+ X1: { PalletInstance: balancesPalletIndex },
+ },
+ },
+ fungible: transferredBalance,
+ },
+ ],
+ beneficiary: random.address,
+ })
+ .withdraw_asset()
+ .clear_origin()
+ .buy_execution()
+ .deposit_asset_v3()
+ .as_v4();
+
+ // Inject an XCM message that should be included in the next block but not executed
+ await injectHrmpMessage(context, foreign_para_id, {
+ type: "XcmVersionedXcm",
+ payload: xcmMessage,
+ } as RawXcmMessage);
+
+ // Simulate block production stall (skip more than PausedThreshold relay blocks)
+ await customDevRpcRequest("test_skipRelayBlocks", [301]);
+
+ // Create a new block, this block should pause XCM incoming execution
+ await context.createBlock([], {
+ expectEvents: [context.polkadotJs().events.emergencyParaXcm.EnteredPausedXcmMode],
+ allowFailures: false,
+ });
+
+ // XCM Mode should be equal to Paused
+ expect((await context.polkadotJs().query.emergencyParaXcm.mode()).isPaused).to.be.true;
+
+ // Produce some blocks when XCm is Paused
+ await context.createBlock();
+ await context.createBlock();
+
+ // The sovereign account of foreign parachain sould still have funds
+ const balance = (
+ await context.polkadotJs().query.system.account(sovereignAddress)
+ ).data.free.toBigInt();
+ expect(balance, "Sovereign account balance has changed").to.eq(transferredBalance);
+
+ // The beneficiary of the XCM message should not have funds
+ const randomBalance = (
+ await context.polkadotJs().query.system.account(random.address)
+ ).data.free.toBigInt();
+ expect(randomBalance, "beneficiary of the XCM message receive funds").to.eq(0n);
+
+ // Sudo should be able to resume XCM execution
+ await context.createBlock(
+ context
+ .polkadotJs()
+ .tx.sudo.sudo(context.polkadotJs().tx.emergencyParaXcm.pausedToNormal()),
+ {
+ expectEvents: [context.polkadotJs().events.emergencyParaXcm.NormalXcmOperationResumed],
+ allowFailures: false,
+ }
+ );
+
+ // XCM Mode should be equal to Normal
+ expect((await context.polkadotJs().query.emergencyParaXcm.mode()).isNormal).to.be.true;
+
+ // The next block should execute previous XCM message
+ await context.createBlock([], {
+ expectEvents: [],
+ allowFailures: false,
+ });
+
+ // The sovereign account of foreign parachain should now be empty
+ const balance2 = (
+ await context.polkadotJs().query.system.account(sovereignAddress)
+ ).data.free.toBigInt();
+ expect(balance2, "Sovereign account not empty, transfer has failed").to.eq(0n);
+
+ // The beneficiary of the XCM message should now have funds
+ const randomBalance2 = (
+ await context.polkadotJs().query.system.account(random.address)
+ ).data.free.toBigInt();
+ expect(randomBalance2, "beneficiary balance not increased, transfer has failed").to.not.eq(
+ 0n
+ );
+ },
+ });
+ },
+});