github.com/decred/dcrlnd@v0.7.6/routing/pathfind_test.go (about)

     1  package routing
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"encoding/binary"
     7  	"encoding/hex"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"math"
    13  	"net"
    14  	"os"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/decred/dcrd/chaincfg/chainhash"
    21  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    22  	"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
    23  	"github.com/decred/dcrd/dcrutil/v4"
    24  	"github.com/decred/dcrd/wire"
    25  	"github.com/decred/dcrlnd/channeldb"
    26  	"github.com/decred/dcrlnd/htlcswitch"
    27  	"github.com/decred/dcrlnd/kvdb"
    28  	"github.com/decred/dcrlnd/lnwire"
    29  	"github.com/decred/dcrlnd/record"
    30  	"github.com/decred/dcrlnd/routing/route"
    31  )
    32  
    33  const (
    34  	// basicGraphFilePath is the file path for a basic graph used within
    35  	// the tests. The basic graph consists of 5 nodes with 5 channels
    36  	// connecting them.
    37  	basicGraphFilePath = "testdata/basic_graph.json"
    38  
    39  	// specExampleFilePath is a file path which stores an example which
    40  	// implementations will use in order to ensure that they're calculating
    41  	// the payload for each hop in path properly.
    42  	specExampleFilePath = "testdata/spec_example.json"
    43  
    44  	// noFeeLimit is the maximum value of a payment through Lightning. We
    45  	// can use this value to signal there is no fee limit since payments
    46  	// should never be larger than this.
    47  	noFeeLimit = lnwire.MilliAtom(math.MaxUint32)
    48  )
    49  
    50  var (
    51  	noRestrictions = &RestrictParams{
    52  		FeeLimit:          noFeeLimit,
    53  		ProbabilitySource: noProbabilitySource,
    54  		CltvLimit:         math.MaxUint32,
    55  	}
    56  
    57  	testPathFindingConfig = &PathFindingConfig{}
    58  
    59  	tlvFeatures = lnwire.NewFeatureVector(
    60  		lnwire.NewRawFeatureVector(
    61  			lnwire.TLVOnionPayloadOptional,
    62  		), lnwire.Features,
    63  	)
    64  
    65  	payAddrFeatures = lnwire.NewFeatureVector(
    66  		lnwire.NewRawFeatureVector(
    67  			lnwire.PaymentAddrOptional,
    68  		), lnwire.Features,
    69  	)
    70  
    71  	tlvPayAddrFeatures = lnwire.NewFeatureVector(
    72  		lnwire.NewRawFeatureVector(
    73  			lnwire.TLVOnionPayloadOptional,
    74  			lnwire.PaymentAddrOptional,
    75  		), lnwire.Features,
    76  	)
    77  
    78  	mppFeatures = lnwire.NewRawFeatureVector(
    79  		lnwire.TLVOnionPayloadOptional,
    80  		lnwire.PaymentAddrOptional,
    81  		lnwire.MPPOptional,
    82  	)
    83  
    84  	unknownRequiredFeatures = lnwire.NewFeatureVector(
    85  		lnwire.NewRawFeatureVector(100), lnwire.Features,
    86  	)
    87  )
    88  
    89  func modNScalar(b []byte) *secp256k1.ModNScalar {
    90  	var m secp256k1.ModNScalar
    91  	m.SetByteSlice(b)
    92  	return &m
    93  }
    94  
    95  var (
    96  	rBytes, _ = hex.DecodeString("63724406601629180062774974542967536251589935445068131219452686511677818569431")
    97  	sBytes, _ = hex.DecodeString("18801056069249825825291287104931333862866033135609736119018462340006816851118")
    98  	testSig   = ecdsa.NewSignature(modNScalar(rBytes), modNScalar(sBytes))
    99  
   100  	testAuthProof = channeldb.ChannelAuthProof{
   101  		NodeSig1Bytes:   testSig.Serialize(),
   102  		NodeSig2Bytes:   testSig.Serialize(),
   103  		DecredSig1Bytes: testSig.Serialize(),
   104  		DecredSig2Bytes: testSig.Serialize(),
   105  	}
   106  )
   107  
   108  // noProbabilitySource is used in testing to return the same probability 1 for
   109  // all edges.
   110  func noProbabilitySource(route.Vertex, route.Vertex, lnwire.MilliAtom) float64 {
   111  	return 1
   112  }
   113  
   114  // testGraph is the struct which corresponds to the JSON format used to encode
   115  // graphs within the files in the testdata directory.
   116  //
   117  // TODO(roasbeef): add test graph auto-generator
   118  type testGraph struct {
   119  	Info  []string   `json:"info"`
   120  	Nodes []testNode `json:"nodes"`
   121  	Edges []testChan `json:"edges"`
   122  }
   123  
   124  // testNode represents a node within the test graph above. We skip certain
   125  // information such as the node's IP address as that information isn't needed
   126  // for our tests. Private keys are optional. If set, they should be consistent
   127  // with the public key. The private key is used to sign error messages
   128  // sent from the node.
   129  type testNode struct {
   130  	Source  bool   `json:"source"`
   131  	PubKey  string `json:"pubkey"`
   132  	PrivKey string `json:"privkey"`
   133  	Alias   string `json:"alias"`
   134  }
   135  
   136  // testChan represents the JSON version of a payment channel. This struct
   137  // matches the Json that's encoded under the "edges" key within the test graph.
   138  type testChan struct {
   139  	Node1         string `json:"node_1"`
   140  	Node2         string `json:"node_2"`
   141  	ChannelID     uint64 `json:"channel_id"`
   142  	ChannelPoint  string `json:"channel_point"`
   143  	ChannelFlags  uint8  `json:"channel_flags"`
   144  	MessageFlags  uint8  `json:"message_flags"`
   145  	Expiry        uint16 `json:"expiry"`
   146  	MinHTLC       int64  `json:"min_htlc"`
   147  	MaxHTLC       int64  `json:"max_htlc"`
   148  	FeeBaseMAtoms int64  `json:"fee_base_m_atoms"`
   149  	FeeRate       int64  `json:"fee_rate"`
   150  	Capacity      int64  `json:"capacity"`
   151  }
   152  
   153  // makeTestGraph creates a new instance of a channeldb.ChannelGraph for testing
   154  // purposes. A callback which cleans up the created temporary directories is
   155  // also returned and intended to be executed after the test completes.
   156  func makeTestGraph(useCache bool) (*channeldb.ChannelGraph, kvdb.Backend,
   157  	func(), error) {
   158  
   159  	// First, create a temporary directory to be used for the duration of
   160  	// this test.
   161  	tempDirName, err := ioutil.TempDir("", "channeldb")
   162  	if err != nil {
   163  		return nil, nil, nil, err
   164  	}
   165  
   166  	// Next, create channelgraph for the first time.
   167  	backend, backendCleanup, err := kvdb.GetTestBackend(tempDirName, "cgr")
   168  	if err != nil {
   169  		return nil, nil, nil, err
   170  	}
   171  
   172  	cleanUp := func() {
   173  		backendCleanup()
   174  		_ = os.RemoveAll(tempDirName)
   175  	}
   176  
   177  	opts := channeldb.DefaultOptions()
   178  	graph, err := channeldb.NewChannelGraph(
   179  		backend, opts.RejectCacheSize, opts.ChannelCacheSize,
   180  		opts.BatchCommitInterval, opts.PreAllocCacheNumNodes,
   181  		useCache,
   182  	)
   183  	if err != nil {
   184  		cleanUp()
   185  		return nil, nil, nil, err
   186  	}
   187  
   188  	return graph, backend, cleanUp, nil
   189  }
   190  
   191  // parseTestGraph returns a fully populated ChannelGraph given a path to a JSON
   192  // file which encodes a test graph.
   193  func parseTestGraph(useCache bool, path string) (*testGraphInstance, error) {
   194  	graphJSON, err := ioutil.ReadFile(path)
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	// First unmarshal the JSON graph into an instance of the testGraph
   200  	// struct. Using the struct tags created above in the struct, the JSON
   201  	// will be properly parsed into the struct above.
   202  	var g testGraph
   203  	if err := json.Unmarshal(graphJSON, &g); err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	// We'll use this fake address for the IP address of all the nodes in
   208  	// our tests. This value isn't needed for path finding so it doesn't
   209  	// need to be unique.
   210  	var testAddrs []net.Addr
   211  	testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888")
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	testAddrs = append(testAddrs, testAddr)
   216  
   217  	// Next, create a temporary graph database for usage within the test.
   218  	graph, graphBackend, cleanUp, err := makeTestGraph(useCache)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  
   223  	aliasMap := make(map[string]route.Vertex)
   224  	privKeyMap := make(map[string]*secp256k1.PrivateKey)
   225  	channelIDs := make(map[route.Vertex]map[route.Vertex]uint64)
   226  	links := make(map[lnwire.ShortChannelID]htlcswitch.ChannelLink)
   227  	var source *channeldb.LightningNode
   228  
   229  	// First we insert all the nodes within the graph as vertexes.
   230  	for _, node := range g.Nodes {
   231  		pubBytes, err := hex.DecodeString(node.PubKey)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  
   236  		dbNode := &channeldb.LightningNode{
   237  			HaveNodeAnnouncement: true,
   238  			AuthSigBytes:         testSig.Serialize(),
   239  			LastUpdate:           testTime,
   240  			Addresses:            testAddrs,
   241  			Alias:                node.Alias,
   242  			Features:             testFeatures,
   243  		}
   244  		copy(dbNode.PubKeyBytes[:], pubBytes)
   245  
   246  		// We require all aliases within the graph to be unique for our
   247  		// tests.
   248  		if _, ok := aliasMap[node.Alias]; ok {
   249  			return nil, errors.New("aliases for nodes " +
   250  				"must be unique!")
   251  		}
   252  
   253  		// If the alias is unique, then add the node to the alias map
   254  		// for easy lookup.
   255  		aliasMap[node.Alias] = dbNode.PubKeyBytes
   256  
   257  		// private keys are needed for signing error messages. If set
   258  		// check the consistency with the public key.
   259  		privBytes, err := hex.DecodeString(node.PrivKey)
   260  		if err != nil {
   261  			return nil, err
   262  		}
   263  		if len(privBytes) > 0 {
   264  			key := secp256k1.PrivKeyFromBytes(
   265  				privBytes,
   266  			)
   267  			derivedPub := key.PubKey()
   268  
   269  			if !bytes.Equal(
   270  				pubBytes, derivedPub.SerializeCompressed(),
   271  			) {
   272  
   273  				return nil, fmt.Errorf("%s public key and "+
   274  					"private key are inconsistent\n"+
   275  					"got  %x\nwant %x\n",
   276  					node.Alias,
   277  					derivedPub.SerializeCompressed(),
   278  					pubBytes,
   279  				)
   280  			}
   281  
   282  			privKeyMap[node.Alias] = key
   283  		}
   284  
   285  		// If the node is tagged as the source, then we create a
   286  		// pointer to is so we can mark the source in the graph
   287  		// properly.
   288  		if node.Source {
   289  			// If we come across a node that's marked as the
   290  			// source, and we've already set the source in a prior
   291  			// iteration, then the JSON has an error as only ONE
   292  			// node can be the source in the graph.
   293  			if source != nil {
   294  				return nil, errors.New("JSON is invalid " +
   295  					"multiple nodes are tagged as the " +
   296  					"source")
   297  			}
   298  
   299  			source = dbNode
   300  		}
   301  
   302  		// With the node fully parsed, add it as a vertex within the
   303  		// graph.
   304  		if err := graph.AddLightningNode(dbNode); err != nil {
   305  			return nil, err
   306  		}
   307  	}
   308  
   309  	if source != nil {
   310  		// Set the selected source node
   311  		if err := graph.SetSourceNode(source); err != nil {
   312  			return nil, err
   313  		}
   314  	}
   315  
   316  	aliasForNode := func(node route.Vertex) string {
   317  		for alias, pubKey := range aliasMap {
   318  			if pubKey == node {
   319  				return alias
   320  			}
   321  		}
   322  
   323  		return ""
   324  	}
   325  
   326  	// With all the vertexes inserted, we can now insert the edges into the
   327  	// test graph.
   328  	for _, edge := range g.Edges {
   329  		node1Bytes, err := hex.DecodeString(edge.Node1)
   330  		if err != nil {
   331  			return nil, err
   332  		}
   333  
   334  		node2Bytes, err := hex.DecodeString(edge.Node2)
   335  		if err != nil {
   336  			return nil, err
   337  		}
   338  
   339  		if bytes.Compare(node1Bytes, node2Bytes) == 1 {
   340  			return nil, fmt.Errorf(
   341  				"channel %v node order incorrect",
   342  				edge.ChannelID,
   343  			)
   344  		}
   345  
   346  		fundingTXID := strings.Split(edge.ChannelPoint, ":")[0]
   347  		txidBytes, err := chainhash.NewHashFromStr(fundingTXID)
   348  		if err != nil {
   349  			return nil, err
   350  		}
   351  		fundingPoint := wire.OutPoint{
   352  			Hash:  *txidBytes,
   353  			Index: 0,
   354  		}
   355  
   356  		// We first insert the existence of the edge between the two
   357  		// nodes.
   358  		edgeInfo := channeldb.ChannelEdgeInfo{
   359  			ChannelID:    edge.ChannelID,
   360  			AuthProof:    &testAuthProof,
   361  			ChannelPoint: fundingPoint,
   362  			Capacity:     dcrutil.Amount(edge.Capacity),
   363  		}
   364  
   365  		copy(edgeInfo.NodeKey1Bytes[:], node1Bytes)
   366  		copy(edgeInfo.NodeKey2Bytes[:], node2Bytes)
   367  		copy(edgeInfo.DecredKey1Bytes[:], node1Bytes)
   368  		copy(edgeInfo.DecredKey2Bytes[:], node2Bytes)
   369  
   370  		shortID := lnwire.NewShortChanIDFromInt(edge.ChannelID)
   371  		links[shortID] = &mockLink{
   372  			bandwidth: lnwire.MilliAtom(
   373  				edgeInfo.Capacity * 1000,
   374  			),
   375  		}
   376  
   377  		err = graph.AddChannelEdge(&edgeInfo)
   378  		if err != nil && err != channeldb.ErrEdgeAlreadyExist {
   379  			return nil, err
   380  		}
   381  
   382  		channelFlags := lnwire.ChanUpdateChanFlags(edge.ChannelFlags)
   383  		isUpdate1 := channelFlags&lnwire.ChanUpdateDirection == 0
   384  		targetNode := edgeInfo.NodeKey1Bytes
   385  		if isUpdate1 {
   386  			targetNode = edgeInfo.NodeKey2Bytes
   387  		}
   388  
   389  		edgePolicy := &channeldb.ChannelEdgePolicy{
   390  			SigBytes:                  testSig.Serialize(),
   391  			MessageFlags:              lnwire.ChanUpdateMsgFlags(edge.MessageFlags),
   392  			ChannelFlags:              channelFlags,
   393  			ChannelID:                 edge.ChannelID,
   394  			LastUpdate:                testTime,
   395  			TimeLockDelta:             edge.Expiry,
   396  			MinHTLC:                   lnwire.MilliAtom(edge.MinHTLC),
   397  			MaxHTLC:                   lnwire.MilliAtom(edge.MaxHTLC),
   398  			FeeBaseMAtoms:             lnwire.MilliAtom(edge.FeeBaseMAtoms),
   399  			FeeProportionalMillionths: lnwire.MilliAtom(edge.FeeRate),
   400  			Node: &channeldb.LightningNode{
   401  				Alias:       aliasForNode(targetNode),
   402  				PubKeyBytes: targetNode,
   403  			},
   404  		}
   405  		if err := graph.UpdateEdgePolicy(edgePolicy); err != nil {
   406  			return nil, err
   407  		}
   408  
   409  		// We also store the channel IDs info for each of the node.
   410  		node1Vertex, err := route.NewVertexFromBytes(node1Bytes)
   411  		if err != nil {
   412  			return nil, err
   413  		}
   414  
   415  		node2Vertex, err := route.NewVertexFromBytes(node2Bytes)
   416  		if err != nil {
   417  			return nil, err
   418  		}
   419  
   420  		if _, ok := channelIDs[node1Vertex]; !ok {
   421  			channelIDs[node1Vertex] = map[route.Vertex]uint64{}
   422  		}
   423  		channelIDs[node1Vertex][node2Vertex] = edge.ChannelID
   424  
   425  		if _, ok := channelIDs[node2Vertex]; !ok {
   426  			channelIDs[node2Vertex] = map[route.Vertex]uint64{}
   427  		}
   428  		channelIDs[node2Vertex][node1Vertex] = edge.ChannelID
   429  	}
   430  
   431  	return &testGraphInstance{
   432  		graph:        graph,
   433  		graphBackend: graphBackend,
   434  		cleanUp:      cleanUp,
   435  		aliasMap:     aliasMap,
   436  		privKeyMap:   privKeyMap,
   437  		channelIDs:   channelIDs,
   438  		links:        links,
   439  	}, nil
   440  }
   441  
   442  type testChannelPolicy struct {
   443  	Expiry        uint16
   444  	MinHTLC       lnwire.MilliAtom
   445  	MaxHTLC       lnwire.MilliAtom
   446  	FeeBaseMAtoms lnwire.MilliAtom
   447  	FeeRate       lnwire.MilliAtom
   448  	LastUpdate    time.Time
   449  	Disabled      bool
   450  	Features      *lnwire.FeatureVector
   451  }
   452  
   453  type testChannelEnd struct {
   454  	Alias string
   455  	*testChannelPolicy
   456  }
   457  
   458  func symmetricTestChannel(alias1, alias2 string, capacity dcrutil.Amount,
   459  	policy *testChannelPolicy, chanID ...uint64) *testChannel {
   460  
   461  	// Leaving id zero will result in auto-generation of a channel id during
   462  	// graph construction.
   463  	var id uint64
   464  	if len(chanID) > 0 {
   465  		id = chanID[0]
   466  	}
   467  
   468  	policy2 := *policy
   469  
   470  	return asymmetricTestChannel(
   471  		alias1, alias2, capacity, policy, &policy2, id,
   472  	)
   473  }
   474  
   475  func asymmetricTestChannel(alias1, alias2 string, capacity dcrutil.Amount,
   476  	policy1, policy2 *testChannelPolicy, id uint64) *testChannel {
   477  
   478  	return &testChannel{
   479  		Capacity: capacity,
   480  		Node1: &testChannelEnd{
   481  			Alias:             alias1,
   482  			testChannelPolicy: policy1,
   483  		},
   484  		Node2: &testChannelEnd{
   485  			Alias:             alias2,
   486  			testChannelPolicy: policy2,
   487  		},
   488  		ChannelID: id,
   489  	}
   490  }
   491  
   492  type testChannel struct {
   493  	Node1     *testChannelEnd
   494  	Node2     *testChannelEnd
   495  	Capacity  dcrutil.Amount
   496  	ChannelID uint64
   497  }
   498  
   499  type testGraphInstance struct {
   500  	graph        *channeldb.ChannelGraph
   501  	graphBackend kvdb.Backend
   502  	cleanUp      func()
   503  
   504  	// aliasMap is a map from a node's alias to its public key. This type is
   505  	// provided in order to allow easily look up from the human memorable alias
   506  	// to an exact node's public key.
   507  	aliasMap map[string]route.Vertex
   508  
   509  	// privKeyMap maps a node alias to its private key. This is used to be
   510  	// able to mock a remote node's signing behaviour.
   511  	privKeyMap map[string]*secp256k1.PrivateKey
   512  
   513  	// channelIDs stores the channel ID for each node.
   514  	channelIDs map[route.Vertex]map[route.Vertex]uint64
   515  
   516  	// links maps channel ids to a mock channel update handler.
   517  	links map[lnwire.ShortChannelID]htlcswitch.ChannelLink
   518  }
   519  
   520  // getLink is a mocked link lookup function which looks up links in our test
   521  // graph.
   522  func (g *testGraphInstance) getLink(chanID lnwire.ShortChannelID) (
   523  	htlcswitch.ChannelLink, error) {
   524  
   525  	link, ok := g.links[chanID]
   526  	if !ok {
   527  		return nil, fmt.Errorf("link not found in mock: %v", chanID)
   528  	}
   529  
   530  	return link, nil
   531  }
   532  
   533  // createTestGraphFromChannels returns a fully populated ChannelGraph based on a set of
   534  // test channels. Additional required information like keys are derived in
   535  // a deterministical way and added to the channel graph. A list of nodes is
   536  // not required and derived from the channel data. The goal is to keep
   537  // instantiating a test channel graph as light weight as possible.
   538  func createTestGraphFromChannels(useCache bool, testChannels []*testChannel,
   539  	source string) (*testGraphInstance, error) {
   540  
   541  	// We'll use this fake address for the IP address of all the nodes in
   542  	// our tests. This value isn't needed for path finding so it doesn't
   543  	// need to be unique.
   544  	var testAddrs []net.Addr
   545  	testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888")
   546  	if err != nil {
   547  		return nil, err
   548  	}
   549  	testAddrs = append(testAddrs, testAddr)
   550  
   551  	// Next, create a temporary graph database for usage within the test.
   552  	graph, graphBackend, cleanUp, err := makeTestGraph(useCache)
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  
   557  	aliasMap := make(map[string]route.Vertex)
   558  	privKeyMap := make(map[string]*secp256k1.PrivateKey)
   559  
   560  	nodeIndex := byte(0)
   561  	addNodeWithAlias := func(alias string, features *lnwire.FeatureVector) (
   562  		*channeldb.LightningNode, error) {
   563  
   564  		keyBytes := []byte{
   565  			0, 0, 0, 0, 0, 0, 0, 0,
   566  			0, 0, 0, 0, 0, 0, 0, 0,
   567  			0, 0, 0, 0, 0, 0, 0, 0,
   568  			0, 0, 0, 0, 0, 0, 0, nodeIndex + 1,
   569  		}
   570  
   571  		privKey := secp256k1.PrivKeyFromBytes(keyBytes)
   572  		pubKey := privKey.PubKey()
   573  
   574  		if features == nil {
   575  			features = lnwire.EmptyFeatureVector()
   576  		}
   577  
   578  		dbNode := &channeldb.LightningNode{
   579  			HaveNodeAnnouncement: true,
   580  			AuthSigBytes:         testSig.Serialize(),
   581  			LastUpdate:           testTime,
   582  			Addresses:            testAddrs,
   583  			Alias:                alias,
   584  			Features:             features,
   585  		}
   586  
   587  		copy(dbNode.PubKeyBytes[:], pubKey.SerializeCompressed())
   588  
   589  		privKeyMap[alias] = privKey
   590  
   591  		// With the node fully parsed, add it as a vertex within the
   592  		// graph.
   593  		if err := graph.AddLightningNode(dbNode); err != nil {
   594  			return nil, err
   595  		}
   596  
   597  		aliasMap[alias] = dbNode.PubKeyBytes
   598  		nodeIndex++
   599  
   600  		return dbNode, nil
   601  	}
   602  
   603  	// Add the source node.
   604  	dbNode, err := addNodeWithAlias(source, lnwire.EmptyFeatureVector())
   605  	if err != nil {
   606  		return nil, err
   607  	}
   608  
   609  	if err = graph.SetSourceNode(dbNode); err != nil {
   610  		return nil, err
   611  	}
   612  
   613  	// Initialize variable that keeps track of the next channel id to assign
   614  	// if none is specified.
   615  	nextUnassignedChannelID := uint64(100000)
   616  
   617  	links := make(map[lnwire.ShortChannelID]htlcswitch.ChannelLink)
   618  
   619  	for _, testChannel := range testChannels {
   620  		for _, node := range []*testChannelEnd{
   621  			testChannel.Node1, testChannel.Node2} {
   622  
   623  			_, exists := aliasMap[node.Alias]
   624  			if !exists {
   625  				var features *lnwire.FeatureVector
   626  				if node.testChannelPolicy != nil {
   627  					features =
   628  						node.testChannelPolicy.Features
   629  				}
   630  				_, err := addNodeWithAlias(
   631  					node.Alias, features,
   632  				)
   633  				if err != nil {
   634  					return nil, err
   635  				}
   636  			}
   637  		}
   638  
   639  		channelID := testChannel.ChannelID
   640  
   641  		// If no channel id is specified, generate an id.
   642  		if channelID == 0 {
   643  			channelID = nextUnassignedChannelID
   644  			nextUnassignedChannelID++
   645  		}
   646  
   647  		var hash [sha256.Size]byte
   648  		hash[len(hash)-1] = byte(channelID)
   649  
   650  		fundingPoint := &wire.OutPoint{
   651  			Hash:  chainhash.Hash(hash),
   652  			Index: 0,
   653  		}
   654  
   655  		capacity := lnwire.MilliAtom(testChannel.Capacity * 1000)
   656  		shortID := lnwire.NewShortChanIDFromInt(channelID)
   657  		links[shortID] = &mockLink{
   658  			bandwidth: capacity,
   659  		}
   660  
   661  		// Sort nodes
   662  		node1 := testChannel.Node1
   663  		node2 := testChannel.Node2
   664  		node1Vertex := aliasMap[node1.Alias]
   665  		node2Vertex := aliasMap[node2.Alias]
   666  		if bytes.Compare(node1Vertex[:], node2Vertex[:]) == 1 {
   667  			node1, node2 = node2, node1
   668  			node1Vertex, node2Vertex = node2Vertex, node1Vertex
   669  		}
   670  
   671  		// We first insert the existence of the edge between the two
   672  		// nodes.
   673  		edgeInfo := channeldb.ChannelEdgeInfo{
   674  			ChannelID:    channelID,
   675  			AuthProof:    &testAuthProof,
   676  			ChannelPoint: *fundingPoint,
   677  			Capacity:     testChannel.Capacity,
   678  
   679  			NodeKey1Bytes:   node1Vertex,
   680  			DecredKey1Bytes: node1Vertex,
   681  			NodeKey2Bytes:   node2Vertex,
   682  			DecredKey2Bytes: node2Vertex,
   683  		}
   684  
   685  		err = graph.AddChannelEdge(&edgeInfo)
   686  		if err != nil && err != channeldb.ErrEdgeAlreadyExist {
   687  			return nil, err
   688  		}
   689  
   690  		if node1.testChannelPolicy != nil {
   691  			var msgFlags lnwire.ChanUpdateMsgFlags
   692  			if node1.MaxHTLC != 0 {
   693  				msgFlags |= lnwire.ChanUpdateOptionMaxHtlc
   694  			}
   695  			var channelFlags lnwire.ChanUpdateChanFlags
   696  			if node1.Disabled {
   697  				channelFlags |= lnwire.ChanUpdateDisabled
   698  			}
   699  
   700  			node2Features := lnwire.EmptyFeatureVector()
   701  			if node2.testChannelPolicy != nil {
   702  				node2Features = node2.Features
   703  			}
   704  
   705  			edgePolicy := &channeldb.ChannelEdgePolicy{
   706  				SigBytes:                  testSig.Serialize(),
   707  				MessageFlags:              msgFlags,
   708  				ChannelFlags:              channelFlags,
   709  				ChannelID:                 channelID,
   710  				LastUpdate:                node1.LastUpdate,
   711  				TimeLockDelta:             node1.Expiry,
   712  				MinHTLC:                   node1.MinHTLC,
   713  				MaxHTLC:                   node1.MaxHTLC,
   714  				FeeBaseMAtoms:             node1.FeeBaseMAtoms,
   715  				FeeProportionalMillionths: node1.FeeRate,
   716  				Node: &channeldb.LightningNode{
   717  					Alias:       node2.Alias,
   718  					PubKeyBytes: node2Vertex,
   719  					Features:    node2Features,
   720  				},
   721  			}
   722  			if err := graph.UpdateEdgePolicy(edgePolicy); err != nil {
   723  				return nil, err
   724  			}
   725  		}
   726  
   727  		if node2.testChannelPolicy != nil {
   728  			var msgFlags lnwire.ChanUpdateMsgFlags
   729  			if node2.MaxHTLC != 0 {
   730  				msgFlags |= lnwire.ChanUpdateOptionMaxHtlc
   731  			}
   732  			var channelFlags lnwire.ChanUpdateChanFlags
   733  			if node2.Disabled {
   734  				channelFlags |= lnwire.ChanUpdateDisabled
   735  			}
   736  			channelFlags |= lnwire.ChanUpdateDirection
   737  
   738  			node1Features := lnwire.EmptyFeatureVector()
   739  			if node1.testChannelPolicy != nil {
   740  				node1Features = node1.Features
   741  			}
   742  
   743  			edgePolicy := &channeldb.ChannelEdgePolicy{
   744  				SigBytes:                  testSig.Serialize(),
   745  				MessageFlags:              msgFlags,
   746  				ChannelFlags:              channelFlags,
   747  				ChannelID:                 channelID,
   748  				LastUpdate:                node2.LastUpdate,
   749  				TimeLockDelta:             node2.Expiry,
   750  				MinHTLC:                   node2.MinHTLC,
   751  				MaxHTLC:                   node2.MaxHTLC,
   752  				FeeBaseMAtoms:             node2.FeeBaseMAtoms,
   753  				FeeProportionalMillionths: node2.FeeRate,
   754  				Node: &channeldb.LightningNode{
   755  					Alias:       node1.Alias,
   756  					PubKeyBytes: node1Vertex,
   757  					Features:    node1Features,
   758  				},
   759  			}
   760  			if err := graph.UpdateEdgePolicy(edgePolicy); err != nil {
   761  				return nil, err
   762  			}
   763  		}
   764  	}
   765  
   766  	return &testGraphInstance{
   767  		graph:        graph,
   768  		graphBackend: graphBackend,
   769  		cleanUp:      cleanUp,
   770  		aliasMap:     aliasMap,
   771  		privKeyMap:   privKeyMap,
   772  		links:        links,
   773  	}, nil
   774  }
   775  
   776  // TestPathFinding tests all path finding related cases both with the in-memory
   777  // graph cached turned on and off.
   778  func TestPathFinding(t *testing.T) {
   779  	testCases := []struct {
   780  		name string
   781  		fn   func(t *testing.T, useCache bool)
   782  	}{{
   783  		name: "lowest fee path",
   784  		fn:   runFindLowestFeePath,
   785  	}, {
   786  		name: "basic graph path finding",
   787  		fn:   runBasicGraphPathFinding,
   788  	}, {
   789  		name: "path finding with additional edges",
   790  		fn:   runPathFindingWithAdditionalEdges,
   791  	}, {
   792  		name: "new route path too long",
   793  		fn:   runNewRoutePathTooLong,
   794  	}, {
   795  		name: "path not available",
   796  		fn:   runPathNotAvailable,
   797  	}, {
   798  		name: "destination tlv graph fallback",
   799  		fn:   runDestTLVGraphFallback,
   800  	}, {
   801  		name: "missing feature dependency",
   802  		fn:   runMissingFeatureDep,
   803  	}, {
   804  		name: "unknown required features",
   805  		fn:   runUnknownRequiredFeatures,
   806  	}, {
   807  		name: "destination payment address",
   808  		fn:   runDestPaymentAddr,
   809  	}, {
   810  		name: "path insufficient capacity",
   811  		fn:   runPathInsufficientCapacity,
   812  	}, {
   813  		name: "route fail min HTLC",
   814  		fn:   runRouteFailMinHTLC,
   815  	}, {
   816  		name: "route fail max HTLC",
   817  		fn:   runRouteFailMaxHTLC,
   818  	}, {
   819  		name: "route fail disabled edge",
   820  		fn:   runRouteFailDisabledEdge,
   821  	}, {
   822  		name: "path source edges bandwidth",
   823  		fn:   runPathSourceEdgesBandwidth,
   824  	}, {
   825  		name: "restrict outgoing channel",
   826  		fn:   runRestrictOutgoingChannel,
   827  	}, {
   828  		name: "restrict last hop",
   829  		fn:   runRestrictLastHop,
   830  	}, {
   831  		name: "CLTV limit",
   832  		fn:   runCltvLimit,
   833  	}, {
   834  		name: "probability routing",
   835  		fn:   runProbabilityRouting,
   836  	}, {
   837  		name: "equal cost route selection",
   838  		fn:   runEqualCostRouteSelection,
   839  	}, {
   840  		name: "no cycle",
   841  		fn:   runNoCycle,
   842  	}, {
   843  		name: "route to self",
   844  		fn:   runRouteToSelf,
   845  	}}
   846  
   847  	// Run with graph cache enabled.
   848  	for _, tc := range testCases {
   849  		tc := tc
   850  
   851  		t.Run("cache=true/"+tc.name, func(tt *testing.T) {
   852  			tt.Parallel()
   853  
   854  			tc.fn(tt, true)
   855  		})
   856  	}
   857  
   858  	// And with the DB fallback to make sure everything works the same
   859  	// still.
   860  	for _, tc := range testCases {
   861  		tc := tc
   862  
   863  		t.Run("cache=false/"+tc.name, func(tt *testing.T) {
   864  			tt.Parallel()
   865  
   866  			tc.fn(tt, false)
   867  		})
   868  	}
   869  }
   870  
   871  // runFindLowestFeePath tests that out of two routes with identical total
   872  // time lock values, the route with the lowest total fee should be returned.
   873  // The fee rates are chosen such that the test failed on the previous edge
   874  // weight function where one of the terms was fee squared.
   875  func runFindLowestFeePath(t *testing.T, useCache bool) {
   876  	// Set up a test graph with two paths from roasbeef to target. Both
   877  	// paths have equal total time locks, but the path through b has lower
   878  	// fees (700 compared to 800 for the path through a).
   879  	testChannels := []*testChannel{
   880  		symmetricTestChannel("roasbeef", "first", 100000, &testChannelPolicy{
   881  			Expiry:  144,
   882  			FeeRate: 400,
   883  			MinHTLC: 1,
   884  			MaxHTLC: 100000000,
   885  		}),
   886  		symmetricTestChannel("first", "a", 100000, &testChannelPolicy{
   887  			Expiry:  144,
   888  			FeeRate: 400,
   889  			MinHTLC: 1,
   890  			MaxHTLC: 100000000,
   891  		}),
   892  		symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
   893  			Expiry:  144,
   894  			FeeRate: 400,
   895  			MinHTLC: 1,
   896  			MaxHTLC: 100000000,
   897  		}),
   898  		symmetricTestChannel("first", "b", 100000, &testChannelPolicy{
   899  			Expiry:  144,
   900  			FeeRate: 100,
   901  			MinHTLC: 1,
   902  			MaxHTLC: 100000000,
   903  		}),
   904  		symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
   905  			Expiry:  144,
   906  			FeeRate: 600,
   907  			MinHTLC: 1,
   908  			MaxHTLC: 100000000,
   909  		}),
   910  	}
   911  
   912  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
   913  	defer ctx.cleanup()
   914  
   915  	const (
   916  		startingHeight = 100
   917  		finalHopCLTV   = 1
   918  	)
   919  
   920  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
   921  	target := ctx.keyFromAlias("target")
   922  	path, err := ctx.findPath(target, paymentAmt)
   923  	if err != nil {
   924  		t.Fatalf("unable to find path: %v", err)
   925  	}
   926  	route, err := newRoute(
   927  		ctx.source, path, startingHeight,
   928  		finalHopParams{
   929  			amt:       paymentAmt,
   930  			cltvDelta: finalHopCLTV,
   931  			records:   nil,
   932  		},
   933  	)
   934  	if err != nil {
   935  		t.Fatalf("unable to create path: %v", err)
   936  	}
   937  
   938  	// Assert that the lowest fee route is returned.
   939  	if route.Hops[1].PubKeyBytes != ctx.keyFromAlias("b") {
   940  		t.Fatalf("expected route to pass through b, "+
   941  			"but got a route through %v",
   942  			ctx.aliasFromKey(route.Hops[1].PubKeyBytes))
   943  	}
   944  }
   945  
   946  func getAliasFromPubKey(pubKey route.Vertex,
   947  	aliases map[string]route.Vertex) string {
   948  
   949  	for alias, key := range aliases {
   950  		if bytes.Equal(key[:], pubKey[:]) {
   951  			return alias
   952  		}
   953  	}
   954  	return ""
   955  }
   956  
   957  type expectedHop struct {
   958  	alias     string
   959  	fee       lnwire.MilliAtom
   960  	fwdAmount lnwire.MilliAtom
   961  	timeLock  uint32
   962  }
   963  
   964  type basicGraphPathFindingTestCase struct {
   965  	target                string
   966  	paymentAmt            dcrutil.Amount
   967  	feeLimit              lnwire.MilliAtom
   968  	expectedTotalAmt      lnwire.MilliAtom
   969  	expectedTotalTimeLock uint32
   970  	expectedHops          []expectedHop
   971  	expectFailureNoPath   bool
   972  }
   973  
   974  var basicGraphPathFindingTests = []basicGraphPathFindingTestCase{
   975  	// Basic route with one intermediate hop.
   976  	{target: "sophon", paymentAmt: 100, feeLimit: noFeeLimit,
   977  		expectedTotalTimeLock: 102, expectedTotalAmt: 100110,
   978  		expectedHops: []expectedHop{
   979  			{alias: "songoku", fwdAmount: 100000, fee: 110, timeLock: 101},
   980  			{alias: "sophon", fwdAmount: 100000, fee: 0, timeLock: 101},
   981  		}},
   982  
   983  	// Basic direct (one hop) route.
   984  	{target: "luoji", paymentAmt: 100, feeLimit: noFeeLimit,
   985  		expectedTotalTimeLock: 101, expectedTotalAmt: 100000,
   986  		expectedHops: []expectedHop{
   987  			{alias: "luoji", fwdAmount: 100000, fee: 0, timeLock: 101},
   988  		}},
   989  
   990  	// Three hop route where fees need to be added in to the forwarding amount.
   991  	// The high fee hop phamnewun should be avoided.
   992  	{target: "elst", paymentAmt: 50000, feeLimit: noFeeLimit,
   993  		expectedTotalTimeLock: 103, expectedTotalAmt: 50050210,
   994  		expectedHops: []expectedHop{
   995  			{alias: "songoku", fwdAmount: 50000200, fee: 50010, timeLock: 102},
   996  			{alias: "sophon", fwdAmount: 50000000, fee: 200, timeLock: 101},
   997  			{alias: "elst", fwdAmount: 50000000, fee: 0, timeLock: 101},
   998  		}},
   999  	// Three hop route where fees need to be added in to the forwarding amount.
  1000  	// However this time the fwdAmount becomes too large for the roasbeef <->
  1001  	// songoku channel. Then there is no other option than to choose the
  1002  	// expensive phamnuwen channel. This test case was failing before
  1003  	// the route search was executed backwards.
  1004  	{target: "elst", paymentAmt: 100000, feeLimit: noFeeLimit,
  1005  		expectedTotalTimeLock: 103, expectedTotalAmt: 110010220,
  1006  		expectedHops: []expectedHop{
  1007  			{alias: "phamnuwen", fwdAmount: 100000200, fee: 10010020, timeLock: 102},
  1008  			{alias: "sophon", fwdAmount: 100000000, fee: 200, timeLock: 101},
  1009  			{alias: "elst", fwdAmount: 100000000, fee: 0, timeLock: 101},
  1010  		}},
  1011  
  1012  	// Basic route with fee limit.
  1013  	{target: "sophon", paymentAmt: 100, feeLimit: 50,
  1014  		expectFailureNoPath: true,
  1015  	}}
  1016  
  1017  func runBasicGraphPathFinding(t *testing.T, useCache bool) {
  1018  	testGraphInstance, err := parseTestGraph(useCache, basicGraphFilePath)
  1019  	if err != nil {
  1020  		t.Fatalf("unable to create graph: %v", err)
  1021  	}
  1022  	defer testGraphInstance.cleanUp()
  1023  
  1024  	// With the test graph loaded, we'll test some basic path finding using
  1025  	// the pre-generated graph. Consult the testdata/basic_graph.json file
  1026  	// to follow along with the assumptions we'll use to test the path
  1027  	// finding.
  1028  
  1029  	for _, testCase := range basicGraphPathFindingTests {
  1030  		t.Run(testCase.target, func(subT *testing.T) {
  1031  			testBasicGraphPathFindingCase(subT, testGraphInstance, &testCase)
  1032  		})
  1033  	}
  1034  }
  1035  
  1036  func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstance,
  1037  	test *basicGraphPathFindingTestCase) {
  1038  
  1039  	aliases := graphInstance.aliasMap
  1040  	expectedHops := test.expectedHops
  1041  	expectedHopCount := len(expectedHops)
  1042  
  1043  	sourceNode, err := graphInstance.graph.SourceNode()
  1044  	if err != nil {
  1045  		t.Fatalf("unable to fetch source node: %v", err)
  1046  	}
  1047  	sourceVertex := route.Vertex(sourceNode.PubKeyBytes)
  1048  
  1049  	const (
  1050  		startingHeight = 100
  1051  		finalHopCLTV   = 1
  1052  	)
  1053  
  1054  	paymentAmt := lnwire.NewMAtomsFromAtoms(test.paymentAmt)
  1055  	target := graphInstance.aliasMap[test.target]
  1056  	path, err := dbFindPath(
  1057  		graphInstance.graph, nil, &mockBandwidthHints{},
  1058  		&RestrictParams{
  1059  			FeeLimit:          test.feeLimit,
  1060  			ProbabilitySource: noProbabilitySource,
  1061  			CltvLimit:         math.MaxUint32,
  1062  		},
  1063  		testPathFindingConfig,
  1064  		sourceNode.PubKeyBytes, target, paymentAmt,
  1065  		startingHeight+finalHopCLTV,
  1066  	)
  1067  	if test.expectFailureNoPath {
  1068  		if err == nil {
  1069  			t.Fatal("expected no path to be found")
  1070  		}
  1071  		return
  1072  	}
  1073  	if err != nil {
  1074  		t.Fatalf("unable to find path: %v", err)
  1075  	}
  1076  
  1077  	route, err := newRoute(
  1078  		sourceVertex, path, startingHeight,
  1079  		finalHopParams{
  1080  			amt:       paymentAmt,
  1081  			cltvDelta: finalHopCLTV,
  1082  			records:   nil,
  1083  		},
  1084  	)
  1085  	if err != nil {
  1086  		t.Fatalf("unable to create path: %v", err)
  1087  	}
  1088  
  1089  	if len(route.Hops) != len(expectedHops) {
  1090  		t.Fatalf("route is of incorrect length, expected %v got %v",
  1091  			expectedHopCount, len(route.Hops))
  1092  	}
  1093  
  1094  	// Check hop nodes
  1095  	for i := 0; i < len(expectedHops); i++ {
  1096  		if route.Hops[i].PubKeyBytes != aliases[expectedHops[i].alias] {
  1097  
  1098  			t.Fatalf("%v-th hop should be %v, is instead: %v",
  1099  				i, expectedHops[i],
  1100  				getAliasFromPubKey(route.Hops[i].PubKeyBytes,
  1101  					aliases))
  1102  		}
  1103  	}
  1104  
  1105  	// Next, we'll assert that the "next hop" field in each route payload
  1106  	// properly points to the channel ID that the HTLC should be forwarded
  1107  	// along.
  1108  	sphinxPath, err := route.ToSphinxPath()
  1109  	if err != nil {
  1110  		t.Fatalf("unable to make sphinx path: %v", err)
  1111  	}
  1112  	if sphinxPath.TrueRouteLength() != expectedHopCount {
  1113  		t.Fatalf("incorrect number of hop payloads: expected %v, got %v",
  1114  			expectedHopCount, sphinxPath.TrueRouteLength())
  1115  	}
  1116  
  1117  	// Hops should point to the next hop
  1118  	for i := 0; i < len(expectedHops)-1; i++ {
  1119  		var expectedHop [8]byte
  1120  		binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].ChannelID)
  1121  
  1122  		hopData, err := sphinxPath[i].HopPayload.HopData()
  1123  		if err != nil {
  1124  			t.Fatalf("unable to make hop data: %v", err)
  1125  		}
  1126  
  1127  		if !bytes.Equal(hopData.NextAddress[:], expectedHop[:]) {
  1128  			t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
  1129  				expectedHop[:], hopData.NextAddress[:])
  1130  		}
  1131  	}
  1132  
  1133  	// The final hop should have a next hop value of all zeroes in order
  1134  	// to indicate it's the exit hop.
  1135  	var exitHop [8]byte
  1136  	lastHopIndex := len(expectedHops) - 1
  1137  
  1138  	hopData, err := sphinxPath[lastHopIndex].HopPayload.HopData()
  1139  	if err != nil {
  1140  		t.Fatalf("unable to create hop data: %v", err)
  1141  	}
  1142  
  1143  	if !bytes.Equal(hopData.NextAddress[:], exitHop[:]) {
  1144  		t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
  1145  			exitHop[:], hopData.NextAddress)
  1146  	}
  1147  
  1148  	var expectedTotalFee lnwire.MilliAtom
  1149  	for i := 0; i < expectedHopCount; i++ {
  1150  		// We'll ensure that the amount to forward, and fees
  1151  		// computed for each hop are correct.
  1152  
  1153  		fee := route.HopFee(i)
  1154  		if fee != expectedHops[i].fee {
  1155  			t.Fatalf("fee incorrect for hop %v: expected %v, got %v",
  1156  				i, expectedHops[i].fee, fee)
  1157  		}
  1158  
  1159  		if route.Hops[i].AmtToForward != expectedHops[i].fwdAmount {
  1160  			t.Fatalf("forwarding amount for hop %v incorrect: "+
  1161  				"expected %v, got %v",
  1162  				i, expectedHops[i].fwdAmount,
  1163  				route.Hops[i].AmtToForward)
  1164  		}
  1165  
  1166  		// We'll also assert that the outgoing CLTV value for each
  1167  		// hop was set accordingly.
  1168  		if route.Hops[i].OutgoingTimeLock != expectedHops[i].timeLock {
  1169  			t.Fatalf("outgoing time-lock for hop %v is incorrect: "+
  1170  				"expected %v, got %v", i,
  1171  				expectedHops[i].timeLock,
  1172  				route.Hops[i].OutgoingTimeLock)
  1173  		}
  1174  
  1175  		expectedTotalFee += expectedHops[i].fee
  1176  	}
  1177  
  1178  	if route.TotalAmount != test.expectedTotalAmt {
  1179  		t.Fatalf("total amount incorrect: "+
  1180  			"expected %v, got %v",
  1181  			test.expectedTotalAmt, route.TotalAmount)
  1182  	}
  1183  
  1184  	if route.TotalTimeLock != test.expectedTotalTimeLock {
  1185  		t.Fatalf("expected time lock of %v, instead have %v", 2,
  1186  			route.TotalTimeLock)
  1187  	}
  1188  }
  1189  
  1190  // runPathFindingWithAdditionalEdges asserts that we are able to find paths to
  1191  // nodes that do not exist in the graph by way of hop hints. We also test that
  1192  // the path can support custom TLV records for the receiver under the
  1193  // appropriate circumstances.
  1194  func runPathFindingWithAdditionalEdges(t *testing.T, useCache bool) {
  1195  	graph, err := parseTestGraph(useCache, basicGraphFilePath)
  1196  	if err != nil {
  1197  		t.Fatalf("unable to create graph: %v", err)
  1198  	}
  1199  	defer graph.cleanUp()
  1200  
  1201  	sourceNode, err := graph.graph.SourceNode()
  1202  	if err != nil {
  1203  		t.Fatalf("unable to fetch source node: %v", err)
  1204  	}
  1205  
  1206  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  1207  
  1208  	// In this test, we'll test that we're able to find paths through
  1209  	// private channels when providing them as additional edges in our path
  1210  	// finding algorithm. To do so, we'll create a new node, doge, and
  1211  	// create a private channel between it and songoku. We'll then attempt
  1212  	// to find a path from our source node, roasbeef, to doge.
  1213  	dogePubKeyHex := "03dd46ff29a6941b4a2607525b043ec9b020b3f318a1bf281536fd7011ec59c882"
  1214  	dogePubKeyBytes, err := hex.DecodeString(dogePubKeyHex)
  1215  	if err != nil {
  1216  		t.Fatalf("unable to decode public key: %v", err)
  1217  	}
  1218  	dogePubKey, err := secp256k1.ParsePubKey(dogePubKeyBytes)
  1219  	if err != nil {
  1220  		t.Fatalf("unable to parse public key from bytes: %v", err)
  1221  	}
  1222  
  1223  	doge := &channeldb.LightningNode{}
  1224  	doge.AddPubKey(dogePubKey)
  1225  	doge.Alias = "doge"
  1226  	copy(doge.PubKeyBytes[:], dogePubKeyBytes)
  1227  	graph.aliasMap["doge"] = doge.PubKeyBytes
  1228  
  1229  	// Create the channel edge going from songoku to doge and include it in
  1230  	// our map of additional edges.
  1231  	songokuToDoge := &channeldb.CachedEdgePolicy{
  1232  		ToNodePubKey: func() route.Vertex {
  1233  			return doge.PubKeyBytes
  1234  		},
  1235  		ToNodeFeatures:            lnwire.EmptyFeatureVector(),
  1236  		ChannelID:                 1337,
  1237  		FeeBaseMAtoms:             1,
  1238  		FeeProportionalMillionths: 1000,
  1239  		TimeLockDelta:             9,
  1240  	}
  1241  
  1242  	additionalEdges := map[route.Vertex][]*channeldb.CachedEdgePolicy{
  1243  		graph.aliasMap["songoku"]: {songokuToDoge},
  1244  	}
  1245  
  1246  	find := func(r *RestrictParams) (
  1247  		[]*channeldb.CachedEdgePolicy, error) {
  1248  
  1249  		return dbFindPath(
  1250  			graph.graph, additionalEdges, &mockBandwidthHints{},
  1251  			r, testPathFindingConfig,
  1252  			sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
  1253  			0,
  1254  		)
  1255  	}
  1256  
  1257  	// We should now be able to find a path from roasbeef to doge.
  1258  	path, err := find(noRestrictions)
  1259  	if err != nil {
  1260  		t.Fatalf("unable to find private path to doge: %v", err)
  1261  	}
  1262  
  1263  	// The path should represent the following hops:
  1264  	//	roasbeef -> songoku -> doge
  1265  	assertExpectedPath(t, graph.aliasMap, path, "songoku", "doge")
  1266  
  1267  	// Now, set custom records for the final hop. This should fail since no
  1268  	// dest features are set, and we won't have a node ann to fall back on.
  1269  	restrictions := *noRestrictions
  1270  	restrictions.DestCustomRecords = record.CustomSet{70000: []byte{}}
  1271  
  1272  	_, err = find(&restrictions)
  1273  	if err != errNoTlvPayload {
  1274  		t.Fatalf("path shouldn't have been found: %v", err)
  1275  	}
  1276  
  1277  	// Set empty dest features so we don't try the fallback. We should still
  1278  	// fail since the tlv feature isn't set.
  1279  	restrictions.DestFeatures = lnwire.EmptyFeatureVector()
  1280  
  1281  	_, err = find(&restrictions)
  1282  	if err != errNoTlvPayload {
  1283  		t.Fatalf("path shouldn't have been found: %v", err)
  1284  	}
  1285  
  1286  	// Finally, set the tlv feature in the payload and assert we found the
  1287  	// same path as before.
  1288  	restrictions.DestFeatures = tlvFeatures
  1289  
  1290  	path, err = find(&restrictions)
  1291  	if err != nil {
  1292  		t.Fatalf("path should have been found: %v", err)
  1293  	}
  1294  	assertExpectedPath(t, graph.aliasMap, path, "songoku", "doge")
  1295  }
  1296  
  1297  // TestNewRoute tests whether the construction of hop payloads by newRoute is
  1298  // executed correctly.
  1299  func TestNewRoute(t *testing.T) {
  1300  
  1301  	var sourceKey [33]byte
  1302  	sourceVertex := route.Vertex(sourceKey)
  1303  
  1304  	testPaymentAddr := [32]byte{0x01, 0x02, 0x03}
  1305  
  1306  	const (
  1307  		startingHeight = 100
  1308  		finalHopCLTV   = 1
  1309  	)
  1310  
  1311  	createHop := func(baseFee lnwire.MilliAtom,
  1312  		feeRate lnwire.MilliAtom,
  1313  		bandwidth lnwire.MilliAtom,
  1314  		timeLockDelta uint16) *channeldb.CachedEdgePolicy {
  1315  
  1316  		return &channeldb.CachedEdgePolicy{
  1317  			ToNodePubKey: func() route.Vertex {
  1318  				return route.Vertex{}
  1319  			},
  1320  			ToNodeFeatures:            lnwire.NewFeatureVector(nil, nil),
  1321  			FeeProportionalMillionths: feeRate,
  1322  			FeeBaseMAtoms:             baseFee,
  1323  			TimeLockDelta:             timeLockDelta,
  1324  		}
  1325  	}
  1326  
  1327  	testCases := []struct {
  1328  		// name identifies the test case in the test output.
  1329  		name string
  1330  
  1331  		// hops is the list of hops (the route) that gets passed into
  1332  		// the call to newRoute.
  1333  		hops []*channeldb.CachedEdgePolicy
  1334  
  1335  		// paymentAmount is the amount that is send into the route
  1336  		// indicated by hops.
  1337  		paymentAmount lnwire.MilliAtom
  1338  
  1339  		// destFeatures is a feature vector, that if non-nil, will
  1340  		// overwrite the final hop's feature vector in the graph.
  1341  		destFeatures *lnwire.FeatureVector
  1342  
  1343  		paymentAddr *[32]byte
  1344  
  1345  		// expectedFees is a list of fees that every hop is expected
  1346  		// to charge for forwarding.
  1347  		expectedFees []lnwire.MilliAtom
  1348  
  1349  		// expectedTimeLocks is a list of time lock values that every
  1350  		// hop is expected to specify in its outgoing HTLC. The time
  1351  		// lock values in this list are relative to the current block
  1352  		// height.
  1353  		expectedTimeLocks []uint32
  1354  
  1355  		// expectedTotalAmount is the total amount that is expected to
  1356  		// be returned from newRoute. This amount should include all
  1357  		// the fees to be paid to intermediate hops.
  1358  		expectedTotalAmount lnwire.MilliAtom
  1359  
  1360  		// expectedTotalTimeLock is the time lock that is expected to
  1361  		// be returned from newRoute. This is the time lock that should
  1362  		// be specified in the HTLC that is sent by the source node.
  1363  		// expectedTotalTimeLock is relative to the current block height.
  1364  		expectedTotalTimeLock uint32
  1365  
  1366  		// expectError indicates whether the newRoute call is expected
  1367  		// to fail or succeed.
  1368  		expectError bool
  1369  
  1370  		// expectedErrorCode indicates the expected error code when
  1371  		// expectError is true.
  1372  		expectedErrorCode errorCode
  1373  
  1374  		expectedTLVPayload bool
  1375  
  1376  		expectedMPP *record.MPP
  1377  	}{
  1378  		{
  1379  			// For a single hop payment, no fees are expected to be paid.
  1380  			name:          "single hop",
  1381  			paymentAmount: 100000,
  1382  			hops: []*channeldb.CachedEdgePolicy{
  1383  				createHop(100, 1000, 1000000, 10),
  1384  			},
  1385  			expectedFees:          []lnwire.MilliAtom{0},
  1386  			expectedTimeLocks:     []uint32{1},
  1387  			expectedTotalAmount:   100000,
  1388  			expectedTotalTimeLock: 1,
  1389  		}, {
  1390  			// For a two hop payment, only the fee for the first hop
  1391  			// needs to be paid. The destination hop does not require
  1392  			// a fee to receive the payment.
  1393  			name:          "two hop",
  1394  			paymentAmount: 100000,
  1395  			hops: []*channeldb.CachedEdgePolicy{
  1396  				createHop(0, 1000, 1000000, 10),
  1397  				createHop(30, 1000, 1000000, 5),
  1398  			},
  1399  			expectedFees:          []lnwire.MilliAtom{130, 0},
  1400  			expectedTimeLocks:     []uint32{1, 1},
  1401  			expectedTotalAmount:   100130,
  1402  			expectedTotalTimeLock: 6,
  1403  		}, {
  1404  			// For a two hop payment, only the fee for the first hop
  1405  			// needs to be paid. The destination hop does not require
  1406  			// a fee to receive the payment.
  1407  			name:          "two hop tlv onion feature",
  1408  			destFeatures:  tlvFeatures,
  1409  			paymentAmount: 100000,
  1410  			hops: []*channeldb.CachedEdgePolicy{
  1411  				createHop(0, 1000, 1000000, 10),
  1412  				createHop(30, 1000, 1000000, 5),
  1413  			},
  1414  			expectedFees:          []lnwire.MilliAtom{130, 0},
  1415  			expectedTimeLocks:     []uint32{1, 1},
  1416  			expectedTotalAmount:   100130,
  1417  			expectedTotalTimeLock: 6,
  1418  			expectedTLVPayload:    true,
  1419  		}, {
  1420  			// For a two hop payment, only the fee for the first hop
  1421  			// needs to be paid. The destination hop does not require
  1422  			// a fee to receive the payment.
  1423  			name:          "two hop single shot mpp",
  1424  			destFeatures:  tlvPayAddrFeatures,
  1425  			paymentAddr:   &testPaymentAddr,
  1426  			paymentAmount: 100000,
  1427  			hops: []*channeldb.CachedEdgePolicy{
  1428  				createHop(0, 1000, 1000000, 10),
  1429  				createHop(30, 1000, 1000000, 5),
  1430  			},
  1431  			expectedFees:          []lnwire.MilliAtom{130, 0},
  1432  			expectedTimeLocks:     []uint32{1, 1},
  1433  			expectedTotalAmount:   100130,
  1434  			expectedTotalTimeLock: 6,
  1435  			expectedTLVPayload:    true,
  1436  			expectedMPP: record.NewMPP(
  1437  				100000, testPaymentAddr,
  1438  			),
  1439  		}, {
  1440  			// A three hop payment where the first and second hop
  1441  			// will both charge 1 mat. The fee for the first hop
  1442  			// is actually slightly higher than 1, because the amount
  1443  			// to forward also includes the fee for the second hop. This
  1444  			// gets rounded down to 1.
  1445  			name:          "three hop",
  1446  			paymentAmount: 100000,
  1447  			hops: []*channeldb.CachedEdgePolicy{
  1448  				createHop(0, 10, 1000000, 10),
  1449  				createHop(0, 10, 1000000, 5),
  1450  				createHop(0, 10, 1000000, 3),
  1451  			},
  1452  			expectedFees:          []lnwire.MilliAtom{1, 1, 0},
  1453  			expectedTotalAmount:   100002,
  1454  			expectedTimeLocks:     []uint32{4, 1, 1},
  1455  			expectedTotalTimeLock: 9,
  1456  		}, {
  1457  			// A three hop payment where the fee of the first hop
  1458  			// is slightly higher (11) than the fee at the second hop,
  1459  			// because of the increase amount to forward.
  1460  			name:          "three hop with fee carry over",
  1461  			paymentAmount: 100000,
  1462  			hops: []*channeldb.CachedEdgePolicy{
  1463  				createHop(0, 10000, 1000000, 10),
  1464  				createHop(0, 10000, 1000000, 5),
  1465  				createHop(0, 10000, 1000000, 3),
  1466  			},
  1467  			expectedFees:          []lnwire.MilliAtom{1010, 1000, 0},
  1468  			expectedTotalAmount:   102010,
  1469  			expectedTimeLocks:     []uint32{4, 1, 1},
  1470  			expectedTotalTimeLock: 9,
  1471  		}, {
  1472  			// A three hop payment where the fee policies of the first and
  1473  			// second hop are just high enough to show the fee carry over
  1474  			// effect.
  1475  			name:          "three hop with minimal fees for carry over",
  1476  			paymentAmount: 100000,
  1477  			hops: []*channeldb.CachedEdgePolicy{
  1478  				createHop(0, 10000, 1000000, 10),
  1479  
  1480  				// First hop charges 0.1% so the second hop fee
  1481  				// should show up in the first hop fee as 1 mat
  1482  				// extra.
  1483  				createHop(0, 1000, 1000000, 5),
  1484  
  1485  				// Second hop charges a fixed 1000 mat.
  1486  				createHop(1000, 0, 1000000, 3),
  1487  			},
  1488  			expectedFees:          []lnwire.MilliAtom{101, 1000, 0},
  1489  			expectedTotalAmount:   101101,
  1490  			expectedTimeLocks:     []uint32{4, 1, 1},
  1491  			expectedTotalTimeLock: 9,
  1492  		}}
  1493  
  1494  	for _, testCase := range testCases {
  1495  		testCase := testCase
  1496  
  1497  		// Overwrite the final hop's features if the test requires a
  1498  		// custom feature vector.
  1499  		if testCase.destFeatures != nil {
  1500  			finalHop := testCase.hops[len(testCase.hops)-1]
  1501  			finalHop.ToNodeFeatures = testCase.destFeatures
  1502  		}
  1503  
  1504  		assertRoute := func(t *testing.T, route *route.Route) {
  1505  			if route.TotalAmount != testCase.expectedTotalAmount {
  1506  				t.Errorf("Expected total amount is be %v"+
  1507  					", but got %v instead",
  1508  					testCase.expectedTotalAmount,
  1509  					route.TotalAmount)
  1510  			}
  1511  
  1512  			for i := 0; i < len(testCase.expectedFees); i++ {
  1513  				fee := route.HopFee(i)
  1514  				if testCase.expectedFees[i] != fee {
  1515  
  1516  					t.Errorf("Expected fee for hop %v to "+
  1517  						"be %v, but got %v instead",
  1518  						i, testCase.expectedFees[i],
  1519  						fee)
  1520  				}
  1521  			}
  1522  
  1523  			expectedTimeLockHeight := startingHeight +
  1524  				testCase.expectedTotalTimeLock
  1525  
  1526  			if route.TotalTimeLock != expectedTimeLockHeight {
  1527  
  1528  				t.Errorf("Expected total time lock to be %v"+
  1529  					", but got %v instead",
  1530  					expectedTimeLockHeight,
  1531  					route.TotalTimeLock)
  1532  			}
  1533  
  1534  			for i := 0; i < len(testCase.expectedTimeLocks); i++ {
  1535  				expectedTimeLockHeight := startingHeight +
  1536  					testCase.expectedTimeLocks[i]
  1537  
  1538  				if expectedTimeLockHeight !=
  1539  					route.Hops[i].OutgoingTimeLock {
  1540  
  1541  					t.Errorf("Expected time lock for hop "+
  1542  						"%v to be %v, but got %v instead",
  1543  						i, expectedTimeLockHeight,
  1544  						route.Hops[i].OutgoingTimeLock)
  1545  				}
  1546  			}
  1547  
  1548  			finalHop := route.Hops[len(route.Hops)-1]
  1549  			if !finalHop.LegacyPayload !=
  1550  				testCase.expectedTLVPayload {
  1551  
  1552  				t.Errorf("Expected final hop tlv payload: %t, "+
  1553  					"but got: %t instead",
  1554  					testCase.expectedTLVPayload,
  1555  					!finalHop.LegacyPayload)
  1556  			}
  1557  
  1558  			if !reflect.DeepEqual(
  1559  				finalHop.MPP, testCase.expectedMPP,
  1560  			) {
  1561  				t.Errorf("Expected final hop mpp field: %v, "+
  1562  					" but got: %v instead",
  1563  					testCase.expectedMPP, finalHop.MPP)
  1564  			}
  1565  		}
  1566  
  1567  		t.Run(testCase.name, func(t *testing.T) {
  1568  			route, err := newRoute(
  1569  				sourceVertex, testCase.hops, startingHeight,
  1570  				finalHopParams{
  1571  					amt:         testCase.paymentAmount,
  1572  					totalAmt:    testCase.paymentAmount,
  1573  					cltvDelta:   finalHopCLTV,
  1574  					records:     nil,
  1575  					paymentAddr: testCase.paymentAddr,
  1576  				},
  1577  			)
  1578  
  1579  			if testCase.expectError {
  1580  				expectedCode := testCase.expectedErrorCode
  1581  				if err == nil || !IsError(err, expectedCode) {
  1582  					t.Fatalf("expected newRoute to fail "+
  1583  						"with error code %v but got "+
  1584  						"%v instead",
  1585  						expectedCode, err)
  1586  				}
  1587  			} else {
  1588  				if err != nil {
  1589  					t.Errorf("unable to create path: %v", err)
  1590  					return
  1591  				}
  1592  
  1593  				assertRoute(t, route)
  1594  			}
  1595  		})
  1596  	}
  1597  }
  1598  
  1599  func runNewRoutePathTooLong(t *testing.T, useCache bool) {
  1600  	var testChannels []*testChannel
  1601  
  1602  	// Setup a linear network of 21 hops.
  1603  	fromNode := "start"
  1604  	for i := 0; i < 21; i++ {
  1605  		toNode := fmt.Sprintf("node-%v", i+1)
  1606  		c := symmetricTestChannel(fromNode, toNode, 100000, &testChannelPolicy{
  1607  			Expiry:  144,
  1608  			FeeRate: 400,
  1609  			MinHTLC: 1,
  1610  			MaxHTLC: 100000001,
  1611  		})
  1612  		testChannels = append(testChannels, c)
  1613  
  1614  		fromNode = toNode
  1615  	}
  1616  
  1617  	ctx := newPathFindingTestContext(t, useCache, testChannels, "start")
  1618  	defer ctx.cleanup()
  1619  
  1620  	// Assert that we can find 20 hop routes.
  1621  	node20 := ctx.keyFromAlias("node-20")
  1622  	payAmt := lnwire.MilliAtom(100001)
  1623  	_, err := ctx.findPath(node20, payAmt)
  1624  	if err != nil {
  1625  		t.Fatalf("unexpected pathfinding failure: %v", err)
  1626  	}
  1627  
  1628  	// Assert that finding a 21 hop route fails.
  1629  	node21 := ctx.keyFromAlias("node-21")
  1630  	_, err = ctx.findPath(node21, payAmt)
  1631  	if err != errNoPathFound {
  1632  		t.Fatalf("not route error expected, but got %v", err)
  1633  	}
  1634  
  1635  	// Assert that we can't find a 20 hop route if custom records make it
  1636  	// exceed the maximum payload size.
  1637  	ctx.restrictParams.DestFeatures = tlvFeatures
  1638  	ctx.restrictParams.DestCustomRecords = map[uint64][]byte{
  1639  		100000: bytes.Repeat([]byte{1}, 100),
  1640  	}
  1641  	_, err = ctx.findPath(node20, payAmt)
  1642  	if err != errNoPathFound {
  1643  		t.Fatalf("not route error expected, but got %v", err)
  1644  	}
  1645  }
  1646  
  1647  func runPathNotAvailable(t *testing.T, useCache bool) {
  1648  	graph, err := parseTestGraph(useCache, basicGraphFilePath)
  1649  	if err != nil {
  1650  		t.Fatalf("unable to create graph: %v", err)
  1651  	}
  1652  	defer graph.cleanUp()
  1653  
  1654  	sourceNode, err := graph.graph.SourceNode()
  1655  	if err != nil {
  1656  		t.Fatalf("unable to fetch source node: %v", err)
  1657  	}
  1658  
  1659  	// With the test graph loaded, we'll test that queries for target that
  1660  	// are either unreachable within the graph, or unknown result in an
  1661  	// error.
  1662  	unknownNodeStr := "03dd46ff29a6941b4a2607525b043ec9b020b3f318a1bf281536fd7011ec59c882"
  1663  	unknownNodeBytes, err := hex.DecodeString(unknownNodeStr)
  1664  	if err != nil {
  1665  		t.Fatalf("unable to parse bytes: %v", err)
  1666  	}
  1667  	var unknownNode route.Vertex
  1668  	copy(unknownNode[:], unknownNodeBytes)
  1669  
  1670  	_, err = dbFindPath(
  1671  		graph.graph, nil, &mockBandwidthHints{},
  1672  		noRestrictions, testPathFindingConfig,
  1673  		sourceNode.PubKeyBytes, unknownNode, 100, 0,
  1674  	)
  1675  	if err != errNoPathFound {
  1676  		t.Fatalf("path shouldn't have been found: %v", err)
  1677  	}
  1678  }
  1679  
  1680  // runDestTLVGraphFallback asserts that we properly detect when we can send TLV
  1681  // records to a receiver, and also that we fallback to the receiver's node
  1682  // announcement if we don't have an invoice features.
  1683  func runDestTLVGraphFallback(t *testing.T, useCache bool) {
  1684  	testChannels := []*testChannel{
  1685  		asymmetricTestChannel("roasbeef", "luoji", 100000,
  1686  			&testChannelPolicy{
  1687  				Expiry:  144,
  1688  				FeeRate: 400,
  1689  				MinHTLC: 1,
  1690  				MaxHTLC: 100000000,
  1691  			}, &testChannelPolicy{
  1692  				Expiry:  144,
  1693  				FeeRate: 400,
  1694  				MinHTLC: 1,
  1695  				MaxHTLC: 100000000,
  1696  			}, 0),
  1697  		asymmetricTestChannel("roasbeef", "satoshi", 100000,
  1698  			&testChannelPolicy{
  1699  				Expiry:  144,
  1700  				FeeRate: 400,
  1701  				MinHTLC: 1,
  1702  				MaxHTLC: 100000000,
  1703  			}, &testChannelPolicy{
  1704  				Expiry:   144,
  1705  				FeeRate:  400,
  1706  				MinHTLC:  1,
  1707  				MaxHTLC:  100000000,
  1708  				Features: tlvFeatures,
  1709  			}, 0),
  1710  	}
  1711  
  1712  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  1713  	defer ctx.cleanup()
  1714  
  1715  	sourceNode, err := ctx.graph.SourceNode()
  1716  	if err != nil {
  1717  		t.Fatalf("unable to fetch source node: %v", err)
  1718  
  1719  	}
  1720  
  1721  	find := func(r *RestrictParams,
  1722  		target route.Vertex) ([]*channeldb.CachedEdgePolicy, error) {
  1723  
  1724  		return dbFindPath(
  1725  			ctx.graph, nil, &mockBandwidthHints{},
  1726  			r, testPathFindingConfig,
  1727  			sourceNode.PubKeyBytes, target, 100, 0,
  1728  		)
  1729  	}
  1730  
  1731  	// Luoji's node ann has an empty feature vector.
  1732  	luoji := ctx.testGraphInstance.aliasMap["luoji"]
  1733  
  1734  	// Satoshi's node ann supports TLV.
  1735  	satoshi := ctx.testGraphInstance.aliasMap["satoshi"]
  1736  
  1737  	restrictions := *noRestrictions
  1738  
  1739  	// Add custom records w/o any dest features.
  1740  	restrictions.DestCustomRecords = record.CustomSet{70000: []byte{}}
  1741  
  1742  	// Path to luoji should fail because his node ann features are empty.
  1743  	_, err = find(&restrictions, luoji)
  1744  	if err != errNoTlvPayload {
  1745  		t.Fatalf("path shouldn't have been found: %v", err)
  1746  	}
  1747  
  1748  	// However, path to satoshi should succeed via the fallback because his
  1749  	// node ann features have the TLV bit.
  1750  	path, err := find(&restrictions, satoshi)
  1751  	if err != nil {
  1752  		t.Fatalf("path should have been found: %v", err)
  1753  	}
  1754  	assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "satoshi")
  1755  
  1756  	// Add empty destination features. This should cause both paths to fail,
  1757  	// since this override anything in the graph.
  1758  	restrictions.DestFeatures = lnwire.EmptyFeatureVector()
  1759  
  1760  	_, err = find(&restrictions, luoji)
  1761  	if err != errNoTlvPayload {
  1762  		t.Fatalf("path shouldn't have been found: %v", err)
  1763  	}
  1764  	_, err = find(&restrictions, satoshi)
  1765  	if err != errNoTlvPayload {
  1766  		t.Fatalf("path shouldn't have been found: %v", err)
  1767  	}
  1768  
  1769  	// Finally, set the TLV dest feature. We should succeed in finding a
  1770  	// path to luoji.
  1771  	restrictions.DestFeatures = tlvFeatures
  1772  
  1773  	path, err = find(&restrictions, luoji)
  1774  	if err != nil {
  1775  		t.Fatalf("path should have been found: %v", err)
  1776  	}
  1777  	assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "luoji")
  1778  }
  1779  
  1780  // runMissingFeatureDep asserts that we fail path finding when the
  1781  // destination's features are broken, in that the feature vector doesn't signal
  1782  // all transitive dependencies.
  1783  func runMissingFeatureDep(t *testing.T, useCache bool) {
  1784  	testChannels := []*testChannel{
  1785  		asymmetricTestChannel("roasbeef", "conner", 100000,
  1786  			&testChannelPolicy{
  1787  				Expiry:  144,
  1788  				FeeRate: 400,
  1789  				MinHTLC: 1,
  1790  				MaxHTLC: 100000000,
  1791  			},
  1792  			&testChannelPolicy{
  1793  				Expiry:   144,
  1794  				FeeRate:  400,
  1795  				MinHTLC:  1,
  1796  				MaxHTLC:  100000000,
  1797  				Features: payAddrFeatures,
  1798  			}, 0,
  1799  		),
  1800  		asymmetricTestChannel("conner", "joost", 100000,
  1801  			&testChannelPolicy{
  1802  				Expiry:   144,
  1803  				FeeRate:  400,
  1804  				MinHTLC:  1,
  1805  				MaxHTLC:  100000000,
  1806  				Features: payAddrFeatures,
  1807  			},
  1808  			&testChannelPolicy{
  1809  				Expiry:  144,
  1810  				FeeRate: 400,
  1811  				MinHTLC: 1,
  1812  				MaxHTLC: 100000000,
  1813  			}, 0,
  1814  		),
  1815  	}
  1816  
  1817  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  1818  	defer ctx.cleanup()
  1819  
  1820  	// Conner's node in the graph has a broken feature vector, since it
  1821  	// signals payment addresses without signaling tlv onions. Pathfinding
  1822  	// should fail since we validate transitive feature dependencies for the
  1823  	// final node.
  1824  	conner := ctx.keyFromAlias("conner")
  1825  	joost := ctx.keyFromAlias("joost")
  1826  
  1827  	_, err := ctx.findPath(conner, 100)
  1828  	if err != errMissingDependentFeature {
  1829  		t.Fatalf("path shouldn't have been found: %v", err)
  1830  	}
  1831  
  1832  	// Now, set the TLV and payment addresses features to override the
  1833  	// broken features found in the graph. We should succeed in finding a
  1834  	// path to conner.
  1835  	ctx.restrictParams.DestFeatures = tlvPayAddrFeatures
  1836  
  1837  	path, err := ctx.findPath(conner, 100)
  1838  	if err != nil {
  1839  		t.Fatalf("path should have been found: %v", err)
  1840  	}
  1841  	assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "conner")
  1842  
  1843  	// Finally, try to find a route to joost through conner. The
  1844  	// destination features are set properly from the previous assertions,
  1845  	// but conner's feature vector in the graph is still broken. We expect
  1846  	// errNoPathFound and not the missing feature dep err above since
  1847  	// intermediate hops are simply skipped if they have invalid feature
  1848  	// vectors, leaving no possible route to joost.
  1849  	_, err = ctx.findPath(joost, 100)
  1850  	if err != errNoPathFound {
  1851  		t.Fatalf("path shouldn't have been found: %v", err)
  1852  	}
  1853  }
  1854  
  1855  // runUnknownRequiredFeatures asserts that we fail path finding when the
  1856  // destination requires an unknown required feature, and that we skip
  1857  // intermediaries that signal unknown required features.
  1858  func runUnknownRequiredFeatures(t *testing.T, useCache bool) {
  1859  	testChannels := []*testChannel{
  1860  		asymmetricTestChannel("roasbeef", "conner", 100000,
  1861  			&testChannelPolicy{
  1862  				Expiry:  144,
  1863  				FeeRate: 400,
  1864  				MinHTLC: 1,
  1865  				MaxHTLC: 100000000,
  1866  			},
  1867  			&testChannelPolicy{
  1868  				Expiry:   144,
  1869  				FeeRate:  400,
  1870  				MinHTLC:  1,
  1871  				MaxHTLC:  100000000,
  1872  				Features: unknownRequiredFeatures,
  1873  			}, 0,
  1874  		),
  1875  		asymmetricTestChannel("conner", "joost", 100000,
  1876  			&testChannelPolicy{
  1877  				Expiry:   144,
  1878  				FeeRate:  400,
  1879  				MinHTLC:  1,
  1880  				MaxHTLC:  100000000,
  1881  				Features: unknownRequiredFeatures,
  1882  			},
  1883  			&testChannelPolicy{
  1884  				Expiry:  144,
  1885  				FeeRate: 400,
  1886  				MinHTLC: 1,
  1887  				MaxHTLC: 100000000,
  1888  			}, 0,
  1889  		),
  1890  	}
  1891  
  1892  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  1893  	defer ctx.cleanup()
  1894  
  1895  	conner := ctx.keyFromAlias("conner")
  1896  	joost := ctx.keyFromAlias("joost")
  1897  
  1898  	// Conner's node in the graph has an unknown required feature (100).
  1899  	// Pathfinding should fail since we check the destination's features for
  1900  	// unknown required features before beginning pathfinding.
  1901  	_, err := ctx.findPath(conner, 100)
  1902  	if !reflect.DeepEqual(err, errUnknownRequiredFeature) {
  1903  		t.Fatalf("path shouldn't have been found: %v", err)
  1904  	}
  1905  
  1906  	// Now, try to find a route to joost through conner. The destination
  1907  	// features are valid, but conner's feature vector in the graph still
  1908  	// requires feature 100. We expect errNoPathFound and not the error
  1909  	// above since intermediate hops are simply skipped if they have invalid
  1910  	// feature vectors, leaving no possible route to joost. This asserts
  1911  	// that we don't try to route _through_ nodes with unknown required
  1912  	// features.
  1913  	_, err = ctx.findPath(joost, 100)
  1914  	if err != errNoPathFound {
  1915  		t.Fatalf("path shouldn't have been found: %v", err)
  1916  	}
  1917  }
  1918  
  1919  // runDestPaymentAddr asserts that we properly detect when we can send a
  1920  // payment address to a receiver, and also that we fallback to the receiver's
  1921  // node announcement if we don't have an invoice features.
  1922  func runDestPaymentAddr(t *testing.T, useCache bool) {
  1923  	testChannels := []*testChannel{
  1924  		symmetricTestChannel("roasbeef", "luoji", 100000,
  1925  			&testChannelPolicy{
  1926  				Expiry:  144,
  1927  				FeeRate: 400,
  1928  				MinHTLC: 1,
  1929  				MaxHTLC: 100000000,
  1930  			},
  1931  		),
  1932  	}
  1933  
  1934  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  1935  	defer ctx.cleanup()
  1936  
  1937  	luoji := ctx.keyFromAlias("luoji")
  1938  
  1939  	// Add payment address w/o any invoice features.
  1940  	ctx.restrictParams.PaymentAddr = &[32]byte{1}
  1941  
  1942  	// Add empty destination features. This should cause us to fail, since
  1943  	// this overrides anything in the graph.
  1944  	ctx.restrictParams.DestFeatures = lnwire.EmptyFeatureVector()
  1945  
  1946  	_, err := ctx.findPath(luoji, 100)
  1947  	if err != errNoPaymentAddr {
  1948  		t.Fatalf("path shouldn't have been found: %v", err)
  1949  	}
  1950  
  1951  	// Now, set the TLV and payment address features for the destination. We
  1952  	// should succeed in finding a path to luoji.
  1953  	ctx.restrictParams.DestFeatures = tlvPayAddrFeatures
  1954  
  1955  	path, err := ctx.findPath(luoji, 100)
  1956  	if err != nil {
  1957  		t.Fatalf("path should have been found: %v", err)
  1958  	}
  1959  	assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "luoji")
  1960  }
  1961  
  1962  func runPathInsufficientCapacity(t *testing.T, useCache bool) {
  1963  	graph, err := parseTestGraph(useCache, basicGraphFilePath)
  1964  	if err != nil {
  1965  		t.Fatalf("unable to create graph: %v", err)
  1966  	}
  1967  	defer graph.cleanUp()
  1968  
  1969  	sourceNode, err := graph.graph.SourceNode()
  1970  	if err != nil {
  1971  		t.Fatalf("unable to fetch source node: %v", err)
  1972  	}
  1973  
  1974  	// Next, test that attempting to find a path in which the current
  1975  	// channel graph cannot support due to insufficient capacity triggers
  1976  	// an error.
  1977  
  1978  	// To test his we'll attempt to make a payment of 1 DCR, or 100 million
  1979  	// atoms. The largest channel in the basic graph is of size 100k
  1980  	// atoms, so we shouldn't be able to find a path to sophon even
  1981  	// though we have a 2-hop link.
  1982  	target := graph.aliasMap["sophon"]
  1983  
  1984  	payAmt := lnwire.NewMAtomsFromAtoms(dcrutil.AtomsPerCoin)
  1985  	_, err = dbFindPath(
  1986  		graph.graph, nil, &mockBandwidthHints{},
  1987  		noRestrictions, testPathFindingConfig,
  1988  		sourceNode.PubKeyBytes, target, payAmt, 0,
  1989  	)
  1990  	if err != errInsufficientBalance {
  1991  		t.Fatalf("graph shouldn't be able to support payment: %v", err)
  1992  	}
  1993  }
  1994  
  1995  // runRouteFailMinHTLC tests that if we attempt to route an HTLC which is
  1996  // smaller than the advertised minHTLC of an edge, then path finding fails.
  1997  func runRouteFailMinHTLC(t *testing.T, useCache bool) {
  1998  	graph, err := parseTestGraph(useCache, basicGraphFilePath)
  1999  	if err != nil {
  2000  		t.Fatalf("unable to create graph: %v", err)
  2001  	}
  2002  	defer graph.cleanUp()
  2003  
  2004  	sourceNode, err := graph.graph.SourceNode()
  2005  	if err != nil {
  2006  		t.Fatalf("unable to fetch source node: %v", err)
  2007  	}
  2008  
  2009  	// We'll not attempt to route an HTLC of 10 atoms from roasbeef to Son
  2010  	// Goku. However, the min HTLC of Son Goku is 1k Atoms, as a result, this
  2011  	// attempt should fail.
  2012  	target := graph.aliasMap["songoku"]
  2013  	payAmt := lnwire.MilliAtom(10)
  2014  	_, err = dbFindPath(
  2015  		graph.graph, nil, &mockBandwidthHints{},
  2016  		noRestrictions, testPathFindingConfig,
  2017  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2018  	)
  2019  	if err != errNoPathFound {
  2020  		t.Fatalf("graph shouldn't be able to support payment: %v", err)
  2021  	}
  2022  }
  2023  
  2024  // runRouteFailMaxHTLC tests that if we attempt to route an HTLC which is
  2025  // larger than the advertised max HTLC of an edge, then path finding fails.
  2026  func runRouteFailMaxHTLC(t *testing.T, useCache bool) {
  2027  	// Set up a test graph:
  2028  	// roasbeef <--> firstHop <--> secondHop <--> target
  2029  	// We will be adjusting the max HTLC of the edge between the first and
  2030  	// second hops.
  2031  	var firstToSecondID uint64 = 1
  2032  	testChannels := []*testChannel{
  2033  		symmetricTestChannel("roasbeef", "first", 100000, &testChannelPolicy{
  2034  			Expiry:  144,
  2035  			FeeRate: 400,
  2036  			MinHTLC: 1,
  2037  			MaxHTLC: 100000001,
  2038  		}),
  2039  		symmetricTestChannel("first", "second", 100000, &testChannelPolicy{
  2040  			Expiry:  144,
  2041  			FeeRate: 400,
  2042  			MinHTLC: 1,
  2043  			MaxHTLC: 100000002,
  2044  		}, firstToSecondID),
  2045  		symmetricTestChannel("second", "target", 100000, &testChannelPolicy{
  2046  			Expiry:  144,
  2047  			FeeRate: 400,
  2048  			MinHTLC: 1,
  2049  			MaxHTLC: 100000003,
  2050  		}),
  2051  	}
  2052  
  2053  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  2054  	defer ctx.cleanup()
  2055  
  2056  	// First, attempt to send a payment greater than the max HTLC we are
  2057  	// about to set, which should succeed.
  2058  	target := ctx.keyFromAlias("target")
  2059  	payAmt := lnwire.MilliAtom(100001)
  2060  	_, err := ctx.findPath(target, payAmt)
  2061  	if err != nil {
  2062  		t.Fatalf("graph should've been able to support payment: %v", err)
  2063  	}
  2064  
  2065  	// Next, update the middle edge policy to only allow payments up to 100k
  2066  	// msat.
  2067  	graph := ctx.testGraphInstance.graph
  2068  	_, midEdge, _, err := graph.FetchChannelEdgesByID(firstToSecondID)
  2069  	if err != nil {
  2070  		t.Fatalf("unable to fetch edge: %v", err)
  2071  	}
  2072  	midEdge.MessageFlags = 1
  2073  	midEdge.MaxHTLC = payAmt - 1
  2074  	if err := graph.UpdateEdgePolicy(midEdge); err != nil {
  2075  		t.Fatalf("unable to update edge: %v", err)
  2076  	}
  2077  
  2078  	// We'll now attempt to route through that edge with a payment above
  2079  	// 100k msat, which should fail.
  2080  	_, err = ctx.findPath(target, payAmt)
  2081  	if err != errNoPathFound {
  2082  		t.Fatalf("graph shouldn't be able to support payment: %v", err)
  2083  	}
  2084  }
  2085  
  2086  // runRouteFailDisabledEdge tests that if we attempt to route to an edge
  2087  // that's disabled, then that edge is disqualified, and the routing attempt
  2088  // will fail. We also test that this is true only for non-local edges, as we'll
  2089  // ignore the disable flags, with the assumption that the correct bandwidth is
  2090  // found among the bandwidth hints.
  2091  func runRouteFailDisabledEdge(t *testing.T, useCache bool) {
  2092  	graph, err := parseTestGraph(useCache, basicGraphFilePath)
  2093  	if err != nil {
  2094  		t.Fatalf("unable to create graph: %v", err)
  2095  	}
  2096  	defer graph.cleanUp()
  2097  
  2098  	sourceNode, err := graph.graph.SourceNode()
  2099  	if err != nil {
  2100  		t.Fatalf("unable to fetch source node: %v", err)
  2101  	}
  2102  
  2103  	// First, we'll try to route from roasbeef -> sophon. This should
  2104  	// succeed without issue, and return a single path via phamnuwen
  2105  	target := graph.aliasMap["sophon"]
  2106  	payAmt := lnwire.NewMAtomsFromAtoms(105000)
  2107  	_, err = dbFindPath(
  2108  		graph.graph, nil, &mockBandwidthHints{},
  2109  		noRestrictions, testPathFindingConfig,
  2110  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2111  	)
  2112  	if err != nil {
  2113  		t.Fatalf("unable to find path: %v", err)
  2114  	}
  2115  
  2116  	// Disable the edge roasbeef->phamnuwen. This should not impact the
  2117  	// path finding, as we don't consider the disable flag for local
  2118  	// channels (and roasbeef is the source).
  2119  	roasToPham := uint64(999991)
  2120  	_, e1, e2, err := graph.graph.FetchChannelEdgesByID(roasToPham)
  2121  	if err != nil {
  2122  		t.Fatalf("unable to fetch edge: %v", err)
  2123  	}
  2124  	e1.ChannelFlags |= lnwire.ChanUpdateDisabled
  2125  	if err := graph.graph.UpdateEdgePolicy(e1); err != nil {
  2126  		t.Fatalf("unable to update edge: %v", err)
  2127  	}
  2128  	e2.ChannelFlags |= lnwire.ChanUpdateDisabled
  2129  	if err := graph.graph.UpdateEdgePolicy(e2); err != nil {
  2130  		t.Fatalf("unable to update edge: %v", err)
  2131  	}
  2132  
  2133  	_, err = dbFindPath(
  2134  		graph.graph, nil, &mockBandwidthHints{},
  2135  		noRestrictions, testPathFindingConfig,
  2136  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2137  	)
  2138  	if err != nil {
  2139  		t.Fatalf("unable to find path: %v", err)
  2140  	}
  2141  
  2142  	// Now, we'll modify the edge from phamnuwen -> sophon, to read that
  2143  	// it's disabled.
  2144  	phamToSophon := uint64(99999)
  2145  	_, e, _, err := graph.graph.FetchChannelEdgesByID(phamToSophon)
  2146  	if err != nil {
  2147  		t.Fatalf("unable to fetch edge: %v", err)
  2148  	}
  2149  	e.ChannelFlags |= lnwire.ChanUpdateDisabled
  2150  	if err := graph.graph.UpdateEdgePolicy(e); err != nil {
  2151  		t.Fatalf("unable to update edge: %v", err)
  2152  	}
  2153  
  2154  	// If we attempt to route through that edge, we should get a failure as
  2155  	// it is no longer eligible.
  2156  	_, err = dbFindPath(
  2157  		graph.graph, nil, &mockBandwidthHints{},
  2158  		noRestrictions, testPathFindingConfig,
  2159  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2160  	)
  2161  	if err != errNoPathFound {
  2162  		t.Fatalf("graph shouldn't be able to support payment: %v", err)
  2163  	}
  2164  }
  2165  
  2166  // runPathSourceEdgesBandwidth tests that explicitly passing in a set of
  2167  // bandwidth hints is used by the path finding algorithm to consider whether to
  2168  // use a local channel.
  2169  func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) {
  2170  	graph, err := parseTestGraph(useCache, basicGraphFilePath)
  2171  	if err != nil {
  2172  		t.Fatalf("unable to create graph: %v", err)
  2173  	}
  2174  	defer graph.cleanUp()
  2175  
  2176  	sourceNode, err := graph.graph.SourceNode()
  2177  	if err != nil {
  2178  		t.Fatalf("unable to fetch source node: %v", err)
  2179  	}
  2180  
  2181  	// First, we'll try to route from roasbeef -> sophon. This should
  2182  	// succeed without issue, and return a path via songoku, as that's the
  2183  	// cheapest path.
  2184  	target := graph.aliasMap["sophon"]
  2185  	payAmt := lnwire.NewMAtomsFromAtoms(50000)
  2186  	path, err := dbFindPath(
  2187  		graph.graph, nil, &mockBandwidthHints{},
  2188  		noRestrictions, testPathFindingConfig,
  2189  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2190  	)
  2191  	if err != nil {
  2192  		t.Fatalf("unable to find path: %v", err)
  2193  	}
  2194  	assertExpectedPath(t, graph.aliasMap, path, "songoku", "sophon")
  2195  
  2196  	// Now we'll set the bandwidth of the edge roasbeef->songoku and
  2197  	// roasbeef->phamnuwen to 0.
  2198  	roasToSongoku := uint64(12345)
  2199  	roasToPham := uint64(999991)
  2200  	bandwidths := &mockBandwidthHints{
  2201  		hints: map[uint64]lnwire.MilliAtom{
  2202  			roasToSongoku: 0,
  2203  			roasToPham:    0,
  2204  		},
  2205  	}
  2206  
  2207  	// Since both these edges has a bandwidth of zero, no path should be
  2208  	// found.
  2209  	_, err = dbFindPath(
  2210  		graph.graph, nil, bandwidths,
  2211  		noRestrictions, testPathFindingConfig,
  2212  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2213  	)
  2214  	if err != errNoPathFound {
  2215  		t.Fatalf("graph shouldn't be able to support payment: %v", err)
  2216  	}
  2217  
  2218  	// Set the bandwidth of roasbeef->phamnuwen high enough to carry the
  2219  	// payment.
  2220  	bandwidths.hints[roasToPham] = 2 * payAmt
  2221  
  2222  	// Now, if we attempt to route again, we should find the path via
  2223  	// phamnuven, as the other source edge won't be considered.
  2224  	path, err = dbFindPath(
  2225  		graph.graph, nil, bandwidths,
  2226  		noRestrictions, testPathFindingConfig,
  2227  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2228  	)
  2229  	if err != nil {
  2230  		t.Fatalf("unable to find path: %v", err)
  2231  	}
  2232  	assertExpectedPath(t, graph.aliasMap, path, "phamnuwen", "sophon")
  2233  
  2234  	// Finally, set the roasbeef->songoku bandwidth, but also set its
  2235  	// disable flag.
  2236  	bandwidths.hints[roasToSongoku] = 2 * payAmt
  2237  	_, e1, e2, err := graph.graph.FetchChannelEdgesByID(roasToSongoku)
  2238  	if err != nil {
  2239  		t.Fatalf("unable to fetch edge: %v", err)
  2240  	}
  2241  	e1.ChannelFlags |= lnwire.ChanUpdateDisabled
  2242  	if err := graph.graph.UpdateEdgePolicy(e1); err != nil {
  2243  		t.Fatalf("unable to update edge: %v", err)
  2244  	}
  2245  	e2.ChannelFlags |= lnwire.ChanUpdateDisabled
  2246  	if err := graph.graph.UpdateEdgePolicy(e2); err != nil {
  2247  		t.Fatalf("unable to update edge: %v", err)
  2248  	}
  2249  
  2250  	// Since we ignore disable flags for local channels, a path should
  2251  	// still be found.
  2252  	path, err = dbFindPath(
  2253  		graph.graph, nil, bandwidths,
  2254  		noRestrictions, testPathFindingConfig,
  2255  		sourceNode.PubKeyBytes, target, payAmt, 0,
  2256  	)
  2257  	if err != nil {
  2258  		t.Fatalf("unable to find path: %v", err)
  2259  	}
  2260  	assertExpectedPath(t, graph.aliasMap, path, "songoku", "sophon")
  2261  }
  2262  
  2263  func TestPathInsufficientCapacityWithFee(t *testing.T) {
  2264  	t.Parallel()
  2265  
  2266  	// TODO(roasbeef): encode live graph to json
  2267  
  2268  	// TODO(roasbeef): need to add a case, or modify the fee ratio for one
  2269  	// to ensure that has going forward, but when fees are applied doesn't
  2270  	// work
  2271  }
  2272  
  2273  func TestPathFindSpecExample(t *testing.T) {
  2274  	t.Parallel()
  2275  
  2276  	// All our path finding tests will assume a starting height of 100, so
  2277  	// we'll pass that in to ensure that the router uses 100 as the current
  2278  	// height.
  2279  	const startingHeight = 100
  2280  	ctx, cleanUp := createTestCtxFromFile(
  2281  		t, startingHeight, specExampleFilePath,
  2282  	)
  2283  	defer cleanUp()
  2284  
  2285  	// We'll first exercise the scenario of a direct payment from Bob to
  2286  	// Carol, so we set "B" as the source node so path finding starts from
  2287  	// Bob.
  2288  	bob := ctx.aliases["B"]
  2289  	bobNode, err := ctx.graph.FetchLightningNode(bob)
  2290  	if err != nil {
  2291  		t.Fatalf("unable to find bob: %v", err)
  2292  	}
  2293  	if err := ctx.graph.SetSourceNode(bobNode); err != nil {
  2294  		t.Fatalf("unable to set source node: %v", err)
  2295  	}
  2296  
  2297  	// Query for a route of 4,999,999 milli-atoms to carol.
  2298  	carol := ctx.aliases["C"]
  2299  	const amt lnwire.MilliAtom = 4999999
  2300  	route, err := ctx.router.FindRoute(
  2301  		bobNode.PubKeyBytes, carol, amt, noRestrictions, nil, nil,
  2302  		MinCLTVDelta,
  2303  	)
  2304  	if err != nil {
  2305  		t.Fatalf("unable to find route: %v", err)
  2306  	}
  2307  
  2308  	// Now we'll examine the route returned for correctness.
  2309  	//
  2310  	// It should be sending the exact payment amount as there are no
  2311  	// additional hops.
  2312  	if route.TotalAmount != amt {
  2313  		t.Fatalf("wrong total amount: got %v, expected %v",
  2314  			route.TotalAmount, amt)
  2315  	}
  2316  	if route.Hops[0].AmtToForward != amt {
  2317  		t.Fatalf("wrong forward amount: got %v, expected %v",
  2318  			route.Hops[0].AmtToForward, amt)
  2319  	}
  2320  
  2321  	fee := route.HopFee(0)
  2322  	if fee != 0 {
  2323  		t.Fatalf("wrong hop fee: got %v, expected %v", fee, 0)
  2324  	}
  2325  
  2326  	// The CLTV expiry should be the current height plus 18 (the expiry for
  2327  	// the B -> C channel.
  2328  	if route.TotalTimeLock !=
  2329  		startingHeight+MinCLTVDelta {
  2330  
  2331  		t.Fatalf("wrong total time lock: got %v, expecting %v",
  2332  			route.TotalTimeLock,
  2333  			startingHeight+MinCLTVDelta)
  2334  	}
  2335  
  2336  	// Next, we'll set A as the source node so we can assert that we create
  2337  	// the proper route for any queries starting with Alice.
  2338  	alice := ctx.aliases["A"]
  2339  	aliceNode, err := ctx.graph.FetchLightningNode(alice)
  2340  	if err != nil {
  2341  		t.Fatalf("unable to find alice: %v", err)
  2342  	}
  2343  	if err := ctx.graph.SetSourceNode(aliceNode); err != nil {
  2344  		t.Fatalf("unable to set source node: %v", err)
  2345  	}
  2346  	ctx.router.selfNode = aliceNode
  2347  	source, err := ctx.graph.SourceNode()
  2348  	if err != nil {
  2349  		t.Fatalf("unable to retrieve source node: %v", err)
  2350  	}
  2351  	if source.PubKeyBytes != alice {
  2352  		t.Fatalf("source node not set")
  2353  	}
  2354  
  2355  	// We'll now request a route from A -> B -> C.
  2356  	route, err = ctx.router.FindRoute(
  2357  		source.PubKeyBytes, carol, amt, noRestrictions, nil, nil,
  2358  		MinCLTVDelta,
  2359  	)
  2360  	if err != nil {
  2361  		t.Fatalf("unable to find routes: %v", err)
  2362  	}
  2363  
  2364  	// The route should be two hops.
  2365  	if len(route.Hops) != 2 {
  2366  		t.Fatalf("route should be %v hops, is instead %v", 2,
  2367  			len(route.Hops))
  2368  	}
  2369  
  2370  	// The total amount should factor in a fee of 10199 and also use a CLTV
  2371  	// delta total of 29 (20 + 9),
  2372  	expectedAmt := lnwire.MilliAtom(5010198)
  2373  	if route.TotalAmount != expectedAmt {
  2374  		t.Fatalf("wrong amount: got %v, expected %v",
  2375  			route.TotalAmount, expectedAmt)
  2376  	}
  2377  	expectedDelta := uint32(20 + MinCLTVDelta)
  2378  	if route.TotalTimeLock != startingHeight+expectedDelta {
  2379  		t.Fatalf("wrong total time lock: got %v, expecting %v",
  2380  			route.TotalTimeLock, startingHeight+expectedDelta)
  2381  	}
  2382  
  2383  	// Ensure that the hops of the route are properly crafted.
  2384  	//
  2385  	// After taking the fee, Bob should be forwarding the remainder which
  2386  	// is the exact payment to Bob.
  2387  	if route.Hops[0].AmtToForward != amt {
  2388  		t.Fatalf("wrong forward amount: got %v, expected %v",
  2389  			route.Hops[0].AmtToForward, amt)
  2390  	}
  2391  
  2392  	// We shouldn't pay any fee for the first, hop, but the fee for the
  2393  	// second hop posted fee should be exactly:
  2394  
  2395  	// The fee that we pay for the second hop will be "applied to the first
  2396  	// hop, so we should get a fee of exactly:
  2397  	//
  2398  	//  * 200 + 4999999 * 2000 / 1000000 = 10199
  2399  
  2400  	fee = route.HopFee(0)
  2401  	if fee != 10199 {
  2402  		t.Fatalf("wrong hop fee: got %v, expected %v", fee, 10199)
  2403  	}
  2404  
  2405  	// While for the final hop, as there's no additional hop afterwards, we
  2406  	// pay no fee.
  2407  	fee = route.HopFee(1)
  2408  	if fee != 0 {
  2409  		t.Fatalf("wrong hop fee: got %v, expected %v", fee, 0)
  2410  	}
  2411  
  2412  	// The outgoing CLTV value itself should be the current height plus 30
  2413  	// to meet Carol's requirements.
  2414  	if route.Hops[0].OutgoingTimeLock !=
  2415  		startingHeight+MinCLTVDelta {
  2416  
  2417  		t.Fatalf("wrong total time lock: got %v, expecting %v",
  2418  			route.Hops[0].OutgoingTimeLock,
  2419  			startingHeight+MinCLTVDelta)
  2420  	}
  2421  
  2422  	// For B -> C, we assert that the final hop also has the proper
  2423  	// parameters.
  2424  	lastHop := route.Hops[1]
  2425  	if lastHop.AmtToForward != amt {
  2426  		t.Fatalf("wrong forward amount: got %v, expected %v",
  2427  			lastHop.AmtToForward, amt)
  2428  	}
  2429  	if lastHop.OutgoingTimeLock !=
  2430  		startingHeight+MinCLTVDelta {
  2431  
  2432  		t.Fatalf("wrong total time lock: got %v, expecting %v",
  2433  			lastHop.OutgoingTimeLock,
  2434  			startingHeight+MinCLTVDelta)
  2435  	}
  2436  }
  2437  
  2438  func assertExpectedPath(t *testing.T, aliasMap map[string]route.Vertex,
  2439  	path []*channeldb.CachedEdgePolicy, nodeAliases ...string) {
  2440  
  2441  	if len(path) != len(nodeAliases) {
  2442  		t.Fatal("number of hops and number of aliases do not match")
  2443  	}
  2444  
  2445  	for i, hop := range path {
  2446  		if hop.ToNodePubKey() != aliasMap[nodeAliases[i]] {
  2447  			t.Fatalf("expected %v to be pos #%v in hop, instead "+
  2448  				"%v was", nodeAliases[i], i, hop.ToNodePubKey())
  2449  		}
  2450  	}
  2451  }
  2452  
  2453  // TestNewRouteFromEmptyHops tests that the NewRouteFromHops function returns an
  2454  // error when the hop list is empty.
  2455  func TestNewRouteFromEmptyHops(t *testing.T) {
  2456  	t.Parallel()
  2457  
  2458  	var source route.Vertex
  2459  	_, err := route.NewRouteFromHops(0, 0, source, []*route.Hop{})
  2460  	if err != route.ErrNoRouteHopsProvided {
  2461  		t.Fatalf("expected empty hops error: instead got: %v", err)
  2462  	}
  2463  }
  2464  
  2465  // runRestrictOutgoingChannel asserts that a outgoing channel restriction is
  2466  // obeyed by the path finding algorithm.
  2467  func runRestrictOutgoingChannel(t *testing.T, useCache bool) {
  2468  	// Define channel id constants
  2469  	const (
  2470  		chanSourceA      = 1
  2471  		chanATarget      = 4
  2472  		chanSourceB1     = 2
  2473  		chanSourceB2     = 3
  2474  		chanBTarget      = 5
  2475  		chanSourceTarget = 6
  2476  	)
  2477  
  2478  	// Set up a test graph with three possible paths from roasbeef to
  2479  	// target. The path through chanSourceB1 is the highest cost path.
  2480  	testChannels := []*testChannel{
  2481  		symmetricTestChannel("roasbeef", "a", 100000, &testChannelPolicy{
  2482  			Expiry: 144,
  2483  		}, chanSourceA),
  2484  		symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
  2485  			Expiry:  144,
  2486  			FeeRate: 400,
  2487  		}, chanATarget),
  2488  		symmetricTestChannel("roasbeef", "b", 100000, &testChannelPolicy{
  2489  			Expiry: 144,
  2490  		}, chanSourceB1),
  2491  		symmetricTestChannel("roasbeef", "b", 100000, &testChannelPolicy{
  2492  			Expiry: 144,
  2493  		}, chanSourceB2),
  2494  		symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
  2495  			Expiry:  144,
  2496  			FeeRate: 800,
  2497  		}, chanBTarget),
  2498  		symmetricTestChannel("roasbeef", "target", 100000, &testChannelPolicy{
  2499  			Expiry: 144,
  2500  		}, chanSourceTarget),
  2501  	}
  2502  
  2503  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  2504  	defer ctx.cleanup()
  2505  
  2506  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  2507  	target := ctx.keyFromAlias("target")
  2508  	outgoingChannelID := uint64(chanSourceB1)
  2509  
  2510  	// Find the best path given the restriction to only use channel 2 as the
  2511  	// outgoing channel.
  2512  	ctx.restrictParams.OutgoingChannelIDs = []uint64{outgoingChannelID}
  2513  	path, err := ctx.findPath(target, paymentAmt)
  2514  	if err != nil {
  2515  		t.Fatalf("unable to find path: %v", err)
  2516  	}
  2517  
  2518  	// Assert that the route starts with channel chanSourceB1, in line with
  2519  	// the specified restriction.
  2520  	if path[0].ChannelID != chanSourceB1 {
  2521  		t.Fatalf("expected route to pass through channel %v, "+
  2522  			"but channel %v was selected instead", chanSourceB1,
  2523  			path[0].ChannelID)
  2524  	}
  2525  
  2526  	// If a direct channel to target is allowed as well, that channel is
  2527  	// expected to be selected because the routing fees are zero.
  2528  	ctx.restrictParams.OutgoingChannelIDs = []uint64{
  2529  		chanSourceB1, chanSourceTarget,
  2530  	}
  2531  	path, err = ctx.findPath(target, paymentAmt)
  2532  	if err != nil {
  2533  		t.Fatalf("unable to find path: %v", err)
  2534  	}
  2535  	if path[0].ChannelID != chanSourceTarget {
  2536  		t.Fatalf("expected route to pass through channel %v",
  2537  			chanSourceTarget)
  2538  	}
  2539  }
  2540  
  2541  // runRestrictLastHop asserts that a last hop restriction is obeyed by the path
  2542  // finding algorithm.
  2543  func runRestrictLastHop(t *testing.T, useCache bool) {
  2544  	// Set up a test graph with three possible paths from roasbeef to
  2545  	// target. The path via channel 1 and 2 is the lowest cost path.
  2546  	testChannels := []*testChannel{
  2547  		symmetricTestChannel("source", "a", 100000, &testChannelPolicy{
  2548  			Expiry: 144,
  2549  		}, 1),
  2550  		symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
  2551  			Expiry:  144,
  2552  			FeeRate: 400,
  2553  		}, 2),
  2554  		symmetricTestChannel("source", "b", 100000, &testChannelPolicy{
  2555  			Expiry: 144,
  2556  		}, 3),
  2557  		symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
  2558  			Expiry:  144,
  2559  			FeeRate: 800,
  2560  		}, 4),
  2561  	}
  2562  
  2563  	ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
  2564  	defer ctx.cleanup()
  2565  
  2566  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  2567  	target := ctx.keyFromAlias("target")
  2568  	lastHop := ctx.keyFromAlias("b")
  2569  
  2570  	// Find the best path given the restriction to use b as the last hop.
  2571  	// This should force pathfinding to not take the lowest cost option.
  2572  	ctx.restrictParams.LastHop = &lastHop
  2573  	path, err := ctx.findPath(target, paymentAmt)
  2574  	if err != nil {
  2575  		t.Fatalf("unable to find path: %v", err)
  2576  	}
  2577  	if path[0].ChannelID != 3 {
  2578  		t.Fatalf("expected route to pass through channel 3, "+
  2579  			"but channel %v was selected instead",
  2580  			path[0].ChannelID)
  2581  	}
  2582  }
  2583  
  2584  // runCltvLimit asserts that a cltv limit is obeyed by the path finding
  2585  // algorithm.
  2586  func runCltvLimit(t *testing.T, useCache bool) {
  2587  	t.Run("no limit", func(t *testing.T) {
  2588  		testCltvLimit(t, useCache, 2016, 1)
  2589  	})
  2590  	t.Run("no path", func(t *testing.T) {
  2591  		testCltvLimit(t, useCache, 50, 0)
  2592  	})
  2593  	t.Run("force high cost", func(t *testing.T) {
  2594  		testCltvLimit(t, useCache, 80, 3)
  2595  	})
  2596  }
  2597  
  2598  func testCltvLimit(t *testing.T, useCache bool, limit uint32,
  2599  	expectedChannel uint64) {
  2600  
  2601  	t.Parallel()
  2602  
  2603  	// Set up a test graph with three possible paths to the target. The path
  2604  	// through a is the lowest cost with a high time lock (144). The path
  2605  	// through b has a higher cost but a lower time lock (100). That path
  2606  	// through c and d (two hops) has the same case as the path through b,
  2607  	// but the total time lock is lower (60).
  2608  	testChannels := []*testChannel{
  2609  		symmetricTestChannel("roasbeef", "a", 100000, &testChannelPolicy{}, 1),
  2610  		symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
  2611  			Expiry:        144,
  2612  			FeeBaseMAtoms: 10000,
  2613  			MinHTLC:       1,
  2614  		}),
  2615  		symmetricTestChannel("roasbeef", "b", 100000, &testChannelPolicy{}, 2),
  2616  		symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
  2617  			Expiry:        100,
  2618  			FeeBaseMAtoms: 20000,
  2619  			MinHTLC:       1,
  2620  		}),
  2621  		symmetricTestChannel("roasbeef", "c", 100000, &testChannelPolicy{}, 3),
  2622  		symmetricTestChannel("c", "d", 100000, &testChannelPolicy{
  2623  			Expiry:        30,
  2624  			FeeBaseMAtoms: 10000,
  2625  			MinHTLC:       1,
  2626  		}),
  2627  		symmetricTestChannel("d", "target", 100000, &testChannelPolicy{
  2628  			Expiry:        30,
  2629  			FeeBaseMAtoms: 10000,
  2630  			MinHTLC:       1,
  2631  		}),
  2632  	}
  2633  
  2634  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  2635  	defer ctx.cleanup()
  2636  
  2637  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  2638  	target := ctx.keyFromAlias("target")
  2639  
  2640  	ctx.restrictParams.CltvLimit = limit
  2641  	path, err := ctx.findPath(target, paymentAmt)
  2642  	if expectedChannel == 0 {
  2643  		// Finish test if we expect no route.
  2644  		if err == errNoPathFound {
  2645  			return
  2646  		}
  2647  		t.Fatal("expected no path to be found")
  2648  	}
  2649  	if err != nil {
  2650  		t.Fatalf("unable to find path: %v", err)
  2651  	}
  2652  
  2653  	const (
  2654  		startingHeight = 100
  2655  		finalHopCLTV   = 1
  2656  	)
  2657  	route, err := newRoute(
  2658  		ctx.source, path, startingHeight,
  2659  		finalHopParams{
  2660  			amt:       paymentAmt,
  2661  			cltvDelta: finalHopCLTV,
  2662  			records:   nil,
  2663  		},
  2664  	)
  2665  	if err != nil {
  2666  		t.Fatalf("unable to create path: %v", err)
  2667  	}
  2668  
  2669  	// Assert that the route starts with the expected channel.
  2670  	if route.Hops[0].ChannelID != expectedChannel {
  2671  		t.Fatalf("expected route to pass through channel %v, "+
  2672  			"but channel %v was selected instead", expectedChannel,
  2673  			route.Hops[0].ChannelID)
  2674  	}
  2675  }
  2676  
  2677  // runProbabilityRouting asserts that path finding not only takes into account
  2678  // fees but also success probability.
  2679  func runProbabilityRouting(t *testing.T, useCache bool) {
  2680  	testCases := []struct {
  2681  		name           string
  2682  		p10, p11, p20  float64
  2683  		minProbability float64
  2684  		expectedChan   uint64
  2685  		amount         dcrutil.Amount
  2686  	}{
  2687  		// Test two variations with probabilities that should multiply
  2688  		// to the same total route probability. In both cases the three
  2689  		// hop route should be the best route. The three hop route has a
  2690  		// probability of 0.5 * 0.8 = 0.4. The fee is 5 (chan 10) + 8
  2691  		// (chan 11) = 13. The attempt cost is 9 + 1% * 100 = 10. Path
  2692  		// finding distance should work out to: 13 + 10 (attempt
  2693  		// penalty) / 0.4 = 38. The two hop route is 25 + 10 / 0.7 = 39.
  2694  		{
  2695  			name: "three hop 1",
  2696  			p10:  0.8, p11: 0.5, p20: 0.7,
  2697  			minProbability: 0.1,
  2698  			expectedChan:   10,
  2699  			amount:         100,
  2700  		},
  2701  		{
  2702  			name: "three hop 2",
  2703  			p10:  0.5, p11: 0.8, p20: 0.7,
  2704  			minProbability: 0.1,
  2705  			expectedChan:   10,
  2706  			amount:         100,
  2707  		},
  2708  
  2709  		// If a larger amount is sent, the effect of the proportional
  2710  		// attempt cost becomes more noticeable. This amount in this
  2711  		// test brings the attempt cost to 9 + 1% * 300 = 12 sat. The
  2712  		// three hop path finding distance should work out to: 13 + 12
  2713  		// (attempt penalty) / 0.4 = 43. The two hop route is 25 + 12 /
  2714  		// 0.7 = 42. For this higher amount, the two hop route is
  2715  		// expected to be selected.
  2716  		{
  2717  			name: "two hop high amount",
  2718  			p10:  0.8, p11: 0.5, p20: 0.7,
  2719  			minProbability: 0.1,
  2720  			expectedChan:   20,
  2721  			amount:         300,
  2722  		},
  2723  
  2724  		// If the probability of the two hop route is increased, its
  2725  		// distance becomes 25 + 10 / 0.85 = 37. This is less than the
  2726  		// three hop route with its distance 38. So with an attempt
  2727  		// penalty of 10, the higher fee route is chosen because of the
  2728  		// compensation for success probability.
  2729  		{
  2730  			name: "two hop higher cost",
  2731  			p10:  0.5, p11: 0.8, p20: 0.85,
  2732  			minProbability: 0.1,
  2733  			expectedChan:   20,
  2734  			amount:         100,
  2735  		},
  2736  
  2737  		// If the same probabilities are used with a probability lower bound of
  2738  		// 0.5, we expect the three hop route with probability 0.4 to be
  2739  		// excluded and the two hop route to be picked.
  2740  		{
  2741  			name: "probability limit",
  2742  			p10:  0.8, p11: 0.5, p20: 0.7,
  2743  			minProbability: 0.5,
  2744  			expectedChan:   20,
  2745  			amount:         100,
  2746  		},
  2747  
  2748  		// With a probability limit above the probability of both routes, we
  2749  		// expect no route to be returned. This expectation is signaled by using
  2750  		// expected channel 0.
  2751  		{
  2752  			name: "probability limit no routes",
  2753  			p10:  0.8, p11: 0.5, p20: 0.7,
  2754  			minProbability: 0.8,
  2755  			expectedChan:   0,
  2756  			amount:         100,
  2757  		},
  2758  	}
  2759  
  2760  	for _, tc := range testCases {
  2761  		tc := tc
  2762  
  2763  		t.Run(tc.name, func(t *testing.T) {
  2764  			testProbabilityRouting(
  2765  				t, useCache, tc.amount, tc.p10, tc.p11, tc.p20,
  2766  				tc.minProbability, tc.expectedChan,
  2767  			)
  2768  		})
  2769  	}
  2770  }
  2771  
  2772  func testProbabilityRouting(t *testing.T, useCache bool,
  2773  	paymentAmt dcrutil.Amount, p10, p11, p20, minProbability float64,
  2774  	expectedChan uint64) {
  2775  
  2776  	t.Parallel()
  2777  
  2778  	// Set up a test graph with two possible paths to the target: a three
  2779  	// hop path (via channels 10 and 11) and a two hop path (via channel
  2780  	// 20).
  2781  	testChannels := []*testChannel{
  2782  		symmetricTestChannel("roasbeef", "a1", 100000, &testChannelPolicy{}),
  2783  		symmetricTestChannel("roasbeef", "b", 100000, &testChannelPolicy{}),
  2784  		symmetricTestChannel("a1", "a2", 100000, &testChannelPolicy{
  2785  			Expiry:        144,
  2786  			FeeBaseMAtoms: lnwire.NewMAtomsFromAtoms(5),
  2787  			MinHTLC:       1,
  2788  		}, 10),
  2789  		symmetricTestChannel("a2", "target", 100000, &testChannelPolicy{
  2790  			Expiry:        144,
  2791  			FeeBaseMAtoms: lnwire.NewMAtomsFromAtoms(8),
  2792  			MinHTLC:       1,
  2793  		}, 11),
  2794  		symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
  2795  			Expiry:        100,
  2796  			FeeBaseMAtoms: lnwire.NewMAtomsFromAtoms(25),
  2797  			MinHTLC:       1,
  2798  		}, 20),
  2799  	}
  2800  
  2801  	ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
  2802  	defer ctx.cleanup()
  2803  
  2804  	alias := ctx.testGraphInstance.aliasMap
  2805  
  2806  	target := ctx.testGraphInstance.aliasMap["target"]
  2807  
  2808  	// Configure a probability source with the test parameters.
  2809  	ctx.restrictParams.ProbabilitySource = func(fromNode, toNode route.Vertex,
  2810  		amt lnwire.MilliAtom) float64 {
  2811  
  2812  		if amt == 0 {
  2813  			t.Fatal("expected non-zero amount")
  2814  		}
  2815  
  2816  		switch {
  2817  		case fromNode == alias["a1"] && toNode == alias["a2"]:
  2818  			return p10
  2819  		case fromNode == alias["a2"] && toNode == alias["target"]:
  2820  			return p11
  2821  		case fromNode == alias["b"] && toNode == alias["target"]:
  2822  			return p20
  2823  		default:
  2824  			return 1
  2825  		}
  2826  	}
  2827  
  2828  	ctx.pathFindingConfig = PathFindingConfig{
  2829  		AttemptCost:    lnwire.NewMAtomsFromAtoms(9),
  2830  		AttemptCostPPM: 10000,
  2831  		MinProbability: minProbability,
  2832  	}
  2833  
  2834  	path, err := ctx.findPath(
  2835  		target, lnwire.NewMAtomsFromAtoms(paymentAmt),
  2836  	)
  2837  	if expectedChan == 0 {
  2838  		if err != errNoPathFound {
  2839  			t.Fatalf("expected no path found, but got %v", err)
  2840  		}
  2841  		return
  2842  	}
  2843  	if err != nil {
  2844  		t.Fatal(err)
  2845  	}
  2846  
  2847  	// Assert that the route passes through the expected channel.
  2848  	if path[1].ChannelID != expectedChan {
  2849  		t.Fatalf("expected route to pass through channel %v, "+
  2850  			"but channel %v was selected instead", expectedChan,
  2851  			path[1].ChannelID)
  2852  	}
  2853  }
  2854  
  2855  // runEqualCostRouteSelection asserts that route probability will be used as a
  2856  // tie breaker in case the path finding probabilities are equal.
  2857  func runEqualCostRouteSelection(t *testing.T, useCache bool) {
  2858  	// Set up a test graph with two possible paths to the target: via a and
  2859  	// via b. The routing fees and probabilities are chosen such that the
  2860  	// algorithm will first explore target->a->source (backwards search).
  2861  	// This route has fee 6 and a penality of 4 for the 25% success
  2862  	// probability. The algorithm will then proceed with evaluating
  2863  	// target->b->source, which has a fee of 8 and a penalty of 2 for the
  2864  	// 50% success probability. Both routes have the same path finding cost
  2865  	// of 10. It is expected that in that case, the highest probability
  2866  	// route (through b) is chosen.
  2867  	testChannels := []*testChannel{
  2868  		symmetricTestChannel("source", "a", 100000, &testChannelPolicy{}),
  2869  		symmetricTestChannel("source", "b", 100000, &testChannelPolicy{}),
  2870  		symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
  2871  			Expiry:        144,
  2872  			FeeBaseMAtoms: lnwire.NewMAtomsFromAtoms(6),
  2873  			MinHTLC:       1,
  2874  		}, 1),
  2875  		symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
  2876  			Expiry:        100,
  2877  			FeeBaseMAtoms: lnwire.NewMAtomsFromAtoms(8),
  2878  			MinHTLC:       1,
  2879  		}, 2),
  2880  	}
  2881  
  2882  	ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
  2883  	defer ctx.cleanup()
  2884  
  2885  	alias := ctx.testGraphInstance.aliasMap
  2886  
  2887  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  2888  	target := ctx.testGraphInstance.aliasMap["target"]
  2889  
  2890  	ctx.restrictParams.ProbabilitySource = func(fromNode, toNode route.Vertex,
  2891  		amt lnwire.MilliAtom) float64 {
  2892  
  2893  		switch {
  2894  		case fromNode == alias["source"] && toNode == alias["a"]:
  2895  			return 0.25
  2896  		case fromNode == alias["source"] && toNode == alias["b"]:
  2897  			return 0.5
  2898  		default:
  2899  			return 1
  2900  		}
  2901  	}
  2902  
  2903  	ctx.pathFindingConfig = PathFindingConfig{
  2904  		AttemptCost: lnwire.NewMAtomsFromAtoms(1),
  2905  	}
  2906  
  2907  	path, err := ctx.findPath(target, paymentAmt)
  2908  	if err != nil {
  2909  		t.Fatal(err)
  2910  	}
  2911  
  2912  	if path[1].ChannelID != 2 {
  2913  		t.Fatalf("expected route to pass through channel %v, "+
  2914  			"but channel %v was selected instead", 2,
  2915  			path[1].ChannelID)
  2916  	}
  2917  }
  2918  
  2919  // runNoCycle tries to guide the path finding algorithm into reconstructing an
  2920  // endless route. It asserts that the algorithm is able to handle this properly.
  2921  func runNoCycle(t *testing.T, useCache bool) {
  2922  	// Set up a test graph with two paths: source->a->target and
  2923  	// source->b->c->target. The fees are setup such that, searching
  2924  	// backwards, the algorithm will evaluate the following end of the route
  2925  	// first: ->target->c->target. This does not make sense, because if
  2926  	// target is reached, there is no need to continue to c. A proper
  2927  	// implementation will then go on with alternative routes. It will then
  2928  	// consider ->a->target because its cost is lower than the alternative
  2929  	// ->b->c->target and finally find source->a->target as the best route.
  2930  	testChannels := []*testChannel{
  2931  		symmetricTestChannel("source", "a", 100000, &testChannelPolicy{
  2932  			Expiry: 144,
  2933  		}, 1),
  2934  		symmetricTestChannel("source", "b", 100000, &testChannelPolicy{
  2935  			Expiry: 144,
  2936  		}, 2),
  2937  		symmetricTestChannel("b", "c", 100000, &testChannelPolicy{
  2938  			Expiry:        144,
  2939  			FeeBaseMAtoms: 2000,
  2940  		}, 3),
  2941  		symmetricTestChannel("c", "target", 100000, &testChannelPolicy{
  2942  			Expiry:        144,
  2943  			FeeBaseMAtoms: 0,
  2944  		}, 4),
  2945  		symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
  2946  			Expiry:        144,
  2947  			FeeBaseMAtoms: 600,
  2948  		}, 5),
  2949  	}
  2950  
  2951  	ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
  2952  	defer ctx.cleanup()
  2953  
  2954  	const (
  2955  		startingHeight = 100
  2956  		finalHopCLTV   = 1
  2957  	)
  2958  
  2959  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  2960  	target := ctx.keyFromAlias("target")
  2961  
  2962  	// Find the best path given the restriction to only use channel 2 as the
  2963  	// outgoing channel.
  2964  	path, err := ctx.findPath(target, paymentAmt)
  2965  	if err != nil {
  2966  		t.Fatalf("unable to find path: %v", err)
  2967  	}
  2968  	route, err := newRoute(
  2969  		ctx.source, path, startingHeight,
  2970  		finalHopParams{
  2971  			amt:       paymentAmt,
  2972  			cltvDelta: finalHopCLTV,
  2973  			records:   nil,
  2974  		},
  2975  	)
  2976  	if err != nil {
  2977  		t.Fatalf("unable to create path: %v", err)
  2978  	}
  2979  
  2980  	if len(route.Hops) != 2 {
  2981  		t.Fatalf("unexpected route")
  2982  	}
  2983  	if route.Hops[0].ChannelID != 1 {
  2984  		t.Fatalf("unexpected first hop")
  2985  	}
  2986  	if route.Hops[1].ChannelID != 5 {
  2987  		t.Fatalf("unexpected second hop")
  2988  	}
  2989  }
  2990  
  2991  // runRouteToSelf tests that it is possible to find a route to the self node.
  2992  func runRouteToSelf(t *testing.T, useCache bool) {
  2993  	testChannels := []*testChannel{
  2994  		symmetricTestChannel("source", "a", 100000, &testChannelPolicy{
  2995  			Expiry:        144,
  2996  			FeeBaseMAtoms: 500,
  2997  		}, 1),
  2998  		symmetricTestChannel("source", "b", 100000, &testChannelPolicy{
  2999  			Expiry:        144,
  3000  			FeeBaseMAtoms: 1000,
  3001  		}, 2),
  3002  		symmetricTestChannel("a", "b", 100000, &testChannelPolicy{
  3003  			Expiry:        144,
  3004  			FeeBaseMAtoms: 1000,
  3005  		}, 3),
  3006  	}
  3007  
  3008  	ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
  3009  	defer ctx.cleanup()
  3010  
  3011  	paymentAmt := lnwire.NewMAtomsFromAtoms(100)
  3012  	target := ctx.source
  3013  
  3014  	// Find the best path to self. We expect this to be source->a->source,
  3015  	// because a charges the lowest forwarding fee.
  3016  	path, err := ctx.findPath(target, paymentAmt)
  3017  	if err != nil {
  3018  		t.Fatalf("unable to find path: %v", err)
  3019  	}
  3020  	ctx.assertPath(path, []uint64{1, 1})
  3021  
  3022  	outgoingChanID := uint64(1)
  3023  	lastHop := ctx.keyFromAlias("b")
  3024  	ctx.restrictParams.OutgoingChannelIDs = []uint64{outgoingChanID}
  3025  	ctx.restrictParams.LastHop = &lastHop
  3026  
  3027  	// Find the best path to self given that we want to go out via channel 1
  3028  	// and return through node b.
  3029  	path, err = ctx.findPath(target, paymentAmt)
  3030  	if err != nil {
  3031  		t.Fatalf("unable to find path: %v", err)
  3032  	}
  3033  	ctx.assertPath(path, []uint64{1, 3, 2})
  3034  }
  3035  
  3036  type pathFindingTestContext struct {
  3037  	t                 *testing.T
  3038  	graph             *channeldb.ChannelGraph
  3039  	restrictParams    RestrictParams
  3040  	bandwidthHints    bandwidthHints
  3041  	pathFindingConfig PathFindingConfig
  3042  	testGraphInstance *testGraphInstance
  3043  	source            route.Vertex
  3044  }
  3045  
  3046  func newPathFindingTestContext(t *testing.T, useCache bool,
  3047  	testChannels []*testChannel, source string) *pathFindingTestContext {
  3048  
  3049  	testGraphInstance, err := createTestGraphFromChannels(
  3050  		useCache, testChannels, source,
  3051  	)
  3052  	if err != nil {
  3053  		t.Fatalf("unable to create graph: %v", err)
  3054  	}
  3055  
  3056  	sourceNode, err := testGraphInstance.graph.SourceNode()
  3057  	if err != nil {
  3058  		t.Fatalf("unable to fetch source node: %v", err)
  3059  	}
  3060  
  3061  	ctx := &pathFindingTestContext{
  3062  		t:                 t,
  3063  		testGraphInstance: testGraphInstance,
  3064  		source:            route.Vertex(sourceNode.PubKeyBytes),
  3065  		pathFindingConfig: *testPathFindingConfig,
  3066  		graph:             testGraphInstance.graph,
  3067  		restrictParams:    *noRestrictions,
  3068  		bandwidthHints:    &mockBandwidthHints{},
  3069  	}
  3070  
  3071  	return ctx
  3072  }
  3073  
  3074  func (c *pathFindingTestContext) keyFromAlias(alias string) route.Vertex {
  3075  	return c.testGraphInstance.aliasMap[alias]
  3076  }
  3077  
  3078  func (c *pathFindingTestContext) aliasFromKey(pubKey route.Vertex) string {
  3079  	for alias, key := range c.testGraphInstance.aliasMap {
  3080  		if key == pubKey {
  3081  			return alias
  3082  		}
  3083  	}
  3084  	return ""
  3085  }
  3086  
  3087  func (c *pathFindingTestContext) cleanup() {
  3088  	c.testGraphInstance.cleanUp()
  3089  }
  3090  
  3091  func (c *pathFindingTestContext) findPath(target route.Vertex,
  3092  	amt lnwire.MilliAtom) ([]*channeldb.CachedEdgePolicy,
  3093  	error) {
  3094  
  3095  	return dbFindPath(
  3096  		c.graph, nil, c.bandwidthHints, &c.restrictParams,
  3097  		&c.pathFindingConfig, c.source, target, amt, 0,
  3098  	)
  3099  }
  3100  
  3101  func (c *pathFindingTestContext) assertPath(path []*channeldb.CachedEdgePolicy,
  3102  	expected []uint64) {
  3103  
  3104  	if len(path) != len(expected) {
  3105  		c.t.Fatalf("expected path of length %v, but got %v",
  3106  			len(expected), len(path))
  3107  	}
  3108  
  3109  	for i, edge := range path {
  3110  		if edge.ChannelID != expected[i] {
  3111  			c.t.Fatalf("expected hop %v to be channel %v, "+
  3112  				"but got %v", i, expected[i], edge.ChannelID)
  3113  		}
  3114  	}
  3115  }
  3116  
  3117  // dbFindPath calls findPath after getting a db transaction from the database
  3118  // graph.
  3119  func dbFindPath(graph *channeldb.ChannelGraph,
  3120  	additionalEdges map[route.Vertex][]*channeldb.CachedEdgePolicy,
  3121  	bandwidthHints bandwidthHints,
  3122  	r *RestrictParams, cfg *PathFindingConfig,
  3123  	source, target route.Vertex, amt lnwire.MilliAtom,
  3124  	finalHtlcExpiry int32) ([]*channeldb.CachedEdgePolicy, error) {
  3125  
  3126  	sourceNode, err := graph.SourceNode()
  3127  	if err != nil {
  3128  		return nil, err
  3129  	}
  3130  
  3131  	routingGraph, err := NewCachedGraph(sourceNode, graph)
  3132  	if err != nil {
  3133  		return nil, err
  3134  	}
  3135  
  3136  	defer func() {
  3137  		if err := routingGraph.close(); err != nil {
  3138  			log.Errorf("Error closing db tx: %v", err)
  3139  		}
  3140  	}()
  3141  
  3142  	return findPath(
  3143  		&graphParams{
  3144  			additionalEdges: additionalEdges,
  3145  			bandwidthHints:  bandwidthHints,
  3146  			graph:           routingGraph,
  3147  		},
  3148  		r, cfg, source, target, amt, finalHtlcExpiry,
  3149  	)
  3150  }