1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//! The Zebra mempool.
//!
//! A service that manages known unmined Zcash transactions.
use std::collections::HashSet;
use tokio::sync::oneshot;
use zebra_chain::{
transaction::{self, UnminedTx, UnminedTxId},
transparent,
};
#[cfg(feature = "getblocktemplate-rpcs")]
use zebra_chain::transaction::VerifiedUnminedTx;
use crate::BoxError;
mod gossip;
mod transaction_dependencies;
pub use transaction_dependencies::TransactionDependencies;
pub use self::gossip::Gossip;
/// A mempool service request.
///
/// Requests can query the current set of mempool transactions,
/// queue transactions to be downloaded and verified, or
/// run the mempool to check for newly verified transactions.
///
/// Requests can't modify the mempool directly,
/// because all mempool transactions must be verified.
#[derive(Debug, Eq, PartialEq)]
pub enum Request {
/// Query all [`UnminedTxId`]s in the mempool.
TransactionIds,
/// Query matching [`UnminedTx`] in the mempool,
/// using a unique set of [`UnminedTxId`]s.
TransactionsById(HashSet<UnminedTxId>),
/// Query matching [`UnminedTx`] in the mempool,
/// using a unique set of [`transaction::Hash`]es. Pre-V5 transactions are matched
/// directly; V5 transaction are matched just by the Hash, disregarding
/// the [`AuthDigest`](zebra_chain::transaction::AuthDigest).
TransactionsByMinedId(HashSet<transaction::Hash>),
/// Request a [`transparent::Output`] identified by the given [`OutPoint`](transparent::OutPoint),
/// waiting until it becomes available if it is unknown.
///
/// This request is purely informational, and there are no guarantees about
/// whether the UTXO remains unspent or is on the best chain, or any chain.
/// Its purpose is to allow orphaned mempool transaction verification.
///
/// # Correctness
///
/// Output requests should be wrapped in a timeout, so that
/// out-of-order and invalid requests do not hang indefinitely.
///
/// Outdated requests are pruned on a regular basis.
AwaitOutput(transparent::OutPoint),
/// Get all the [`VerifiedUnminedTx`] in the mempool.
///
/// Equivalent to `TransactionsById(TransactionIds)`,
/// but each transaction also includes the `miner_fee` and `legacy_sigop_count` fields.
//
// TODO: make the Transactions response return VerifiedUnminedTx,
// and remove the FullTransactions variant
#[cfg(feature = "getblocktemplate-rpcs")]
FullTransactions,
/// Query matching cached rejected transaction IDs in the mempool,
/// using a unique set of [`UnminedTxId`]s.
RejectedTransactionIds(HashSet<UnminedTxId>),
/// Queue a list of gossiped transactions or transaction IDs, or
/// crawled transaction IDs.
///
/// The transaction downloader checks for duplicates across IDs and transactions.
Queue(Vec<Gossip>),
/// Check for newly verified transactions.
///
/// The transaction downloader does not push transactions into the mempool.
/// So a task should send this request regularly (every 5-10 seconds).
///
/// These checks also happen for other request variants,
/// but we can't rely on peers to send queries regularly,
/// and crawler queue requests depend on peer responses.
/// Also, crawler requests aren't frequent enough for transaction propagation.
///
/// # Correctness
///
/// This request is required to avoid hangs in the mempool.
///
/// The queue checker task can't call `poll_ready` directly on the mempool
/// service, because the service is wrapped in a `Buffer`. Calling
/// `Buffer::poll_ready` reserves a buffer slot, which can cause hangs
/// when too many slots are reserved but unused:
/// <https://docs.rs/tower/0.4.10/tower/buffer/struct.Buffer.html#a-note-on-choosing-a-bound>
CheckForVerifiedTransactions,
}
/// A response to a mempool service request.
///
/// Responses can read the current set of mempool transactions,
/// check the queued status of transactions to be downloaded and verified, or
/// confirm that the mempool has been checked for newly verified transactions.
#[derive(Debug)]
pub enum Response {
/// Returns all [`UnminedTxId`]s from the mempool.
TransactionIds(HashSet<UnminedTxId>),
/// Returns matching [`UnminedTx`] from the mempool.
///
/// Since the [`Request::TransactionsById`] request is unique,
/// the response transactions are also unique. The same applies to
/// [`Request::TransactionsByMinedId`] requests, since the mempool does not allow
/// different transactions with different mined IDs.
Transactions(Vec<UnminedTx>),
/// Response to [`Request::AwaitOutput`] with the transparent output
UnspentOutput(transparent::Output),
/// Returns all [`VerifiedUnminedTx`] in the mempool.
//
// TODO: make the Transactions response return VerifiedUnminedTx,
// and remove the FullTransactions variant
#[cfg(feature = "getblocktemplate-rpcs")]
FullTransactions {
/// All [`VerifiedUnminedTx`]s in the mempool
transactions: Vec<VerifiedUnminedTx>,
/// All transaction dependencies in the mempool
transaction_dependencies: TransactionDependencies,
/// Last seen chain tip hash by mempool service
last_seen_tip_hash: zebra_chain::block::Hash,
},
/// Returns matching cached rejected [`UnminedTxId`]s from the mempool,
RejectedTransactionIds(HashSet<UnminedTxId>),
/// Returns a list of initial queue checks results and a oneshot receiver
/// for awaiting download and/or verification results.
///
/// Each result matches the request at the corresponding vector index.
Queued(Vec<Result<oneshot::Receiver<Result<(), BoxError>>, BoxError>>),
/// Confirms that the mempool has checked for recently verified transactions.
CheckedForVerifiedTransactions,
}