mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-07 02:38:02 +00:00
ab3a3bc278
It changes following APIs: - trait `ChainApi` -- `validate_transaction` - trait `TransactionPool` --`submit_at` --`submit_one` --`submit_and_watch` and some implementation details, in particular: - impl `Pool` --`submit_at` --`resubmit_at` --`submit_one` --`submit_and_watch` --`prune_known` --`prune` --`prune_tags` --`resolve_block_number` --`verify` --`verify_one` - revalidation queue All tests are also adjusted. --------- Co-authored-by: command-bot <> Co-authored-by: Bastian Köcher <git@kchr.de>
213 lines
6.1 KiB
Rust
213 lines
6.1 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
//! Testing related primitives for internal usage in this crate.
|
|
|
|
use crate::graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool};
|
|
use codec::Encode;
|
|
use parking_lot::Mutex;
|
|
use sc_transaction_pool_api::error;
|
|
use sp_blockchain::TreeRoute;
|
|
use sp_runtime::{
|
|
generic::BlockId,
|
|
traits::{Block as BlockT, Hash},
|
|
transaction_validity::{
|
|
InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction,
|
|
},
|
|
};
|
|
use std::{collections::HashSet, sync::Arc};
|
|
use substrate_test_runtime::{
|
|
substrate_test_pallet::pallet::Call as PalletCall, BalancesCall, Block, BlockNumber, Extrinsic,
|
|
ExtrinsicBuilder, Hashing, RuntimeCall, Transfer, TransferData, H256,
|
|
};
|
|
|
|
pub(crate) const INVALID_NONCE: u64 = 254;
|
|
|
|
/// Test api that implements [`ChainApi`].
|
|
#[derive(Clone, Debug, Default)]
|
|
pub(crate) struct TestApi {
|
|
pub delay: Arc<Mutex<Option<std::sync::mpsc::Receiver<()>>>>,
|
|
pub invalidate: Arc<Mutex<HashSet<H256>>>,
|
|
pub clear_requirements: Arc<Mutex<HashSet<H256>>>,
|
|
pub add_requirements: Arc<Mutex<HashSet<H256>>>,
|
|
pub validation_requests: Arc<Mutex<Vec<Extrinsic>>>,
|
|
}
|
|
|
|
impl TestApi {
|
|
/// Query validation requests received.
|
|
pub fn validation_requests(&self) -> Vec<Extrinsic> {
|
|
self.validation_requests.lock().clone()
|
|
}
|
|
|
|
/// Helper function for mapping block number to hash. Use if mapping shall not fail.
|
|
pub fn expect_hash_from_number(&self, n: BlockNumber) -> H256 {
|
|
self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap()
|
|
}
|
|
}
|
|
|
|
impl ChainApi for TestApi {
|
|
type Block = Block;
|
|
type Error = error::Error;
|
|
type ValidationFuture = futures::future::Ready<error::Result<TransactionValidity>>;
|
|
type BodyFuture = futures::future::Ready<error::Result<Option<Vec<Extrinsic>>>>;
|
|
|
|
/// Verify extrinsic at given block.
|
|
fn validate_transaction(
|
|
&self,
|
|
at: <Self::Block as BlockT>::Hash,
|
|
_source: TransactionSource,
|
|
uxt: ExtrinsicFor<Self>,
|
|
) -> Self::ValidationFuture {
|
|
self.validation_requests.lock().push(uxt.clone());
|
|
let hash = self.hash_and_length(&uxt).0;
|
|
let block_number = self.block_id_to_number(&BlockId::Hash(at)).unwrap().unwrap();
|
|
|
|
let res = match uxt {
|
|
Extrinsic {
|
|
function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { .. }),
|
|
..
|
|
} => {
|
|
let TransferData { nonce, .. } = (&uxt).try_into().unwrap();
|
|
// This is used to control the test flow.
|
|
if nonce > 0 {
|
|
let opt = self.delay.lock().take();
|
|
if let Some(delay) = opt {
|
|
if delay.recv().is_err() {
|
|
println!("Error waiting for delay!");
|
|
}
|
|
}
|
|
}
|
|
|
|
if self.invalidate.lock().contains(&hash) {
|
|
InvalidTransaction::Custom(0).into()
|
|
} else if nonce < block_number {
|
|
InvalidTransaction::Stale.into()
|
|
} else {
|
|
let mut transaction = ValidTransaction {
|
|
priority: 4,
|
|
requires: if nonce > block_number {
|
|
vec![vec![nonce as u8 - 1]]
|
|
} else {
|
|
vec![]
|
|
},
|
|
provides: if nonce == INVALID_NONCE {
|
|
vec![]
|
|
} else {
|
|
vec![vec![nonce as u8]]
|
|
},
|
|
longevity: 3,
|
|
propagate: true,
|
|
};
|
|
|
|
if self.clear_requirements.lock().contains(&hash) {
|
|
transaction.requires.clear();
|
|
}
|
|
|
|
if self.add_requirements.lock().contains(&hash) {
|
|
transaction.requires.push(vec![128]);
|
|
}
|
|
|
|
Ok(transaction)
|
|
}
|
|
},
|
|
Extrinsic {
|
|
function: RuntimeCall::SubstrateTest(PalletCall::include_data { .. }),
|
|
..
|
|
} => Ok(ValidTransaction {
|
|
priority: 9001,
|
|
requires: vec![],
|
|
provides: vec![vec![42]],
|
|
longevity: 9001,
|
|
propagate: false,
|
|
}),
|
|
Extrinsic {
|
|
function: RuntimeCall::SubstrateTest(PalletCall::indexed_call { .. }),
|
|
..
|
|
} => Ok(ValidTransaction {
|
|
priority: 9001,
|
|
requires: vec![],
|
|
provides: vec![vec![43]],
|
|
longevity: 9001,
|
|
propagate: false,
|
|
}),
|
|
_ => unimplemented!(),
|
|
};
|
|
|
|
futures::future::ready(Ok(res))
|
|
}
|
|
|
|
/// Returns a block number given the block id.
|
|
fn block_id_to_number(
|
|
&self,
|
|
at: &BlockId<Self::Block>,
|
|
) -> Result<Option<NumberFor<Self>>, Self::Error> {
|
|
Ok(match at {
|
|
BlockId::Number(num) => Some(*num),
|
|
BlockId::Hash(hash) if *hash == H256::from_low_u64_be(hash.to_low_u64_be()) =>
|
|
Some(hash.to_low_u64_be()),
|
|
BlockId::Hash(_) => None,
|
|
})
|
|
}
|
|
|
|
/// Returns a block hash given the block id.
|
|
fn block_id_to_hash(
|
|
&self,
|
|
at: &BlockId<Self::Block>,
|
|
) -> Result<Option<<Self::Block as BlockT>::Hash>, Self::Error> {
|
|
Ok(match at {
|
|
BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(),
|
|
BlockId::Hash(hash) => Some(*hash),
|
|
})
|
|
}
|
|
|
|
/// Hash the extrinsic.
|
|
fn hash_and_length(&self, uxt: &ExtrinsicFor<Self>) -> (BlockHash<Self>, usize) {
|
|
let encoded = uxt.encode();
|
|
let len = encoded.len();
|
|
(Hashing::hash(&encoded), len)
|
|
}
|
|
|
|
fn block_body(&self, _id: <Self::Block as BlockT>::Hash) -> Self::BodyFuture {
|
|
futures::future::ready(Ok(None))
|
|
}
|
|
|
|
fn block_header(
|
|
&self,
|
|
_: <Self::Block as BlockT>::Hash,
|
|
) -> Result<Option<<Self::Block as BlockT>::Header>, Self::Error> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn tree_route(
|
|
&self,
|
|
_from: <Self::Block as BlockT>::Hash,
|
|
_to: <Self::Block as BlockT>::Hash,
|
|
) -> Result<TreeRoute<Self::Block>, Self::Error> {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
pub(crate) fn uxt(transfer: Transfer) -> Extrinsic {
|
|
ExtrinsicBuilder::new_transfer(transfer).build()
|
|
}
|
|
|
|
pub(crate) fn pool() -> (Pool<TestApi>, Arc<TestApi>) {
|
|
let api = Arc::new(TestApi::default());
|
|
(Pool::new(Default::default(), true.into(), api.clone()), api)
|
|
}
|