From f32b0d2a79e81884218f9b75ba763cd738a313b2 Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Wed, 15 Jun 2022 18:53:57 +0200 Subject: [PATCH] rust: get_unspent_outputs: fix bug returning utxos from replaced txs In 0a55d9944e0f02df2948cf692836eadb703d6ac0 a regression was introduced, which caused transactions that have been replaced or dropped out of mempool be included in the utxos. This might cause the balance to be incorrect or sent transactions to be rejected. This commit fixes the above issue. --- CHANGELOG.md | 4 ++++ subprojects/gdk_rust/gdk_electrum/src/account.rs | 6 +++++- subprojects/gdk_rust/gdk_rust/tests/integration.rs | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3e9d0d15..0f48b3e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ - Singlesig: Remove is_segwit from GA_get_unspent_outputs returned json - GA_register_user: Change interface to match GA_login_user. +### Fixed + +- GA_get_unspent_outputs: fix bug returning utxos from replaced transactions. + ### Removed - Removed GA_get_mnemonic_passphrase, callers should use GA_get_credentials. diff --git a/subprojects/gdk_rust/gdk_electrum/src/account.rs b/subprojects/gdk_rust/gdk_electrum/src/account.rs index dc0735cb3..e2d8a3d59 100644 --- a/subprojects/gdk_rust/gdk_electrum/src/account.rs +++ b/subprojects/gdk_rust/gdk_electrum/src/account.rs @@ -625,7 +625,11 @@ impl Account { let mut inputs = HashSet::new(); let store_read = self.store.read()?; let acc_store = store_read.account_cache(self.account_num)?; - for txe in acc_store.all_txs.values() { + for (txid, txe) in acc_store.all_txs.iter() { + if !acc_store.heights.contains_key(&txid) { + // transaction has been replaced or dropped out of mempool + continue; + } inputs.extend(txe.tx.previous_outputs()); for vout in 0..(txe.tx.output_len() as u32) { let script_pubkey = txe.tx.output_script(vout); diff --git a/subprojects/gdk_rust/gdk_rust/tests/integration.rs b/subprojects/gdk_rust/gdk_rust/tests/integration.rs index 61d6cdb67..5926222f3 100644 --- a/subprojects/gdk_rust/gdk_rust/tests/integration.rs +++ b/subprojects/gdk_rust/gdk_rust/tests/integration.rs @@ -1258,6 +1258,9 @@ fn rbf() { let txid1 = test_session.session.broadcast_transaction(&signed_tx.hex).unwrap(); test_session.wait_tx(vec![1], &txid1, Some(signed_tx.fee), Some(TransactionType::Redeposit)); let txitem = test_session.get_tx_from_list(1, &txid1); + assert!(test_session.utxos(1).0.get("btc").unwrap().iter().any(|e| e.txhash == txid1)); + assert_eq!(test_session.balance_account(1, None, None), sat - txitem.fee); + assert_eq!(txitem.fee_rate / 1000, 25); // Replace it @@ -1279,6 +1282,8 @@ fn rbf() { for i in 0..60 { std::thread::sleep(std::time::Duration::from_secs(1)); if test_session.get_tx_list(1).iter().all(|e| e.txhash != txid1) { + assert!(test_session.utxos(1).0.get("btc").unwrap().iter().all(|e| e.txhash != txid1)); + assert_eq!(test_session.balance_account(1, None, None), sat - txitem.fee); break; } assert!(i < 59, "timeout waiting for replaced transaction to disappear");