Files
pezkuwi-subxt/substrate/frame/system/src/tests.rs
T
Xiliang Chen d346028a9d reset events before apply runtime upgrade (#10620)
* reset events before apply runtime upgrade

* fix tests

* add test

* update comment

* Update frame/system/src/lib.rs

* trigger CI

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
2022-01-12 08:22:29 +00:00

519 lines
16 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2017-2022 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::PostDispatchInfo, weights::WithPostDispatchInfo,
};
use mock::{Origin, *};
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, Header},
DispatchError, DispatchErrorWithPostInfo,
};
#[test]
fn origin_works() {
let o = Origin::from(RawOrigin::<u64>::Signed(1u64));
let x: Result<RawOrigin<u64>, Origin> = o.into();
assert_eq!(x.unwrap(), RawOrigin::<u64>::Signed(1u64));
}
#[test]
fn stored_map_works() {
new_test_ext().execute_with(|| {
assert_ok!(System::insert(&0, 42));
assert!(!System::is_provider_required(&0));
assert_eq!(
Account::<Test>::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.with(|r| r.borrow().is_empty()));
assert_ok!(System::remove(&0));
assert_eq!(KILLED.with(|r| r.borrow().clone()), 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![],
}]
);
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: Default::default() }.into(),
topics: vec![]
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: SysEvent::ExtrinsicFailed {
dispatch_error: DispatchError::BadOrigin.into(),
dispatch_info: Default::default()
}
.into(),
topics: vec![]
},
EventRecord {
phase: Phase::Finalization,
event: SysEvent::NewAccount { account: 3 }.into(),
topics: vec![]
},
]
);
});
}
#[test]
fn deposit_event_uses_actual_weight() {
new_test_ext().execute_with(|| {
System::reset_events();
System::initialize(&1, &[0u8; 32].into(), &Default::default());
System::note_finished_initialize();
let pre_info = DispatchInfo { weight: 1000, ..Default::default() };
System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info);
System::note_applied_extrinsic(&Ok(Some(1000).into()), pre_info);
System::note_applied_extrinsic(
// values over the pre info should be capped at pre dispatch value
&Ok(Some(1200).into()),
pre_info,
);
System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.with_weight(999)), pre_info);
assert_eq!(
System::events(),
vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchInfo { weight: 300, ..Default::default() },
}
.into(),
topics: vec![]
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchInfo { weight: 1000, ..Default::default() },
}
.into(),
topics: vec![]
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchInfo { weight: 1000, ..Default::default() },
}
.into(),
topics: vec![]
},
EventRecord {
phase: Phase::ApplyExtrinsic(3),
event: SysEvent::ExtrinsicFailed {
dispatch_error: DispatchError::BadOrigin.into(),
dispatch_info: DispatchInfo { weight: 999, ..Default::default() },
}
.into(),
topics: vec![]
},
]
);
});
}
#[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<u8>);
impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion {
fn read_runtime_version(
&self,
_wasm_code: &[u8],
_ext: &mut dyn sp_externalities::Externalities,
) -> Result<Vec<u8>, String> {
Ok(self.0.clone())
}
}
let test_data = vec![
("test", 1, 2, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
("test", 1, 1, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
("test2", 1, 1, Err(Error::<Test>::InvalidSpecName)),
("test", 2, 1, Ok(PostDispatchInfo::default())),
("test", 0, 1, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
("test", 1, 0, Err(Error::<Test>::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_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 runtime_upgraded_with_set_storage() {
let executor = substrate_test_runtime_client::new_native_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);
assert!(System::events().is_empty());
// 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::<BlakeTwo256>(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<u64> for Members {
fn sorted_members() -> Vec<u64> {
(0..10).collect()
}
}
let signed_origin = Origin::signed(0u64);
assert_ok!(EnsureSigned::try_origin(signed_origin.clone()));
assert_ok!(EnsureSignedBy::<Members, _>::try_origin(signed_origin));
#[cfg(feature = "runtime-benchmarks")]
{
let successful_origin: Origin = EnsureSigned::successful_origin();
assert_ok!(EnsureSigned::try_origin(successful_origin));
let successful_origin: Origin = EnsureSignedBy::<Members, _>::successful_origin();
assert_ok!(EnsureSignedBy::<Members, _>::try_origin(successful_origin));
}
}