mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 09:01:02 +00:00
sc-transcation-pool refactor (#9228)
* Use TransactionPool trait * sc-transaction-pool-primitives * sc-transaction-pool-api * TP * bye sc_transaction_graph * fix line widths * fix import errors * fix import errors * fix import errors 🤦🏾♂️ * fix import errors 🤦🏾♂️🤦🏾♂️🤦🏾♂️ * remove sp-keyring
This commit is contained in:
@@ -22,21 +22,34 @@ parity-util-mem = { version = "0.10.0", default-features = false, features = ["p
|
||||
parking_lot = "0.11.1"
|
||||
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0"}
|
||||
sc-client-api = { version = "3.0.0", path = "../api" }
|
||||
sc-transaction-graph = { version = "3.0.0", path = "./graph" }
|
||||
sp-api = { version = "3.0.0", path = "../../primitives/api" }
|
||||
sp-core = { version = "3.0.0", path = "../../primitives/core" }
|
||||
sp-runtime = { version = "3.0.0", path = "../../primitives/runtime" }
|
||||
sp-tracing = { version = "3.0.0", path = "../../primitives/tracing" }
|
||||
sp-transaction-pool = { version = "3.0.0", path = "../../primitives/transaction-pool" }
|
||||
sc-transaction-pool-api = { version = "3.0.0", path = "./api" }
|
||||
sp-blockchain = { version = "3.0.0", path = "../../primitives/blockchain" }
|
||||
sp-utils = { version = "3.0.0", path = "../../primitives/utils" }
|
||||
wasm-timer = "0.2"
|
||||
derive_more = "0.99.2"
|
||||
serde = { version = "1.0.101", features = ["derive"] }
|
||||
linked-hash-map = "0.5.2"
|
||||
retain_mut = "0.1.3"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
hex = "0.4"
|
||||
sp-keyring = { version = "3.0.0", path = "../../primitives/keyring" }
|
||||
sp-consensus = { version = "0.9.0", path = "../../primitives/consensus/common" }
|
||||
substrate-test-runtime-transaction-pool = { version = "2.0.0", path = "../../test-utils/runtime/transaction-pool" }
|
||||
substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" }
|
||||
sc-block-builder = { version = "0.9.0", path = "../block-builder" }
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" }
|
||||
criterion = "0.3"
|
||||
|
||||
[[bench]]
|
||||
name = "basics"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
test-helpers = []
|
||||
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "sc-transaction-pool-api"
|
||||
version = "3.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
homepage = "https://substrate.dev"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
description = "Transaction pool client facing API."
|
||||
|
||||
[dependencies]
|
||||
futures = { version = "0.3.1" }
|
||||
log = { version = "0.4.8" }
|
||||
serde = { version = "1.0.101", features = ["derive"] }
|
||||
thiserror = { version = "1.0.21" }
|
||||
sp-runtime = { version = "3.0.0", default-features = false, path = "../../../primitives/runtime" }
|
||||
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
derive_more = { version = "0.99.11" }
|
||||
sp-blockchain = { version = "3.0.0", path = "../../../primitives/blockchain" }
|
||||
@@ -0,0 +1,86 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Transaction pool errors.
|
||||
|
||||
use sp_runtime::transaction_validity::{
|
||||
TransactionPriority as Priority, InvalidTransaction, UnknownTransaction,
|
||||
};
|
||||
|
||||
/// Transaction pool result.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Transaction pool error type.
|
||||
#[derive(Debug, thiserror::Error, derive_more::From)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Error {
|
||||
#[error("Unknown transaction validity: {0:?}")]
|
||||
UnknownTransaction(UnknownTransaction),
|
||||
|
||||
#[error("Invalid transaction validity: {0:?}")]
|
||||
InvalidTransaction(InvalidTransaction),
|
||||
|
||||
/// The transaction validity returned no "provides" tag.
|
||||
///
|
||||
/// Such transactions are not accepted to the pool, since we use those tags
|
||||
/// to define identity of transactions (occupance of the same "slot").
|
||||
#[error("Transaction does not provide any tags, so the pool can't identify it")]
|
||||
NoTagsProvided,
|
||||
|
||||
#[error("Transaction temporarily Banned")]
|
||||
TemporarilyBanned,
|
||||
|
||||
#[error("[{0:?}] Already imported")]
|
||||
AlreadyImported(Box<dyn std::any::Any + Send>),
|
||||
|
||||
#[error("Too low priority ({} > {})", old, new)]
|
||||
TooLowPriority {
|
||||
/// Transaction already in the pool.
|
||||
old: Priority,
|
||||
/// Transaction entering the pool.
|
||||
new: Priority
|
||||
},
|
||||
#[error("Transaction with cyclic dependency")]
|
||||
CycleDetected,
|
||||
|
||||
#[error("Transaction couldn't enter the pool because of the limit")]
|
||||
ImmediatelyDropped,
|
||||
|
||||
#[error("Transaction cannot be propagated and the local node does not author blocks")]
|
||||
Unactionable,
|
||||
|
||||
#[from(ignore)]
|
||||
#[error("{0}")]
|
||||
InvalidBlockId(String),
|
||||
|
||||
#[error("The pool is not accepting future transactions")]
|
||||
RejectedFutureTransaction,
|
||||
}
|
||||
|
||||
/// Transaction pool error conversion.
|
||||
pub trait IntoPoolError: std::error::Error + Send + Sized {
|
||||
/// Try to extract original `Error`
|
||||
///
|
||||
/// This implementation is optional and used only to
|
||||
/// provide more descriptive error messages for end users
|
||||
/// of RPC API.
|
||||
fn into_pool_error(self) -> std::result::Result<Error, Self> { Err(self) }
|
||||
}
|
||||
|
||||
impl IntoPoolError for Error {
|
||||
fn into_pool_error(self) -> std::result::Result<Error, Self> { Ok(self) }
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Transaction pool client facing API.
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod error;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hash::Hash,
|
||||
sync::Arc,
|
||||
pin::Pin,
|
||||
};
|
||||
use futures::{Future, Stream};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Member, NumberFor},
|
||||
};
|
||||
pub use sp_runtime::transaction_validity::{
|
||||
TransactionLongevity, TransactionPriority, TransactionTag, TransactionSource,
|
||||
};
|
||||
|
||||
/// Transaction pool status.
|
||||
#[derive(Debug)]
|
||||
pub struct PoolStatus {
|
||||
/// Number of transactions in the ready queue.
|
||||
pub ready: usize,
|
||||
/// Sum of bytes of ready transaction encodings.
|
||||
pub ready_bytes: usize,
|
||||
/// Number of transactions in the future queue.
|
||||
pub future: usize,
|
||||
/// Sum of bytes of ready transaction encodings.
|
||||
pub future_bytes: usize,
|
||||
}
|
||||
|
||||
impl PoolStatus {
|
||||
/// Returns true if the are no transactions in the pool.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.ready == 0 && self.future == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible transaction status events.
|
||||
///
|
||||
/// This events are being emitted by `TransactionPool` watchers,
|
||||
/// which are also exposed over RPC.
|
||||
///
|
||||
/// The status events can be grouped based on their kinds as:
|
||||
/// 1. Entering/Moving within the pool:
|
||||
/// - `Future`
|
||||
/// - `Ready`
|
||||
/// 2. Inside `Ready` queue:
|
||||
/// - `Broadcast`
|
||||
/// 3. Leaving the pool:
|
||||
/// - `InBlock`
|
||||
/// - `Invalid`
|
||||
/// - `Usurped`
|
||||
/// - `Dropped`
|
||||
/// 4. Re-entering the pool:
|
||||
/// - `Retracted`
|
||||
/// 5. Block finalized:
|
||||
/// - `Finalized`
|
||||
/// - `FinalityTimeout`
|
||||
///
|
||||
/// The events will always be received in the order described above, however
|
||||
/// there might be cases where transactions alternate between `Future` and `Ready`
|
||||
/// pool, and are `Broadcast` in the meantime.
|
||||
///
|
||||
/// There is also only single event causing the transaction to leave the pool.
|
||||
/// I.e. only one of the listed ones should be triggered.
|
||||
///
|
||||
/// Note that there are conditions that may cause transactions to reappear in the pool.
|
||||
/// 1. Due to possible forks, the transaction that ends up being in included
|
||||
/// in one block, may later re-enter the pool or be marked as invalid.
|
||||
/// 2. Transaction `Dropped` at one point, may later re-enter the pool if some other
|
||||
/// transactions are removed.
|
||||
/// 3. `Invalid` transaction may become valid at some point in the future.
|
||||
/// (Note that runtimes are encouraged to use `UnknownValidity` to inform the pool about
|
||||
/// such case).
|
||||
/// 4. `Retracted` transactions might be included in some next block.
|
||||
///
|
||||
/// The stream is considered finished only when either `Finalized` or `FinalityTimeout`
|
||||
/// event is triggered. You are however free to unsubscribe from notifications at any point.
|
||||
/// The first one will be emitted when the block, in which transaction was included gets
|
||||
/// finalized. The `FinalityTimeout` event will be emitted when the block did not reach finality
|
||||
/// within 512 blocks. This either indicates that finality is not available for your chain,
|
||||
/// or that finality gadget is lagging behind. If you choose to wait for finality longer, you can
|
||||
/// re-subscribe for a particular transaction hash manually again.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum TransactionStatus<Hash, BlockHash> {
|
||||
/// Transaction is part of the future queue.
|
||||
Future,
|
||||
/// Transaction is part of the ready queue.
|
||||
Ready,
|
||||
/// The transaction has been broadcast to the given peers.
|
||||
Broadcast(Vec<String>),
|
||||
/// Transaction has been included in block with given hash.
|
||||
InBlock(BlockHash),
|
||||
/// The block this transaction was included in has been retracted.
|
||||
Retracted(BlockHash),
|
||||
/// Maximum number of finality watchers has been reached,
|
||||
/// old watchers are being removed.
|
||||
FinalityTimeout(BlockHash),
|
||||
/// Transaction has been finalized by a finality-gadget, e.g GRANDPA
|
||||
Finalized(BlockHash),
|
||||
/// Transaction has been replaced in the pool, by another transaction
|
||||
/// that provides the same tags. (e.g. same (sender, nonce)).
|
||||
Usurped(Hash),
|
||||
/// Transaction has been dropped from the pool because of the limit.
|
||||
Dropped,
|
||||
/// Transaction is no longer valid in the current state.
|
||||
Invalid,
|
||||
}
|
||||
|
||||
/// The stream of transaction events.
|
||||
pub type TransactionStatusStream<Hash, BlockHash> = dyn Stream<Item=TransactionStatus<Hash, BlockHash>> + Send + Unpin;
|
||||
|
||||
/// The import notification event stream.
|
||||
pub type ImportNotificationStream<H> = futures::channel::mpsc::Receiver<H>;
|
||||
|
||||
/// Transaction hash type for a pool.
|
||||
pub type TxHash<P> = <P as TransactionPool>::Hash;
|
||||
/// Block hash type for a pool.
|
||||
pub type BlockHash<P> = <<P as TransactionPool>::Block as BlockT>::Hash;
|
||||
/// Transaction type for a pool.
|
||||
pub type TransactionFor<P> = <<P as TransactionPool>::Block as BlockT>::Extrinsic;
|
||||
/// Type of transactions event stream for a pool.
|
||||
pub type TransactionStatusStreamFor<P> = TransactionStatusStream<TxHash<P>, BlockHash<P>>;
|
||||
/// Transaction type for a local pool.
|
||||
pub type LocalTransactionFor<P> = <<P as LocalTransactionPool>::Block as BlockT>::Extrinsic;
|
||||
|
||||
/// Typical future type used in transaction pool api.
|
||||
pub type PoolFuture<T, E> = std::pin::Pin<Box<dyn Future<Output=Result<T, E>> + Send>>;
|
||||
|
||||
/// In-pool transaction interface.
|
||||
///
|
||||
/// The pool is container of transactions that are implementing this trait.
|
||||
/// See `sp_runtime::ValidTransaction` for details about every field.
|
||||
pub trait InPoolTransaction {
|
||||
/// Transaction type.
|
||||
type Transaction;
|
||||
/// Transaction hash type.
|
||||
type Hash;
|
||||
|
||||
/// Get the reference to the transaction data.
|
||||
fn data(&self) -> &Self::Transaction;
|
||||
/// Get hash of the transaction.
|
||||
fn hash(&self) -> &Self::Hash;
|
||||
/// Get priority of the transaction.
|
||||
fn priority(&self) -> &TransactionPriority;
|
||||
/// Get longevity of the transaction.
|
||||
fn longevity(&self) -> &TransactionLongevity;
|
||||
/// Get transaction dependencies.
|
||||
fn requires(&self) -> &[TransactionTag];
|
||||
/// Get tags that transaction provides.
|
||||
fn provides(&self) -> &[TransactionTag];
|
||||
/// Return a flag indicating if the transaction should be propagated to other peers.
|
||||
fn is_propagable(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Transaction pool interface.
|
||||
pub trait TransactionPool: Send + Sync {
|
||||
/// Block type.
|
||||
type Block: BlockT;
|
||||
/// Transaction hash type.
|
||||
type Hash: Hash + Eq + Member + Serialize;
|
||||
/// In-pool transaction type.
|
||||
type InPoolTransaction: InPoolTransaction<
|
||||
Transaction = TransactionFor<Self>,
|
||||
Hash = TxHash<Self>
|
||||
>;
|
||||
/// Error type.
|
||||
type Error: From<crate::error::Error> + crate::error::IntoPoolError;
|
||||
|
||||
// *** RPC
|
||||
|
||||
/// Returns a future that imports a bunch of unverified transactions to the pool.
|
||||
fn submit_at(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xts: Vec<TransactionFor<Self>>,
|
||||
) -> PoolFuture<Vec<Result<TxHash<Self>, Self::Error>>, Self::Error>;
|
||||
|
||||
/// Returns a future that imports one unverified transaction to the pool.
|
||||
fn submit_one(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xt: TransactionFor<Self>,
|
||||
) -> PoolFuture<TxHash<Self>, Self::Error>;
|
||||
|
||||
/// Returns a future that import a single transaction and starts to watch their progress in the pool.
|
||||
fn submit_and_watch(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xt: TransactionFor<Self>,
|
||||
) -> PoolFuture<Box<TransactionStatusStreamFor<Self>>, Self::Error>;
|
||||
|
||||
// *** Block production / Networking
|
||||
/// Get an iterator for ready transactions ordered by priority.
|
||||
///
|
||||
/// Guarantees to return only when transaction pool got updated at `at` block.
|
||||
/// Guarantees to return immediately when `None` is passed.
|
||||
fn ready_at(&self, at: NumberFor<Self::Block>)
|
||||
-> Pin<Box<dyn Future<Output=Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send>> + Send>>;
|
||||
|
||||
/// Get an iterator for ready transactions ordered by priority.
|
||||
fn ready(&self) -> Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send>;
|
||||
|
||||
// *** Block production
|
||||
/// Remove transactions identified by given hashes (and dependent transactions) from the pool.
|
||||
fn remove_invalid(&self, hashes: &[TxHash<Self>]) -> Vec<Arc<Self::InPoolTransaction>>;
|
||||
|
||||
// *** logging
|
||||
/// Returns pool status.
|
||||
fn status(&self) -> PoolStatus;
|
||||
|
||||
// *** logging / RPC / networking
|
||||
/// Return an event stream of transactions imported to the pool.
|
||||
fn import_notification_stream(&self) -> ImportNotificationStream<TxHash<Self>>;
|
||||
|
||||
// *** networking
|
||||
/// Notify the pool about transactions broadcast.
|
||||
fn on_broadcasted(&self, propagations: HashMap<TxHash<Self>, Vec<String>>);
|
||||
|
||||
/// Returns transaction hash
|
||||
fn hash_of(&self, xt: &TransactionFor<Self>) -> TxHash<Self>;
|
||||
|
||||
/// Return specific ready transaction by hash, if there is one.
|
||||
fn ready_transaction(&self, hash: &TxHash<Self>) -> Option<Arc<Self::InPoolTransaction>>;
|
||||
}
|
||||
|
||||
/// Events that the transaction pool listens for.
|
||||
pub enum ChainEvent<B: BlockT> {
|
||||
/// New best block have been added to the chain
|
||||
NewBestBlock {
|
||||
/// Hash of the block.
|
||||
hash: B::Hash,
|
||||
/// Tree route from old best to new best parent that was calculated on import.
|
||||
///
|
||||
/// If `None`, no re-org happened on import.
|
||||
tree_route: Option<Arc<sp_blockchain::TreeRoute<B>>>,
|
||||
},
|
||||
/// An existing block has been finalized.
|
||||
Finalized {
|
||||
/// Hash of just finalized block
|
||||
hash: B::Hash,
|
||||
},
|
||||
}
|
||||
|
||||
/// Trait for transaction pool maintenance.
|
||||
pub trait MaintainedTransactionPool: TransactionPool {
|
||||
/// Perform maintenance
|
||||
fn maintain(&self, event: ChainEvent<Self::Block>) -> Pin<Box<dyn Future<Output=()> + Send>>;
|
||||
}
|
||||
|
||||
/// Transaction pool interface for submitting local transactions that exposes a
|
||||
/// blocking interface for submission.
|
||||
pub trait LocalTransactionPool: Send + Sync {
|
||||
/// Block type.
|
||||
type Block: BlockT;
|
||||
/// Transaction hash type.
|
||||
type Hash: Hash + Eq + Member + Serialize;
|
||||
/// Error type.
|
||||
type Error: From<crate::error::Error> + crate::error::IntoPoolError;
|
||||
|
||||
/// Submits the given local unverified transaction to the pool blocking the
|
||||
/// current thread for any necessary pre-verification.
|
||||
/// NOTE: It MUST NOT be used for transactions that originate from the
|
||||
/// network or RPC, since the validation is performed with
|
||||
/// `TransactionSource::Local`.
|
||||
fn submit_local(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
xt: LocalTransactionFor<Self>,
|
||||
) -> Result<Self::Hash, Self::Error>;
|
||||
}
|
||||
|
||||
/// An abstraction for transaction pool.
|
||||
///
|
||||
/// This trait is used by offchain calls to be able to submit transactions.
|
||||
/// The main use case is for offchain workers, to feed back the results of computations,
|
||||
/// but since the transaction pool access is a separate `ExternalitiesExtension` it can
|
||||
/// be also used in context of other offchain calls. For one may generate and submit
|
||||
/// a transaction for some misbehavior reports (say equivocation).
|
||||
pub trait OffchainSubmitTransaction<Block: BlockT>: Send + Sync {
|
||||
/// Submit transaction.
|
||||
///
|
||||
/// The transaction will end up in the pool and be propagated to others.
|
||||
fn submit_at(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
extrinsic: Block::Extrinsic,
|
||||
) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
impl<TPool: LocalTransactionPool> OffchainSubmitTransaction<TPool::Block> for TPool {
|
||||
fn submit_at(
|
||||
&self,
|
||||
at: &BlockId<TPool::Block>,
|
||||
extrinsic: <TPool::Block as BlockT>::Extrinsic,
|
||||
) -> Result<(), ()> {
|
||||
log::debug!(
|
||||
target: "txpool",
|
||||
"(offchain call) Submitting a transaction to the pool: {:?}",
|
||||
extrinsic
|
||||
);
|
||||
|
||||
let result = self.submit_local(&at, extrinsic);
|
||||
|
||||
result.map(|_| ()).map_err(|e| {
|
||||
log::warn!(
|
||||
target: "txpool",
|
||||
"(offchain call) Error submitting a transaction to the pool: {:?}",
|
||||
e
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -19,7 +19,7 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
|
||||
use futures::{future::{ready, Ready}, executor::block_on};
|
||||
use sc_transaction_graph::*;
|
||||
use sc_transaction_pool::{*, test_helpers::*};
|
||||
use codec::Encode;
|
||||
use substrate_test_runtime::{Block, Extrinsic, Transfer, H256, AccountId};
|
||||
use sp_runtime::{
|
||||
@@ -51,15 +51,15 @@ fn to_tag(nonce: u64, from: AccountId) -> Tag {
|
||||
|
||||
impl ChainApi for TestApi {
|
||||
type Block = Block;
|
||||
type Error = sp_transaction_pool::error::Error;
|
||||
type ValidationFuture = Ready<sp_transaction_pool::error::Result<TransactionValidity>>;
|
||||
type BodyFuture = Ready<sp_transaction_pool::error::Result<Option<Vec<Extrinsic>>>>;
|
||||
type Error = sc_transaction_pool_api::error::Error;
|
||||
type ValidationFuture = Ready<sc_transaction_pool_api::error::Result<TransactionValidity>>;
|
||||
type BodyFuture = Ready<sc_transaction_pool_api::error::Result<Option<Vec<Extrinsic>>>>;
|
||||
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
_source: TransactionSource,
|
||||
uxt: ExtrinsicFor<Self>,
|
||||
uxt: test_helpers::ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let nonce = uxt.transfer().nonce;
|
||||
let from = uxt.transfer().from.clone();
|
||||
@@ -89,7 +89,7 @@ impl ChainApi for TestApi {
|
||||
fn block_id_to_number(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> Result<Option<NumberFor<Self>>, Self::Error> {
|
||||
) -> Result<Option<test_helpers::NumberFor<Self>>, Self::Error> {
|
||||
Ok(match at {
|
||||
BlockId::Number(num) => Some(*num),
|
||||
BlockId::Hash(_) => None,
|
||||
@@ -99,14 +99,14 @@ impl ChainApi for TestApi {
|
||||
fn block_id_to_hash(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> Result<Option<BlockHash<Self>>, Self::Error> {
|
||||
) -> Result<Option<test_helpers::BlockHash<Self>>, Self::Error> {
|
||||
Ok(match at {
|
||||
BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(),
|
||||
BlockId::Hash(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn hash_and_length(&self, uxt: &ExtrinsicFor<Self>) -> (H256, usize) {
|
||||
fn hash_and_length(&self, uxt: &test_helpers::ExtrinsicFor<Self>) -> (H256, usize) {
|
||||
let encoded = uxt.encode();
|
||||
(blake2_256(&encoded).into(), encoded.len())
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
Generic Transaction Pool
|
||||
|
||||
The pool is based on dependency graph between transactions
|
||||
and their priority.
|
||||
The pool is able to return an iterator that traverses transaction
|
||||
graph in the correct order taking into account priorities and dependencies.
|
||||
|
||||
License: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
@@ -37,7 +37,7 @@ use sp_api::{ProvideRuntimeApi, ApiExt};
|
||||
use prometheus_endpoint::Registry as PrometheusRegistry;
|
||||
use sp_core::traits::SpawnEssentialNamed;
|
||||
|
||||
use crate::{metrics::{ApiMetrics, ApiMetricsExt}, error::{self, Error}};
|
||||
use crate::{metrics::{ApiMetrics, ApiMetricsExt}, error::{self, Error}, graph};
|
||||
|
||||
/// The transaction pool logic for full client.
|
||||
pub struct FullChainApi<Client, Block> {
|
||||
@@ -103,7 +103,7 @@ impl<Client, Block> FullChainApi<Client, Block> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Block> sc_transaction_graph::ChainApi for FullChainApi<Client, Block>
|
||||
impl<Client, Block> graph::ChainApi for FullChainApi<Client, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
Client: ProvideRuntimeApi<Block> + BlockBackend<Block> + BlockIdTo<Block> + HeaderBackend<Block>,
|
||||
@@ -125,7 +125,7 @@ where
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
uxt: graph::ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let client = self.client.clone();
|
||||
@@ -158,21 +158,21 @@ where
|
||||
fn block_id_to_number(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> error::Result<Option<sc_transaction_graph::NumberFor<Self>>> {
|
||||
) -> error::Result<Option<graph::NumberFor<Self>>> {
|
||||
self.client.to_number(at).map_err(|e| Error::BlockIdConversion(format!("{:?}", e)))
|
||||
}
|
||||
|
||||
fn block_id_to_hash(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> error::Result<Option<sc_transaction_graph::BlockHash<Self>>> {
|
||||
) -> error::Result<Option<graph::BlockHash<Self>>> {
|
||||
self.client.to_hash(at).map_err(|e| Error::BlockIdConversion(format!("{:?}", e)))
|
||||
}
|
||||
|
||||
fn hash_and_length(
|
||||
&self,
|
||||
ex: &sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
) -> (sc_transaction_graph::ExtrinsicHash<Self>, usize) {
|
||||
ex: &graph::ExtrinsicFor<Self>,
|
||||
) -> (graph::ExtrinsicHash<Self>, usize) {
|
||||
ex.using_encoded(|x| {
|
||||
(<traits::HashFor::<Block> as traits::Hash>::hash(x), x.len())
|
||||
})
|
||||
@@ -192,7 +192,7 @@ fn validate_transaction_blocking<Client, Block>(
|
||||
client: &Client,
|
||||
at: &BlockId<Block>,
|
||||
source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<FullChainApi<Client, Block>>,
|
||||
uxt: graph::ExtrinsicFor<FullChainApi<Client, Block>>,
|
||||
) -> error::Result<TransactionValidity>
|
||||
where
|
||||
Block: BlockT,
|
||||
@@ -269,7 +269,7 @@ where
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
uxt: graph::ExtrinsicFor<Self>,
|
||||
) -> error::Result<TransactionValidity> {
|
||||
validate_transaction_blocking(&*self.client, at, source, uxt)
|
||||
}
|
||||
@@ -293,7 +293,7 @@ impl<Client, F, Block> LightChainApi<Client, F, Block> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, F, Block> sc_transaction_graph::ChainApi for
|
||||
impl<Client, F, Block> graph::ChainApi for
|
||||
LightChainApi<Client, F, Block> where
|
||||
Block: BlockT,
|
||||
Client: HeaderBackend<Block> + 'static,
|
||||
@@ -315,7 +315,7 @@ impl<Client, F, Block> sc_transaction_graph::ChainApi for
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
uxt: graph::ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let header_hash = self.client.expect_block_hash_from_id(at);
|
||||
let header_and_hash = header_hash
|
||||
@@ -349,21 +349,21 @@ impl<Client, F, Block> sc_transaction_graph::ChainApi for
|
||||
fn block_id_to_number(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> error::Result<Option<sc_transaction_graph::NumberFor<Self>>> {
|
||||
) -> error::Result<Option<graph::NumberFor<Self>>> {
|
||||
Ok(self.client.block_number_from_id(at)?)
|
||||
}
|
||||
|
||||
fn block_id_to_hash(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> error::Result<Option<sc_transaction_graph::BlockHash<Self>>> {
|
||||
) -> error::Result<Option<graph::BlockHash<Self>>> {
|
||||
Ok(self.client.block_hash_from_id(at)?)
|
||||
}
|
||||
|
||||
fn hash_and_length(
|
||||
&self,
|
||||
ex: &sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
) -> (sc_transaction_graph::ExtrinsicHash<Self>, usize) {
|
||||
ex: &graph::ExtrinsicFor<Self>,
|
||||
) -> (graph::ExtrinsicHash<Self>, usize) {
|
||||
ex.using_encoded(|x| {
|
||||
(<<Block::Header as HeaderT>::Hashing as HashT>::hash(x), x.len())
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
//! Transaction pool error.
|
||||
|
||||
use sp_transaction_pool::error::Error as TxPoolError;
|
||||
use sc_transaction_pool_api::error::Error as TxPoolError;
|
||||
|
||||
/// Transaction pool result.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -41,7 +41,7 @@ pub enum Error {
|
||||
}
|
||||
|
||||
|
||||
impl sp_transaction_pool::error::IntoPoolError for Error {
|
||||
impl sc_transaction_pool_api::error::IntoPoolError for Error {
|
||||
fn into_pool_error(self) -> std::result::Result<TxPoolError, Self> {
|
||||
match self {
|
||||
Error::Pool(e) => Ok(e),
|
||||
|
||||
+5
-3
@@ -37,10 +37,12 @@ use sp_runtime::transaction_validity::{
|
||||
TransactionPriority as Priority,
|
||||
TransactionSource as Source,
|
||||
};
|
||||
use sp_transaction_pool::{error, PoolStatus, InPoolTransaction};
|
||||
use sc_transaction_pool_api::{error, PoolStatus, InPoolTransaction};
|
||||
|
||||
use crate::future::{FutureTransactions, WaitingTransaction};
|
||||
use crate::ready::ReadyTransactions;
|
||||
use super::{
|
||||
future::{FutureTransactions, WaitingTransaction},
|
||||
ready::ReadyTransactions,
|
||||
};
|
||||
|
||||
/// Successful import result.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
+1
-1
@@ -29,7 +29,7 @@ use sp_runtime::transaction_validity::{
|
||||
};
|
||||
use wasm_timer::Instant;
|
||||
|
||||
use crate::base_pool::Transaction;
|
||||
use super::base_pool::Transaction;
|
||||
|
||||
#[cfg_attr(not(target_os = "unknown"), derive(parity_util_mem::MallocSizeOf))]
|
||||
/// Transaction with partially satisfied dependencies.
|
||||
+1
-1
@@ -26,7 +26,7 @@ use serde::Serialize;
|
||||
use log::{debug, trace};
|
||||
use sp_runtime::traits;
|
||||
|
||||
use crate::{watcher, ChainApi, ExtrinsicHash, BlockHash};
|
||||
use super::{watcher, ChainApi, ExtrinsicHash, BlockHash};
|
||||
|
||||
/// Extrinsic pool default listener.
|
||||
pub struct Listener<H: hash::Hash + Eq, C: ChainApi> {
|
||||
+3
-2
@@ -38,7 +38,8 @@ pub mod base_pool;
|
||||
pub mod watcher;
|
||||
|
||||
pub use self::base_pool::Transaction;
|
||||
pub use validated_pool::{IsValidator, ValidatedTransaction};
|
||||
pub use self::pool::{
|
||||
BlockHash, ChainApi, EventStream, ExtrinsicFor, ExtrinsicHash, IsValidator, NumberFor, Options,
|
||||
Pool, TransactionFor, ValidatedTransaction,
|
||||
BlockHash, ChainApi, EventStream, ExtrinsicFor, ExtrinsicHash,
|
||||
NumberFor, Options, Pool, TransactionFor,
|
||||
};
|
||||
+7
-6
@@ -29,13 +29,14 @@ use sp_runtime::{
|
||||
TransactionValidity, TransactionTag as Tag, TransactionValidityError, TransactionSource,
|
||||
},
|
||||
};
|
||||
use sp_transaction_pool::error;
|
||||
use sc_transaction_pool_api::error;
|
||||
use wasm_timer::Instant;
|
||||
use futures::channel::mpsc::Receiver;
|
||||
|
||||
use crate::{base_pool as base, watcher::Watcher};
|
||||
use crate::validated_pool::ValidatedPool;
|
||||
pub use crate::validated_pool::{IsValidator, ValidatedTransaction};
|
||||
use super::{
|
||||
base_pool as base, watcher::Watcher,
|
||||
validated_pool::{IsValidator, ValidatedTransaction, ValidatedPool},
|
||||
};
|
||||
|
||||
/// Modification notification event stream type;
|
||||
pub type EventStream<H> = Receiver<H>;
|
||||
@@ -462,7 +463,7 @@ mod tests {
|
||||
use parking_lot::Mutex;
|
||||
use futures::executor::block_on;
|
||||
use super::*;
|
||||
use sp_transaction_pool::TransactionStatus;
|
||||
use sc_transaction_pool_api::TransactionStatus;
|
||||
use sp_runtime::{
|
||||
traits::Hash,
|
||||
transaction_validity::{ValidTransaction, InvalidTransaction, TransactionSource},
|
||||
@@ -471,7 +472,7 @@ mod tests {
|
||||
use substrate_test_runtime::{Block, Extrinsic, Transfer, H256, AccountId, Hashing};
|
||||
use assert_matches::assert_matches;
|
||||
use wasm_timer::Instant;
|
||||
use crate::base_pool::Limit;
|
||||
use super::super::base_pool::Limit;
|
||||
|
||||
const INVALID_NONCE: u64 = 254;
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
+4
-3
@@ -29,9 +29,9 @@ use sp_runtime::traits::Member;
|
||||
use sp_runtime::transaction_validity::{
|
||||
TransactionTag as Tag,
|
||||
};
|
||||
use sp_transaction_pool::error;
|
||||
use sc_transaction_pool_api::error;
|
||||
|
||||
use crate::{
|
||||
use super::{
|
||||
base_pool::Transaction,
|
||||
future::WaitingTransaction,
|
||||
tracked_map::{self, ReadOnlyTrackedMap, TrackedMap},
|
||||
@@ -149,7 +149,8 @@ impl<Hash: hash::Hash + Member + Serialize, Ex> ReadyTransactions<Hash, Ex> {
|
||||
///
|
||||
/// Transactions are returned in order:
|
||||
/// 1. First by the dependencies:
|
||||
/// - never return transaction that requires a tag, which was not provided by one of the previously returned transactions
|
||||
/// - never return transaction that requires a tag, which was not provided by one of the previously
|
||||
/// returned transactions
|
||||
/// 2. Then by priority:
|
||||
/// - If there are two transactions with all requirements satisfied the one with higher priority goes first.
|
||||
/// 3. Then by the ttl that's left
|
||||
+1
-1
@@ -30,7 +30,7 @@ use std::{
|
||||
use parking_lot::RwLock;
|
||||
use wasm_timer::Instant;
|
||||
|
||||
use crate::base_pool::Transaction;
|
||||
use super::base_pool::Transaction;
|
||||
|
||||
/// Expected size of the banned extrinsics cache.
|
||||
const EXPECTED_SIZE: usize = 2048;
|
||||
+11
-9
@@ -29,17 +29,15 @@ use sp_runtime::{
|
||||
traits::{self, SaturatedConversion},
|
||||
transaction_validity::{TransactionTag as Tag, ValidTransaction, TransactionSource},
|
||||
};
|
||||
use sp_transaction_pool::{error, PoolStatus};
|
||||
use sc_transaction_pool_api::{error, PoolStatus};
|
||||
use wasm_timer::Instant;
|
||||
use futures::channel::mpsc::{channel, Sender};
|
||||
use retain_mut::RetainMut;
|
||||
|
||||
use crate::base_pool::{self as base, PruneStatus};
|
||||
use crate::listener::Listener;
|
||||
use crate::rotator::PoolRotator;
|
||||
use crate::watcher::Watcher;
|
||||
use crate::pool::{
|
||||
EventStream, Options, ChainApi, BlockHash, ExtrinsicHash, ExtrinsicFor, TransactionFor,
|
||||
use super::{
|
||||
base_pool::{self as base, PruneStatus}, watcher::Watcher,
|
||||
listener::Listener, rotator::PoolRotator,
|
||||
pool::{EventStream, Options, ChainApi, BlockHash, ExtrinsicHash, ExtrinsicFor, TransactionFor},
|
||||
};
|
||||
|
||||
/// Pre-validated transaction. Validated pool only accepts transactions wrapped in this enum.
|
||||
@@ -211,7 +209,11 @@ impl<B: ChainApi> ValidatedPool<B> {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
if e.is_full() {
|
||||
log::warn!(target: "txpool", "[{:?}] Trying to notify an import but the channel is full", hash);
|
||||
log::warn!(
|
||||
target: "txpool",
|
||||
"[{:?}] Trying to notify an import but the channel is full",
|
||||
hash,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -548,7 +550,7 @@ impl<B: ChainApi> ValidatedPool<B> {
|
||||
}
|
||||
|
||||
/// Get rotator reference.
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub fn rotator(&self) -> &PoolRotator<ExtrinsicHash<B>> {
|
||||
&self.rotator
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
//! Extrinsics status updates.
|
||||
|
||||
use futures::Stream;
|
||||
use sp_transaction_pool::TransactionStatus;
|
||||
use sc_transaction_pool_api::TransactionStatus;
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender, TracingUnboundedReceiver};
|
||||
|
||||
/// Extrinsic watcher.
|
||||
@@ -23,17 +23,23 @@
|
||||
#![warn(unused_extern_crates)]
|
||||
|
||||
mod api;
|
||||
mod graph;
|
||||
mod revalidation;
|
||||
mod metrics;
|
||||
|
||||
pub mod error;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod testing;
|
||||
/// Common types for testing the transaction pool
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub mod test_helpers {
|
||||
pub use super::{
|
||||
graph::{ChainApi, Pool, NumberFor, BlockHash, ExtrinsicFor},
|
||||
revalidation::RevalidationQueue,
|
||||
};
|
||||
}
|
||||
|
||||
pub use sc_transaction_graph::{ChainApi, Options, Pool};
|
||||
pub use graph::{Options, Transaction};
|
||||
pub use crate::api::{FullChainApi, LightChainApi};
|
||||
|
||||
use std::{collections::{HashMap, HashSet}, sync::Arc, pin::Pin, convert::TryInto};
|
||||
use futures::{prelude::*, future::{self, ready}, channel::oneshot};
|
||||
use parking_lot::Mutex;
|
||||
@@ -43,23 +49,23 @@ use sp_runtime::{
|
||||
traits::{Block as BlockT, NumberFor, AtLeast32Bit, Extrinsic, Zero, Header as HeaderT},
|
||||
};
|
||||
use sp_core::traits::SpawnEssentialNamed;
|
||||
use sp_transaction_pool::{
|
||||
use sc_transaction_pool_api::{
|
||||
TransactionPool, PoolStatus, ImportNotificationStream, TxHash, TransactionFor,
|
||||
TransactionStatusStreamFor, MaintainedTransactionPool, PoolFuture, ChainEvent,
|
||||
TransactionSource,
|
||||
};
|
||||
use sc_transaction_graph::{IsValidator, ExtrinsicHash};
|
||||
use graph::{IsValidator, ExtrinsicHash};
|
||||
use wasm_timer::Instant;
|
||||
|
||||
use prometheus_endpoint::Registry as PrometheusRegistry;
|
||||
use crate::metrics::MetricsLink as PrometheusMetrics;
|
||||
|
||||
type BoxedReadyIterator<Hash, Data> = Box<
|
||||
dyn Iterator<Item=Arc<sc_transaction_graph::base_pool::Transaction<Hash, Data>>> + Send
|
||||
dyn Iterator<Item=Arc<graph::base_pool::Transaction<Hash, Data>>> + Send
|
||||
>;
|
||||
|
||||
type ReadyIteratorFor<PoolApi> = BoxedReadyIterator<
|
||||
sc_transaction_graph::ExtrinsicHash<PoolApi>, sc_transaction_graph::ExtrinsicFor<PoolApi>
|
||||
graph::ExtrinsicHash<PoolApi>, graph::ExtrinsicFor<PoolApi>
|
||||
>;
|
||||
|
||||
type PolledIterator<PoolApi> = Pin<Box<dyn Future<Output=ReadyIteratorFor<PoolApi>> + Send>>;
|
||||
@@ -73,9 +79,9 @@ pub type LightPool<Block, Client, Fetcher> = BasicPool<LightChainApi<Client, Fet
|
||||
pub struct BasicPool<PoolApi, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
PoolApi: ChainApi<Block=Block>,
|
||||
PoolApi: graph::ChainApi<Block=Block>,
|
||||
{
|
||||
pool: Arc<sc_transaction_graph::Pool<PoolApi>>,
|
||||
pool: Arc<graph::Pool<PoolApi>>,
|
||||
api: Arc<PoolApi>,
|
||||
revalidation_strategy: Arc<Mutex<RevalidationStrategy<NumberFor<Block>>>>,
|
||||
revalidation_queue: Arc<revalidation::RevalidationQueue<PoolApi>>,
|
||||
@@ -134,7 +140,7 @@ impl<T, Block: BlockT> ReadyPoll<T, Block> {
|
||||
#[cfg(not(target_os = "unknown"))]
|
||||
impl<PoolApi, Block> parity_util_mem::MallocSizeOf for BasicPool<PoolApi, Block>
|
||||
where
|
||||
PoolApi: ChainApi<Block=Block>,
|
||||
PoolApi: graph::ChainApi<Block=Block>,
|
||||
Block: BlockT,
|
||||
{
|
||||
fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize {
|
||||
@@ -163,14 +169,14 @@ pub enum RevalidationType {
|
||||
impl<PoolApi, Block> BasicPool<PoolApi, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
PoolApi: ChainApi<Block=Block> + 'static,
|
||||
PoolApi: graph::ChainApi<Block=Block> + 'static,
|
||||
{
|
||||
/// Create new basic transaction pool with provided api, for tests.
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub fn new_test(
|
||||
pool_api: Arc<PoolApi>,
|
||||
) -> (Self, Pin<Box<dyn Future<Output=()> + Send>>, intervalier::BackSignalControl) {
|
||||
let pool = Arc::new(sc_transaction_graph::Pool::new(Default::default(), true.into(), pool_api.clone()));
|
||||
let pool = Arc::new(graph::Pool::new(Default::default(), true.into(), pool_api.clone()));
|
||||
let (revalidation_queue, background_task, notifier) =
|
||||
revalidation::RevalidationQueue::new_test(pool_api.clone(), pool.clone());
|
||||
(
|
||||
@@ -190,7 +196,7 @@ impl<PoolApi, Block> BasicPool<PoolApi, Block>
|
||||
/// Create new basic transaction pool with provided api and custom
|
||||
/// revalidation type.
|
||||
pub fn with_revalidation_type(
|
||||
options: sc_transaction_graph::Options,
|
||||
options: graph::Options,
|
||||
is_validator: IsValidator,
|
||||
pool_api: Arc<PoolApi>,
|
||||
prometheus: Option<&PrometheusRegistry>,
|
||||
@@ -198,7 +204,7 @@ impl<PoolApi, Block> BasicPool<PoolApi, Block>
|
||||
spawner: impl SpawnEssentialNamed,
|
||||
best_block_number: NumberFor<Block>,
|
||||
) -> Self {
|
||||
let pool = Arc::new(sc_transaction_graph::Pool::new(options, is_validator, pool_api.clone()));
|
||||
let pool = Arc::new(graph::Pool::new(options, is_validator, pool_api.clone()));
|
||||
let (revalidation_queue, background_task) = match revalidation_type {
|
||||
RevalidationType::Light => (
|
||||
revalidation::RevalidationQueue::new(pool_api.clone(), pool.clone()),
|
||||
@@ -233,19 +239,25 @@ impl<PoolApi, Block> BasicPool<PoolApi, Block>
|
||||
}
|
||||
|
||||
/// Gets shared reference to the underlying pool.
|
||||
pub fn pool(&self) -> &Arc<sc_transaction_graph::Pool<PoolApi>> {
|
||||
pub fn pool(&self) -> &Arc<graph::Pool<PoolApi>> {
|
||||
&self.pool
|
||||
}
|
||||
|
||||
/// Get access to the underlying api
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub fn api(&self) -> &PoolApi {
|
||||
&self.api
|
||||
}
|
||||
}
|
||||
|
||||
impl<PoolApi, Block> TransactionPool for BasicPool<PoolApi, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
PoolApi: 'static + ChainApi<Block=Block>,
|
||||
PoolApi: 'static + graph::ChainApi<Block=Block>,
|
||||
{
|
||||
type Block = PoolApi::Block;
|
||||
type Hash = sc_transaction_graph::ExtrinsicHash<PoolApi>;
|
||||
type InPoolTransaction = sc_transaction_graph::base_pool::Transaction<
|
||||
type Hash = graph::ExtrinsicHash<PoolApi>;
|
||||
type InPoolTransaction = graph::base_pool::Transaction<
|
||||
TxHash<Self>, TransactionFor<Self>
|
||||
>;
|
||||
type Error = PoolApi::Error;
|
||||
@@ -361,7 +373,7 @@ where
|
||||
{
|
||||
/// Create new basic transaction pool for a light node with the provided api.
|
||||
pub fn new_light(
|
||||
options: sc_transaction_graph::Options,
|
||||
options: graph::Options,
|
||||
prometheus: Option<&PrometheusRegistry>,
|
||||
spawner: impl SpawnEssentialNamed,
|
||||
client: Arc<Client>,
|
||||
@@ -396,7 +408,7 @@ where
|
||||
{
|
||||
/// Create new basic transaction pool for a full node with the provided api.
|
||||
pub fn new_full(
|
||||
options: sc_transaction_graph::Options,
|
||||
options: graph::Options,
|
||||
is_validator: IsValidator,
|
||||
prometheus: Option<&PrometheusRegistry>,
|
||||
spawner: impl SpawnEssentialNamed,
|
||||
@@ -420,7 +432,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block, Client> sp_transaction_pool::LocalTransactionPool
|
||||
impl<Block, Client> sc_transaction_pool_api::LocalTransactionPool
|
||||
for BasicPool<FullChainApi<Client, Block>, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
@@ -432,15 +444,15 @@ where
|
||||
Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
|
||||
{
|
||||
type Block = Block;
|
||||
type Hash = sc_transaction_graph::ExtrinsicHash<FullChainApi<Client, Block>>;
|
||||
type Error = <FullChainApi<Client, Block> as ChainApi>::Error;
|
||||
type Hash = graph::ExtrinsicHash<FullChainApi<Client, Block>>;
|
||||
type Error = <FullChainApi<Client, Block> as graph::ChainApi>::Error;
|
||||
|
||||
fn submit_local(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
xt: sp_transaction_pool::LocalTransactionFor<Self>,
|
||||
xt: sc_transaction_pool_api::LocalTransactionFor<Self>,
|
||||
) -> Result<Self::Hash, Self::Error> {
|
||||
use sc_transaction_graph::ValidatedTransaction;
|
||||
use graph::{ValidatedTransaction, ChainApi};
|
||||
use sp_runtime::traits::SaturatedConversion;
|
||||
use sp_runtime::transaction_validity::TransactionValidityError;
|
||||
|
||||
@@ -558,10 +570,10 @@ impl<N: Clone + Copy + AtLeast32Bit> RevalidationStatus<N> {
|
||||
}
|
||||
|
||||
/// Prune the known txs for the given block.
|
||||
async fn prune_known_txs_for_block<Block: BlockT, Api: ChainApi<Block = Block>>(
|
||||
async fn prune_known_txs_for_block<Block: BlockT, Api: graph::ChainApi<Block = Block>>(
|
||||
block_id: BlockId<Block>,
|
||||
api: &Api,
|
||||
pool: &sc_transaction_graph::Pool<Api>,
|
||||
pool: &graph::Pool<Api>,
|
||||
) -> Vec<ExtrinsicHash<Api>> {
|
||||
let extrinsics = api.block_body(&block_id).await
|
||||
.unwrap_or_else(|e| {
|
||||
@@ -598,7 +610,7 @@ async fn prune_known_txs_for_block<Block: BlockT, Api: ChainApi<Block = Block>>(
|
||||
impl<PoolApi, Block> MaintainedTransactionPool for BasicPool<PoolApi, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
PoolApi: 'static + ChainApi<Block=Block>,
|
||||
PoolApi: 'static + graph::ChainApi<Block=Block>,
|
||||
{
|
||||
fn maintain(&self, event: ChainEvent<Self::Block>) -> Pin<Box<dyn Future<Output=()> + Send>> {
|
||||
match event {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
use std::{sync::Arc, pin::Pin, collections::{HashMap, HashSet, BTreeMap}};
|
||||
|
||||
use sc_transaction_graph::{ChainApi, Pool, ExtrinsicHash, NumberFor, ValidatedTransaction};
|
||||
use crate::graph::{ChainApi, Pool, ExtrinsicHash, NumberFor, ValidatedTransaction};
|
||||
use sp_runtime::traits::{Zero, SaturatedConversion};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_runtime::transaction_validity::TransactionValidityError;
|
||||
@@ -29,9 +29,9 @@ use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender, TracingUnbounded
|
||||
use futures::prelude::*;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[cfg(not(feature = "test-helpers"))]
|
||||
const BACKGROUND_REVALIDATION_INTERVAL: Duration = Duration::from_millis(200);
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub const BACKGROUND_REVALIDATION_INTERVAL: Duration = Duration::from_millis(1);
|
||||
|
||||
const MIN_BACKGROUND_REVALIDATION_BATCH_SIZE: usize = 20;
|
||||
@@ -225,7 +225,7 @@ impl<Api: ChainApi> RevalidationWorker<Api> {
|
||||
|
||||
batch_revalidate(this.pool.clone(), this.api.clone(), this.best_block, next_batch).await;
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "test-helpers")]
|
||||
{
|
||||
use intervalier::Guard;
|
||||
// only trigger test events if something was processed
|
||||
@@ -293,6 +293,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// New revalidation queue with background worker.
|
||||
pub fn new_with_interval<R: intervalier::IntoStream>(
|
||||
api: Arc<Api>,
|
||||
pool: Arc<Pool<Api>>,
|
||||
@@ -320,7 +321,7 @@ where
|
||||
}
|
||||
|
||||
/// New revalidation queue with background worker and test signal.
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub fn new_test(api: Arc<Api>, pool: Arc<Pool<Api>>) ->
|
||||
(Self, Pin<Box<dyn Future<Output=()> + Send>>, intervalier::BackSignalControl)
|
||||
{
|
||||
@@ -361,35 +362,5 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sc_transaction_graph::Pool;
|
||||
use sp_transaction_pool::TransactionSource;
|
||||
use substrate_test_runtime_transaction_pool::{TestApi, uxt};
|
||||
use futures::executor::block_on;
|
||||
use substrate_test_runtime_client::AccountKeyring::*;
|
||||
|
||||
fn setup() -> (Arc<TestApi>, Pool<TestApi>) {
|
||||
let test_api = Arc::new(TestApi::empty());
|
||||
let pool = Pool::new(Default::default(), true.into(), test_api.clone());
|
||||
(test_api, pool)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoky() {
|
||||
let (api, pool) = setup();
|
||||
let pool = Arc::new(pool);
|
||||
let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone()));
|
||||
|
||||
let uxt = uxt(Alice, 0);
|
||||
let uxt_hash = block_on(
|
||||
pool.submit_one(&BlockId::number(0), TransactionSource::External, uxt.clone())
|
||||
).expect("Should be valid");
|
||||
|
||||
block_on(queue.revalidate_later(0, vec![uxt_hash]));
|
||||
|
||||
// revalidated in sync offload 2nd time
|
||||
assert_eq!(api.validation_requests().len(), 2);
|
||||
// number of ready
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2021 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/>.
|
||||
|
||||
//! Tests for top-level transaction pool api
|
||||
|
||||
mod pool;
|
||||
+75
-73
@@ -16,11 +16,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
use sp_transaction_pool::TransactionStatus;
|
||||
//! Tests for top-level transaction pool api
|
||||
use sc_transaction_pool_api::{TransactionStatus, ChainEvent, MaintainedTransactionPool, TransactionPool};
|
||||
use futures::executor::{block_on, block_on_stream};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
generic::BlockId, traits::Block as _,
|
||||
transaction_validity::{ValidTransaction, TransactionSource, InvalidTransaction},
|
||||
};
|
||||
use substrate_test_runtime_client::{
|
||||
@@ -30,10 +30,11 @@ use substrate_test_runtime_client::{
|
||||
use substrate_test_runtime_transaction_pool::{TestApi, uxt};
|
||||
use futures::{prelude::*, task::Poll};
|
||||
use codec::Encode;
|
||||
use std::collections::BTreeSet;
|
||||
use std::{collections::BTreeSet, sync::Arc, convert::TryInto};
|
||||
use sc_client_api::client::BlockchainEvents;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sc_transaction_pool::{*, test_helpers::*};
|
||||
|
||||
fn pool() -> Pool<TestApi> {
|
||||
Pool::new(Default::default(), true.into(), TestApi::with_alice_nonce(209).into())
|
||||
@@ -142,10 +143,10 @@ fn only_prune_on_new_best() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(0), SOURCE, uxt.clone())
|
||||
).expect("1. Imported");
|
||||
pool.api.push_block(1, vec![uxt.clone()], true);
|
||||
pool.api().push_block(1, vec![uxt.clone()], true);
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let header = pool.api.push_block(2, vec![uxt], true);
|
||||
let header = pool.api().push_block(2, vec![uxt], true);
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
hash: header.hash(),
|
||||
tree_route: None,
|
||||
@@ -220,7 +221,7 @@ fn should_prune_old_during_maintenance() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let header = pool.api.push_block(1, vec![xt.clone()], true);
|
||||
let header = pool.api().push_block(1, vec![xt.clone()], true);
|
||||
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
@@ -235,16 +236,16 @@ fn should_revalidate_during_maintenance() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("2. Imported");
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
assert_eq!(pool.api.validation_requests().len(), 2);
|
||||
assert_eq!(pool.api().validation_requests().len(), 2);
|
||||
|
||||
let header = pool.api.push_block(1, vec![xt1.clone()], true);
|
||||
let header = pool.api().push_block(1, vec![xt1.clone()], true);
|
||||
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
block_on(notifier.next());
|
||||
|
||||
// test that pool revalidated transaction that left ready and not included in the block
|
||||
assert_eq!(pool.api.validation_requests().len(), 3);
|
||||
assert_eq!(pool.api().validation_requests().len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -256,10 +257,10 @@ fn should_resubmit_from_retracted_during_maintenance() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let fork_header = pool.api.push_block(1, vec![], false);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
let fork_header = pool.api().push_block(1, vec![], false);
|
||||
|
||||
let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api);
|
||||
let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api());
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
@@ -275,10 +276,10 @@ fn should_not_resubmit_from_retracted_during_maintenance_if_tx_is_also_in_enacte
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let header = pool.api.push_block(1, vec![xt.clone()], true);
|
||||
let fork_header = pool.api.push_block(1, vec![xt], false);
|
||||
let header = pool.api().push_block(1, vec![xt.clone()], true);
|
||||
let fork_header = pool.api().push_block(1, vec![xt], false);
|
||||
|
||||
let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api);
|
||||
let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api());
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
@@ -293,11 +294,11 @@ fn should_not_retain_invalid_hashes_from_retracted() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let fork_header = pool.api.push_block(1, vec![xt.clone()], false);
|
||||
pool.api.add_invalid(&xt);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
let fork_header = pool.api().push_block(1, vec![xt.clone()], false);
|
||||
pool.api().add_invalid(&xt);
|
||||
|
||||
let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api);
|
||||
let event = block_event_with_retracted(header, fork_header.hash(), &*pool.api());
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
block_on(notifier.next());
|
||||
@@ -317,20 +318,20 @@ fn should_revalidate_across_many_blocks() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
block_on(notifier.next());
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt3.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
|
||||
let header = pool.api.push_block(2, vec![xt1.clone()], true);
|
||||
let header = pool.api().push_block(2, vec![xt1.clone()], true);
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
block_on(notifier.next());
|
||||
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
// xt1 and xt2 validated twice, then xt3 once, then xt2 and xt3 again
|
||||
assert_eq!(pool.api.validation_requests().len(), 7);
|
||||
assert_eq!(pool.api().validation_requests().len(), 7);
|
||||
}
|
||||
|
||||
|
||||
@@ -366,11 +367,11 @@ fn should_push_watchers_during_maintenance() {
|
||||
assert_eq!(pool.status().ready, 5);
|
||||
|
||||
// when
|
||||
pool.api.add_invalid(&tx3);
|
||||
pool.api.add_invalid(&tx4);
|
||||
pool.api().add_invalid(&tx3);
|
||||
pool.api().add_invalid(&tx4);
|
||||
|
||||
// clear timer events if any
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
block_on(notifier.next());
|
||||
|
||||
@@ -388,7 +389,7 @@ fn should_push_watchers_during_maintenance() {
|
||||
);
|
||||
|
||||
// when
|
||||
let header = pool.api.push_block(2, vec![tx0, tx1, tx2], true);
|
||||
let header = pool.api().push_block(2, vec![tx0, tx1, tx2], true);
|
||||
let header_hash = header.hash();
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
|
||||
@@ -442,9 +443,9 @@ fn finalization() {
|
||||
let watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())
|
||||
).expect("1. Imported");
|
||||
pool.api.push_block(2, vec![xt.clone()], true);
|
||||
pool.api().push_block(2, vec![xt.clone()], true);
|
||||
|
||||
let header = pool.api.chain().read().block_by_number.get(&2).unwrap()[0].0.header().clone();
|
||||
let header = pool.api().chain().read().block_by_number.get(&2).unwrap()[0].0.header().clone();
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
hash: header.hash(),
|
||||
tree_route: None,
|
||||
@@ -474,10 +475,10 @@ fn fork_aware_finalization() {
|
||||
let from_dave = uxt(Dave, 2);
|
||||
let from_bob = uxt(Bob, 1);
|
||||
let from_charlie = uxt(Charlie, 1);
|
||||
pool.api.increment_nonce(Alice.into());
|
||||
pool.api.increment_nonce(Dave.into());
|
||||
pool.api.increment_nonce(Charlie.into());
|
||||
pool.api.increment_nonce(Bob.into());
|
||||
pool.api().increment_nonce(Alice.into());
|
||||
pool.api().increment_nonce(Dave.into());
|
||||
pool.api().increment_nonce(Charlie.into());
|
||||
pool.api().increment_nonce(Bob.into());
|
||||
|
||||
let from_dave_watcher;
|
||||
let from_bob_watcher;
|
||||
@@ -491,7 +492,7 @@ fn fork_aware_finalization() {
|
||||
let watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(2, vec![from_alice.clone()], true);
|
||||
let header = pool.api().push_block(2, vec![from_alice.clone()], true);
|
||||
canon_watchers.push((watcher, header.hash()));
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
@@ -508,7 +509,7 @@ fn fork_aware_finalization() {
|
||||
|
||||
// block C2
|
||||
{
|
||||
let header = pool.api.push_block_with_parent(b1, vec![from_dave.clone()], true);
|
||||
let header = pool.api().push_block_with_parent(b1, vec![from_dave.clone()], true);
|
||||
from_dave_watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_dave.clone())
|
||||
).expect("1. Imported");
|
||||
@@ -528,7 +529,7 @@ fn fork_aware_finalization() {
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())
|
||||
).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
let header = pool.api.push_block_with_parent(c2, vec![from_bob.clone()], true);
|
||||
let header = pool.api().push_block_with_parent(c2, vec![from_bob.clone()], true);
|
||||
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
hash: header.hash(),
|
||||
@@ -545,10 +546,10 @@ fn fork_aware_finalization() {
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())
|
||||
).expect("1.Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
let header = pool.api.push_block(3, vec![from_charlie.clone()], true);
|
||||
let header = pool.api().push_block(3, vec![from_charlie.clone()], true);
|
||||
|
||||
canon_watchers.push((watcher, header.hash()));
|
||||
let event = block_event_with_retracted(header.clone(), d2, &*pool.api);
|
||||
let event = block_event_with_retracted(header.clone(), d2, &*pool.api());
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
|
||||
@@ -563,7 +564,7 @@ fn fork_aware_finalization() {
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())
|
||||
).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
let header = pool.api.push_block(4, vec![xt.clone()], true);
|
||||
let header = pool.api().push_block(4, vec![xt.clone()], true);
|
||||
canon_watchers.push((w, header.hash()));
|
||||
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
@@ -581,7 +582,7 @@ fn fork_aware_finalization() {
|
||||
|
||||
// block e1
|
||||
{
|
||||
let header = pool.api.push_block(5, vec![from_dave, from_bob], true);
|
||||
let header = pool.api().push_block(5, vec![from_dave, from_bob], true);
|
||||
e1 = header.hash();
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
hash: header.hash(),
|
||||
@@ -636,7 +637,7 @@ fn prune_and_retract_tx_at_same_time() {
|
||||
let (pool, _background, _) = BasicPool::new_test(api.into());
|
||||
|
||||
let from_alice = uxt(Alice, 1);
|
||||
pool.api.increment_nonce(Alice.into());
|
||||
pool.api().increment_nonce(Alice.into());
|
||||
|
||||
let watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())
|
||||
@@ -644,7 +645,7 @@ fn prune_and_retract_tx_at_same_time() {
|
||||
|
||||
// Block B1
|
||||
let b1 = {
|
||||
let header = pool.api.push_block(2, vec![from_alice.clone()], true);
|
||||
let header = pool.api().push_block(2, vec![from_alice.clone()], true);
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
@@ -658,10 +659,10 @@ fn prune_and_retract_tx_at_same_time() {
|
||||
|
||||
// Block B2
|
||||
let b2 = {
|
||||
let header = pool.api.push_block(2, vec![from_alice.clone()], false);
|
||||
let header = pool.api().push_block(2, vec![from_alice.clone()], false);
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
|
||||
let event = block_event_with_retracted(header.clone(), b1, &*pool.api);
|
||||
let event = block_event_with_retracted(header.clone(), b1, &*pool.api());
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
|
||||
@@ -708,8 +709,8 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() {
|
||||
|
||||
let tx0 = uxt(Alice, 1);
|
||||
let tx1 = uxt(Dave, 2);
|
||||
pool.api.increment_nonce(Alice.into());
|
||||
pool.api.increment_nonce(Dave.into());
|
||||
pool.api().increment_nonce(Alice.into());
|
||||
pool.api().increment_nonce(Dave.into());
|
||||
|
||||
let d0;
|
||||
|
||||
@@ -718,7 +719,7 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx0.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(2, vec![tx0.clone()], true);
|
||||
let header = pool.api().push_block(2, vec![tx0.clone()], true);
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let event = ChainEvent::NewBestBlock {
|
||||
@@ -735,14 +736,14 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx1.clone())
|
||||
).expect("1. Imported");
|
||||
pool.api.push_block(2, vec![tx1.clone()], false);
|
||||
pool.api().push_block(2, vec![tx1.clone()], false);
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
}
|
||||
|
||||
// Block D2
|
||||
{
|
||||
let header = pool.api.push_block(2, vec![], false);
|
||||
let event = block_event_with_retracted(header, d0, &*pool.api);
|
||||
let header = pool.api().push_block(2, vec![], false);
|
||||
let event = block_event_with_retracted(header, d0, &*pool.api());
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
}
|
||||
@@ -765,19 +766,19 @@ fn resubmit_from_retracted_fork() {
|
||||
let tx4 = uxt(Ferdie, 2);
|
||||
let tx5 = uxt(One, 3);
|
||||
|
||||
pool.api.increment_nonce(Alice.into());
|
||||
pool.api.increment_nonce(Dave.into());
|
||||
pool.api.increment_nonce(Bob.into());
|
||||
pool.api.increment_nonce(Eve.into());
|
||||
pool.api.increment_nonce(Ferdie.into());
|
||||
pool.api.increment_nonce(One.into());
|
||||
pool.api().increment_nonce(Alice.into());
|
||||
pool.api().increment_nonce(Dave.into());
|
||||
pool.api().increment_nonce(Bob.into());
|
||||
pool.api().increment_nonce(Eve.into());
|
||||
pool.api().increment_nonce(Ferdie.into());
|
||||
pool.api().increment_nonce(One.into());
|
||||
|
||||
// Block D0
|
||||
{
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx0.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(2, vec![tx0.clone()], true);
|
||||
let header = pool.api().push_block(2, vec![tx0.clone()], true);
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
@@ -789,7 +790,7 @@ fn resubmit_from_retracted_fork() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx1.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(3, vec![tx1.clone()], true);
|
||||
let header = pool.api().push_block(3, vec![tx1.clone()], true);
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
}
|
||||
@@ -799,7 +800,7 @@ fn resubmit_from_retracted_fork() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx2.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(4, vec![tx2.clone()], true);
|
||||
let header = pool.api().push_block(4, vec![tx2.clone()], true);
|
||||
block_on(pool.maintain(block_event(header.clone())));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
header.hash()
|
||||
@@ -810,7 +811,7 @@ fn resubmit_from_retracted_fork() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx3.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(2, vec![tx3.clone()], true);
|
||||
let header = pool.api().push_block(2, vec![tx3.clone()], true);
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
header.hash()
|
||||
};
|
||||
@@ -820,7 +821,7 @@ fn resubmit_from_retracted_fork() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx4.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block_with_parent(d1.clone(), vec![tx4.clone()], true);
|
||||
let header = pool.api().push_block_with_parent(d1.clone(), vec![tx4.clone()], true);
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
header.hash()
|
||||
};
|
||||
@@ -830,7 +831,7 @@ fn resubmit_from_retracted_fork() {
|
||||
let _ = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, tx5.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block_with_parent(e1.clone(), vec![tx5.clone()], true);
|
||||
let header = pool.api().push_block_with_parent(e1.clone(), vec![tx5.clone()], true);
|
||||
// Don't announce the block event to the pool directly, because we will
|
||||
// re-org to this block.
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
@@ -841,7 +842,7 @@ fn resubmit_from_retracted_fork() {
|
||||
let expected_ready = vec![tx3, tx4, tx5].iter().map(Encode::encode).collect::<BTreeSet<_>>();
|
||||
assert_eq!(expected_ready, ready);
|
||||
|
||||
let event = block_event_with_retracted(f1_header, f0, &*pool.api);
|
||||
let event = block_event_with_retracted(f1_header, f0, &*pool.api());
|
||||
block_on(pool.maintain(event));
|
||||
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
@@ -862,7 +863,7 @@ fn ready_set_should_not_resolve_before_block_update() {
|
||||
#[test]
|
||||
fn ready_set_should_resolve_after_block_update() {
|
||||
let (pool, _guard, _notifier) = maintained_pool();
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
|
||||
let xt1 = uxt(Alice, 209);
|
||||
|
||||
@@ -875,7 +876,7 @@ fn ready_set_should_resolve_after_block_update() {
|
||||
#[test]
|
||||
fn ready_set_should_eventually_resolve_when_block_update_arrives() {
|
||||
let (pool, _guard, _notifier) = maintained_pool();
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
|
||||
let xt1 = uxt(Alice, 209);
|
||||
|
||||
@@ -926,7 +927,8 @@ fn should_not_accept_old_signatures() {
|
||||
|
||||
// generated with schnorrkel 0.1.1 from `_bytes`
|
||||
let old_singature = sp_core::sr25519::Signature::try_from(&hex::decode(
|
||||
"c427eb672e8c441c86d31f1a81b22b43102058e9ce237cabe9897ea5099ffd426cd1c6a1f4f2869c3df57901d36bedcb295657adb3a4355add86ed234eb83108"
|
||||
"c427eb672e8c441c86d31f1a81b22b43102058e9ce237cabe9897ea5099ffd426\
|
||||
cd1c6a1f4f2869c3df57901d36bedcb295657adb3a4355add86ed234eb83108"
|
||||
).expect("hex invalid")[..]).expect("signature construction failed");
|
||||
|
||||
let xt = Extrinsic::Transfer {
|
||||
@@ -938,7 +940,7 @@ fn should_not_accept_old_signatures() {
|
||||
assert_matches::assert_matches!(
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())),
|
||||
Err(error::Error::Pool(
|
||||
sp_transaction_pool::error::Error::InvalidTransaction(InvalidTransaction::BadProof)
|
||||
sc_transaction_pool_api::error::Error::InvalidTransaction(InvalidTransaction::BadProof)
|
||||
)),
|
||||
"Should be invalid transaction with bad proof",
|
||||
);
|
||||
@@ -985,7 +987,7 @@ fn pruning_a_transaction_should_remove_it_from_best_transaction() {
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
let header = pool.api.push_block(1, vec![xt1.clone()], true);
|
||||
let header = pool.api().push_block(1, vec![xt1.clone()], true);
|
||||
|
||||
// This will prune `xt1`.
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
@@ -1002,10 +1004,10 @@ fn only_revalidate_on_best_block() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
let header = pool.api.push_block(1, vec![], true);
|
||||
let header = pool.api().push_block(1, vec![], true);
|
||||
|
||||
pool.api.push_block(2, vec![], false);
|
||||
pool.api.push_block(2, vec![], false);
|
||||
pool.api().push_block(2, vec![], false);
|
||||
pool.api().push_block(2, vec![], false);
|
||||
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
block_on(notifier.next());
|
||||
@@ -1073,7 +1075,7 @@ fn stale_transactions_are_pruned() {
|
||||
];
|
||||
|
||||
// Import block
|
||||
let header = pool.api.push_block(1, xts, true);
|
||||
let header = pool.api().push_block(1, xts, true);
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
// The imported transactions have a different hash and should not evict our initial
|
||||
// transactions.
|
||||
@@ -1081,7 +1083,7 @@ fn stale_transactions_are_pruned() {
|
||||
|
||||
// Import enough blocks to make our transactions stale
|
||||
for n in 1..66 {
|
||||
let header = pool.api.push_block(n, vec![], true);
|
||||
let header = pool.api().push_block(n, vec![], true);
|
||||
block_on(pool.maintain(block_event(header)));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
use sc_transaction_pool::test_helpers::{Pool, RevalidationQueue};
|
||||
use sc_transaction_pool_api::TransactionSource;
|
||||
use substrate_test_runtime_transaction_pool::{TestApi, uxt};
|
||||
use futures::executor::block_on;
|
||||
use substrate_test_runtime_client::AccountKeyring::*;
|
||||
use std::sync::Arc;
|
||||
use sp_runtime::generic::BlockId;
|
||||
|
||||
fn setup() -> (Arc<TestApi>, Pool<TestApi>) {
|
||||
let test_api = Arc::new(TestApi::empty());
|
||||
let pool = Pool::new(Default::default(), true.into(), test_api.clone());
|
||||
(test_api, pool)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoky() {
|
||||
let (api, pool) = setup();
|
||||
let pool = Arc::new(pool);
|
||||
let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone()));
|
||||
|
||||
let uxt = uxt(Alice, 0);
|
||||
let uxt_hash = block_on(
|
||||
pool.submit_one(&BlockId::number(0), TransactionSource::External, uxt.clone())
|
||||
).expect("Should be valid");
|
||||
|
||||
block_on(queue.revalidate_later(0, vec![uxt_hash]));
|
||||
|
||||
// revalidated in sync offload 2nd time
|
||||
assert_eq!(api.validation_requests().len(), 2);
|
||||
// number of ready
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user