feat(mempool): add TransactionsByMinedId (#3907)
This commit is contained in:
parent
e1eb916b6d
commit
41d240feaf
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use zebra_chain::transaction::{UnminedTx, UnminedTxId};
|
use zebra_chain::transaction::{Hash, UnminedTx, UnminedTxId};
|
||||||
|
|
||||||
use crate::BoxError;
|
use crate::BoxError;
|
||||||
|
|
||||||
|
|
@ -29,6 +29,12 @@ pub enum Request {
|
||||||
/// using a unique set of [`UnminedTxId`]s.
|
/// using a unique set of [`UnminedTxId`]s.
|
||||||
TransactionsById(HashSet<UnminedTxId>),
|
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,
|
/// Query matching cached rejected transaction IDs in the mempool,
|
||||||
/// using a unique set of [`UnminedTxId`]s.
|
/// using a unique set of [`UnminedTxId`]s.
|
||||||
RejectedTransactionIds(HashSet<UnminedTxId>),
|
RejectedTransactionIds(HashSet<UnminedTxId>),
|
||||||
|
|
@ -74,7 +80,9 @@ pub enum Response {
|
||||||
/// Returns matching transactions from the mempool.
|
/// Returns matching transactions from the mempool.
|
||||||
///
|
///
|
||||||
/// Since the [`TransactionsById`] request is unique,
|
/// 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>),
|
Transactions(Vec<UnminedTx>),
|
||||||
|
|
||||||
/// Returns matching cached rejected transaction IDs from the mempool,
|
/// 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();
|
let res = storage.transactions_exact(ids).cloned().collect();
|
||||||
async move { Ok(Response::Transactions(res)) }.boxed()
|
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) => {
|
Request::RejectedTransactionIds(ids) => {
|
||||||
let res = storage.rejected_transactions(ids).collect();
|
let res = storage.rejected_transactions(ids).collect();
|
||||||
async move { Ok(Response::RejectedTransactionIds(res)) }.boxed()
|
async move { Ok(Response::RejectedTransactionIds(res)) }.boxed()
|
||||||
|
|
@ -431,6 +435,7 @@ impl Service<Request> for Mempool {
|
||||||
// Empty Queries
|
// Empty Queries
|
||||||
Request::TransactionIds => Response::TransactionIds(Default::default()),
|
Request::TransactionIds => Response::TransactionIds(Default::default()),
|
||||||
Request::TransactionsById(_) => Response::Transactions(Default::default()),
|
Request::TransactionsById(_) => Response::Transactions(Default::default()),
|
||||||
|
Request::TransactionsByMinedId(_) => Response::Transactions(Default::default()),
|
||||||
Request::RejectedTransactionIds(_) => {
|
Request::RejectedTransactionIds(_) => {
|
||||||
Response::RejectedTransactionIds(Default::default())
|
Response::RejectedTransactionIds(Default::default())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use std::{
|
||||||
|
|
||||||
use thiserror::Error;
|
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 self::{eviction_list::EvictionList, verified_set::VerifiedSet};
|
||||||
use super::{config, downloads::TransactionDownloadVerifyError, MempoolError};
|
use super::{config, downloads::TransactionDownloadVerifyError, MempoolError};
|
||||||
|
|
@ -338,6 +338,19 @@ impl Storage {
|
||||||
.filter(move |tx| tx_ids.contains(&tx.id))
|
.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
|
/// Returns `true` if a transaction exactly matching an [`UnminedTxId`] is in
|
||||||
/// the mempool.
|
/// the mempool.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,30 @@ async fn mempool_service_basic_single() -> Result<(), Report> {
|
||||||
// response of `Request::TransactionsById`
|
// response of `Request::TransactionsById`
|
||||||
assert_eq!(genesis_transaction.transaction, transactions[0]);
|
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.
|
// Insert more transactions into the mempool storage.
|
||||||
// This will cause the genesis transaction to be moved into rejected.
|
// This will cause the genesis transaction to be moved into rejected.
|
||||||
// Skip the last (will be used later)
|
// Skip the last (will be used later)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue