Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
H256::repeat_byte(3),
];
// We deposit a few events with different sets of topics.
System::deposit_event_indexed(&topics[0..3], 1u16);
System::deposit_event_indexed(&topics[0..1], 2u16);
System::deposit_event_indexed(&topics[1..2], 3u16);
System::finalize();
// Check that topics are reflected in the event record.
assert_eq!(
System::events(),
vec![
EventRecord {
phase: Phase::Finalization,
event: 1u16,
topics: topics[0..3].to_vec(),
},
EventRecord {
phase: Phase::Finalization,
event: 2u16,
topics: topics[0..1].to_vec(),
},
EventRecord {
phase: Phase::Finalization,
event: 3u16,
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 prunes_block_hash_mappings() {
new_test_ext().execute_with(|| {
// simulate import of 15 blocks
for n in 1..=15 {
System::initialize(
&n,
&[n as u8 - 1; 32].into(),
&[0u8; 32].into(),
&Default::default(),
Tomasz Drwięga
committed
InitKind::Full,
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
);
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 signed_ext_check_nonce_works() {
new_test_ext().execute_with(|| {
Account::<Test>::insert(1, AccountInfo { nonce: 1, refcount: 0, data: 0 });
let info = DispatchInfo::default();
let len = 0_usize;
// stale
assert!(CheckNonce::<Test>(0).validate(&1, CALL, &info, len).is_err());
assert!(CheckNonce::<Test>(0).pre_dispatch(&1, CALL, &info, len).is_err());
assert!(CheckNonce::<Test>(1).validate(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(1).pre_dispatch(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(5).validate(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(5).pre_dispatch(&1, CALL, &info, len).is_err());
fn signed_ext_check_weight_works_normal_tx() {
new_test_ext().execute_with(|| {
let small = DispatchInfo { weight: 100, ..Default::default() };
let medium = DispatchInfo {
weight: normal_limit - <Test as Trait>::ExtrinsicBaseWeight::get(),
..Default::default()
};
let big = DispatchInfo {
weight: normal_limit - <Test as Trait>::ExtrinsicBaseWeight::get() + 1,
..Default::default()
};
let len = 0_usize;
let reset_check_weight = |i, f, s| {
AllExtrinsicsWeight::mutate(|current_weight| {
current_weight.put(s, DispatchClass::Normal)
});
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, i, len);
if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
};
reset_check_weight(&small, false, 0);
reset_check_weight(&medium, false, 0);
reset_check_weight(&big, true, 1);
#[test]
fn signed_ext_check_weight_refund_works() {
new_test_ext().execute_with(|| {
// This is half of the max block weight
let info = DispatchInfo { weight: 512, ..Default::default() };
let post_info = PostDispatchInfo { actual_weight: Some(128), };
let len = 0_usize;
// We allow 75% for normal transaction, so we put 25% - extrinsic base weight
AllExtrinsicsWeight::mutate(|current_weight| {
current_weight.put(256 - <Test as Trait>::ExtrinsicBaseWeight::get(), DispatchClass::Normal)
});
let pre = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap();
assert_eq!(AllExtrinsicsWeight::get().total(), info.weight + 256);
assert!(
CheckWeight::<Test>::post_dispatch(pre, &info, &post_info, len, &Ok(()))
.is_ok()
);
assert_eq!(
AllExtrinsicsWeight::get().total(),
post_info.actual_weight.unwrap() + 256,
);
})
}
#[test]
fn signed_ext_check_weight_actual_weight_higher_than_max_is_capped() {
new_test_ext().execute_with(|| {
let info = DispatchInfo { weight: 512, ..Default::default() };
let post_info = PostDispatchInfo { actual_weight: Some(700), };
let len = 0_usize;
AllExtrinsicsWeight::mutate(|current_weight| {
current_weight.put(128, DispatchClass::Normal)
});
let pre = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap();
assert_eq!(
AllExtrinsicsWeight::get().total(),
info.weight + 128 + <Test as Trait>::ExtrinsicBaseWeight::get(),
);
assert!(
CheckWeight::<Test>::post_dispatch(pre, &info, &post_info, len, &Ok(()))
.is_ok()
);
assert_eq!(
AllExtrinsicsWeight::get().total(),
info.weight + 128 + <Test as Trait>::ExtrinsicBaseWeight::get(),
);
fn zero_weight_extrinsic_still_has_base_weight() {
new_test_ext().execute_with(|| {
let free = DispatchInfo { weight: 0, ..Default::default() };
let len = 0_usize;
// Initial weight from `BlockExecutionWeight`
assert_eq!(System::all_extrinsics_weight().total(), <Test as Trait>::BlockExecutionWeight::get());
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &free, len);
assert_eq!(
System::all_extrinsics_weight().total(),
<Test as Trait>::ExtrinsicBaseWeight::get() + <Test as Trait>::BlockExecutionWeight::get()
);
#[test]
fn mandatory_extrinsic_doesnt_care_about_limits() {
new_test_ext().execute_with(|| {
let max = DispatchInfo {
weight: Weight::max_value(),
class: DispatchClass::Mandatory,
..Default::default()
};
let len = 0_usize;
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max, len));
assert_eq!(System::all_extrinsics_weight().total(), Weight::max_value());
assert!(System::all_extrinsics_weight().total() > <Test as Trait>::MaximumBlockWeight::get());
});
}
#[test]
fn register_extra_weight_unchecked_doesnt_care_about_limits() {
new_test_ext().execute_with(|| {
System::register_extra_weight_unchecked(Weight::max_value(), DispatchClass::Normal);
assert_eq!(System::all_extrinsics_weight().total(), Weight::max_value());
assert!(System::all_extrinsics_weight().total() > <Test as Trait>::MaximumBlockWeight::get());
});
}
#[test]
fn full_block_with_normal_and_operational() {
new_test_ext().execute_with(|| {
// Max block is 1024
// Max normal is 768 (75%)
// 10 is taken for block execution weight
// So normal extrinsic can be 758 weight (-5 for base extrinsic weight)
// And Operational can be 256 to produce a full block (-5 for base)
let max_normal = DispatchInfo { weight: 753, ..Default::default() };
let rest_operational = DispatchInfo { weight: 251, class: DispatchClass::Operational, ..Default::default() };
let len = 0_usize;
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max_normal, len));
assert_eq!(System::all_extrinsics_weight().total(), 768);
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&rest_operational, len));
assert_eq!(<Test as Trait>::MaximumBlockWeight::get(), 1024);
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
assert_eq!(System::all_extrinsics_weight().total(), <Test as Trait>::MaximumBlockWeight::get());
});
}
#[test]
fn dispatch_order_does_not_effect_weight_logic() {
new_test_ext().execute_with(|| {
// We switch the order of `full_block_with_normal_and_operational`
let max_normal = DispatchInfo { weight: 753, ..Default::default() };
let rest_operational = DispatchInfo { weight: 251, class: DispatchClass::Operational, ..Default::default() };
let len = 0_usize;
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&rest_operational, len));
// Extra 15 here from block execution + base extrinsic weight
assert_eq!(System::all_extrinsics_weight().total(), 266);
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max_normal, len));
assert_eq!(<Test as Trait>::MaximumBlockWeight::get(), 1024);
assert_eq!(System::all_extrinsics_weight().total(), <Test as Trait>::MaximumBlockWeight::get());
});
}
#[test]
fn operational_works_on_full_block() {
new_test_ext().execute_with(|| {
// An on_initialize takes up the whole block! (Every time!)
System::register_extra_weight_unchecked(Weight::max_value(), DispatchClass::Mandatory);
let dispatch_normal = DispatchInfo { weight: 251, class: DispatchClass::Normal, ..Default::default() };
let dispatch_operational = DispatchInfo { weight: 251, class: DispatchClass::Operational, ..Default::default() };
let len = 0_usize;
assert_noop!(CheckWeight::<Test>::do_pre_dispatch(&dispatch_normal, len), InvalidTransaction::ExhaustsResources);
// Thank goodness we can still do an operational transaction to possibly save the blockchain.
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&dispatch_operational, len));
// Not too much though
assert_noop!(CheckWeight::<Test>::do_pre_dispatch(&dispatch_operational, len), InvalidTransaction::ExhaustsResources);
}
#[test]
fn signed_ext_check_weight_works_operational_tx() {
new_test_ext().execute_with(|| {
let normal = DispatchInfo { weight: 100, ..Default::default() };
let op = DispatchInfo { weight: 100, class: DispatchClass::Operational, pays_fee: Pays::Yes };
// given almost full block
AllExtrinsicsWeight::mutate(|current_weight| {
current_weight.put(normal_limit, DispatchClass::Normal)
});
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &normal, len).is_err());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &op, len).is_ok());
// likewise for length limit.
let len = 100_usize;
AllExtrinsicsLen::put(normal_length_limit());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &normal, len).is_err());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &op, len).is_ok());
})
}
#[test]
fn signed_ext_check_weight_priority_works() {
new_test_ext().execute_with(|| {
let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes };
let op = DispatchInfo { weight: 100, class: DispatchClass::Operational, pays_fee: Pays::Yes };
let priority = CheckWeight::<Test>(PhantomData)
.unwrap()
.priority;
assert_eq!(priority, 100);
let priority = CheckWeight::<Test>(PhantomData)
assert_eq!(priority, u64::max_value());
})
}
#[test]
fn signed_ext_check_weight_block_size_works() {
new_test_ext().execute_with(|| {
let normal = DispatchInfo::default();
let normal_limit = normal_weight_limit() as usize;
let reset_check_weight = |tx, s, f| {
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, tx, s);
if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
};
reset_check_weight(&normal, normal_limit - 1, false);
reset_check_weight(&normal, normal_limit, false);
reset_check_weight(&normal, normal_limit + 1, true);
// Operational ones don't have this limit.
let op = DispatchInfo { weight: 0, class: DispatchClass::Operational, pays_fee: Pays::Yes };
reset_check_weight(&op, normal_limit, false);
reset_check_weight(&op, normal_limit + 100, false);
reset_check_weight(&op, 1024, false);
reset_check_weight(&op, 1025, true);
})
}
#[test]
fn signed_ext_check_era_should_work() {
new_test_ext().execute_with(|| {
// future
assert_eq!(
CheckEra::<Test>::from(Era::mortal(4, 2)).additional_signed().err().unwrap(),
InvalidTransaction::AncientBirthBlock.into(),
);
// correct
System::set_block_number(13);
<BlockHash<Test>>::insert(12, H256::repeat_byte(1));
assert!(CheckEra::<Test>::from(Era::mortal(4, 12)).additional_signed().is_ok());
})
}
#[test]
fn signed_ext_check_era_should_change_longevity() {
new_test_ext().execute_with(|| {
let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes };
let len = 0_usize;
let ext = (
CheckWeight::<Test>(PhantomData),
CheckEra::<Test>::from(Era::mortal(16, 256)),
);
System::set_block_number(17);
<BlockHash<Test>>::insert(16, H256::repeat_byte(1));
assert_eq!(ext.validate(&1, CALL, &normal, len).unwrap().longevity, 15);
#[test]
fn set_code_checks_works() {
struct CallInWasm(Vec<u8>);
impl sp_core::traits::CallInWasm for CallInWasm {
fn call_in_wasm(
&self,
_: &[u8],
_: Option<Vec<u8>>,
_: &str,
_: &[u8],
_: &mut dyn sp_externalities::Externalities,
_: sp_core::traits::MissingHostFunctions,
) -> 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(())),
("test", 0, 1, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
("test", 1, 0, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
];
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 call_in_wasm = CallInWasm(version.encode());
let mut ext = new_test_ext();
ext.register_extension(sp_core::traits::CallInWasmExt::new(call_in_wasm));
ext.execute_with(|| {
let res = System::set_code(
RawOrigin::Root.into(),
vec![1, 2, 3, 4],
);
assert_eq!(expected.map_err(DispatchError::from), res);
});
}
}
#[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::CallInWasmExt::new(executor));
ext.execute_with(|| {
System::set_block_number(1);
System::set_code(
RawOrigin::Root.into(),
substrate_test_runtime_client::runtime::WASM_BINARY.to_vec(),
).unwrap();
assert_eq!(
System::events(),
vec![EventRecord { phase: Phase::Initialization, event: 102u16, 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::CallInWasmExt::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.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());
System::on_created_account(Default::default());
assert!(System::events().is_empty());
// Events will be emitted starting on block 1
System::set_block_number(1);
System::on_created_account(Default::default());
assert!(System::events().len() == 1);
});
}