@@ -2,11 +2,13 @@ use bdk_chain::{BlockId, CheckPoint, ConfirmationBlockTime};
22use bdk_wallet:: event:: WalletEvent ;
33use bdk_wallet:: test_utils:: { get_test_wpkh_and_change_desc, new_wallet_and_funding_update} ;
44use bdk_wallet:: Update ;
5+ use bitcoin:: block:: Header ;
56use bitcoin:: hashes:: Hash ;
6- use bitcoin:: { Address , Amount , BlockHash , FeeRate } ;
7+ use bitcoin:: { Address , Amount , Block , BlockHash , FeeRate , Transaction , TxMerkleNode } ;
78use core:: str:: FromStr ;
89use std:: sync:: Arc ;
910
11+ /// apply_update_events tests.
1012#[ test]
1113fn test_new_confirmed_tx_event ( ) {
1214 let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
@@ -27,9 +29,8 @@ fn test_new_confirmed_tx_event() {
2729 ) ;
2830 assert ! ( matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { tx, ..} if tx. output. len( ) == 1 ) ) ;
2931 assert ! (
30- matches!( events[ 2 ] , WalletEvent :: TxConfirmed { block_time, ..} if block_time. block_id. height == 2000 )
32+ matches!( & events[ 2 ] , WalletEvent :: TxConfirmed { tx , block_time, ..} if block_time. block_id. height == 2000 && tx . output . len ( ) == 2 )
3133 ) ;
32- assert ! ( matches!( & events[ 2 ] , WalletEvent :: TxConfirmed { tx, ..} if tx. output. len( ) == 2 ) ) ;
3334}
3435
3536#[ test]
@@ -86,7 +87,6 @@ fn test_tx_replaced_event() {
8687 update. tx_update . seen_ats = [ ( orig_txid, 210 ) ] . into ( ) ;
8788 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
8889 assert_eq ! ( events. len( ) , 1 ) ;
89- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
9090 assert ! (
9191 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == orig_txid)
9292 ) ;
@@ -107,9 +107,8 @@ fn test_tx_replaced_event() {
107107 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
108108 assert_eq ! ( events. len( ) , 2 ) ;
109109 assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { txid, .. } if txid == rbf_txid) ) ;
110- assert ! ( matches!( events[ 1 ] , WalletEvent :: TxReplaced { txid, ..} if txid == orig_txid) ) ;
111110 assert ! (
112- matches!( & events[ 1 ] , WalletEvent :: TxReplaced { conflicts, ..} if conflicts. len( ) == 1 &&
111+ matches!( & events[ 1 ] , WalletEvent :: TxReplaced { txid , conflicts, ..} if * txid == orig_txid && conflicts. len( ) == 1 &&
113112 conflicts. contains( & ( 0 , rbf_txid) ) )
114113 ) ;
115114}
@@ -139,7 +138,6 @@ fn test_tx_confirmed_event() {
139138 update. tx_update . seen_ats = [ ( new_txid, 210 ) ] . into ( ) ;
140139 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
141140 assert_eq ! ( events. len( ) , 1 ) ;
142- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
143141 assert ! (
144142 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == new_txid)
145143 ) ;
@@ -196,7 +194,6 @@ fn test_tx_confirmed_new_block_event() {
196194 update. tx_update . seen_ats = [ ( new_txid, 210 ) ] . into ( ) ;
197195 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
198196 assert_eq ! ( events. len( ) , 1 ) ;
199- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
200197 assert ! (
201198 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == new_txid)
202199 ) ;
@@ -280,7 +277,6 @@ fn test_tx_dropped_event() {
280277 update. tx_update . seen_ats = [ ( new_txid, 210 ) ] . into ( ) ;
281278 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
282279 assert_eq ! ( events. len( ) , 1 ) ;
283- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
284280 assert ! (
285281 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == new_txid)
286282 ) ;
@@ -293,3 +289,178 @@ fn test_tx_dropped_event() {
293289 assert_eq ! ( events. len( ) , 1 ) ;
294290 assert ! ( matches!( events[ 0 ] , WalletEvent :: TxDropped { txid, .. } if txid == new_txid) ) ;
295291}
292+
293+ // apply_block_events tests.
294+
295+ fn test_block ( prev_blockhash : BlockHash , time : u32 , txdata : Vec < Transaction > ) -> Block {
296+ Block {
297+ header : Header {
298+ version : Default :: default ( ) ,
299+ prev_blockhash,
300+ merkle_root : TxMerkleNode :: all_zeros ( ) ,
301+ time,
302+ bits : Default :: default ( ) ,
303+ nonce : time,
304+ } ,
305+ txdata,
306+ }
307+ }
308+
309+ #[ test]
310+ fn test_apply_block_new_confirmed_tx_event ( ) {
311+ let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
312+ let ( mut wallet, _, update) = new_wallet_and_funding_update ( desc, Some ( change_desc) ) ;
313+
314+ let genesis = BlockId {
315+ height : 0 ,
316+ hash : wallet. local_chain ( ) . genesis_hash ( ) ,
317+ } ;
318+ // apply empty block
319+ let block1 = test_block ( genesis. hash , 1000 , vec ! [ ] ) ;
320+ let events = wallet. apply_block_events ( & block1, 1 ) . unwrap ( ) ;
321+ assert_eq ! ( events. len( ) , 1 ) ;
322+
323+ // apply funding block
324+ let block2 = test_block (
325+ block1. block_hash ( ) ,
326+ 2000 ,
327+ update. tx_update . txs [ ..1 ]
328+ . iter ( )
329+ . map ( |tx| ( * * tx) . clone ( ) )
330+ . collect ( ) ,
331+ ) ;
332+ let events = wallet. apply_block_events ( & block2, 2 ) . unwrap ( ) ;
333+ assert_eq ! ( events. len( ) , 2 ) ;
334+ let new_tip2 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
335+ assert ! (
336+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 1 , block1. block_hash( ) ) . into( ) && new_tip == new_tip2)
337+ ) ;
338+ assert ! (
339+ matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { tx, block_time, ..} if block_time. block_id. height == 2 && tx. output. len( ) == 1 )
340+ ) ;
341+
342+ // apply empty block
343+ let block3 = test_block ( block2. block_hash ( ) , 3000 , vec ! [ ] ) ;
344+ let events = wallet. apply_block_events ( & block3, 3 ) . unwrap ( ) ;
345+ assert_eq ! ( events. len( ) , 1 ) ;
346+
347+ // apply spending block
348+ let block4 = test_block (
349+ block3. block_hash ( ) ,
350+ 4000 ,
351+ update. tx_update . txs [ 1 ..]
352+ . iter ( )
353+ . map ( |tx| ( * * tx) . clone ( ) )
354+ . collect ( ) ,
355+ ) ;
356+ let events = wallet. apply_block_events ( & block4, 4 ) . unwrap ( ) ;
357+ let new_tip3 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
358+ assert_eq ! ( events. len( ) , 2 ) ;
359+ assert ! (
360+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 3 , block3. block_hash( ) ) . into( ) && new_tip == new_tip3)
361+ ) ;
362+ assert ! (
363+ matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { tx, block_time, ..} if block_time. block_id. height == 4 && tx. output. len( ) == 2 )
364+ ) ;
365+ }
366+
367+ #[ test]
368+ fn test_apply_block_tx_unconfirmed_event ( ) {
369+ let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
370+ let ( mut wallet, _, update) = new_wallet_and_funding_update ( desc, Some ( change_desc) ) ;
371+ // apply funding block
372+ let genesis = BlockId {
373+ height : 0 ,
374+ hash : wallet. local_chain ( ) . genesis_hash ( ) ,
375+ } ;
376+ let block1 = test_block (
377+ genesis. hash ,
378+ 1000 ,
379+ update. tx_update . txs [ ..1 ]
380+ . iter ( )
381+ . map ( |tx| ( * * tx) . clone ( ) )
382+ . collect ( ) ,
383+ ) ;
384+ let events = wallet. apply_block_events ( & block1, 1 ) . unwrap ( ) ;
385+ assert_eq ! ( events. len( ) , 2 ) ;
386+
387+ // apply spending block
388+ let block2 = test_block (
389+ block1. block_hash ( ) ,
390+ 2000 ,
391+ update. tx_update . txs [ 1 ..]
392+ . iter ( )
393+ . map ( |tx| ( * * tx) . clone ( ) )
394+ . collect ( ) ,
395+ ) ;
396+ let events = wallet. apply_block_events ( & block2, 2 ) . unwrap ( ) ;
397+ assert_eq ! ( events. len( ) , 2 ) ;
398+ let new_tip2 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
399+ assert ! (
400+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 1 , block1. block_hash( ) ) . into( ) && new_tip == new_tip2)
401+ ) ;
402+ assert ! (
403+ matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { block_time, tx, ..} if block_time. block_id. height == 2 && tx. output. len( ) == 2 )
404+ ) ;
405+
406+ // apply reorg of spending block without previously confirmed tx
407+ let reorg_block2 = test_block ( block1. block_hash ( ) , 2100 , vec ! [ ] ) ;
408+ let events = wallet. apply_block_events ( & reorg_block2, 2 ) . unwrap ( ) ;
409+ assert_eq ! ( events. len( ) , 2 ) ;
410+ assert ! (
411+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip ==
412+ ( 2 , block2. block_hash( ) ) . into( ) && new_tip == ( 2 , reorg_block2. block_hash( ) ) . into( ) )
413+ ) ;
414+ assert ! (
415+ matches!( & events[ 1 ] , WalletEvent :: TxUnconfirmed { tx, old_block_time, ..} if
416+ tx. output. len( ) == 2 && old_block_time. is_some( ) )
417+ ) ;
418+ }
419+
420+ #[ test]
421+ fn test_apply_block_tx_confirmed_new_block_event ( ) {
422+ let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
423+ let ( mut wallet, _, update) = new_wallet_and_funding_update ( desc, Some ( change_desc) ) ;
424+ // apply funding block
425+ let genesis = BlockId {
426+ height : 0 ,
427+ hash : wallet. local_chain ( ) . genesis_hash ( ) ,
428+ } ;
429+ let block1 = test_block (
430+ genesis. hash ,
431+ 1000 ,
432+ update. tx_update . txs [ ..1 ]
433+ . iter ( )
434+ . map ( |tx| ( * * tx) . clone ( ) )
435+ . collect ( ) ,
436+ ) ;
437+ let events = wallet. apply_block_events ( & block1, 1 ) . unwrap ( ) ;
438+ assert_eq ! ( events. len( ) , 2 ) ;
439+
440+ // apply spending block
441+ let spending_tx: Transaction = ( * update. tx_update . txs [ 1 ] . clone ( ) ) . clone ( ) ;
442+ let block2 = test_block ( block1. block_hash ( ) , 2000 , vec ! [ spending_tx. clone( ) ] ) ;
443+ let events = wallet. apply_block_events ( & block2, 2 ) . unwrap ( ) ;
444+ assert_eq ! ( events. len( ) , 2 ) ;
445+ let new_tip2 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
446+ assert ! (
447+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 1 , block1. block_hash( ) ) . into( ) && new_tip == new_tip2)
448+ ) ;
449+ assert ! (
450+ matches!( events[ 1 ] , WalletEvent :: TxConfirmed { txid, block_time, old_block_time, .. } if
451+ txid == spending_tx. compute_txid( ) && block_time. block_id == ( 2 , block2. block_hash( ) ) . into( ) && old_block_time. is_none( ) )
452+ ) ;
453+
454+ // apply reorg of spending block including the original spending tx
455+ let reorg_block2 = test_block ( block1. block_hash ( ) , 2100 , vec ! [ spending_tx. clone( ) ] ) ;
456+ let events = wallet. apply_block_events ( & reorg_block2, 2 ) . unwrap ( ) ;
457+ assert_eq ! ( events. len( ) , 2 ) ;
458+ assert ! (
459+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip ==
460+ ( 2 , block2. block_hash( ) ) . into( ) && new_tip == ( 2 , reorg_block2. block_hash( ) ) . into( ) )
461+ ) ;
462+ assert ! (
463+ matches!( events[ 1 ] , WalletEvent :: TxConfirmed { txid, block_time, old_block_time, .. } if
464+ txid == spending_tx. compute_txid( ) && block_time. block_id == ( 2 , reorg_block2. block_hash( ) ) . into( ) && old_block_time. is_some( ) )
465+ ) ;
466+ }
0 commit comments