@@ -72,15 +72,7 @@ impl LipaChainAccess {
72
72
debug ! ( "{} confirmed transactions" , confirmed_txs. len( ) ) ;
73
73
debug ! ( "Confirmed transaction list: {:?}" , confirmed_txs) ;
74
74
75
- // Sort all confirmed transactions by block height and feed them to the interface
76
- // in order.
77
- confirmed_txs. sort_unstable_by ( |( _, block_height1, _, _) , ( _, block_height2, _, _) | {
78
- block_height1. cmp ( block_height2)
79
- } ) ;
80
-
81
- // todo also sort within block
82
- // From the Confirm trait documentation:
83
- // Dependent transactions within the same block must be given in topological order, possibly in separate calls
75
+ sort_txs ( & mut confirmed_txs) ;
84
76
85
77
for ( tx, block_height, block_header, pos) in confirmed_txs {
86
78
for c in & confirmables {
@@ -368,6 +360,16 @@ impl LipaChainAccess {
368
360
}
369
361
}
370
362
363
+ // Sorting by blocks and by transaction position within the each block
364
+ // From the Confirm trait documentation:
365
+ // - Transactions confirmed in a block must be given before transactions confirmed in a later
366
+ // block.
367
+ // - Dependent transactions within the same block must be given in topological order, possibly in
368
+ // separate calls.
369
+ fn sort_txs ( txs : & mut [ ( Transaction , u32 , BlockHeader , usize ) ] ) {
370
+ txs. sort_unstable_by_key ( |tx| ( tx. 1 , tx. 3 ) ) ;
371
+ }
372
+
371
373
impl Filter for LipaChainAccess {
372
374
fn register_tx ( & self , txid : & Txid , script_pubkey : & Script ) {
373
375
self . queued_txs
@@ -388,10 +390,11 @@ impl Filter for LipaChainAccess {
388
390
389
391
#[ cfg( test) ]
390
392
mod tests {
393
+ use crate :: chain_access:: sort_txs;
391
394
use crate :: LipaChainAccess ;
392
395
use bitcoin:: consensus:: deserialize;
393
396
use bitcoin:: hashes:: hex:: FromHex ;
394
- use bitcoin:: Transaction ;
397
+ use bitcoin:: { BlockHeader , Transaction } ;
395
398
use esplora_client:: Builder ;
396
399
use lightning:: chain:: transaction:: OutPoint ;
397
400
use lightning:: chain:: { Filter , WatchedOutput } ;
@@ -417,6 +420,17 @@ mod tests {
417
420
tx. unwrap ( )
418
421
}
419
422
423
+ fn build_default_block_header ( ) -> BlockHeader {
424
+ BlockHeader {
425
+ version : 0 ,
426
+ prev_blockhash : Default :: default ( ) ,
427
+ merkle_root : Default :: default ( ) ,
428
+ time : 0 ,
429
+ bits : 0 ,
430
+ nonce : 0 ,
431
+ }
432
+ }
433
+
420
434
#[ test]
421
435
fn filter_is_initialised_empty ( ) {
422
436
let filter = build_filter ( ) ;
@@ -480,4 +494,49 @@ mod tests {
480
494
assert_eq ! ( filter_output. outpoint, output. outpoint) ;
481
495
assert_eq ! ( filter_output. block_hash, output. block_hash) ;
482
496
}
497
+
498
+ #[ test]
499
+ fn txs_are_sorted_by_block_and_position_within_block ( ) {
500
+ let mut txs = vec ! [
501
+ (
502
+ build_sample_tx( ) ,
503
+ 10 , // block height
504
+ build_default_block_header( ) ,
505
+ 10 , // position within block
506
+ ) ,
507
+ (
508
+ build_sample_tx( ) ,
509
+ 5 , // block height
510
+ build_default_block_header( ) ,
511
+ 5 , // position within block
512
+ ) ,
513
+ (
514
+ build_sample_tx( ) ,
515
+ 10 , // block height
516
+ build_default_block_header( ) ,
517
+ 5 , // position within block
518
+ ) ,
519
+ (
520
+ build_sample_tx( ) ,
521
+ 5 , // block height
522
+ build_default_block_header( ) ,
523
+ 10 , // position within block
524
+ ) ,
525
+ ] ;
526
+
527
+ let unsorted: Vec < ( u32 , usize ) > = txs
528
+ . iter ( )
529
+ . map ( |( _, block_height, _, pos_within_block) | ( * block_height, * pos_within_block) )
530
+ . collect ( ) ;
531
+
532
+ sort_txs ( & mut txs) ;
533
+
534
+ let sorted: Vec < ( u32 , usize ) > = txs
535
+ . iter ( )
536
+ . map ( |( _, block_height, _, pos_within_block) | ( * block_height, * pos_within_block) )
537
+ . collect ( ) ;
538
+
539
+ assert_eq ! ( unsorted, vec![ ( 10 , 10 ) , ( 5 , 5 ) , ( 10 , 5 ) , ( 5 , 10 ) ] ) ;
540
+ assert_eq ! ( sorted, vec![ ( 5 , 5 ) , ( 5 , 10 ) , ( 10 , 5 ) , ( 10 , 10 ) ] ) ;
541
+ }
483
542
}
0 commit comments