@@ -6234,49 +6234,56 @@ func TestPreferHighestAndGetVersions(t *testing.T) {
62346234 return
62356235 }
62366236
6237- // Add v2 node announcements for the same pubkeys so we can create a
6238- // versioned duplicate of the channel in the SQL store.
62396237 node1V2 := createNode (t , lnwire .GossipVersion2 , node1Priv )
62406238 node2V2 := createNode (t , lnwire .GossipVersion2 , node2Priv )
6241-
62426239 require .NoError (t , graph .AddNode (ctx , node1V2 ))
62436240 require .NoError (t , graph .AddNode (ctx , node2V2 ))
62446241
6245- // Add a v2 copy of the same channel so the prefer-highest queries can
6246- // choose between both versions for the same SCID/outpoint.
6247- edgeInfoV2 , _ := createEdge (
6248- lnwire .GossipVersion2 , 100 , 1 , 0 , 1 , node1V2 , node2V2 ,
6242+ // Add a duplicate v1/v2 channel and verify prefer-highest chooses
6243+ // the v2 edge while GetVersions reports both versions.
6244+ dupV1 , dupSCID := createEdge (
6245+ lnwire .GossipVersion1 , 101 , 1 , 0 , 2 , node1V1 , node2V1 ,
6246+ )
6247+ dupV2 , _ := createEdge (
6248+ lnwire .GossipVersion2 , 101 , 1 , 0 , 2 , node1V2 , node2V2 ,
62496249 )
6250- require .NoError (t , graph .AddChannelEdge (ctx , edgeInfoV2 ))
6250+ require .NoError (t , graph .AddChannelEdge (ctx , dupV1 ))
6251+ require .NoError (t , graph .AddChannelEdge (ctx , dupV2 ))
6252+
6253+ dupChanID := dupSCID .ToUint64 ()
6254+ dupOutpoint := dupV1 .ChannelPoint
62516255
6252- versions , err = store .GetVersionsBySCID (ctx , chanID )
6256+ info , _ , _ , err = store .FetchChannelEdgesByIDPreferHighest (
6257+ ctx , dupChanID ,
6258+ )
6259+ require .NoError (t , err )
6260+ require .Equal (t , dupChanID , info .ChannelID )
6261+ require .Equal (t , lnwire .GossipVersion2 , info .Version )
6262+
6263+ info , _ , _ , err = store .FetchChannelEdgesByOutpointPreferHighest (
6264+ ctx , & dupOutpoint ,
6265+ )
6266+ require .NoError (t , err )
6267+ require .Equal (t , dupChanID , info .ChannelID )
6268+ require .Equal (t , lnwire .GossipVersion2 , info .Version )
6269+
6270+ versions , err = store .GetVersionsBySCID (ctx , dupChanID )
62536271 require .NoError (t , err )
62546272 require .Equal (t , []lnwire.GossipVersion {
62556273 lnwire .GossipVersion1 ,
62566274 lnwire .GossipVersion2 ,
62576275 }, versions )
62586276
6259- versions , err = store .GetVersionsByOutpoint (ctx , & op )
6277+ versions , err = store .GetVersionsByOutpoint (ctx , & dupOutpoint )
62606278 require .NoError (t , err )
62616279 require .Equal (t , []lnwire.GossipVersion {
62626280 lnwire .GossipVersion1 ,
62636281 lnwire .GossipVersion2 ,
62646282 }, versions )
6265-
6266- // With no policies present for either version, prefer-highest should
6267- // fall back to the higher gossip version.
6268- info , _ , _ , err = store .FetchChannelEdgesByIDPreferHighest (ctx , chanID )
6269- require .NoError (t , err )
6270- require .Equal (t , lnwire .GossipVersion2 , info .Version )
6271-
6272- info , _ , _ , err = store .FetchChannelEdgesByOutpointPreferHighest (
6273- ctx , & op ,
6274- )
6275- require .NoError (t , err )
6276- require .Equal (t , lnwire .GossipVersion2 , info .Version )
62776283}
6278- // TestPreferHighestNodeTraversal verifies the no-cache traversal behavior of
6279- // ChannelGraph's ForEachNodeDirectedChannel and FetchNodeFeatures.
6284+ // TestPreferHighestNodeTraversal verifies that ChannelGraph's
6285+ // ForEachNodeDirectedChannel and FetchNodeFeatures correctly prefer v2 over v1
6286+ // when the graph cache is disabled (exercising the no-cache code paths).
62806287func TestPreferHighestNodeTraversal (t * testing.T ) {
62816288 t .Parallel ()
62826289
@@ -6314,33 +6321,35 @@ func TestPreferHighestNodeTraversal(t *testing.T) {
63146321
63156322 features , err = graph .FetchNodeFeatures (ctx , nodeV2 .PubKeyBytes )
63166323 require .NoError (t , err )
6317- require .Empty (t , features .Features (),
6318- "no-cache traversal still uses the v1 feature lookup path " )
6324+ require .False (t , features .IsEmpty (),
6325+ "v2-only node should have features " )
63196326
63206327 // Create a node with both v1 and v2 announcements.
63216328 privBoth , err := btcec .NewPrivateKey ()
63226329 require .NoError (t , err )
63236330
63246331 nodeBothV1 := createNode (t , lnwire .GossipVersion1 , privBoth )
6325- nodeBothV1 . Features = lnwire .NewFeatureVector (
6332+ v1Features : = lnwire .NewFeatureVector (
63266333 lnwire .NewRawFeatureVector (lnwire .GossipQueriesRequired ),
63276334 lnwire .Features ,
63286335 )
6336+ nodeBothV1 .Features = v1Features
63296337 require .NoError (t , graph .AddNode (ctx , nodeBothV1 ))
63306338
63316339 nodeBothV2 := createNode (t , lnwire .GossipVersion2 , privBoth )
6332- nodeBothV2 . Features = lnwire .NewFeatureVector (
6333- lnwire .NewRawFeatureVector (lnwire .DataLossProtectRequired ),
6340+ v2Features : = lnwire .NewFeatureVector (
6341+ lnwire .NewRawFeatureVector (lnwire .TLVOnionPayloadRequired ),
63346342 lnwire .Features ,
63356343 )
6344+ nodeBothV2 .Features = v2Features
63366345 require .NoError (t , graph .AddNode (ctx , nodeBothV2 ))
63376346
63386347 features , err = graph .FetchNodeFeatures (
63396348 ctx , nodeBothV1 .PubKeyBytes ,
63406349 )
63416350 require .NoError (t , err )
6342- require .Equal (t , nodeBothV1 . Features , features ,
6343- "no-cache feature lookup should return the v1 features" )
6351+ require .Equal (t , v2Features , features )
6352+ require . NotEqual ( t , v1Features , features )
63446353
63456354 // --- ForEachNodeDirectedChannel ---
63466355
@@ -6569,3 +6578,97 @@ func TestPreferHighestForEachChannel(t *testing.T) {
65696578 require .Nil (t , gotShellPref .p1 )
65706579 require .Nil (t , gotShellPref .p2 )
65716580}
6581+
6582+ // TestPreferHighestNodeDirectedChannelTraversal verifies that the no-cache
6583+ // ChannelGraph.ForEachNodeDirectedChannel path streams one directed channel per
6584+ // SCID while preferring the v2 advertisement when both versions exist.
6585+ func TestPreferHighestNodeDirectedChannelTraversal (t * testing.T ) {
6586+ t .Parallel ()
6587+
6588+ if ! isSQLDB {
6589+ t .Skip ("prefer-highest requires SQL backend" )
6590+ }
6591+
6592+ ctx := t .Context ()
6593+ graph := MakeTestGraph (t , WithUseGraphCache (false ))
6594+
6595+ localPriv , err := btcec .NewPrivateKey ()
6596+ require .NoError (t , err )
6597+ peerBothPriv , err := btcec .NewPrivateKey ()
6598+ require .NoError (t , err )
6599+ peerV1OnlyPriv , err := btcec .NewPrivateKey ()
6600+ require .NoError (t , err )
6601+
6602+ localV1 := createNode (t , lnwire .GossipVersion1 , localPriv )
6603+ localV2 := createNode (t , lnwire .GossipVersion2 , localPriv )
6604+ peerBothV1 := createNode (t , lnwire .GossipVersion1 , peerBothPriv )
6605+ peerBothV2 := createNode (t , lnwire .GossipVersion2 , peerBothPriv )
6606+ peerV1Only := createNode (t , lnwire .GossipVersion1 , peerV1OnlyPriv )
6607+
6608+ require .NoError (t , graph .AddNode (ctx , localV1 ))
6609+ require .NoError (t , graph .AddNode (ctx , localV2 ))
6610+ require .NoError (t , graph .AddNode (ctx , peerBothV1 ))
6611+ require .NoError (t , graph .AddNode (ctx , peerBothV2 ))
6612+ require .NoError (t , graph .AddNode (ctx , peerV1Only ))
6613+
6614+ dupV1 , _ := createEdge (
6615+ lnwire .GossipVersion1 , 400 , 0 , 0 , 10 , localV1 , peerBothV1 ,
6616+ )
6617+ dupV2 , _ := createEdge (
6618+ lnwire .GossipVersion2 , 400 , 0 , 0 , 10 , localV2 , peerBothV2 ,
6619+ )
6620+ v1Only , _ := createEdge (
6621+ lnwire .GossipVersion1 , 401 , 0 , 0 , 11 , localV1 , peerV1Only ,
6622+ )
6623+
6624+ require .NoError (t , graph .AddChannelEdge (ctx , dupV1 ))
6625+ require .NoError (t , graph .AddChannelEdge (ctx , dupV2 ))
6626+ require .NoError (t , graph .AddChannelEdge (ctx , v1Only ))
6627+
6628+ addPolicies := func (edgeInfo * models.ChannelEdgeInfo ,
6629+ version lnwire.GossipVersion ,
6630+ fee lnwire.MilliSatoshi ) {
6631+
6632+ policy1 := newEdgePolicy (version , edgeInfo .ChannelID , 1000 , true )
6633+ policy1 .ToNode = edgeInfo .NodeKey2Bytes
6634+ policy1 .SigBytes = testSig .Serialize ()
6635+ policy1 .FeeBaseMSat = fee
6636+
6637+ policy2 := newEdgePolicy (version , edgeInfo .ChannelID , 1001 , false )
6638+ policy2 .ToNode = edgeInfo .NodeKey1Bytes
6639+ policy2 .SigBytes = testSig .Serialize ()
6640+ policy2 .FeeBaseMSat = fee
6641+
6642+ require .NoError (t , graph .UpdateEdgePolicy (ctx , policy1 ))
6643+ require .NoError (t , graph .UpdateEdgePolicy (ctx , policy2 ))
6644+ }
6645+
6646+ addPolicies (dupV1 , lnwire .GossipVersion1 , 1111 )
6647+ addPolicies (dupV2 , lnwire .GossipVersion2 , 2222 )
6648+ addPolicies (v1Only , lnwire .GossipVersion1 , 3333 )
6649+
6650+ channelsByID := make (map [uint64 ]* DirectedChannel )
6651+ err = graph .ForEachNodeDirectedChannel (
6652+ ctx , localV1 .PubKeyBytes ,
6653+ func (channel * DirectedChannel ) error {
6654+ channelsByID [channel .ChannelID ] = channel .DeepCopy ()
6655+ return nil
6656+ }, func () {
6657+ clear (channelsByID )
6658+ },
6659+ )
6660+ require .NoError (t , err )
6661+ require .Len (t , channelsByID , 2 )
6662+
6663+ gotDup := channelsByID [dupV1 .ChannelID ]
6664+ require .NotNil (t , gotDup )
6665+ require .NotNil (t , gotDup .InPolicy )
6666+ require .Equal (t , lnwire .MilliSatoshi (2222 ), gotDup .InPolicy .FeeBaseMSat )
6667+
6668+ gotV1Only := channelsByID [v1Only .ChannelID ]
6669+ require .NotNil (t , gotV1Only )
6670+ require .NotNil (t , gotV1Only .InPolicy )
6671+ require .Equal (
6672+ t , lnwire .MilliSatoshi (3333 ), gotV1Only .InPolicy .FeeBaseMSat ,
6673+ )
6674+ }
0 commit comments