diff --git a/lnd_test.go b/lnd_test.go index b4cc67a2..57fc0f34 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -870,7 +870,9 @@ func assertChannelPolicy(t *harnessTest, node *lntest.HarnessNode, advertisingNode string, expectedPolicy *lnrpc.RoutingPolicy, chanPoints ...*lnrpc.ChannelPoint) { - descReq := &lnrpc.ChannelGraphRequest{} + descReq := &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } chanGraph, err := node.DescribeGraph(context.Background(), descReq) if err != nil { t.Fatalf("unable to query for alice's graph: %v", err) @@ -1496,7 +1498,9 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) { } // Alice should now have 1 edge in her graph. - req := &lnrpc.ChannelGraphRequest{} + req := &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } chanGraph, err := net.Alice.DescribeGraph(ctxb, req) if err != nil { t.Fatalf("unable to query for alice's routing table: %v", err) @@ -1538,7 +1542,9 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) { // Since the fundingtx was reorged out, Alice should now have no edges // in her graph. - req = &lnrpc.ChannelGraphRequest{} + req = &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } chanGraph, err = net.Alice.DescribeGraph(ctxb, req) if err != nil { t.Fatalf("unable to query for alice's routing table: %v", err) @@ -4122,6 +4128,116 @@ func testSendToRouteErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false) } +// testUnannouncedChannels checks unannounced channels are not returned by +// describeGraph RPC request unless explicity asked for. +func testUnannouncedChannels(net *lntest.NetworkHarness, t *harnessTest) { + timeout := time.Duration(time.Second * 5) + ctb := context.Background() + amount := maxBtcFundingAmount + + // Open a channel between Alice and Bob, ensuring the + // channel has been opened properly. + ctx, _ := context.WithTimeout(ctb, timeout) + chanOpenUpdate, err := net.OpenChannel( + ctx, net.Alice, net.Bob, + lntest.OpenChannelParams{ + Amt: amount, + }, + ) + if err != nil { + t.Fatalf("unable to open channel: %v", err) + } + + // Mine 2 blocks, and check that the channel is opened but not yet + // announced to the network. + mineBlocks(t, net, 2) + + // One block is enough to make the channel ready for use, since the + // nodes have defaultNumConfs=1 set. + ctx, _ = context.WithTimeout(ctb, timeout) + fundingChanPoint, err := net.WaitForChannelOpen(ctx, chanOpenUpdate) + if err != nil { + t.Fatalf("error while waiting for channel open: %v", err) + } + + // Alice should have 1 edge in her graph. + req := &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } + ctx, _ = context.WithTimeout(ctb, timeout) + chanGraph, err := net.Alice.DescribeGraph(ctx, req) + if err != nil { + t.Fatalf("unable to query alice's graph: %v", err) + } + + numEdges := len(chanGraph.Edges) + if numEdges != 1 { + t.Fatalf("expected to find 1 edge in the graph, found %d", numEdges) + } + + // Channels should not be announced yet, hence Alice should have no + // announced edges in her graph. + req.IncludeUnannounced = false + ctx, _ = context.WithTimeout(ctb, timeout) + chanGraph, err = net.Alice.DescribeGraph(ctx, req) + if err != nil { + t.Fatalf("unable to query alice's graph: %v", err) + } + + numEdges = len(chanGraph.Edges) + if numEdges != 0 { + t.Fatalf("expected to find 0 announced edges in the graph, found %d", + numEdges) + } + + // Mine 4 more blocks, and check that the channel is now announced. + mineBlocks(t, net, 4) + + // Give the network a chance to learn that auth proof is confirmed. + var predErr error + err = lntest.WaitPredicate(func() bool { + // The channel should now be announced. Check that Alice has 1 + // announced edge. + req.IncludeUnannounced = false + ctx, _ = context.WithTimeout(ctb, timeout) + chanGraph, err = net.Alice.DescribeGraph(ctx, req) + if err != nil { + predErr = fmt.Errorf("unable to query alice's graph: %v", err) + return false + } + + numEdges = len(chanGraph.Edges) + if numEdges != 1 { + predErr = fmt.Errorf("expected to find 1 announced edge in "+ + "the graph, found %d", numEdges) + return false + } + return true + }, time.Second*15) + if err != nil { + t.Fatalf("%v", predErr) + } + + // The channel should now be announced. Check that Alice has 1 announced + // edge. + req.IncludeUnannounced = false + ctx, _ = context.WithTimeout(ctb, timeout) + chanGraph, err = net.Alice.DescribeGraph(ctx, req) + if err != nil { + t.Fatalf("unable to query alice's graph: %v", err) + } + + numEdges = len(chanGraph.Edges) + if numEdges != 1 { + t.Fatalf("expected to find 1 announced edge in the graph, found %d", + numEdges) + } + + // Close the channel used during the test. + ctx, _ = context.WithTimeout(ctb, timeout) + closeChannelAndAssert(ctx, t, net, net.Alice, fundingChanPoint, false) +} + // testPrivateChannels tests that a private channel can be used for // routing by the two endpoints of the channel, but is not known by // the rest of the nodes in the graph. @@ -4432,8 +4548,10 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { // nodes know about. Carol and Alice should know about 4, while // Bob and Dave should only know about 3, since one channel is // private. - numChannels := func(node *lntest.HarnessNode) int { - req := &lnrpc.ChannelGraphRequest{} + numChannels := func(node *lntest.HarnessNode, includeUnannounced bool) int { + req := &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: includeUnannounced, + } ctxt, _ := context.WithTimeout(ctxb, timeout) chanGraph, err := node.DescribeGraph(ctxt, req) if err != nil { @@ -4444,25 +4562,37 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { var predErr error err = lntest.WaitPredicate(func() bool { - aliceChans := numChannels(net.Alice) + aliceChans := numChannels(net.Alice, true) if aliceChans != 4 { predErr = fmt.Errorf("expected Alice to know 4 edges, "+ "had %v", aliceChans) return false } - bobChans := numChannels(net.Bob) + alicePubChans := numChannels(net.Alice, false) + if alicePubChans != 3 { + predErr = fmt.Errorf("expected Alice to know 3 public edges, "+ + "had %v", alicePubChans) + return false + } + bobChans := numChannels(net.Bob, true) if bobChans != 3 { predErr = fmt.Errorf("expected Bob to know 3 edges, "+ "had %v", bobChans) return false } - carolChans := numChannels(carol) + carolChans := numChannels(carol, true) if carolChans != 4 { predErr = fmt.Errorf("expected Carol to know 4 edges, "+ "had %v", carolChans) return false } - daveChans := numChannels(dave) + carolPubChans := numChannels(carol, false) + if carolPubChans != 3 { + predErr = fmt.Errorf("expected Carol to know 3 public edges, "+ + "had %v", carolPubChans) + return false + } + daveChans := numChannels(dave, true) if daveChans != 3 { predErr = fmt.Errorf("expected Dave to know 3 edges, "+ "had %v", daveChans) @@ -5781,7 +5911,9 @@ func testGarbageCollectLinkNodes(net *lntest.NetworkHarness, t *harnessTest) { // Finally, we'll ensure that Bob and Carol no longer show in Alice's // channel graph. - describeGraphReq := &lnrpc.ChannelGraphRequest{} + describeGraphReq := &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } channelGraph, err := net.Alice.DescribeGraph(ctxb, describeGraphReq) if err != nil { t.Fatalf("unable to query for alice's channel graph: %v", err) @@ -12184,6 +12316,10 @@ var testsCases = []*testCase{ name: "send to route error propagation", test: testSendToRouteErrorPropagation, }, + { + name: "unannounced channels", + test: testUnannouncedChannels, + }, { name: "private channels", test: testPrivateChannels, diff --git a/rpcserver.go b/rpcserver.go index 949a76ac..2188c1ac 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -3095,9 +3095,10 @@ func (r *rpcServer) GetTransactions(ctx context.Context, // specific routing policy which includes: the time lock delta, fee // information, etc. func (r *rpcServer) DescribeGraph(ctx context.Context, - _ *lnrpc.ChannelGraphRequest) (*lnrpc.ChannelGraph, error) { + req *lnrpc.ChannelGraphRequest) (*lnrpc.ChannelGraph, error) { resp := &lnrpc.ChannelGraph{} + includeUnannounced := req.IncludeUnannounced // Obtain the pointer to the global singleton channel graph, this will // provide a consistent view of the graph due to bolt db's @@ -3138,8 +3139,17 @@ func (r *rpcServer) DescribeGraph(ctx context.Context, err = graph.ForEachChannel(func(edgeInfo *channeldb.ChannelEdgeInfo, c1, c2 *channeldb.ChannelEdgePolicy) error { + // Do not include unannounced channels unless specifically + // requested. Unannounced channels include both private channels as + // well as public channels whose authentication proof were not + // confirmed yet, hence were not announced. + if !includeUnannounced && edgeInfo.AuthProof == nil { + return nil + } + edge := marshalDbEdge(edgeInfo, c1, c2) resp.Edges = append(resp.Edges, edge) + return nil }) if err != nil && err != channeldb.ErrGraphNoEdgesFound {