1
1
#![ cfg( any( feature = "esplora-blocking" , feature = "esplora-async" ) ) ]
2
2
use 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 } ;
5
5
use lightning:: util:: test_utils:: TestLogger ;
6
6
7
7
use electrsd:: { bitcoind, bitcoind:: BitcoinD , ElectrsD } ;
@@ -168,9 +168,13 @@ fn test_esplora_syncs() {
168
168
assert_eq ! ( events. len( ) , 1 ) ;
169
169
170
170
// 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 ( ) ) ;
174
178
175
179
tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
176
180
@@ -187,6 +191,29 @@ fn test_esplora_syncs() {
187
191
assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
188
192
assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
189
193
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
+
190
217
// Check previously confirmed transactions are marked unconfirmed when they are reorged.
191
218
let best_block_hash = bitcoind. client . get_best_block_hash ( ) . unwrap ( ) ;
192
219
bitcoind. client . invalidate_block ( & best_block_hash) . unwrap ( ) ;
@@ -203,32 +230,54 @@ fn test_esplora_syncs() {
203
230
assert_ne ! ( bitcoind. client. get_best_block_hash( ) . unwrap( ) , best_block_hash) ;
204
231
tx_sync. sync ( vec ! [ & confirmable] ) . unwrap ( ) ;
205
232
206
- // Transaction still confirmed but under new tip.
233
+ // Transactions still confirmed but under new tip.
207
234
assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
235
+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
208
236
assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
209
237
210
238
// Check we got unconfirmed, then reconfirmed in the meantime.
239
+ let mut seen_txids = HashSet :: new ( ) ;
211
240
let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
212
- assert_eq ! ( events. len( ) , 3 ) ;
241
+ assert_eq ! ( events. len( ) , 5 ) ;
213
242
214
243
match events[ 0 ] {
215
244
TestConfirmableEvent :: Unconfirmed ( t) => {
216
- assert_eq ! ( t, txid) ;
245
+ assert ! ( t == txid || t == second_txid) ;
246
+ assert ! ( seen_txids. insert( t) ) ;
217
247
} ,
218
248
_ => panic ! ( "Unexpected event" ) ,
219
249
}
220
250
221
251
match events[ 1 ] {
222
- TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
252
+ TestConfirmableEvent :: Unconfirmed ( t) => {
253
+ assert ! ( t == txid || t == second_txid) ;
254
+ assert ! ( seen_txids. insert( t) ) ;
255
+ } ,
223
256
_ => panic ! ( "Unexpected event" ) ,
224
257
}
225
258
226
259
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 ] {
227
273
TestConfirmableEvent :: Confirmed ( t, _, _) => {
228
- assert_eq ! ( t, txid) ;
274
+ assert ! ( t == txid || t == second_txid) ;
275
+ assert ! ( seen_txids. remove( & t) ) ;
229
276
} ,
230
277
_ => panic ! ( "Unexpected event" ) ,
231
278
}
279
+
280
+ assert_eq ! ( seen_txids. len( ) , 0 ) ;
232
281
}
233
282
234
283
#[ tokio:: test]
@@ -251,9 +300,13 @@ async fn test_esplora_syncs() {
251
300
assert_eq ! ( events. len( ) , 1 ) ;
252
301
253
302
// 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 ( ) ) ;
257
310
258
311
tx_sync. sync ( vec ! [ & confirmable] ) . await . unwrap ( ) ;
259
312
@@ -270,6 +323,29 @@ async fn test_esplora_syncs() {
270
323
assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
271
324
assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
272
325
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
+
273
349
// Check previously confirmed transactions are marked unconfirmed when they are reorged.
274
350
let best_block_hash = bitcoind. client . get_best_block_hash ( ) . unwrap ( ) ;
275
351
bitcoind. client . invalidate_block ( & best_block_hash) . unwrap ( ) ;
@@ -286,30 +362,52 @@ async fn test_esplora_syncs() {
286
362
assert_ne ! ( bitcoind. client. get_best_block_hash( ) . unwrap( ) , best_block_hash) ;
287
363
tx_sync. sync ( vec ! [ & confirmable] ) . await . unwrap ( ) ;
288
364
289
- // Transaction still confirmed but under new tip.
365
+ // Transactions still confirmed but under new tip.
290
366
assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & txid) ) ;
367
+ assert ! ( confirmable. confirmed_txs. lock( ) . unwrap( ) . contains_key( & second_txid) ) ;
291
368
assert ! ( confirmable. unconfirmed_txs. lock( ) . unwrap( ) . is_empty( ) ) ;
292
369
293
370
// Check we got unconfirmed, then reconfirmed in the meantime.
371
+ let mut seen_txids = HashSet :: new ( ) ;
294
372
let events = std:: mem:: take ( & mut * confirmable. events . lock ( ) . unwrap ( ) ) ;
295
- assert_eq ! ( events. len( ) , 3 ) ;
373
+ assert_eq ! ( events. len( ) , 5 ) ;
296
374
297
375
match events[ 0 ] {
298
376
TestConfirmableEvent :: Unconfirmed ( t) => {
299
- assert_eq ! ( t, txid) ;
377
+ assert ! ( t == txid || t == second_txid) ;
378
+ assert ! ( seen_txids. insert( t) ) ;
300
379
} ,
301
380
_ => panic ! ( "Unexpected event" ) ,
302
381
}
303
382
304
383
match events[ 1 ] {
305
- TestConfirmableEvent :: BestBlockUpdated ( ..) => { } ,
384
+ TestConfirmableEvent :: Unconfirmed ( t) => {
385
+ assert ! ( t == txid || t == second_txid) ;
386
+ assert ! ( seen_txids. insert( t) ) ;
387
+ } ,
306
388
_ => panic ! ( "Unexpected event" ) ,
307
389
}
308
390
309
391
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 ] {
310
405
TestConfirmableEvent :: Confirmed ( t, _, _) => {
311
- assert_eq ! ( t, txid) ;
406
+ assert ! ( t == txid || t == second_txid) ;
407
+ assert ! ( seen_txids. remove( & t) ) ;
312
408
} ,
313
409
_ => panic ! ( "Unexpected event" ) ,
314
410
}
411
+
412
+ assert_eq ! ( seen_txids. len( ) , 0 ) ;
315
413
}
0 commit comments