// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::*; use frame_support::{ assert_noop, assert_ok, dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo}, traits::{OnRuntimeUpgrade, WhitelistedStorageKeys}, }; use std::collections::BTreeSet; use mock::{RuntimeOrigin, *}; use sp_core::{hexdisplay::HexDisplay, H256}; use sp_runtime::{ traits::{BlakeTwo256, Header}, DispatchError, DispatchErrorWithPostInfo, }; #[test] fn check_whitelist() { let whitelist: BTreeSet = AllPalletsWithSystem::whitelisted_storage_keys() .iter() .map(|s| HexDisplay::from(&s.key).to_string()) .collect(); // Block Number assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")); // Execution Phase assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")); // Event Count assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")); // System Events assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")); // System BlockWeight assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96")); } #[test] fn origin_works() { let o = RuntimeOrigin::from(RawOrigin::::Signed(1u64)); let x: Result, RuntimeOrigin> = o.into(); assert_eq!(x.unwrap(), RawOrigin::::Signed(1u64)); } #[test] fn unique_datum_works() { new_test_ext().execute_with(|| { System::initialize(&1, &[0u8; 32].into(), &Default::default()); assert!(sp_io::storage::exists(well_known_keys::INTRABLOCK_ENTROPY)); let h1 = unique(b""); assert_eq!( 32, sp_io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap() ); let h2 = unique(b""); assert_eq!( 32, sp_io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap() ); assert_ne!(h1, h2); let h3 = unique(b"Hello"); assert_eq!( 32, sp_io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap() ); assert_ne!(h2, h3); let h4 = unique(b"Hello"); assert_eq!( 32, sp_io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap() ); assert_ne!(h3, h4); System::finalize(); assert!(!sp_io::storage::exists(well_known_keys::INTRABLOCK_ENTROPY)); }); } #[test] fn stored_map_works() { new_test_ext().execute_with(|| { assert_eq!(System::inc_providers(&0), IncRefStatus::Created); assert_ok!(System::insert(&0, 42)); assert!(!System::is_provider_required(&0)); assert_eq!( Account::::get(0), AccountInfo { nonce: 0, providers: 1, consumers: 0, sufficients: 0, data: 42 } ); assert_ok!(System::inc_consumers(&0)); assert!(System::is_provider_required(&0)); assert_ok!(System::insert(&0, 69)); assert!(System::is_provider_required(&0)); System::dec_consumers(&0); assert!(!System::is_provider_required(&0)); assert!(Killed::get().is_empty()); assert_ok!(System::remove(&0)); assert_ok!(System::dec_providers(&0)); assert_eq!(Killed::get(), vec![0u64]); }); } #[test] fn provider_ref_handover_to_self_sufficient_ref_works() { new_test_ext().execute_with(|| { assert_eq!(System::inc_providers(&0), IncRefStatus::Created); System::inc_account_nonce(&0); assert_eq!(System::account_nonce(&0), 1); // a second reference coming and going doesn't change anything. assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed); assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); // a provider reference coming and going doesn't change anything. assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); // decreasing the providers with a self-sufficient present should not delete the account assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); // decreasing the sufficients should delete the account assert_eq!(System::dec_sufficients(&0), DecRefStatus::Reaped); assert_eq!(System::account_nonce(&0), 0); }); } #[test] fn self_sufficient_ref_handover_to_provider_ref_works() { new_test_ext().execute_with(|| { assert_eq!(System::inc_sufficients(&0), IncRefStatus::Created); System::inc_account_nonce(&0); assert_eq!(System::account_nonce(&0), 1); // a second reference coming and going doesn't change anything. assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); // a sufficient reference coming and going doesn't change anything. assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed); assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); // decreasing the sufficients with a provider present should not delete the account assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); // decreasing the providers should delete the account assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Reaped); assert_eq!(System::account_nonce(&0), 0); }); } #[test] fn sufficient_cannot_support_consumer() { new_test_ext().execute_with(|| { assert_eq!(System::inc_sufficients(&0), IncRefStatus::Created); System::inc_account_nonce(&0); assert_eq!(System::account_nonce(&0), 1); assert_noop!(System::inc_consumers(&0), DispatchError::NoProviders); assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_ok!(System::inc_consumers(&0)); assert_noop!(System::dec_providers(&0), DispatchError::ConsumerRemaining); }); } #[test] fn provider_required_to_support_consumer() { new_test_ext().execute_with(|| { assert_noop!(System::inc_consumers(&0), DispatchError::NoProviders); assert_eq!(System::inc_providers(&0), IncRefStatus::Created); System::inc_account_nonce(&0); assert_eq!(System::account_nonce(&0), 1); assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); assert_eq!(System::account_nonce(&0), 1); assert_ok!(System::inc_consumers(&0)); assert_noop!(System::dec_providers(&0), DispatchError::ConsumerRemaining); System::dec_consumers(&0); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Reaped); assert_eq!(System::account_nonce(&0), 0); }); } #[test] fn deposit_event_should_work() { new_test_ext().execute_with(|| { System::reset_events(); System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_extrinsics(); System::deposit_event(SysEvent::CodeUpdated); System::finalize(); assert_eq!( System::events(), vec![EventRecord { phase: Phase::Finalization, event: SysEvent::CodeUpdated.into(), topics: vec![], }] ); let normal_base = ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; System::reset_events(); System::initialize(&2, &[0u8; 32].into(), &Default::default()); System::deposit_event(SysEvent::NewAccount { account: 32 }); System::note_finished_initialize(); System::deposit_event(SysEvent::KilledAccount { account: 42 }); System::note_applied_extrinsic(&Ok(().into()), Default::default()); System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.into()), Default::default()); System::note_finished_extrinsics(); System::deposit_event(SysEvent::NewAccount { account: 3 }); System::finalize(); assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, event: SysEvent::NewAccount { account: 32 }.into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: SysEvent::KilledAccount { account: 42 }.into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } } .into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } } .into(), topics: vec![] }, EventRecord { phase: Phase::Finalization, event: SysEvent::NewAccount { account: 3 }.into(), topics: vec![] }, ] ); }); } #[test] fn deposit_event_uses_actual_weight_and_pays_fee() { new_test_ext().execute_with(|| { System::reset_events(); System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); let normal_base = ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; let pre_info = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(300))), pre_info); System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(1000))), pre_info); System::note_applied_extrinsic( // values over the pre info should be capped at pre dispatch value &Ok(from_actual_ref_time(Some(1200))), pre_info, ); System::note_applied_extrinsic( &Ok(from_post_weight_info(Some(2_500_000), Pays::Yes)), pre_info, ); System::note_applied_extrinsic(&Ok(Pays::No.into()), pre_info); System::note_applied_extrinsic( &Ok(from_post_weight_info(Some(2_500_000), Pays::No)), pre_info, ); System::note_applied_extrinsic(&Ok(from_post_weight_info(Some(500), Pays::No)), pre_info); System::note_applied_extrinsic( &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(999, 0))), pre_info, ); System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }, error: DispatchError::BadOrigin, }), pre_info, ); System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some(Weight::from_parts(800, 0)), pays_fee: Pays::Yes, }, error: DispatchError::BadOrigin, }), pre_info, ); System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some(Weight::from_parts(800, 0)), pays_fee: Pays::No, }, error: DispatchError::BadOrigin, }), pre_info, ); // Also works for operational. let operational_base = ::BlockWeights::get() .get(DispatchClass::Operational) .base_extrinsic; assert!(normal_base != operational_base, "Test pre-condition violated"); let pre_info = DispatchInfo { weight: Weight::from_parts(1000, 0), class: DispatchClass::Operational, ..Default::default() }; System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(300))), pre_info); let got = System::events(); let want = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(300, 0).saturating_add(normal_base), ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(3), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::Yes, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(4), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(5), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(6), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(500, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(7), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { weight: Weight::from_parts(999, 0).saturating_add(normal_base), ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(8), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::Yes, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(9), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { weight: Weight::from_parts(800, 0).saturating_add(normal_base), pays_fee: Pays::Yes, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(10), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { weight: Weight::from_parts(800, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, } .into(), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(11), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: Weight::from_parts(300, 0).saturating_add(operational_base), class: DispatchClass::Operational, ..Default::default() }, } .into(), topics: vec![], }, ]; for (i, event) in want.into_iter().enumerate() { assert_eq!(got[i], event, "Event mismatch at index {}", i); } }); } #[test] fn deposit_event_topics() { new_test_ext().execute_with(|| { const BLOCK_NUMBER: u64 = 1; System::reset_events(); System::initialize(&BLOCK_NUMBER, &[0u8; 32].into(), &Default::default()); System::note_finished_extrinsics(); let topics = vec![H256::repeat_byte(1), H256::repeat_byte(2), H256::repeat_byte(3)]; // We deposit a few events with different sets of topics. System::deposit_event_indexed(&topics[0..3], SysEvent::NewAccount { account: 1 }.into()); System::deposit_event_indexed(&topics[0..1], SysEvent::NewAccount { account: 2 }.into()); System::deposit_event_indexed(&topics[1..2], SysEvent::NewAccount { account: 3 }.into()); System::finalize(); // Check that topics are reflected in the event record. assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Finalization, event: SysEvent::NewAccount { account: 1 }.into(), topics: topics[0..3].to_vec(), }, EventRecord { phase: Phase::Finalization, event: SysEvent::NewAccount { account: 2 }.into(), topics: topics[0..1].to_vec(), }, EventRecord { phase: Phase::Finalization, event: SysEvent::NewAccount { account: 3 }.into(), topics: topics[1..2].to_vec(), } ] ); // Check that the topic-events mapping reflects the deposited topics. // Note that these are indexes of the events. assert_eq!(System::event_topics(&topics[0]), vec![(BLOCK_NUMBER, 0), (BLOCK_NUMBER, 1)]); assert_eq!(System::event_topics(&topics[1]), vec![(BLOCK_NUMBER, 0), (BLOCK_NUMBER, 2)]); assert_eq!(System::event_topics(&topics[2]), vec![(BLOCK_NUMBER, 0)]); }); } #[test] fn event_util_functions_should_work() { new_test_ext().execute_with(|| { System::set_block_number(1); System::deposit_event(SysEvent::CodeUpdated); System::assert_has_event(SysEvent::CodeUpdated.into()); System::assert_last_event(SysEvent::CodeUpdated.into()); }); } #[test] fn prunes_block_hash_mappings() { new_test_ext().execute_with(|| { // simulate import of 15 blocks for n in 1..=15 { System::reset_events(); System::initialize(&n, &[n as u8 - 1; 32].into(), &Default::default()); System::finalize(); } // first 5 block hashes are pruned for n in 0..5 { assert_eq!(System::block_hash(n), H256::zero()); } // the remaining 10 are kept for n in 5..15 { assert_eq!(System::block_hash(n), [n as u8; 32].into()); } }) } #[test] fn set_code_checks_works() { struct ReadRuntimeVersion(Vec); impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion { fn read_runtime_version( &self, _wasm_code: &[u8], _ext: &mut dyn sp_externalities::Externalities, ) -> Result, String> { Ok(self.0.clone()) } } let test_data = vec![ ("test", 1, 2, Err(Error::::SpecVersionNeedsToIncrease)), ("test", 1, 1, Err(Error::::SpecVersionNeedsToIncrease)), ("test2", 1, 1, Err(Error::::InvalidSpecName)), ( "test", 2, 1, Ok(Some(::BlockWeights::get().max_block).into()), ), ("test", 0, 1, Err(Error::::SpecVersionNeedsToIncrease)), ("test", 1, 0, Err(Error::::SpecVersionNeedsToIncrease)), ]; for (spec_name, spec_version, impl_version, expected) in test_data.into_iter() { let version = RuntimeVersion { spec_name: spec_name.into(), spec_version, impl_version, ..Default::default() }; let read_runtime_version = ReadRuntimeVersion(version.encode()); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(read_runtime_version)); ext.execute_with(|| { let res = System::set_code(RawOrigin::Root.into(), vec![1, 2, 3, 4]); assert_runtime_updated_digest(if res.is_ok() { 1 } else { 0 }); assert_eq!(expected.map_err(DispatchErrorWithPostInfo::from), res); }); } } fn assert_runtime_updated_digest(num: usize) { assert_eq!( System::digest() .logs .into_iter() .filter(|item| *item == generic::DigestItem::RuntimeEnvironmentUpdated) .count(), num, "Incorrect number of Runtime Updated digest items", ); } #[test] fn set_code_with_real_wasm_blob() { let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { System::set_block_number(1); System::set_code( RawOrigin::Root.into(), substrate_test_runtime_client::runtime::wasm_binary_unwrap().to_vec(), ) .unwrap(); assert_eq!( System::events(), vec![EventRecord { phase: Phase::Initialization, event: SysEvent::CodeUpdated.into(), topics: vec![], }], ); }); } #[test] fn set_code_rejects_during_mbm() { Ongoing::set(true); let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { System::set_block_number(1); let res = System::set_code( RawOrigin::Root.into(), substrate_test_runtime_client::runtime::wasm_binary_unwrap().to_vec(), ); assert_eq!( res, Err(DispatchErrorWithPostInfo::from(Error::::MultiBlockMigrationsOngoing)) ); assert!(System::events().is_empty()); }); } #[test] fn set_code_via_authorization_works() { let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { System::set_block_number(1); assert!(System::authorized_upgrade().is_none()); let runtime = substrate_test_runtime_client::runtime::wasm_binary_unwrap().to_vec(); let hash = ::Hashing::hash(&runtime); // Can't apply before authorization assert_noop!( System::apply_authorized_upgrade(RawOrigin::None.into(), runtime.clone()), Error::::NothingAuthorized, ); // Can authorize assert_ok!(System::authorize_upgrade(RawOrigin::Root.into(), hash)); System::assert_has_event( SysEvent::UpgradeAuthorized { code_hash: hash, check_version: true }.into(), ); assert!(System::authorized_upgrade().is_some()); // Can't be sneaky let mut bad_runtime = substrate_test_runtime_client::runtime::wasm_binary_unwrap().to_vec(); bad_runtime.extend(b"sneaky"); assert_noop!( System::apply_authorized_upgrade(RawOrigin::None.into(), bad_runtime), Error::::Unauthorized, ); // Can apply correct runtime assert_ok!(System::apply_authorized_upgrade(RawOrigin::None.into(), runtime)); System::assert_has_event(SysEvent::CodeUpdated.into()); assert!(System::authorized_upgrade().is_none()); }); } #[test] fn runtime_upgraded_with_set_storage() { let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { System::set_storage( RawOrigin::Root.into(), vec![( well_known_keys::CODE.to_vec(), substrate_test_runtime_client::runtime::wasm_binary_unwrap().to_vec(), )], ) .unwrap(); }); } #[test] fn events_not_emitted_during_genesis() { new_test_ext().execute_with(|| { // Block Number is zero at genesis assert!(System::block_number().is_zero()); let mut account_data = AccountInfo::default(); System::on_created_account(Default::default(), &mut account_data); // No events registered at the genesis block assert!(!System::read_events_no_consensus().any(|_| true)); // Events will be emitted starting on block 1 System::set_block_number(1); System::on_created_account(Default::default(), &mut account_data); assert!(System::events().len() == 1); }); } #[test] fn extrinsics_root_is_calculated_correctly() { new_test_ext().execute_with(|| { System::reset_events(); System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); System::note_extrinsic(vec![1]); System::note_applied_extrinsic(&Ok(().into()), Default::default()); System::note_extrinsic(vec![2]); System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.into()), Default::default()); System::note_finished_extrinsics(); let header = System::finalize(); let ext_root = extrinsics_data_root::(vec![vec![1], vec![2]]); assert_eq!(ext_root, *header.extrinsics_root()); }); } #[test] fn runtime_updated_digest_emitted_when_heap_pages_changed() { new_test_ext().execute_with(|| { System::reset_events(); System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::set_heap_pages(RawOrigin::Root.into(), 5).unwrap(); assert_runtime_updated_digest(1); }); } #[test] fn ensure_signed_stuff_works() { struct Members; impl SortedMembers for Members { fn sorted_members() -> Vec { (0..10).collect() } } let signed_origin = RuntimeOrigin::signed(0u64); assert_ok!( as EnsureOrigin<_>>::try_origin(signed_origin.clone())); assert_ok!( as EnsureOrigin<_>>::try_origin(signed_origin)); #[cfg(feature = "runtime-benchmarks")] { let successful_origin: RuntimeOrigin = as EnsureOrigin<_>>::try_successful_origin() .expect("EnsureSigned has no successful origin required for the test"); assert_ok!( as EnsureOrigin<_>>::try_origin(successful_origin)); let successful_origin: RuntimeOrigin = as EnsureOrigin<_>>::try_successful_origin() .expect("EnsureSignedBy has no successful origin required for the test"); assert_ok!( as EnsureOrigin<_>>::try_origin(successful_origin)); } } pub fn from_actual_ref_time(ref_time: Option) -> PostDispatchInfo { PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee: Default::default(), } } pub fn from_post_weight_info(ref_time: Option, pays_fee: Pays) -> PostDispatchInfo { PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee } } #[docify::export] #[test] fn last_runtime_upgrade_spec_version_usage() { struct Migration; impl OnRuntimeUpgrade for Migration { fn on_runtime_upgrade() -> Weight { // Ensure to compare the spec version against some static version to prevent applying // the same migration multiple times. // // `1337` here is the spec version of the runtime running on chain. If there is maybe // a runtime upgrade in the pipeline of being applied, you should use the spec version // of this upgrade. if System::last_runtime_upgrade_spec_version() > 1337 { return Weight::zero() } // Do the migration. Weight::zero() } } }