feat(mempool): add TransactionsByMinedId (#3907)
This commit is contained in:
parent
e1eb916b6d
commit
41d240feaf
|
@ -4,7 +4,7 @@
|
|||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use zebra_chain::transaction::{UnminedTx, UnminedTxId};
|
||||
use zebra_chain::transaction::{Hash, UnminedTx, UnminedTxId};
|
||||
|
||||
use crate::BoxError;
|
||||
|
||||
|
@ -29,6 +29,12 @@ pub enum Request {
|
|||
/// using a unique set of [`UnminedTxId`]s.
|
||||
TransactionsById(HashSet<UnminedTxId>),
|
||||
|
||||
/// Query matching transactions in the mempool,
|
||||
/// using a unique set of [`Hash`]s. Pre-V5 transactions are matched
|
||||
/// directly; V5 transaction are matched just by the Hash, disregarding
|
||||
/// the [`AuthDigest`].
|
||||
TransactionsByMinedId(HashSet<Hash>),
|
||||
|
||||
/// Query matching cached rejected transaction IDs in the mempool,
|
||||
/// using a unique set of [`UnminedTxId`]s.
|
||||
RejectedTransactionIds(HashSet<UnminedTxId>),
|
||||
|
@ -74,7 +80,9 @@ pub enum Response {
|
|||
/// Returns matching transactions from the mempool.
|
||||
///
|
||||
/// Since the [`TransactionsById`] request is unique,
|
||||
/// the response transactions are also unique.
|
||||
/// the response transactions are also unique. The same applies to
|
||||
/// [`TransactionByMinedId`] requests, since the mempool does not allow
|
||||
/// different transactions with different mined IDs.
|
||||
Transactions(Vec<UnminedTx>),
|
||||
|
||||
/// Returns matching cached rejected transaction IDs from the mempool,
|
||||
|
|
|
@ -398,6 +398,10 @@ impl Service<Request> for Mempool {
|
|||
let res = storage.transactions_exact(ids).cloned().collect();
|
||||
async move { Ok(Response::Transactions(res)) }.boxed()
|
||||
}
|
||||
Request::TransactionsByMinedId(ids) => {
|
||||
let res = storage.transactions_same_effects(ids).cloned().collect();
|
||||
async move { Ok(Response::Transactions(res)) }.boxed()
|
||||
}
|
||||
Request::RejectedTransactionIds(ids) => {
|
||||
let res = storage.rejected_transactions(ids).collect();
|
||||
async move { Ok(Response::RejectedTransactionIds(res)) }.boxed()
|
||||
|
@ -431,6 +435,7 @@ impl Service<Request> for Mempool {
|
|||
// Empty Queries
|
||||
Request::TransactionIds => Response::TransactionIds(Default::default()),
|
||||
Request::TransactionsById(_) => Response::Transactions(Default::default()),
|
||||
Request::TransactionsByMinedId(_) => Response::Transactions(Default::default()),
|
||||
Request::RejectedTransactionIds(_) => {
|
||||
Response::RejectedTransactionIds(Default::default())
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::{
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
use zebra_chain::transaction::{self, UnminedTx, UnminedTxId, VerifiedUnminedTx};
|
||||
use zebra_chain::transaction::{self, Hash, UnminedTx, UnminedTxId, VerifiedUnminedTx};
|
||||
|
||||
use self::{eviction_list::EvictionList, verified_set::VerifiedSet};
|
||||
use super::{config, downloads::TransactionDownloadVerifyError, MempoolError};
|
||||
|
@ -338,6 +338,19 @@ impl Storage {
|
|||
.filter(move |tx| tx_ids.contains(&tx.id))
|
||||
}
|
||||
|
||||
/// Returns the set of [`UnminedTx`]es with matching [`transaction::Hash`]es
|
||||
/// in the mempool.
|
||||
///
|
||||
/// This matches transactions with the same effects, regardless of [`AuthDigest`].
|
||||
pub fn transactions_same_effects(
|
||||
&self,
|
||||
tx_ids: HashSet<Hash>,
|
||||
) -> impl Iterator<Item = &UnminedTx> {
|
||||
self.verified
|
||||
.transactions()
|
||||
.filter(move |tx| tx_ids.contains(&tx.id.mined_id()))
|
||||
}
|
||||
|
||||
/// Returns `true` if a transaction exactly matching an [`UnminedTxId`] is in
|
||||
/// the mempool.
|
||||
///
|
||||
|
|
|
@ -98,6 +98,30 @@ async fn mempool_service_basic_single() -> Result<(), Report> {
|
|||
// response of `Request::TransactionsById`
|
||||
assert_eq!(genesis_transaction.transaction, transactions[0]);
|
||||
|
||||
// Test `Request::TransactionsByMinedId`
|
||||
// TODO: use a V5 tx to test if it's really matched by mined ID
|
||||
let genesis_transactions_mined_hash_set = genesis_transaction_ids
|
||||
.iter()
|
||||
.map(|txid| txid.mined_id())
|
||||
.collect::<HashSet<_>>();
|
||||
let response = service
|
||||
.ready()
|
||||
.await
|
||||
.unwrap()
|
||||
.call(Request::TransactionsByMinedId(
|
||||
genesis_transactions_mined_hash_set,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
let transactions = match response {
|
||||
Response::Transactions(transactions) => transactions,
|
||||
_ => unreachable!("will never happen in this test"),
|
||||
};
|
||||
|
||||
// Make sure the transaction from the blockchain test vector is the same as the
|
||||
// response of `Request::TransactionsByMinedId`
|
||||
assert_eq!(genesis_transaction.transaction, transactions[0]);
|
||||
|
||||
// Insert more transactions into the mempool storage.
|
||||
// This will cause the genesis transaction to be moved into rejected.
|
||||
// Skip the last (will be used later)
|
||||
|
|
Loading…
Reference in New Issue