diff --git a/runtime/kusama/src/xcm_config.rs b/runtime/kusama/src/xcm_config.rs index 7d69c1aad487..abc52f42c1be 100644 --- a/runtime/kusama/src/xcm_config.rs +++ b/runtime/kusama/src/xcm_config.rs @@ -22,7 +22,7 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Everything, Nothing}, + traits::{Contains, Everything, Nothing}, weights::Weight, }; use runtime_common::{xcm_sender, ToAuthor}; @@ -135,6 +135,185 @@ pub type Barrier = ( AllowSubscriptionsFrom<OnlyParachains>, ); +/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly +/// account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. +pub struct SafeCallFilter; +impl Contains<RuntimeCall> for SafeCallFilter { + fn contains(t: &RuntimeCall) -> bool { + match t { + RuntimeCall::System( + frame_system::Call::fill_block { .. } | + frame_system::Call::kill_prefix { .. } | + frame_system::Call::set_heap_pages { .. }, + ) | + RuntimeCall::Babe(..) | + RuntimeCall::Timestamp(..) | + RuntimeCall::Indices(..) | + RuntimeCall::Balances(..) | + RuntimeCall::Staking( + pallet_staking::Call::bond { .. } | + pallet_staking::Call::bond_extra { .. } | + pallet_staking::Call::unbond { .. } | + pallet_staking::Call::withdraw_unbonded { .. } | + pallet_staking::Call::validate { .. } | + pallet_staking::Call::chill { .. } | + pallet_staking::Call::set_payee { .. } | + pallet_staking::Call::set_controller { .. } | + pallet_staking::Call::set_validator_count { .. } | + pallet_staking::Call::increase_validator_count { .. } | + pallet_staking::Call::scale_validator_count { .. } | + pallet_staking::Call::force_no_eras { .. } | + pallet_staking::Call::force_new_era { .. } | + pallet_staking::Call::set_invulnerables { .. } | + pallet_staking::Call::force_unstake { .. } | + pallet_staking::Call::force_new_era_always { .. } | + pallet_staking::Call::payout_stakers { .. } | + pallet_staking::Call::unbond { .. } | + pallet_staking::Call::reap_stash { .. } | + pallet_staking::Call::set_staking_configs { .. } | + pallet_staking::Call::chill_other { .. } | + pallet_staking::Call::force_apply_min_commission { .. }, + ) | + RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | + RuntimeCall::Grandpa(..) | + RuntimeCall::ImOnline(..) | + RuntimeCall::Democracy( + pallet_democracy::Call::second { .. } | + pallet_democracy::Call::vote { .. } | + pallet_democracy::Call::emergency_cancel { .. } | + pallet_democracy::Call::fast_track { .. } | + pallet_democracy::Call::veto_external { .. } | + pallet_democracy::Call::cancel_referendum { .. } | + pallet_democracy::Call::delegate { .. } | + pallet_democracy::Call::undelegate { .. } | + pallet_democracy::Call::clear_public_proposals { .. } | + pallet_democracy::Call::unlock { .. } | + pallet_democracy::Call::remove_vote { .. } | + pallet_democracy::Call::remove_other_vote { .. } | + pallet_democracy::Call::blacklist { .. } | + pallet_democracy::Call::cancel_proposal { .. }, + ) | + RuntimeCall::Council( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::close_old_weight { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | + RuntimeCall::TechnicalCommittee( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::close_old_weight { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | + RuntimeCall::PhragmenElection( + pallet_elections_phragmen::Call::remove_voter { .. } | + pallet_elections_phragmen::Call::submit_candidacy { .. } | + pallet_elections_phragmen::Call::renounce_candidacy { .. } | + pallet_elections_phragmen::Call::remove_member { .. } | + pallet_elections_phragmen::Call::clean_defunct_voters { .. }, + ) | + RuntimeCall::TechnicalMembership( + pallet_membership::Call::add_member { .. } | + pallet_membership::Call::remove_member { .. } | + pallet_membership::Call::swap_member { .. } | + pallet_membership::Call::change_key { .. } | + pallet_membership::Call::set_prime { .. } | + pallet_membership::Call::clear_prime { .. }, + ) | + RuntimeCall::Treasury(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda( + pallet_referenda::Call::place_decision_deposit { .. } | + pallet_referenda::Call::refund_decision_deposit { .. } | + pallet_referenda::Call::cancel { .. } | + pallet_referenda::Call::kill { .. } | + pallet_referenda::Call::nudge_referendum { .. } | + pallet_referenda::Call::one_fewer_deciding { .. }, + ) | + RuntimeCall::FellowshipCollective(..) | + RuntimeCall::FellowshipReferenda( + pallet_referenda::Call::place_decision_deposit { .. } | + pallet_referenda::Call::refund_decision_deposit { .. } | + pallet_referenda::Call::cancel { .. } | + pallet_referenda::Call::kill { .. } | + pallet_referenda::Call::nudge_referendum { .. } | + pallet_referenda::Call::one_fewer_deciding { .. }, + ) | + RuntimeCall::Claims( + super::claims::Call::claim { .. } | + super::claims::Call::mint_claim { .. } | + super::claims::Call::move_claim { .. }, + ) | + RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | + RuntimeCall::Identity( + pallet_identity::Call::add_registrar { .. } | + pallet_identity::Call::set_identity { .. } | + pallet_identity::Call::clear_identity { .. } | + pallet_identity::Call::request_judgement { .. } | + pallet_identity::Call::cancel_request { .. } | + pallet_identity::Call::set_fee { .. } | + pallet_identity::Call::set_account_id { .. } | + pallet_identity::Call::set_fields { .. } | + pallet_identity::Call::provide_judgement { .. } | + pallet_identity::Call::kill_identity { .. } | + pallet_identity::Call::add_sub { .. } | + pallet_identity::Call::rename_sub { .. } | + pallet_identity::Call::remove_sub { .. } | + pallet_identity::Call::quit_sub { .. }, + ) | + RuntimeCall::Society( + pallet_society::Call::bid { .. } | + pallet_society::Call::unbid { .. } | + pallet_society::Call::vouch { .. } | + pallet_society::Call::unvouch { .. } | + pallet_society::Call::vote { .. } | + pallet_society::Call::defender_vote { .. } | + pallet_society::Call::payout { .. } | + pallet_society::Call::unfound { .. } | + pallet_society::Call::judge_suspended_member { .. } | + pallet_society::Call::judge_suspended_candidate { .. } | + pallet_society::Call::set_max_members { .. }, + ) | + RuntimeCall::Recovery(..) | + RuntimeCall::Vesting(..) | + RuntimeCall::Bounties( + pallet_bounties::Call::propose_bounty { .. } | + pallet_bounties::Call::approve_bounty { .. } | + pallet_bounties::Call::propose_curator { .. } | + pallet_bounties::Call::unassign_curator { .. } | + pallet_bounties::Call::accept_curator { .. } | + pallet_bounties::Call::award_bounty { .. } | + pallet_bounties::Call::claim_bounty { .. } | + pallet_bounties::Call::close_bounty { .. }, + ) | + RuntimeCall::ChildBounties(..) | + RuntimeCall::ElectionProviderMultiPhase(..) | + RuntimeCall::Gilt(..) | + RuntimeCall::VoterList(..) | + RuntimeCall::NominationPools( + pallet_nomination_pools::Call::join { .. } | + pallet_nomination_pools::Call::bond_extra { .. } | + pallet_nomination_pools::Call::claim_payout { .. } | + pallet_nomination_pools::Call::unbond { .. } | + pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } | + pallet_nomination_pools::Call::withdraw_unbonded { .. } | + pallet_nomination_pools::Call::create { .. } | + pallet_nomination_pools::Call::create_with_pool_id { .. } | + pallet_nomination_pools::Call::set_state { .. } | + pallet_nomination_pools::Call::set_configs { .. } | + pallet_nomination_pools::Call::update_roles { .. } | + pallet_nomination_pools::Call::chill { .. }, + ) => true, + _ => false, + } + } +} + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -166,6 +345,7 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = SafeCallFilter; } parameter_types! { diff --git a/runtime/parachains/src/ump.rs b/runtime/parachains/src/ump.rs index 2bd4056bdd45..b8e642de654f 100644 --- a/runtime/parachains/src/ump.rs +++ b/runtime/parachains/src/ump.rs @@ -505,6 +505,8 @@ impl<T: Config> Pallet<T> { /// Devote some time into dispatching pending upward messages. pub(crate) fn process_pending_upward_messages() -> Weight { + const MAX_MESSAGES_PER_BLOCK: u8 = 10; + let mut messages_processed = 0; let mut weight_used = Weight::zero(); let config = <configuration::Pallet<T>>::config(); @@ -512,7 +514,12 @@ impl<T: Config> Pallet<T> { let mut queue_cache = QueueCache::new(); while let Some(dispatchee) = cursor.peek() { - if weight_used.any_gte(config.ump_service_total_weight) { + if weight_used.any_gte(config.ump_service_total_weight) || + messages_processed >= MAX_MESSAGES_PER_BLOCK + { + // Temporarily allow for processing of a max of 10 messages per block, until we + // properly account for proof size weights. + // // Then check whether we've reached or overshoot the // preferred weight for the dispatching stage. // @@ -534,6 +541,7 @@ impl<T: Config> Pallet<T> { // our remaining weight limit, then consume it. let maybe_next = queue_cache.peek_front::<T>(dispatchee); if let Some(upward_message) = maybe_next { + messages_processed += 1; match T::UmpSink::process_upward_message(dispatchee, upward_message, max_weight) { Ok(used) => { weight_used += used; diff --git a/runtime/polkadot/src/xcm_config.rs b/runtime/polkadot/src/xcm_config.rs index fcdc0c6427f0..76d4d754eb4a 100644 --- a/runtime/polkadot/src/xcm_config.rs +++ b/runtime/polkadot/src/xcm_config.rs @@ -22,7 +22,7 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Everything, Nothing}, + traits::{Contains, Everything, Nothing}, weights::Weight, }; use runtime_common::{xcm_sender, ToAuthor}; @@ -131,6 +131,152 @@ pub type Barrier = ( AllowSubscriptionsFrom<OnlyParachains>, ); +/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly +/// account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. +pub struct SafeCallFilter; +impl Contains<RuntimeCall> for SafeCallFilter { + fn contains(t: &RuntimeCall) -> bool { + match t { + RuntimeCall::System( + frame_system::Call::fill_block { .. } | + frame_system::Call::kill_prefix { .. } | + frame_system::Call::set_heap_pages { .. }, + ) | + RuntimeCall::Babe(..) | + RuntimeCall::Timestamp(..) | + RuntimeCall::Indices(..) | + RuntimeCall::Balances(..) | + RuntimeCall::Staking( + pallet_staking::Call::bond { .. } | + pallet_staking::Call::bond_extra { .. } | + pallet_staking::Call::unbond { .. } | + pallet_staking::Call::withdraw_unbonded { .. } | + pallet_staking::Call::validate { .. } | + pallet_staking::Call::chill { .. } | + pallet_staking::Call::set_payee { .. } | + pallet_staking::Call::set_controller { .. } | + pallet_staking::Call::set_validator_count { .. } | + pallet_staking::Call::increase_validator_count { .. } | + pallet_staking::Call::scale_validator_count { .. } | + pallet_staking::Call::force_no_eras { .. } | + pallet_staking::Call::force_new_era { .. } | + pallet_staking::Call::set_invulnerables { .. } | + pallet_staking::Call::force_unstake { .. } | + pallet_staking::Call::force_new_era_always { .. } | + pallet_staking::Call::payout_stakers { .. } | + pallet_staking::Call::unbond { .. } | + pallet_staking::Call::reap_stash { .. } | + pallet_staking::Call::set_staking_configs { .. } | + pallet_staking::Call::chill_other { .. } | + pallet_staking::Call::force_apply_min_commission { .. }, + ) | + RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | + RuntimeCall::Grandpa(..) | + RuntimeCall::ImOnline(..) | + RuntimeCall::Democracy( + pallet_democracy::Call::second { .. } | + pallet_democracy::Call::vote { .. } | + pallet_democracy::Call::emergency_cancel { .. } | + pallet_democracy::Call::fast_track { .. } | + pallet_democracy::Call::veto_external { .. } | + pallet_democracy::Call::cancel_referendum { .. } | + pallet_democracy::Call::delegate { .. } | + pallet_democracy::Call::undelegate { .. } | + pallet_democracy::Call::clear_public_proposals { .. } | + pallet_democracy::Call::unlock { .. } | + pallet_democracy::Call::remove_vote { .. } | + pallet_democracy::Call::remove_other_vote { .. } | + pallet_democracy::Call::blacklist { .. } | + pallet_democracy::Call::cancel_proposal { .. }, + ) | + RuntimeCall::Council( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::close_old_weight { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | + RuntimeCall::TechnicalCommittee( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::close_old_weight { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | + RuntimeCall::PhragmenElection( + pallet_elections_phragmen::Call::remove_voter { .. } | + pallet_elections_phragmen::Call::submit_candidacy { .. } | + pallet_elections_phragmen::Call::renounce_candidacy { .. } | + pallet_elections_phragmen::Call::remove_member { .. } | + pallet_elections_phragmen::Call::clean_defunct_voters { .. }, + ) | + RuntimeCall::TechnicalMembership( + pallet_membership::Call::add_member { .. } | + pallet_membership::Call::remove_member { .. } | + pallet_membership::Call::swap_member { .. } | + pallet_membership::Call::change_key { .. } | + pallet_membership::Call::set_prime { .. } | + pallet_membership::Call::clear_prime { .. }, + ) | + RuntimeCall::Treasury(..) | + RuntimeCall::Claims( + super::claims::Call::claim { .. } | + super::claims::Call::mint_claim { .. } | + super::claims::Call::move_claim { .. }, + ) | + RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | + RuntimeCall::Identity( + pallet_identity::Call::add_registrar { .. } | + pallet_identity::Call::set_identity { .. } | + pallet_identity::Call::clear_identity { .. } | + pallet_identity::Call::request_judgement { .. } | + pallet_identity::Call::cancel_request { .. } | + pallet_identity::Call::set_fee { .. } | + pallet_identity::Call::set_account_id { .. } | + pallet_identity::Call::set_fields { .. } | + pallet_identity::Call::provide_judgement { .. } | + pallet_identity::Call::kill_identity { .. } | + pallet_identity::Call::add_sub { .. } | + pallet_identity::Call::rename_sub { .. } | + pallet_identity::Call::remove_sub { .. } | + pallet_identity::Call::quit_sub { .. }, + ) | + RuntimeCall::Vesting(..) | + RuntimeCall::Bounties( + pallet_bounties::Call::propose_bounty { .. } | + pallet_bounties::Call::approve_bounty { .. } | + pallet_bounties::Call::propose_curator { .. } | + pallet_bounties::Call::unassign_curator { .. } | + pallet_bounties::Call::accept_curator { .. } | + pallet_bounties::Call::award_bounty { .. } | + pallet_bounties::Call::claim_bounty { .. } | + pallet_bounties::Call::close_bounty { .. }, + ) | + RuntimeCall::ChildBounties(..) | + RuntimeCall::ElectionProviderMultiPhase(..) | + RuntimeCall::VoterList(..) | + RuntimeCall::NominationPools( + pallet_nomination_pools::Call::join { .. } | + pallet_nomination_pools::Call::bond_extra { .. } | + pallet_nomination_pools::Call::claim_payout { .. } | + pallet_nomination_pools::Call::unbond { .. } | + pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } | + pallet_nomination_pools::Call::withdraw_unbonded { .. } | + pallet_nomination_pools::Call::create { .. } | + pallet_nomination_pools::Call::create_with_pool_id { .. } | + pallet_nomination_pools::Call::set_state { .. } | + pallet_nomination_pools::Call::set_configs { .. } | + pallet_nomination_pools::Call::update_roles { .. } | + pallet_nomination_pools::Call::chill { .. }, + ) => true, + _ => false, + } + } +} + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -159,6 +305,7 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = SafeCallFilter; } parameter_types! { diff --git a/runtime/rococo/src/xcm_config.rs b/runtime/rococo/src/xcm_config.rs index 2b35d4e9a11f..bd550c97bff4 100644 --- a/runtime/rococo/src/xcm_config.rs +++ b/runtime/rococo/src/xcm_config.rs @@ -22,7 +22,7 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Everything, Nothing}, + traits::{Contains, Everything, Nothing}, weights::Weight, }; use runtime_common::{xcm_sender, ToAuthor}; @@ -133,6 +133,127 @@ pub type Barrier = ( AllowSubscriptionsFrom<OnlyParachains>, ); +/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly +/// account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. +pub struct SafeCallFilter; +impl Contains<RuntimeCall> for SafeCallFilter { + fn contains(t: &RuntimeCall) -> bool { + match t { + RuntimeCall::System( + frame_system::Call::fill_block { .. } | + frame_system::Call::kill_prefix { .. } | + frame_system::Call::set_heap_pages { .. }, + ) | + RuntimeCall::Babe(..) | + RuntimeCall::Timestamp(..) | + RuntimeCall::Indices(..) | + RuntimeCall::Balances(..) | + RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | + RuntimeCall::Grandpa(..) | + RuntimeCall::ImOnline(..) | + RuntimeCall::Democracy( + pallet_democracy::Call::second { .. } | + pallet_democracy::Call::vote { .. } | + pallet_democracy::Call::emergency_cancel { .. } | + pallet_democracy::Call::fast_track { .. } | + pallet_democracy::Call::veto_external { .. } | + pallet_democracy::Call::cancel_referendum { .. } | + pallet_democracy::Call::delegate { .. } | + pallet_democracy::Call::undelegate { .. } | + pallet_democracy::Call::clear_public_proposals { .. } | + pallet_democracy::Call::unlock { .. } | + pallet_democracy::Call::remove_vote { .. } | + pallet_democracy::Call::remove_other_vote { .. } | + pallet_democracy::Call::blacklist { .. } | + pallet_democracy::Call::cancel_proposal { .. }, + ) | + RuntimeCall::Council( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::close_old_weight { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | + RuntimeCall::TechnicalCommittee( + pallet_collective::Call::vote { .. } | + pallet_collective::Call::close_old_weight { .. } | + pallet_collective::Call::disapprove_proposal { .. } | + pallet_collective::Call::close { .. }, + ) | + RuntimeCall::PhragmenElection( + pallet_elections_phragmen::Call::remove_voter { .. } | + pallet_elections_phragmen::Call::submit_candidacy { .. } | + pallet_elections_phragmen::Call::renounce_candidacy { .. } | + pallet_elections_phragmen::Call::remove_member { .. } | + pallet_elections_phragmen::Call::clean_defunct_voters { .. }, + ) | + RuntimeCall::TechnicalMembership( + pallet_membership::Call::add_member { .. } | + pallet_membership::Call::remove_member { .. } | + pallet_membership::Call::swap_member { .. } | + pallet_membership::Call::change_key { .. } | + pallet_membership::Call::set_prime { .. } | + pallet_membership::Call::clear_prime { .. }, + ) | + RuntimeCall::Treasury(..) | + RuntimeCall::Claims( + super::claims::Call::claim { .. } | + super::claims::Call::mint_claim { .. } | + super::claims::Call::move_claim { .. }, + ) | + RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | + RuntimeCall::Identity( + pallet_identity::Call::add_registrar { .. } | + pallet_identity::Call::set_identity { .. } | + pallet_identity::Call::clear_identity { .. } | + pallet_identity::Call::request_judgement { .. } | + pallet_identity::Call::cancel_request { .. } | + pallet_identity::Call::set_fee { .. } | + pallet_identity::Call::set_account_id { .. } | + pallet_identity::Call::set_fields { .. } | + pallet_identity::Call::provide_judgement { .. } | + pallet_identity::Call::kill_identity { .. } | + pallet_identity::Call::add_sub { .. } | + pallet_identity::Call::rename_sub { .. } | + pallet_identity::Call::remove_sub { .. } | + pallet_identity::Call::quit_sub { .. }, + ) | + RuntimeCall::Society( + pallet_society::Call::bid { .. } | + pallet_society::Call::unbid { .. } | + pallet_society::Call::vouch { .. } | + pallet_society::Call::unvouch { .. } | + pallet_society::Call::vote { .. } | + pallet_society::Call::defender_vote { .. } | + pallet_society::Call::payout { .. } | + pallet_society::Call::unfound { .. } | + pallet_society::Call::judge_suspended_member { .. } | + pallet_society::Call::judge_suspended_candidate { .. } | + pallet_society::Call::set_max_members { .. }, + ) | + RuntimeCall::Recovery(..) | + RuntimeCall::Vesting(..) | + RuntimeCall::Bounties( + pallet_bounties::Call::propose_bounty { .. } | + pallet_bounties::Call::approve_bounty { .. } | + pallet_bounties::Call::propose_curator { .. } | + pallet_bounties::Call::unassign_curator { .. } | + pallet_bounties::Call::accept_curator { .. } | + pallet_bounties::Call::award_bounty { .. } | + pallet_bounties::Call::claim_bounty { .. } | + pallet_bounties::Call::close_bounty { .. }, + ) | + RuntimeCall::ChildBounties(..) | + RuntimeCall::Gilt(..) => true, + _ => false, + } + } +} + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -162,6 +283,7 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = SafeCallFilter; } parameter_types! { diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index 992b116e98ea..7308772e0e6e 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -104,4 +104,5 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = super::RuntimeCall; + type SafeCallFilter = Everything; } diff --git a/runtime/westend/src/xcm_config.rs b/runtime/westend/src/xcm_config.rs index 2ad4ede3e247..123dfbc9aa97 100644 --- a/runtime/westend/src/xcm_config.rs +++ b/runtime/westend/src/xcm_config.rs @@ -22,7 +22,7 @@ use super::{ }; use frame_support::{ parameter_types, - traits::{Everything, Nothing}, + traits::{Contains, Everything, Nothing}, }; use runtime_common::{xcm_sender, ToAuthor}; use xcm::latest::prelude::*; @@ -99,6 +99,93 @@ pub type Barrier = ( AllowSubscriptionsFrom<Everything>, ); +/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly +/// account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. +pub struct SafeCallFilter; +impl Contains<RuntimeCall> for SafeCallFilter { + fn contains(t: &RuntimeCall) -> bool { + match t { + RuntimeCall::System( + frame_system::Call::fill_block { .. } | + frame_system::Call::kill_prefix { .. } | + frame_system::Call::set_heap_pages { .. }, + ) | + RuntimeCall::Babe(..) | + RuntimeCall::Timestamp(..) | + RuntimeCall::Indices(..) | + RuntimeCall::Balances(..) | + RuntimeCall::Staking( + pallet_staking::Call::bond { .. } | + pallet_staking::Call::bond_extra { .. } | + pallet_staking::Call::unbond { .. } | + pallet_staking::Call::withdraw_unbonded { .. } | + pallet_staking::Call::validate { .. } | + pallet_staking::Call::chill { .. } | + pallet_staking::Call::set_payee { .. } | + pallet_staking::Call::set_controller { .. } | + pallet_staking::Call::set_validator_count { .. } | + pallet_staking::Call::increase_validator_count { .. } | + pallet_staking::Call::scale_validator_count { .. } | + pallet_staking::Call::force_no_eras { .. } | + pallet_staking::Call::force_new_era { .. } | + pallet_staking::Call::set_invulnerables { .. } | + pallet_staking::Call::force_unstake { .. } | + pallet_staking::Call::force_new_era_always { .. } | + pallet_staking::Call::payout_stakers { .. } | + pallet_staking::Call::unbond { .. } | + pallet_staking::Call::reap_stash { .. } | + pallet_staking::Call::set_staking_configs { .. } | + pallet_staking::Call::chill_other { .. } | + pallet_staking::Call::force_apply_min_commission { .. }, + ) | + RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | + RuntimeCall::Grandpa(..) | + RuntimeCall::ImOnline(..) | + RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) | + RuntimeCall::Identity( + pallet_identity::Call::add_registrar { .. } | + pallet_identity::Call::set_identity { .. } | + pallet_identity::Call::clear_identity { .. } | + pallet_identity::Call::request_judgement { .. } | + pallet_identity::Call::cancel_request { .. } | + pallet_identity::Call::set_fee { .. } | + pallet_identity::Call::set_account_id { .. } | + pallet_identity::Call::set_fields { .. } | + pallet_identity::Call::provide_judgement { .. } | + pallet_identity::Call::kill_identity { .. } | + pallet_identity::Call::add_sub { .. } | + pallet_identity::Call::rename_sub { .. } | + pallet_identity::Call::remove_sub { .. } | + pallet_identity::Call::quit_sub { .. }, + ) | + RuntimeCall::Recovery(..) | + RuntimeCall::Vesting(..) | + RuntimeCall::ElectionProviderMultiPhase(..) | + RuntimeCall::VoterList(..) | + RuntimeCall::NominationPools( + pallet_nomination_pools::Call::join { .. } | + pallet_nomination_pools::Call::bond_extra { .. } | + pallet_nomination_pools::Call::claim_payout { .. } | + pallet_nomination_pools::Call::unbond { .. } | + pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } | + pallet_nomination_pools::Call::withdraw_unbonded { .. } | + pallet_nomination_pools::Call::create { .. } | + pallet_nomination_pools::Call::create_with_pool_id { .. } | + pallet_nomination_pools::Call::set_state { .. } | + pallet_nomination_pools::Call::set_configs { .. } | + pallet_nomination_pools::Call::update_roles { .. } | + pallet_nomination_pools::Call::chill { .. }, + ) => true, + _ => false, + } + } +} + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -125,6 +212,7 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = SafeCallFilter; } /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 9c0d34194ab0..11f343fd3cb3 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -301,6 +301,7 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; } pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, AnyNetwork>; diff --git a/xcm/xcm-builder/src/tests/mock.rs b/xcm/xcm-builder/src/tests/mock.rs index eb7fd9491c29..3662a4acf7b5 100644 --- a/xcm/xcm-builder/src/tests/mock.rs +++ b/xcm/xcm-builder/src/tests/mock.rs @@ -19,7 +19,7 @@ pub use crate::{ AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, FixedRateOfFungible, FixedWeightBounds, TakeWeightCredit, }; -use frame_support::traits::ContainsPair; +use frame_support::traits::{ContainsPair, Everything}; pub use frame_support::{ dispatch::{ DispatchError, DispatchInfo, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, @@ -642,6 +642,7 @@ impl Config for TestConfig { type UniversalAliases = TestUniversalAliases; type MessageExporter = TestMessageExporter; type CallDispatcher = TestCall; + type SafeCallFilter = Everything; } pub fn fungible_multi_asset(location: MultiLocation, amount: u128) -> MultiAsset { diff --git a/xcm/xcm-builder/tests/mock/mod.rs b/xcm/xcm-builder/tests/mock/mod.rs index 99e7843f8dc1..a4b3439b3392 100644 --- a/xcm/xcm-builder/tests/mock/mod.rs +++ b/xcm/xcm-builder/tests/mock/mod.rs @@ -196,6 +196,7 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; } pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, KusamaNetwork>; diff --git a/xcm/xcm-executor/src/config.rs b/xcm/xcm-executor/src/config.rs index bd8143adcb7b..9bb98055fb20 100644 --- a/xcm/xcm-executor/src/config.rs +++ b/xcm/xcm-executor/src/config.rs @@ -100,4 +100,10 @@ pub trait Config { /// XCM will use this to dispatch any calls. When no special call dispatcher is required, /// this can be set to the same type as `Self::Call`. type CallDispatcher: CallDispatcher<Self::RuntimeCall>; + + /// The safe call filter for `Transact`. + /// + /// Use this type to explicitly whitelist calls that cannot undergo recursion. This is a + /// temporary measure until we properly account for proof size weights for XCM instructions. + type SafeCallFilter: Contains<Self::RuntimeCall>; } diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 07e6c063c486..06a1afe3f481 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -515,6 +515,7 @@ impl<Config: config::Config> XcmExecutor<Config> { // TODO: #2841 #TRANSACTFILTER allow the trait to issue filters for the relay-chain let message_call = call.take_decoded().map_err(|_| XcmError::FailedToDecode)?; + ensure!(Config::SafeCallFilter::contains(&message_call), XcmError::NoPermission); let dispatch_origin = Config::OriginConverter::convert_origin(origin, origin_kind) .map_err(|_| XcmError::BadOrigin)?; let weight = message_call.get_dispatch_info().weight; diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 023e1a41ac15..26dfd12de08c 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -242,6 +242,7 @@ impl Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; } #[frame_support::pallet] diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index c4161c0770a1..c70307cf042f 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -182,6 +182,7 @@ impl Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; } pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; diff --git a/xcm/xcm-simulator/fuzzer/src/parachain.rs b/xcm/xcm-simulator/fuzzer/src/parachain.rs index 6598589f2b3e..2b6ab01e20ae 100644 --- a/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -156,6 +156,7 @@ impl Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; } #[frame_support::pallet] diff --git a/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 4a464b64ec01..4fdcf51789ee 100644 --- a/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -147,6 +147,7 @@ impl Config for XcmConfig { type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; } pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>;