feat(mempool): add TransactionsByMinedId (#3907)

This commit is contained in:
Conrado Gouvea 2022-03-18 20:00:03 -03:00 committed by GitHub
parent e1eb916b6d
commit 41d240feaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 3 deletions

View File

@ -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,

View File

@ -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())
}

View File

@ -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.
///

View File

@ -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)