Newer
Older
impl<T: Trait + Send + Sync> rstd::fmt::Debug for CheckEra<T> {
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
self.0.fmt(f)
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
type AccountId = T::AccountId;
type AdditionalSigned = T::Hash;
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
let n = (self.0).0.birth(current_u64).saturated_into::<T::BlockNumber>();
if !<BlockHash<T>>::exists(n) { Err("transaction birth block ancient")? }
Ok(<Module<T>>::block_hash(n))
}
}
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
/// Nonce check and increment to give replay protection for transactions.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckGenesis<T: Trait + Send + Sync>(rstd::marker::PhantomData<T>);
#[cfg(feature = "std")]
impl<T: Trait + Send + Sync> rstd::fmt::Debug for CheckGenesis<T> {
fn fmt(&self, _f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
Ok(())
}
}
#[cfg(feature = "std")]
impl<T: Trait + Send + Sync> CheckGenesis<T> {
pub fn new() -> Self {
Self(std::marker::PhantomData)
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckGenesis<T> {
type AccountId = T::AccountId;
type AdditionalSigned = T::Hash;
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
Ok(<Module<T>>::block_hash(T::BlockNumber::zero()))
}
}
pub struct ChainContext<T>(::rstd::marker::PhantomData<T>);
impl<T> Default for ChainContext<T> {
fn default() -> Self {
ChainContext(::rstd::marker::PhantomData)
}
}
impl<T: Trait> Lookup for ChainContext<T> {
type Source = <T::Lookup as StaticLookup>::Source;
type Target = <T::Lookup as StaticLookup>::Target;
fn lookup(&self, s: Self::Source) -> rstd::result::Result<Self::Target, &'static str> {
<T::Lookup as StaticLookup>::lookup(s)
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::with_externalities;
use primitives::H256;
use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header};
use srml_support::{impl_outer_origin, parameter_types};
impl_outer_origin!{
pub enum Origin for Test where system = super {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 10;
pub const MaximumBlockWeight: Weight = 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
pub const MaximumBlockLength: u32 = 1024;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
impl From<Event> for u16 {
fn from(e: Event) -> u16 {
Event::ExtrinsicSuccess => 100,
Event::ExtrinsicFailed => 101,
}
}
}
fn new_test_ext() -> runtime_io::TestExternalities<Blake2Hasher> {
GenesisConfig::default().build_storage::<Test>().unwrap().0.into()
fn normal_weight_limit() -> Weight {
<Test as Trait>::AvailableBlockRatio::get() * <Test as Trait>::MaximumBlockWeight::get()
}
fn normal_length_limit() -> u32 {
<Test as Trait>::AvailableBlockRatio::get() * <Test as Trait>::MaximumBlockLength::get()
}
#[test]
fn origin_works() {
let o = Origin::from(RawOrigin::<u64>::Signed(1u64));
let x: Result<RawOrigin<u64>, Origin> = o.into();
assert_eq!(x, Ok(RawOrigin::<u64>::Signed(1u64)));
}
#[test]
fn deposit_event_should_work() {
with_externalities(&mut new_test_ext(), || {
System::initialize(&1, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default());
System::note_finished_extrinsics();
System::deposit_event(1u16);
assert_eq!(
System::events(),
vec![
EventRecord {
phase: Phase::Finalization,
event: 1u16,
topics: vec![],
}
]
System::initialize(&2, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default());
System::note_applied_extrinsic(&Ok(()), 0);
System::note_applied_extrinsic(&Err(""), 0);
System::note_finished_extrinsics();
System::deposit_event(3u16);
EventRecord { phase: Phase::ApplyExtrinsic(0), event: 42u16, topics: vec![] },
EventRecord { phase: Phase::ApplyExtrinsic(0), event: 100u16, topics: vec![] },
EventRecord { phase: Phase::ApplyExtrinsic(1), event: 101u16, topics: vec![] },
EventRecord { phase: Phase::Finalization, event: 3u16, topics: vec![] }
#[test]
fn deposit_event_topics() {
with_externalities(&mut new_test_ext(), || {
const BLOCK_NUMBER: u64 = 1;
System::initialize(&BLOCK_NUMBER, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default());
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
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], 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)],
);
});
}
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
#[test]
fn prunes_block_hash_mappings() {
with_externalities(&mut new_test_ext(), || {
// simulate import of 15 blocks
for n in 1..=15 {
System::initialize(
&n,
&[n as u8 - 1; 32].into(),
&[0u8; 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 signed_ext_check_nonce_works() {
with_externalities(&mut new_test_ext(), || {
<AccountNonce<Test>>::insert(1, 1);
let info = DispatchInfo::default();
let len = 0_usize;
// stale
assert!(CheckNonce::<Test>(0).validate(&1, info, len).is_err());
assert!(CheckNonce::<Test>(0).pre_dispatch(&1, info, len).is_err());
// correct
assert!(CheckNonce::<Test>(1).validate(&1, info, len).is_ok());
assert!(CheckNonce::<Test>(1).pre_dispatch(&1, info, len).is_ok());
// future
assert!(CheckNonce::<Test>(5).validate(&1, info, len).is_ok());
assert!(CheckNonce::<Test>(5).pre_dispatch(&1, info, len).is_err());
})
}
#[test]
fn signed_ext_check_weight_works_normal_tx() {
with_externalities(&mut new_test_ext(), || {
let small = DispatchInfo { weight: 100, ..Default::default() };
let medium = DispatchInfo {
..Default::default()
};
let big = DispatchInfo {
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
..Default::default()
};
let len = 0_usize;
let reset_check_weight = |i, f, s| {
AllExtrinsicsWeight::put(s);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, 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_fee_works() {
with_externalities(&mut new_test_ext(), || {
let free = DispatchInfo { weight: 0, ..Default::default() };
let len = 0_usize;
assert_eq!(System::all_extrinsics_weight(), 0);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, free, len);
assert!(r.is_ok());
assert_eq!(System::all_extrinsics_weight(), 0);
})
}
#[test]
fn signed_ext_check_weight_max_works() {
with_externalities(&mut new_test_ext(), || {
let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() };
let len = 0_usize;
assert_eq!(System::all_extrinsics_weight(), 0);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, max, len);
assert!(r.is_ok());
assert_eq!(System::all_extrinsics_weight(), normal_limit);
})
}
#[test]
fn signed_ext_check_weight_works_operational_tx() {
with_externalities(&mut new_test_ext(), || {
let normal = DispatchInfo { weight: 100, ..Default::default() };
let op = DispatchInfo { weight: 100, class: DispatchClass::Operational };
let len = 0_usize;
// given almost full block
// will not fit.
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, normal, len).is_err());
// will fit.
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, op, len).is_ok());
// likewise for length limit.
let len = 100_usize;
AllExtrinsicsLen::put(normal_length_limit());
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, normal, len).is_err());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, op, len).is_ok());
})
}
#[test]
fn signed_ext_check_weight_priority_works() {
with_externalities(&mut new_test_ext(), || {
let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal };
let op = DispatchInfo { weight: 100, class: DispatchClass::Operational };
let len = 0_usize;
assert_eq!(
CheckWeight::<Test>(PhantomData).validate(&1, normal, len).unwrap().priority,
100,
);
assert_eq!(
CheckWeight::<Test>(PhantomData).validate(&1, op, len).unwrap().priority,
Bounded::max_value(),
);
})
}
#[test]
fn signed_ext_check_weight_block_size_works() {
with_externalities(&mut new_test_ext(), || {
let normal = DispatchInfo::default();
let normal_limit = normal_weight_limit() as usize;
let reset_check_weight = |tx, s, f| {
AllExtrinsicsLen::put(0);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, 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 };
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() {
with_externalities(&mut new_test_ext(), || {
// future
assert_eq!(
CheckEra::<Test>::from(Era::mortal(4, 2)).additional_signed().err().unwrap(),
"transaction birth block ancient"
);
// 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());
})
}