From bb9897bdbb9926f6c3f8d9fb95339e45546372e2 Mon Sep 17 00:00:00 2001 From: edouard Date: Mon, 19 Sep 2022 18:25:35 +0200 Subject: [PATCH] Update coin txid if conflicting tx was confirmed --- src/bitcoin/d/mod.rs | 17 ++++++++++++++++- src/bitcoin/mod.rs | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/bitcoin/d/mod.rs b/src/bitcoin/d/mod.rs index 60ce4fd2..217dd957 100644 --- a/src/bitcoin/d/mod.rs +++ b/src/bitcoin/d/mod.rs @@ -748,8 +748,9 @@ impl From for LSBlockRes { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct GetTxRes { + pub conflicting_txs: Vec, pub block_height: Option, pub block_time: Option, } @@ -764,7 +765,21 @@ impl From for GetTxRes { .get("blocktime") .and_then(Json::as_u64) .map(|bt| bt as u32); + let conflicting_txs = json + .get("walletconflicts") + .map(|v| Json::as_array(&v)) + .flatten() + .map(|array| { + array + .into_iter() + .map(|v| { + bitcoin::Txid::from_str(v.as_str().expect("wrong json format")).unwrap() + }) + .collect() + }); + GetTxRes { + conflicting_txs: conflicting_txs.unwrap_or_default(), block_height, block_time, } diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 4141edd9..0c0f9c1c 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -156,7 +156,6 @@ impl BitcoinInterface for d::BitcoinD { let mut spent = Vec::with_capacity(outpoints.len()); let mut cache: HashMap> = HashMap::new(); - for (op, txid) in outpoints { let tx: Option<&d::GetTxRes> = match cache.get(txid) { Some(tx) => tx.as_ref(), @@ -167,16 +166,43 @@ impl BitcoinInterface for d::BitcoinD { } }; + // There is an immutable borrow on the cache, these txs will be added once it is + // dropped. + let mut txs_to_cache: Vec<(bitcoin::Txid, Option)> = Vec::new(); + if let Some(tx) = tx { if let Some(block_height) = tx.block_height { if block_height > 1 { spent.push((*op, *txid, tx.block_time.expect("Spend is confirmed"))) } - } else { - // TODO: handle the case where new transaction which txid is not the - // coin spending_txid, spent the coin. + } else if !tx.conflicting_txs.is_empty() { + for txid in tx.conflicting_txs.clone() { + let tx: Option<&d::GetTxRes> = match cache.get(&txid) { + Some(tx) => tx.as_ref(), + None => { + let tx = self.get_transaction(&txid); + txs_to_cache.push((txid, tx)); + txs_to_cache.last().unwrap().1.as_ref() + } + }; + if let Some(tx) = tx { + if let Some(block_height) = tx.block_height { + if block_height > 1 { + spent.push(( + *op, + txid, + tx.block_time.expect("Spend is confirmed"), + )) + } + } + } + } } } + + for (txid, res) in txs_to_cache { + cache.insert(txid, res); + } } spent