11#![ cfg( any( feature = "esplora-blocking" , feature = "esplora-async" ) ) ]
22use lightning_transaction_sync:: EsploraSyncClient ;
3- use lightning:: chain:: { Confirm , Filter } ;
4- use lightning:: chain:: transaction:: TransactionData ;
3+ use lightning:: chain:: { Confirm , Filter , WatchedOutput } ;
4+ use lightning:: chain:: transaction:: { OutPoint , TransactionData } ;
55use lightning:: util:: test_utils:: TestLogger ;
66
77use electrsd:: { bitcoind, bitcoind:: BitcoinD , ElectrsD } ;
@@ -168,9 +168,13 @@ fn test_esplora_syncs() {
168168 assert_eq ! ( events. len( ) , 1 ) ;
169169
170170 // Check registered confirmed transactions are marked confirmed
171- let new_address = bitcoind. client . get_new_address ( Some ( "test" ) , Some ( AddressType :: Legacy ) ) . unwrap ( ) . assume_checked ( ) ;
172- let txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None , None , None , None , None , None ) . unwrap ( ) ;
173- tx_sync. register_tx ( & txid, & new_address. payload . script_pubkey ( ) ) ;
171+ let new_address = bitcoind. client . get_new_address ( Some ( "test" ) ,
172+ Some ( AddressType :: Legacy ) ) . unwrap ( ) . assume_checked ( ) ;
173+ let txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None , None ,
174+ None , None , None , None ) . unwrap ( ) ;
175+ let second_txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None ,
176+ None , None , None , None , None ) . unwrap ( ) ;
177+ tx_sync. register_tx ( & txid, & new_address. script_pubkey ( ) ) ;
174178
175179 tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
176180
@@ -187,6 +191,29 @@ fn test_esplora_syncs() {
187191 assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
188192 assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
189193
194+ // Now take an arbitrary output of the second transaction and check we'll confirm its spend.
195+ let tx_res = bitcoind. client . get_transaction ( & second_txid, None ) . unwrap ( ) ;
196+ let block_hash = tx_res. info . blockhash . unwrap ( ) ;
197+ let tx = tx_res. transaction ( ) . unwrap ( ) ;
198+ let prev_outpoint = tx. input . first ( ) . unwrap ( ) . previous_output ;
199+ let prev_tx = bitcoind. client . get_transaction ( & prev_outpoint. txid , None ) . unwrap ( ) . transaction ( )
200+ . unwrap ( ) ;
201+ let prev_script_pubkey = prev_tx. output [ prev_outpoint. vout as usize ] . script_pubkey . clone ( ) ;
202+ let output = WatchedOutput {
203+ block_hash : Some ( block_hash) ,
204+ outpoint : OutPoint { txid : prev_outpoint. txid , index : prev_outpoint. vout as u16 } ,
205+ script_pubkey : prev_script_pubkey
206+ } ;
207+
208+ tx_sync. register_output ( output) ;
209+ tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
210+
211+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
212+ assert_eq ! ( events. len( ) , 1 ) ;
213+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
214+ assert_eq ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . len( ) , 2 ) ;
215+ assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
216+
190217 // Check previously confirmed transactions are marked unconfirmed when they are reorged.
191218 let best_block_hash = bitcoind. client . get_best_block_hash ( ) . unwrap ( ) ;
192219 bitcoind. client . invalidate_block ( & best_block_hash) . unwrap ( ) ;
@@ -203,32 +230,54 @@ fn test_esplora_syncs() {
203230 assert_ne ! ( bitcoind. client. get_best_block_hash( ) . unwrap( ) , best_block_hash) ;
204231 tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
205232
206- // Transaction still confirmed but under new tip.
233+ // Transactions still confirmed but under new tip.
207234 assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
235+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
208236 assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
209237
210238 // Check we got unconfirmed, then reconfirmed in the meantime.
239+ let mut seen_txids = HashSet :: new ( ) ;
211240 let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
212- assert_eq ! ( events. len( ) , 3 ) ;
241+ assert_eq ! ( events. len( ) , 5 ) ;
213242
214243 match events[ 0 ] {
215244 TestConfirmableEvent :: Unconfirmed ( t) => {
216- assert_eq ! ( t, txid) ;
245+ assert ! ( t == txid || t == second_txid) ;
246+ assert ! ( seen_txids. insert( t) ) ;
217247 } ,
218248 _ => panic ! ( "Unexpected event" ) ,
219249 }
220250
221251 match events[ 1 ] {
222- TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
252+ TestConfirmableEvent :: Unconfirmed ( t) => {
253+ assert ! ( t == txid || t == second_txid) ;
254+ assert ! ( seen_txids. insert( t) ) ;
255+ } ,
223256 _ => panic ! ( "Unexpected event" ) ,
224257 }
225258
226259 match events[ 2 ] {
260+ TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
261+ _ => panic ! ( "Unexpected event" ) ,
262+ }
263+
264+ match events[ 3 ] {
265+ TestConfirmableEvent :: Confirmed ( t, _, _) => {
266+ assert ! ( t == txid || t == second_txid) ;
267+ assert ! ( seen_txids. remove( & t) ) ;
268+ } ,
269+ _ => panic ! ( "Unexpected event" ) ,
270+ }
271+
272+ match events[ 4 ] {
227273 TestConfirmableEvent :: Confirmed ( t, _, _) => {
228- assert_eq ! ( t, txid) ;
274+ assert ! ( t == txid || t == second_txid) ;
275+ assert ! ( seen_txids. remove( & t) ) ;
229276 } ,
230277 _ => panic ! ( "Unexpected event" ) ,
231278 }
279+
280+ assert_eq ! ( seen_txids. len( ) , 0 ) ;
232281}
233282
234283#[ tokio:: test]
@@ -251,9 +300,13 @@ async fn test_esplora_syncs() {
251300 assert_eq ! ( events. len( ) , 1 ) ;
252301
253302 // Check registered confirmed transactions are marked confirmed
254- let new_address = bitcoind. client . get_new_address ( Some ( "test" ) , Some ( AddressType :: Legacy ) ) . unwrap ( ) . assume_checked ( ) ;
255- let txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None , None , None , None , None , None ) . unwrap ( ) ;
256- tx_sync. register_tx ( & txid, & new_address. payload . script_pubkey ( ) ) ;
303+ let new_address = bitcoind. client . get_new_address ( Some ( "test" ) ,
304+ Some ( AddressType :: Legacy ) ) . unwrap ( ) . assume_checked ( ) ;
305+ let txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None , None ,
306+ None , None , None , None ) . unwrap ( ) ;
307+ let second_txid = bitcoind. client . send_to_address ( & new_address, Amount :: from_sat ( 5000 ) , None ,
308+ None , None , None , None , None ) . unwrap ( ) ;
309+ tx_sync. register_tx ( & txid, & new_address. script_pubkey ( ) ) ;
257310
258311 tx_sync. sync ( vec ! [ & confirmable] ) . await . unwrap ( ) ;
259312
@@ -270,6 +323,29 @@ async fn test_esplora_syncs() {
270323 assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
271324 assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
272325
326+ // Now take an arbitrary output of the second transaction and check we'll confirm its spend.
327+ let tx_res = bitcoind. client . get_transaction ( & second_txid, None ) . unwrap ( ) ;
328+ let block_hash = tx_res. info . blockhash . unwrap ( ) ;
329+ let tx = tx_res. transaction ( ) . unwrap ( ) ;
330+ let prev_outpoint = tx. input . first ( ) . unwrap ( ) . previous_output ;
331+ let prev_tx = bitcoind. client . get_transaction ( & prev_outpoint. txid , None ) . unwrap ( ) . transaction ( )
332+ . unwrap ( ) ;
333+ let prev_script_pubkey = prev_tx. output [ prev_outpoint. vout as usize ] . script_pubkey . clone ( ) ;
334+ let output = WatchedOutput {
335+ block_hash : Some ( block_hash) ,
336+ outpoint : OutPoint { txid : prev_outpoint. txid , index : prev_outpoint. vout as u16 } ,
337+ script_pubkey : prev_script_pubkey
338+ } ;
339+
340+ tx_sync. register_output ( output) ;
341+ tx_sync. sync ( vec ! [ & confirmable] ) . await . unwrap ( ) ;
342+
343+ let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
344+ assert_eq ! ( events. len( ) , 1 ) ;
345+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
346+ assert_eq ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . len( ) , 2 ) ;
347+ assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
348+
273349 // Check previously confirmed transactions are marked unconfirmed when they are reorged.
274350 let best_block_hash = bitcoind. client . get_best_block_hash ( ) . unwrap ( ) ;
275351 bitcoind. client . invalidate_block ( & best_block_hash) . unwrap ( ) ;
@@ -286,30 +362,52 @@ async fn test_esplora_syncs() {
286362 assert_ne ! ( bitcoind. client. get_best_block_hash( ) . unwrap( ) , best_block_hash) ;
287363 tx_sync. sync ( vec ! [ & confirmable] ) . await . unwrap ( ) ;
288364
289- // Transaction still confirmed but under new tip.
365+ // Transactions still confirmed but under new tip.
290366 assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
367+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
291368 assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
292369
293370 // Check we got unconfirmed, then reconfirmed in the meantime.
371+ let mut seen_txids = HashSet :: new ( ) ;
294372 let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
295- assert_eq ! ( events. len( ) , 3 ) ;
373+ assert_eq ! ( events. len( ) , 5 ) ;
296374
297375 match events[ 0 ] {
298376 TestConfirmableEvent :: Unconfirmed ( t) => {
299- assert_eq ! ( t, txid) ;
377+ assert ! ( t == txid || t == second_txid) ;
378+ assert ! ( seen_txids. insert( t) ) ;
300379 } ,
301380 _ => panic ! ( "Unexpected event" ) ,
302381 }
303382
304383 match events[ 1 ] {
305- TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
384+ TestConfirmableEvent :: Unconfirmed ( t) => {
385+ assert ! ( t == txid || t == second_txid) ;
386+ assert ! ( seen_txids. insert( t) ) ;
387+ } ,
306388 _ => panic ! ( "Unexpected event" ) ,
307389 }
308390
309391 match events[ 2 ] {
392+ TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
393+ _ => panic ! ( "Unexpected event" ) ,
394+ }
395+
396+ match events[ 3 ] {
397+ TestConfirmableEvent :: Confirmed ( t, _, _) => {
398+ assert ! ( t == txid || t == second_txid) ;
399+ assert ! ( seen_txids. remove( & t) ) ;
400+ } ,
401+ _ => panic ! ( "Unexpected event" ) ,
402+ }
403+
404+ match events[ 4 ] {
310405 TestConfirmableEvent :: Confirmed ( t, _, _) => {
311- assert_eq ! ( t, txid) ;
406+ assert ! ( t == txid || t == second_txid) ;
407+ assert ! ( seen_txids. remove( & t) ) ;
312408 } ,
313409 _ => panic ! ( "Unexpected event" ) ,
314410 }
411+
412+ assert_eq ! ( seen_txids. len( ) , 0 ) ;
315413}
0 commit comments