1
0
Fork 0
mirror of https://github.com/romanz/electrs.git synced 2025-02-24 06:57:53 +01:00

Fix txid index collision handling

This commit is contained in:
Roman Zeyde 2022-01-08 10:36:55 +02:00
parent 6f301a0167
commit ca2841f432
2 changed files with 38 additions and 13 deletions

View file

@ -356,18 +356,26 @@ impl Rpc {
fn transaction_get(&self, args: &TxGetArgs) -> Result<Value> {
let (txid, verbose) = args.into();
if verbose {
let blockhash = self.tracker.get_blockhash_by_txid(txid);
let blockhash = self
.tracker
.lookup_transaction(&self.daemon, txid)?
.map(|(blockhash, _tx)| blockhash);
return self.daemon.get_transaction_info(&txid, blockhash);
}
let cached = self.cache.get_tx(&txid, |tx| serialize(tx).to_hex());
Ok(match cached {
Some(tx_hex) => json!(tx_hex),
None => {
debug!("tx cache miss: txid={}", txid);
let blockhash = self.tracker.get_blockhash_by_txid(txid);
json!(self.daemon.get_transaction_hex(&txid, blockhash)?)
if let Some(tx) = self.cache.get_tx(&txid, |tx| serialize(tx)) {
return Ok(json!(tx.to_hex()));
}
})
debug!("tx cache miss: txid={}", txid);
// use internal index to load confirmed transaction without an RPC
if let Some(tx) = self
.tracker
.lookup_transaction(&self.daemon, txid)?
.map(|(_blockhash, tx)| tx)
{
return Ok(json!(serialize(&tx).to_hex()));
}
// load unconfirmed transaction via RPC
Ok(json!(self.daemon.get_transaction_hex(&txid, None)?))
}
fn transaction_get_merkle(&self, (txid, height): &(Txid, usize)) -> Result<Value> {

View file

@ -1,5 +1,5 @@
use anyhow::{Context, Result};
use bitcoin::{BlockHash, Txid};
use bitcoin::{BlockHash, Transaction, Txid};
use crate::{
cache::Cache,
@ -93,8 +93,25 @@ impl Tracker {
status.get_balance(self.chain())
}
pub(crate) fn get_blockhash_by_txid(&self, txid: Txid) -> Option<BlockHash> {
pub(crate) fn lookup_transaction(
&self,
daemon: &Daemon,
txid: Txid,
) -> Result<Option<(BlockHash, Transaction)>> {
// Note: there are two blocks with coinbase transactions having same txid (see BIP-30)
self.index.filter_by_txid(txid).next()
let blockhashes = self.index.filter_by_txid(txid);
let mut result = None;
daemon.for_blocks(blockhashes, |blockhash, block| {
for tx in block.txdata {
if result.is_some() {
return;
}
if tx.txid() == txid {
result = Some((blockhash, tx));
return;
}
}
})?;
Ok(result)
}
}