11use 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} ;
4- use bdk_wallet:: Update ;
4+ use bdk_wallet:: { SignOptions , Update } ;
55use bitcoin:: hashes:: Hash ;
6- use bitcoin:: { Address , Amount , BlockHash , FeeRate } ;
6+ use bitcoin:: { Address , Amount , Block , BlockHash , FeeRate , Transaction , TxMerkleNode } ;
77use core:: str:: FromStr ;
88use std:: sync:: Arc ;
99
10+ /// apply_update_events tests.
1011#[ test]
1112fn test_new_confirmed_tx_event ( ) {
1213 let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
@@ -27,9 +28,8 @@ fn test_new_confirmed_tx_event() {
2728 ) ;
2829 assert ! ( matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { tx, ..} if tx. output. len( ) == 1 ) ) ;
2930 assert ! (
30- matches!( events[ 2 ] , WalletEvent :: TxConfirmed { block_time, ..} if block_time. block_id. height == 2000 )
31+ matches!( & events[ 2 ] , WalletEvent :: TxConfirmed { tx , block_time, ..} if block_time. block_id. height == 2000 && tx . output . len ( ) == 2 )
3132 ) ;
32- assert ! ( matches!( & events[ 2 ] , WalletEvent :: TxConfirmed { tx, ..} if tx. output. len( ) == 2 ) ) ;
3333}
3434
3535#[ test]
@@ -86,7 +86,6 @@ fn test_tx_replaced_event() {
8686 update. tx_update . seen_ats = [ ( orig_txid, 210 ) ] . into ( ) ;
8787 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
8888 assert_eq ! ( events. len( ) , 1 ) ;
89- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
9089 assert ! (
9190 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == orig_txid)
9291 ) ;
@@ -107,9 +106,8 @@ fn test_tx_replaced_event() {
107106 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
108107 assert_eq ! ( events. len( ) , 2 ) ;
109108 assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { txid, .. } if txid == rbf_txid) ) ;
110- assert ! ( matches!( events[ 1 ] , WalletEvent :: TxReplaced { txid, ..} if txid == orig_txid) ) ;
111109 assert ! (
112- matches!( & events[ 1 ] , WalletEvent :: TxReplaced { conflicts, ..} if conflicts. len( ) == 1 &&
110+ matches!( & events[ 1 ] , WalletEvent :: TxReplaced { txid , conflicts, ..} if * txid == orig_txid && conflicts. len( ) == 1 &&
113111 conflicts. contains( & ( 0 , rbf_txid) ) )
114112 ) ;
115113}
@@ -139,7 +137,6 @@ fn test_tx_confirmed_event() {
139137 update. tx_update . seen_ats = [ ( new_txid, 210 ) ] . into ( ) ;
140138 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
141139 assert_eq ! ( events. len( ) , 1 ) ;
142- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
143140 assert ! (
144141 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == new_txid)
145142 ) ;
@@ -196,7 +193,6 @@ fn test_tx_confirmed_new_block_event() {
196193 update. tx_update . seen_ats = [ ( new_txid, 210 ) ] . into ( ) ;
197194 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
198195 assert_eq ! ( events. len( ) , 1 ) ;
199- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
200196 assert ! (
201197 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == new_txid)
202198 ) ;
@@ -280,7 +276,6 @@ fn test_tx_dropped_event() {
280276 update. tx_update . seen_ats = [ ( new_txid, 210 ) ] . into ( ) ;
281277 let events = wallet. apply_update_events ( update) . unwrap ( ) ;
282278 assert_eq ! ( events. len( ) , 1 ) ;
283- assert ! ( matches!( events[ 0 ] , WalletEvent :: TxUnconfirmed { .. } ) ) ;
284279 assert ! (
285280 matches!( & events[ 0 ] , WalletEvent :: TxUnconfirmed { tx, ..} if tx. compute_txid( ) == new_txid)
286281 ) ;
@@ -293,3 +288,178 @@ fn test_tx_dropped_event() {
293288 assert_eq ! ( events. len( ) , 1 ) ;
294289 assert ! ( matches!( events[ 0 ] , WalletEvent :: TxDropped { txid, .. } if txid == new_txid) ) ;
295290}
291+
292+ // apply_block_events tests.
293+
294+ fn test_block ( prev_blockhash : BlockHash , time : u32 , txdata : Vec < Transaction > ) -> Block {
295+ Block {
296+ header : Header {
297+ version : Default :: default ( ) ,
298+ prev_blockhash,
299+ merkle_root : TxMerkleNode :: all_zeros ( ) ,
300+ time,
301+ bits : Default :: default ( ) ,
302+ nonce : time,
303+ } ,
304+ txdata,
305+ }
306+ }
307+
308+ #[ test]
309+ fn test_apply_block_new_confirmed_tx_event ( ) {
310+ let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
311+ let ( mut wallet, _, update) = new_wallet_and_funding_update ( desc, Some ( change_desc) ) ;
312+
313+ let genesis = BlockId {
314+ height : 0 ,
315+ hash : wallet. local_chain ( ) . genesis_hash ( ) ,
316+ } ;
317+ // apply empty block
318+ let block1 = test_block ( genesis. hash , 1000 , vec ! [ ] ) ;
319+ let events = wallet. apply_block_events ( & block1, 1 ) . unwrap ( ) ;
320+ assert_eq ! ( events. len( ) , 1 ) ;
321+
322+ // apply funding block
323+ let block2 = test_block (
324+ block1. block_hash ( ) ,
325+ 2000 ,
326+ update. tx_update . txs [ ..1 ]
327+ . iter ( )
328+ . map ( |tx| ( * * tx) . clone ( ) )
329+ . collect ( ) ,
330+ ) ;
331+ let events = wallet. apply_block_events ( & block2, 2 ) . unwrap ( ) ;
332+ assert_eq ! ( events. len( ) , 2 ) ;
333+ let new_tip2 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
334+ assert ! (
335+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 1 , block1. block_hash( ) ) . into( ) && new_tip == new_tip2)
336+ ) ;
337+ assert ! (
338+ matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { tx, block_time, ..} if block_time. block_id. height == 2 && tx. output. len( ) == 1 )
339+ ) ;
340+
341+ // apply empty block
342+ let block3 = test_block ( block2. block_hash ( ) , 3000 , vec ! [ ] ) ;
343+ let events = wallet. apply_block_events ( & block3, 3 ) . unwrap ( ) ;
344+ assert_eq ! ( events. len( ) , 1 ) ;
345+
346+ // apply spending block
347+ let block4 = test_block (
348+ block3. block_hash ( ) ,
349+ 4000 ,
350+ update. tx_update . txs [ 1 ..]
351+ . iter ( )
352+ . map ( |tx| ( * * tx) . clone ( ) )
353+ . collect ( ) ,
354+ ) ;
355+ let events = wallet. apply_block_events ( & block4, 4 ) . unwrap ( ) ;
356+ let new_tip3 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
357+ assert_eq ! ( events. len( ) , 2 ) ;
358+ assert ! (
359+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 3 , block3. block_hash( ) ) . into( ) && new_tip == new_tip3)
360+ ) ;
361+ assert ! (
362+ matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { tx, block_time, ..} if block_time. block_id. height == 4 && tx. output. len( ) == 2 )
363+ ) ;
364+ }
365+
366+ #[ test]
367+ fn test_apply_block_tx_unconfirmed_event ( ) {
368+ let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
369+ let ( mut wallet, _, update) = new_wallet_and_funding_update ( desc, Some ( change_desc) ) ;
370+ // apply funding block
371+ let genesis = BlockId {
372+ height : 0 ,
373+ hash : wallet. local_chain ( ) . genesis_hash ( ) ,
374+ } ;
375+ let block1 = test_block (
376+ genesis. hash ,
377+ 1000 ,
378+ update. tx_update . txs [ ..1 ]
379+ . iter ( )
380+ . map ( |tx| ( * * tx) . clone ( ) )
381+ . collect ( ) ,
382+ ) ;
383+ let events = wallet. apply_block_events ( & block1, 1 ) . unwrap ( ) ;
384+ assert_eq ! ( events. len( ) , 2 ) ;
385+
386+ // apply spending block
387+ let block2 = test_block (
388+ block1. block_hash ( ) ,
389+ 2000 ,
390+ update. tx_update . txs [ 1 ..]
391+ . iter ( )
392+ . map ( |tx| ( * * tx) . clone ( ) )
393+ . collect ( ) ,
394+ ) ;
395+ let events = wallet. apply_block_events ( & block2, 2 ) . unwrap ( ) ;
396+ assert_eq ! ( events. len( ) , 2 ) ;
397+ let new_tip2 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
398+ assert ! (
399+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 1 , block1. block_hash( ) ) . into( ) && new_tip == new_tip2)
400+ ) ;
401+ assert ! (
402+ matches!( & events[ 1 ] , WalletEvent :: TxConfirmed { block_time, tx, ..} if block_time. block_id. height == 2 && tx. output. len( ) == 2 )
403+ ) ;
404+
405+ // apply reorg of spending block without previously confirmed tx
406+ let reorg_block2 = test_block ( block1. block_hash ( ) , 2100 , vec ! [ ] ) ;
407+ let events = wallet. apply_block_events ( & reorg_block2, 2 ) . unwrap ( ) ;
408+ assert_eq ! ( events. len( ) , 2 ) ;
409+ assert ! (
410+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip ==
411+ ( 2 , block2. block_hash( ) ) . into( ) && new_tip == ( 2 , reorg_block2. block_hash( ) ) . into( ) )
412+ ) ;
413+ assert ! (
414+ matches!( & events[ 1 ] , WalletEvent :: TxUnconfirmed { tx, old_block_time, ..} if
415+ tx. output. len( ) == 2 && old_block_time. is_some( ) )
416+ ) ;
417+ }
418+
419+ #[ test]
420+ fn test_apply_block_tx_confirmed_new_block_event ( ) {
421+ let ( desc, change_desc) = get_test_wpkh_and_change_desc ( ) ;
422+ let ( mut wallet, _, update) = new_wallet_and_funding_update ( desc, Some ( change_desc) ) ;
423+ // apply funding block
424+ let genesis = BlockId {
425+ height : 0 ,
426+ hash : wallet. local_chain ( ) . genesis_hash ( ) ,
427+ } ;
428+ let block1 = test_block (
429+ genesis. hash ,
430+ 1000 ,
431+ update. tx_update . txs [ ..1 ]
432+ . iter ( )
433+ . map ( |tx| ( * * tx) . clone ( ) )
434+ . collect ( ) ,
435+ ) ;
436+ let events = wallet. apply_block_events ( & block1, 1 ) . unwrap ( ) ;
437+ assert_eq ! ( events. len( ) , 2 ) ;
438+
439+ // apply spending block
440+ let spending_tx: Transaction = ( * update. tx_update . txs [ 1 ] . clone ( ) ) . clone ( ) ;
441+ let block2 = test_block ( block1. block_hash ( ) , 2000 , vec ! [ spending_tx. clone( ) ] ) ;
442+ let events = wallet. apply_block_events ( & block2, 2 ) . unwrap ( ) ;
443+ assert_eq ! ( events. len( ) , 2 ) ;
444+ let new_tip2 = wallet. local_chain ( ) . tip ( ) . block_id ( ) ;
445+ assert ! (
446+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip == ( 1 , block1. block_hash( ) ) . into( ) && new_tip == new_tip2)
447+ ) ;
448+ assert ! (
449+ matches!( events[ 1 ] , WalletEvent :: TxConfirmed { txid, block_time, old_block_time, .. } if
450+ txid == spending_tx. compute_txid( ) && block_time. block_id == ( 2 , block2. block_hash( ) ) . into( ) && old_block_time. is_none( ) )
451+ ) ;
452+
453+ // apply reorg of spending block including the original spending tx
454+ let reorg_block2 = test_block ( block1. block_hash ( ) , 2100 , vec ! [ spending_tx. clone( ) ] ) ;
455+ let events = wallet. apply_block_events ( & reorg_block2, 2 ) . unwrap ( ) ;
456+ assert_eq ! ( events. len( ) , 2 ) ;
457+ assert ! (
458+ matches!( events[ 0 ] , WalletEvent :: ChainTipChanged { old_tip, new_tip } if old_tip ==
459+ ( 2 , block2. block_hash( ) ) . into( ) && new_tip == ( 2 , reorg_block2. block_hash( ) ) . into( ) )
460+ ) ;
461+ assert ! (
462+ matches!( events[ 1 ] , WalletEvent :: TxConfirmed { txid, block_time, old_block_time, .. } if
463+ txid == spending_tx. compute_txid( ) && block_time. block_id == ( 2 , reorg_block2. block_hash( ) ) . into( ) && old_block_time. is_some( ) )
464+ ) ;
465+ }
0 commit comments