10
10
//! Further functional tests which test blockchain reorganizations.
11
11
12
12
use chain:: channelmonitor:: { ANTI_REORG_DELAY , ChannelMonitor } ;
13
+ use chain:: transaction:: OutPoint ;
13
14
use chain:: { Confirm , Watch } ;
14
15
use ln:: channelmanager:: { ChannelManager , ChannelManagerReadArgs } ;
15
16
use ln:: features:: InitFeatures ;
@@ -20,7 +21,10 @@ use util::test_utils;
20
21
use util:: ser:: { ReadableArgs , Writeable } ;
21
22
22
23
use bitcoin:: blockdata:: block:: { Block , BlockHeader } ;
24
+ use bitcoin:: blockdata:: script:: Builder ;
25
+ use bitcoin:: blockdata:: opcodes;
23
26
use bitcoin:: hash_types:: BlockHash ;
27
+ use bitcoin:: secp256k1:: Secp256k1 ;
24
28
25
29
use prelude:: * ;
26
30
use core:: mem;
@@ -427,3 +431,112 @@ fn test_set_outpoints_partial_claiming() {
427
431
node_txn. clear ( ) ;
428
432
}
429
433
}
434
+
435
+ fn do_test_to_remote_after_local_detection ( style : ConnectStyle ) {
436
+ // In previous code, detection of to_remote outputs in a counterparty commitment transaction
437
+ // was dependent on whether a local commitment transaction had been seen on-chain previously.
438
+ // This resulted in some edge cases around not being able to generate a SpendableOutput event
439
+ // after a reorg.
440
+ //
441
+ // Here, we test this by first confirming one set of commitment transactions, then
442
+ // disconnecting them and reconnecting another. We then confirm them and check that the correct
443
+ // SpendableOutput event is generated.
444
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
445
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
446
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
447
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
448
+
449
+ * nodes[ 0 ] . connect_style . borrow_mut ( ) = style;
450
+ * nodes[ 1 ] . connect_style . borrow_mut ( ) = style;
451
+
452
+ let ( _, _, chan_id, funding_tx) =
453
+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 100_000_000 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
454
+ let funding_outpoint = OutPoint { txid : funding_tx. txid ( ) , index : 0 } ;
455
+ assert_eq ! ( funding_outpoint. to_channel_id( ) , chan_id) ;
456
+
457
+ let remote_txn_a = get_local_commitment_txn ! ( nodes[ 0 ] , chan_id) ;
458
+ let remote_txn_b = get_local_commitment_txn ! ( nodes[ 1 ] , chan_id) ;
459
+
460
+ mine_transaction ( & nodes[ 0 ] , & remote_txn_a[ 0 ] ) ;
461
+ mine_transaction ( & nodes[ 1 ] , & remote_txn_a[ 0 ] ) ;
462
+
463
+ assert ! ( nodes[ 0 ] . node. list_channels( ) . is_empty( ) ) ;
464
+ check_closed_broadcast ! ( nodes[ 0 ] , true ) ;
465
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
466
+ assert ! ( nodes[ 1 ] . node. list_channels( ) . is_empty( ) ) ;
467
+ check_closed_broadcast ! ( nodes[ 1 ] , true ) ;
468
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
469
+
470
+ // Drop transactions broadcasted in response to the first commitment transaction (we have good
471
+ // test coverage of these things already elsewhere).
472
+ assert_eq ! ( nodes[ 0 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . split_off( 0 ) . len( ) , 1 ) ;
473
+ assert_eq ! ( nodes[ 1 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . split_off( 0 ) . len( ) , 1 ) ;
474
+
475
+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
476
+ assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
477
+
478
+ disconnect_blocks ( & nodes[ 0 ] , 1 ) ;
479
+ disconnect_blocks ( & nodes[ 1 ] , 1 ) ;
480
+
481
+ assert ! ( nodes[ 0 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
482
+ assert ! ( nodes[ 1 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
483
+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
484
+ assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
485
+
486
+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
487
+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
488
+
489
+ assert ! ( nodes[ 0 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
490
+ assert ! ( nodes[ 1 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
491
+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
492
+ assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
493
+
494
+ mine_transaction ( & nodes[ 0 ] , & remote_txn_b[ 0 ] ) ;
495
+ mine_transaction ( & nodes[ 1 ] , & remote_txn_b[ 0 ] ) ;
496
+
497
+ assert ! ( nodes[ 0 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
498
+ assert ! ( nodes[ 1 ] . tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) . is_empty( ) ) ;
499
+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
500
+ assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
501
+
502
+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
503
+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
504
+
505
+ let mut node_a_spendable = nodes[ 0 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
506
+ assert_eq ! ( node_a_spendable. len( ) , 1 ) ;
507
+ if let Event :: SpendableOutputs { outputs } = node_a_spendable. pop ( ) . unwrap ( ) {
508
+ assert_eq ! ( outputs. len( ) , 1 ) ;
509
+ let spend_tx = nodes[ 0 ] . keys_manager . backing . spend_spendable_outputs ( & [ & outputs[ 0 ] ] , Vec :: new ( ) ,
510
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) , 253 , & Secp256k1 :: new ( ) ) . unwrap ( ) ;
511
+ check_spends ! ( spend_tx, remote_txn_b[ 0 ] ) ;
512
+ }
513
+
514
+ // nodes[1] is waiting for the to_self_delay to expire, which is many more than
515
+ // ANTI_REORG_DELAY. Instead, walk it back and confirm the original remote_txn_a commitment
516
+ // again and check that nodes[1] generates a similar spendable output.
517
+ // Technically a reorg of ANTI_REORG_DELAY violates our assumptions, so this is undefined by
518
+ // our API spec, but we currently handle this correctly and there's little reason we shouldn't
519
+ // in the future.
520
+ assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
521
+ disconnect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY ) ;
522
+ mine_transaction ( & nodes[ 1 ] , & remote_txn_a[ 0 ] ) ;
523
+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
524
+
525
+ let mut node_b_spendable = nodes[ 1 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
526
+ assert_eq ! ( node_b_spendable. len( ) , 1 ) ;
527
+ if let Event :: SpendableOutputs { outputs } = node_b_spendable. pop ( ) . unwrap ( ) {
528
+ assert_eq ! ( outputs. len( ) , 1 ) ;
529
+ let spend_tx = nodes[ 1 ] . keys_manager . backing . spend_spendable_outputs ( & [ & outputs[ 0 ] ] , Vec :: new ( ) ,
530
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) , 253 , & Secp256k1 :: new ( ) ) . unwrap ( ) ;
531
+ check_spends ! ( spend_tx, remote_txn_a[ 0 ] ) ;
532
+ }
533
+ }
534
+
535
+ #[ test]
536
+ fn test_to_remote_after_local_detection ( ) {
537
+ do_test_to_remote_after_local_detection ( ConnectStyle :: BestBlockFirst ) ;
538
+ do_test_to_remote_after_local_detection ( ConnectStyle :: BestBlockFirstSkippingBlocks ) ;
539
+ do_test_to_remote_after_local_detection ( ConnectStyle :: TransactionsFirst ) ;
540
+ do_test_to_remote_after_local_detection ( ConnectStyle :: TransactionsFirstSkippingBlocks ) ;
541
+ do_test_to_remote_after_local_detection ( ConnectStyle :: FullBlockViaListen ) ;
542
+ }
0 commit comments