1- #![ cfg( any( feature = "esplora-blocking" , feature = "esplora-async" ) ) ]
1+ #![ cfg( any( feature = "esplora-blocking" , feature = "esplora-async" , feature = "electrum" ) ) ]
2+
3+ #[ cfg( any( feature = "esplora-blocking" , feature = "esplora-async" ) ) ]
24use lightning_transaction_sync:: EsploraSyncClient ;
5+ #[ cfg( feature = "electrum" ) ]
6+ use lightning_transaction_sync:: ElectrumSyncClient ;
37use lightning:: chain:: { Confirm , Filter , WatchedOutput } ;
48use lightning:: chain:: transaction:: { OutPoint , TransactionData } ;
59use lightning:: util:: test_utils:: TestLogger ;
@@ -11,7 +15,6 @@ use bitcoin::blockdata::constants::genesis_block;
1115use bitcoin:: network:: constants:: Network ;
1216use electrsd:: bitcoind:: bitcoincore_rpc:: bitcoincore_rpc_json:: AddressType ;
1317use bitcoind:: bitcoincore_rpc:: RpcApi ;
14- use electrsd:: electrum_client:: ElectrumApi ;
1518
1619use std:: env;
1720use std:: sync:: Mutex ;
@@ -51,6 +54,7 @@ pub fn generate_blocks_and_wait(bitcoind: &BitcoinD, electrsd: &ElectrsD, num: u
5154}
5255
5356pub fn wait_for_block ( electrsd : & ElectrsD , min_height : usize ) {
57+ use electrsd:: electrum_client:: ElectrumApi ;
5458 let mut header = match electrsd. client . block_headers_subscribe_raw ( ) {
5559 Ok ( header) => header,
5660 Err ( _) => {
@@ -411,3 +415,135 @@ async fn test_esplora_syncs() {
411415
412416 assert_eq ! ( seen_txids. len( ) , 0 ) ;
413417}
418+
419+ #[ test]
420+ #[ cfg( feature = "electrum" ) ]
421+ fn test_electrum_syncs ( ) {
422+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
423+ generate_blocks_and_wait ( & bitcoind, & electrsd, 101 ) ;
424+ let mut logger = TestLogger :: new ( ) ;
425+ let electrum_url = format ! ( "tcp://{}" , electrsd. electrum_url) ;
426+ let tx_sync = ElectrumSyncClient :: new ( electrum_url, & mut logger) . unwrap ( ) ;
427+ let confirmable = TestConfirmable :: new ( ) ;
428+
429+ // Check we pick up on new best blocks
430+ assert_eq ! ( confirmable. best_block. lock( ) . unwrap( ) . 1 , 0 ) ;
431+
432+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
433+ assert_eq ! ( confirmable. best_block. lock( ) . unwrap( ) . 1 , 102 ) ;
434+
435+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
436+ assert_eq ! ( events. len( ) , 1 ) ;
437+
438+ // Check registered confirmed transactions are marked confirmed
439+ let new_address = bitcoind. client . get_new_address ( Some ( "test" ) ,
440+ Some ( AddressType :: Legacy ) ) . unwrap ( ) . assume_checked ( ) ;
441+ let txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None , None ,
442+ None , None , None , None ) . unwrap ( ) ;
443+ let second_txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None ,
444+ None , None , None , None , None ) . unwrap ( ) ;
445+ tx_sync. register_tx ( & txid, & new_address. script_pubkey ( ) ) ;
446+
447+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
448+
449+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
450+ assert_eq ! ( events. len( ) , 0 ) ;
451+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
452+ assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
453+
454+ generate_blocks_and_wait ( & bitcoind, & electrsd, 1 ) ;
455+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
456+
457+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
458+ assert_eq ! ( events. len( ) , 2 ) ;
459+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
460+ assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
461+
462+ // Now take an arbitrary output of the second transaction and check we'll confirm its spend.
463+ let tx_res = bitcoind. client . get_transaction ( & second_txid, None ) . unwrap ( ) ;
464+ let block_hash = tx_res. info . blockhash . unwrap ( ) ;
465+ let tx = tx_res. transaction ( ) . unwrap ( ) ;
466+ let prev_outpoint = tx. input . first ( ) . unwrap ( ) . previous_output ;
467+ let prev_tx = bitcoind. client . get_transaction ( & prev_outpoint. txid , None ) . unwrap ( ) . transaction ( )
468+ . unwrap ( ) ;
469+ let prev_script_pubkey = prev_tx. output [ prev_outpoint. vout as usize ] . script_pubkey . clone ( ) ;
470+ let output = WatchedOutput {
471+ block_hash : Some ( block_hash) ,
472+ outpoint : OutPoint { txid : prev_outpoint. txid , index : prev_outpoint. vout as u16 } ,
473+ script_pubkey : prev_script_pubkey
474+ } ;
475+
476+ tx_sync. register_output ( output) ;
477+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
478+
479+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
480+ assert_eq ! ( events. len( ) , 1 ) ;
481+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
482+ assert_eq ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . len( ) , 2 ) ;
483+ assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
484+
485+ // Check previously confirmed transactions are marked unconfirmed when they are reorged.
486+ let best_block_hash = bitcoind. client . get_best_block_hash ( ) . unwrap ( ) ;
487+ bitcoind. client . invalidate_block ( & best_block_hash) . unwrap ( ) ;
488+
489+ // We're getting back to the previous height with a new tip, but best block shouldn't change.
490+ generate_blocks_and_wait ( & bitcoind, & electrsd, 1 ) ;
491+ assert_ne ! ( bitcoind. client. get_best_block_hash( ) . unwrap( ) , best_block_hash) ;
492+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
493+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
494+ assert_eq ! ( events. len( ) , 0 ) ;
495+
496+ // Now we're surpassing previous height, getting new tip.
497+ generate_blocks_and_wait ( & bitcoind, & electrsd, 1 ) ;
498+ assert_ne ! ( bitcoind. client. get_best_block_hash( ) . unwrap( ) , best_block_hash) ;
499+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
500+
501+ // Transactions still confirmed but under new tip.
502+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
503+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
504+ assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
505+
506+ // Check we got unconfirmed, then reconfirmed in the meantime.
507+ let mut seen_txids = HashSet :: new ( ) ;
508+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
509+ assert_eq ! ( events. len( ) , 5 ) ;
510+
511+ match events[ 0 ] {
512+ TestConfirmableEvent :: Unconfirmed ( t) => {
513+ assert ! ( t == txid || t == second_txid) ;
514+ assert ! ( seen_txids. insert( t) ) ;
515+ } ,
516+ _ => panic ! ( "Unexpected event" ) ,
517+ }
518+
519+ match events[ 1 ] {
520+ TestConfirmableEvent :: Unconfirmed ( t) => {
521+ assert ! ( t == txid || t == second_txid) ;
522+ assert ! ( seen_txids. insert( t) ) ;
523+ } ,
524+ _ => panic ! ( "Unexpected event" ) ,
525+ }
526+
527+ match events[ 2 ] {
528+ TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
529+ _ => panic ! ( "Unexpected event" ) ,
530+ }
531+
532+ match events[ 3 ] {
533+ TestConfirmableEvent :: Confirmed ( t, _, _) => {
534+ assert ! ( t == txid || t == second_txid) ;
535+ assert ! ( seen_txids. remove( & t) ) ;
536+ } ,
537+ _ => panic ! ( "Unexpected event" ) ,
538+ }
539+
540+ match events[ 4 ] {
541+ TestConfirmableEvent :: Confirmed ( t, _, _) => {
542+ assert ! ( t == txid || t == second_txid) ;
543+ assert ! ( seen_txids. remove( & t) ) ;
544+ } ,
545+ _ => panic ! ( "Unexpected event" ) ,
546+ }
547+
548+ assert_eq ! ( seen_txids. len( ) , 0 ) ;
549+ }
0 commit comments