diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index f641b428d4c6..7944d451e437 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -34,6 +34,7 @@ use bp_runtime::ChainId; use frame_support::{ parameter_types, traits::{ConstU32, Contains, Equals, Everything, Nothing}, + StoragePrefixedMap, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; @@ -168,6 +169,17 @@ impl Contains for SafeCallFilter { _ => (), }; + // Allow to removed dedicated storage items (called by governance-like) + if let RuntimeCall::System(frame_system::Call::kill_storage { keys }) = call { + return keys.iter().all(|k| { + // Allow resetting of Ethereum nonces in Rococo only. + k.starts_with(&snowbridge_pallet_inbound_queue::Nonce::::final_prefix()) || + k.starts_with( + &snowbridge_pallet_outbound_queue::Nonce::::final_prefix(), + ) + }); + } + matches!( call, RuntimeCall::PolkadotXcm( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 9e46dc086548..9861d88afe56 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -26,11 +26,14 @@ use bridge_hub_rococo_runtime::{ }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; -use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; +use frame_support::{ + dispatch::GetDispatchInfo, parameter_types, traits::ConstU8, StoragePrefixedMap, +}; use parachains_common::{ rococo::{consensus::RELAY_CHAIN_SLOT_DURATION_MILLIS, fee::WeightToFee}, AccountId, AuraId, Balance, SLOT_DURATION, }; +use snowbridge_core::ChannelId; use sp_consensus_aura::SlotDuration; use sp_core::H160; use sp_keyring::AccountKeyring::Alice; @@ -222,6 +225,75 @@ mod bridge_hub_westend_tests { ) } + #[test] + fn kill_ethereum_nonces_by_governance_works() { + let channel_id_one: ChannelId = [1; 32].into(); + let channel_id_two: ChannelId = [2; 32].into(); + let nonce = 42; + + // Reset a single inbound channel + bridge_hub_test_utils::test_cases::kill_storage_keys_by_governance_works::( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + Box::new(|call| RuntimeCall::System(call).encode()), + snowbridge_pallet_inbound_queue::Nonce::::hashed_key_for::( + channel_id_one, + ) + .to_vec(), + || { + snowbridge_pallet_inbound_queue::Nonce::::insert::( + channel_id_one, + nonce, + ); + snowbridge_pallet_inbound_queue::Nonce::::insert::( + channel_id_two, + nonce, + ); + }, + || { + assert_eq!( + snowbridge_pallet_inbound_queue::Nonce::::get(channel_id_one), + 0 + ); + assert_eq!( + snowbridge_pallet_inbound_queue::Nonce::::get(channel_id_two), + nonce + ); + }, + ); + + // Reset a single outbound channel + bridge_hub_test_utils::test_cases::kill_storage_keys_by_governance_works::( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + Box::new(|call| RuntimeCall::System(call).encode()), + snowbridge_pallet_outbound_queue::Nonce::::hashed_key_for::( + channel_id_one, + ) + .to_vec(), + || { + snowbridge_pallet_outbound_queue::Nonce::::insert::( + channel_id_one, + nonce, + ); + snowbridge_pallet_outbound_queue::Nonce::::insert::( + channel_id_two, + nonce, + ); + }, + || { + assert_eq!( + snowbridge_pallet_outbound_queue::Nonce::::get(channel_id_one), + 0 + ); + assert_eq!( + snowbridge_pallet_outbound_queue::Nonce::::get(channel_id_two), + nonce + ); + }, + ); + } + #[test] fn change_delivery_reward_by_governance_works() { bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index ce9396926449..edee39ef2116 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -72,7 +72,9 @@ pub type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; // Re-export test_case from `parachains-runtimes-test-utils` -pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; +pub use parachains_runtimes_test_utils::test_cases::{ + change_storage_constant_by_governance_works, kill_storage_keys_by_governance_works, +}; /// Prepare default runtime storage and run test within this context. pub fn run_test( diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs index 950d0498130e..87c8d70468b1 100644 --- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs @@ -91,3 +91,53 @@ pub fn change_storage_constant_by_governance_works( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + runtime_call_encode: Box) -> Vec>, + storage_constant_key: Vec, + initialize_storage: impl FnOnce() -> (), + assert_storage: impl FnOnce() -> (), +) where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config, + ValidatorIdOf: From>, +{ + let mut runtime = ExtBuilder::::default() + .with_collators(collator_session_key.collators()) + .with_session_keys(collator_session_key.session_keys()) + .with_para_id(runtime_para_id.into()) + .with_tracing() + .build(); + runtime.execute_with(|| { + initialize_storage(); + }); + runtime.execute_with(|| { + // encode `kill_storage` call + let kill_storage_call = runtime_call_encode(frame_system::Call::::kill_storage { + keys: vec![storage_constant_key.clone()], + }); + + // estimate - storing just 1 value + use frame_system::WeightInfo; + let require_weight_at_most = + ::SystemWeightInfo::kill_storage(1); + + // execute XCM with Transact to `set_storage` as governance does + assert_ok!(RuntimeHelper::::execute_as_governance( + kill_storage_call, + require_weight_at_most + ) + .ensure_complete()); + }); + runtime.execute_with(|| { + assert_storage(); + }); +}