Skip to content

Commit e9d68b2

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() and allow_missing, which are no longer neceesary
1 parent 168e241 commit e9d68b2

File tree

5 files changed

+30
-44
lines changed

5 files changed

+30
-44
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;
@@ -310,7 +310,7 @@ impl Mempool {
310310
self.txstore.insert(txid, tx);
311311
}
312312
// Phase 2: index history and spend edges (can fail if some txos cannot be found)
313-
let txos = match self.lookup_txos(&self.get_prevouts(&txids)) {
313+
let txos = match self.lookup_txos(self.get_prevouts(&txids)) {
314314
Ok(txos) => txos,
315315
Err(err) => {
316316
warn!("lookup txouts failed: {}", err);
@@ -397,34 +397,29 @@ impl Mempool {
397397
}
398398
}
399399

400-
pub fn lookup_txo(&self, outpoint: &OutPoint) -> Result<TxOut> {
401-
let mut outpoints = BTreeSet::new();
402-
outpoints.insert(*outpoint);
403-
Ok(self.lookup_txos(&outpoints)?.remove(outpoint).unwrap())
400+
fn lookup_txo(&self, outpoint: &OutPoint) -> Option<TxOut> {
401+
self.txstore
402+
.get(&outpoint.txid)
403+
.and_then(|tx| tx.output.get(outpoint.vout as usize).cloned())
404404
}
405405

406-
pub fn lookup_txos(&self, outpoints: &BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
406+
pub fn lookup_txos(&self, outpoints: BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
407407
let _timer = self
408408
.latency
409409
.with_label_values(&["lookup_txos"])
410410
.start_timer();
411411

412-
let confirmed_txos = self.chain.lookup_avail_txos(outpoints);
412+
// Get the txos available in the mempool, skipping over (and collecting) missing ones
413+
let (mut txos, remain_outpoints): (HashMap<_, _>, _) = outpoints
414+
.into_iter()
415+
.partition_map(|outpoint| match self.lookup_txo(&outpoint) {
416+
Some(txout) => Either::Left((outpoint, txout)),
417+
None => Either::Right(outpoint),
418+
});
413419

414-
let mempool_txos = outpoints
415-
.iter()
416-
.filter(|outpoint| !confirmed_txos.contains_key(outpoint))
417-
.map(|outpoint| {
418-
self.txstore
419-
.get(&outpoint.txid)
420-
.and_then(|tx| tx.output.get(outpoint.vout as usize).cloned())
421-
.map(|txout| (*outpoint, txout))
422-
.chain_err(|| format!("missing outpoint {:?}", outpoint))
423-
})
424-
.collect::<Result<HashMap<OutPoint, TxOut>>>()?;
420+
// Get the remaining txos from the chain (fails if any are missing)
421+
txos.extend(self.chain.lookup_txos(remain_outpoints)?);
425422

426-
let mut txos = confirmed_txos;
427-
txos.extend(mempool_txos);
428423
Ok(txos)
429424
}
430425

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: 10 additions & 19 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,17 @@ 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> {
1041-
let mut remain_outpoints = outpoints.iter();
1031+
fn lookup_txos(txstore_db: &DB, outpoints: BTreeSet<OutPoint>) -> Result<HashMap<OutPoint, TxOut>> {
1032+
let keys = outpoints.iter().map(TxOutRow::key).collect::<Vec<_>>();
1033+
let mut remain_outpoints = outpoints.into_iter();
10421034
txstore_db
1043-
.multi_get(outpoints.iter().map(TxOutRow::key))
1035+
.multi_get(keys)
10441036
.into_iter()
1045-
.filter_map(|res| {
1037+
.map(|res| {
10461038
let outpoint = remain_outpoints.next().unwrap();
10471039
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),
1040+
Some(txo) => Ok((outpoint, deserialize(&txo).expect("failed to parse TxOut"))),
1041+
None => Err(format!("missing txo {}", outpoint).into()),
10511042
}
10521043
})
10531044
.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)