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