Skip to content

Commit 8c632e5

Browse files
committed
Collect the raw mempool txids into a HashSet
Mempool reconciliation checks every cached transaction against the raw mempool response. Using a Vec to store the raw mempool txids makes each membership check linear and the retention pass quadratic. Store the txids in a HashSet to make membership checks expected constant time and reconciliation expected linear. Co-Authored-By: HAL 9000
1 parent 0428cab commit 8c632e5

1 file changed

Lines changed: 13 additions & 10 deletions

File tree

src/chain/bitcoind.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8-
use std::collections::HashMap;
8+
use std::collections::{HashMap, HashSet};
99
use std::fmt;
1010
use std::future::Future;
1111
use std::sync::atomic::{AtomicU64, Ordering};
@@ -1072,7 +1072,7 @@ impl BitcoindClient {
10721072
}
10731073

10741074
/// Retrieves the raw mempool.
1075-
pub(crate) async fn get_raw_mempool(&self) -> Result<Vec<Txid>, BitcoindClientError> {
1075+
pub(crate) async fn get_raw_mempool(&self) -> Result<HashSet<Txid>, BitcoindClientError> {
10761076
match self {
10771077
BitcoindClient::Rpc { rpc_client, .. } => {
10781078
Self::get_raw_mempool_rpc(Arc::clone(rpc_client))
@@ -1088,7 +1088,9 @@ impl BitcoindClient {
10881088
}
10891089

10901090
/// Retrieves the raw mempool via the RPC interface.
1091-
async fn get_raw_mempool_rpc(rpc_client: Arc<RpcClient>) -> Result<Vec<Txid>, RpcClientError> {
1091+
async fn get_raw_mempool_rpc(
1092+
rpc_client: Arc<RpcClient>,
1093+
) -> Result<HashSet<Txid>, RpcClientError> {
10921094
let verbose_flag_json = serde_json::json!(false);
10931095
rpc_client
10941096
.call_method::<GetRawMempoolResponse>("getrawmempool", &[verbose_flag_json])
@@ -1099,7 +1101,7 @@ impl BitcoindClient {
10991101
/// Retrieves the raw mempool via the REST interface.
11001102
async fn get_raw_mempool_rest(
11011103
rest_client: Arc<RestClient>,
1102-
) -> Result<Vec<Txid>, HttpClientError> {
1104+
) -> Result<HashSet<Txid>, HttpClientError> {
11031105
rest_client
11041106
.request_resource::<JsonResponse, GetRawMempoolResponse>(
11051107
"mempool/contents.json?verbose=false",
@@ -1441,14 +1443,14 @@ impl TryInto<GetRawTransactionResponse> for JsonResponse {
14411443
}
14421444
}
14431445

1444-
pub struct GetRawMempoolResponse(Vec<Txid>);
1446+
pub struct GetRawMempoolResponse(HashSet<Txid>);
14451447

14461448
impl TryInto<GetRawMempoolResponse> for JsonResponse {
14471449
type Error = String;
14481450
fn try_into(self) -> Result<GetRawMempoolResponse, String> {
14491451
let res = self.0.as_array().ok_or("Failed to parse getrawmempool response".to_string())?;
14501452

1451-
let mut mempool_transactions = Vec::with_capacity(res.len());
1453+
let mut mempool_transactions = HashSet::with_capacity(res.len());
14521454

14531455
for hex in res {
14541456
let txid = if let Some(hex_str) = hex.as_str() {
@@ -1462,7 +1464,7 @@ impl TryInto<GetRawMempoolResponse> for JsonResponse {
14621464
return Err("Failed to parse getrawmempool response".to_string());
14631465
};
14641466

1465-
mempool_transactions.push(txid);
1467+
mempool_transactions.insert(txid);
14661468
}
14671469

14681470
Ok(GetRawMempoolResponse(mempool_transactions))
@@ -1616,6 +1618,7 @@ impl std::error::Error for BitcoindClientError {}
16161618

16171619
#[cfg(test)]
16181620
mod tests {
1621+
use std::collections::HashSet;
16191622
use std::sync::Mutex;
16201623
use std::time::Duration;
16211624

@@ -1724,10 +1727,10 @@ mod tests {
17241727

17251728
#[test]
17261729
fn prop_get_raw_mempool_response_roundtrip(txids in vec(any::<[u8;32]>(), 0..10)) {
1727-
let txid_vec: Vec<Txid> = txids.into_iter().map(Txid::from_byte_array).collect();
1728-
let original = GetRawMempoolResponse(txid_vec.clone());
1730+
let txid_set: HashSet<Txid> = txids.into_iter().map(Txid::from_byte_array).collect();
1731+
let original = GetRawMempoolResponse(txid_set.clone());
17291732

1730-
let json_vec: Vec<String> = txid_vec.iter().map(|t| t.to_string()).collect();
1733+
let json_vec: Vec<String> = txid_set.iter().map(|t| t.to_string()).collect();
17311734
let json_val = serde_json::Value::Array(json_vec.iter().map(|s| json!(s)).collect());
17321735

17331736
let resp = JsonResponse(json_val);

0 commit comments

Comments
 (0)