/ graph / builder_test.go
builder_test.go
   1  package graph
   2  
   3  import (
   4  	"bytes"
   5  	"crypto/sha256"
   6  	"encoding/hex"
   7  	"encoding/json"
   8  	"errors"
   9  	"fmt"
  10  	"image/color"
  11  	"math/rand"
  12  	"net"
  13  	"os"
  14  	"strings"
  15  	"testing"
  16  	"time"
  17  
  18  	"github.com/btcsuite/btcd/btcec/v2"
  19  	"github.com/btcsuite/btcd/btcutil"
  20  	"github.com/btcsuite/btcd/chaincfg"
  21  	"github.com/btcsuite/btcd/chaincfg/chainhash"
  22  	"github.com/btcsuite/btcd/wire"
  23  	"github.com/lightningnetwork/lnd/chainntnfs"
  24  	graphdb "github.com/lightningnetwork/lnd/graph/db"
  25  	"github.com/lightningnetwork/lnd/graph/db/models"
  26  	"github.com/lightningnetwork/lnd/htlcswitch"
  27  	"github.com/lightningnetwork/lnd/lntest/wait"
  28  	"github.com/lightningnetwork/lnd/lnwire"
  29  	"github.com/lightningnetwork/lnd/routing/route"
  30  	"github.com/stretchr/testify/require"
  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  	testTimeout = 5 * time.Second
  40  )
  41  
  42  // TestAddProof checks that we can update the channel proof after channel
  43  // info was added to the database.
  44  func TestAddProof(t *testing.T) {
  45  	t.Parallel()
  46  	ctxb := t.Context()
  47  
  48  	ctx := createTestCtxSingleNode(t, 0)
  49  
  50  	// Before creating out edge, we'll create two new nodes within the
  51  	// network that the channel will connect.
  52  	node1 := createTestNode(t)
  53  	node2 := createTestNode(t)
  54  
  55  	// In order to be able to add the edge we should have a valid funding
  56  	// UTXO within the blockchain.
  57  	script, fundingTx, _, chanID := createChannelEdge(
  58  		t, bitcoinKey1.SerializeCompressed(),
  59  		bitcoinKey2.SerializeCompressed(), 100, 0,
  60  	)
  61  	fundingBlock := &wire.MsgBlock{
  62  		Transactions: []*wire.MsgTx{fundingTx},
  63  	}
  64  	ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
  65  
  66  	// After utxo was recreated adding the edge without the proof.
  67  	btcKey1 := route.NewVertex(bitcoinKey1)
  68  	btcKey2 := route.NewVertex(bitcoinKey2)
  69  
  70  	edge, err := models.NewV1Channel(
  71  		chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
  72  		node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
  73  			BitcoinKey1Bytes: btcKey1,
  74  			BitcoinKey2Bytes: btcKey2,
  75  		}, models.WithFundingScript(script),
  76  	)
  77  	require.NoError(t, err)
  78  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge))
  79  
  80  	// Now we'll attempt to update the proof and check that it has been
  81  	// properly updated.
  82  	require.NoError(t, ctx.builder.AddProof(*chanID, &testAuthProof))
  83  
  84  	info, _, _, err := ctx.builder.GetChannelByID(*chanID)
  85  	require.NoError(t, err, "unable to get channel")
  86  	require.NotNil(t, info.AuthProof)
  87  }
  88  
  89  // TestIgnoreNodeAnnouncement tests that adding a node to the router that is
  90  // not known from any channel announcement, leads to the announcement being
  91  // ignored.
  92  func TestIgnoreNodeAnnouncement(t *testing.T) {
  93  	t.Parallel()
  94  
  95  	const startingBlockHeight = 101
  96  	ctx := createTestCtxFromFile(t, startingBlockHeight, basicGraphFilePath)
  97  
  98  	pub := priv1.PubKey()
  99  	node := models.NewV1Node(
 100  		route.NewVertex(pub), &models.NodeV1Fields{
 101  			Addresses:    testAddrs,
 102  			AuthSigBytes: testSig.Serialize(),
 103  			Features:     testFeatures.RawFeatureVector,
 104  			LastUpdate:   time.Unix(123, 0),
 105  			Color:        color.RGBA{1, 2, 3, 0},
 106  			Alias:        "node11",
 107  		},
 108  	)
 109  
 110  	err := ctx.builder.AddNode(t.Context(), node)
 111  	require.Truef(
 112  		t, IsError(err, ErrIgnored),
 113  		"expected to get ErrIgnore, instead got: %v", err,
 114  	)
 115  }
 116  
 117  // TestIgnoreChannelEdgePolicyForUnknownChannel checks that a router will
 118  // ignore a channel policy for a channel not in the graph.
 119  func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) {
 120  	t.Parallel()
 121  	ctxb := t.Context()
 122  
 123  	const startingBlockHeight = 101
 124  
 125  	// Setup an initially empty network.
 126  	var testChannels []*testChannel
 127  	testGraph, err := createTestGraphFromChannels(
 128  		t, true, testChannels, "roasbeef",
 129  	)
 130  	require.NoError(t, err, "unable to create graph")
 131  
 132  	ctx := createTestCtxFromGraphInstance(
 133  		t, startingBlockHeight, testGraph, false,
 134  	)
 135  
 136  	var pub1 [33]byte
 137  	copy(pub1[:], priv1.PubKey().SerializeCompressed())
 138  
 139  	var pub2 [33]byte
 140  	copy(pub2[:], priv2.PubKey().SerializeCompressed())
 141  
 142  	// Add the edge between the two unknown nodes to the graph, and check
 143  	// that the nodes are found after the fact.
 144  	script, fundingTx, _, chanID := createChannelEdge(
 145  		t, bitcoinKey1.SerializeCompressed(),
 146  		bitcoinKey2.SerializeCompressed(), 10000, 500,
 147  	)
 148  	fundingBlock := &wire.MsgBlock{
 149  		Transactions: []*wire.MsgTx{fundingTx},
 150  	}
 151  	ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
 152  
 153  	pub1Vertex, err := route.NewVertexFromBytes(pub1[:])
 154  	require.NoError(t, err)
 155  	pub2Vertex, err := route.NewVertexFromBytes(pub2[:])
 156  	require.NoError(t, err)
 157  
 158  	edge, err := models.NewV1Channel(
 159  		chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
 160  		pub1Vertex, pub2Vertex, &models.ChannelV1Fields{
 161  			BitcoinKey1Bytes: pub1Vertex,
 162  			BitcoinKey2Bytes: pub2Vertex,
 163  		}, models.WithFundingScript(script),
 164  	)
 165  	require.NoError(t, err)
 166  
 167  	edgePolicy := &models.ChannelEdgePolicy{
 168  		Version:                   lnwire.GossipVersion1,
 169  		SigBytes:                  testSig.Serialize(),
 170  		ChannelID:                 edge.ChannelID,
 171  		LastUpdate:                testTime,
 172  		TimeLockDelta:             10,
 173  		MinHTLC:                   1,
 174  		FeeBaseMSat:               10,
 175  		FeeProportionalMillionths: 10000,
 176  	}
 177  
 178  	// Attempt to update the edge. This should be ignored, since the edge
 179  	// is not yet added to the router.
 180  	err = ctx.builder.UpdateEdge(ctxb, edgePolicy)
 181  	require.Truef(
 182  		t, IsError(err, ErrIgnored),
 183  		"expected to get ErrIgnore, instead got: %v", err,
 184  	)
 185  
 186  	// Add the edge.
 187  	require.NoErrorf(
 188  		t, ctx.builder.AddEdge(ctxb, edge),
 189  		"expected to be able to add edge to the channel graph, even "+
 190  			"though the vertexes were unknown: %v.", err,
 191  	)
 192  
 193  	// Now updating the edge policy should succeed.
 194  	require.NoError(t, ctx.builder.UpdateEdge(ctxb, edgePolicy))
 195  }
 196  
 197  // TestWakeUpOnStaleBranch tests that upon startup of the ChannelRouter, if the
 198  // chain previously reflected in the channel graph is stale (overtaken by a
 199  // longer chain), the channel router will prune the graph for any channels
 200  // confirmed on the stale chain, and resync to the main chain.
 201  func TestWakeUpOnStaleBranch(t *testing.T) {
 202  	t.Parallel()
 203  	ctxb := t.Context()
 204  
 205  	const startingBlockHeight = 101
 206  	ctx := createTestCtxSingleNode(t, startingBlockHeight)
 207  
 208  	const chanValue = 10000
 209  
 210  	// chanID1 will not be reorged out.
 211  	var chanID1 uint64
 212  
 213  	// chanID2 will be reorged out.
 214  	var chanID2 uint64
 215  
 216  	// Create 10 common blocks, confirming chanID1.
 217  	var fundingScript1 []byte
 218  	for i := uint32(1); i <= 10; i++ {
 219  		block := &wire.MsgBlock{
 220  			Transactions: []*wire.MsgTx{},
 221  		}
 222  		height := startingBlockHeight + i
 223  		if i == 5 {
 224  			script, fundingTx, _, chanID := createChannelEdge(
 225  				t, bitcoinKey1.SerializeCompressed(),
 226  				bitcoinKey2.SerializeCompressed(),
 227  				chanValue, height,
 228  			)
 229  			block.Transactions = append(block.Transactions,
 230  				fundingTx)
 231  			chanID1 = chanID.ToUint64()
 232  			fundingScript1 = script
 233  		}
 234  		ctx.chain.addBlock(block, height, rand.Uint32())
 235  		ctx.chain.setBestBlock(int32(height))
 236  		ctx.chainView.notifyBlock(block.BlockHash(), height,
 237  			[]*wire.MsgTx{}, t)
 238  	}
 239  
 240  	// Give time to process new blocks
 241  	time.Sleep(time.Millisecond * 500)
 242  
 243  	_, forkHeight, err := ctx.chain.GetBestBlock()
 244  	require.NoError(t, err, "unable to ge best block")
 245  
 246  	// Create 10 blocks on the minority chain, confirming chanID2.
 247  	var fundingScript2 []byte
 248  	for i := uint32(1); i <= 10; i++ {
 249  		block := &wire.MsgBlock{
 250  			Transactions: []*wire.MsgTx{},
 251  		}
 252  		height := uint32(forkHeight) + i
 253  		if i == 5 {
 254  			script, fundingTx, _, chanID := createChannelEdge(
 255  				t, bitcoinKey1.SerializeCompressed(),
 256  				bitcoinKey2.SerializeCompressed(),
 257  				chanValue, height)
 258  			block.Transactions = append(block.Transactions,
 259  				fundingTx)
 260  			chanID2 = chanID.ToUint64()
 261  			fundingScript2 = script
 262  		}
 263  		ctx.chain.addBlock(block, height, rand.Uint32())
 264  		ctx.chain.setBestBlock(int32(height))
 265  		ctx.chainView.notifyBlock(block.BlockHash(), height,
 266  			[]*wire.MsgTx{}, t)
 267  	}
 268  	// Give time to process new blocks
 269  	time.Sleep(time.Millisecond * 500)
 270  
 271  	// Now add the two edges to the channel graph, and check that they
 272  	// correctly show up in the database.
 273  	node1 := createTestNode(t)
 274  	node2 := createTestNode(t)
 275  
 276  	btcKey1, err := route.NewVertexFromBytes(
 277  		bitcoinKey1.SerializeCompressed(),
 278  	)
 279  	require.NoError(t, err)
 280  	btcKey2, err := route.NewVertexFromBytes(
 281  		bitcoinKey2.SerializeCompressed(),
 282  	)
 283  	require.NoError(t, err)
 284  
 285  	edge1, err := models.NewV1Channel(
 286  		chanID1, *chaincfg.SimNetParams.GenesisHash,
 287  		node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
 288  			BitcoinKey1Bytes: btcKey1,
 289  			BitcoinKey2Bytes: btcKey2,
 290  		}, models.WithChanProof(models.NewV1ChannelAuthProof(
 291  			testSig.Serialize(), testSig.Serialize(),
 292  			testSig.Serialize(), testSig.Serialize(),
 293  		)), models.WithFundingScript(fundingScript1),
 294  	)
 295  	require.NoError(t, err)
 296  
 297  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge1))
 298  
 299  	edge2, err := models.NewV1Channel(
 300  		chanID2, *chaincfg.SimNetParams.GenesisHash, node1.PubKeyBytes,
 301  		node2.PubKeyBytes, &models.ChannelV1Fields{
 302  			BitcoinKey1Bytes: btcKey1,
 303  			BitcoinKey2Bytes: btcKey2,
 304  		}, models.WithChanProof(models.NewV1ChannelAuthProof(
 305  			testSig.Serialize(), testSig.Serialize(),
 306  			testSig.Serialize(), testSig.Serialize(),
 307  		)), models.WithFundingScript(fundingScript2),
 308  	)
 309  	require.NoError(t, err)
 310  
 311  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge2))
 312  
 313  	// Check that the fundingTxs are in the graph db.
 314  	has, isZombie, err := ctx.graph.HasChannelEdge(t.Context(), chanID1)
 315  	require.NoError(t, err)
 316  	require.True(t, has)
 317  	require.False(t, isZombie)
 318  
 319  	has, isZombie, err = ctx.graph.HasChannelEdge(t.Context(), chanID2)
 320  	require.NoError(t, err)
 321  	require.True(t, has)
 322  	require.False(t, isZombie)
 323  
 324  	// Stop the router, so we can reorg the chain while its offline.
 325  	require.NoError(t, ctx.builder.Stop())
 326  
 327  	// Create a 15 block fork.
 328  	for i := uint32(1); i <= 15; i++ {
 329  		block := &wire.MsgBlock{
 330  			Transactions: []*wire.MsgTx{},
 331  		}
 332  		height := uint32(forkHeight) + i
 333  		ctx.chain.addBlock(block, height, rand.Uint32())
 334  		ctx.chain.setBestBlock(int32(height))
 335  	}
 336  
 337  	// Give time to process new blocks.
 338  	time.Sleep(time.Millisecond * 500)
 339  
 340  	selfNode, err := ctx.graph.SourceNode(t.Context())
 341  	require.NoError(t, err)
 342  
 343  	// Create new router with same graph database.
 344  	router, err := NewBuilder(&Config{
 345  		SelfNode:           selfNode.PubKeyBytes,
 346  		Graph:              ctx.graph.ChannelGraph,
 347  		Chain:              ctx.chain,
 348  		ChainView:          ctx.chainView,
 349  		ChannelPruneExpiry: time.Hour * 24,
 350  		GraphPruneInterval: time.Hour * 2,
 351  
 352  		// We'll set the delay to zero to prune immediately.
 353  		FirstTimePruneDelay: 0,
 354  		IsAlias: func(scid lnwire.ShortChannelID) bool {
 355  			return false
 356  		},
 357  	})
 358  	require.NoError(t, err)
 359  
 360  	// It should resync to the longer chain on startup.
 361  	require.NoError(t, router.Start())
 362  
 363  	// The channel with chanID2 should not be in the database anymore,
 364  	// since it is not confirmed on the longest chain. chanID1 should
 365  	// still be.
 366  	has, isZombie, err = ctx.graph.HasChannelEdge(t.Context(), chanID1)
 367  	require.NoError(t, err)
 368  	require.True(t, has)
 369  	require.False(t, isZombie)
 370  
 371  	has, isZombie, err = ctx.graph.HasChannelEdge(t.Context(), chanID2)
 372  	require.NoError(t, err)
 373  	require.False(t, has)
 374  	require.False(t, isZombie)
 375  }
 376  
 377  // TestDisconnectedBlocks checks that the router handles a reorg happening when
 378  // it is active.
 379  func TestDisconnectedBlocks(t *testing.T) {
 380  	t.Parallel()
 381  	ctxb := t.Context()
 382  
 383  	const startingBlockHeight = 101
 384  	ctx := createTestCtxSingleNode(t, startingBlockHeight)
 385  
 386  	const chanValue = 10000
 387  
 388  	// chanID1 will not be reorged out, while chanID2 will be reorged out.
 389  	var chanID1, chanID2 uint64
 390  
 391  	// Create 10 common blocks, confirming chanID1.
 392  	for i := uint32(1); i <= 10; i++ {
 393  		block := &wire.MsgBlock{
 394  			Transactions: []*wire.MsgTx{},
 395  		}
 396  		height := startingBlockHeight + i
 397  		if i == 5 {
 398  			_, fundingTx, _, chanID := createChannelEdge(
 399  				t, bitcoinKey1.SerializeCompressed(),
 400  				bitcoinKey2.SerializeCompressed(),
 401  				chanValue, height,
 402  			)
 403  			block.Transactions = append(block.Transactions,
 404  				fundingTx)
 405  			chanID1 = chanID.ToUint64()
 406  		}
 407  		ctx.chain.addBlock(block, height, rand.Uint32())
 408  		ctx.chain.setBestBlock(int32(height))
 409  		ctx.chainView.notifyBlock(block.BlockHash(), height,
 410  			[]*wire.MsgTx{}, t)
 411  	}
 412  
 413  	// Give time to process new blocks
 414  	time.Sleep(time.Millisecond * 500)
 415  
 416  	_, forkHeight, err := ctx.chain.GetBestBlock()
 417  	require.NoError(t, err, "unable to get best block")
 418  
 419  	// Create 10 blocks on the minority chain, confirming chanID2.
 420  	var minorityChain []*wire.MsgBlock
 421  	for i := uint32(1); i <= 10; i++ {
 422  		block := &wire.MsgBlock{
 423  			Transactions: []*wire.MsgTx{},
 424  		}
 425  		height := uint32(forkHeight) + i
 426  		if i == 5 {
 427  			_, fundingTx, _, chanID := createChannelEdge(
 428  				t, bitcoinKey1.SerializeCompressed(),
 429  				bitcoinKey2.SerializeCompressed(),
 430  				chanValue, height,
 431  			)
 432  			block.Transactions = append(block.Transactions,
 433  				fundingTx)
 434  			chanID2 = chanID.ToUint64()
 435  		}
 436  		minorityChain = append(minorityChain, block)
 437  		ctx.chain.addBlock(block, height, rand.Uint32())
 438  		ctx.chain.setBestBlock(int32(height))
 439  		ctx.chainView.notifyBlock(block.BlockHash(), height,
 440  			[]*wire.MsgTx{}, t)
 441  	}
 442  	// Give time to process new blocks
 443  	time.Sleep(time.Millisecond * 500)
 444  
 445  	// Now add the two edges to the channel graph, and check that they
 446  	// correctly show up in the database.
 447  	node1 := createTestNode(t)
 448  	node2 := createTestNode(t)
 449  
 450  	btcKey1 := route.NewVertex(bitcoinKey1)
 451  	btcKey2 := route.NewVertex(bitcoinKey2)
 452  
 453  	proof := models.NewV1ChannelAuthProof(
 454  		testSig.Serialize(),
 455  		testSig.Serialize(),
 456  		testSig.Serialize(),
 457  		testSig.Serialize(),
 458  	)
 459  
 460  	edge1, err := models.NewV1Channel(
 461  		chanID1, *chaincfg.SimNetParams.GenesisHash, node1.PubKeyBytes,
 462  		node2.PubKeyBytes, &models.ChannelV1Fields{
 463  			BitcoinKey1Bytes: btcKey1,
 464  			BitcoinKey2Bytes: btcKey2,
 465  		}, models.WithChanProof(proof),
 466  		models.WithFundingScript([]byte{}),
 467  	)
 468  	require.NoError(t, err)
 469  
 470  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge1))
 471  
 472  	edge2, err := models.NewV1Channel(
 473  		chanID2, *chaincfg.SimNetParams.GenesisHash, node1.PubKeyBytes,
 474  		node2.PubKeyBytes, &models.ChannelV1Fields{
 475  			BitcoinKey1Bytes: btcKey1,
 476  			BitcoinKey2Bytes: btcKey2,
 477  		}, models.WithChanProof(proof),
 478  		models.WithFundingScript([]byte{}),
 479  	)
 480  	require.NoError(t, err)
 481  
 482  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge2))
 483  
 484  	// Check that the fundingTxs are in the graph db.
 485  	has, isZombie, err := ctx.graph.HasChannelEdge(t.Context(), chanID1)
 486  	require.NoError(t, err)
 487  	require.True(t, has)
 488  	require.False(t, isZombie)
 489  
 490  	has, isZombie, err = ctx.graph.HasChannelEdge(t.Context(), chanID2)
 491  	require.NoError(t, err)
 492  	require.True(t, has)
 493  	require.False(t, isZombie)
 494  
 495  	// Create a 15 block fork. We first let the chainView notify the router
 496  	// about stale blocks, before sending the now connected blocks. We do
 497  	// this because we expect this order from the chainview.
 498  	ctx.chainView.notifyStaleBlockAck = make(chan struct{}, 1)
 499  	for i := len(minorityChain) - 1; i >= 0; i-- {
 500  		block := minorityChain[i]
 501  		height := uint32(forkHeight) + uint32(i) + 1
 502  		ctx.chainView.notifyStaleBlock(block.BlockHash(), height,
 503  			block.Transactions, t)
 504  		<-ctx.chainView.notifyStaleBlockAck
 505  	}
 506  
 507  	time.Sleep(time.Second * 2)
 508  
 509  	ctx.chainView.notifyBlockAck = make(chan struct{}, 1)
 510  	for i := uint32(1); i <= 15; i++ {
 511  		block := &wire.MsgBlock{
 512  			Transactions: []*wire.MsgTx{},
 513  		}
 514  		height := uint32(forkHeight) + i
 515  		ctx.chain.addBlock(block, height, rand.Uint32())
 516  		ctx.chain.setBestBlock(int32(height))
 517  		ctx.chainView.notifyBlock(block.BlockHash(), height,
 518  			block.Transactions, t)
 519  		<-ctx.chainView.notifyBlockAck
 520  	}
 521  
 522  	time.Sleep(time.Millisecond * 500)
 523  
 524  	// chanID2 should not be in the database anymore, since it is not
 525  	// confirmed on the longest chain. chanID1 should still be.
 526  	has, isZombie, err = ctx.graph.HasChannelEdge(t.Context(), chanID1)
 527  	require.NoError(t, err)
 528  	require.True(t, has)
 529  	require.False(t, isZombie)
 530  
 531  	has, isZombie, err = ctx.graph.HasChannelEdge(t.Context(), chanID2)
 532  	require.NoError(t, err)
 533  	require.False(t, has)
 534  	require.False(t, isZombie)
 535  }
 536  
 537  // TestChansClosedOfflinePruneGraph tests that if channels we know of are
 538  // closed while we're offline, then once we resume operation of the
 539  // ChannelRouter, then the channels are properly pruned.
 540  func TestChansClosedOfflinePruneGraph(t *testing.T) {
 541  	t.Parallel()
 542  	ctxb := t.Context()
 543  
 544  	const startingBlockHeight = 101
 545  	ctx := createTestCtxSingleNode(t, startingBlockHeight)
 546  
 547  	const chanValue = 10000
 548  
 549  	// First, we'll create a channel, to be mined shortly at height 102.
 550  	block102 := &wire.MsgBlock{
 551  		Transactions: []*wire.MsgTx{},
 552  	}
 553  	nextHeight := startingBlockHeight + 1
 554  	script, fundingTx1, chanUTXO, chanID1 := createChannelEdge(
 555  		t, bitcoinKey1.SerializeCompressed(),
 556  		bitcoinKey2.SerializeCompressed(),
 557  		chanValue, uint32(nextHeight),
 558  	)
 559  	block102.Transactions = append(block102.Transactions, fundingTx1)
 560  	ctx.chain.addBlock(block102, uint32(nextHeight), rand.Uint32())
 561  	ctx.chain.setBestBlock(int32(nextHeight))
 562  	ctx.chainView.notifyBlock(block102.BlockHash(), uint32(nextHeight),
 563  		[]*wire.MsgTx{}, t)
 564  
 565  	// We'll now create the edges and nodes within the database required
 566  	// for the ChannelRouter to properly recognize the channel we added
 567  	// above.
 568  	node1 := createTestNode(t)
 569  	node2 := createTestNode(t)
 570  
 571  	btcKey1 := route.NewVertex(bitcoinKey1)
 572  	btcKey2 := route.NewVertex(bitcoinKey2)
 573  
 574  	proof := models.NewV1ChannelAuthProof(
 575  		testSig.Serialize(),
 576  		testSig.Serialize(),
 577  		testSig.Serialize(),
 578  		testSig.Serialize(),
 579  	)
 580  
 581  	edge1, err := models.NewV1Channel(
 582  		chanID1.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
 583  		node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
 584  			BitcoinKey1Bytes: btcKey1,
 585  			BitcoinKey2Bytes: btcKey2,
 586  		}, models.WithChanProof(proof),
 587  		models.WithCapacity(chanValue),
 588  		models.WithChannelPoint(*chanUTXO),
 589  		models.WithFundingScript(script),
 590  	)
 591  	require.NoError(t, err)
 592  
 593  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge1))
 594  
 595  	// The router should now be aware of the channel we created above.
 596  	hasChan, isZombie, err := ctx.graph.HasChannelEdge(
 597  		t.Context(), chanID1.ToUint64(),
 598  	)
 599  	require.NoError(t, err)
 600  	require.True(t, hasChan)
 601  	require.False(t, isZombie)
 602  
 603  	// With the transaction included, and the router's database state
 604  	// updated, we'll now mine 5 additional blocks on top of it.
 605  	for i := 0; i < 5; i++ {
 606  		nextHeight++
 607  
 608  		block := &wire.MsgBlock{
 609  			Transactions: []*wire.MsgTx{},
 610  		}
 611  		ctx.chain.addBlock(block, uint32(nextHeight), rand.Uint32())
 612  		ctx.chain.setBestBlock(int32(nextHeight))
 613  		ctx.chainView.notifyBlock(block.BlockHash(), uint32(nextHeight),
 614  			[]*wire.MsgTx{}, t)
 615  	}
 616  
 617  	// At this point, our starting height should be 107.
 618  	_, chainHeight, err := ctx.chain.GetBestBlock()
 619  	require.NoError(t, err, "unable to get best block")
 620  	require.EqualValues(t, 107, chainHeight)
 621  
 622  	// Next, we'll "shut down" the router in order to simulate downtime.
 623  	require.NoError(t, ctx.builder.Stop())
 624  
 625  	// While the router is "offline" we'll mine 5 additional blocks, with
 626  	// the second block closing the channel we created above.
 627  	for i := 0; i < 5; i++ {
 628  		nextHeight++
 629  
 630  		block := &wire.MsgBlock{
 631  			Transactions: []*wire.MsgTx{},
 632  		}
 633  
 634  		if i == 2 {
 635  			// For the second block, we'll add a transaction that
 636  			// closes the channel we created above by spending the
 637  			// output.
 638  			closingTx := wire.NewMsgTx(2)
 639  			closingTx.AddTxIn(&wire.TxIn{
 640  				PreviousOutPoint: *chanUTXO,
 641  			})
 642  			block.Transactions = append(block.Transactions,
 643  				closingTx)
 644  		}
 645  
 646  		ctx.chain.addBlock(block, uint32(nextHeight), rand.Uint32())
 647  		ctx.chain.setBestBlock(int32(nextHeight))
 648  		ctx.chainView.notifyBlock(block.BlockHash(), uint32(nextHeight),
 649  			[]*wire.MsgTx{}, t)
 650  	}
 651  
 652  	// At this point, our starting height should be 112.
 653  	_, chainHeight, err = ctx.chain.GetBestBlock()
 654  	require.NoError(t, err, "unable to get best block")
 655  	require.EqualValues(t, 112, chainHeight)
 656  
 657  	// Now we'll re-start the ChannelRouter. It should recognize that it's
 658  	// behind the main chain and prune all the blocks that it missed while
 659  	// it was down.
 660  	ctx.RestartBuilder(t)
 661  
 662  	// At this point, the channel that was pruned should no longer be known
 663  	// by the router.
 664  	hasChan, isZombie, err = ctx.graph.HasChannelEdge(
 665  		t.Context(), chanID1.ToUint64(),
 666  	)
 667  	require.NoError(t, err)
 668  	require.False(t, hasChan)
 669  	require.False(t, isZombie)
 670  }
 671  
 672  // TestPruneChannelGraphStaleEdges ensures that we properly prune stale edges
 673  // from the channel graph.
 674  func TestPruneChannelGraphStaleEdges(t *testing.T) {
 675  	t.Parallel()
 676  
 677  	freshTimestamp := time.Now()
 678  	staleTimestamp := time.Unix(0, 0)
 679  
 680  	// We'll create the following test graph so that two of the channels
 681  	// are pruned.
 682  	testChannels := []*testChannel{
 683  		// No edges.
 684  		{
 685  			Node1:     &testChannelEnd{Alias: "a"},
 686  			Node2:     &testChannelEnd{Alias: "b"},
 687  			Capacity:  100000,
 688  			ChannelID: 1,
 689  		},
 690  
 691  		// Only one edge with a stale timestamp.
 692  		{
 693  			Node1: &testChannelEnd{
 694  				Alias: "d",
 695  				testChannelPolicy: &testChannelPolicy{
 696  					LastUpdate: staleTimestamp,
 697  				},
 698  			},
 699  			Node2:     &testChannelEnd{Alias: "b"},
 700  			Capacity:  100000,
 701  			ChannelID: 2,
 702  		},
 703  
 704  		// Only one edge with a stale timestamp, but it's the source
 705  		// node so it won't get pruned.
 706  		{
 707  			Node1: &testChannelEnd{
 708  				Alias: "a",
 709  				testChannelPolicy: &testChannelPolicy{
 710  					LastUpdate: staleTimestamp,
 711  				},
 712  			},
 713  			Node2:     &testChannelEnd{Alias: "b"},
 714  			Capacity:  100000,
 715  			ChannelID: 3,
 716  		},
 717  
 718  		// Only one edge with a fresh timestamp.
 719  		{
 720  			Node1: &testChannelEnd{
 721  				Alias: "a",
 722  				testChannelPolicy: &testChannelPolicy{
 723  					LastUpdate: freshTimestamp,
 724  				},
 725  			},
 726  			Node2:     &testChannelEnd{Alias: "b"},
 727  			Capacity:  100000,
 728  			ChannelID: 4,
 729  		},
 730  
 731  		// One edge fresh, one edge stale. This will be pruned with
 732  		// strict pruning activated.
 733  		{
 734  			Node1: &testChannelEnd{
 735  				Alias: "c",
 736  				testChannelPolicy: &testChannelPolicy{
 737  					LastUpdate: freshTimestamp,
 738  				},
 739  			},
 740  			Node2: &testChannelEnd{
 741  				Alias: "d",
 742  				testChannelPolicy: &testChannelPolicy{
 743  					LastUpdate: staleTimestamp,
 744  				},
 745  			},
 746  			Capacity:  100000,
 747  			ChannelID: 5,
 748  		},
 749  
 750  		// Both edges fresh.
 751  		symmetricTestChannel("g", "h", 100000, &testChannelPolicy{
 752  			LastUpdate: freshTimestamp,
 753  		}, 6),
 754  
 755  		// Both edges stale, only one pruned. This should be pruned for
 756  		// both normal and strict pruning.
 757  		symmetricTestChannel("e", "f", 100000, &testChannelPolicy{
 758  			LastUpdate: staleTimestamp,
 759  		}, 7),
 760  	}
 761  
 762  	for _, strictPruning := range []bool{true, false} {
 763  		// We'll create our test graph and router backed with these test
 764  		// channels we've created.
 765  		testGraph, err := createTestGraphFromChannels(
 766  			t, true, testChannels, "a",
 767  		)
 768  		require.NoError(t, err)
 769  
 770  		const startingHeight = 100
 771  		ctx := createTestCtxFromGraphInstance(
 772  			t, startingHeight, testGraph, strictPruning,
 773  		)
 774  
 775  		// All of the channels should exist before pruning them.
 776  		assertChannelsPruned(t, ctx.graph, testChannels)
 777  
 778  		// Proceed to prune the channels - only the last one should be
 779  		// pruned.
 780  		require.NoError(t, ctx.builder.pruneZombieChans())
 781  
 782  		// We expect channels that have either both edges stale, or one
 783  		// edge stale with both known.
 784  		var prunedChannels []uint64
 785  		if strictPruning {
 786  			prunedChannels = []uint64{2, 5, 7}
 787  		} else {
 788  			prunedChannels = []uint64{2, 7}
 789  		}
 790  		assertChannelsPruned(
 791  			t, ctx.graph, testChannels, prunedChannels...,
 792  		)
 793  	}
 794  }
 795  
 796  // TestPruneChannelGraphDoubleDisabled test that we can properly prune channels
 797  // with both edges disabled from our channel graph.
 798  func TestPruneChannelGraphDoubleDisabled(t *testing.T) {
 799  	t.Parallel()
 800  
 801  	t.Run("no_assumechannelvalid", func(t *testing.T) {
 802  		testPruneChannelGraphDoubleDisabled(t, false)
 803  	})
 804  	t.Run("assumechannelvalid", func(t *testing.T) {
 805  		testPruneChannelGraphDoubleDisabled(t, true)
 806  	})
 807  }
 808  
 809  func testPruneChannelGraphDoubleDisabled(t *testing.T, assumeValid bool) {
 810  	timestamp := time.Now()
 811  
 812  	// nextTimeStamp is a helper closure that will return a new
 813  	// timestamp each time it's called, this helps us create channel updates
 814  	// with new timestamps so that we don't run into our SQL DB constraint
 815  	// which only allows an update to a channel edge if the last update
 816  	// timestamp is greater than the previous one.
 817  	nextTimeStamp := func() time.Time {
 818  		timestamp = timestamp.Add(time.Second)
 819  
 820  		return timestamp
 821  	}
 822  
 823  	// We'll create the following test graph so that only the last channel
 824  	// is pruned. We'll use a fresh timestamp to ensure they're not pruned
 825  	// according to that heuristic.
 826  	testChannels := []*testChannel{
 827  		// Channel from self shouldn't be pruned.
 828  		symmetricTestChannel(
 829  			"self", "a", 100000, &testChannelPolicy{
 830  				LastUpdate: nextTimeStamp(),
 831  				Disabled:   true,
 832  			}, 99,
 833  		),
 834  
 835  		// No edges.
 836  		{
 837  			Node1:     &testChannelEnd{Alias: "a"},
 838  			Node2:     &testChannelEnd{Alias: "b"},
 839  			Capacity:  100000,
 840  			ChannelID: 1,
 841  		},
 842  
 843  		// Only one edge disabled.
 844  		{
 845  			Node1: &testChannelEnd{
 846  				Alias: "a",
 847  				testChannelPolicy: &testChannelPolicy{
 848  					LastUpdate: nextTimeStamp(),
 849  					Disabled:   true,
 850  				},
 851  			},
 852  			Node2:     &testChannelEnd{Alias: "b"},
 853  			Capacity:  100000,
 854  			ChannelID: 2,
 855  		},
 856  
 857  		// Only one edge enabled.
 858  		{
 859  			Node1: &testChannelEnd{
 860  				Alias: "a",
 861  				testChannelPolicy: &testChannelPolicy{
 862  					LastUpdate: nextTimeStamp(),
 863  					Disabled:   false,
 864  				},
 865  			},
 866  			Node2:     &testChannelEnd{Alias: "b"},
 867  			Capacity:  100000,
 868  			ChannelID: 3,
 869  		},
 870  
 871  		// One edge disabled, one edge enabled.
 872  		{
 873  			Node1: &testChannelEnd{
 874  				Alias: "a",
 875  				testChannelPolicy: &testChannelPolicy{
 876  					LastUpdate: nextTimeStamp(),
 877  					Disabled:   true,
 878  				},
 879  			},
 880  			Node2: &testChannelEnd{
 881  				Alias: "b",
 882  				testChannelPolicy: &testChannelPolicy{
 883  					LastUpdate: nextTimeStamp(),
 884  					Disabled:   false,
 885  				},
 886  			},
 887  			Capacity:  100000,
 888  			ChannelID: 1,
 889  		},
 890  
 891  		// Both edges enabled.
 892  		symmetricTestChannel("c", "d", 100000, &testChannelPolicy{
 893  			LastUpdate: nextTimeStamp(),
 894  			Disabled:   false,
 895  		}, 2),
 896  
 897  		// Both edges disabled, only one pruned.
 898  		symmetricTestChannel("e", "f", 100000, &testChannelPolicy{
 899  			LastUpdate: nextTimeStamp(),
 900  			Disabled:   true,
 901  		}, 3),
 902  	}
 903  
 904  	// We'll create our test graph and router backed with these test
 905  	// channels we've created.
 906  	testGraph, err := createTestGraphFromChannels(
 907  		t, true, testChannels, "self",
 908  	)
 909  	require.NoError(t, err, "unable to create test graph")
 910  
 911  	const startingHeight = 100
 912  	ctx := createTestCtxFromGraphInstanceAssumeValid(
 913  		t, startingHeight, testGraph, assumeValid, false,
 914  	)
 915  
 916  	// All the channels should exist within the graph before pruning them
 917  	// when not using AssumeChannelValid, otherwise we should have pruned
 918  	// the last channel on startup.
 919  	if !assumeValid {
 920  		assertChannelsPruned(t, ctx.graph, testChannels)
 921  	} else {
 922  		// Sleep to allow the pruning to finish.
 923  		time.Sleep(200 * time.Millisecond)
 924  
 925  		prunedChannel := testChannels[len(testChannels)-1].ChannelID
 926  		assertChannelsPruned(t, ctx.graph, testChannels, prunedChannel)
 927  	}
 928  
 929  	require.NoError(t, ctx.builder.pruneZombieChans())
 930  
 931  	// If we attempted to prune them without AssumeChannelValid being set,
 932  	// none should be pruned. Otherwise the last channel should still be
 933  	// pruned.
 934  	if !assumeValid {
 935  		assertChannelsPruned(t, ctx.graph, testChannels)
 936  	} else {
 937  		prunedChannel := testChannels[len(testChannels)-1].ChannelID
 938  		assertChannelsPruned(t, ctx.graph, testChannels, prunedChannel)
 939  	}
 940  }
 941  
 942  // TestIsStaleNode tests that the IsStaleNode method properly detects stale
 943  // node announcements.
 944  func TestIsStaleNode(t *testing.T) {
 945  	t.Parallel()
 946  	ctxb := t.Context()
 947  
 948  	const startingBlockHeight = 101
 949  	ctx := createTestCtxSingleNode(t, startingBlockHeight)
 950  
 951  	// Before we can insert a node in to the database, we need to create a
 952  	// channel that it's linked to.
 953  	var (
 954  		pub1 [33]byte
 955  		pub2 [33]byte
 956  	)
 957  	copy(pub1[:], priv1.PubKey().SerializeCompressed())
 958  	copy(pub2[:], priv2.PubKey().SerializeCompressed())
 959  
 960  	script, fundingTx, _, chanID := createChannelEdge(
 961  		t, bitcoinKey1.SerializeCompressed(),
 962  		bitcoinKey2.SerializeCompressed(),
 963  		10000, 500,
 964  	)
 965  	fundingBlock := &wire.MsgBlock{
 966  		Transactions: []*wire.MsgTx{fundingTx},
 967  	}
 968  	ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
 969  
 970  	edge, err := models.NewV1Channel(
 971  		chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
 972  		pub1, pub2, &models.ChannelV1Fields{
 973  			BitcoinKey1Bytes: pub1,
 974  			BitcoinKey2Bytes: pub2,
 975  		}, models.WithFundingScript(script),
 976  	)
 977  	require.NoError(t, err)
 978  
 979  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge))
 980  
 981  	// Before we add the node, if we query for staleness, we should get
 982  	// false, as we haven't added the full node.
 983  	updateTimeStamp := time.Unix(123, 0)
 984  	require.False(t, ctx.builder.IsStaleNode(ctxb, pub1, updateTimeStamp))
 985  
 986  	// With the node stub in the database, we'll add the fully node
 987  	// announcement to the database.
 988  	n1 := models.NewV1Node(
 989  		route.NewVertex(priv1.PubKey()), &models.NodeV1Fields{
 990  			LastUpdate:   updateTimeStamp,
 991  			Addresses:    testAddrs,
 992  			Color:        color.RGBA{1, 2, 3, 0},
 993  			Alias:        "node11",
 994  			AuthSigBytes: testSig.Serialize(),
 995  			Features:     testFeatures.RawFeatureVector,
 996  		},
 997  	)
 998  	require.NoError(t, ctx.builder.AddNode(t.Context(), n1))
 999  
1000  	// If we use the same timestamp and query for staleness, we should get
1001  	// true.
1002  	require.True(t, ctx.builder.IsStaleNode(ctxb, pub1, updateTimeStamp))
1003  
1004  	// If we update the timestamp and once again query for staleness, it
1005  	// should report false.
1006  	newTimeStamp := time.Unix(1234, 0)
1007  	require.False(t, ctx.builder.IsStaleNode(ctxb, pub1, newTimeStamp))
1008  }
1009  
1010  // TestIsKnownEdge tests that the IsKnownEdge method properly detects stale
1011  // channel announcements.
1012  func TestIsKnownEdge(t *testing.T) {
1013  	t.Parallel()
1014  	ctxb := t.Context()
1015  
1016  	const startingBlockHeight = 101
1017  	ctx := createTestCtxSingleNode(t, startingBlockHeight)
1018  
1019  	// First, we'll create a new channel edge (just the info) and insert it
1020  	// into the database.
1021  	var (
1022  		pub1 [33]byte
1023  		pub2 [33]byte
1024  	)
1025  	copy(pub1[:], priv1.PubKey().SerializeCompressed())
1026  	copy(pub2[:], priv2.PubKey().SerializeCompressed())
1027  
1028  	script, fundingTx, _, chanID := createChannelEdge(
1029  		t, bitcoinKey1.SerializeCompressed(),
1030  		bitcoinKey2.SerializeCompressed(),
1031  		10000, 500,
1032  	)
1033  	fundingBlock := &wire.MsgBlock{
1034  		Transactions: []*wire.MsgTx{fundingTx},
1035  	}
1036  	ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
1037  
1038  	edge, err := models.NewV1Channel(
1039  		chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash, pub1,
1040  		pub2, &models.ChannelV1Fields{
1041  			BitcoinKey1Bytes: pub1,
1042  			BitcoinKey2Bytes: pub2,
1043  		},
1044  		models.WithFundingScript(script),
1045  	)
1046  	require.NoError(t, err)
1047  
1048  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge))
1049  
1050  	// Now that the edge has been inserted, query is the router already
1051  	// knows of the edge should return true.
1052  	require.True(t, ctx.builder.IsKnownEdge(*chanID))
1053  }
1054  
1055  // TestIsStaleEdgePolicy tests that the IsStaleEdgePolicy properly detects
1056  // stale channel edge update announcements.
1057  func TestIsStaleEdgePolicy(t *testing.T) {
1058  	t.Parallel()
1059  	ctxb := t.Context()
1060  
1061  	const startingBlockHeight = 101
1062  	ctx := createTestCtxFromFile(t, startingBlockHeight, basicGraphFilePath)
1063  
1064  	// First, we'll create a new channel edge (just the info) and insert it
1065  	// into the database.
1066  	var (
1067  		pub1 [33]byte
1068  		pub2 [33]byte
1069  	)
1070  	copy(pub1[:], priv1.PubKey().SerializeCompressed())
1071  	copy(pub2[:], priv2.PubKey().SerializeCompressed())
1072  
1073  	script, fundingTx, _, chanID := createChannelEdge(
1074  		t, bitcoinKey1.SerializeCompressed(),
1075  		bitcoinKey2.SerializeCompressed(),
1076  		10000, 500,
1077  	)
1078  	fundingBlock := &wire.MsgBlock{
1079  		Transactions: []*wire.MsgTx{fundingTx},
1080  	}
1081  	ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
1082  
1083  	// If we query for staleness before adding the edge, we should get
1084  	// false.
1085  	updateTimeStamp := time.Unix(123, 0)
1086  	require.False(
1087  		t, ctx.builder.IsStaleEdgePolicy(
1088  			*chanID, updateTimeStamp, 0,
1089  		),
1090  	)
1091  	require.False(
1092  		t, ctx.builder.IsStaleEdgePolicy(
1093  			*chanID, updateTimeStamp, 1,
1094  		),
1095  	)
1096  
1097  	edge, err := models.NewV1Channel(
1098  		chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash, pub1,
1099  		pub2, &models.ChannelV1Fields{
1100  			BitcoinKey1Bytes: pub1,
1101  			BitcoinKey2Bytes: pub2,
1102  		}, models.WithFundingScript(script),
1103  	)
1104  	require.NoError(t, err)
1105  
1106  	require.NoError(t, ctx.builder.AddEdge(ctxb, edge))
1107  
1108  	// We'll also add two edge policies, one for each direction.
1109  	edgePolicy := &models.ChannelEdgePolicy{
1110  		Version:                   lnwire.GossipVersion1,
1111  		SigBytes:                  testSig.Serialize(),
1112  		ChannelID:                 edge.ChannelID,
1113  		LastUpdate:                updateTimeStamp,
1114  		TimeLockDelta:             10,
1115  		MinHTLC:                   1,
1116  		FeeBaseMSat:               10,
1117  		FeeProportionalMillionths: 10000,
1118  	}
1119  	edgePolicy.ChannelFlags = 0
1120  	require.NoError(t, ctx.builder.UpdateEdge(ctxb, edgePolicy))
1121  
1122  	edgePolicy = &models.ChannelEdgePolicy{
1123  		Version:                   lnwire.GossipVersion1,
1124  		SigBytes:                  testSig.Serialize(),
1125  		ChannelID:                 edge.ChannelID,
1126  		LastUpdate:                updateTimeStamp,
1127  		TimeLockDelta:             10,
1128  		MinHTLC:                   1,
1129  		FeeBaseMSat:               10,
1130  		FeeProportionalMillionths: 10000,
1131  	}
1132  	edgePolicy.ChannelFlags = 1
1133  	require.NoError(t, ctx.builder.UpdateEdge(ctxb, edgePolicy))
1134  
1135  	// Now that the edges have been added, an identical (chanID, flag,
1136  	// timestamp) tuple for each edge should be detected as a stale edge.
1137  	require.True(
1138  		t, ctx.builder.IsStaleEdgePolicy(
1139  			*chanID, updateTimeStamp, 0,
1140  		),
1141  	)
1142  	require.True(
1143  		t, ctx.builder.IsStaleEdgePolicy(
1144  			*chanID, updateTimeStamp, 1,
1145  		),
1146  	)
1147  
1148  	// If we now update the timestamp for both edges, the router should
1149  	// detect that this tuple represents a fresh edge.
1150  	updateTimeStamp = time.Unix(9999, 0)
1151  	require.False(
1152  		t, ctx.builder.IsStaleEdgePolicy(
1153  			*chanID, updateTimeStamp, 0,
1154  		),
1155  	)
1156  	require.False(
1157  		t, ctx.builder.IsStaleEdgePolicy(
1158  			*chanID, updateTimeStamp, 1,
1159  		),
1160  	)
1161  }
1162  
1163  // TestBlockDifferenceFix tests if when the router is behind on blocks, the
1164  // router catches up to the best block head.
1165  func TestBlockDifferenceFix(t *testing.T) {
1166  	t.Parallel()
1167  
1168  	initialBlockHeight := uint32(0)
1169  
1170  	// Starting height here is set to 0, which is behind where we want to
1171  	// be.
1172  	ctx := createTestCtxSingleNode(t, initialBlockHeight)
1173  
1174  	// Add initial block to our mini blockchain.
1175  	block := &wire.MsgBlock{
1176  		Transactions: []*wire.MsgTx{},
1177  	}
1178  	ctx.chain.addBlock(block, initialBlockHeight, rand.Uint32())
1179  
1180  	// Let's generate a new block of height 5, 5 above where our node is at.
1181  	newBlock := &wire.MsgBlock{
1182  		Transactions: []*wire.MsgTx{},
1183  	}
1184  	newBlockHeight := uint32(5)
1185  
1186  	blockDifference := newBlockHeight - initialBlockHeight
1187  
1188  	ctx.chainView.notifyBlockAck = make(chan struct{}, 1)
1189  
1190  	ctx.chain.addBlock(newBlock, newBlockHeight, rand.Uint32())
1191  	ctx.chain.setBestBlock(int32(newBlockHeight))
1192  	ctx.chainView.notifyBlock(block.BlockHash(), newBlockHeight,
1193  		[]*wire.MsgTx{}, t)
1194  
1195  	<-ctx.chainView.notifyBlockAck
1196  
1197  	// At this point, the chain notifier should have noticed that we're
1198  	// behind on blocks, and will send the n missing blocks that we
1199  	// need to the client's epochs channel. Let's replicate this
1200  	// functionality.
1201  	for i := 0; i < int(blockDifference); i++ {
1202  		currBlockHeight := int32(i + 1)
1203  
1204  		nonce := rand.Uint32()
1205  
1206  		newBlock := &wire.MsgBlock{
1207  			Transactions: []*wire.MsgTx{},
1208  			Header:       wire.BlockHeader{Nonce: nonce},
1209  		}
1210  		ctx.chain.addBlock(newBlock, uint32(currBlockHeight), nonce)
1211  		currHash := newBlock.Header.BlockHash()
1212  
1213  		newEpoch := &chainntnfs.BlockEpoch{
1214  			Height: currBlockHeight,
1215  			Hash:   &currHash,
1216  		}
1217  
1218  		ctx.notifier.EpochChan <- newEpoch
1219  
1220  		ctx.chainView.notifyBlock(currHash,
1221  			uint32(currBlockHeight), block.Transactions, t)
1222  
1223  		<-ctx.chainView.notifyBlockAck
1224  	}
1225  
1226  	err := wait.NoError(func() error {
1227  		// Then router height should be updated to the latest block.
1228  		if ctx.builder.bestHeight.Load() != newBlockHeight {
1229  			return fmt.Errorf("height should have been updated "+
1230  				"to %v, instead got %v", newBlockHeight,
1231  				ctx.builder.bestHeight.Load())
1232  		}
1233  
1234  		return nil
1235  	}, testTimeout)
1236  	require.NoError(t, err, "block height wasn't updated")
1237  }
1238  
1239  func createTestCtxFromFile(t *testing.T,
1240  	startingHeight uint32, testGraph string) *testCtx {
1241  
1242  	// We'll attempt to locate and parse out the file
1243  	// that encodes the graph that our tests should be run against.
1244  	graphInstance, err := parseTestGraph(t, true, testGraph)
1245  	require.NoError(t, err, "unable to create test graph")
1246  
1247  	return createTestCtxFromGraphInstance(
1248  		t, startingHeight, graphInstance, false,
1249  	)
1250  }
1251  
1252  // parseTestGraph returns a fully populated ChannelGraph given a path to a JSON
1253  // file which encodes a test graph.
1254  func parseTestGraph(t *testing.T, useCache bool, path string) (
1255  	*testGraphInstance, error) {
1256  
1257  	ctx := t.Context()
1258  
1259  	graphJSON, err := os.ReadFile(path)
1260  	if err != nil {
1261  		return nil, err
1262  	}
1263  
1264  	// First unmarshal the JSON graph into an instance of the testGraph
1265  	// struct. Using the struct tags created above in the struct, the JSON
1266  	// will be properly parsed into the struct above.
1267  	var g testGraph
1268  	if err := json.Unmarshal(graphJSON, &g); err != nil {
1269  		return nil, err
1270  	}
1271  
1272  	// We'll use this fake address for the IP address of all the nodes in
1273  	// our tests. This value isn't needed for path finding so it doesn't
1274  	// need to be unique.
1275  	var testAddrs []net.Addr
1276  	testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888")
1277  	if err != nil {
1278  		return nil, err
1279  	}
1280  	testAddrs = append(testAddrs, testAddr)
1281  
1282  	// Next, create a temporary graph database for usage within the test.
1283  	graph := graphdb.MakeTestGraph(
1284  		t, graphdb.WithUseGraphCache(useCache),
1285  	)
1286  
1287  	aliasMap := make(map[string]route.Vertex)
1288  	privKeyMap := make(map[string]*btcec.PrivateKey)
1289  	channelIDs := make(map[route.Vertex]map[route.Vertex]uint64)
1290  	links := make(map[lnwire.ShortChannelID]htlcswitch.ChannelLink)
1291  	var source *models.Node
1292  
1293  	// First we insert all the nodes within the graph as vertexes.
1294  	for _, node := range g.Nodes {
1295  		pubBytes, err := hex.DecodeString(node.PubKey)
1296  		if err != nil {
1297  			return nil, err
1298  		}
1299  
1300  		pubKey, err := route.NewVertexFromBytes(pubBytes)
1301  		require.NoError(t, err)
1302  
1303  		dbNode := models.NewV1Node(pubKey, &models.NodeV1Fields{
1304  			AuthSigBytes: testSig.Serialize(),
1305  			LastUpdate:   testTime,
1306  			Addresses:    testAddrs,
1307  			Alias:        node.Alias,
1308  			Features:     testFeatures.RawFeatureVector,
1309  		})
1310  
1311  		// We require all aliases within the graph to be unique for our
1312  		// tests.
1313  		if _, ok := aliasMap[node.Alias]; ok {
1314  			return nil, errors.New("aliases for nodes " +
1315  				"must be unique!")
1316  		}
1317  
1318  		// If the alias is unique, then add the node to the
1319  		// alias map for easy lookup.
1320  		aliasMap[node.Alias] = dbNode.PubKeyBytes
1321  
1322  		// private keys are needed for signing error messages. If set
1323  		// check the consistency with the public key.
1324  		privBytes, err := hex.DecodeString(node.PrivKey)
1325  		if err != nil {
1326  			return nil, err
1327  		}
1328  		if len(privBytes) > 0 {
1329  			key, derivedPub := btcec.PrivKeyFromBytes(
1330  				privBytes,
1331  			)
1332  
1333  			if !bytes.Equal(
1334  				pubBytes, derivedPub.SerializeCompressed(),
1335  			) {
1336  
1337  				return nil, fmt.Errorf("%s public key and "+
1338  					"private key are inconsistent\n"+
1339  					"got  %x\nwant %x\n",
1340  					node.Alias,
1341  					derivedPub.SerializeCompressed(),
1342  					pubBytes,
1343  				)
1344  			}
1345  
1346  			privKeyMap[node.Alias] = key
1347  		}
1348  
1349  		// If the node is tagged as the source, then we create a
1350  		// pointer to is so we can mark the source in the graph
1351  		// properly.
1352  		if node.Source {
1353  			// If we come across a node that's marked as the
1354  			// source, and we've already set the source in a prior
1355  			// iteration, then the JSON has an error as only ONE
1356  			// node can be the source in the graph.
1357  			if source != nil {
1358  				return nil, errors.New("JSON is invalid " +
1359  					"multiple nodes are tagged as the " +
1360  					"source")
1361  			}
1362  
1363  			source = dbNode
1364  
1365  			// Set the selected source node.
1366  			if err := graph.SetSourceNode(ctx, source); err != nil {
1367  				return nil, err
1368  			}
1369  
1370  			continue
1371  		}
1372  
1373  		// With the node fully parsed, add it as a vertex within the
1374  		// graph.
1375  		if err := graph.AddNode(ctx, dbNode); err != nil {
1376  			return nil, err
1377  		}
1378  	}
1379  
1380  	// With all the vertexes inserted, we can now insert the edges into the
1381  	// test graph.
1382  	for _, edge := range g.Edges {
1383  		node1Bytes, err := hex.DecodeString(edge.Node1)
1384  		if err != nil {
1385  			return nil, err
1386  		}
1387  
1388  		node2Bytes, err := hex.DecodeString(edge.Node2)
1389  		if err != nil {
1390  			return nil, err
1391  		}
1392  
1393  		if bytes.Compare(node1Bytes, node2Bytes) == 1 {
1394  			return nil, fmt.Errorf(
1395  				"channel %v node order incorrect",
1396  				edge.ChannelID,
1397  			)
1398  		}
1399  
1400  		fundingTXID := strings.Split(edge.ChannelPoint, ":")[0]
1401  		txidBytes, err := chainhash.NewHashFromStr(fundingTXID)
1402  		if err != nil {
1403  			return nil, err
1404  		}
1405  		fundingPoint := wire.OutPoint{
1406  			Hash:  *txidBytes,
1407  			Index: 0,
1408  		}
1409  
1410  		// We first insert the existence of the edge between the two
1411  		// nodes.
1412  		var node1Vertex, node2Vertex route.Vertex
1413  		copy(node1Vertex[:], node1Bytes)
1414  		copy(node2Vertex[:], node2Bytes)
1415  
1416  		var btcKey1, btcKey2 route.Vertex
1417  		copy(btcKey1[:], node1Bytes)
1418  		copy(btcKey2[:], node2Bytes)
1419  
1420  		edgeInfo, err := models.NewV1Channel(
1421  			edge.ChannelID, *chaincfg.SimNetParams.GenesisHash,
1422  			node1Vertex, node2Vertex, &models.ChannelV1Fields{
1423  				BitcoinKey1Bytes: btcKey1,
1424  				BitcoinKey2Bytes: btcKey2,
1425  			},
1426  			models.WithChanProof(&testAuthProof),
1427  			models.WithChannelPoint(fundingPoint),
1428  			models.WithCapacity(btcutil.Amount(edge.Capacity)),
1429  		)
1430  		if err != nil {
1431  			return nil, err
1432  		}
1433  
1434  		shortID := lnwire.NewShortChanIDFromInt(edge.ChannelID)
1435  		links[shortID] = &mockLink{
1436  			bandwidth: lnwire.MilliSatoshi(
1437  				edgeInfo.Capacity * 1000,
1438  			),
1439  		}
1440  
1441  		err = graph.AddChannelEdge(ctx, edgeInfo)
1442  		if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) {
1443  			return nil, err
1444  		}
1445  
1446  		channelFlags := lnwire.ChanUpdateChanFlags(edge.ChannelFlags)
1447  		isUpdate1 := channelFlags&lnwire.ChanUpdateDirection == 0
1448  		targetNode := edgeInfo.NodeKey1Bytes
1449  		if isUpdate1 {
1450  			targetNode = edgeInfo.NodeKey2Bytes
1451  		}
1452  
1453  		edgePolicy := &models.ChannelEdgePolicy{
1454  			Version:  lnwire.GossipVersion1,
1455  			SigBytes: testSig.Serialize(),
1456  			MessageFlags: lnwire.ChanUpdateMsgFlags(
1457  				edge.MessageFlags,
1458  			),
1459  			ChannelFlags:  channelFlags,
1460  			ChannelID:     edge.ChannelID,
1461  			LastUpdate:    testTime,
1462  			TimeLockDelta: edge.Expiry,
1463  			MinHTLC: lnwire.MilliSatoshi(
1464  				edge.MinHTLC,
1465  			),
1466  			MaxHTLC: lnwire.MilliSatoshi(
1467  				edge.MaxHTLC,
1468  			),
1469  			FeeBaseMSat: lnwire.MilliSatoshi(
1470  				edge.FeeBaseMsat,
1471  			),
1472  			FeeProportionalMillionths: lnwire.MilliSatoshi(
1473  				edge.FeeRate,
1474  			),
1475  			ToNode: targetNode,
1476  		}
1477  		if err := graph.UpdateEdgePolicy(ctx, edgePolicy); err != nil {
1478  			return nil, err
1479  		}
1480  
1481  		// We also store the channel IDs info for each of the node.
1482  		node1Vertex, err = route.NewVertexFromBytes(node1Bytes)
1483  		if err != nil {
1484  			return nil, err
1485  		}
1486  
1487  		node2Vertex, err = route.NewVertexFromBytes(node2Bytes)
1488  		if err != nil {
1489  			return nil, err
1490  		}
1491  
1492  		if _, ok := channelIDs[node1Vertex]; !ok {
1493  			channelIDs[node1Vertex] = map[route.Vertex]uint64{}
1494  		}
1495  		channelIDs[node1Vertex][node2Vertex] = edge.ChannelID
1496  
1497  		if _, ok := channelIDs[node2Vertex]; !ok {
1498  			channelIDs[node2Vertex] = map[route.Vertex]uint64{}
1499  		}
1500  		channelIDs[node2Vertex][node1Vertex] = edge.ChannelID
1501  	}
1502  
1503  	return &testGraphInstance{
1504  		graph: graphdb.NewVersionedGraph(
1505  			graph, lnwire.GossipVersion1,
1506  		),
1507  		aliasMap:   aliasMap,
1508  		privKeyMap: privKeyMap,
1509  		channelIDs: channelIDs,
1510  		links:      links,
1511  	}, nil
1512  }
1513  
1514  // testGraph is the struct which corresponds to the JSON format used to encode
1515  // graphs within the files in the testdata directory.
1516  //
1517  // TODO(roasbeef): add test graph auto-generator.
1518  type testGraph struct {
1519  	Info  []string   `json:"info"`
1520  	Nodes []testNode `json:"nodes"`
1521  	Edges []testChan `json:"edges"`
1522  }
1523  
1524  // testNode represents a node within the test graph above. We skip certain
1525  // information such as the node's IP address as that information isn't needed
1526  // for our tests. Private keys are optional. If set, they should be consistent
1527  // with the public key. The private key is used to sign error messages
1528  // sent from the node.
1529  type testNode struct {
1530  	Source  bool   `json:"source"`
1531  	PubKey  string `json:"pubkey"`
1532  	PrivKey string `json:"privkey"`
1533  	Alias   string `json:"alias"`
1534  }
1535  
1536  // testChan represents the JSON version of a payment channel. This struct
1537  // matches the Json that's encoded under the "edges" key within the test graph.
1538  type testChan struct {
1539  	Node1        string `json:"node_1"`
1540  	Node2        string `json:"node_2"`
1541  	ChannelID    uint64 `json:"channel_id"`
1542  	ChannelPoint string `json:"channel_point"`
1543  	ChannelFlags uint8  `json:"channel_flags"`
1544  	MessageFlags uint8  `json:"message_flags"`
1545  	Expiry       uint16 `json:"expiry"`
1546  	MinHTLC      int64  `json:"min_htlc"`
1547  	MaxHTLC      int64  `json:"max_htlc"`
1548  	FeeBaseMsat  int64  `json:"fee_base_msat"`
1549  	FeeRate      int64  `json:"fee_rate"`
1550  	Capacity     int64  `json:"capacity"`
1551  }
1552  
1553  type testChannel struct {
1554  	Node1     *testChannelEnd
1555  	Node2     *testChannelEnd
1556  	Capacity  btcutil.Amount
1557  	ChannelID uint64
1558  }
1559  
1560  type testChannelEnd struct {
1561  	Alias string
1562  	*testChannelPolicy
1563  }
1564  
1565  func symmetricTestChannel(alias1, alias2 string, capacity btcutil.Amount,
1566  	policy *testChannelPolicy, chanID ...uint64) *testChannel {
1567  
1568  	// Leaving id zero will result in auto-generation of a channel id during
1569  	// graph construction.
1570  	var id uint64
1571  	if len(chanID) > 0 {
1572  		id = chanID[0]
1573  	}
1574  
1575  	policy2 := *policy
1576  
1577  	return asymmetricTestChannel(
1578  		alias1, alias2, capacity, policy, &policy2, id,
1579  	)
1580  }
1581  
1582  func asymmetricTestChannel(alias1, alias2 string, capacity btcutil.Amount,
1583  	policy1, policy2 *testChannelPolicy, id uint64) *testChannel {
1584  
1585  	return &testChannel{
1586  		Capacity: capacity,
1587  		Node1: &testChannelEnd{
1588  			Alias:             alias1,
1589  			testChannelPolicy: policy1,
1590  		},
1591  		Node2: &testChannelEnd{
1592  			Alias:             alias2,
1593  			testChannelPolicy: policy2,
1594  		},
1595  		ChannelID: id,
1596  	}
1597  }
1598  
1599  // assertChannelsPruned ensures that only the given channels are pruned from the
1600  // graph out of the set of all channels.
1601  func assertChannelsPruned(t *testing.T, graph *graphdb.VersionedGraph,
1602  	channels []*testChannel, prunedChanIDs ...uint64) {
1603  
1604  	t.Helper()
1605  
1606  	pruned := make(map[uint64]struct{}, len(channels))
1607  	for _, chanID := range prunedChanIDs {
1608  		pruned[chanID] = struct{}{}
1609  	}
1610  
1611  	for _, channel := range channels {
1612  		_, shouldPrune := pruned[channel.ChannelID]
1613  		exists, isZombie, err := graph.HasChannelEdge(
1614  			t.Context(), channel.ChannelID,
1615  		)
1616  		require.NoError(t, err)
1617  		if shouldPrune {
1618  			require.Falsef(t, exists,
1619  				"expected channel=%v to not exist within "+
1620  					"the graph",
1621  				channel.ChannelID)
1622  			require.Truef(t, isZombie,
1623  				"expected channel=%v to be marked as zombie",
1624  				channel.ChannelID)
1625  
1626  			continue
1627  		}
1628  
1629  		require.Truef(t, exists,
1630  			"expected channel=%v to exist within the graph",
1631  			channel.ChannelID)
1632  		require.Falsef(t, isZombie,
1633  			"expected channel=%v to not be marked as zombie",
1634  			channel.ChannelID)
1635  	}
1636  }
1637  
1638  type testChannelPolicy struct {
1639  	Expiry             uint16
1640  	MinHTLC            lnwire.MilliSatoshi
1641  	MaxHTLC            lnwire.MilliSatoshi
1642  	FeeBaseMsat        lnwire.MilliSatoshi
1643  	FeeRate            lnwire.MilliSatoshi
1644  	InboundFeeBaseMsat int64
1645  	InboundFeeRate     int64
1646  	LastUpdate         time.Time
1647  	Disabled           bool
1648  	Features           *lnwire.FeatureVector
1649  }
1650  
1651  // createTestGraphFromChannels returns a fully populated ChannelGraph based on a
1652  // set of test channels. Additional required information like keys are derived
1653  // in a deterministic way and added to the channel graph. A list of nodes is not
1654  // required and derived from the channel data. The goal is to keep instantiating
1655  // a test channel graph as light weight as possible.
1656  func createTestGraphFromChannels(t *testing.T, useCache bool,
1657  	testChannels []*testChannel, source string) (*testGraphInstance,
1658  	error) {
1659  
1660  	ctx := t.Context()
1661  
1662  	// We'll use this fake address for the IP address of all the nodes in
1663  	// our tests. This value isn't needed for path finding so it doesn't
1664  	// need to be unique.
1665  	var testAddrs []net.Addr
1666  	testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888")
1667  	if err != nil {
1668  		return nil, err
1669  	}
1670  	testAddrs = append(testAddrs, testAddr)
1671  
1672  	// Next, create a temporary graph database for usage within the test.
1673  	graph := graphdb.MakeTestGraph(
1674  		t, graphdb.WithUseGraphCache(useCache),
1675  	)
1676  
1677  	aliasMap := make(map[string]route.Vertex)
1678  	privKeyMap := make(map[string]*btcec.PrivateKey)
1679  
1680  	nodeIndex := byte(0)
1681  	addNodeWithAlias := func(alias string,
1682  		features *lnwire.FeatureVector) error {
1683  
1684  		keyBytes := []byte{
1685  			0, 0, 0, 0, 0, 0, 0, 0,
1686  			0, 0, 0, 0, 0, 0, 0, 0,
1687  			0, 0, 0, 0, 0, 0, 0, 0,
1688  			0, 0, 0, 0, 0, 0, 0, nodeIndex + 1,
1689  		}
1690  
1691  		privKey, pubKey := btcec.PrivKeyFromBytes(keyBytes)
1692  
1693  		if features == nil {
1694  			features = lnwire.EmptyFeatureVector()
1695  		}
1696  
1697  		dbNode := models.NewV1Node(
1698  			route.NewVertex(pubKey), &models.NodeV1Fields{
1699  				AuthSigBytes: testSig.Serialize(),
1700  				LastUpdate:   testTime,
1701  				Addresses:    testAddrs,
1702  				Alias:        alias,
1703  				Features:     features.RawFeatureVector,
1704  			},
1705  		)
1706  
1707  		privKeyMap[alias] = privKey
1708  
1709  		// With the node fully parsed, add it as a vertex within the
1710  		// graph.
1711  		if alias == source {
1712  			err = graph.SetSourceNode(ctx, dbNode)
1713  			require.NoError(t, err)
1714  		} else {
1715  			err := graph.AddNode(ctx, dbNode)
1716  			require.NoError(t, err)
1717  		}
1718  
1719  		aliasMap[alias] = dbNode.PubKeyBytes
1720  		nodeIndex++
1721  
1722  		return nil
1723  	}
1724  
1725  	// Add the source node.
1726  	err = addNodeWithAlias(source, lnwire.EmptyFeatureVector())
1727  	if err != nil {
1728  		return nil, err
1729  	}
1730  
1731  	// Initialize variable that keeps track of the next channel id to assign
1732  	// if none is specified.
1733  	nextUnassignedChannelID := uint64(100000)
1734  
1735  	links := make(map[lnwire.ShortChannelID]htlcswitch.ChannelLink)
1736  
1737  	for _, testChannel := range testChannels {
1738  		for _, node := range []*testChannelEnd{
1739  			testChannel.Node1, testChannel.Node2,
1740  		} {
1741  			_, exists := aliasMap[node.Alias]
1742  			if !exists {
1743  				var features *lnwire.FeatureVector
1744  				if node.testChannelPolicy != nil {
1745  					features =
1746  						node.testChannelPolicy.Features
1747  				}
1748  				err := addNodeWithAlias(
1749  					node.Alias, features,
1750  				)
1751  				if err != nil {
1752  					return nil, err
1753  				}
1754  			}
1755  		}
1756  
1757  		channelID := testChannel.ChannelID
1758  
1759  		// If no channel id is specified, generate an id.
1760  		if channelID == 0 {
1761  			channelID = nextUnassignedChannelID
1762  			nextUnassignedChannelID++
1763  		}
1764  
1765  		var hash [sha256.Size]byte
1766  		hash[len(hash)-1] = byte(channelID)
1767  
1768  		fundingPoint := &wire.OutPoint{
1769  			Hash:  chainhash.Hash(hash),
1770  			Index: 0,
1771  		}
1772  
1773  		capacity := lnwire.MilliSatoshi(testChannel.Capacity * 1000)
1774  		shortID := lnwire.NewShortChanIDFromInt(channelID)
1775  		links[shortID] = &mockLink{
1776  			bandwidth: capacity,
1777  		}
1778  
1779  		// Sort nodes
1780  		node1 := testChannel.Node1
1781  		node2 := testChannel.Node2
1782  		node1Vertex := aliasMap[node1.Alias]
1783  		node2Vertex := aliasMap[node2.Alias]
1784  		if bytes.Compare(node1Vertex[:], node2Vertex[:]) == 1 {
1785  			node1, node2 = node2, node1
1786  			node1Vertex, node2Vertex = node2Vertex, node1Vertex
1787  		}
1788  
1789  		// We first insert the existence of the edge between the two
1790  		// nodes.
1791  		edgeInfo, err := models.NewV1Channel(
1792  			channelID, *chaincfg.SimNetParams.GenesisHash,
1793  			node1Vertex, node2Vertex, &models.ChannelV1Fields{
1794  				BitcoinKey1Bytes: node1Vertex,
1795  				BitcoinKey2Bytes: node2Vertex,
1796  			},
1797  			models.WithChanProof(&testAuthProof),
1798  			models.WithChannelPoint(*fundingPoint),
1799  			models.WithCapacity(testChannel.Capacity),
1800  		)
1801  		if err != nil {
1802  			return nil, err
1803  		}
1804  
1805  		err = graph.AddChannelEdge(ctx, edgeInfo)
1806  		if err != nil &&
1807  			!errors.Is(err, graphdb.ErrEdgeAlreadyExist) {
1808  
1809  			return nil, err
1810  		}
1811  
1812  		getExtraData := func(
1813  			end *testChannelEnd) lnwire.ExtraOpaqueData {
1814  
1815  			var extraData lnwire.ExtraOpaqueData
1816  			inboundFee := lnwire.Fee{
1817  				BaseFee: int32(end.InboundFeeBaseMsat),
1818  				FeeRate: int32(end.InboundFeeRate),
1819  			}
1820  			require.NoError(t, extraData.PackRecords(&inboundFee))
1821  
1822  			return extraData
1823  		}
1824  
1825  		if node1.testChannelPolicy != nil {
1826  			var msgFlags lnwire.ChanUpdateMsgFlags
1827  			if node1.MaxHTLC != 0 {
1828  				msgFlags |= lnwire.ChanUpdateRequiredMaxHtlc
1829  			}
1830  			var channelFlags lnwire.ChanUpdateChanFlags
1831  			if node1.Disabled {
1832  				channelFlags |= lnwire.ChanUpdateDisabled
1833  			}
1834  
1835  			//nolint:ll
1836  			edgePolicy := &models.ChannelEdgePolicy{
1837  				Version:                   lnwire.GossipVersion1,
1838  				SigBytes:                  testSig.Serialize(),
1839  				MessageFlags:              msgFlags,
1840  				ChannelFlags:              channelFlags,
1841  				ChannelID:                 channelID,
1842  				LastUpdate:                node1.LastUpdate,
1843  				TimeLockDelta:             node1.Expiry,
1844  				MinHTLC:                   node1.MinHTLC,
1845  				MaxHTLC:                   node1.MaxHTLC,
1846  				FeeBaseMSat:               node1.FeeBaseMsat,
1847  				FeeProportionalMillionths: node1.FeeRate,
1848  				ToNode:                    node2Vertex,
1849  				ExtraOpaqueData:           getExtraData(node1),
1850  			}
1851  			err := graph.UpdateEdgePolicy(ctx, edgePolicy)
1852  			if err != nil {
1853  				return nil, err
1854  			}
1855  		}
1856  
1857  		if node2.testChannelPolicy != nil {
1858  			var msgFlags lnwire.ChanUpdateMsgFlags
1859  			if node2.MaxHTLC != 0 {
1860  				msgFlags |= lnwire.ChanUpdateRequiredMaxHtlc
1861  			}
1862  			var channelFlags lnwire.ChanUpdateChanFlags
1863  			if node2.Disabled {
1864  				channelFlags |= lnwire.ChanUpdateDisabled
1865  			}
1866  			channelFlags |= lnwire.ChanUpdateDirection
1867  
1868  			//nolint:ll
1869  			edgePolicy := &models.ChannelEdgePolicy{
1870  				Version:                   lnwire.GossipVersion1,
1871  				SigBytes:                  testSig.Serialize(),
1872  				MessageFlags:              msgFlags,
1873  				ChannelFlags:              channelFlags,
1874  				ChannelID:                 channelID,
1875  				LastUpdate:                node2.LastUpdate,
1876  				TimeLockDelta:             node2.Expiry,
1877  				MinHTLC:                   node2.MinHTLC,
1878  				MaxHTLC:                   node2.MaxHTLC,
1879  				FeeBaseMSat:               node2.FeeBaseMsat,
1880  				FeeProportionalMillionths: node2.FeeRate,
1881  				ToNode:                    node1Vertex,
1882  				ExtraOpaqueData:           getExtraData(node2),
1883  			}
1884  			err := graph.UpdateEdgePolicy(ctx, edgePolicy)
1885  			if err != nil {
1886  				return nil, err
1887  			}
1888  		}
1889  
1890  		channelID++ //nolint:ineffassign
1891  	}
1892  
1893  	return &testGraphInstance{
1894  		graph: graphdb.NewVersionedGraph(
1895  			graph, lnwire.GossipVersion1,
1896  		),
1897  		aliasMap:   aliasMap,
1898  		privKeyMap: privKeyMap,
1899  		links:      links,
1900  	}, nil
1901  }
1902  
1903  type mockLink struct {
1904  	htlcswitch.ChannelLink
1905  	bandwidth         lnwire.MilliSatoshi
1906  	mayAddOutgoingErr error
1907  	ineligible        bool
1908  }
1909  
1910  // Bandwidth returns the bandwidth the mock was configured with.
1911  func (m *mockLink) Bandwidth() lnwire.MilliSatoshi {
1912  	return m.bandwidth
1913  }
1914  
1915  // EligibleToForward returns the mock's configured eligibility.
1916  func (m *mockLink) EligibleToForward() bool {
1917  	return !m.ineligible
1918  }
1919  
1920  // MayAddOutgoingHtlc returns the error configured in our mock.
1921  func (m *mockLink) MayAddOutgoingHtlc(_ lnwire.MilliSatoshi) error {
1922  	return m.mayAddOutgoingErr
1923  }