@@ -369,11 +369,6 @@ impl PendingChecks {
369369 if latest_announce. is_none ( ) ||
370370 latest_announce. as_ref ( ) . unwrap ( ) . timestamp ( ) < msg. timestamp
371371 {
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.
377372 * latest_announce = Some (
378373 if let Some ( msg) = full_msg { NodeAnnouncement :: Full ( msg. clone ( ) ) }
379374 else { NodeAnnouncement :: Unsigned ( msg. clone ( ) ) } ) ;
@@ -559,3 +554,309 @@ impl PendingChecks {
559554 }
560555 }
561556}
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