diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 87c98be2..f15eec31 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1520,7 +1520,7 @@ func (d *AuthenticatedGossiper) processRejectedEdge( if err != nil { return nil, err } - err = ValidateChannelAnn(chanAnn) + err = routing.ValidateChannelAnn(chanAnn) if err != nil { err := fmt.Errorf("assembled channel announcement proof "+ "for shortChanID=%v isn't valid: %v", @@ -1598,7 +1598,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( return nil } - if err := ValidateNodeAnn(msg); err != nil { + if err := routing.ValidateNodeAnn(msg); err != nil { err := fmt.Errorf("unable to validate "+ "node announcement: %v", err) log.Error(err) @@ -1701,7 +1701,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // formed. var proof *channeldb.ChannelAuthProof if nMsg.isRemote { - if err := ValidateChannelAnn(msg); err != nil { + if err := routing.ValidateChannelAnn(msg); err != nil { err := fmt.Errorf("unable to validate "+ "announcement: %v", err) d.rejectMtx.Lock() @@ -1993,7 +1993,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // Validate the channel announcement with the expected public // key, In the case of an invalid channel , we'll return an // error to the caller and exit early. - if err := ValidateChannelUpdateAnn(pubKey, msg); err != nil { + if err := routing.ValidateChannelUpdateAnn(pubKey, msg); err != nil { rErr := fmt.Errorf("unable to validate channel "+ "update announcement for short_chan_id=%v: %v", spew.Sdump(msg.ShortChannelID), err) @@ -2297,7 +2297,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // With all the necessary components assembled validate the // full channel announcement proof. - if err := ValidateChannelAnn(chanAnn); err != nil { + if err := routing.ValidateChannelAnn(chanAnn); err != nil { err := fmt.Errorf("channel announcement proof "+ "for short_chan_id=%v isn't valid: %v", shortChanID, err) @@ -2505,7 +2505,7 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo, // To ensure that our signature is valid, we'll verify it ourself // before committing it to the slice returned. - err = ValidateChannelUpdateAnn(d.selfKey, chanUpdate) + err = routing.ValidateChannelUpdateAnn(d.selfKey, chanUpdate) if err != nil { return nil, nil, fmt.Errorf("generated invalid channel "+ "update sig: %v", err) diff --git a/discovery/ann_validation.go b/routing/ann_validation.go similarity index 99% rename from discovery/ann_validation.go rename to routing/ann_validation.go index 6ca07f64..257ac3fd 100644 --- a/discovery/ann_validation.go +++ b/routing/ann_validation.go @@ -1,4 +1,4 @@ -package discovery +package routing import ( "bytes" diff --git a/routing/notifications_test.go b/routing/notifications_test.go index dbd9467a..2fa12274 100644 --- a/routing/notifications_test.go +++ b/routing/notifications_test.go @@ -35,6 +35,8 @@ var ( 0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53, } + testTime = time.Date(2018, time.January, 9, 14, 00, 00, 0, time.UTC) + priv1, _ = btcec.NewPrivateKey(btcec.S256()) bitcoinKey1 = priv1.PubKey() @@ -337,7 +339,7 @@ func (m *mockChainView) Stop() error { func TestEdgeUpdateNotification(t *testing.T) { t.Parallel() - ctx, cleanUp, err := createTestCtx(0) + ctx, cleanUp, err := createTestCtxSingleNode(0) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -526,7 +528,7 @@ func TestNodeUpdateNotification(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -704,7 +706,7 @@ func TestNotificationCancellation(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -796,7 +798,7 @@ func TestChannelCloseNotification(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index c5e41501..a014bfb2 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -14,7 +14,6 @@ import ( "os" "strings" "testing" - "time" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -22,8 +21,6 @@ import ( "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" - - prand "math/rand" ) const ( @@ -50,9 +47,7 @@ const ( ) var ( - randSource = prand.NewSource(time.Now().Unix()) - randInts = prand.New(randSource) - testSig = &btcec.Signature{ + testSig = &btcec.Signature{ R: new(big.Int), S: new(big.Int), } @@ -126,17 +121,12 @@ func makeTestGraph() (*channeldb.ChannelGraph, func(), error) { return cdb.ChannelGraph(), cleanUp, nil } -// aliasMap is a map from a node's alias to its public key. This type is -// provided in order to allow easily look up from the human memorable alias -// to an exact node's public key. -type aliasMap map[string]*btcec.PublicKey - // parseTestGraph returns a fully populated ChannelGraph given a path to a JSON // file which encodes a test graph. -func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, error) { +func parseTestGraph(path string) (*testGraphInstance, error) { graphJSON, err := ioutil.ReadFile(path) if err != nil { - return nil, nil, nil, err + return nil, err } // First unmarshal the JSON graph into an instance of the testGraph @@ -144,7 +134,7 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err // will be properly parsed into the struct above. var g testGraph if err := json.Unmarshal(graphJSON, &g); err != nil { - return nil, nil, nil, err + return nil, err } // We'll use this fake address for the IP address of all the nodes in @@ -153,14 +143,14 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err var testAddrs []net.Addr testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888") if err != nil { - return nil, nil, nil, err + return nil, err } testAddrs = append(testAddrs, testAddr) // Next, create a temporary graph database for usage within the test. graph, cleanUp, err := makeTestGraph() if err != nil { - return nil, nil, nil, err + return nil, err } aliasMap := make(map[string]*btcec.PublicKey) @@ -170,13 +160,13 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err for _, node := range g.Nodes { pubBytes, err := hex.DecodeString(node.PubKey) if err != nil { - return nil, nil, nil, err + return nil, err } dbNode := &channeldb.LightningNode{ HaveNodeAnnouncement: true, AuthSigBytes: testSig.Serialize(), - LastUpdate: time.Now(), + LastUpdate: testTime, Addresses: testAddrs, Alias: node.Alias, Features: testFeatures, @@ -186,13 +176,13 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err // We require all aliases within the graph to be unique for our // tests. if _, ok := aliasMap[node.Alias]; ok { - return nil, nil, nil, errors.New("aliases for nodes " + + return nil, errors.New("aliases for nodes " + "must be unique!") } pub, err := btcec.ParsePubKey(pubBytes, btcec.S256()) if err != nil { - return nil, nil, nil, err + return nil, err } // If the alias is unique, then add the node to the @@ -208,7 +198,7 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err // iteration, then the JSON has an error as only ONE // node can be the source in the graph. if source != nil { - return nil, nil, nil, errors.New("JSON is invalid " + + return nil, errors.New("JSON is invalid " + "multiple nodes are tagged as the source") } @@ -218,14 +208,14 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err // With the node fully parsed, add it as a vertex within the // graph. if err := graph.AddLightningNode(dbNode); err != nil { - return nil, nil, nil, err + return nil, err } } if source != nil { // Set the selected source node if err := graph.SetSourceNode(source); err != nil { - return nil, nil, nil, err + return nil, err } } @@ -234,18 +224,18 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err for _, edge := range g.Edges { node1Bytes, err := hex.DecodeString(edge.Node1) if err != nil { - return nil, nil, nil, err + return nil, err } node2Bytes, err := hex.DecodeString(edge.Node2) if err != nil { - return nil, nil, nil, err + return nil, err } fundingTXID := strings.Split(edge.ChannelPoint, ":")[0] txidBytes, err := chainhash.NewHashFromStr(fundingTXID) if err != nil { - return nil, nil, nil, err + return nil, err } fundingPoint := wire.OutPoint{ Hash: *txidBytes, @@ -268,25 +258,29 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err err = graph.AddChannelEdge(&edgeInfo) if err != nil && err != channeldb.ErrEdgeAlreadyExist { - return nil, nil, nil, err + return nil, err } edgePolicy := &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), Flags: lnwire.ChanUpdateFlag(edge.Flags), ChannelID: edge.ChannelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: edge.Expiry, MinHTLC: lnwire.MilliSatoshi(edge.MinHTLC), FeeBaseMSat: lnwire.MilliSatoshi(edge.FeeBaseMsat), FeeProportionalMillionths: lnwire.MilliSatoshi(edge.FeeRate), } if err := graph.UpdateEdgePolicy(edgePolicy); err != nil { - return nil, nil, nil, err + return nil, err } } - return graph, cleanUp, aliasMap, nil + return &testGraphInstance{ + graph: graph, + cleanUp: cleanUp, + aliasMap: aliasMap, + }, nil } type testChannelPolicy struct { @@ -314,7 +308,15 @@ func defaultTestChannelEnd(alias string) *testChannelEnd { } func symmetricTestChannel(alias1 string, alias2 string, capacity btcutil.Amount, - policy *testChannelPolicy) *testChannel { + policy *testChannelPolicy, chanID ...uint64) *testChannel { + + // Leaving id zero will result in auto-generation of a channel id during + // graph construction. + var id uint64 + if len(chanID) > 0 { + id = chanID[0] + } + return &testChannel{ Capacity: capacity, Node1: &testChannelEnd{ @@ -325,38 +327,55 @@ func symmetricTestChannel(alias1 string, alias2 string, capacity btcutil.Amount, Alias: alias2, testChannelPolicy: *policy, }, + ChannelID: id, } } type testChannel struct { - Node1 *testChannelEnd - Node2 *testChannelEnd - Capacity btcutil.Amount + Node1 *testChannelEnd + Node2 *testChannelEnd + Capacity btcutil.Amount + ChannelID uint64 } -// createTestGraph returns a fully populated ChannelGraph based on a set of +type testGraphInstance struct { + graph *channeldb.ChannelGraph + cleanUp func() + + // aliasMap is a map from a node's alias to its public key. This type is + // provided in order to allow easily look up from the human memorable alias + // to an exact node's public key. + aliasMap map[string]*btcec.PublicKey + + // privKeyMap maps a node alias to its private key. This is used to be + // able to mock a remote node's signing behaviour. + privKeyMap map[string]*btcec.PrivateKey +} + +// createTestGraphFromChannels returns a fully populated ChannelGraph based on a set of // test channels. Additional required information like keys are derived in // a deterministical way and added to the channel graph. A list of nodes is // not required and derived from the channel data. The goal is to keep // instantiating a test channel graph as light weight as possible. -func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func(), aliasMap, error) { +func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstance, error) { // We'll use this fake address for the IP address of all the nodes in // our tests. This value isn't needed for path finding so it doesn't // need to be unique. var testAddrs []net.Addr testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888") if err != nil { - return nil, nil, nil, err + return nil, err } testAddrs = append(testAddrs, testAddr) // Next, create a temporary graph database for usage within the test. graph, cleanUp, err := makeTestGraph() if err != nil { - return nil, nil, nil, err + return nil, err } aliasMap := make(map[string]*btcec.PublicKey) + privKeyMap := make(map[string]*btcec.PrivateKey) nodeIndex := byte(0) addNodeWithAlias := func(alias string) (*channeldb.LightningNode, error) { @@ -368,13 +387,13 @@ func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func 0, 0, 0, 0, 0, 0, 0, nodeIndex + 1, } - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), + privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), keyBytes) dbNode := &channeldb.LightningNode{ HaveNodeAnnouncement: true, AuthSigBytes: testSig.Serialize(), - LastUpdate: time.Now(), + LastUpdate: testTime, Addresses: testAddrs, Alias: alias, Features: testFeatures, @@ -382,6 +401,8 @@ func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func copy(dbNode.PubKeyBytes[:], pubKey.SerializeCompressed()) + privKeyMap[alias] = privKey + // With the node fully parsed, add it as a vertex within the // graph. if err := graph.AddLightningNode(dbNode); err != nil { @@ -396,15 +417,18 @@ func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func var source *channeldb.LightningNode if source, err = addNodeWithAlias("roasbeef"); err != nil { - return nil, nil, nil, err + return nil, err } // Set the source node if err := graph.SetSourceNode(source); err != nil { - return nil, nil, nil, err + return nil, err } - channelID := uint64(0) + // Initialize variable that keeps track of the next channel id to assign + // if none is specified. + nextUnassignedChannelID := uint64(100000) + for _, testChannel := range testChannels { for _, alias := range []string{ testChannel.Node1.Alias, testChannel.Node2.Alias} { @@ -415,6 +439,14 @@ func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func } } + channelID := testChannel.ChannelID + + // If no channel id is specified, generate an id. + if channelID == 0 { + channelID = nextUnassignedChannelID + nextUnassignedChannelID++ + } + var hash [sha256.Size]byte hash[len(hash)-1] = byte(channelID) @@ -442,28 +474,28 @@ func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func err = graph.AddChannelEdge(&edgeInfo) if err != nil && err != channeldb.ErrEdgeAlreadyExist { - return nil, nil, nil, err + return nil, err } edgePolicy := &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), Flags: lnwire.ChanUpdateFlag(0), ChannelID: channelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: testChannel.Node1.Expiry, MinHTLC: testChannel.Node1.MinHTLC, FeeBaseMSat: testChannel.Node1.FeeBaseMsat, FeeProportionalMillionths: testChannel.Node1.FeeRate, } if err := graph.UpdateEdgePolicy(edgePolicy); err != nil { - return nil, nil, nil, err + return nil, err } edgePolicy = &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), Flags: lnwire.ChanUpdateFlag(lnwire.ChanUpdateDirection), ChannelID: channelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: testChannel.Node2.Expiry, MinHTLC: testChannel.Node2.MinHTLC, FeeBaseMSat: testChannel.Node2.FeeBaseMsat, @@ -471,13 +503,18 @@ func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func } if err := graph.UpdateEdgePolicy(edgePolicy); err != nil { - return nil, nil, nil, err + return nil, err } channelID++ } - return graph, cleanUp, aliasMap, nil + return &testGraphInstance{ + graph: graph, + cleanUp: cleanUp, + aliasMap: aliasMap, + privKeyMap: privKeyMap, + }, nil } // TestFindLowestFeePath tests that out of two routes with identical total @@ -518,13 +555,13 @@ func TestFindLowestFeePath(t *testing.T) { }), } - graph, cleanUp, aliases, err := createTestGraph(testChannels) - defer cleanUp() + testGraphInstance, err := createTestGraphFromChannels(testChannels) + defer testGraphInstance.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := testGraphInstance.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -539,10 +576,10 @@ func TestFindLowestFeePath(t *testing.T) { ) paymentAmt := lnwire.NewMSatFromSatoshis(100) - target := aliases["target"] + target := testGraphInstance.aliasMap["target"] path, err := findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, - ignoredEdges, paymentAmt, noFeeLimit, nil, + nil, testGraphInstance.graph, nil, sourceNode, target, + ignoredVertexes, ignoredEdges, paymentAmt, noFeeLimit, nil, ) if err != nil { t.Fatalf("unable to find path: %v", err) @@ -556,7 +593,7 @@ func TestFindLowestFeePath(t *testing.T) { // Assert that the lowest fee route is returned. if !bytes.Equal(route.Hops[1].Channel.Node.PubKeyBytes[:], - aliases["b"].SerializeCompressed()) { + testGraphInstance.aliasMap["b"].SerializeCompressed()) { t.Fatalf("expected route to pass through b, "+ "but got a route through %v", route.Hops[1].Channel.Node.Alias) @@ -626,8 +663,8 @@ var basicGraphPathFindingTests = []basicGraphPathFindingTestCase{ func TestBasicGraphPathFinding(t *testing.T) { t.Parallel() - graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + testGraphInstance, err := parseTestGraph(basicGraphFilePath) + defer testGraphInstance.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } @@ -639,18 +676,19 @@ func TestBasicGraphPathFinding(t *testing.T) { for _, testCase := range basicGraphPathFindingTests { t.Run(testCase.target, func(subT *testing.T) { - testBasicGraphPathFindingCase(subT, graph, aliases, &testCase) + testBasicGraphPathFindingCase(subT, testGraphInstance, &testCase) }) } } -func testBasicGraphPathFindingCase(t *testing.T, graph *channeldb.ChannelGraph, - aliases aliasMap, test *basicGraphPathFindingTestCase) { +func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstance, + test *basicGraphPathFindingTestCase) { + aliases := graphInstance.aliasMap expectedHops := test.expectedHops expectedHopCount := len(expectedHops) - sourceNode, err := graph.SourceNode() + sourceNode, err := graphInstance.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -665,10 +703,10 @@ func testBasicGraphPathFindingCase(t *testing.T, graph *channeldb.ChannelGraph, ) paymentAmt := lnwire.NewMSatFromSatoshis(test.paymentAmt) - target := aliases[test.target] + target := graphInstance.aliasMap[test.target] path, err := findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, - ignoredEdges, paymentAmt, test.feeLimit, nil, + nil, graphInstance.graph, nil, sourceNode, target, + ignoredVertexes, ignoredEdges, paymentAmt, test.feeLimit, nil, ) if test.expectFailureNoPath { if err == nil { @@ -804,13 +842,13 @@ func testBasicGraphPathFindingCase(t *testing.T, graph *channeldb.ChannelGraph, func TestPathFindingWithAdditionalEdges(t *testing.T) { t.Parallel() - graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(basicGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -847,12 +885,12 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) { } additionalEdges := map[Vertex][]*channeldb.ChannelEdgePolicy{ - NewVertex(aliases["songoku"]): {songokuToDoge}, + NewVertex(graph.aliasMap["songoku"]): {songokuToDoge}, } // We should now be able to find a path from roasbeef to doge. path, err := findPath( - nil, graph, additionalEdges, sourceNode, dogePubKey, nil, nil, + nil, graph.graph, additionalEdges, sourceNode, dogePubKey, nil, nil, paymentAmt, noFeeLimit, nil, ) if err != nil { @@ -867,13 +905,13 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) { func TestKShortestPathFinding(t *testing.T) { t.Parallel() - graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(basicGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -887,9 +925,9 @@ func TestKShortestPathFinding(t *testing.T) { // them in order of their total "distance". paymentAmt := lnwire.NewMSatFromSatoshis(100) - target := aliases["luoji"] + target := graph.aliasMap["luoji"] paths, err := findPaths( - nil, graph, sourceNode, target, paymentAmt, noFeeLimit, 100, + nil, graph.graph, sourceNode, target, paymentAmt, noFeeLimit, 100, nil, ) if err != nil { @@ -1206,13 +1244,13 @@ func TestNewRoutePathTooLong(t *testing.T) { // Ensure that potential paths which are over the maximum hop-limit are // rejected. - graph, cleanUp, aliases, err := parseTestGraph(excessiveHopsGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(excessiveHopsGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -1224,9 +1262,9 @@ func TestNewRoutePathTooLong(t *testing.T) { // We start by confirming that routing a payment 20 hops away is possible. // Alice should be able to find a valid route to ursula. - target := aliases["ursula"] + target := graph.aliasMap["ursula"] _, err = findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, + nil, graph.graph, nil, sourceNode, target, ignoredVertexes, ignoredEdges, paymentAmt, noFeeLimit, nil, ) if err != nil { @@ -1235,9 +1273,9 @@ func TestNewRoutePathTooLong(t *testing.T) { // Vincent is 21 hops away from Alice, and thus no valid route should be // presented to Alice. - target = aliases["vincent"] + target = graph.aliasMap["vincent"] path, err := findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, + nil, graph.graph, nil, sourceNode, target, ignoredVertexes, ignoredEdges, paymentAmt, noFeeLimit, nil, ) if err == nil { @@ -1251,13 +1289,13 @@ func TestNewRoutePathTooLong(t *testing.T) { func TestPathNotAvailable(t *testing.T) { t.Parallel() - graph, cleanUp, _, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(basicGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -1279,7 +1317,7 @@ func TestPathNotAvailable(t *testing.T) { } _, err = findPath( - nil, graph, nil, sourceNode, unknownNode, ignoredVertexes, + nil, graph.graph, nil, sourceNode, unknownNode, ignoredVertexes, ignoredEdges, 100, noFeeLimit, nil, ) if !IsError(err, ErrNoPathFound) { @@ -1290,13 +1328,13 @@ func TestPathNotAvailable(t *testing.T) { func TestPathInsufficientCapacity(t *testing.T) { t.Parallel() - graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(basicGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -1311,11 +1349,11 @@ func TestPathInsufficientCapacity(t *testing.T) { // satoshis. The largest channel in the basic graph is of size 100k // satoshis, so we shouldn't be able to find a path to sophon even // though we have a 2-hop link. - target := aliases["sophon"] + target := graph.aliasMap["sophon"] payAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) _, err = findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, + nil, graph.graph, nil, sourceNode, target, ignoredVertexes, ignoredEdges, payAmt, noFeeLimit, nil, ) if !IsError(err, ErrNoPathFound) { @@ -1328,13 +1366,13 @@ func TestPathInsufficientCapacity(t *testing.T) { func TestRouteFailMinHTLC(t *testing.T) { t.Parallel() - graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(basicGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -1344,10 +1382,10 @@ func TestRouteFailMinHTLC(t *testing.T) { // We'll not attempt to route an HTLC of 10 SAT from roasbeef to Son // Goku. However, the min HTLC of Son Goku is 1k SAT, as a result, this // attempt should fail. - target := aliases["songoku"] + target := graph.aliasMap["songoku"] payAmt := lnwire.MilliSatoshi(10) _, err = findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, + nil, graph.graph, nil, sourceNode, target, ignoredVertexes, ignoredEdges, payAmt, noFeeLimit, nil, ) if !IsError(err, ErrNoPathFound) { @@ -1361,13 +1399,13 @@ func TestRouteFailMinHTLC(t *testing.T) { func TestRouteFailDisabledEdge(t *testing.T) { t.Parallel() - graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) - defer cleanUp() + graph, err := parseTestGraph(basicGraphFilePath) + defer graph.cleanUp() if err != nil { t.Fatalf("unable to create graph: %v", err) } - sourceNode, err := graph.SourceNode() + sourceNode, err := graph.graph.SourceNode() if err != nil { t.Fatalf("unable to fetch source node: %v", err) } @@ -1376,10 +1414,10 @@ func TestRouteFailDisabledEdge(t *testing.T) { // First, we'll try to route from roasbeef -> sophon. This should // succeed without issue, and return a single path via phamnuwen - target := aliases["sophon"] + target := graph.aliasMap["sophon"] payAmt := lnwire.NewMSatFromSatoshis(105000) _, err = findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, + nil, graph.graph, nil, sourceNode, target, ignoredVertexes, ignoredEdges, payAmt, noFeeLimit, nil, ) if err != nil { @@ -1388,19 +1426,19 @@ func TestRouteFailDisabledEdge(t *testing.T) { // First, we'll modify the edge from roasbeef -> phamnuwen, to read that // it's disabled. - _, _, phamnuwenEdge, err := graph.FetchChannelEdgesByID(999991) + _, _, phamnuwenEdge, err := graph.graph.FetchChannelEdgesByID(999991) if err != nil { t.Fatalf("unable to fetch goku's edge: %v", err) } phamnuwenEdge.Flags = lnwire.ChanUpdateDisabled | lnwire.ChanUpdateDirection - if err := graph.UpdateEdgePolicy(phamnuwenEdge); err != nil { + if err := graph.graph.UpdateEdgePolicy(phamnuwenEdge); err != nil { t.Fatalf("unable to update edge: %v", err) } // Now, if we attempt to route through that edge, we should get a // failure as it is no longer eligible. _, err = findPath( - nil, graph, nil, sourceNode, target, ignoredVertexes, + nil, graph.graph, nil, sourceNode, target, ignoredVertexes, ignoredEdges, payAmt, noFeeLimit, nil, ) if !IsError(err, ErrNoPathFound) { @@ -1425,7 +1463,7 @@ func TestPathFindSpecExample(t *testing.T) { // we'll pass that in to ensure that the router uses 100 as the current // height. const startingHeight = 100 - ctx, cleanUp, err := createTestCtx(startingHeight, specExampleFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingHeight, specExampleFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) diff --git a/routing/router.go b/routing/router.go index 075dcdea..5186476f 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1801,7 +1801,8 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // correct block height is. case *lnwire.FailExpiryTooSoon: update := onionErr.Update - if err := r.applyChannelUpdate(&update); err != nil { + err := r.applyChannelUpdate(&update, errSource) + if err != nil { log.Errorf("unable to apply channel "+ "update for onion error: %v", err) } @@ -1826,7 +1827,8 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // and continue with the rest of the routes. case *lnwire.FailAmountBelowMinimum: update := onionErr.Update - if err := r.applyChannelUpdate(&update); err != nil { + err := r.applyChannelUpdate(&update, errSource) + if err != nil { log.Errorf("unable to apply channel "+ "update for onion error: %v", err) } @@ -1838,7 +1840,8 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // newly updated fees. case *lnwire.FailFeeInsufficient: update := onionErr.Update - if err := r.applyChannelUpdate(&update); err != nil { + err := r.applyChannelUpdate(&update, errSource) + if err != nil { log.Errorf("unable to apply channel "+ "update for onion error: %v", err) @@ -1871,7 +1874,8 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // finding. case *lnwire.FailIncorrectCltvExpiry: update := onionErr.Update - if err := r.applyChannelUpdate(&update); err != nil { + err := r.applyChannelUpdate(&update, errSource) + if err != nil { log.Errorf("unable to apply channel "+ "update for onion error: %v", err) } @@ -1886,7 +1890,8 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // the update and continue. case *lnwire.FailChannelDisabled: update := onionErr.Update - if err := r.applyChannelUpdate(&update); err != nil { + err := r.applyChannelUpdate(&update, errSource) + if err != nil { log.Errorf("unable to apply channel "+ "update for onion error: %v", err) } @@ -1899,7 +1904,8 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment, // now, and continue onwards with our path finding. case *lnwire.FailTemporaryChannelFailure: update := onionErr.Update - if err := r.applyChannelUpdate(update); err != nil { + err := r.applyChannelUpdate(update, errSource) + if err != nil { log.Errorf("unable to apply channel "+ "update for onion error: %v", err) } @@ -2023,15 +2029,20 @@ func pruneEdgeFailure(paySession *paymentSession, route *Route, paySession.ReportChannelFailure(badChan.ChannelID) } -// applyChannelUpdate applies a channel update directly to the database, -// skipping preliminary validation. -func (r *ChannelRouter) applyChannelUpdate(msg *lnwire.ChannelUpdate) error { +// applyChannelUpdate validates a channel update and if valid, applies it to the +// database. +func (r *ChannelRouter) applyChannelUpdate(msg *lnwire.ChannelUpdate, + pubKey *btcec.PublicKey) error { // If we get passed a nil channel update (as it's optional with some // onion errors), then we'll exit early with a nil error. if msg == nil { return nil } + if err := ValidateChannelUpdateAnn(pubKey, msg); err != nil { + return err + } + err := r.UpdateEdge(&channeldb.ChannelEdgePolicy{ SigBytes: msg.Signature.ToSignatureBytes(), ChannelID: msg.ShortChannelID.ToUint64(), diff --git a/routing/router_test.go b/routing/router_test.go index 0c9492be..c1d7d344 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -14,6 +14,7 @@ import ( "github.com/lightningnetwork/lnd/htlcswitch" "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/lnwire" @@ -74,51 +75,17 @@ func copyPubKey(pub *btcec.PublicKey) *btcec.PublicKey { } } -func createTestCtx(startingHeight uint32, testGraph ...string) (*testCtx, func(), error) { - var ( - graph *channeldb.ChannelGraph - sourceNode *channeldb.LightningNode - cleanup func() - err error - ) +func createTestCtxFromGraphInstance(startingHeight uint32, graphInstance *testGraphInstance) ( + *testCtx, func(), error) { - aliasMap := make(map[string]*btcec.PublicKey) - - // If the testGraph isn't set, then we'll create an empty graph to - // start out with. Our usage of a variadic parameter allows caller to - // omit the testGraph argument all together if they wish to start with - // a blank graph. - if testGraph == nil { - // First we'll set up a test graph for usage within the test. - graph, cleanup, err = makeTestGraph() - if err != nil { - return nil, nil, fmt.Errorf("unable to create test graph: %v", err) - } - - sourceNode, err = createTestNode() - if err != nil { - return nil, nil, fmt.Errorf("unable to create source node: %v", err) - } - if err = graph.SetSourceNode(sourceNode); err != nil { - return nil, nil, fmt.Errorf("unable to set source node: %v", err) - } - } else { - // Otherwise, we'll attempt to locate and parse out the file - // that encodes the graph that our tests should be run against. - graph, cleanup, aliasMap, err = parseTestGraph(testGraph[0]) - if err != nil { - return nil, nil, fmt.Errorf("unable to create test graph: %v", err) - } - } - - // Next we'll initialize an instance of the channel router with mock + // We'll initialize an instance of the channel router with mock // versions of the chain and channel notifier. As we don't need to test // any p2p functionality, the peer send and switch send messages won't // be populated. chain := newMockChain(startingHeight) chainView := newMockChainView(chain) router, err := New(Config{ - Graph: graph, + Graph: graphInstance.graph, Chain: chain, ChainView: chainView, SendToSwitch: func(_ lnwire.ShortChannelID, @@ -141,20 +108,60 @@ func createTestCtx(startingHeight uint32, testGraph ...string) (*testCtx, func() ctx := &testCtx{ router: router, - graph: graph, - aliases: aliasMap, + graph: graphInstance.graph, + aliases: graphInstance.aliasMap, chain: chain, chainView: chainView, } cleanUp := func() { ctx.router.Stop() - cleanup() + graphInstance.cleanUp() } return ctx, cleanUp, nil } +func createTestCtxSingleNode(startingHeight uint32) (*testCtx, func(), error) { + var ( + graph *channeldb.ChannelGraph + sourceNode *channeldb.LightningNode + cleanup func() + err error + ) + + graph, cleanup, err = makeTestGraph() + if err != nil { + return nil, nil, fmt.Errorf("unable to create test graph: %v", err) + } + + sourceNode, err = createTestNode() + if err != nil { + return nil, nil, fmt.Errorf("unable to create source node: %v", err) + } + if err = graph.SetSourceNode(sourceNode); err != nil { + return nil, nil, fmt.Errorf("unable to set source node: %v", err) + } + + graphInstance := &testGraphInstance{ + graph: graph, + cleanUp: cleanup, + } + + return createTestCtxFromGraphInstance(startingHeight, graphInstance) +} + +func createTestCtxFromFile(startingHeight uint32, testGraph string) (*testCtx, func(), error) { + // We'll attempt to locate and parse out the file + // that encodes the graph that our tests should be run against. + graphInstance, err := parseTestGraph(testGraph) + if err != nil { + return nil, nil, fmt.Errorf("unable to create test graph: %v", err) + } + + return createTestCtxFromGraphInstance(startingHeight, graphInstance) +} + // TestFindRoutesFeeSorting asserts that routes found by the FindRoutes method // within the channel router are properly returned in a sorted order, with the // lowest fee route coming first. @@ -162,7 +169,7 @@ func TestFindRoutesFeeSorting(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -215,7 +222,7 @@ func TestFindRoutesWithFeeLimit(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx( + ctx, cleanUp, err := createTestCtxFromFile( startingBlockHeight, basicGraphFilePath, ) defer cleanUp() @@ -269,7 +276,7 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -341,6 +348,171 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) { } } +// TestChannelUpdateValidation tests that a failed payment with an associated +// channel update will only be applied to the graph when the update contains a +// valid signature. +func TestChannelUpdateValidation(t *testing.T) { + t.Parallel() + + // Setup a three node network. + testChannels := []*testChannel{ + symmetricTestChannel("a", "b", 100000, &testChannelPolicy{ + Expiry: 144, + FeeRate: 400, + MinHTLC: 1, + }, 1), + symmetricTestChannel("b", "c", 100000, &testChannelPolicy{ + Expiry: 144, + FeeRate: 400, + MinHTLC: 1, + }, 2), + } + + testGraph, err := createTestGraphFromChannels(testChannels) + defer testGraph.cleanUp() + if err != nil { + t.Fatalf("unable to create graph: %v", err) + } + + const startingBlockHeight = 101 + + ctx, cleanUp, err := createTestCtxFromGraphInstance(startingBlockHeight, + testGraph) + + defer cleanUp() + if err != nil { + t.Fatalf("unable to create router: %v", err) + } + + // Assert that the initially configured fee is retrieved correctly. + _, policy, _, err := ctx.router.GetChannelByID( + lnwire.NewShortChanIDFromInt(1)) + if err != nil { + t.Fatalf("cannot retrieve channel") + } + + if policy.FeeProportionalMillionths != 400 { + t.Fatalf("invalid fee") + } + + // Setup a route from source a to destination c. The route will be used + // in a call to SendToRoute. SendToRoute also applies channel updates, + // but it saves us from including RequestRoute in the test scope too. + var hop1 [33]byte + copy(hop1[:], ctx.aliases["b"].SerializeCompressed()) + + var hop2 [33]byte + copy(hop2[:], ctx.aliases["c"].SerializeCompressed()) + + hops := []*Hop{ + { + Channel: &ChannelHop{ + ChannelEdgePolicy: &channeldb.ChannelEdgePolicy{ + ChannelID: 1, + Node: &channeldb.LightningNode{ + PubKeyBytes: hop1, + }, + }, + }, + }, + { + Channel: &ChannelHop{ + ChannelEdgePolicy: &channeldb.ChannelEdgePolicy{ + ChannelID: 2, + Node: &channeldb.LightningNode{ + PubKeyBytes: hop2, + }, + }, + }, + }, + } + + route := &Route{ + Hops: hops, + } + + // Set up a channel update message with an invalid signature to be + // returned to the sender. + var invalidSignature [64]byte + errChanUpdate := lnwire.ChannelUpdate{ + Signature: invalidSignature, + FeeRate: 500, + ShortChannelID: lnwire.NewShortChanIDFromInt(1), + Timestamp: uint32(testTime.Add(time.Minute).Unix()), + } + + // We'll modify the SendToSwitch method so that it simulates a failed + // payment with an error originating from the first hop of the route. + // The unsigned channel update is attached to the failure message. + ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, + _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { + + return [32]byte{}, &htlcswitch.ForwardingError{ + ErrorSource: ctx.aliases["b"], + FailureMessage: &lnwire.FailFeeInsufficient{ + Update: errChanUpdate, + }, + } + } + + // The payment parameter is mostly redundant in SendToRoute. Can be left + // empty for this test. + payment := &LightningPayment{} + + // Send off the payment request to the router. The specified route + // should be attempted and the channel update should be received by + // router and ignored because it is missing a valid signature. + _, _, err = ctx.router.SendToRoute([]*Route{route}, payment) + if err == nil { + t.Fatalf("expected route to fail with channel update") + } + + _, policy, _, err = ctx.router.GetChannelByID( + lnwire.NewShortChanIDFromInt(1)) + if err != nil { + t.Fatalf("cannot retrieve channel") + } + + if policy.FeeProportionalMillionths != 400 { + t.Fatalf("fee updated without valid signature") + } + + // Next, add a signature to the channel update. + chanUpdateMsg, err := errChanUpdate.DataToSign() + if err != nil { + t.Fatal(err) + } + + digest := chainhash.DoubleHashB(chanUpdateMsg) + sig, err := testGraph.privKeyMap["b"].Sign(digest) + if err != nil { + t.Fatal(err) + } + + errChanUpdate.Signature, err = lnwire.NewSigFromSignature(sig) + if err != nil { + t.Fatal(err) + } + + // Retry the payment using the same route as before. + _, _, err = ctx.router.SendToRoute([]*Route{route}, payment) + if err == nil { + t.Fatalf("expected route to fail with channel update") + } + + // This time a valid signature was supplied and the policy change should + // have been applied to the graph. + _, policy, _, err = ctx.router.GetChannelByID( + lnwire.NewShortChanIDFromInt(1)) + if err != nil { + t.Fatalf("cannot retrieve channel") + } + + if policy.FeeProportionalMillionths != 500 { + t.Fatalf("fee not updated even though signature is valid") + } +} + // TestSendPaymentErrorRepeatedFeeInsufficient tests that if we receive // multiple fee related errors from a channel that we're attempting to route // through, then we'll prune the channel after the second attempt. @@ -348,7 +520,7 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -449,7 +621,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -581,7 +753,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -753,7 +925,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) { func TestAddProof(t *testing.T) { t.Parallel() - ctx, cleanup, err := createTestCtx(0) + ctx, cleanup, err := createTestCtxSingleNode(0) if err != nil { t.Fatal(err) } @@ -816,7 +988,7 @@ func TestIgnoreNodeAnnouncement(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { @@ -849,7 +1021,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { @@ -910,7 +1082,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { edgePolicy := &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: 10, MinHTLC: 1, FeeBaseMSat: 10, @@ -926,7 +1098,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { edgePolicy = &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: 10, MinHTLC: 1, FeeBaseMSat: 10, @@ -1006,7 +1178,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { edgePolicy = &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: 10, MinHTLC: 1, FeeBaseMSat: 10, @@ -1021,7 +1193,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { edgePolicy = &channeldb.ChannelEdgePolicy{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, - LastUpdate: time.Now(), + LastUpdate: testTime, TimeLockDelta: 10, MinHTLC: 1, FeeBaseMSat: 10, @@ -1119,7 +1291,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -1322,7 +1494,7 @@ func TestDisconnectedBlocks(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -1512,7 +1684,7 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -1665,7 +1837,7 @@ func TestFindPathFeeWeighting(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath) + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -1716,7 +1888,7 @@ func TestIsStaleNode(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -1798,7 +1970,7 @@ func TestIsKnownEdge(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight) + ctx, cleanUp, err := createTestCtxSingleNode(startingBlockHeight) defer cleanUp() if err != nil { t.Fatalf("unable to create router: %v", err) @@ -1850,7 +2022,7 @@ func TestIsStaleEdgePolicy(t *testing.T) { t.Parallel() const startingBlockHeight = 101 - ctx, cleanUp, err := createTestCtx(startingBlockHeight, + ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight, basicGraphFilePath) defer cleanUp() if err != nil {