]> Untitled Git - bdk/commitdiff
fix(electrum): Don't ignore multiple coinbase txs
authorDaniela Brozzoni <danielabrozzoni@protonmail.com>
Tue, 22 Aug 2023 14:29:19 +0000 (16:29 +0200)
committerDaniela Brozzoni <danielabrozzoni@protonmail.com>
Tue, 22 Aug 2023 14:42:37 +0000 (16:42 +0200)
We would previously insert just one coinbase transaction in the database
if we caught multiple in the same sync.
When we sync with electrum, before committing to the database, we remove
from the update conflicting transactions, using the
`make_txs_consistent` function. This function considers two txs to be
conflicting if they spend from the same outpoint - but every coinbase
transaction spends from the same outpoint!
Here we make sure to avoid filtering out coinbase transactions, by
adding a check on the txid just before we do the filtering.

Fixes #1051

src/blockchain/script_sync.rs
src/testutils/blockchain_tests.rs

index 9aeec7a4a99d4c65ca1af17256e6fa83e73605f5..e4c46999ca1adafbb0db7b264d7ebf6325036ac1 100644 (file)
@@ -9,7 +9,7 @@ use crate::{
     wallet::time::Instant,
     BlockTime, Error, KeychainKind, LocalUtxo, TransactionDetails,
 };
-use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid};
+use bitcoin::{hashes::Hash, OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid};
 use log::*;
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
 
@@ -444,8 +444,14 @@ impl<'a, D: BatchDatabase> State<'a, D> {
 /// Remove conflicting transactions -- tie breaking them by fee.
 fn make_txs_consistent(txs: &[TransactionDetails]) -> Vec<&TransactionDetails> {
     let mut utxo_index: HashMap<OutPoint, &TransactionDetails> = HashMap::default();
+    let mut coinbase_txs = vec![];
     for tx in txs {
         for input in &tx.transaction.as_ref().unwrap().input {
+            if input.previous_output.txid == Txid::all_zeros() {
+                coinbase_txs.push(tx);
+                break;
+            }
+
             utxo_index
                 .entry(input.previous_output)
                 .and_modify(|existing| match (tx.fee, existing.fee) {
@@ -463,5 +469,6 @@ fn make_txs_consistent(txs: &[TransactionDetails]) -> Vec<&TransactionDetails> {
         .collect::<HashMap<_, _>>()
         .into_iter()
         .map(|(_, tx)| tx)
+        .chain(coinbase_txs)
         .collect()
 }
index 510a2c5bbc20ba574f56cc86f0d6d4af56bbd6ab..485c7922a94b4a6756e30801cefc30e35365ac37 100644 (file)
@@ -1098,18 +1098,18 @@ macro_rules! bdk_blockchain_tests {
                 wallet.sync(&blockchain, SyncOptions::default()).unwrap();
                 assert_eq!(wallet.get_balance().unwrap().immature, 0, "incorrect balance");
 
-                test_client.generate(1, Some(wallet_addr));
+                test_client.generate(2, Some(wallet_addr));
 
                 wallet.sync(&blockchain, SyncOptions::default()).unwrap();
 
-                assert!(wallet.get_balance().unwrap().immature > 0, "incorrect balance after receiving coinbase");
+                assert_eq!(wallet.get_balance().unwrap().immature, 5000000000*2, "incorrect balance after receiving coinbase");
 
                 // make coinbase mature (100 blocks)
                 let node_addr = test_client.get_node_address(None);
                 test_client.generate(100, Some(node_addr));
                 wallet.sync(&blockchain, SyncOptions::default()).unwrap();
 
-                assert!(wallet.get_balance().unwrap().confirmed > 0, "incorrect balance after maturing coinbase");
+                assert_eq!(wallet.get_balance().unwrap().confirmed, 5000000000 * 2, "incorrect balance after maturing coinbase");
 
             }