Skip to main content

zebra_node_services/
mempool.rs

1//! The Zebra mempool.
2//!
3//! A service that manages known unmined Zcash transactions.
4
5use std::{collections::HashSet, net::SocketAddr};
6
7use tokio::sync::oneshot;
8use zebra_chain::{
9    block,
10    transaction::{self, UnminedTx, UnminedTxId, VerifiedUnminedTx},
11    transparent,
12};
13
14use crate::BoxError;
15
16mod gossip;
17mod mempool_change;
18mod service_trait;
19mod transaction_dependencies;
20
21pub use self::{
22    gossip::Gossip,
23    mempool_change::{MempoolChange, MempoolChangeKind, MempoolTxSubscriber},
24    service_trait::MempoolService,
25    transaction_dependencies::TransactionDependencies,
26};
27
28/// A mempool service request.
29///
30/// Requests can query the current set of mempool transactions,
31/// queue transactions to be downloaded and verified, or
32/// run the mempool to check for newly verified transactions.
33///
34/// Requests can't modify the mempool directly,
35/// because all mempool transactions must be verified.
36#[derive(Debug, Eq, PartialEq)]
37pub enum Request {
38    /// Query all [`UnminedTxId`]s in the mempool.
39    TransactionIds,
40
41    /// Query matching [`UnminedTx`] in the mempool,
42    /// using a unique set of [`UnminedTxId`]s.
43    TransactionsById(HashSet<UnminedTxId>),
44
45    /// Query matching [`UnminedTx`] in the mempool,
46    /// using a unique set of [`transaction::Hash`]es. Pre-V5 transactions are matched
47    /// directly; V5 transaction are matched just by the Hash, disregarding
48    /// the [`AuthDigest`](zebra_chain::transaction::AuthDigest).
49    TransactionsByMinedId(HashSet<transaction::Hash>),
50
51    /// Request a [`transparent::Output`] identified by the given [`OutPoint`](transparent::OutPoint),
52    /// waiting until it becomes available if it is unknown.
53    ///
54    /// This request is purely informational, and there are no guarantees about
55    /// whether the UTXO remains unspent or is on the best chain, or any chain.
56    /// Its purpose is to allow orphaned mempool transaction verification.
57    ///
58    /// # Correctness
59    ///
60    /// Output requests should be wrapped in a timeout, so that
61    /// out-of-order and invalid requests do not hang indefinitely.
62    ///
63    /// Outdated requests are pruned on a regular basis.
64    AwaitOutput(transparent::OutPoint),
65
66    /// Request a [`VerifiedUnminedTx`] and its dependencies by its mined id.
67    TransactionWithDepsByMinedId(transaction::Hash),
68
69    /// Get all the [`VerifiedUnminedTx`] in the mempool.
70    ///
71    /// Equivalent to `TransactionsById(TransactionIds)`,
72    /// but each transaction also includes the `miner_fee` and `legacy_sigop_count` fields.
73    //
74    // TODO: make the Transactions response return VerifiedUnminedTx,
75    //       and remove the FullTransactions variant
76    FullTransactions,
77
78    /// Query matching cached rejected transaction IDs in the mempool,
79    /// using a unique set of [`UnminedTxId`]s.
80    RejectedTransactionIds(HashSet<UnminedTxId>),
81
82    /// Queue a list of gossiped transactions or transaction IDs, or
83    /// crawled transaction IDs.
84    ///
85    /// The transaction downloader checks for duplicates across IDs and transactions.
86    Queue(Vec<Gossip>),
87
88    /// Queue candidate transactions received from a specific peer — either
89    /// transaction IDs advertised via an `Inv` message, or a full transaction
90    /// pushed via a `Tx` message — tagging each one with the sending peer so the
91    /// downloader can enforce a per-peer queue cap. This routes every
92    /// peer-originated candidate through the same per-peer admission accounting,
93    /// so a single peer cannot crowd out honest peers' transaction relay.
94    /// See `GHSA-4fc2-h7jh-287c` and `GHSA-m9xx-8rcj-vmgp`.
95    QueueFromPeer {
96        /// The candidate transactions received from the peer.
97        candidates: Vec<Gossip>,
98        /// The address of the peer that sent them.
99        source: SocketAddr,
100    },
101
102    /// Check for newly verified transactions.
103    ///
104    /// The transaction downloader does not push transactions into the mempool.
105    /// So a task should send this request regularly (every 5-10 seconds).
106    ///
107    /// These checks also happen for other request variants,
108    /// but we can't rely on peers to send queries regularly,
109    /// and crawler queue requests depend on peer responses.
110    /// Also, crawler requests aren't frequent enough for transaction propagation.
111    ///
112    /// # Correctness
113    ///
114    /// This request is required to avoid hangs in the mempool.
115    ///
116    /// The queue checker task can't call `poll_ready` directly on the mempool
117    /// service, because the service is wrapped in a `Buffer`. Calling
118    /// `Buffer::poll_ready` reserves a buffer slot, which can cause hangs
119    /// when too many slots are reserved but unused:
120    /// <https://docs.rs/tower/0.4.10/tower/buffer/struct.Buffer.html#a-note-on-choosing-a-bound>
121    CheckForVerifiedTransactions,
122
123    /// Request summary statistics from the mempool for `getmempoolinfo`.
124    QueueStats,
125
126    /// Check whether a transparent output is spent in the mempool.
127    UnspentOutput(transparent::OutPoint),
128}
129
130/// A response to a mempool service request.
131///
132/// Responses can read the current set of mempool transactions,
133/// check the queued status of transactions to be downloaded and verified, or
134/// confirm that the mempool has been checked for newly verified transactions.
135#[derive(Debug)]
136pub enum Response {
137    /// Returns all [`UnminedTxId`]s from the mempool.
138    TransactionIds(HashSet<UnminedTxId>),
139
140    /// Returns matching [`UnminedTx`] from the mempool.
141    ///
142    /// Since the [`Request::TransactionsById`] request is unique,
143    /// the response transactions are also unique. The same applies to
144    /// [`Request::TransactionsByMinedId`] requests, since the mempool does not allow
145    /// different transactions with different mined IDs.
146    Transactions(Vec<UnminedTx>),
147
148    /// Response to [`Request::AwaitOutput`] with the transparent output
149    UnspentOutput(transparent::Output),
150
151    /// Response to [`Request::TransactionWithDepsByMinedId`].
152    TransactionWithDeps {
153        /// The queried transaction
154        transaction: VerifiedUnminedTx,
155        /// A list of dependencies of the queried transaction.
156        dependencies: HashSet<transaction::Hash>,
157    },
158
159    /// Returns all [`VerifiedUnminedTx`] in the mempool.
160    //
161    // TODO: make the Transactions response return VerifiedUnminedTx,
162    //       and remove the FullTransactions variant
163    FullTransactions {
164        /// All [`VerifiedUnminedTx`]s in the mempool
165        transactions: Vec<VerifiedUnminedTx>,
166
167        /// All transaction dependencies in the mempool
168        transaction_dependencies: TransactionDependencies,
169
170        /// Last seen chain tip hash by mempool service
171        last_seen_tip_hash: zebra_chain::block::Hash,
172    },
173
174    /// Returns matching cached rejected [`UnminedTxId`]s from the mempool,
175    RejectedTransactionIds(HashSet<UnminedTxId>),
176
177    /// Returns a list of initial queue checks results and a oneshot receiver
178    /// for awaiting download and/or verification results.
179    ///
180    /// Each result matches the request at the corresponding vector index.
181    Queued(Vec<Result<oneshot::Receiver<Result<(), BoxError>>, BoxError>>),
182
183    /// Confirms that the mempool has checked for recently verified transactions.
184    CheckedForVerifiedTransactions,
185
186    /// Summary statistics for the mempool: count, total size, memory usage, and regtest info.
187    QueueStats {
188        /// Number of transactions currently in the mempool
189        size: usize,
190        /// Total size in bytes of all transactions
191        bytes: usize,
192        /// Estimated memory usage in bytes
193        usage: usize,
194        /// Whether all transactions have been fully notified (regtest only)
195        fully_notified: Option<bool>,
196    },
197
198    /// Returns whether a transparent output is created or spent in the mempool, if present.
199    TransparentOutput(Option<CreatedOrSpent>),
200}
201
202/// Indicates whether an output was created or spent by a mempool transaction.
203#[derive(Debug)]
204pub enum CreatedOrSpent {
205    /// An unspent output that was created by a transaction in the mempool and not spent by any other mempool tx.
206    Created {
207        /// The output
208        output: transparent::Output,
209        /// The version
210        tx_version: u32,
211        /// The last seen hash
212        last_seen_hash: block::Hash,
213    },
214    /// Indicates that an output was spent by a mempool transaction.
215    Spent,
216}