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