Skip to content

Commit ee5ea61

Browse files
committed
fix: deduplicate InstantSend events across mixed entry points
`process_instant_send_lock` did not record txids in `instant_send_locks`, so a subsequent `check_transaction_in_all_wallets(..., InstantSend)` for the same txid would emit a duplicate `TransactionStatusChanged` event. Record the txid in `instant_send_locks` inside `mark_instant_send_utxos` so both paths share the same deduplication set. Add tests covering both orderings of the mixed entry points. Addresses CodeRabbit review comment on PR #552 Files: key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs, key-wallet-manager/src/wallet_manager/event_tests.rs
1 parent ebabdc4 commit ee5ea61

2 files changed

Lines changed: 70 additions & 0 deletions

File tree

key-wallet/src/manager/event_tests.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,73 @@ async fn test_process_instant_send_lock_for_unknown_txid() {
194194
assert_eq!(balance_before, balance_after);
195195
}
196196

197+
#[tokio::test]
198+
async fn test_mixed_instantsend_paths_no_duplicate_events() {
199+
let (mut manager, wallet_id, addr) = setup_manager_with_wallet();
200+
let mut rx = manager.subscribe_events();
201+
let tx = create_tx_paying_to(&addr, 0xf0);
202+
203+
// Mempool first
204+
manager.check_transaction_in_all_wallets(&tx, TransactionContext::Mempool, true, true).await;
205+
drain_events(&mut rx);
206+
207+
// IS lock via process_instant_send_lock (network IS lock message)
208+
manager.process_instant_send_lock(tx.txid());
209+
let events = drain_events(&mut rx);
210+
assert!(
211+
events.iter().any(|e| matches!(
212+
e,
213+
WalletEvent::TransactionStatusChanged {
214+
wallet_id: wid,
215+
status: TransactionContext::InstantSend,
216+
..
217+
} if *wid == wallet_id
218+
)),
219+
"expected TransactionStatusChanged(InstantSend) with correct wallet_id, got {:?}",
220+
events
221+
);
222+
223+
// Same IS lock via check_transaction_in_all_wallets (block/tx processing path)
224+
// should be suppressed — no duplicate event
225+
manager
226+
.check_transaction_in_all_wallets(&tx, TransactionContext::InstantSend, true, true)
227+
.await;
228+
assert_no_events(&mut rx);
229+
}
230+
231+
#[tokio::test]
232+
async fn test_mixed_instantsend_paths_reverse_no_duplicate_events() {
233+
let (mut manager, wallet_id, addr) = setup_manager_with_wallet();
234+
let mut rx = manager.subscribe_events();
235+
let tx = create_tx_paying_to(&addr, 0xf1);
236+
237+
// Mempool first
238+
manager.check_transaction_in_all_wallets(&tx, TransactionContext::Mempool, true, true).await;
239+
drain_events(&mut rx);
240+
241+
// IS lock via check_transaction_in_all_wallets first
242+
manager
243+
.check_transaction_in_all_wallets(&tx, TransactionContext::InstantSend, true, true)
244+
.await;
245+
let events = drain_events(&mut rx);
246+
assert!(
247+
events.iter().any(|e| matches!(
248+
e,
249+
WalletEvent::TransactionStatusChanged {
250+
wallet_id: wid,
251+
status: TransactionContext::InstantSend,
252+
..
253+
} if *wid == wallet_id
254+
)),
255+
"expected TransactionStatusChanged(InstantSend) with correct wallet_id, got {:?}",
256+
events
257+
);
258+
259+
// Same IS lock via process_instant_send_lock — should be suppressed
260+
manager.process_instant_send_lock(tx.txid());
261+
assert_no_events(&mut rx);
262+
}
263+
197264
#[tokio::test]
198265
async fn test_process_block_emits_events() {
199266
use dashcore::blockdata::block::{Block, Header, Version};

key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ impl WalletInfoInterface for ManagedWalletInfo {
234234
}
235235

236236
fn mark_instant_send_utxos(&mut self, txid: &Txid) -> bool {
237+
if !self.instant_send_locks.insert(*txid) {
238+
return false;
239+
}
237240
let mut any_changed = false;
238241
for account in self.accounts.all_accounts_mut() {
239242
if account.mark_utxos_instant_send(txid) {

0 commit comments

Comments
 (0)