diff --git a/parachain/pallets/system/src/benchmarking.rs b/parachain/pallets/system/src/benchmarking.rs index 46140986f7..30a6a187ea 100644 --- a/parachain/pallets/system/src/benchmarking.rs +++ b/parachain/pallets/system/src/benchmarking.rs @@ -157,5 +157,9 @@ mod benchmarks { Ok(()) } - impl_benchmark_test_suite!(SnowbridgeControl, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!( + SnowbridgeControl, + crate::mock::new_test_ext(true), + crate::mock::Test + ); } diff --git a/parachain/pallets/system/src/lib.rs b/parachain/pallets/system/src/lib.rs index 522699d49f..2e62ab24d3 100644 --- a/parachain/pallets/system/src/lib.rs +++ b/parachain/pallets/system/src/lib.rs @@ -47,6 +47,7 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; pub mod api; pub mod weights; @@ -256,34 +257,7 @@ pub mod pallet { #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { - let bridge_hub_agent_id = - agent_id_of::(&MultiLocation::here()).expect("infallible; qed"); - // Agent for BridgeHub - Agents::::insert(bridge_hub_agent_id, ()); - - // Primary governance channel - Channels::::insert( - PRIMARY_GOVERNANCE_CHANNEL, - Channel { agent_id: bridge_hub_agent_id, para_id: self.para_id }, - ); - - // Secondary governance channel - Channels::::insert( - SECONDARY_GOVERNANCE_CHANNEL, - Channel { agent_id: bridge_hub_agent_id, para_id: self.para_id }, - ); - - // Asset Hub - let asset_hub_location: MultiLocation = - ParentThen(X1(Parachain(self.asset_hub_para_id.into()))).into(); - let asset_hub_agent_id = - agent_id_of::(&asset_hub_location).expect("infallible; qed"); - let asset_hub_channel_id: ChannelId = self.asset_hub_para_id.into(); - Agents::::insert(asset_hub_agent_id, ()); - Channels::::insert( - asset_hub_channel_id, - Channel { agent_id: asset_hub_agent_id, para_id: self.asset_hub_para_id }, - ); + Pallet::::initialize(self.para_id, self.asset_hub_para_id).expect("infallible; qed"); } } @@ -643,6 +617,49 @@ pub mod pallet { }); Ok(()) } + + /// Checks if the pallet has been initialized. + pub(crate) fn is_initialized() -> bool { + let primary_exists = Channels::::contains_key(PRIMARY_GOVERNANCE_CHANNEL); + let secondary_exists = Channels::::contains_key(SECONDARY_GOVERNANCE_CHANNEL); + primary_exists && secondary_exists + } + + /// Initializes agents and channels. + pub(crate) fn initialize( + para_id: ParaId, + asset_hub_para_id: ParaId, + ) -> Result<(), DispatchError> { + // Asset Hub + let asset_hub_location: MultiLocation = + ParentThen(X1(Parachain(asset_hub_para_id.into()))).into(); + let asset_hub_agent_id = agent_id_of::(&asset_hub_location)?; + let asset_hub_channel_id: ChannelId = asset_hub_para_id.into(); + Agents::::insert(asset_hub_agent_id, ()); + Channels::::insert( + asset_hub_channel_id, + Channel { agent_id: asset_hub_agent_id, para_id: asset_hub_para_id }, + ); + + // Governance channels + let bridge_hub_agent_id = agent_id_of::(&MultiLocation::here())?; + // Agent for BridgeHub + Agents::::insert(bridge_hub_agent_id, ()); + + // Primary governance channel + Channels::::insert( + PRIMARY_GOVERNANCE_CHANNEL, + Channel { agent_id: bridge_hub_agent_id, para_id }, + ); + + // Secondary governance channel + Channels::::insert( + SECONDARY_GOVERNANCE_CHANNEL, + Channel { agent_id: bridge_hub_agent_id, para_id }, + ); + + Ok(()) + } } impl StaticLookup for Pallet { diff --git a/parachain/pallets/system/src/migration.rs b/parachain/pallets/system/src/migration.rs new file mode 100644 index 0000000000..ee94fc091b --- /dev/null +++ b/parachain/pallets/system/src/migration.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +//! Governance API for controlling the Ethereum side of the bridge +use super::*; +use frame_support::traits::OnRuntimeUpgrade; +use log; + +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; + +pub mod v0 { + use frame_support::{pallet_prelude::*, weights::Weight}; + + use super::*; + + const LOG_TARGET: &str = "ethereum_system::migration"; + + pub struct InitializeOnUpgrade( + sp_std::marker::PhantomData<(T, BridgeHubParaId, AssetHubParaId)>, + ); + impl OnRuntimeUpgrade + for InitializeOnUpgrade + where + T: Config, + BridgeHubParaId: Get, + AssetHubParaId: Get, + { + fn on_runtime_upgrade() -> Weight { + if !Pallet::::is_initialized() { + Pallet::::initialize( + BridgeHubParaId::get().into(), + AssetHubParaId::get().into(), + ) + .expect("infallible; qed"); + log::info!( + target: LOG_TARGET, + "Ethereum system initialized." + ); + T::DbWeight::get().reads_writes(2, 5) + } else { + log::info!( + target: LOG_TARGET, + "Ethereum system already initialized. Skipping." + ); + T::DbWeight::get().reads(2) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + if !Pallet::::is_initialized() { + log::info!( + target: LOG_TARGET, + "Agents and channels not initialized. Initialization will run." + ); + } else { + log::info!( + target: LOG_TARGET, + "Agents and channels are initialized. Initialization will not run." + ); + } + Ok(vec![]) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + frame_support::ensure!( + Pallet::::is_initialized(), + "Agents and channels were not initialized." + ); + Ok(()) + } + } +} diff --git a/parachain/pallets/system/src/mock.rs b/parachain/pallets/system/src/mock.rs index 604348b9f3..b1744e1119 100644 --- a/parachain/pallets/system/src/mock.rs +++ b/parachain/pallets/system/src/mock.rs @@ -232,16 +232,18 @@ impl crate::Config for Test { } // Build genesis storage according to the mock runtime. -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext(genesis_build: bool) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - crate::GenesisConfig:: { - para_id: OwnParaId::get(), - asset_hub_para_id: AssetHubParaId::get(), - _config: Default::default(), + if genesis_build { + crate::GenesisConfig:: { + para_id: OwnParaId::get(), + asset_hub_para_id: AssetHubParaId::get(), + _config: Default::default(), + } + .assimilate_storage(&mut storage) + .unwrap(); } - .assimilate_storage(&mut storage) - .unwrap(); let mut ext: sp_io::TestExternalities = storage.into(); let initial_amount = InitialFunding::get(); diff --git a/parachain/pallets/system/src/tests.rs b/parachain/pallets/system/src/tests.rs index 8c57cc880e..808c185c1d 100644 --- a/parachain/pallets/system/src/tests.rs +++ b/parachain/pallets/system/src/tests.rs @@ -9,7 +9,7 @@ use sp_runtime::{AccountId32, DispatchError::BadOrigin, TokenError}; #[test] fn create_agent() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_para_id = 2000; let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(origin_para_id)) }; let agent_id = make_agent_id(origin_location); @@ -29,7 +29,7 @@ fn create_agent() { #[test] fn test_agent_for_here() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_location = MultiLocation::here(); let agent_id = make_agent_id(origin_location); assert_eq!( @@ -41,7 +41,7 @@ fn test_agent_for_here() { #[test] fn create_agent_fails_on_funds_unavailable() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(2000)) }; let origin = make_xcm_origin(origin_location); // Reset balance of sovereign_account to zero so to trigger the FundsUnavailable error @@ -53,7 +53,7 @@ fn create_agent_fails_on_funds_unavailable() { #[test] fn create_agent_bad_origin() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { // relay chain location not allowed assert_noop!( EthereumSystem::create_agent(make_xcm_origin(MultiLocation { @@ -85,7 +85,7 @@ fn create_agent_bad_origin() { #[test] fn upgrade_as_root() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let address: H160 = Default::default(); let code_hash: H256 = Default::default(); @@ -102,7 +102,7 @@ fn upgrade_as_root() { #[test] fn upgrade_as_signed_fails() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::signed(AccountId32::new([0; 32])); let address: H160 = Default::default(); let code_hash: H256 = Default::default(); @@ -113,7 +113,7 @@ fn upgrade_as_signed_fails() { #[test] fn upgrade_with_params() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let address: H160 = Default::default(); let code_hash: H256 = Default::default(); @@ -125,7 +125,7 @@ fn upgrade_with_params() { #[test] fn set_operating_mode() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let mode = OperatingMode::RejectingOutboundMessages; @@ -139,7 +139,7 @@ fn set_operating_mode() { #[test] fn set_operating_mode_as_signed_fails() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::signed([14; 32].into()); let mode = OperatingMode::RejectingOutboundMessages; @@ -149,7 +149,7 @@ fn set_operating_mode_as_signed_fails() { #[test] fn set_pricing_parameters() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let mut params = Parameters::get(); params.rewards.local = 7; @@ -162,7 +162,7 @@ fn set_pricing_parameters() { #[test] fn set_pricing_parameters_as_signed_fails() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::signed([14; 32].into()); let params = Parameters::get(); @@ -172,7 +172,7 @@ fn set_pricing_parameters_as_signed_fails() { #[test] fn set_pricing_parameters_invalid() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let mut params = Parameters::get(); params.rewards.local = 0; @@ -186,7 +186,7 @@ fn set_pricing_parameters_invalid() { #[test] fn set_token_transfer_fees() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); assert_ok!(EthereumSystem::set_token_transfer_fees(origin, 1, 1, eth(1))); @@ -195,7 +195,7 @@ fn set_token_transfer_fees() { #[test] fn set_token_transfer_fees_root_only() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::signed([14; 32].into()); assert_noop!(EthereumSystem::set_token_transfer_fees(origin, 1, 1, 1.into()), BadOrigin); @@ -204,7 +204,7 @@ fn set_token_transfer_fees_root_only() { #[test] fn set_token_transfer_fees_invalid() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); assert_noop!( @@ -216,7 +216,7 @@ fn set_token_transfer_fees_invalid() { #[test] fn create_channel() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_para_id = 2000; let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(origin_para_id)) }; let sovereign_account = sibling_sovereign_account::(origin_para_id.into()); @@ -232,7 +232,7 @@ fn create_channel() { #[test] fn create_channel_fail_already_exists() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_para_id = 2000; let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(origin_para_id)) }; let sovereign_account = sibling_sovereign_account::(origin_para_id.into()); @@ -253,7 +253,7 @@ fn create_channel_fail_already_exists() { #[test] fn create_channel_bad_origin() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { // relay chain location not allowed assert_noop!( EthereumSystem::create_channel( @@ -306,7 +306,7 @@ fn create_channel_bad_origin() { #[test] fn update_channel() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_para_id = 2000; let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(origin_para_id)) }; let sovereign_account = sibling_sovereign_account::(origin_para_id.into()); @@ -329,7 +329,7 @@ fn update_channel() { #[test] fn update_channel_bad_origin() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let mode = OperatingMode::Normal; // relay chain location not allowed @@ -381,7 +381,7 @@ fn update_channel_bad_origin() { #[test] fn update_channel_fails_not_exist() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(2000)) }; let origin = make_xcm_origin(origin_location); @@ -395,7 +395,7 @@ fn update_channel_fails_not_exist() { #[test] fn force_update_channel() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_para_id = 2000; let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(origin_para_id)) }; let sovereign_account = sibling_sovereign_account::(origin_para_id.into()); @@ -425,7 +425,7 @@ fn force_update_channel() { #[test] fn force_update_channel_bad_origin() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let mode = OperatingMode::Normal; // signed origin not allowed @@ -442,7 +442,7 @@ fn force_update_channel_bad_origin() { #[test] fn transfer_native_from_agent() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(2000)) }; let recipient: H160 = [27u8; 20].into(); let amount = 103435; @@ -465,7 +465,7 @@ fn transfer_native_from_agent() { #[test] fn force_transfer_native_from_agent() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let location = MultiLocation { parents: 1, interior: X1(Parachain(2000)) }; let versioned_location: Box = Box::new(location.into()); @@ -494,7 +494,7 @@ fn force_transfer_native_from_agent() { #[test] fn force_transfer_native_from_agent_bad_origin() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let recipient: H160 = [27u8; 20].into(); let amount = 103435; @@ -527,7 +527,7 @@ fn force_transfer_native_from_agent_bad_origin() { #[ignore] #[test] fn check_sibling_sovereign_account() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let para_id = 1001; let sovereign_account = sibling_sovereign_account::(para_id.into()); let sovereign_account_raw = sibling_sovereign_account_raw(para_id.into()); @@ -542,7 +542,7 @@ fn check_sibling_sovereign_account() { #[test] fn charge_fee_for_create_agent() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let para_id: u32 = TestParaId::get(); let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(para_id)) }; let origin = make_xcm_origin(origin_location); @@ -571,7 +571,7 @@ fn charge_fee_for_create_agent() { #[test] fn charge_fee_for_transfer_native_from_agent() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let para_id: u32 = TestParaId::get(); let origin_location = MultiLocation { parents: 1, interior: X1(Parachain(para_id)) }; let recipient: H160 = [27u8; 20].into(); @@ -601,7 +601,7 @@ fn charge_fee_for_transfer_native_from_agent() { #[test] fn charge_fee_for_upgrade() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let para_id: u32 = TestParaId::get(); let origin = RuntimeOrigin::root(); let address: H160 = Default::default(); @@ -616,3 +616,17 @@ fn charge_fee_for_upgrade() { assert_eq!(sovereign_balance, InitialFunding::get()); }); } + +#[test] +fn genesis_build_initializes_correctly() { + new_test_ext(true).execute_with(|| { + assert!(EthereumSystem::is_initialized(), "Ethereum uninitialized."); + }); +} + +#[test] +fn no_genesis_build_is_uninitialized() { + new_test_ext(false).execute_with(|| { + assert!(!EthereumSystem::is_initialized(), "Ethereum initialized."); + }); +} diff --git a/polkadot-sdk b/polkadot-sdk index 00e8eb2e04..7c7cd74edb 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 00e8eb2e04375260d728f143352e21cbf7a4436c +Subproject commit 7c7cd74edb300aa76b283fb7f42f5f9df85434a3 diff --git a/smoketest/src/helper.rs b/smoketest/src/helper.rs index 31b793a8ec..61393f42ac 100644 --- a/smoketest/src/helper.rs +++ b/smoketest/src/helper.rs @@ -2,16 +2,7 @@ use crate::{ constants::*, contracts::i_gateway, parachains::{ - bridgehub::{ - self, - api::{ - runtime_types::{ - bridge_hub_rococo_runtime::RuntimeCall as BHRuntimeCall, - snowbridge_core::outbound::v1::OperatingMode, - }, - utility, - }, - }, + bridgehub::{self, api::runtime_types::snowbridge_core::outbound::v1::OperatingMode}, penpal::{ api::runtime_types as penpalTypes, {self},