// Copyright 2019-2020 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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. // Substrate 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 Substrate. If not, see . //! Transaction pool primitives types & Runtime API. use std::{ collections::HashMap, hash::Hash, sync::Arc, pin::Pin, }; use futures::{Future, Stream,}; use serde::{Deserialize, Serialize}; use sp_utils::mpsc; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Member, NumberFor}, 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 { /// 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), /// 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 = dyn Stream> + Send + Unpin; /// The import notification event stream. pub type ImportNotificationStream = mpsc::TracingUnboundedReceiver; /// Transaction hash type for a pool. pub type TxHash

=

::Hash; /// Block hash type for a pool. pub type BlockHash

= <

::Block as BlockT>::Hash; /// Transaction type for a pool. pub type TransactionFor

= <

::Block as BlockT>::Extrinsic; /// Type of transactions event stream for a pool. pub type TransactionStatusStreamFor

= TransactionStatusStream, BlockHash

>; /// Typical future type used in transaction pool api. pub type PoolFuture = std::pin::Pin> + 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, Hash = TxHash >; /// Error type. type Error: From + crate::error::IntoPoolError; // *** RPC /// Returns a future that imports a bunch of unverified transactions to the pool. fn submit_at( &self, at: &BlockId, source: TransactionSource, xts: Vec>, ) -> PoolFuture, Self::Error>>, Self::Error>; /// Returns a future that imports one unverified transaction to the pool. fn submit_one( &self, at: &BlockId, source: TransactionSource, xt: TransactionFor, ) -> PoolFuture, 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, source: TransactionSource, xt: TransactionFor, ) -> PoolFuture>, 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) -> Pin> + Send>> + Send>>; /// Get an iterator for ready transactions ordered by priority. fn ready(&self) -> Box> + Send>; // *** Block production /// Remove transactions identified by given hashes (and dependent transactions) from the pool. fn remove_invalid(&self, hashes: &[TxHash]) -> Vec>; // *** 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>; // *** networking /// Notify the pool about transactions broadcast. fn on_broadcasted(&self, propagations: HashMap, Vec>); /// Returns transaction hash fn hash_of(&self, xt: &TransactionFor) -> TxHash; /// Return specific ready transaction by hash, if there is one. fn ready_transaction(&self, hash: &TxHash) -> Option>; } /// Events that the transaction pool listens for. pub enum ChainEvent { /// New blocks have been added to the chain NewBlock { /// Is this the new best block. is_new_best: bool, /// Id of the just imported block. id: BlockId, /// Header of the just imported block header: B::Header, /// List of retracted blocks ordered by block number. retracted: Vec, }, /// 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) -> Pin + Send>>; } /// 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: Send + Sync { /// Submit transaction. /// /// The transaction will end up in the pool and be propagated to others. fn submit_at( &self, at: &BlockId, extrinsic: Block::Extrinsic, ) -> Result<(), ()>; } impl OffchainSubmitTransaction for TPool { fn submit_at( &self, at: &BlockId, extrinsic: ::Extrinsic, ) -> Result<(), ()> { log::debug!( target: "txpool", "(offchain call) Submitting a transaction to the pool: {:?}", extrinsic ); let result = futures::executor::block_on(self.submit_one( &at, TransactionSource::Local, extrinsic, )); result.map(|_| ()) .map_err(|e| log::warn!( target: "txpool", "(offchain call) Error submitting a transaction to the pool: {:?}", e )) } }