use crate::system::*;
use mock::{RuntimeOrigin, *};
use std::collections::BTreeSet;
use subsoil::core::{hexdisplay::HexDisplay, H256};
use subsoil::runtime::{
generic::{Digest, DigestItem},
traits::{BlakeTwo256, Header},
DispatchError, DispatchErrorWithPostInfo,
};
use soil_test_node_runtime_client::WasmExecutor;
use topsoil_core::{
assert_noop, assert_ok,
dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo},
traits::{OnRuntimeUpgrade, WhitelistedStorageKeys},
};
#[test]
fn check_whitelist() {
let whitelist: BTreeSet<String> = AllPalletsWithSystem::whitelisted_storage_keys()
.iter()
.map(|s| HexDisplay::from(&s.key).to_string())
.collect();
assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"));
assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a"));
assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"));
assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"));
assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96"));
}
#[test]
fn origin_works() {
let o = RuntimeOrigin::from(RawOrigin::<u64>::Signed(1u64));
let x: Result<RawOrigin<u64>, RuntimeOrigin> = o.into();
assert_eq!(x.unwrap(), RawOrigin::<u64>::Signed(1u64));
}
#[test]
fn unique_datum_works() {
new_test_ext().execute_with(|| {
System::initialize(&1, &[0u8; 32].into(), &Default::default());
assert!(subsoil::io::storage::exists(well_known_keys::INTRABLOCK_ENTROPY));
let h1 = unique(b"");
assert_eq!(
32,
subsoil::io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap()
);
let h2 = unique(b"");
assert_eq!(
32,
subsoil::io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap()
);
assert_ne!(h1, h2);
let h3 = unique(b"Hello");
assert_eq!(
32,
subsoil::io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap()
);
assert_ne!(h2, h3);
let h4 = unique(b"Hello");
assert_eq!(
32,
subsoil::io::storage::read(well_known_keys::INTRABLOCK_ENTROPY, &mut [], 0).unwrap()
);
assert_ne!(h3, h4);
System::finalize();
assert!(!subsoil::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::<Test>::get(0),
AccountInfo {
nonce: 0u64.into(),
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), 1u64.into());
assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed);
assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
assert_eq!(System::inc_providers(&0), IncRefStatus::Existed);
assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed);
assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
assert_eq!(System::dec_sufficients(&0), DecRefStatus::Reaped);
assert_eq!(System::account_nonce(&0), 0u64.into());
});
}
#[test]
fn dec_sufficients_does_not_undeflow() {
new_test_ext().execute_with(|| {
assert_eq!(System::inc_providers(&0), IncRefStatus::Created);
assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists);
});
}
#[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), 1u64.into());
assert_eq!(System::inc_providers(&0), IncRefStatus::Existed);
assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed);
assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
assert_eq!(System::inc_providers(&0), IncRefStatus::Existed);
assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Reaped);
assert_eq!(System::account_nonce(&0), 0u64.into());
});
}
#[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), 1u64.into());
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), 1u64.into());
assert_eq!(System::inc_providers(&0), IncRefStatus::Existed);
assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists);
assert_eq!(System::account_nonce(&0), 1u64.into());
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), 0u64.into());
});
}
#[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 = <Test as crate::system::Config>::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: DispatchEventInfo {
weight: normal_base,
..Default::default()
}
}
.into(),
topics: vec![]
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: SysEvent::ExtrinsicFailed {
dispatch_error: DispatchError::BadOrigin.into(),
dispatch_info: DispatchEventInfo {
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 = <Test as crate::system::Config>::BlockWeights::get()
.get(DispatchClass::Normal)
.base_extrinsic;
let pre_info =
DispatchInfo { call_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(
&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,
);
let operational_base = <Test as crate::system::Config>::BlockWeights::get()
.get(DispatchClass::Operational)
.base_extrinsic;
assert!(normal_base != operational_base, "Test pre-condition violated");
let pre_info = DispatchInfo {
call_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: DispatchEventInfo {
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: DispatchEventInfo {
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: DispatchEventInfo {
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: DispatchEventInfo {
weight: Weight::from_parts(1000, 0).saturating_add(normal_base),
pays_fee: Pays::Yes,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(4),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: Weight::from_parts(1000, 0).saturating_add(normal_base),
pays_fee: Pays::No,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(5),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: Weight::from_parts(1000, 0).saturating_add(normal_base),
pays_fee: Pays::No,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(6),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: Weight::from_parts(500, 0).saturating_add(normal_base),
pays_fee: Pays::No,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(7),
event: SysEvent::ExtrinsicFailed {
dispatch_error: DispatchError::BadOrigin.into(),
dispatch_info: DispatchEventInfo {
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: DispatchEventInfo {
weight: Weight::from_parts(1000, 0).saturating_add(normal_base),
pays_fee: Pays::Yes,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(9),
event: SysEvent::ExtrinsicFailed {
dispatch_error: DispatchError::BadOrigin.into(),
dispatch_info: DispatchEventInfo {
weight: Weight::from_parts(800, 0).saturating_add(normal_base),
pays_fee: Pays::Yes,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(10),
event: SysEvent::ExtrinsicFailed {
dispatch_error: DispatchError::BadOrigin.into(),
dispatch_info: DispatchEventInfo {
weight: Weight::from_parts(800, 0).saturating_add(normal_base),
pays_fee: Pays::No,
class: Default::default(),
},
}
.into(),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(11),
event: SysEvent::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: Weight::from_parts(300, 0).saturating_add(operational_base),
class: DispatchClass::Operational,
pays_fee: 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)];
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();
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(),
}
]
);
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(|| {
for n in 1..=15 {
System::reset_events();
System::initialize(&n, &[n as u8 - 1; 32].into(), &Default::default());
System::finalize();
}
for n in 0..5 {
assert_eq!(System::block_hash(n), H256::zero());
}
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 subsoil::core::traits::ReadRuntimeVersion for ReadRuntimeVersion {
fn read_runtime_version(
&self,
_wasm_code: &[u8],
_ext: &mut dyn subsoil::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(Some(<mock::Test as pallet::Config>::BlockWeights::get().max_block).into()),
),
("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(subsoil::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 = WasmExecutor::default();
let mut ext = new_test_ext();
ext.register_extension(subsoil::core::traits::ReadRuntimeVersionExt::new(executor));
ext.execute_with(|| {
System::set_block_number(1);
System::set_code(
RawOrigin::Root.into(),
soil_test_node_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 = soil_test_node_runtime_client::WasmExecutor::default();
let mut ext = new_test_ext();
ext.register_extension(subsoil::core::traits::ReadRuntimeVersionExt::new(executor));
ext.execute_with(|| {
System::set_block_number(1);
let res = System::set_code(
RawOrigin::Root.into(),
soil_test_node_runtime_client::runtime::wasm_binary_unwrap().to_vec(),
);
assert_eq!(
res,
Err(DispatchErrorWithPostInfo::from(Error::<Test>::MultiBlockMigrationsOngoing))
);
assert!(System::events().is_empty());
});
}
#[test]
fn set_code_via_authorization_works() {
let executor = soil_test_node_runtime_client::WasmExecutor::default();
let mut ext = new_test_ext();
ext.register_extension(subsoil::core::traits::ReadRuntimeVersionExt::new(executor));
ext.execute_with(|| {
System::set_block_number(1);
assert!(System::authorized_upgrade().is_none());
let runtime = soil_test_node_runtime_client::runtime::wasm_binary_unwrap().to_vec();
let hash = <mock::Test as pallet::Config>::Hashing::hash(&runtime);
assert_noop!(
System::apply_authorized_upgrade(RawOrigin::None.into(), runtime.clone()),
Error::<Test>::NothingAuthorized,
);
assert_ok!(System::authorize_upgrade(RawOrigin::Root.into(), hash));
System::assert_has_event(
SysEvent::UpgradeAuthorized { code_hash: hash, check_version: true }.into(),
);
assert_eq!(System::authorized_upgrade().unwrap().code_hash(), &hash);
let mut bad_runtime = soil_test_node_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::<Test>::Unauthorized,
);
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 = soil_test_node_runtime_client::WasmExecutor::default();
let mut ext = new_test_ext();
ext.register_extension(subsoil::core::traits::ReadRuntimeVersionExt::new(executor));
ext.execute_with(|| {
System::set_storage(
RawOrigin::Root.into(),
vec![(
well_known_keys::CODE.to_vec(),
soil_test_node_runtime_client::runtime::wasm_binary_unwrap().to_vec(),
)],
)
.unwrap();
});
}
#[test]
fn events_not_emitted_during_genesis() {
new_test_ext().execute_with(|| {
assert!(System::block_number().is_zero());
let mut account_data = AccountInfo::default();
System::on_created_account(Default::default(), &mut account_data);
assert!(!System::read_events_no_consensus().any(|_| true));
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]],
subsoil::core::storage::StateVersion::V0,
);
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 = RuntimeOrigin::signed(0u64);
assert_ok!(<EnsureSigned<_> as EnsureOrigin<_>>::try_origin(signed_origin.clone()));
assert_ok!(<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_origin(signed_origin));
#[cfg(feature = "runtime-benchmarks")]
{
let successful_origin: RuntimeOrigin =
<EnsureSigned<_> as EnsureOrigin<_>>::try_successful_origin()
.expect("EnsureSigned has no successful origin required for the test");
assert_ok!(<EnsureSigned<_> as EnsureOrigin<_>>::try_origin(successful_origin));
let successful_origin: RuntimeOrigin =
<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_successful_origin()
.expect("EnsureSignedBy has no successful origin required for the test");
assert_ok!(<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_origin(successful_origin));
}
}
pub fn from_actual_ref_time(ref_time: Option<u64>) -> 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<u64>, 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() {
#[allow(dead_code)]
struct Migration;
impl OnRuntimeUpgrade for Migration {
fn on_runtime_upgrade() -> Weight {
if System::last_runtime_upgrade_spec_version() > 1337 {
return Weight::zero();
}
Weight::zero()
}
}
}
#[test]
fn test_default_account_nonce() {
new_test_ext().execute_with(|| {
System::set_block_number(2);
assert_eq!(System::account_nonce(&1), 2u64.into());
System::inc_account_nonce(&1);
assert_eq!(System::account_nonce(&1), 3u64.into());
System::set_block_number(5);
assert_eq!(System::account_nonce(&1), 3u64.into());
Account::<Test>::remove(&1);
assert_eq!(System::account_nonce(&1), 5u64.into());
});
}
#[test]
fn extrinsic_weight_refunded_is_cleaned() {
new_test_ext().execute_with(|| {
crate::system::ExtrinsicWeightReclaimed::<Test>::put(Weight::from_parts(1, 2));
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::from_parts(1, 2));
System::note_applied_extrinsic(&Ok(().into()), Default::default());
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::zero());
crate::system::ExtrinsicWeightReclaimed::<Test>::put(Weight::from_parts(1, 2));
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::from_parts(1, 2));
System::note_applied_extrinsic(&Err(DispatchError::BadOrigin.into()), Default::default());
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::zero());
});
}
#[test]
fn reclaim_works() {
new_test_ext().execute_with(|| {
let info = DispatchInfo { call_weight: Weight::from_parts(100, 200), ..Default::default() };
crate::system::Pallet::<Test>::reclaim_weight(
&info,
&PostDispatchInfo {
actual_weight: Some(Weight::from_parts(50, 100)),
..Default::default()
},
)
.unwrap();
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::from_parts(50, 100));
crate::system::Pallet::<Test>::reclaim_weight(
&info,
&PostDispatchInfo {
actual_weight: Some(Weight::from_parts(25, 200)),
..Default::default()
},
)
.unwrap();
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::from_parts(75, 100));
crate::system::Pallet::<Test>::reclaim_weight(
&info,
&PostDispatchInfo {
actual_weight: Some(Weight::from_parts(300, 50)),
..Default::default()
},
)
.unwrap();
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::from_parts(75, 150));
crate::system::Pallet::<Test>::reclaim_weight(
&info,
&PostDispatchInfo {
actual_weight: Some(Weight::from_parts(300, 300)),
..Default::default()
},
)
.unwrap();
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::from_parts(75, 150));
System::note_applied_extrinsic(&Ok(().into()), Default::default());
assert_eq!(crate::system::ExtrinsicWeightReclaimed::<Test>::get(), Weight::zero());
});
}
#[test]
#[should_panic(expected = "Block number must be strictly increasing.")]
fn initialize_block_number_must_be_sequential() {
new_test_ext().execute_with(|| {
System::initialize(&1, &[0u8; 32].into(), &Default::default());
System::finalize();
System::initialize(&3, &[0u8; 32].into(), &Default::default());
});
}
#[test]
fn preinherent_digest_is_preserved() {
new_test_ext().execute_with(|| {
let data = vec![42u8; 100];
let digest = Digest { logs: vec![DigestItem::PreRuntime(*b"test", data.clone())] };
System::initialize(&1, &[0u8; 32].into(), &digest);
let stored_digest = <crate::system::Digest<Test>>::get();
assert_eq!(stored_digest.logs.len(), 1);
if let Some(DigestItem::PreRuntime(id, stored_data)) = stored_digest.logs.first() {
assert_eq!(id, b"test");
assert_eq!(stored_data, &data);
} else {
panic!("Expected PreRuntime digest item");
}
let header = System::finalize();
assert_eq!(header.digest().logs.len(), 1);
if let Some(DigestItem::PreRuntime(id, header_data)) = header.digest().logs.first() {
assert_eq!(id, b"test");
assert_eq!(header_data, &data);
} else {
panic!("Expected PreRuntime digest item in finalized header");
}
});
}
#[test]
fn block_size_includes_digest_and_header_overhead() {
new_test_ext().execute_with(|| {
let data = vec![42u8; 100];
let digest = Digest { logs: vec![DigestItem::PreRuntime(*b"test", data.clone())] };
System::initialize(&1, &[0u8; 32].into(), &digest);
let block_size = System::block_size();
let digest_size = digest.encoded_size();
use subsoil::runtime::traits::{Block as BlockT, Header as HeaderT};
let empty_header = <<Test as Config>::Block as BlockT>::Header::new(
1,
Default::default(),
Default::default(),
[0u8; 32].into(),
Default::default(),
);
let empty_header_size = empty_header.encoded_size();
let expected_overhead = digest_size + empty_header_size;
assert_eq!(block_size as usize, expected_overhead);
assert!(block_size > 100);
});
}
#[test]
fn deposit_log_updates_block_size() {
new_test_ext().execute_with(|| {
System::initialize(&1, &[0u8; 32].into(), &Default::default());
let initial_len = System::block_size();
let log_data = vec![42u8; 1000];
let log_item = DigestItem::Other(log_data.clone());
let log_size = log_item.encoded_size();
System::deposit_log(log_item);
let new_len = System::block_size();
assert_eq!(new_len, initial_len + log_size as u32);
});
}
#[test]
#[should_panic(expected = "Header size")]
fn inherent_digest_exceeding_max_header_size_panics() {
new_test_ext().execute_with(|| {
let max_header_size = RuntimeBlockLength::get().max_header_size();
let large_data = vec![42u8; max_header_size as usize + 10];
let digest = Digest { logs: vec![DigestItem::PreRuntime(*b"test", large_data)] };
System::initialize(&1, &[0u8; 32].into(), &digest);
});
}