Skip to content

Commit 5913e22

Browse files
committed
Optimize and refactor lookup_txos()
- Avoid unnecessary copying of prev outpoints - When looking for both mempool and on-chain txos, accumulate the set of outpoints that remain to be looked up to avoid re-checking for them later again in the found set - Refactored lookup_txos() to use lookup_txo() internally rather than the other way around, which was less efficient - Lookup txos in mempool first, then on-chain - ChainQuery::lookup_txos() now returns a Result instead of panicking when outpoints are missing - Removed ChainQuery::lookup_avail_txos(), which is now longer neceesary
1 parent 331049e commit 5913e22

File tree

5 files changed

+27
-42
lines changed

5 files changed

+27
-42
lines changed

src/bin/tx-fingerprint-stats.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ fn main() {
8383
//info!("{:?},{:?}", txid, blockid);
8484

8585
let prevouts = chain.lookup_txos(
86-
&tx.input
86+
tx.input
8787
.iter()
8888
.filter(|txin| has_prevout(txin))
8989
.map(|txin| txin.previous_output)
9090
.collect(),
91-
);
91+
).unwrap();
9292

9393
let total_out: u64 = tx.output.iter().map(|out| out.value.to_sat()).sum();
9494
let small_out = tx

src/new_index/mempool.rs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use arraydeque::{ArrayDeque, Wrapping};
2-
use itertools::Itertools;
2+
use itertools::{Either, Itertools};
33

44
#[cfg(not(feature = "liquid"))]
55
use bitcoin::consensus::encode::serialize;
@@ -340,7 +340,7 @@ impl Mempool {
340340
self.txstore.insert(txid, tx);
341341
}
342342
// Phase 2: index history and spend edges (can fail if some txos cannot be found)
343-
let txos = match self.lookup_txos(&self.get_prevouts(&txids)) {
343+
let txos = match self.lookup_txos(self.get_prevouts(&txids)) {
344344
Ok(txos) => txos,
345345
Err(err) => {
346346
warn!("lookup txouts failed: {}", err);
@@ -427,34 +427,29 @@ impl Mempool {
427427
}
428428
}
429429

430-
pub fn lookup_txo(&self, outpoint: &OutPoint) -> Result<TxOut> {
431-
let mut outpoints = BTreeSet::new();
432-
outpoints.insert(*outpoint);
433-
Ok(self.lookup_txos(&outpoints)?.remove(outpoint).unwrap())
430+
fn lookup_txo(&self, outpoint: &OutPoint) -> Option<TxOut> {
431+
self.txstore
432+
.get(&outpoint.txid)
433+
.and_then(|tx| tx.output.get(outpoint.vout as usize).cloned())
434434
}
435435

436-
pub fn lookup_txos(&self, outpoints: &BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
436+
pub fn lookup_txos(&self, outpoints: BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
437437
let _timer = self
438438
.latency
439439
.with_label_values(&["lookup_txos"])
440440
.start_timer();
441441

442-
let confirmed_txos = self.chain.lookup_avail_txos(outpoints);
442+
// Get the txos available in the mempool, skipping over (and collecting) missing ones
443+
let (mut txos, remain_outpoints): (HashMap<_, _>, _) = outpoints
444+
.into_iter()
445+
.partition_map(|outpoint| match self.lookup_txo(&outpoint) {
446+
Some(txout) => Either::Left((outpoint, txout)),
447+
None => Either::Right(outpoint),
448+
});
443449

444-
let mempool_txos = outpoints
445-
.iter()
446-
.filter(|outpoint| !confirmed_txos.contains_key(outpoint))
447-
.map(|outpoint| {
448-
self.txstore
449-
.get(&outpoint.txid)
450-
.and_then(|tx| tx.output.get(outpoint.vout as usize).cloned())
451-
.map(|txout| (*outpoint, txout))
452-
.chain_err(|| format!("missing outpoint {:?}", outpoint))
453-
})
454-
.collect::<Result<HashMap<OutPoint, TxOut>>>()?;
450+
// Get the remaining txos from the chain (fails if any are missing)
451+
txos.extend(self.chain.lookup_txos(remain_outpoints)?);
455452

456-
let mut txos = confirmed_txos;
457-
txos.extend(mempool_txos);
458453
Ok(txos)
459454
}
460455

src/new_index/query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl Query {
118118
.or_else(|| self.mempool().lookup_raw_txn(txid))
119119
}
120120

121-
pub fn lookup_txos(&self, outpoints: &BTreeSet<OutPoint>) -> HashMap<OutPoint, TxOut> {
121+
pub fn lookup_txos(&self, outpoints: BTreeSet<OutPoint>) -> HashMap<OutPoint, TxOut> {
122122
// the mempool lookup_txos() internally looks up confirmed txos as well
123123
self.mempool()
124124
.lookup_txos(outpoints)

src/new_index/schema.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ impl Indexer {
327327
fn index(&self, blocks: &[BlockEntry]) {
328328
let previous_txos_map = {
329329
let _timer = self.start_timer("index_lookup");
330-
lookup_txos(&self.store.txstore_db, &get_previous_txos(blocks), false)
330+
lookup_txos(&self.store.txstore_db, get_previous_txos(blocks)).unwrap()
331331
};
332332
let rows = {
333333
let _timer = self.start_timer("index_process");
@@ -859,14 +859,9 @@ impl ChainQuery {
859859
lookup_txo(&self.store.txstore_db, outpoint)
860860
}
861861

862-
pub fn lookup_txos(&self, outpoints: &BTreeSet<OutPoint>) -> HashMap<OutPoint, TxOut> {
862+
pub fn lookup_txos(&self, outpoints: BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
863863
let _timer = self.start_timer("lookup_txos");
864-
lookup_txos(&self.store.txstore_db, outpoints, false)
865-
}
866-
867-
pub fn lookup_avail_txos(&self, outpoints: &BTreeSet<OutPoint>) -> HashMap<OutPoint, TxOut> {
868-
let _timer = self.start_timer("lookup_available_txos");
869-
lookup_txos(&self.store.txstore_db, outpoints, true)
864+
lookup_txos(&self.store.txstore_db, outpoints)
870865
}
871866

872867
pub fn lookup_spend(&self, outpoint: &OutPoint) -> Option<SpendingInput> {
@@ -1033,21 +1028,16 @@ fn get_previous_txos(block_entries: &[BlockEntry]) -> BTreeSet<OutPoint> {
10331028
.collect()
10341029
}
10351030

1036-
fn lookup_txos(
1037-
txstore_db: &DB,
1038-
outpoints: &BTreeSet<OutPoint>,
1039-
allow_missing: bool,
1040-
) -> HashMap<OutPoint, TxOut> {
1031+
fn lookup_txos(txstore_db: &DB, outpoints: BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
10411032
let mut remain_outpoints = outpoints.iter();
10421033
txstore_db
10431034
.multi_get(outpoints.iter().map(TxOutRow::key))
10441035
.into_iter()
1045-
.filter_map(|res| {
1036+
.map(|res| {
10461037
let outpoint = remain_outpoints.next().unwrap();
10471038
match res.unwrap() {
1048-
Some(txo) => Some((*outpoint, deserialize(&txo).expect("failed to parse TxOut"))),
1049-
None if allow_missing => None,
1050-
None => panic!("missing txo {}", outpoint),
1039+
Some(txo) => Ok((*outpoint, deserialize(&txo).expect("failed to parse TxOut"))),
1040+
None => Err(format!("missing txo {}", outpoint).into()),
10511041
}
10521042
})
10531043
.collect()

src/rest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ fn prepare_txs(
468468
})
469469
.collect();
470470

471-
let prevouts = query.lookup_txos(&outpoints);
471+
let prevouts = query.lookup_txos(outpoints);
472472

473473
txs.into_iter()
474474
.map(|(tx, blockid)| TransactionValue::new(tx, blockid, &prevouts, config))

0 commit comments

Comments
 (0)