@@ -359,11 +359,6 @@ impl PendingChecks {
359
359
if latest_announce. is_none ( ) ||
360
360
latest_announce. as_ref ( ) . unwrap ( ) . timestamp ( ) < msg. timestamp
361
361
{
362
- // If the messages we got has a higher timestamp, just blindly
363
- // assume the signatures on the new message are correct and drop
364
- // the old message. This may cause us to end up dropping valid
365
- // `node_announcement`s if a peer is malicious, but we should get
366
- // the correct ones when the node updates them.
367
362
* latest_announce = Some (
368
363
if let Some ( msg) = full_msg { NodeAnnouncement :: Full ( msg. clone ( ) ) }
369
364
else { NodeAnnouncement :: Unsigned ( msg. clone ( ) ) } ) ;
@@ -541,3 +536,313 @@ impl PendingChecks {
541
536
}
542
537
}
543
538
}
539
+
540
+ #[ cfg( test) ]
541
+ mod tests {
542
+ use super :: * ;
543
+ use crate :: routing:: gossip:: tests:: * ;
544
+ use crate :: util:: test_utils:: { TestChainSource , TestLogger } ;
545
+ use crate :: ln:: msgs;
546
+
547
+ use bitcoin:: blockdata:: constants:: genesis_block;
548
+ use bitcoin:: secp256k1:: { Secp256k1 , SecretKey } ;
549
+
550
+ use core:: sync:: atomic:: Ordering ;
551
+
552
+ fn get_network ( ) -> ( TestChainSource , NetworkGraph < Box < TestLogger > > ) {
553
+ let logger = Box :: new ( TestLogger :: new ( ) ) ;
554
+ let genesis_hash = genesis_block ( bitcoin:: Network :: Testnet ) . header . block_hash ( ) ;
555
+ let chain_source = TestChainSource :: new ( bitcoin:: Network :: Testnet ) ;
556
+ let network_graph = NetworkGraph :: new ( genesis_hash, logger) ;
557
+
558
+ ( chain_source, network_graph)
559
+ }
560
+
561
+ fn get_test_objects ( ) -> ( msgs:: ChannelAnnouncement , TestChainSource ,
562
+ NetworkGraph < Box < TestLogger > > , bitcoin:: Script , msgs:: NodeAnnouncement ,
563
+ msgs:: NodeAnnouncement , msgs:: ChannelUpdate , msgs:: ChannelUpdate , msgs:: ChannelUpdate )
564
+ {
565
+ let secp_ctx = Secp256k1 :: new ( ) ;
566
+
567
+ let ( chain_source, network_graph) = get_network ( ) ;
568
+
569
+ let good_script = get_channel_script ( & secp_ctx) ;
570
+ let node_1_privkey = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
571
+ let node_2_privkey = & SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
572
+ let valid_announcement = get_signed_channel_announcement ( |_| { } , node_1_privkey, node_2_privkey, & secp_ctx) ;
573
+
574
+ let node_a_announce = get_signed_node_announcement ( |_| { } , node_1_privkey, & secp_ctx) ;
575
+ let node_b_announce = get_signed_node_announcement ( |_| { } , node_2_privkey, & secp_ctx) ;
576
+
577
+ // Note that we have to set the "direction" flag correctly on both messages
578
+ let chan_update_a = get_signed_channel_update ( |msg| msg. flags = 0 , node_1_privkey, & secp_ctx) ;
579
+ let chan_update_b = get_signed_channel_update ( |msg| msg. flags = 1 , node_2_privkey, & secp_ctx) ;
580
+ let chan_update_c = get_signed_channel_update ( |msg| {
581
+ msg. flags = 1 ; msg. timestamp += 1 ; } , node_2_privkey, & secp_ctx) ;
582
+
583
+ ( valid_announcement, chain_source, network_graph, good_script, node_a_announce,
584
+ node_b_announce, chan_update_a, chan_update_b, chan_update_c)
585
+ }
586
+
587
+ #[ test]
588
+ fn test_fast_async_lookup ( ) {
589
+ // Check that async lookups which resolve quicker than the future is returned to the
590
+ // `get_utxo` call can read it still resolve properly.
591
+ let ( valid_announcement, chain_source, network_graph, good_script, ..) = get_test_objects ( ) ;
592
+
593
+ let future = AccessFuture :: new ( ) ;
594
+ future. resolve_without_forwarding ( & network_graph,
595
+ Ok ( TxOut { value : 1_000_000 , script_pubkey : good_script } ) ) ;
596
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
597
+
598
+ network_graph. update_channel_from_announcement ( & valid_announcement, & Some ( & chain_source) ) . unwrap ( ) ;
599
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_some( ) ) ;
600
+ }
601
+
602
+ #[ test]
603
+ fn test_async_lookup ( ) {
604
+ // Test a simple async lookup
605
+ let ( valid_announcement, chain_source, network_graph, good_script,
606
+ node_a_announce, node_b_announce, ..) = get_test_objects ( ) ;
607
+
608
+ let future = AccessFuture :: new ( ) ;
609
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
610
+
611
+ assert_eq ! (
612
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
613
+ "Channel being checked async" ) ;
614
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
615
+
616
+ future. resolve_without_forwarding ( & network_graph,
617
+ Ok ( TxOut { value : 0 , script_pubkey : good_script } ) ) ;
618
+ network_graph. read_only ( ) . channels ( ) . get ( & valid_announcement. contents . short_channel_id ) . unwrap ( ) ;
619
+ network_graph. read_only ( ) . channels ( ) . get ( & valid_announcement. contents . short_channel_id ) . unwrap ( ) ;
620
+
621
+ assert ! ( network_graph. read_only( ) . nodes( )
622
+ . get( & NodeId :: from_pubkey( & valid_announcement. contents. node_id_1) ) . unwrap( )
623
+ . announcement_info. is_none( ) ) ;
624
+
625
+ network_graph. update_node_from_announcement ( & node_a_announce) . unwrap ( ) ;
626
+ network_graph. update_node_from_announcement ( & node_b_announce) . unwrap ( ) ;
627
+
628
+ assert ! ( network_graph. read_only( ) . nodes( )
629
+ . get( & NodeId :: from_pubkey( & valid_announcement. contents. node_id_1) ) . unwrap( )
630
+ . announcement_info. is_some( ) ) ;
631
+ }
632
+
633
+ #[ test]
634
+ fn test_invalid_async_lookup ( ) {
635
+ // Test an async lookup which returns an incorrect script
636
+ let ( valid_announcement, chain_source, network_graph, ..) = get_test_objects ( ) ;
637
+
638
+ let future = AccessFuture :: new ( ) ;
639
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
640
+
641
+ assert_eq ! (
642
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
643
+ "Channel being checked async" ) ;
644
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
645
+
646
+ future. resolve_without_forwarding ( & network_graph,
647
+ Ok ( TxOut { value : 1_000_000 , script_pubkey : bitcoin:: Script :: new ( ) } ) ) ;
648
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
649
+ }
650
+
651
+ #[ test]
652
+ fn test_failing_async_lookup ( ) {
653
+ // Test an async lookup which returns an error
654
+ let ( valid_announcement, chain_source, network_graph, ..) = get_test_objects ( ) ;
655
+
656
+ let future = AccessFuture :: new ( ) ;
657
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
658
+
659
+ assert_eq ! (
660
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
661
+ "Channel being checked async" ) ;
662
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
663
+
664
+ future. resolve_without_forwarding ( & network_graph, Err ( ChainAccessError :: UnknownTx ) ) ;
665
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
666
+ }
667
+
668
+ #[ test]
669
+ fn test_updates_async_lookup ( ) {
670
+ // Test async lookups will process pending channel_update/node_announcements once they
671
+ // complete.
672
+ let ( valid_announcement, chain_source, network_graph, good_script, node_a_announce,
673
+ node_b_announce, chan_update_a, chan_update_b, ..) = get_test_objects ( ) ;
674
+
675
+ let future = AccessFuture :: new ( ) ;
676
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
677
+
678
+ assert_eq ! (
679
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
680
+ "Channel being checked async" ) ;
681
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
682
+
683
+ assert_eq ! (
684
+ network_graph. update_node_from_announcement( & node_a_announce) . unwrap_err( ) . err,
685
+ "Awaiting channel_announcement validation to accept node_announcement" ) ;
686
+ assert_eq ! (
687
+ network_graph. update_node_from_announcement( & node_b_announce) . unwrap_err( ) . err,
688
+ "Awaiting channel_announcement validation to accept node_announcement" ) ;
689
+
690
+ assert_eq ! ( network_graph. update_channel( & chan_update_a) . unwrap_err( ) . err,
691
+ "Awaiting channel_announcement validation to accept channel_update" ) ;
692
+ assert_eq ! ( network_graph. update_channel( & chan_update_b) . unwrap_err( ) . err,
693
+ "Awaiting channel_announcement validation to accept channel_update" ) ;
694
+
695
+ future. resolve_without_forwarding ( & network_graph,
696
+ Ok ( TxOut { value : 1_000_000 , script_pubkey : good_script } ) ) ;
697
+
698
+ assert ! ( network_graph. read_only( ) . channels( )
699
+ . get( & valid_announcement. contents. short_channel_id) . unwrap( ) . one_to_two. is_some( ) ) ;
700
+ assert ! ( network_graph. read_only( ) . channels( )
701
+ . get( & valid_announcement. contents. short_channel_id) . unwrap( ) . two_to_one. is_some( ) ) ;
702
+
703
+ assert ! ( network_graph. read_only( ) . nodes( )
704
+ . get( & NodeId :: from_pubkey( & valid_announcement. contents. node_id_1) ) . unwrap( )
705
+ . announcement_info. is_some( ) ) ;
706
+ assert ! ( network_graph. read_only( ) . nodes( )
707
+ . get( & NodeId :: from_pubkey( & valid_announcement. contents. node_id_2) ) . unwrap( )
708
+ . announcement_info. is_some( ) ) ;
709
+ }
710
+
711
+ #[ test]
712
+ fn test_latest_update_async_lookup ( ) {
713
+ // Test async lookups will process the latest channel_update if two are received while
714
+ // awaiting an async UTXO lookup.
715
+ let ( valid_announcement, chain_source, network_graph, good_script, _,
716
+ _, chan_update_a, chan_update_b, chan_update_c, ..) = get_test_objects ( ) ;
717
+
718
+ let future = AccessFuture :: new ( ) ;
719
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
720
+
721
+ assert_eq ! (
722
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
723
+ "Channel being checked async" ) ;
724
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & valid_announcement. contents. short_channel_id) . is_none( ) ) ;
725
+
726
+ assert_eq ! ( network_graph. update_channel( & chan_update_a) . unwrap_err( ) . err,
727
+ "Awaiting channel_announcement validation to accept channel_update" ) ;
728
+ assert_eq ! ( network_graph. update_channel( & chan_update_b) . unwrap_err( ) . err,
729
+ "Awaiting channel_announcement validation to accept channel_update" ) ;
730
+ assert_eq ! ( network_graph. update_channel( & chan_update_c) . unwrap_err( ) . err,
731
+ "Awaiting channel_announcement validation to accept channel_update" ) ;
732
+
733
+ future. resolve_without_forwarding ( & network_graph,
734
+ Ok ( TxOut { value : 1_000_000 , script_pubkey : good_script } ) ) ;
735
+
736
+ assert_eq ! ( chan_update_a. contents. timestamp, chan_update_b. contents. timestamp) ;
737
+ assert ! ( network_graph. read_only( ) . channels( )
738
+ . get( & valid_announcement. contents. short_channel_id) . as_ref( ) . unwrap( )
739
+ . one_to_two. as_ref( ) . unwrap( ) . last_update !=
740
+ network_graph. read_only( ) . channels( )
741
+ . get( & valid_announcement. contents. short_channel_id) . as_ref( ) . unwrap( )
742
+ . two_to_one. as_ref( ) . unwrap( ) . last_update) ;
743
+ }
744
+
745
+ #[ test]
746
+ fn test_no_double_lookups ( ) {
747
+ // Test that a pending async lookup will prevent a second async lookup from flying, but
748
+ // only if the channel_announcement message is identical.
749
+ let ( valid_announcement, chain_source, network_graph, good_script, ..) = get_test_objects ( ) ;
750
+
751
+ let future = AccessFuture :: new ( ) ;
752
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
753
+
754
+ assert_eq ! (
755
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
756
+ "Channel being checked async" ) ;
757
+ assert_eq ! ( chain_source. get_utxo_call_count. load( Ordering :: Relaxed ) , 1 ) ;
758
+
759
+ // If we make a second request with the same message, the call count doesn't increase...
760
+ let future_b = AccessFuture :: new ( ) ;
761
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future_b. clone ( ) ) ;
762
+ assert_eq ! (
763
+ network_graph. update_channel_from_announcement( & valid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
764
+ "Channel announcement is already being checked" ) ;
765
+ assert_eq ! ( chain_source. get_utxo_call_count. load( Ordering :: Relaxed ) , 1 ) ;
766
+
767
+ // But if we make a third request with a tweaked message, we should get a second call
768
+ // against our new future...
769
+ let secp_ctx = Secp256k1 :: new ( ) ;
770
+ let replacement_pk_1 = & SecretKey :: from_slice ( & [ 99 ; 32 ] ) . unwrap ( ) ;
771
+ let replacement_pk_2 = & SecretKey :: from_slice ( & [ 98 ; 32 ] ) . unwrap ( ) ;
772
+ let invalid_announcement = get_signed_channel_announcement ( |_| { } , replacement_pk_1, replacement_pk_2, & secp_ctx) ;
773
+ assert_eq ! (
774
+ network_graph. update_channel_from_announcement( & invalid_announcement, & Some ( & chain_source) ) . unwrap_err( ) . err,
775
+ "Channel being checked async" ) ;
776
+ assert_eq ! ( chain_source. get_utxo_call_count. load( Ordering :: Relaxed ) , 2 ) ;
777
+
778
+ // Still, if we resolve the original future, the original channel will be accepted.
779
+ future. resolve_without_forwarding ( & network_graph,
780
+ Ok ( TxOut { value : 1_000_000 , script_pubkey : good_script } ) ) ;
781
+ assert ! ( !network_graph. read_only( ) . channels( )
782
+ . get( & valid_announcement. contents. short_channel_id) . unwrap( )
783
+ . announcement_message. as_ref( ) . unwrap( )
784
+ . contents. features. supports_unknown_test_feature( ) ) ;
785
+ }
786
+
787
+ #[ test]
788
+ fn test_checks_backpressure ( ) {
789
+ // Test that too_many_checks_pending returns true when there are many checks pending, and
790
+ // returns false once they complete.
791
+ let secp_ctx = Secp256k1 :: new ( ) ;
792
+ let ( chain_source, network_graph) = get_network ( ) ;
793
+
794
+ // We cheat and use a single future for all the lookups to complete them all at once.
795
+ let future = AccessFuture :: new ( ) ;
796
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( future. clone ( ) ) ;
797
+
798
+ let node_1_privkey = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
799
+ let node_2_privkey = & SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
800
+
801
+ for i in 0 ..PendingChecks :: MAX_PENDING_LOOKUPS {
802
+ let valid_announcement = get_signed_channel_announcement (
803
+ |msg| msg. short_channel_id += 1 + i as u64 , node_1_privkey, node_2_privkey, & secp_ctx) ;
804
+ network_graph. update_channel_from_announcement ( & valid_announcement, & Some ( & chain_source) ) . unwrap_err ( ) ;
805
+ assert ! ( !network_graph. pending_checks. too_many_checks_pending( ) ) ;
806
+ }
807
+
808
+ let valid_announcement = get_signed_channel_announcement (
809
+ |_| { } , node_1_privkey, node_2_privkey, & secp_ctx) ;
810
+ network_graph. update_channel_from_announcement ( & valid_announcement, & Some ( & chain_source) ) . unwrap_err ( ) ;
811
+ assert ! ( network_graph. pending_checks. too_many_checks_pending( ) ) ;
812
+
813
+ // Once the future completes the "too many checks" flag should reset.
814
+ future. resolve_without_forwarding ( & network_graph, Err ( ChainAccessError :: UnknownTx ) ) ;
815
+ assert ! ( !network_graph. pending_checks. too_many_checks_pending( ) ) ;
816
+ }
817
+
818
+ #[ test]
819
+ fn test_checks_backpressure_drop ( ) {
820
+ // Test that too_many_checks_pending returns true when there are many checks pending, and
821
+ // returns false if we drop some of the futures without completion.
822
+ let secp_ctx = Secp256k1 :: new ( ) ;
823
+ let ( chain_source, network_graph) = get_network ( ) ;
824
+
825
+ // We cheat and use a single future for all the lookups to complete them all at once.
826
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Async ( AccessFuture :: new ( ) ) ;
827
+
828
+ let node_1_privkey = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
829
+ let node_2_privkey = & SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
830
+
831
+ for i in 0 ..PendingChecks :: MAX_PENDING_LOOKUPS {
832
+ let valid_announcement = get_signed_channel_announcement (
833
+ |msg| msg. short_channel_id += 1 + i as u64 , node_1_privkey, node_2_privkey, & secp_ctx) ;
834
+ network_graph. update_channel_from_announcement ( & valid_announcement, & Some ( & chain_source) ) . unwrap_err ( ) ;
835
+ assert ! ( !network_graph. pending_checks. too_many_checks_pending( ) ) ;
836
+ }
837
+
838
+ let valid_announcement = get_signed_channel_announcement (
839
+ |_| { } , node_1_privkey, node_2_privkey, & secp_ctx) ;
840
+ network_graph. update_channel_from_announcement ( & valid_announcement, & Some ( & chain_source) ) . unwrap_err ( ) ;
841
+ assert ! ( network_graph. pending_checks. too_many_checks_pending( ) ) ;
842
+
843
+ // Once the future is drop'd (by resetting the `utxo_ret` value) the "too many checks" flag
844
+ // should reset to false.
845
+ * chain_source. utxo_ret . lock ( ) . unwrap ( ) = ChainAccessResult :: Sync ( Err ( ChainAccessError :: UnknownTx ) ) ;
846
+ assert ! ( !network_graph. pending_checks. too_many_checks_pending( ) ) ;
847
+ }
848
+ }
0 commit comments