1use async_trait::async_trait;
23use codec::Encode;
24use parking_lot::RwLock;
25use sc_transaction_pool::{ChainApi, ValidateTransactionPriority};
26use sp_blockchain::{CachedHeaderMetadata, HashAndNumber, TreeRoute};
27use sp_runtime::{
28 generic::{self, BlockId},
29 traits::{
30 BlakeTwo256, Block as BlockT, Hash as HashT, Header as _, NumberFor, TrailingZeroInput,
31 },
32 transaction_validity::{
33 InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
34 ValidTransaction,
35 },
36};
37use std::{
38 collections::{BTreeMap, HashMap, HashSet},
39 sync::Arc,
40};
41use substrate_test_runtime_client::{
42 runtime::{
43 AccountId, Block, BlockNumber, Extrinsic, ExtrinsicBuilder, Hash, Header, Nonce, Transfer,
44 TransferData,
45 },
46 Sr25519Keyring::{self, *},
47};
48
49#[derive(Debug, thiserror::Error)]
51#[error(transparent)]
52pub struct Error(#[from] pub sc_transaction_pool_api::error::Error);
53
54impl sc_transaction_pool_api::error::IntoPoolError for Error {
55 fn into_pool_error(self) -> Result<sc_transaction_pool_api::error::Error, Self> {
56 Ok(self.0)
57 }
58}
59
60pub enum IsBestBlock {
61 Yes,
62 No,
63}
64
65impl IsBestBlock {
66 pub fn is_best(&self) -> bool {
67 matches!(self, Self::Yes)
68 }
69}
70
71impl From<bool> for IsBestBlock {
72 fn from(is_best: bool) -> Self {
73 if is_best {
74 Self::Yes
75 } else {
76 Self::No
77 }
78 }
79}
80
81#[derive(Default)]
82pub struct ChainState {
83 pub block_by_number: BTreeMap<BlockNumber, Vec<(Block, IsBestBlock)>>,
84 pub block_by_hash: HashMap<Hash, Block>,
85 pub nonces: HashMap<Hash, HashMap<AccountId, u64>>,
86 pub invalid_hashes: HashSet<Hash>,
87 pub priorities: HashMap<Hash, u64>,
88 pub valid_till_blocks: HashMap<Hash, u64>,
89}
90
91pub struct TestApi {
93 valid_modifier: RwLock<Box<dyn Fn(&mut ValidTransaction) + Send + Sync>>,
94 chain: RwLock<ChainState>,
95 validation_requests: RwLock<Vec<Extrinsic>>,
96 enable_stale_check: bool,
97}
98
99impl TestApi {
100 pub fn with_alice_nonce(nonce: u64) -> Self {
102 let api = Self::empty();
103 assert_eq!(api.chain.read().block_by_hash.len(), 1);
104 assert_eq!(api.chain.read().nonces.len(), 1);
105
106 api.chain
107 .write()
108 .nonces
109 .values_mut()
110 .nth(0)
111 .map(|h| h.insert(Alice.into(), nonce));
112
113 api
114 }
115
116 pub fn empty() -> Self {
118 let api = TestApi {
119 valid_modifier: RwLock::new(Box::new(|_| {})),
120 chain: Default::default(),
121 validation_requests: RwLock::new(Default::default()),
122 enable_stale_check: false,
123 };
124
125 api.push_block(0, Vec::new(), true);
127
128 let hash0 = *api.chain.read().block_by_hash.keys().nth(0).unwrap();
129 api.chain.write().nonces.insert(hash0, Default::default());
130
131 api
132 }
133
134 pub fn enable_stale_check(mut self) -> Self {
135 self.enable_stale_check = true;
136 self
137 }
138
139 pub fn set_valid_modifier(&self, modifier: Box<dyn Fn(&mut ValidTransaction) + Send + Sync>) {
141 *self.valid_modifier.write() = modifier;
142 }
143
144 pub fn push_block(
146 &self,
147 block_number: BlockNumber,
148 xts: Vec<Extrinsic>,
149 is_best_block: bool,
150 ) -> Header {
151 let parent_hash = {
152 let chain = self.chain.read();
153 block_number
154 .checked_sub(1)
155 .and_then(|num| {
156 chain.block_by_number.get(&num).map(|blocks| blocks[0].0.header.hash())
157 })
158 .unwrap_or_default()
159 };
160
161 self.push_block_with_parent(parent_hash, xts, is_best_block)
162 }
163
164 pub fn push_block_with_parent(
168 &self,
169 parent: Hash,
170 xts: Vec<Extrinsic>,
171 is_best_block: bool,
172 ) -> Header {
173 let block_number = if parent == Hash::default() {
175 0
176 } else {
177 *self
178 .chain
179 .read()
180 .block_by_hash
181 .get(&parent)
182 .expect("`parent` exists")
183 .header()
184 .number() + 1
185 };
186
187 let header = Header {
188 number: block_number,
189 digest: Default::default(),
190 extrinsics_root: Hash::random(),
191 parent_hash: parent,
192 state_root: Default::default(),
193 };
194
195 self.add_block(Block::new(header.clone(), xts), is_best_block);
196
197 header
198 }
199
200 pub fn add_block(&self, block: Block, is_best_block: bool) {
202 let hash = block.header.hash();
203 let block_number = block.header.number();
204
205 let mut chain = self.chain.write();
206 chain.block_by_hash.insert(hash, block.clone());
207
208 if *block_number > 0 {
209 let prev_nonces = chain
211 .nonces
212 .get(block.header.parent_hash())
213 .expect("there shall be nonces for parent block")
214 .clone();
215 chain.nonces.insert(hash, prev_nonces);
216 }
217
218 log::info!(
219 "add_block: {:?} {:?} {:?} nonces:{:#?}",
220 block_number,
221 hash,
222 block.header.parent_hash(),
223 chain.nonces
224 );
225
226 if is_best_block {
227 chain
228 .block_by_number
229 .entry(*block_number)
230 .or_default()
231 .iter_mut()
232 .for_each(|x| {
233 x.1 = IsBestBlock::No;
234 });
235 }
236
237 chain
238 .block_by_number
239 .entry(*block_number)
240 .or_default()
241 .push((block, is_best_block.into()));
242 }
243
244 fn hash_and_length_inner(ex: &Extrinsic) -> (Hash, usize) {
245 let encoded = ex.encode();
246 (BlakeTwo256::hash(&encoded), encoded.len())
247 }
248
249 pub fn add_invalid(&self, xts: &Extrinsic) {
254 self.chain.write().invalid_hashes.insert(Self::hash_and_length_inner(xts).0);
255 }
256
257 pub fn remove_invalid(&self, xts: &Extrinsic) {
262 self.chain.write().invalid_hashes.remove(&Self::hash_and_length_inner(xts).0);
263 }
264
265 pub fn set_priority(&self, xts: &Extrinsic, priority: u64) {
267 self.chain
268 .write()
269 .priorities
270 .insert(Self::hash_and_length_inner(xts).0, priority);
271 }
272
273 pub fn set_valid_till(&self, xts: &Extrinsic, valid_till: u64) {
275 self.chain
276 .write()
277 .valid_till_blocks
278 .insert(Self::hash_and_length_inner(xts).0, valid_till);
279 }
280
281 pub fn validation_requests(&self) -> Vec<Extrinsic> {
283 self.validation_requests.read().clone()
284 }
285
286 pub fn chain(&self) -> &RwLock<ChainState> {
288 &self.chain
289 }
290
291 pub fn set_nonce(&self, at: Hash, account: AccountId, nonce: u64) {
293 let mut chain = self.chain.write();
294 chain.nonces.entry(at).and_modify(|h| {
295 h.insert(account, nonce);
296 });
297
298 log::debug!("set_nonce: {:?} nonces:{:#?}", at, chain.nonces);
299 }
300
301 pub fn increment_nonce_at_block(&self, at: Hash, account: AccountId) {
303 let mut chain = self.chain.write();
304 chain.nonces.entry(at).and_modify(|h| {
305 h.entry(account).and_modify(|n| *n += 1).or_insert(1);
306 });
307
308 log::debug!("increment_nonce_at_block: {:?} nonces:{:#?}", at, chain.nonces);
309 }
310
311 pub fn increment_nonce(&self, account: AccountId) {
313 let mut chain = self.chain.write();
314 chain.nonces.values_mut().for_each(|h| {
316 h.entry(account).and_modify(|n| *n += 1).or_insert(1);
317 })
318 }
319
320 pub fn tree_route(
322 &self,
323 from: Hash,
324 to: Hash,
325 ) -> Result<sp_blockchain::TreeRoute<Block>, Error> {
326 sp_blockchain::tree_route(self, from, to)
327 }
328
329 pub fn expect_hash_from_number(&self, n: BlockNumber) -> Hash {
331 self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap()
332 }
333
334 pub fn genesis_hash(&self) -> Hash {
336 self.expect_hash_from_number(0)
337 }
338
339 pub fn expect_hash_and_number(&self, n: BlockNumber) -> HashAndNumber<Block> {
340 HashAndNumber { hash: self.expect_hash_from_number(n), number: n }
341 }
342}
343
344trait TagFrom {
345 fn tag_from(&self) -> u8;
346}
347
348impl TagFrom for AccountId {
349 fn tag_from(&self) -> u8 {
350 let f = Sr25519Keyring::iter().enumerate().find(|k| AccountId::from(k.1) == *self);
351 u8::try_from(f.unwrap().0).unwrap()
352 }
353}
354
355#[async_trait]
356impl ChainApi for TestApi {
357 type Block = Block;
358 type Error = Error;
359
360 async fn validate_transaction(
361 &self,
362 at: <Self::Block as BlockT>::Hash,
363 source: TransactionSource,
364 uxt: Arc<<Self::Block as BlockT>::Extrinsic>,
365 _: ValidateTransactionPriority,
366 ) -> Result<TransactionValidity, Error> {
367 self.validate_transaction_blocking(at, source, uxt)
368 }
369
370 fn validate_transaction_blocking(
371 &self,
372 at: <Self::Block as BlockT>::Hash,
373 _source: TransactionSource,
374 uxt: Arc<<Self::Block as BlockT>::Extrinsic>,
375 ) -> Result<TransactionValidity, Error> {
376 let uxt = (*uxt).clone();
377 self.validation_requests.write().push(uxt.clone());
378 let block_number;
379
380 match self.block_id_to_number(&BlockId::Hash(at)) {
381 Ok(Some(number)) => {
382 let found_best = self
383 .chain
384 .read()
385 .block_by_number
386 .get(&number)
387 .map(|blocks| blocks.iter().any(|b| b.1.is_best()))
388 .unwrap_or(false);
389 block_number = Some(number);
390
391 if !found_best {
395 return Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1))))
396 }
397 },
398 Ok(None) =>
399 return Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(2)))),
400 Err(e) => return Err(e),
401 }
402
403 let (requires, provides) = if let Ok(transfer) = TransferData::try_from(&uxt) {
404 let chain_nonce = self
405 .chain
406 .read()
407 .nonces
408 .get(&at)
409 .expect("nonces must be there for every block")
410 .get(&transfer.from)
411 .cloned()
412 .unwrap_or(0);
413 let requires = if chain_nonce == transfer.nonce {
414 vec![]
415 } else {
416 if self.enable_stale_check {
417 vec![vec![transfer.from.tag_from(), (transfer.nonce - 1) as u8]]
418 } else {
419 vec![vec![(transfer.nonce - 1) as u8]]
420 }
421 };
422 let provides = if self.enable_stale_check {
423 vec![vec![transfer.from.tag_from(), transfer.nonce as u8]]
424 } else {
425 vec![vec![transfer.nonce as u8]]
426 };
427
428 log::info!(
429 "test_api::validate_transaction: h:{:?} n:{:?} cn:{:?} tn:{:?} r:{:?} p:{:?}",
430 at,
431 block_number,
432 chain_nonce,
433 transfer.nonce,
434 requires,
435 provides,
436 );
437
438 if self.enable_stale_check && transfer.nonce < chain_nonce {
439 log::info!("test_api::validate_transaction: invalid_transaction(stale)....");
440 return Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)))
441 }
442
443 (requires, provides)
444 } else {
445 (Vec::new(), vec![uxt.encode()])
446 };
447
448 if self.chain.read().invalid_hashes.contains(&self.hash_and_length(&uxt).0) {
449 log::info!("test_api::validate_transaction: invalid_transaction....");
450 return Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))))
451 }
452
453 let priority = self.chain.read().priorities.get(&self.hash_and_length(&uxt).0).cloned();
454 let longevity = self
455 .chain
456 .read()
457 .valid_till_blocks
458 .get(&self.hash_and_length(&uxt).0)
459 .cloned()
460 .map(|valid_till| valid_till.saturating_sub(block_number.unwrap()))
461 .unwrap_or(64);
462
463 if longevity == 0 {
464 return Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::BadProof)))
465 }
466
467 let mut validity = ValidTransaction {
468 priority: priority.unwrap_or(1),
469 requires,
470 provides,
471 longevity,
472 propagate: true,
473 };
474
475 (self.valid_modifier.read())(&mut validity);
476
477 Ok(Ok(validity))
478 }
479
480 fn block_id_to_number(
481 &self,
482 at: &BlockId<Self::Block>,
483 ) -> Result<Option<NumberFor<Self::Block>>, Error> {
484 Ok(match at {
485 generic::BlockId::Hash(x) =>
486 self.chain.read().block_by_hash.get(x).map(|b| *b.header.number()),
487 generic::BlockId::Number(num) => Some(*num),
488 })
489 }
490
491 fn block_id_to_hash(
492 &self,
493 at: &BlockId<Self::Block>,
494 ) -> Result<Option<<Self::Block as BlockT>::Hash>, Error> {
495 Ok(match at {
496 generic::BlockId::Hash(x) => Some(*x),
497 generic::BlockId::Number(num) =>
498 self.chain.read().block_by_number.get(num).and_then(|blocks| {
499 blocks.iter().find(|b| b.1.is_best()).map(|b| b.0.header().hash())
500 }),
501 })
502 }
503
504 fn hash_and_length(&self, ex: &<Self::Block as BlockT>::Extrinsic) -> (Hash, usize) {
505 Self::hash_and_length_inner(ex)
506 }
507
508 async fn block_body(
509 &self,
510 hash: <Self::Block as BlockT>::Hash,
511 ) -> Result<Option<Vec<Extrinsic>>, Error> {
512 Ok(self.chain.read().block_by_hash.get(&hash).map(|b| b.extrinsics().to_vec()))
513 }
514
515 fn block_header(
516 &self,
517 hash: <Self::Block as BlockT>::Hash,
518 ) -> Result<Option<<Self::Block as BlockT>::Header>, Self::Error> {
519 Ok(self.chain.read().block_by_hash.get(&hash).map(|b| b.header().clone()))
520 }
521
522 fn tree_route(
523 &self,
524 from: <Self::Block as BlockT>::Hash,
525 to: <Self::Block as BlockT>::Hash,
526 ) -> Result<TreeRoute<Self::Block>, Self::Error> {
527 sp_blockchain::tree_route::<Block, TestApi>(self, from, to).map_err(Into::into)
528 }
529}
530
531impl sp_blockchain::HeaderMetadata<Block> for TestApi {
532 type Error = Error;
533
534 fn header_metadata(&self, hash: Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
535 let chain = self.chain.read();
536 let block = chain.block_by_hash.get(&hash).expect("Hash exists");
537
538 Ok(block.header().into())
539 }
540
541 fn insert_header_metadata(&self, _: Hash, _: CachedHeaderMetadata<Block>) {
542 unimplemented!("Not implemented for tests")
543 }
544
545 fn remove_header_metadata(&self, _: Hash) {
546 unimplemented!("Not implemented for tests")
547 }
548}
549
550pub fn uxt(who: Sr25519Keyring, nonce: Nonce) -> Extrinsic {
554 let dummy = codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap();
555 let transfer = Transfer { from: who.into(), to: dummy, nonce, amount: 1 };
556 ExtrinsicBuilder::new_transfer(transfer).build()
557}