github.com/decred/dcrlnd@v0.7.6/routing/router_test.go (about) 1 package routing 2 3 import ( 4 "bytes" 5 "fmt" 6 "image/color" 7 "math" 8 "math/rand" 9 "sync/atomic" 10 "testing" 11 "time" 12 13 "github.com/davecgh/go-spew/spew" 14 "github.com/stretchr/testify/mock" 15 "github.com/stretchr/testify/require" 16 17 "github.com/decred/dcrd/chaincfg/chainhash" 18 "github.com/decred/dcrd/dcrec/secp256k1/v4" 19 "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" 20 "github.com/decred/dcrd/dcrutil/v4" 21 "github.com/decred/dcrd/wire" 22 "github.com/decred/dcrlnd/chainntnfs" 23 "github.com/decred/dcrlnd/channeldb" 24 "github.com/decred/dcrlnd/clock" 25 "github.com/decred/dcrlnd/htlcswitch" 26 lnmock "github.com/decred/dcrlnd/lntest/mock" 27 "github.com/decred/dcrlnd/lntest/wait" 28 "github.com/decred/dcrlnd/lntypes" 29 "github.com/decred/dcrlnd/lnwire" 30 "github.com/decred/dcrlnd/record" 31 "github.com/decred/dcrlnd/routing/route" 32 "github.com/decred/dcrlnd/zpay32" 33 ) 34 35 var uniquePaymentID uint64 = 1 // to be used atomically 36 37 type testCtx struct { 38 router *ChannelRouter 39 40 graph *channeldb.ChannelGraph 41 42 aliases map[string]route.Vertex 43 44 privKeys map[string]*secp256k1.PrivateKey 45 46 channelIDs map[route.Vertex]map[route.Vertex]uint64 47 48 chain *mockChain 49 50 chainView *mockChainView 51 52 notifier *lnmock.ChainNotifier 53 } 54 55 func (c *testCtx) getChannelIDFromAlias(t *testing.T, a, b string) uint64 { 56 vertexA, ok := c.aliases[a] 57 require.True(t, ok, "cannot find aliases for %s", a) 58 59 vertexB, ok := c.aliases[b] 60 require.True(t, ok, "cannot find aliases for %s", b) 61 62 channelIDMap, ok := c.channelIDs[vertexA] 63 require.True(t, ok, "cannot find channelID map %s(%s)", vertexA, a) 64 65 channelID, ok := channelIDMap[vertexB] 66 require.True(t, ok, "cannot find channelID using %s(%s)", vertexB, b) 67 68 return channelID 69 } 70 71 func (c *testCtx) RestartRouter(t *testing.T) { 72 // First, we'll reset the chainView's state as it doesn't persist the 73 // filter between restarts. 74 c.chainView.Reset() 75 76 // With the chainView reset, we'll now re-create the router itself, and 77 // start it. 78 router, err := New(Config{ 79 Graph: c.graph, 80 Chain: c.chain, 81 ChainView: c.chainView, 82 Payer: &mockPaymentAttemptDispatcherOld{}, 83 Control: makeMockControlTower(), 84 ChannelPruneExpiry: time.Hour * 24, 85 GraphPruneInterval: time.Hour * 2, 86 }) 87 require.NoError(t, err, "unable to create router") 88 require.NoError(t, router.Start(), "unable to start router") 89 90 // Finally, we'll swap out the pointer in the testCtx with this fresh 91 // instance of the router. 92 c.router = router 93 } 94 95 func createTestCtxFromGraphInstance(t *testing.T, 96 startingHeight uint32, graphInstance *testGraphInstance, 97 strictPruning bool) (*testCtx, func()) { 98 99 return createTestCtxFromGraphInstanceAssumeValid( 100 t, startingHeight, graphInstance, false, strictPruning, 101 ) 102 } 103 104 func createTestCtxFromGraphInstanceAssumeValid(t *testing.T, 105 startingHeight uint32, graphInstance *testGraphInstance, 106 assumeValid bool, strictPruning bool) (*testCtx, func()) { 107 108 // We'll initialize an instance of the channel router with mock 109 // versions of the chain and channel notifier. As we don't need to test 110 // any p2p functionality, the peer send and switch send messages won't 111 // be populated. 112 chain := newMockChain(startingHeight) 113 chainView := newMockChainView(chain) 114 115 pathFindingConfig := PathFindingConfig{ 116 MinProbability: 0.01, 117 AttemptCost: 100, 118 } 119 120 mcConfig := &MissionControlConfig{ 121 ProbabilityEstimatorCfg: ProbabilityEstimatorCfg{ 122 PenaltyHalfLife: time.Hour, 123 AprioriHopProbability: 0.9, 124 AprioriWeight: 0.5, 125 }, 126 } 127 128 mc, err := NewMissionControl( 129 graphInstance.graphBackend, route.Vertex{}, mcConfig, 130 ) 131 require.NoError(t, err, "failed to create missioncontrol") 132 drainMCStoreQueueChan(t, mc.store) 133 134 sourceNode, err := graphInstance.graph.SourceNode() 135 require.NoError(t, err) 136 sessionSource := &SessionSource{ 137 Graph: graphInstance.graph, 138 SourceNode: sourceNode, 139 GetLink: graphInstance.getLink, 140 PathFindingConfig: pathFindingConfig, 141 MissionControl: mc, 142 } 143 144 notifier := &lnmock.ChainNotifier{ 145 EpochChan: make(chan *chainntnfs.BlockEpoch), 146 SpendChan: make(chan *chainntnfs.SpendDetail), 147 ConfChan: make(chan *chainntnfs.TxConfirmation), 148 } 149 150 router, err := New(Config{ 151 Graph: graphInstance.graph, 152 Chain: chain, 153 ChainView: chainView, 154 Payer: &mockPaymentAttemptDispatcherOld{}, 155 Notifier: notifier, 156 Control: makeMockControlTower(), 157 MissionControl: mc, 158 SessionSource: sessionSource, 159 ChannelPruneExpiry: time.Hour * 24, 160 GraphPruneInterval: time.Hour * 2, 161 GetLink: graphInstance.getLink, 162 NextPaymentID: func() (uint64, error) { 163 next := atomic.AddUint64(&uniquePaymentID, 1) 164 return next, nil 165 }, 166 PathFindingConfig: pathFindingConfig, 167 LocalOpenChanIDs: func() (map[uint64]struct{}, error) { return map[uint64]struct{}{}, nil }, 168 Clock: clock.NewTestClock(time.Unix(1, 0)), 169 AssumeChannelValid: assumeValid, 170 StrictZombiePruning: strictPruning, 171 }) 172 require.NoError(t, err, "unable to create router") 173 require.NoError(t, router.Start(), "unable to start router") 174 175 ctx := &testCtx{ 176 router: router, 177 graph: graphInstance.graph, 178 aliases: graphInstance.aliasMap, 179 privKeys: graphInstance.privKeyMap, 180 channelIDs: graphInstance.channelIDs, 181 chain: chain, 182 chainView: chainView, 183 notifier: notifier, 184 } 185 186 cleanUp := func() { 187 ctx.router.Stop() 188 } 189 190 return ctx, cleanUp 191 } 192 193 func createTestCtxSingleNode(t *testing.T, 194 startingHeight uint32) (*testCtx, func()) { 195 196 graph, graphBackend, cleanup, err := makeTestGraph(true) 197 require.NoError(t, err, "failed to make test graph") 198 199 sourceNode, err := createTestNode() 200 require.NoError(t, err, "failed to create test node") 201 202 require.NoError(t, 203 graph.SetSourceNode(sourceNode), "failed to set source node", 204 ) 205 206 graphInstance := &testGraphInstance{ 207 graph: graph, 208 graphBackend: graphBackend, 209 cleanUp: cleanup, 210 } 211 212 return createTestCtxFromGraphInstance( 213 t, startingHeight, graphInstance, false, 214 ) 215 } 216 217 func createTestCtxFromFile(t *testing.T, 218 startingHeight uint32, testGraph string) (*testCtx, func()) { 219 220 // We'll attempt to locate and parse out the file 221 // that encodes the graph that our tests should be run against. 222 graphInstance, err := parseTestGraph(true, testGraph) 223 require.NoError(t, err, "unable to create test graph") 224 225 return createTestCtxFromGraphInstance( 226 t, startingHeight, graphInstance, false, 227 ) 228 } 229 230 // Add valid signature to channel update simulated as error received from the 231 // network. 232 func signErrChanUpdate(t *testing.T, key *secp256k1.PrivateKey, 233 errChanUpdate *lnwire.ChannelUpdate) { 234 235 chanUpdateMsg, err := errChanUpdate.DataToSign() 236 require.NoError(t, err, "failed to retrieve data to sign") 237 238 digest := chainhash.HashB(chanUpdateMsg) 239 sig := ecdsa.Sign(key, digest) 240 241 errChanUpdate.Signature, err = lnwire.NewSigFromSignature(sig) 242 require.NoError(t, err, "failed to create new signature") 243 } 244 245 // TestFindRoutesWithFeeLimit asserts that routes found by the FindRoutes method 246 // within the channel router contain a total fee less than or equal to the fee 247 // limit. 248 func TestFindRoutesWithFeeLimit(t *testing.T) { 249 t.Parallel() 250 251 const startingBlockHeight = 101 252 ctx, cleanUp := createTestCtxFromFile( 253 t, startingBlockHeight, basicGraphFilePath, 254 ) 255 defer cleanUp() 256 257 // This test will attempt to find routes from roasbeef to sophon for 100 258 // atoms with a fee limit of 10 atoms. There are two routes from 259 // roasbeef to sophon: 260 // 1. roasbeef -> songoku -> sophon 261 // 2. roasbeef -> phamnuwen -> sophon 262 // The second route violates our fee limit, so we should only expect to 263 // see the first route. 264 target := ctx.aliases["sophon"] 265 paymentAmt := lnwire.NewMAtomsFromAtoms(100) 266 restrictions := &RestrictParams{ 267 FeeLimit: lnwire.NewMAtomsFromAtoms(10), 268 ProbabilitySource: noProbabilitySource, 269 CltvLimit: math.MaxUint32, 270 } 271 272 route, err := ctx.router.FindRoute( 273 ctx.router.selfNode.PubKeyBytes, 274 target, paymentAmt, restrictions, nil, nil, 275 MinCLTVDelta, 276 ) 277 require.NoError(t, err, "unable to find any routes") 278 279 require.Falsef(t, 280 route.TotalFees() > restrictions.FeeLimit, 281 "route exceeded fee limit: %v", spew.Sdump(route), 282 ) 283 284 hops := route.Hops 285 require.Equal(t, 2, len(hops), "expected 2 hops") 286 287 require.Equalf(t, 288 ctx.aliases["songoku"], hops[0].PubKeyBytes, 289 "expected first hop through songoku, got %s", 290 getAliasFromPubKey(hops[0].PubKeyBytes, ctx.aliases), 291 ) 292 } 293 294 // TestSendPaymentRouteFailureFallback tests that when sending a payment, if 295 // one of the target routes is seen as unavailable, then the next route in the 296 // queue is used instead. This process should continue until either a payment 297 // succeeds, or all routes have been exhausted. 298 func TestSendPaymentRouteFailureFallback(t *testing.T) { 299 t.Parallel() 300 301 const startingBlockHeight = 101 302 ctx, cleanUp := createTestCtxFromFile( 303 t, startingBlockHeight, basicGraphFilePath, 304 ) 305 defer cleanUp() 306 307 // Craft a LightningPayment struct that'll send a payment from roasbeef 308 // to luo ji for 1000 atoms, with a maximum of 1000 atoms in fees. 309 var payHash lntypes.Hash 310 paymentAmt := lnwire.NewMAtomsFromAtoms(1000) 311 payment := LightningPayment{ 312 Target: ctx.aliases["sophon"], 313 Amount: paymentAmt, 314 FeeLimit: noFeeLimit, 315 paymentHash: &payHash, 316 } 317 318 var preImage [32]byte 319 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 320 321 // Get the channel ID. 322 roasbeefSongoku := lnwire.NewShortChanIDFromInt( 323 ctx.getChannelIDFromAlias(t, "roasbeef", "songoku"), 324 ) 325 326 // We'll modify the SendToSwitch method that's been set within the 327 // router's configuration to ignore the path that has son goku as the 328 // first hop. This should force the router to instead take the 329 // the more costly path (through pham nuwen). 330 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 331 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 332 333 if firstHop == roasbeefSongoku { 334 return [32]byte{}, htlcswitch.NewForwardingError( 335 // TODO(roasbeef): temp node failure 336 // should be? 337 &lnwire.FailTemporaryChannelFailure{}, 338 1, 339 ) 340 } 341 342 return preImage, nil 343 }) 344 345 // Send off the payment request to the router, route through pham nuwen 346 // should've been selected as a fall back and succeeded correctly. 347 paymentPreImage, route, err := ctx.router.SendPayment(&payment) 348 require.NoError(t, err, "unable to send payment") 349 350 // The route selected should have two hops 351 require.Equal(t, 2, len(route.Hops), "incorrect route length") 352 353 // The preimage should match up with the once created above. 354 if !bytes.Equal(paymentPreImage[:], preImage[:]) { 355 t.Fatalf("incorrect preimage used: expected %x got %x", 356 preImage[:], paymentPreImage[:]) 357 } 358 359 // The route should have pham nuwen as the first hop. 360 require.Equalf(t, 361 ctx.aliases["phamnuwen"], route.Hops[0].PubKeyBytes, 362 "route should go through phamnuwen as first hop, instead "+ 363 "passes through: %v", 364 getAliasFromPubKey(route.Hops[0].PubKeyBytes, ctx.aliases), 365 ) 366 } 367 368 // TestChannelUpdateValidation tests that a failed payment with an associated 369 // channel update will only be applied to the graph when the update contains a 370 // valid signature. 371 func TestChannelUpdateValidation(t *testing.T) { 372 t.Parallel() 373 374 // Setup a three node network. 375 chanCapSat := dcrutil.Amount(100000) 376 feeRate := lnwire.MilliAtom(400) 377 testChannels := []*testChannel{ 378 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 379 Expiry: 144, 380 FeeRate: feeRate, 381 MinHTLC: 1, 382 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 383 }, 1), 384 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 385 Expiry: 144, 386 FeeRate: feeRate, 387 MinHTLC: 1, 388 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 389 }, 2), 390 } 391 392 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 393 require.NoError(t, err, "unable to create graph") 394 defer testGraph.cleanUp() 395 396 const startingBlockHeight = 101 397 ctx, cleanUp := createTestCtxFromGraphInstance( 398 t, startingBlockHeight, testGraph, true, 399 ) 400 defer cleanUp() 401 402 // Assert that the initially configured fee is retrieved correctly. 403 _, policy, _, err := ctx.router.GetChannelByID( 404 lnwire.NewShortChanIDFromInt(1)) 405 require.NoError(t, err, "cannot retrieve channel") 406 407 require.Equal(t, 408 feeRate, policy.FeeProportionalMillionths, "invalid fee", 409 ) 410 411 // Setup a route from source a to destination c. The route will be used 412 // in a call to SendToRoute. SendToRoute also applies channel updates, 413 // but it saves us from including RequestRoute in the test scope too. 414 hop1 := ctx.aliases["b"] 415 hop2 := ctx.aliases["c"] 416 hops := []*route.Hop{ 417 { 418 ChannelID: 1, 419 PubKeyBytes: hop1, 420 LegacyPayload: true, 421 }, 422 { 423 ChannelID: 2, 424 PubKeyBytes: hop2, 425 LegacyPayload: true, 426 }, 427 } 428 429 rt, err := route.NewRouteFromHops( 430 lnwire.MilliAtom(10000), 100, 431 ctx.aliases["a"], hops, 432 ) 433 require.NoError(t, err, "unable to create route") 434 435 // Set up a channel update message with an invalid signature to be 436 // returned to the sender. 437 var invalidSignature [64]byte 438 errChanUpdate := lnwire.ChannelUpdate{ 439 Signature: invalidSignature, 440 FeeRate: 500, 441 ShortChannelID: lnwire.NewShortChanIDFromInt(1), 442 Timestamp: uint32(testTime.Add(time.Minute).Unix()), 443 } 444 445 // We'll modify the SendToSwitch method so that it simulates a failed 446 // payment with an error originating from the first hop of the route. 447 // The unsigned channel update is attached to the failure message. 448 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 449 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 450 return [32]byte{}, htlcswitch.NewForwardingError( 451 &lnwire.FailFeeInsufficient{ 452 Update: errChanUpdate, 453 }, 454 1, 455 ) 456 }) 457 458 // The payment parameter is mostly redundant in SendToRoute. Can be left 459 // empty for this test. 460 var payment lntypes.Hash 461 462 // Send off the payment request to the router. The specified route 463 // should be attempted and the channel update should be received by 464 // router and ignored because it is missing a valid signature. 465 _, err = ctx.router.SendToRoute(payment, rt) 466 require.Error(t, err, "expected route to fail with channel update") 467 468 _, policy, _, err = ctx.router.GetChannelByID( 469 lnwire.NewShortChanIDFromInt(1)) 470 require.NoError(t, err, "cannot retrieve channel") 471 472 require.Equal(t, 473 feeRate, policy.FeeProportionalMillionths, 474 "fee updated without valid signature", 475 ) 476 477 // Next, add a signature to the channel update. 478 signErrChanUpdate(t, testGraph.privKeyMap["b"], &errChanUpdate) 479 480 // Retry the payment using the same route as before. 481 _, err = ctx.router.SendToRoute(payment, rt) 482 if err == nil { 483 t.Fatalf("expected route to fail with channel update") 484 } 485 486 // This time a valid signature was supplied and the policy change should 487 // have been applied to the graph. 488 _, policy, _, err = ctx.router.GetChannelByID( 489 lnwire.NewShortChanIDFromInt(1)) 490 require.NoError(t, err, "cannot retrieve channel") 491 492 require.Equal(t, 493 lnwire.MilliAtom(500), policy.FeeProportionalMillionths, 494 "fee not updated even though signature is valid", 495 ) 496 } 497 498 // TestSendPaymentErrorRepeatedFeeInsufficient tests that if we receive 499 // multiple fee related errors from a channel that we're attempting to route 500 // through, then we'll prune the channel after the second attempt. 501 func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { 502 t.Parallel() 503 504 const startingBlockHeight = 101 505 ctx, cleanUp := createTestCtxFromFile( 506 t, startingBlockHeight, basicGraphFilePath, 507 ) 508 defer cleanUp() 509 510 // Get the channel ID. 511 roasbeefSongokuChanID := ctx.getChannelIDFromAlias( 512 t, "roasbeef", "songoku", 513 ) 514 songokuSophonChanID := ctx.getChannelIDFromAlias( 515 t, "songoku", "sophon", 516 ) 517 518 // Craft a LightningPayment struct that'll send a payment from roasbeef 519 // to sophon for 1000 atoms. 520 var payHash lntypes.Hash 521 amt := lnwire.NewMAtomsFromAtoms(1000) 522 payment := LightningPayment{ 523 Target: ctx.aliases["sophon"], 524 Amount: amt, 525 FeeLimit: noFeeLimit, 526 paymentHash: &payHash, 527 } 528 529 var preImage [32]byte 530 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 531 532 // We'll also fetch the first outgoing channel edge from son goku 533 // to sophon. We'll obtain this as we'll need to to generate the 534 // FeeInsufficient error that we'll send back. 535 _, _, edgeUpdateToFail, err := ctx.graph.FetchChannelEdgesByID( 536 songokuSophonChanID, 537 ) 538 require.NoError(t, err, "unable to fetch chan id") 539 540 errChanUpdate := lnwire.ChannelUpdate{ 541 ShortChannelID: lnwire.NewShortChanIDFromInt( 542 songokuSophonChanID, 543 ), 544 Timestamp: uint32(edgeUpdateToFail.LastUpdate.Unix()), 545 MessageFlags: edgeUpdateToFail.MessageFlags, 546 ChannelFlags: edgeUpdateToFail.ChannelFlags, 547 TimeLockDelta: edgeUpdateToFail.TimeLockDelta, 548 HtlcMinimumMAtoms: edgeUpdateToFail.MinHTLC, 549 HtlcMaximumMAtoms: edgeUpdateToFail.MaxHTLC, 550 BaseFee: uint32(edgeUpdateToFail.FeeBaseMAtoms), 551 FeeRate: uint32(edgeUpdateToFail.FeeProportionalMillionths), 552 } 553 554 signErrChanUpdate(t, ctx.privKeys["songoku"], &errChanUpdate) 555 556 // We'll now modify the SendToSwitch method to return an error for the 557 // outgoing channel to Son goku. This will be a fee related error, so 558 // it should only cause the edge to be pruned after the second attempt. 559 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 560 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 561 562 roasbeefSongoku := lnwire.NewShortChanIDFromInt( 563 roasbeefSongokuChanID, 564 ) 565 if firstHop == roasbeefSongoku { 566 return [32]byte{}, htlcswitch.NewForwardingError( 567 // Within our error, we'll add a 568 // channel update which is meant to 569 // reflect the new fee schedule for the 570 // node/channel. 571 &lnwire.FailFeeInsufficient{ 572 Update: errChanUpdate, 573 }, 1, 574 ) 575 } 576 577 return preImage, nil 578 }) 579 580 // Send off the payment request to the router, route through phamnuwen 581 // should've been selected as a fall back and succeeded correctly. 582 paymentPreImage, route, err := ctx.router.SendPayment(&payment) 583 require.NoError(t, err, "unable to send payment") 584 585 // The route selected should have two hops 586 require.Equal(t, 2, len(route.Hops), "incorrect route length") 587 588 // The preimage should match up with the once created above. 589 require.Equal(t, preImage[:], paymentPreImage[:], "incorrect preimage") 590 591 // The route should have pham nuwen as the first hop. 592 require.Equalf(t, 593 ctx.aliases["phamnuwen"], route.Hops[0].PubKeyBytes, 594 "route should go through pham nuwen as first hop, "+ 595 "instead passes through: %v", 596 getAliasFromPubKey(route.Hops[0].PubKeyBytes, ctx.aliases), 597 ) 598 } 599 600 // TestSendPaymentErrorFeeInsufficientPrivateEdge tests that if we receive 601 // a fee related error from a private channel that we're attempting to route 602 // through, then we'll update the fees in the route hints and successfully 603 // route through the private channel in the second attempt. 604 // 605 // The test will send a payment from roasbeef to elst, available paths are, 606 // path1: roasbeef -> songoku -> sophon -> elst, total fee: 210k 607 // path2: roasbeef -> phamnuwen -> sophon -> elst, total fee: 220k 608 // path3: roasbeef -> songoku ->(private channel) elst 609 // We will setup the path3 to have the lowest fee so it's always the preferred 610 // path. 611 func TestSendPaymentErrorFeeInsufficientPrivateEdge(t *testing.T) { 612 t.Parallel() 613 614 const startingBlockHeight = 101 615 ctx, cleanUp := createTestCtxFromFile( 616 t, startingBlockHeight, basicGraphFilePath, 617 ) 618 defer cleanUp() 619 620 // Get the channel ID. 621 roasbeefSongoku := lnwire.NewShortChanIDFromInt( 622 ctx.getChannelIDFromAlias(t, "roasbeef", "songoku"), 623 ) 624 625 var ( 626 payHash lntypes.Hash 627 preImage [32]byte 628 amt = lnwire.NewMAtomsFromAtoms(1000) 629 privateChannelID = uint64(55555) 630 feeBaseMAtoms = uint32(15) 631 expiryDelta = uint16(32) 632 sgNode = ctx.aliases["songoku"] 633 ) 634 635 sgNodeID, err := secp256k1.ParsePubKey(sgNode[:]) 636 require.NoError(t, err) 637 638 // Craft a LightningPayment struct that'll send a payment from roasbeef 639 // to elst, through a private channel between songoku and elst for 640 // 1000 satoshis. This route has lowest fees compared with the rest. 641 // This also holds when the private channel fee is updated to a higher 642 // value. 643 payment := LightningPayment{ 644 Target: ctx.aliases["elst"], 645 Amount: amt, 646 FeeLimit: noFeeLimit, 647 paymentHash: &payHash, 648 RouteHints: [][]zpay32.HopHint{{ 649 // Add a private channel between songoku and elst. 650 zpay32.HopHint{ 651 NodeID: sgNodeID, 652 ChannelID: privateChannelID, 653 FeeBaseMAtoms: feeBaseMAtoms, 654 CLTVExpiryDelta: expiryDelta, 655 }, 656 }}, 657 } 658 659 // Prepare an error update for the private channel, with twice the 660 // original fee. 661 updatedFeeBaseMAtoms := feeBaseMAtoms * 2 662 errChanUpdate := lnwire.ChannelUpdate{ 663 ShortChannelID: lnwire.NewShortChanIDFromInt(privateChannelID), 664 Timestamp: uint32(testTime.Add(time.Minute).Unix()), 665 BaseFee: updatedFeeBaseMAtoms, 666 TimeLockDelta: expiryDelta, 667 } 668 signErrChanUpdate(t, ctx.privKeys["songoku"], &errChanUpdate) 669 670 // We'll now modify the SendHTLC method to return an error for the 671 // outgoing channel to songoku. 672 errorReturned := false 673 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 674 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 675 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 676 677 if firstHop != roasbeefSongoku || errorReturned { 678 return preImage, nil 679 } 680 681 errorReturned = true 682 return [32]byte{}, htlcswitch.NewForwardingError( 683 // Within our error, we'll add a 684 // channel update which is meant to 685 // reflect the new fee schedule for the 686 // node/channel. 687 &lnwire.FailFeeInsufficient{ 688 Update: errChanUpdate, 689 }, 1, 690 ) 691 }) 692 693 // Send off the payment request to the router, route through son 694 // goku and then across the private channel to elst. 695 paymentPreImage, route, err := ctx.router.SendPayment(&payment) 696 require.NoError(t, err, "unable to send payment") 697 698 require.True(t, errorReturned, 699 "failed to simulate error in the first payment attempt", 700 ) 701 702 // The route selected should have two hops. Make sure that, 703 // path: roasbeef -> son goku -> sophon -> elst 704 // path: roasbeef -> pham nuwen -> sophon -> elst 705 // are not selected instead. 706 require.Equal(t, 2, len(route.Hops), "incorrect route length") 707 708 // The preimage should match up with the one created above. 709 require.Equal(t, 710 paymentPreImage[:], preImage[:], "incorrect preimage used", 711 ) 712 713 // The route should have son goku as the first hop. 714 require.Equal(t, route.Hops[0].PubKeyBytes, ctx.aliases["songoku"], 715 "route should go through son goku as first hop", 716 ) 717 718 // The route should pass via the private channel. 719 require.Equal(t, 720 privateChannelID, route.FinalHop().ChannelID, 721 "route did not pass through private channel "+ 722 "between pham nuwen and elst", 723 ) 724 725 // The route should have the updated fee. 726 require.Equal(t, 727 lnwire.MilliAtom(updatedFeeBaseMAtoms).String(), 728 route.HopFee(0).String(), 729 "fee to forward to the private channel not matched", 730 ) 731 } 732 733 // TestSendPaymentPrivateEdgeUpdateFeeExceedsLimit tests that upon receiving a 734 // ChannelUpdate in a fee related error from the private channel, we won't 735 // choose the route in our second attempt if the updated fee exceeds our fee 736 // limit specified in the payment. 737 // 738 // The test will send a payment from roasbeef to elst, available paths are, 739 // path1: roasbeef -> songoku -> sophon -> elst, total fee: 210k 740 // path2: roasbeef -> phamnuwen -> sophon -> elst, total fee: 220k 741 // path3: roasbeef -> songoku ->(private channel) elst 742 // We will setup the path3 to have the lowest fee and then update it with a fee 743 // exceeds our fee limit, thus this route won't be chosen. 744 func TestSendPaymentPrivateEdgeUpdateFeeExceedsLimit(t *testing.T) { 745 t.Parallel() 746 747 const startingBlockHeight = 101 748 ctx, cleanUp := createTestCtxFromFile( 749 t, startingBlockHeight, basicGraphFilePath, 750 ) 751 defer cleanUp() 752 753 // Get the channel ID. 754 roasbeefSongoku := lnwire.NewShortChanIDFromInt( 755 ctx.getChannelIDFromAlias(t, "roasbeef", "songoku"), 756 ) 757 758 var ( 759 payHash lntypes.Hash 760 preImage [32]byte 761 amt = lnwire.NewMAtomsFromAtoms(1000) 762 privateChannelID = uint64(55555) 763 feeBaseMSat = uint32(15) 764 expiryDelta = uint16(32) 765 sgNode = ctx.aliases["songoku"] 766 feeLimit = lnwire.MilliAtom(500000) 767 ) 768 769 sgNodeID, err := secp256k1.ParsePubKey(sgNode[:]) 770 require.NoError(t, err) 771 772 // Craft a LightningPayment struct that'll send a payment from roasbeef 773 // to elst, through a private channel between songoku and elst for 774 // 1000 satoshis. This route has lowest fees compared with the rest. 775 payment := LightningPayment{ 776 Target: ctx.aliases["elst"], 777 Amount: amt, 778 FeeLimit: feeLimit, 779 paymentHash: &payHash, 780 RouteHints: [][]zpay32.HopHint{{ 781 // Add a private channel between songoku and elst. 782 zpay32.HopHint{ 783 NodeID: sgNodeID, 784 ChannelID: privateChannelID, 785 FeeBaseMAtoms: feeBaseMSat, 786 CLTVExpiryDelta: expiryDelta, 787 }, 788 }}, 789 } 790 791 // Prepare an error update for the private channel. The updated fee 792 // will exceeds the feeLimit. 793 updatedFeeBaseMAtoms := feeBaseMSat + uint32(feeLimit) 794 errChanUpdate := lnwire.ChannelUpdate{ 795 ShortChannelID: lnwire.NewShortChanIDFromInt(privateChannelID), 796 Timestamp: uint32(testTime.Add(time.Minute).Unix()), 797 BaseFee: updatedFeeBaseMAtoms, 798 TimeLockDelta: expiryDelta, 799 } 800 signErrChanUpdate(t, ctx.privKeys["songoku"], &errChanUpdate) 801 802 // We'll now modify the SendHTLC method to return an error for the 803 // outgoing channel to songoku. 804 errorReturned := false 805 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 806 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 807 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 808 809 if firstHop != roasbeefSongoku || errorReturned { 810 return preImage, nil 811 } 812 813 errorReturned = true 814 return [32]byte{}, htlcswitch.NewForwardingError( 815 // Within our error, we'll add a 816 // channel update which is meant to 817 // reflect the new fee schedule for the 818 // node/channel. 819 &lnwire.FailFeeInsufficient{ 820 Update: errChanUpdate, 821 }, 1, 822 ) 823 }) 824 825 // Send off the payment request to the router, route through son 826 // goku and then across the private channel to elst. 827 paymentPreImage, route, err := ctx.router.SendPayment(&payment) 828 require.NoError(t, err, "unable to send payment") 829 830 require.True(t, errorReturned, 831 "failed to simulate error in the first payment attempt", 832 ) 833 834 // The route selected should have three hops. Make sure that, 835 // path1: roasbeef -> son goku -> sophon -> elst 836 // path2: roasbeef -> pham nuwen -> sophon -> elst 837 // path3: roasbeef -> sophon -> (private channel) else 838 // path1 is selected. 839 require.Equal(t, 3, len(route.Hops), "incorrect route length") 840 841 // The preimage should match up with the one created above. 842 require.Equal(t, 843 paymentPreImage[:], preImage[:], "incorrect preimage used", 844 ) 845 846 // The route should have son goku as the first hop. 847 require.Equal(t, route.Hops[0].PubKeyBytes, ctx.aliases["songoku"], 848 "route should go through son goku as the first hop", 849 ) 850 851 // The route should have sophon as the first hop. 852 require.Equal(t, route.Hops[1].PubKeyBytes, ctx.aliases["sophon"], 853 "route should go through sophon as the second hop", 854 ) 855 // The route should pass via the public channel. 856 require.Equal(t, route.FinalHop().PubKeyBytes, ctx.aliases["elst"], 857 "route should go through elst as the final hop", 858 ) 859 } 860 861 // TestSendPaymentErrorNonFinalTimeLockErrors tests that if we receive either 862 // an ExpiryTooSoon or a IncorrectCltvExpiry error from a node, then we prune 863 // that node from the available graph witin a mission control session. This 864 // test ensures that we'll route around errors due to nodes not knowing the 865 // current block height. 866 func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { 867 t.Parallel() 868 869 const startingBlockHeight = 101 870 ctx, cleanUp := createTestCtxFromFile( 871 t, startingBlockHeight, basicGraphFilePath, 872 ) 873 defer cleanUp() 874 875 // Craft a LightningPayment struct that'll send a payment from roasbeef 876 // to sophon for 1k atoms. 877 var payHash lntypes.Hash 878 amt := lnwire.NewMAtomsFromAtoms(1000) 879 payment := LightningPayment{ 880 Target: ctx.aliases["sophon"], 881 Amount: amt, 882 FeeLimit: noFeeLimit, 883 paymentHash: &payHash, 884 } 885 886 var preImage [32]byte 887 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 888 889 // We'll also fetch the first outgoing channel edge from roasbeef to 890 // son goku. This edge will be included in the time lock related expiry 891 // errors that we'll get back due to disagrements in what the current 892 // block height is. 893 chanID := ctx.getChannelIDFromAlias(t, "roasbeef", "songoku") 894 roasbeefSongoku := lnwire.NewShortChanIDFromInt(chanID) 895 896 _, _, edgeUpdateToFail, err := ctx.graph.FetchChannelEdgesByID(chanID) 897 require.NoError(t, err, "unable to fetch chan id") 898 899 errChanUpdate := lnwire.ChannelUpdate{ 900 ShortChannelID: lnwire.NewShortChanIDFromInt(chanID), 901 Timestamp: uint32(edgeUpdateToFail.LastUpdate.Unix()), 902 MessageFlags: edgeUpdateToFail.MessageFlags, 903 ChannelFlags: edgeUpdateToFail.ChannelFlags, 904 TimeLockDelta: edgeUpdateToFail.TimeLockDelta, 905 HtlcMinimumMAtoms: edgeUpdateToFail.MinHTLC, 906 HtlcMaximumMAtoms: edgeUpdateToFail.MaxHTLC, 907 BaseFee: uint32(edgeUpdateToFail.FeeBaseMAtoms), 908 FeeRate: uint32(edgeUpdateToFail.FeeProportionalMillionths), 909 } 910 911 // We'll now modify the SendToSwitch method to return an error for the 912 // outgoing channel to son goku. Since this is a time lock related 913 // error, we should fail the payment flow all together, as Goku is the 914 // only channel to Sophon. 915 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 916 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 917 918 if firstHop == roasbeefSongoku { 919 return [32]byte{}, htlcswitch.NewForwardingError( 920 &lnwire.FailExpiryTooSoon{ 921 Update: errChanUpdate, 922 }, 1, 923 ) 924 } 925 926 return preImage, nil 927 }) 928 929 // assertExpectedPath is a helper function that asserts the returned 930 // route properly routes around the failure we've introduced in the 931 // graph. 932 assertExpectedPath := func(retPreImage [32]byte, route *route.Route) { 933 // The route selected should have two hops 934 require.Equal(t, 2, len(route.Hops), "incorrect route length") 935 936 // The preimage should match up with the once created above. 937 require.Equal(t, 938 preImage[:], retPreImage[:], "incorrect preimage used", 939 ) 940 941 // The route should have satoshi as the first hop. 942 require.Equalf(t, 943 ctx.aliases["phamnuwen"], route.Hops[0].PubKeyBytes, 944 "route should go through phamnuwen as first hop, "+ 945 "instead passes through: %v", 946 getAliasFromPubKey( 947 route.Hops[0].PubKeyBytes, ctx.aliases, 948 ), 949 ) 950 } 951 952 // Send off the payment request to the router, this payment should 953 // succeed as we should actually go through Pham Nuwen in order to get 954 // to Sophon, even though he has higher fees. 955 paymentPreImage, rt, err := ctx.router.SendPayment(&payment) 956 require.NoError(t, err, "unable to send payment") 957 958 assertExpectedPath(paymentPreImage, rt) 959 960 // We'll now modify the error return an IncorrectCltvExpiry error 961 // instead, this should result in the same behavior of roasbeef routing 962 // around the faulty Son Goku node. 963 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 964 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 965 966 if firstHop == roasbeefSongoku { 967 return [32]byte{}, htlcswitch.NewForwardingError( 968 &lnwire.FailIncorrectCltvExpiry{ 969 Update: errChanUpdate, 970 }, 1, 971 ) 972 } 973 974 return preImage, nil 975 }) 976 977 // Once again, Roasbeef should route around Goku since they disagree 978 // w.r.t to the block height, and instead go through Pham Nuwen. We 979 // flip a bit in the payment hash to allow resending this payment. 980 payment.paymentHash[1] ^= 1 981 paymentPreImage, rt, err = ctx.router.SendPayment(&payment) 982 require.NoError(t, err, "unable to send payment") 983 984 assertExpectedPath(paymentPreImage, rt) 985 } 986 987 // TestSendPaymentErrorPathPruning tests that the send of candidate routes 988 // properly gets pruned in response to ForwardingError response from the 989 // underlying SendToSwitch function. 990 func TestSendPaymentErrorPathPruning(t *testing.T) { 991 t.Parallel() 992 993 const startingBlockHeight = 101 994 ctx, cleanUp := createTestCtxFromFile( 995 t, startingBlockHeight, basicGraphFilePath, 996 ) 997 defer cleanUp() 998 999 // Craft a LightningPayment struct that'll send a payment from roasbeef 1000 // to luo ji for 1000 atoms, with a maximum of 1000 atoms in fees. 1001 var payHash lntypes.Hash 1002 paymentAmt := lnwire.NewMAtomsFromAtoms(1000) 1003 payment := LightningPayment{ 1004 Target: ctx.aliases["sophon"], 1005 Amount: paymentAmt, 1006 FeeLimit: noFeeLimit, 1007 paymentHash: &payHash, 1008 } 1009 1010 var preImage [32]byte 1011 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 1012 1013 roasbeefSongoku := lnwire.NewShortChanIDFromInt( 1014 ctx.getChannelIDFromAlias(t, "roasbeef", "songoku"), 1015 ) 1016 roasbeefPhanNuwen := lnwire.NewShortChanIDFromInt( 1017 ctx.getChannelIDFromAlias(t, "roasbeef", "phamnuwen"), 1018 ) 1019 1020 // First, we'll modify the SendToSwitch method to return an error 1021 // indicating that the channel from roasbeef to son goku is not operable 1022 // with an UnknownNextPeer. 1023 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 1024 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 1025 1026 if firstHop == roasbeefSongoku { 1027 // We'll first simulate an error from the first 1028 // hop to simulate the channel from songoku to 1029 // sophon not having enough capacity. 1030 return [32]byte{}, htlcswitch.NewForwardingError( 1031 &lnwire.FailTemporaryChannelFailure{}, 1032 1, 1033 ) 1034 } 1035 1036 // Next, we'll create an error from phan nuwen to 1037 // indicate that the sophon node is not longer online, 1038 // which should prune out the rest of the routes. 1039 if firstHop == roasbeefPhanNuwen { 1040 return [32]byte{}, htlcswitch.NewForwardingError( 1041 &lnwire.FailUnknownNextPeer{}, 1, 1042 ) 1043 } 1044 1045 return preImage, nil 1046 }) 1047 1048 ctx.router.cfg.MissionControl.(*MissionControl).ResetHistory() 1049 1050 // When we try to dispatch that payment, we should receive an error as 1051 // both attempts should fail and cause both routes to be pruned. 1052 _, _, err := ctx.router.SendPayment(&payment) 1053 require.Error(t, err, "payment didn't return error") 1054 1055 // The final error returned should also indicate that the peer wasn't 1056 // online (the last error we returned). 1057 require.Equal(t, channeldb.FailureReasonNoRoute, err) 1058 1059 // Inspect the two attempts that were made before the payment failed. 1060 p, err := ctx.router.cfg.Control.FetchPayment(payHash) 1061 require.NoError(t, err) 1062 1063 require.Equal(t, 2, len(p.HTLCs), "expected two attempts") 1064 1065 // We expect the first attempt to have failed with a 1066 // TemporaryChannelFailure, the second with UnknownNextPeer. 1067 msg := p.HTLCs[0].Failure.Message 1068 _, ok := msg.(*lnwire.FailTemporaryChannelFailure) 1069 require.True(t, ok, "unexpected fail message") 1070 1071 msg = p.HTLCs[1].Failure.Message 1072 _, ok = msg.(*lnwire.FailUnknownNextPeer) 1073 require.True(t, ok, "unexpected fail message") 1074 1075 err = ctx.router.cfg.MissionControl.(*MissionControl).ResetHistory() 1076 require.NoError(t, err, "reset history failed") 1077 1078 // Next, we'll modify the SendToSwitch method to indicate that the 1079 // connection between songoku and isn't up. 1080 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 1081 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 1082 1083 if firstHop == roasbeefSongoku { 1084 failure := htlcswitch.NewForwardingError( 1085 &lnwire.FailUnknownNextPeer{}, 1, 1086 ) 1087 return [32]byte{}, failure 1088 } 1089 1090 return preImage, nil 1091 }) 1092 1093 // This shouldn't return an error, as we'll make a payment attempt via 1094 // the pham nuwen channel based on the assumption that there might be an 1095 // intermittent issue with the songoku <-> sophon channel. 1096 paymentPreImage, rt, err := ctx.router.SendPayment(&payment) 1097 require.NoError(t, err, "unable send payment") 1098 1099 // This path should go: roasbeef -> pham nuwen -> sophon 1100 require.Equal(t, 2, len(rt.Hops), "incorrect route length") 1101 require.Equal(t, preImage[:], paymentPreImage[:], "incorrect preimage") 1102 require.Equalf(t, 1103 ctx.aliases["phamnuwen"], rt.Hops[0].PubKeyBytes, 1104 "route should go through phamnuwen as first hop, "+ 1105 "instead passes through: %v", 1106 getAliasFromPubKey(rt.Hops[0].PubKeyBytes, ctx.aliases), 1107 ) 1108 1109 ctx.router.cfg.MissionControl.(*MissionControl).ResetHistory() 1110 1111 // Finally, we'll modify the SendToSwitch function to indicate that the 1112 // roasbeef -> luoji channel has insufficient capacity. This should 1113 // again cause us to instead go via the satoshi route. 1114 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 1115 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 1116 1117 if firstHop == roasbeefSongoku { 1118 // We'll first simulate an error from the first 1119 // outgoing link to simulate the channel from luo ji to 1120 // roasbeef not having enough capacity. 1121 return [32]byte{}, htlcswitch.NewForwardingError( 1122 &lnwire.FailTemporaryChannelFailure{}, 1123 1, 1124 ) 1125 } 1126 return preImage, nil 1127 }) 1128 1129 // We flip a bit in the payment hash to allow resending this payment. 1130 payment.paymentHash[1] ^= 1 1131 paymentPreImage, rt, err = ctx.router.SendPayment(&payment) 1132 require.NoError(t, err, "unable send payment") 1133 1134 // This should succeed finally. The route selected should have two 1135 // hops. 1136 require.Equal(t, 2, len(rt.Hops), "incorrect route length") 1137 1138 // The preimage should match up with the once created above. 1139 require.Equal(t, preImage[:], paymentPreImage[:], "incorrect preimage") 1140 1141 // The route should have satoshi as the first hop. 1142 require.Equalf(t, 1143 ctx.aliases["phamnuwen"], rt.Hops[0].PubKeyBytes, 1144 "route should go through phamnuwen as first hop, "+ 1145 "instead passes through: %v", 1146 getAliasFromPubKey(rt.Hops[0].PubKeyBytes, ctx.aliases), 1147 ) 1148 } 1149 1150 // TestAddProof checks that we can update the channel proof after channel 1151 // info was added to the database. 1152 func TestAddProof(t *testing.T) { 1153 t.Parallel() 1154 1155 ctx, cleanup := createTestCtxSingleNode(t, 0) 1156 defer cleanup() 1157 1158 // Before creating out edge, we'll create two new nodes within the 1159 // network that the channel will connect. 1160 node1, err := createTestNode() 1161 if err != nil { 1162 t.Fatal(err) 1163 } 1164 node2, err := createTestNode() 1165 if err != nil { 1166 t.Fatal(err) 1167 } 1168 1169 // In order to be able to add the edge we should have a valid funding 1170 // UTXO within the blockchain. 1171 fundingTx, _, chanID, err := createChannelEdge(ctx, 1172 bitcoinKey1.SerializeCompressed(), bitcoinKey2.SerializeCompressed(), 1173 100, 0) 1174 if err != nil { 1175 t.Fatalf("unable create channel edge: %v", err) 1176 } 1177 fundingBlock := &wire.MsgBlock{ 1178 Transactions: []*wire.MsgTx{fundingTx}, 1179 } 1180 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 1181 1182 // After utxo was recreated adding the edge without the proof. 1183 edge := &channeldb.ChannelEdgeInfo{ 1184 ChannelID: chanID.ToUint64(), 1185 NodeKey1Bytes: node1.PubKeyBytes, 1186 NodeKey2Bytes: node2.PubKeyBytes, 1187 AuthProof: nil, 1188 } 1189 copy(edge.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 1190 copy(edge.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 1191 1192 if err := ctx.router.AddEdge(edge); err != nil { 1193 t.Fatalf("unable to add edge: %v", err) 1194 } 1195 1196 // Now we'll attempt to update the proof and check that it has been 1197 // properly updated. 1198 if err := ctx.router.AddProof(*chanID, &testAuthProof); err != nil { 1199 t.Fatalf("unable to add proof: %v", err) 1200 } 1201 1202 info, _, _, err := ctx.router.GetChannelByID(*chanID) 1203 if err != nil { 1204 t.Fatalf("unable to get channel with id: %v", *chanID) 1205 } 1206 if info.AuthProof == nil { 1207 t.Fatal("proof have been updated") 1208 } 1209 } 1210 1211 // TestIgnoreNodeAnnouncement tests that adding a node to the router that is 1212 // not known from any channel announcement, leads to the announcement being 1213 // ignored. 1214 func TestIgnoreNodeAnnouncement(t *testing.T) { 1215 t.Parallel() 1216 1217 const startingBlockHeight = 101 1218 ctx, cleanUp := createTestCtxFromFile( 1219 t, startingBlockHeight, basicGraphFilePath, 1220 ) 1221 defer cleanUp() 1222 1223 pub := priv1.PubKey() 1224 node := &channeldb.LightningNode{ 1225 HaveNodeAnnouncement: true, 1226 LastUpdate: time.Unix(123, 0), 1227 Addresses: testAddrs, 1228 Color: color.RGBA{1, 2, 3, 0}, 1229 Alias: "node11", 1230 AuthSigBytes: testSig.Serialize(), 1231 Features: testFeatures, 1232 } 1233 copy(node.PubKeyBytes[:], pub.SerializeCompressed()) 1234 1235 err := ctx.router.AddNode(node) 1236 if !IsError(err, ErrIgnored) { 1237 t.Fatalf("expected to get ErrIgnore, instead got: %v", err) 1238 } 1239 } 1240 1241 // TestIgnoreChannelEdgePolicyForUnknownChannel checks that a router will 1242 // ignore a channel policy for a channel not in the graph. 1243 func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) { 1244 t.Parallel() 1245 1246 const startingBlockHeight = 101 1247 1248 // Setup an initially empty network. 1249 testChannels := []*testChannel{} 1250 testGraph, err := createTestGraphFromChannels( 1251 true, testChannels, "roasbeef", 1252 ) 1253 if err != nil { 1254 t.Fatalf("unable to create graph: %v", err) 1255 } 1256 defer testGraph.cleanUp() 1257 1258 ctx, cleanUp := createTestCtxFromGraphInstance( 1259 t, startingBlockHeight, testGraph, false, 1260 ) 1261 defer cleanUp() 1262 1263 var pub1 [33]byte 1264 copy(pub1[:], priv1.PubKey().SerializeCompressed()) 1265 1266 var pub2 [33]byte 1267 copy(pub2[:], priv2.PubKey().SerializeCompressed()) 1268 1269 // Add the edge between the two unknown nodes to the graph, and check 1270 // that the nodes are found after the fact. 1271 fundingTx, _, chanID, err := createChannelEdge( 1272 ctx, bitcoinKey1.SerializeCompressed(), 1273 bitcoinKey2.SerializeCompressed(), 10000, 500, 1274 ) 1275 if err != nil { 1276 t.Fatalf("unable to create channel edge: %v", err) 1277 } 1278 fundingBlock := &wire.MsgBlock{ 1279 Transactions: []*wire.MsgTx{fundingTx}, 1280 } 1281 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 1282 1283 edge := &channeldb.ChannelEdgeInfo{ 1284 ChannelID: chanID.ToUint64(), 1285 NodeKey1Bytes: pub1, 1286 NodeKey2Bytes: pub2, 1287 DecredKey1Bytes: pub1, 1288 DecredKey2Bytes: pub2, 1289 AuthProof: nil, 1290 } 1291 edgePolicy := &channeldb.ChannelEdgePolicy{ 1292 SigBytes: testSig.Serialize(), 1293 ChannelID: edge.ChannelID, 1294 LastUpdate: testTime, 1295 TimeLockDelta: 10, 1296 MinHTLC: 1, 1297 FeeBaseMAtoms: 10, 1298 FeeProportionalMillionths: 10000, 1299 } 1300 1301 // Attempt to update the edge. This should be ignored, since the edge 1302 // is not yet added to the router. 1303 err = ctx.router.UpdateEdge(edgePolicy) 1304 if !IsError(err, ErrIgnored) { 1305 t.Fatalf("expected to get ErrIgnore, instead got: %v", err) 1306 } 1307 1308 // Add the edge. 1309 if err := ctx.router.AddEdge(edge); err != nil { 1310 t.Fatalf("expected to be able to add edge to the channel graph,"+ 1311 " even though the vertexes were unknown: %v.", err) 1312 } 1313 1314 // Now updating the edge policy should succeed. 1315 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 1316 t.Fatalf("unable to update edge policy: %v", err) 1317 } 1318 } 1319 1320 // TestAddEdgeUnknownVertexes tests that if an edge is added that contains two 1321 // vertexes which we don't know of, the edge should be available for use 1322 // regardless. This is due to the fact that we don't actually need node 1323 // announcements for the channel vertexes to be able to use the channel. 1324 func TestAddEdgeUnknownVertexes(t *testing.T) { 1325 t.Parallel() 1326 1327 const startingBlockHeight = 101 1328 ctx, cleanUp := createTestCtxFromFile( 1329 t, startingBlockHeight, basicGraphFilePath, 1330 ) 1331 defer cleanUp() 1332 1333 var pub1 [33]byte 1334 copy(pub1[:], priv1.PubKey().SerializeCompressed()) 1335 1336 var pub2 [33]byte 1337 copy(pub2[:], priv2.PubKey().SerializeCompressed()) 1338 1339 // The two nodes we are about to add should not exist yet. 1340 _, exists1, err := ctx.graph.HasLightningNode(pub1) 1341 if err != nil { 1342 t.Fatalf("unable to query graph: %v", err) 1343 } 1344 if exists1 { 1345 t.Fatalf("node already existed") 1346 } 1347 _, exists2, err := ctx.graph.HasLightningNode(pub2) 1348 if err != nil { 1349 t.Fatalf("unable to query graph: %v", err) 1350 } 1351 if exists2 { 1352 t.Fatalf("node already existed") 1353 } 1354 1355 // Add the edge between the two unknown nodes to the graph, and check 1356 // that the nodes are found after the fact. 1357 fundingTx, _, chanID, err := createChannelEdge(ctx, 1358 bitcoinKey1.SerializeCompressed(), 1359 bitcoinKey2.SerializeCompressed(), 1360 10000, 500, 1361 ) 1362 if err != nil { 1363 t.Fatalf("unable to create channel edge: %v", err) 1364 } 1365 fundingBlock := &wire.MsgBlock{ 1366 Transactions: []*wire.MsgTx{fundingTx}, 1367 } 1368 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 1369 1370 edge := &channeldb.ChannelEdgeInfo{ 1371 ChannelID: chanID.ToUint64(), 1372 NodeKey1Bytes: pub1, 1373 NodeKey2Bytes: pub2, 1374 DecredKey1Bytes: pub1, 1375 DecredKey2Bytes: pub2, 1376 AuthProof: nil, 1377 } 1378 if err := ctx.router.AddEdge(edge); err != nil { 1379 t.Fatalf("expected to be able to add edge to the channel graph,"+ 1380 " even though the vertexes were unknown: %v.", err) 1381 } 1382 1383 // We must add the edge policy to be able to use the edge for route 1384 // finding. 1385 edgePolicy := &channeldb.ChannelEdgePolicy{ 1386 SigBytes: testSig.Serialize(), 1387 ChannelID: edge.ChannelID, 1388 LastUpdate: testTime, 1389 TimeLockDelta: 10, 1390 MinHTLC: 1, 1391 FeeBaseMAtoms: 10, 1392 FeeProportionalMillionths: 10000, 1393 Node: &channeldb.LightningNode{ 1394 PubKeyBytes: edge.NodeKey2Bytes, 1395 }, 1396 } 1397 edgePolicy.ChannelFlags = 0 1398 1399 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 1400 t.Fatalf("unable to update edge policy: %v", err) 1401 } 1402 1403 // Create edge in the other direction as well. 1404 edgePolicy = &channeldb.ChannelEdgePolicy{ 1405 SigBytes: testSig.Serialize(), 1406 ChannelID: edge.ChannelID, 1407 LastUpdate: testTime, 1408 TimeLockDelta: 10, 1409 MinHTLC: 1, 1410 FeeBaseMAtoms: 10, 1411 FeeProportionalMillionths: 10000, 1412 Node: &channeldb.LightningNode{ 1413 PubKeyBytes: edge.NodeKey1Bytes, 1414 }, 1415 } 1416 edgePolicy.ChannelFlags = 1 1417 1418 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 1419 t.Fatalf("unable to update edge policy: %v", err) 1420 } 1421 1422 // After adding the edge between the two previously unknown nodes, they 1423 // should have been added to the graph. 1424 _, exists1, err = ctx.graph.HasLightningNode(pub1) 1425 if err != nil { 1426 t.Fatalf("unable to query graph: %v", err) 1427 } 1428 if !exists1 { 1429 t.Fatalf("node1 was not added to the graph") 1430 } 1431 _, exists2, err = ctx.graph.HasLightningNode(pub2) 1432 if err != nil { 1433 t.Fatalf("unable to query graph: %v", err) 1434 } 1435 if !exists2 { 1436 t.Fatalf("node2 was not added to the graph") 1437 } 1438 1439 // We will connect node1 to the rest of the test graph, and make sure 1440 // we can find a route to node2, which will use the just added channel 1441 // edge. 1442 1443 // We will connect node 1 to "sophon" 1444 connectNode := ctx.aliases["sophon"] 1445 connectNodeKey, err := secp256k1.ParsePubKey(connectNode[:]) 1446 if err != nil { 1447 t.Fatal(err) 1448 } 1449 1450 var ( 1451 pubKey1 *secp256k1.PublicKey 1452 pubKey2 *secp256k1.PublicKey 1453 ) 1454 node1Bytes := priv1.PubKey().SerializeCompressed() 1455 node2Bytes := connectNode 1456 if bytes.Compare(node1Bytes[:], node2Bytes[:]) == -1 { 1457 pubKey1 = priv1.PubKey() 1458 pubKey2 = connectNodeKey 1459 } else { 1460 pubKey1 = connectNodeKey 1461 pubKey2 = priv1.PubKey() 1462 } 1463 1464 fundingTx, _, chanID, err = createChannelEdge(ctx, 1465 pubKey1.SerializeCompressed(), pubKey2.SerializeCompressed(), 1466 10000, 510) 1467 if err != nil { 1468 t.Fatalf("unable to create channel edge: %v", err) 1469 } 1470 fundingBlock = &wire.MsgBlock{ 1471 Transactions: []*wire.MsgTx{fundingTx}, 1472 } 1473 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 1474 1475 edge = &channeldb.ChannelEdgeInfo{ 1476 ChannelID: chanID.ToUint64(), 1477 AuthProof: nil, 1478 } 1479 copy(edge.NodeKey1Bytes[:], node1Bytes) 1480 edge.NodeKey2Bytes = node2Bytes 1481 copy(edge.DecredKey1Bytes[:], node1Bytes) 1482 edge.DecredKey2Bytes = node2Bytes 1483 1484 if err := ctx.router.AddEdge(edge); err != nil { 1485 t.Fatalf("unable to add edge to the channel graph: %v.", err) 1486 } 1487 1488 edgePolicy = &channeldb.ChannelEdgePolicy{ 1489 SigBytes: testSig.Serialize(), 1490 ChannelID: edge.ChannelID, 1491 LastUpdate: testTime, 1492 TimeLockDelta: 10, 1493 MinHTLC: 1, 1494 FeeBaseMAtoms: 10, 1495 FeeProportionalMillionths: 10000, 1496 Node: &channeldb.LightningNode{ 1497 PubKeyBytes: edge.NodeKey2Bytes, 1498 }, 1499 } 1500 edgePolicy.ChannelFlags = 0 1501 1502 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 1503 t.Fatalf("unable to update edge policy: %v", err) 1504 } 1505 1506 edgePolicy = &channeldb.ChannelEdgePolicy{ 1507 SigBytes: testSig.Serialize(), 1508 ChannelID: edge.ChannelID, 1509 LastUpdate: testTime, 1510 TimeLockDelta: 10, 1511 MinHTLC: 1, 1512 FeeBaseMAtoms: 10, 1513 FeeProportionalMillionths: 10000, 1514 Node: &channeldb.LightningNode{ 1515 PubKeyBytes: edge.NodeKey1Bytes, 1516 }, 1517 } 1518 edgePolicy.ChannelFlags = 1 1519 1520 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 1521 t.Fatalf("unable to update edge policy: %v", err) 1522 } 1523 1524 // We should now be able to find a route to node 2. 1525 paymentAmt := lnwire.NewMAtomsFromAtoms(100) 1526 targetNode := priv2.PubKey() 1527 var targetPubKeyBytes route.Vertex 1528 copy(targetPubKeyBytes[:], targetNode.SerializeCompressed()) 1529 _, err = ctx.router.FindRoute( 1530 ctx.router.selfNode.PubKeyBytes, 1531 targetPubKeyBytes, paymentAmt, noRestrictions, nil, nil, 1532 MinCLTVDelta, 1533 ) 1534 if err != nil { 1535 t.Fatalf("unable to find any routes: %v", err) 1536 } 1537 1538 // Now check that we can update the node info for the partial node 1539 // without messing up the channel graph. 1540 n1 := &channeldb.LightningNode{ 1541 HaveNodeAnnouncement: true, 1542 LastUpdate: time.Unix(123, 0), 1543 Addresses: testAddrs, 1544 Color: color.RGBA{1, 2, 3, 0}, 1545 Alias: "node11", 1546 AuthSigBytes: testSig.Serialize(), 1547 Features: testFeatures, 1548 } 1549 copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed()) 1550 1551 if err := ctx.router.AddNode(n1); err != nil { 1552 t.Fatalf("could not add node: %v", err) 1553 } 1554 1555 n2 := &channeldb.LightningNode{ 1556 HaveNodeAnnouncement: true, 1557 LastUpdate: time.Unix(123, 0), 1558 Addresses: testAddrs, 1559 Color: color.RGBA{1, 2, 3, 0}, 1560 Alias: "node22", 1561 AuthSigBytes: testSig.Serialize(), 1562 Features: testFeatures, 1563 } 1564 copy(n2.PubKeyBytes[:], priv2.PubKey().SerializeCompressed()) 1565 1566 if err := ctx.router.AddNode(n2); err != nil { 1567 t.Fatalf("could not add node: %v", err) 1568 } 1569 1570 // Should still be able to find the route, and the info should be 1571 // updated. 1572 _, err = ctx.router.FindRoute( 1573 ctx.router.selfNode.PubKeyBytes, 1574 targetPubKeyBytes, paymentAmt, noRestrictions, nil, nil, 1575 MinCLTVDelta, 1576 ) 1577 if err != nil { 1578 t.Fatalf("unable to find any routes: %v", err) 1579 } 1580 1581 copy1, err := ctx.graph.FetchLightningNode(pub1) 1582 if err != nil { 1583 t.Fatalf("unable to fetch node: %v", err) 1584 } 1585 1586 if copy1.Alias != n1.Alias { 1587 t.Fatalf("fetched node not equal to original") 1588 } 1589 1590 copy2, err := ctx.graph.FetchLightningNode(pub2) 1591 if err != nil { 1592 t.Fatalf("unable to fetch node: %v", err) 1593 } 1594 1595 if copy2.Alias != n2.Alias { 1596 t.Fatalf("fetched node not equal to original") 1597 } 1598 } 1599 1600 // TestWakeUpOnStaleBranch tests that upon startup of the ChannelRouter, if the 1601 // the chain previously reflected in the channel graph is stale (overtaken by a 1602 // longer chain), the channel router will prune the graph for any channels 1603 // confirmed on the stale chain, and resync to the main chain. 1604 func TestWakeUpOnStaleBranch(t *testing.T) { 1605 t.Parallel() 1606 1607 const startingBlockHeight = 101 1608 ctx, cleanUp := createTestCtxSingleNode(t, startingBlockHeight) 1609 defer cleanUp() 1610 1611 const chanValue = 10000 1612 1613 // chanID1 will not be reorged out. 1614 var chanID1 uint64 1615 1616 // chanID2 will be reorged out. 1617 var chanID2 uint64 1618 1619 // Create 10 common blocks, confirming chanID1. 1620 for i := uint32(1); i <= 10; i++ { 1621 block := &wire.MsgBlock{ 1622 Transactions: []*wire.MsgTx{}, 1623 } 1624 height := startingBlockHeight + i 1625 if i == 5 { 1626 fundingTx, _, chanID, err := createChannelEdge(ctx, 1627 bitcoinKey1.SerializeCompressed(), 1628 bitcoinKey2.SerializeCompressed(), 1629 chanValue, height) 1630 if err != nil { 1631 t.Fatalf("unable create channel edge: %v", err) 1632 } 1633 block.Transactions = append(block.Transactions, 1634 fundingTx) 1635 chanID1 = chanID.ToUint64() 1636 1637 } 1638 ctx.chain.addBlock(block, height, rand.Uint32()) 1639 ctx.chain.setBestBlock(int32(height)) 1640 ctx.chainView.notifyBlock(block.BlockHash(), height, 1641 []*wire.MsgTx{}, t) 1642 } 1643 1644 // Give time to process new blocks 1645 time.Sleep(time.Millisecond * 500) 1646 1647 _, forkHeight, err := ctx.chain.GetBestBlock() 1648 if err != nil { 1649 t.Fatalf("unable to ge best block: %v", err) 1650 } 1651 1652 // Create 10 blocks on the minority chain, confirming chanID2. 1653 for i := uint32(1); i <= 10; i++ { 1654 block := &wire.MsgBlock{ 1655 Transactions: []*wire.MsgTx{}, 1656 } 1657 height := uint32(forkHeight) + i 1658 if i == 5 { 1659 fundingTx, _, chanID, err := createChannelEdge(ctx, 1660 bitcoinKey1.SerializeCompressed(), 1661 bitcoinKey2.SerializeCompressed(), 1662 chanValue, height) 1663 if err != nil { 1664 t.Fatalf("unable create channel edge: %v", err) 1665 } 1666 block.Transactions = append(block.Transactions, 1667 fundingTx) 1668 chanID2 = chanID.ToUint64() 1669 } 1670 ctx.chain.addBlock(block, height, rand.Uint32()) 1671 ctx.chain.setBestBlock(int32(height)) 1672 ctx.chainView.notifyBlock(block.BlockHash(), height, 1673 []*wire.MsgTx{}, t) 1674 } 1675 // Give time to process new blocks 1676 time.Sleep(time.Millisecond * 500) 1677 1678 // Now add the two edges to the channel graph, and check that they 1679 // correctly show up in the database. 1680 node1, err := createTestNode() 1681 if err != nil { 1682 t.Fatalf("unable to create test node: %v", err) 1683 } 1684 node2, err := createTestNode() 1685 if err != nil { 1686 t.Fatalf("unable to create test node: %v", err) 1687 } 1688 1689 edge1 := &channeldb.ChannelEdgeInfo{ 1690 ChannelID: chanID1, 1691 NodeKey1Bytes: node1.PubKeyBytes, 1692 NodeKey2Bytes: node2.PubKeyBytes, 1693 AuthProof: &channeldb.ChannelAuthProof{ 1694 NodeSig1Bytes: testSig.Serialize(), 1695 NodeSig2Bytes: testSig.Serialize(), 1696 DecredSig1Bytes: testSig.Serialize(), 1697 DecredSig2Bytes: testSig.Serialize(), 1698 }, 1699 } 1700 copy(edge1.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 1701 copy(edge1.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 1702 1703 if err := ctx.router.AddEdge(edge1); err != nil { 1704 t.Fatalf("unable to add edge: %v", err) 1705 } 1706 1707 edge2 := &channeldb.ChannelEdgeInfo{ 1708 ChannelID: chanID2, 1709 NodeKey1Bytes: node1.PubKeyBytes, 1710 NodeKey2Bytes: node2.PubKeyBytes, 1711 AuthProof: &channeldb.ChannelAuthProof{ 1712 NodeSig1Bytes: testSig.Serialize(), 1713 NodeSig2Bytes: testSig.Serialize(), 1714 DecredSig1Bytes: testSig.Serialize(), 1715 DecredSig2Bytes: testSig.Serialize(), 1716 }, 1717 } 1718 copy(edge2.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 1719 copy(edge2.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 1720 1721 if err := ctx.router.AddEdge(edge2); err != nil { 1722 t.Fatalf("unable to add edge: %v", err) 1723 } 1724 1725 // Check that the fundingTxs are in the graph db. 1726 _, _, has, isZombie, err := ctx.graph.HasChannelEdge(chanID1) 1727 if err != nil { 1728 t.Fatalf("error looking for edge: %v", chanID1) 1729 } 1730 if !has { 1731 t.Fatalf("could not find edge in graph") 1732 } 1733 if isZombie { 1734 t.Fatal("edge was marked as zombie") 1735 } 1736 1737 _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) 1738 if err != nil { 1739 t.Fatalf("error looking for edge: %v", chanID2) 1740 } 1741 if !has { 1742 t.Fatalf("could not find edge in graph") 1743 } 1744 if isZombie { 1745 t.Fatal("edge was marked as zombie") 1746 } 1747 1748 // Stop the router, so we can reorg the chain while its offline. 1749 if err := ctx.router.Stop(); err != nil { 1750 t.Fatalf("unable to stop router: %v", err) 1751 } 1752 1753 // Create a 15 block fork. 1754 for i := uint32(1); i <= 15; i++ { 1755 block := &wire.MsgBlock{ 1756 Transactions: []*wire.MsgTx{}, 1757 } 1758 height := uint32(forkHeight) + i 1759 ctx.chain.addBlock(block, height, rand.Uint32()) 1760 ctx.chain.setBestBlock(int32(height)) 1761 } 1762 1763 // Give time to process new blocks. 1764 time.Sleep(time.Millisecond * 500) 1765 1766 // Create new router with same graph database. 1767 router, err := New(Config{ 1768 Graph: ctx.graph, 1769 Chain: ctx.chain, 1770 ChainView: ctx.chainView, 1771 Payer: &mockPaymentAttemptDispatcherOld{}, 1772 Control: makeMockControlTower(), 1773 ChannelPruneExpiry: time.Hour * 24, 1774 GraphPruneInterval: time.Hour * 2, 1775 1776 // We'll set the delay to zero to prune immediately. 1777 FirstTimePruneDelay: 0, 1778 }) 1779 if err != nil { 1780 t.Fatalf("unable to create router %v", err) 1781 } 1782 1783 // It should resync to the longer chain on startup. 1784 if err := router.Start(); err != nil { 1785 t.Fatalf("unable to start router: %v", err) 1786 } 1787 1788 // The channel with chanID2 should not be in the database anymore, 1789 // since it is not confirmed on the longest chain. chanID1 should 1790 // still be. 1791 _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID1) 1792 if err != nil { 1793 t.Fatalf("error looking for edge: %v", chanID1) 1794 } 1795 if !has { 1796 t.Fatalf("did not find edge in graph") 1797 } 1798 if isZombie { 1799 t.Fatal("edge was marked as zombie") 1800 } 1801 1802 _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) 1803 if err != nil { 1804 t.Fatalf("error looking for edge: %v", chanID2) 1805 } 1806 if has { 1807 t.Fatalf("found edge in graph") 1808 } 1809 if isZombie { 1810 t.Fatal("reorged edge should not be marked as zombie") 1811 } 1812 } 1813 1814 // TestDisconnectedBlocks checks that the router handles a reorg happening when 1815 // it is active. 1816 func TestDisconnectedBlocks(t *testing.T) { 1817 t.Parallel() 1818 1819 const startingBlockHeight = 101 1820 ctx, cleanUp := createTestCtxSingleNode(t, startingBlockHeight) 1821 defer cleanUp() 1822 1823 const chanValue = 10000 1824 1825 // chanID1 will not be reorged out, while chanID2 will be reorged out. 1826 var chanID1, chanID2 uint64 1827 1828 // Create 10 common blocks, confirming chanID1. 1829 for i := uint32(1); i <= 10; i++ { 1830 block := &wire.MsgBlock{ 1831 Transactions: []*wire.MsgTx{}, 1832 } 1833 height := startingBlockHeight + i 1834 if i == 5 { 1835 fundingTx, _, chanID, err := createChannelEdge(ctx, 1836 bitcoinKey1.SerializeCompressed(), 1837 bitcoinKey2.SerializeCompressed(), 1838 chanValue, height) 1839 if err != nil { 1840 t.Fatalf("unable create channel edge: %v", err) 1841 } 1842 block.Transactions = append(block.Transactions, 1843 fundingTx) 1844 chanID1 = chanID.ToUint64() 1845 1846 } 1847 ctx.chain.addBlock(block, height, rand.Uint32()) 1848 ctx.chain.setBestBlock(int32(height)) 1849 ctx.chainView.notifyBlock(block.BlockHash(), height, 1850 []*wire.MsgTx{}, t) 1851 } 1852 1853 // Give time to process new blocks 1854 time.Sleep(time.Millisecond * 500) 1855 1856 _, forkHeight, err := ctx.chain.GetBestBlock() 1857 if err != nil { 1858 t.Fatalf("unable to get best block: %v", err) 1859 } 1860 1861 // Create 10 blocks on the minority chain, confirming chanID2. 1862 var minorityChain []*wire.MsgBlock 1863 for i := uint32(1); i <= 10; i++ { 1864 block := &wire.MsgBlock{ 1865 Transactions: []*wire.MsgTx{}, 1866 } 1867 height := uint32(forkHeight) + i 1868 if i == 5 { 1869 fundingTx, _, chanID, err := createChannelEdge(ctx, 1870 bitcoinKey1.SerializeCompressed(), 1871 bitcoinKey2.SerializeCompressed(), 1872 chanValue, height) 1873 if err != nil { 1874 t.Fatalf("unable create channel edge: %v", err) 1875 } 1876 block.Transactions = append(block.Transactions, 1877 fundingTx) 1878 chanID2 = chanID.ToUint64() 1879 } 1880 minorityChain = append(minorityChain, block) 1881 ctx.chain.addBlock(block, height, rand.Uint32()) 1882 ctx.chain.setBestBlock(int32(height)) 1883 ctx.chainView.notifyBlock(block.BlockHash(), height, 1884 []*wire.MsgTx{}, t) 1885 } 1886 // Give time to process new blocks 1887 time.Sleep(time.Millisecond * 500) 1888 1889 // Now add the two edges to the channel graph, and check that they 1890 // correctly show up in the database. 1891 node1, err := createTestNode() 1892 if err != nil { 1893 t.Fatalf("unable to create test node: %v", err) 1894 } 1895 node2, err := createTestNode() 1896 if err != nil { 1897 t.Fatalf("unable to create test node: %v", err) 1898 } 1899 1900 edge1 := &channeldb.ChannelEdgeInfo{ 1901 ChannelID: chanID1, 1902 NodeKey1Bytes: node1.PubKeyBytes, 1903 NodeKey2Bytes: node2.PubKeyBytes, 1904 DecredKey1Bytes: node1.PubKeyBytes, 1905 DecredKey2Bytes: node2.PubKeyBytes, 1906 AuthProof: &channeldb.ChannelAuthProof{ 1907 NodeSig1Bytes: testSig.Serialize(), 1908 NodeSig2Bytes: testSig.Serialize(), 1909 DecredSig1Bytes: testSig.Serialize(), 1910 DecredSig2Bytes: testSig.Serialize(), 1911 }, 1912 } 1913 copy(edge1.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 1914 copy(edge1.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 1915 1916 if err := ctx.router.AddEdge(edge1); err != nil { 1917 t.Fatalf("unable to add edge: %v", err) 1918 } 1919 1920 edge2 := &channeldb.ChannelEdgeInfo{ 1921 ChannelID: chanID2, 1922 NodeKey1Bytes: node1.PubKeyBytes, 1923 NodeKey2Bytes: node2.PubKeyBytes, 1924 DecredKey1Bytes: node1.PubKeyBytes, 1925 DecredKey2Bytes: node2.PubKeyBytes, 1926 AuthProof: &channeldb.ChannelAuthProof{ 1927 NodeSig1Bytes: testSig.Serialize(), 1928 NodeSig2Bytes: testSig.Serialize(), 1929 DecredSig1Bytes: testSig.Serialize(), 1930 DecredSig2Bytes: testSig.Serialize(), 1931 }, 1932 } 1933 copy(edge2.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 1934 copy(edge2.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 1935 1936 if err := ctx.router.AddEdge(edge2); err != nil { 1937 t.Fatalf("unable to add edge: %v", err) 1938 } 1939 1940 // Check that the fundingTxs are in the graph db. 1941 _, _, has, isZombie, err := ctx.graph.HasChannelEdge(chanID1) 1942 if err != nil { 1943 t.Fatalf("error looking for edge: %v", chanID1) 1944 } 1945 if !has { 1946 t.Fatalf("could not find edge in graph") 1947 } 1948 if isZombie { 1949 t.Fatal("edge was marked as zombie") 1950 } 1951 1952 _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) 1953 if err != nil { 1954 t.Fatalf("error looking for edge: %v", chanID2) 1955 } 1956 if !has { 1957 t.Fatalf("could not find edge in graph") 1958 } 1959 if isZombie { 1960 t.Fatal("edge was marked as zombie") 1961 } 1962 1963 // Create a 15 block fork. We first let the chainView notify the router 1964 // about stale blocks, before sending the now connected blocks. We do 1965 // this because we expect this order from the chainview. 1966 ctx.chainView.notifyStaleBlockAck = make(chan struct{}, 1) 1967 for i := len(minorityChain) - 1; i >= 0; i-- { 1968 block := minorityChain[i] 1969 height := uint32(forkHeight) + uint32(i) + 1 1970 ctx.chainView.notifyStaleBlock(block.BlockHash(), height, 1971 block.Transactions, t) 1972 <-ctx.chainView.notifyStaleBlockAck 1973 } 1974 1975 time.Sleep(time.Second * 2) 1976 1977 ctx.chainView.notifyBlockAck = make(chan struct{}, 1) 1978 for i := uint32(1); i <= 15; i++ { 1979 block := &wire.MsgBlock{ 1980 Transactions: []*wire.MsgTx{}, 1981 } 1982 height := uint32(forkHeight) + i 1983 ctx.chain.addBlock(block, height, rand.Uint32()) 1984 ctx.chain.setBestBlock(int32(height)) 1985 ctx.chainView.notifyBlock(block.BlockHash(), height, 1986 block.Transactions, t) 1987 <-ctx.chainView.notifyBlockAck 1988 } 1989 1990 time.Sleep(time.Millisecond * 500) 1991 1992 // chanID2 should not be in the database anymore, since it is not 1993 // confirmed on the longest chain. chanID1 should still be. 1994 _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID1) 1995 if err != nil { 1996 t.Fatalf("error looking for edge: %v", chanID1) 1997 } 1998 if !has { 1999 t.Fatalf("did not find edge in graph") 2000 } 2001 if isZombie { 2002 t.Fatal("edge was marked as zombie") 2003 } 2004 2005 _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) 2006 if err != nil { 2007 t.Fatalf("error looking for edge: %v", chanID2) 2008 } 2009 if has { 2010 t.Fatalf("found edge in graph") 2011 } 2012 if isZombie { 2013 t.Fatal("reorged edge should not be marked as zombie") 2014 } 2015 } 2016 2017 // TestChansClosedOfflinePruneGraph tests that if channels we know of are 2018 // closed while we're offline, then once we resume operation of the 2019 // ChannelRouter, then the channels are properly pruned. 2020 func TestRouterChansClosedOfflinePruneGraph(t *testing.T) { 2021 t.Parallel() 2022 2023 const startingBlockHeight = 101 2024 ctx, cleanUp := createTestCtxSingleNode(t, startingBlockHeight) 2025 defer cleanUp() 2026 2027 const chanValue = 10000 2028 2029 // First, we'll create a channel, to be mined shortly at height 102. 2030 block102 := &wire.MsgBlock{ 2031 Transactions: []*wire.MsgTx{}, 2032 } 2033 nextHeight := startingBlockHeight + 1 2034 fundingTx1, chanUTXO, chanID1, err := createChannelEdge(ctx, 2035 bitcoinKey1.SerializeCompressed(), 2036 bitcoinKey2.SerializeCompressed(), 2037 chanValue, uint32(nextHeight)) 2038 if err != nil { 2039 t.Fatalf("unable create channel edge: %v", err) 2040 } 2041 block102.Transactions = append(block102.Transactions, fundingTx1) 2042 ctx.chain.addBlock(block102, uint32(nextHeight), rand.Uint32()) 2043 ctx.chain.setBestBlock(int32(nextHeight)) 2044 ctx.chainView.notifyBlock(block102.BlockHash(), uint32(nextHeight), 2045 []*wire.MsgTx{}, t) 2046 2047 // We'll now create the edges and nodes within the database required 2048 // for the ChannelRouter to properly recognize the channel we added 2049 // above. 2050 node1, err := createTestNode() 2051 if err != nil { 2052 t.Fatalf("unable to create test node: %v", err) 2053 } 2054 node2, err := createTestNode() 2055 if err != nil { 2056 t.Fatalf("unable to create test node: %v", err) 2057 } 2058 edge1 := &channeldb.ChannelEdgeInfo{ 2059 ChannelID: chanID1.ToUint64(), 2060 NodeKey1Bytes: node1.PubKeyBytes, 2061 NodeKey2Bytes: node2.PubKeyBytes, 2062 AuthProof: &channeldb.ChannelAuthProof{ 2063 NodeSig1Bytes: testSig.Serialize(), 2064 NodeSig2Bytes: testSig.Serialize(), 2065 DecredSig1Bytes: testSig.Serialize(), 2066 DecredSig2Bytes: testSig.Serialize(), 2067 }, 2068 } 2069 copy(edge1.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 2070 copy(edge1.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 2071 if err := ctx.router.AddEdge(edge1); err != nil { 2072 t.Fatalf("unable to add edge: %v", err) 2073 } 2074 2075 // The router should now be aware of the channel we created above. 2076 _, _, hasChan, isZombie, err := ctx.graph.HasChannelEdge(chanID1.ToUint64()) 2077 if err != nil { 2078 t.Fatalf("error looking for edge: %v", chanID1) 2079 } 2080 if !hasChan { 2081 t.Fatalf("could not find edge in graph") 2082 } 2083 if isZombie { 2084 t.Fatal("edge was marked as zombie") 2085 } 2086 2087 // With the transaction included, and the router's database state 2088 // updated, we'll now mine 5 additional blocks on top of it. 2089 for i := 0; i < 5; i++ { 2090 nextHeight++ 2091 2092 block := &wire.MsgBlock{ 2093 Transactions: []*wire.MsgTx{}, 2094 } 2095 ctx.chain.addBlock(block, uint32(nextHeight), rand.Uint32()) 2096 ctx.chain.setBestBlock(int32(nextHeight)) 2097 ctx.chainView.notifyBlock(block.BlockHash(), uint32(nextHeight), 2098 []*wire.MsgTx{}, t) 2099 } 2100 2101 // At this point, our starting height should be 107. 2102 _, chainHeight, err := ctx.chain.GetBestBlock() 2103 if err != nil { 2104 t.Fatalf("unable to get best block: %v", err) 2105 } 2106 if chainHeight != 107 { 2107 t.Fatalf("incorrect chain height: expected %v, got %v", 2108 107, chainHeight) 2109 } 2110 2111 // Next, we'll "shut down" the router in order to simulate downtime. 2112 if err := ctx.router.Stop(); err != nil { 2113 t.Fatalf("unable to shutdown router: %v", err) 2114 } 2115 2116 // While the router is "offline" we'll mine 5 additional blocks, with 2117 // the second block closing the channel we created above. 2118 for i := 0; i < 5; i++ { 2119 nextHeight++ 2120 2121 block := &wire.MsgBlock{ 2122 Transactions: []*wire.MsgTx{}, 2123 } 2124 2125 if i == 2 { 2126 // For the second block, we'll add a transaction that 2127 // closes the channel we created above by spending the 2128 // output. 2129 closingTx := wire.NewMsgTx() 2130 closingTx.Version = 2 2131 closingTx.AddTxIn(&wire.TxIn{ 2132 PreviousOutPoint: *chanUTXO, 2133 }) 2134 block.Transactions = append(block.Transactions, 2135 closingTx) 2136 } 2137 2138 ctx.chain.addBlock(block, uint32(nextHeight), rand.Uint32()) 2139 ctx.chain.setBestBlock(int32(nextHeight)) 2140 ctx.chainView.notifyBlock(block.BlockHash(), uint32(nextHeight), 2141 []*wire.MsgTx{}, t) 2142 } 2143 2144 // At this point, our starting height should be 112. 2145 _, chainHeight, err = ctx.chain.GetBestBlock() 2146 if err != nil { 2147 t.Fatalf("unable to get best block: %v", err) 2148 } 2149 if chainHeight != 112 { 2150 t.Fatalf("incorrect chain height: expected %v, got %v", 2151 112, chainHeight) 2152 } 2153 2154 // Now we'll re-start the ChannelRouter. It should recognize that it's 2155 // behind the main chain and prune all the blocks that it missed while 2156 // it was down. 2157 ctx.RestartRouter(t) 2158 2159 // At this point, the channel that was pruned should no longer be known 2160 // by the router. 2161 _, _, hasChan, isZombie, err = ctx.graph.HasChannelEdge(chanID1.ToUint64()) 2162 if err != nil { 2163 t.Fatalf("error looking for edge: %v", chanID1) 2164 } 2165 if hasChan { 2166 t.Fatalf("channel was found in graph but shouldn't have been") 2167 } 2168 if isZombie { 2169 t.Fatal("closed channel should not be marked as zombie") 2170 } 2171 } 2172 2173 // TestPruneChannelGraphStaleEdges ensures that we properly prune stale edges 2174 // from the channel graph. 2175 func TestPruneChannelGraphStaleEdges(t *testing.T) { 2176 t.Parallel() 2177 2178 freshTimestamp := time.Now() 2179 staleTimestamp := time.Unix(0, 0) 2180 2181 // We'll create the following test graph so that two of the channels 2182 // are pruned. 2183 testChannels := []*testChannel{ 2184 // No edges. 2185 { 2186 Node1: &testChannelEnd{Alias: "a"}, 2187 Node2: &testChannelEnd{Alias: "b"}, 2188 Capacity: 100000, 2189 ChannelID: 1, 2190 }, 2191 2192 // Only one edge with a stale timestamp. 2193 { 2194 Node1: &testChannelEnd{ 2195 Alias: "d", 2196 testChannelPolicy: &testChannelPolicy{ 2197 LastUpdate: staleTimestamp, 2198 }, 2199 }, 2200 Node2: &testChannelEnd{Alias: "b"}, 2201 Capacity: 100000, 2202 ChannelID: 2, 2203 }, 2204 2205 // Only one edge with a stale timestamp, but it's the source 2206 // node so it won't get pruned. 2207 { 2208 Node1: &testChannelEnd{ 2209 Alias: "a", 2210 testChannelPolicy: &testChannelPolicy{ 2211 LastUpdate: staleTimestamp, 2212 }, 2213 }, 2214 Node2: &testChannelEnd{Alias: "b"}, 2215 Capacity: 100000, 2216 ChannelID: 3, 2217 }, 2218 2219 // Only one edge with a fresh timestamp. 2220 { 2221 Node1: &testChannelEnd{ 2222 Alias: "a", 2223 testChannelPolicy: &testChannelPolicy{ 2224 LastUpdate: freshTimestamp, 2225 }, 2226 }, 2227 Node2: &testChannelEnd{Alias: "b"}, 2228 Capacity: 100000, 2229 ChannelID: 4, 2230 }, 2231 2232 // One edge fresh, one edge stale. This will be pruned with 2233 // strict pruning activated. 2234 { 2235 Node1: &testChannelEnd{ 2236 Alias: "c", 2237 testChannelPolicy: &testChannelPolicy{ 2238 LastUpdate: freshTimestamp, 2239 }, 2240 }, 2241 Node2: &testChannelEnd{ 2242 Alias: "d", 2243 testChannelPolicy: &testChannelPolicy{ 2244 LastUpdate: staleTimestamp, 2245 }, 2246 }, 2247 Capacity: 100000, 2248 ChannelID: 5, 2249 }, 2250 2251 // Both edges fresh. 2252 symmetricTestChannel("g", "h", 100000, &testChannelPolicy{ 2253 LastUpdate: freshTimestamp, 2254 }, 6), 2255 2256 // Both edges stale, only one pruned. This should be pruned for 2257 // both normal and strict pruning. 2258 symmetricTestChannel("e", "f", 100000, &testChannelPolicy{ 2259 LastUpdate: staleTimestamp, 2260 }, 7), 2261 } 2262 2263 for _, strictPruning := range []bool{true, false} { 2264 // We'll create our test graph and router backed with these test 2265 // channels we've created. 2266 testGraph, err := createTestGraphFromChannels( 2267 true, testChannels, "a", 2268 ) 2269 if err != nil { 2270 t.Fatalf("unable to create test graph: %v", err) 2271 } 2272 defer testGraph.cleanUp() 2273 2274 const startingHeight = 100 2275 ctx, cleanUp := createTestCtxFromGraphInstance( 2276 t, startingHeight, testGraph, strictPruning, 2277 ) 2278 defer cleanUp() 2279 2280 // All of the channels should exist before pruning them. 2281 assertChannelsPruned(t, ctx.graph, testChannels) 2282 2283 // Proceed to prune the channels - only the last one should be pruned. 2284 if err := ctx.router.pruneZombieChans(); err != nil { 2285 t.Fatalf("unable to prune zombie channels: %v", err) 2286 } 2287 2288 // We expect channels that have either both edges stale, or one edge 2289 // stale with both known. 2290 var prunedChannels []uint64 2291 if strictPruning { 2292 prunedChannels = []uint64{2, 5, 7} 2293 } else { 2294 prunedChannels = []uint64{2, 7} 2295 } 2296 assertChannelsPruned(t, ctx.graph, testChannels, prunedChannels...) 2297 } 2298 } 2299 2300 // TestPruneChannelGraphDoubleDisabled test that we can properly prune channels 2301 // with both edges disabled from our channel graph. 2302 func TestPruneChannelGraphDoubleDisabled(t *testing.T) { 2303 t.Parallel() 2304 2305 t.Run("no_assumechannelvalid", func(t *testing.T) { 2306 testPruneChannelGraphDoubleDisabled(t, false) 2307 }) 2308 t.Run("assumechannelvalid", func(t *testing.T) { 2309 testPruneChannelGraphDoubleDisabled(t, true) 2310 }) 2311 } 2312 2313 func testPruneChannelGraphDoubleDisabled(t *testing.T, assumeValid bool) { 2314 // We'll create the following test graph so that only the last channel 2315 // is pruned. We'll use a fresh timestamp to ensure they're not pruned 2316 // according to that heuristic. 2317 timestamp := time.Now() 2318 testChannels := []*testChannel{ 2319 // Channel from self shouldn't be pruned. 2320 symmetricTestChannel( 2321 "self", "a", 100000, &testChannelPolicy{ 2322 LastUpdate: timestamp, 2323 Disabled: true, 2324 }, 99, 2325 ), 2326 2327 // No edges. 2328 { 2329 Node1: &testChannelEnd{Alias: "a"}, 2330 Node2: &testChannelEnd{Alias: "b"}, 2331 Capacity: 100000, 2332 ChannelID: 1, 2333 }, 2334 2335 // Only one edge disabled. 2336 { 2337 Node1: &testChannelEnd{ 2338 Alias: "a", 2339 testChannelPolicy: &testChannelPolicy{ 2340 LastUpdate: timestamp, 2341 Disabled: true, 2342 }, 2343 }, 2344 Node2: &testChannelEnd{Alias: "b"}, 2345 Capacity: 100000, 2346 ChannelID: 2, 2347 }, 2348 2349 // Only one edge enabled. 2350 { 2351 Node1: &testChannelEnd{ 2352 Alias: "a", 2353 testChannelPolicy: &testChannelPolicy{ 2354 LastUpdate: timestamp, 2355 Disabled: false, 2356 }, 2357 }, 2358 Node2: &testChannelEnd{Alias: "b"}, 2359 Capacity: 100000, 2360 ChannelID: 3, 2361 }, 2362 2363 // One edge disabled, one edge enabled. 2364 { 2365 Node1: &testChannelEnd{ 2366 Alias: "a", 2367 testChannelPolicy: &testChannelPolicy{ 2368 LastUpdate: timestamp, 2369 Disabled: true, 2370 }, 2371 }, 2372 Node2: &testChannelEnd{ 2373 Alias: "b", 2374 testChannelPolicy: &testChannelPolicy{ 2375 LastUpdate: timestamp, 2376 Disabled: false, 2377 }, 2378 }, 2379 Capacity: 100000, 2380 ChannelID: 1, 2381 }, 2382 2383 // Both edges enabled. 2384 symmetricTestChannel("c", "d", 100000, &testChannelPolicy{ 2385 LastUpdate: timestamp, 2386 Disabled: false, 2387 }, 2), 2388 2389 // Both edges disabled, only one pruned. 2390 symmetricTestChannel("e", "f", 100000, &testChannelPolicy{ 2391 LastUpdate: timestamp, 2392 Disabled: true, 2393 }, 3), 2394 } 2395 2396 // We'll create our test graph and router backed with these test 2397 // channels we've created. 2398 testGraph, err := createTestGraphFromChannels( 2399 true, testChannels, "self", 2400 ) 2401 if err != nil { 2402 t.Fatalf("unable to create test graph: %v", err) 2403 } 2404 defer testGraph.cleanUp() 2405 2406 const startingHeight = 100 2407 ctx, cleanUp := createTestCtxFromGraphInstanceAssumeValid( 2408 t, startingHeight, testGraph, assumeValid, false, 2409 ) 2410 defer cleanUp() 2411 2412 // All the channels should exist within the graph before pruning them 2413 // when not using AssumeChannelValid, otherwise we should have pruned 2414 // the last channel on startup. 2415 if !assumeValid { 2416 assertChannelsPruned(t, ctx.graph, testChannels) 2417 } else { 2418 // Sleep to allow the pruning to finish. 2419 time.Sleep(200 * time.Millisecond) 2420 2421 prunedChannel := testChannels[len(testChannels)-1].ChannelID 2422 assertChannelsPruned(t, ctx.graph, testChannels, prunedChannel) 2423 } 2424 2425 if err := ctx.router.pruneZombieChans(); err != nil { 2426 t.Fatalf("unable to prune zombie channels: %v", err) 2427 } 2428 2429 // If we attempted to prune them without AssumeChannelValid being set, 2430 // none should be pruned. Otherwise the last channel should still be 2431 // pruned. 2432 if !assumeValid { 2433 assertChannelsPruned(t, ctx.graph, testChannels) 2434 } else { 2435 prunedChannel := testChannels[len(testChannels)-1].ChannelID 2436 assertChannelsPruned(t, ctx.graph, testChannels, prunedChannel) 2437 } 2438 } 2439 2440 // TestFindPathFeeWeighting tests that the findPath method will properly prefer 2441 // routes with lower fees over routes with lower time lock values. This is 2442 // meant to exercise the fact that the internal findPath method ranks edges 2443 // with the square of the total fee in order bias towards lower fees. 2444 func TestFindPathFeeWeighting(t *testing.T) { 2445 t.Parallel() 2446 2447 const startingBlockHeight = 101 2448 ctx, cleanUp := createTestCtxFromFile( 2449 t, startingBlockHeight, basicGraphFilePath, 2450 ) 2451 defer cleanUp() 2452 2453 var preImage [32]byte 2454 copy(preImage[:], bytes.Repeat([]byte{9}, 32)) 2455 2456 sourceNode, err := ctx.graph.SourceNode() 2457 if err != nil { 2458 t.Fatalf("unable to fetch source node: %v", err) 2459 } 2460 2461 amt := lnwire.MilliAtom(100) 2462 2463 target := ctx.aliases["luoji"] 2464 2465 // We'll now attempt a path finding attempt using this set up. Due to 2466 // the edge weighting, we should select the direct path over the 2 hop 2467 // path even though the direct path has a higher potential time lock. 2468 path, err := dbFindPath( 2469 ctx.graph, nil, &mockBandwidthHints{}, 2470 noRestrictions, 2471 testPathFindingConfig, 2472 sourceNode.PubKeyBytes, target, amt, 0, 2473 ) 2474 if err != nil { 2475 t.Fatalf("unable to find path: %v", err) 2476 } 2477 2478 // The route that was chosen should be exactly one hop, and should be 2479 // directly to luoji. 2480 if len(path) != 1 { 2481 t.Fatalf("expected path length of 1, instead was: %v", len(path)) 2482 } 2483 if path[0].ToNodePubKey() != ctx.aliases["luoji"] { 2484 t.Fatalf("wrong node: %v", path[0].ToNodePubKey()) 2485 } 2486 } 2487 2488 // TestIsStaleNode tests that the IsStaleNode method properly detects stale 2489 // node announcements. 2490 func TestIsStaleNode(t *testing.T) { 2491 t.Parallel() 2492 2493 const startingBlockHeight = 101 2494 ctx, cleanUp := createTestCtxSingleNode(t, startingBlockHeight) 2495 defer cleanUp() 2496 2497 // Before we can insert a node in to the database, we need to create a 2498 // channel that it's linked to. 2499 var ( 2500 pub1 [33]byte 2501 pub2 [33]byte 2502 ) 2503 copy(pub1[:], priv1.PubKey().SerializeCompressed()) 2504 copy(pub2[:], priv2.PubKey().SerializeCompressed()) 2505 2506 fundingTx, _, chanID, err := createChannelEdge(ctx, 2507 bitcoinKey1.SerializeCompressed(), 2508 bitcoinKey2.SerializeCompressed(), 2509 10000, 500) 2510 if err != nil { 2511 t.Fatalf("unable to create channel edge: %v", err) 2512 } 2513 fundingBlock := &wire.MsgBlock{ 2514 Transactions: []*wire.MsgTx{fundingTx}, 2515 } 2516 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 2517 2518 edge := &channeldb.ChannelEdgeInfo{ 2519 ChannelID: chanID.ToUint64(), 2520 NodeKey1Bytes: pub1, 2521 NodeKey2Bytes: pub2, 2522 DecredKey1Bytes: pub1, 2523 DecredKey2Bytes: pub2, 2524 AuthProof: nil, 2525 } 2526 if err := ctx.router.AddEdge(edge); err != nil { 2527 t.Fatalf("unable to add edge: %v", err) 2528 } 2529 2530 // Before we add the node, if we query for staleness, we should get 2531 // false, as we haven't added the full node. 2532 updateTimeStamp := time.Unix(123, 0) 2533 if ctx.router.IsStaleNode(pub1, updateTimeStamp) { 2534 t.Fatalf("incorrectly detected node as stale") 2535 } 2536 2537 // With the node stub in the database, we'll add the fully node 2538 // announcement to the database. 2539 n1 := &channeldb.LightningNode{ 2540 HaveNodeAnnouncement: true, 2541 LastUpdate: updateTimeStamp, 2542 Addresses: testAddrs, 2543 Color: color.RGBA{1, 2, 3, 0}, 2544 Alias: "node11", 2545 AuthSigBytes: testSig.Serialize(), 2546 Features: testFeatures, 2547 } 2548 copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed()) 2549 if err := ctx.router.AddNode(n1); err != nil { 2550 t.Fatalf("could not add node: %v", err) 2551 } 2552 2553 // If we use the same timestamp and query for staleness, we should get 2554 // true. 2555 if !ctx.router.IsStaleNode(pub1, updateTimeStamp) { 2556 t.Fatalf("failure to detect stale node update") 2557 } 2558 2559 // If we update the timestamp and once again query for staleness, it 2560 // should report false. 2561 newTimeStamp := time.Unix(1234, 0) 2562 if ctx.router.IsStaleNode(pub1, newTimeStamp) { 2563 t.Fatalf("incorrectly detected node as stale") 2564 } 2565 } 2566 2567 // TestIsKnownEdge tests that the IsKnownEdge method properly detects stale 2568 // channel announcements. 2569 func TestIsKnownEdge(t *testing.T) { 2570 t.Parallel() 2571 2572 const startingBlockHeight = 101 2573 ctx, cleanUp := createTestCtxSingleNode(t, startingBlockHeight) 2574 defer cleanUp() 2575 2576 // First, we'll create a new channel edge (just the info) and insert it 2577 // into the database. 2578 var ( 2579 pub1 [33]byte 2580 pub2 [33]byte 2581 ) 2582 copy(pub1[:], priv1.PubKey().SerializeCompressed()) 2583 copy(pub2[:], priv2.PubKey().SerializeCompressed()) 2584 2585 fundingTx, _, chanID, err := createChannelEdge(ctx, 2586 bitcoinKey1.SerializeCompressed(), 2587 bitcoinKey2.SerializeCompressed(), 2588 10000, 500) 2589 if err != nil { 2590 t.Fatalf("unable to create channel edge: %v", err) 2591 } 2592 fundingBlock := &wire.MsgBlock{ 2593 Transactions: []*wire.MsgTx{fundingTx}, 2594 } 2595 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 2596 2597 edge := &channeldb.ChannelEdgeInfo{ 2598 ChannelID: chanID.ToUint64(), 2599 NodeKey1Bytes: pub1, 2600 NodeKey2Bytes: pub2, 2601 DecredKey1Bytes: pub1, 2602 DecredKey2Bytes: pub2, 2603 AuthProof: nil, 2604 } 2605 if err := ctx.router.AddEdge(edge); err != nil { 2606 t.Fatalf("unable to add edge: %v", err) 2607 } 2608 2609 // Now that the edge has been inserted, query is the router already 2610 // knows of the edge should return true. 2611 if !ctx.router.IsKnownEdge(*chanID) { 2612 t.Fatalf("router should detect edge as known") 2613 } 2614 } 2615 2616 // TestIsStaleEdgePolicy tests that the IsStaleEdgePolicy properly detects 2617 // stale channel edge update announcements. 2618 func TestIsStaleEdgePolicy(t *testing.T) { 2619 t.Parallel() 2620 2621 const startingBlockHeight = 101 2622 ctx, cleanUp := createTestCtxFromFile( 2623 t, startingBlockHeight, basicGraphFilePath, 2624 ) 2625 defer cleanUp() 2626 2627 // First, we'll create a new channel edge (just the info) and insert it 2628 // into the database. 2629 var ( 2630 pub1 [33]byte 2631 pub2 [33]byte 2632 ) 2633 copy(pub1[:], priv1.PubKey().SerializeCompressed()) 2634 copy(pub2[:], priv2.PubKey().SerializeCompressed()) 2635 2636 fundingTx, _, chanID, err := createChannelEdge(ctx, 2637 bitcoinKey1.SerializeCompressed(), 2638 bitcoinKey2.SerializeCompressed(), 2639 10000, 500) 2640 if err != nil { 2641 t.Fatalf("unable to create channel edge: %v", err) 2642 } 2643 fundingBlock := &wire.MsgBlock{ 2644 Transactions: []*wire.MsgTx{fundingTx}, 2645 } 2646 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 2647 2648 // If we query for staleness before adding the edge, we should get 2649 // false. 2650 updateTimeStamp := time.Unix(123, 0) 2651 if ctx.router.IsStaleEdgePolicy(*chanID, updateTimeStamp, 0) { 2652 t.Fatalf("router failed to detect fresh edge policy") 2653 } 2654 if ctx.router.IsStaleEdgePolicy(*chanID, updateTimeStamp, 1) { 2655 t.Fatalf("router failed to detect fresh edge policy") 2656 } 2657 2658 edge := &channeldb.ChannelEdgeInfo{ 2659 ChannelID: chanID.ToUint64(), 2660 NodeKey1Bytes: pub1, 2661 NodeKey2Bytes: pub2, 2662 DecredKey1Bytes: pub1, 2663 DecredKey2Bytes: pub2, 2664 AuthProof: nil, 2665 } 2666 if err := ctx.router.AddEdge(edge); err != nil { 2667 t.Fatalf("unable to add edge: %v", err) 2668 } 2669 2670 // We'll also add two edge policies, one for each direction. 2671 edgePolicy := &channeldb.ChannelEdgePolicy{ 2672 SigBytes: testSig.Serialize(), 2673 ChannelID: edge.ChannelID, 2674 LastUpdate: updateTimeStamp, 2675 TimeLockDelta: 10, 2676 MinHTLC: 1, 2677 FeeBaseMAtoms: 10, 2678 FeeProportionalMillionths: 10000, 2679 } 2680 edgePolicy.ChannelFlags = 0 2681 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 2682 t.Fatalf("unable to update edge policy: %v", err) 2683 } 2684 2685 edgePolicy = &channeldb.ChannelEdgePolicy{ 2686 SigBytes: testSig.Serialize(), 2687 ChannelID: edge.ChannelID, 2688 LastUpdate: updateTimeStamp, 2689 TimeLockDelta: 10, 2690 MinHTLC: 1, 2691 FeeBaseMAtoms: 10, 2692 FeeProportionalMillionths: 10000, 2693 } 2694 edgePolicy.ChannelFlags = 1 2695 if err := ctx.router.UpdateEdge(edgePolicy); err != nil { 2696 t.Fatalf("unable to update edge policy: %v", err) 2697 } 2698 2699 // Now that the edges have been added, an identical (chanID, flag, 2700 // timestamp) tuple for each edge should be detected as a stale edge. 2701 if !ctx.router.IsStaleEdgePolicy(*chanID, updateTimeStamp, 0) { 2702 t.Fatalf("router failed to detect stale edge policy") 2703 } 2704 if !ctx.router.IsStaleEdgePolicy(*chanID, updateTimeStamp, 1) { 2705 t.Fatalf("router failed to detect stale edge policy") 2706 } 2707 2708 // If we now update the timestamp for both edges, the router should 2709 // detect that this tuple represents a fresh edge. 2710 updateTimeStamp = time.Unix(9999, 0) 2711 if ctx.router.IsStaleEdgePolicy(*chanID, updateTimeStamp, 0) { 2712 t.Fatalf("router failed to detect fresh edge policy") 2713 } 2714 if ctx.router.IsStaleEdgePolicy(*chanID, updateTimeStamp, 1) { 2715 t.Fatalf("router failed to detect fresh edge policy") 2716 } 2717 } 2718 2719 // TestEmptyRoutesGenerateSphinxPacket tests that the generateSphinxPacket 2720 // function is able to gracefully handle being passed a nil set of hops for the 2721 // route by the caller. 2722 func TestEmptyRoutesGenerateSphinxPacket(t *testing.T) { 2723 t.Parallel() 2724 2725 sessionKey, _ := secp256k1.GeneratePrivateKey() 2726 emptyRoute := &route.Route{} 2727 _, _, err := generateSphinxPacket(emptyRoute, testHash[:], sessionKey) 2728 if err != route.ErrNoRouteHopsProvided { 2729 t.Fatalf("expected empty hops error: instead got: %v", err) 2730 } 2731 } 2732 2733 // TestUnknownErrorSource tests that if the source of an error is unknown, all 2734 // edges along the route will be pruned. 2735 func TestUnknownErrorSource(t *testing.T) { 2736 t.Parallel() 2737 2738 // Setup a network. It contains two paths to c: a->b->c and an 2739 // alternative a->d->c. 2740 chanCapSat := dcrutil.Amount(100000) 2741 testChannels := []*testChannel{ 2742 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 2743 Expiry: 144, 2744 FeeRate: 400, 2745 MinHTLC: 1, 2746 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 2747 }, 1), 2748 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 2749 Expiry: 144, 2750 FeeRate: 400, 2751 MinHTLC: 1, 2752 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 2753 }, 3), 2754 symmetricTestChannel("a", "d", chanCapSat, &testChannelPolicy{ 2755 Expiry: 144, 2756 FeeRate: 400, 2757 FeeBaseMAtoms: 100000, 2758 MinHTLC: 1, 2759 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 2760 }, 2), 2761 symmetricTestChannel("d", "c", chanCapSat, &testChannelPolicy{ 2762 Expiry: 144, 2763 FeeRate: 400, 2764 FeeBaseMAtoms: 100000, 2765 MinHTLC: 1, 2766 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 2767 }, 4), 2768 } 2769 2770 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 2771 defer testGraph.cleanUp() 2772 if err != nil { 2773 t.Fatalf("unable to create graph: %v", err) 2774 } 2775 2776 const startingBlockHeight = 101 2777 ctx, cleanUp := createTestCtxFromGraphInstance( 2778 t, startingBlockHeight, testGraph, false, 2779 ) 2780 defer cleanUp() 2781 2782 // Create a payment to node c. 2783 var payHash lntypes.Hash 2784 payment := LightningPayment{ 2785 Target: ctx.aliases["c"], 2786 Amount: lnwire.NewMAtomsFromAtoms(1000), 2787 FeeLimit: noFeeLimit, 2788 paymentHash: &payHash, 2789 } 2790 2791 // We'll modify the SendToSwitch method so that it simulates hop b as a 2792 // node that returns an unparsable failure if approached via the a->b 2793 // channel. 2794 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 2795 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 2796 2797 // If channel a->b is used, return an error without 2798 // source and message. The sender won't know the origin 2799 // of the error. 2800 if firstHop.ToUint64() == 1 { 2801 return [32]byte{}, 2802 htlcswitch.ErrUnreadableFailureMessage 2803 } 2804 2805 // Otherwise the payment succeeds. 2806 return lntypes.Preimage{}, nil 2807 }) 2808 2809 // Send off the payment request to the router. The expectation is that 2810 // the route a->b->c is tried first. An unreadable faiure is returned 2811 // which should pruning the channel a->b. We expect the payment to 2812 // succeed via a->d. 2813 _, _, err = ctx.router.SendPayment(&payment) 2814 if err != nil { 2815 t.Fatalf("expected payment to succeed, but got: %v", err) 2816 } 2817 2818 // Next we modify payment result to return an unknown failure. 2819 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 2820 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 2821 2822 // If channel a->b is used, simulate that the failure 2823 // couldn't be decoded (FailureMessage is nil). 2824 if firstHop.ToUint64() == 2 { 2825 return [32]byte{}, 2826 htlcswitch.NewUnknownForwardingError(1) 2827 } 2828 2829 // Otherwise the payment succeeds. 2830 return lntypes.Preimage{}, nil 2831 }) 2832 2833 // Send off the payment request to the router. We expect the payment to 2834 // fail because both routes have been pruned. 2835 payHash = lntypes.Hash{1} 2836 payment.paymentHash = &payHash 2837 _, _, err = ctx.router.SendPayment(&payment) 2838 if err == nil { 2839 t.Fatalf("expected payment to fail") 2840 } 2841 } 2842 2843 // assertChannelsPruned ensures that only the given channels are pruned from the 2844 // graph out of the set of all channels. 2845 func assertChannelsPruned(t *testing.T, graph *channeldb.ChannelGraph, 2846 channels []*testChannel, prunedChanIDs ...uint64) { 2847 2848 t.Helper() 2849 2850 pruned := make(map[uint64]struct{}, len(channels)) 2851 for _, chanID := range prunedChanIDs { 2852 pruned[chanID] = struct{}{} 2853 } 2854 2855 for _, channel := range channels { 2856 _, shouldPrune := pruned[channel.ChannelID] 2857 _, _, exists, isZombie, err := graph.HasChannelEdge( 2858 channel.ChannelID, 2859 ) 2860 if err != nil { 2861 t.Fatalf("unable to determine existence of "+ 2862 "channel=%v in the graph: %v", 2863 channel.ChannelID, err) 2864 } 2865 if !shouldPrune && !exists { 2866 t.Fatalf("expected channel=%v to exist within "+ 2867 "the graph", channel.ChannelID) 2868 } 2869 if shouldPrune && exists { 2870 t.Fatalf("expected channel=%v to not exist "+ 2871 "within the graph", channel.ChannelID) 2872 } 2873 if !shouldPrune && isZombie { 2874 t.Fatalf("expected channel=%v to not be marked "+ 2875 "as zombie", channel.ChannelID) 2876 } 2877 if shouldPrune && !isZombie { 2878 t.Fatalf("expected channel=%v to be marked as "+ 2879 "zombie", channel.ChannelID) 2880 } 2881 } 2882 } 2883 2884 // TestSendToRouteStructuredError asserts that SendToRoute returns a structured 2885 // error. 2886 func TestSendToRouteStructuredError(t *testing.T) { 2887 t.Parallel() 2888 2889 // Setup a three node network. 2890 chanCapSat := dcrutil.Amount(100000) 2891 testChannels := []*testChannel{ 2892 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 2893 Expiry: 144, 2894 FeeRate: 400, 2895 MinHTLC: 1, 2896 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 2897 }, 1), 2898 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 2899 Expiry: 144, 2900 FeeRate: 400, 2901 MinHTLC: 1, 2902 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 2903 }, 2), 2904 } 2905 2906 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 2907 if err != nil { 2908 t.Fatalf("unable to create graph: %v", err) 2909 } 2910 defer testGraph.cleanUp() 2911 2912 const startingBlockHeight = 101 2913 ctx, cleanUp := createTestCtxFromGraphInstance( 2914 t, startingBlockHeight, testGraph, false, 2915 ) 2916 defer cleanUp() 2917 2918 // Set up an init channel for the control tower, such that we can make 2919 // sure the payment is initiated correctly. 2920 init := make(chan initArgs, 1) 2921 ctx.router.cfg.Control.(*mockControlTowerOld).init = init 2922 2923 // Setup a route from source a to destination c. The route will be used 2924 // in a call to SendToRoute. SendToRoute also applies channel updates, 2925 // but it saves us from including RequestRoute in the test scope too. 2926 const payAmt = lnwire.MilliAtom(10000) 2927 hop1 := ctx.aliases["b"] 2928 hop2 := ctx.aliases["c"] 2929 hops := []*route.Hop{ 2930 { 2931 ChannelID: 1, 2932 PubKeyBytes: hop1, 2933 AmtToForward: payAmt, 2934 LegacyPayload: true, 2935 }, 2936 { 2937 ChannelID: 2, 2938 PubKeyBytes: hop2, 2939 AmtToForward: payAmt, 2940 LegacyPayload: true, 2941 }, 2942 } 2943 2944 rt, err := route.NewRouteFromHops(payAmt, 100, ctx.aliases["a"], hops) 2945 if err != nil { 2946 t.Fatalf("unable to create route: %v", err) 2947 } 2948 2949 finalHopIndex := len(hops) 2950 testCases := map[int]lnwire.FailureMessage{ 2951 finalHopIndex: lnwire.NewFailIncorrectDetails(payAmt, 100), 2952 1: &lnwire.FailFeeInsufficient{ 2953 Update: lnwire.ChannelUpdate{}, 2954 }, 2955 } 2956 2957 for failIndex, errorType := range testCases { 2958 failIndex := failIndex 2959 errorType := errorType 2960 2961 t.Run(fmt.Sprintf("%T", errorType), func(t *testing.T) { 2962 // We'll modify the SendToSwitch method so that it 2963 // simulates a failed payment with an error originating 2964 // from the final hop in the route. 2965 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 2966 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 2967 return [32]byte{}, htlcswitch.NewForwardingError( 2968 errorType, failIndex, 2969 ) 2970 }, 2971 ) 2972 2973 // The payment parameter is mostly redundant in 2974 // SendToRoute. Can be left empty for this test. 2975 var payment lntypes.Hash 2976 2977 // Send off the payment request to the router. The 2978 // specified route should be attempted and the channel 2979 // update should be received by router and ignored 2980 // because it is missing a valid 2981 // signature. 2982 _, err = ctx.router.SendToRoute(payment, rt) 2983 2984 fErr, ok := err.(*htlcswitch.ForwardingError) 2985 require.True( 2986 t, ok, "expected forwarding error, got: %T", err, 2987 ) 2988 2989 require.IsType( 2990 t, errorType, fErr.WireMessage(), 2991 "expected type %T got %T", errorType, 2992 fErr.WireMessage(), 2993 ) 2994 2995 // Check that the correct values were used when 2996 // initiating the payment. 2997 select { 2998 case initVal := <-init: 2999 if initVal.c.Value != payAmt { 3000 t.Fatalf("expected %v, got %v", payAmt, 3001 initVal.c.Value) 3002 } 3003 case <-time.After(100 * time.Millisecond): 3004 t.Fatalf("initPayment not called") 3005 } 3006 }) 3007 } 3008 } 3009 3010 // TestSendToRouteMultiShardSend checks that a 3-shard payment can be executed 3011 // using SendToRoute. 3012 func TestSendToRouteMultiShardSend(t *testing.T) { 3013 t.Parallel() 3014 3015 ctx, cleanup := createTestCtxSingleNode(t, 0) 3016 defer cleanup() 3017 3018 const numShards = 3 3019 const payAmt = lnwire.MilliAtom(numShards * 10000) 3020 node, err := createTestNode() 3021 if err != nil { 3022 t.Fatal(err) 3023 } 3024 3025 // Create a simple 1-hop route that we will use for all three shards. 3026 hops := []*route.Hop{ 3027 { 3028 ChannelID: 1, 3029 PubKeyBytes: node.PubKeyBytes, 3030 AmtToForward: payAmt / numShards, 3031 MPP: record.NewMPP(payAmt, [32]byte{}), 3032 }, 3033 } 3034 3035 sourceNode, err := ctx.graph.SourceNode() 3036 if err != nil { 3037 t.Fatal(err) 3038 } 3039 3040 rt, err := route.NewRouteFromHops( 3041 payAmt, 100, sourceNode.PubKeyBytes, hops, 3042 ) 3043 if err != nil { 3044 t.Fatalf("unable to create route: %v", err) 3045 } 3046 3047 // The first shard we send we'll fail immediately, to check that we are 3048 // still allowed to retry with other shards after a failed one. 3049 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 3050 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 3051 return [32]byte{}, htlcswitch.NewForwardingError( 3052 &lnwire.FailFeeInsufficient{ 3053 Update: lnwire.ChannelUpdate{}, 3054 }, 1, 3055 ) 3056 }) 3057 3058 // The payment parameter is mostly redundant in SendToRoute. Can be left 3059 // empty for this test. 3060 var payment lntypes.Hash 3061 3062 // Send the shard using the created route, and expect an error to be 3063 // returned. 3064 _, err = ctx.router.SendToRoute(payment, rt) 3065 if err == nil { 3066 t.Fatalf("expected forwarding error") 3067 } 3068 3069 // Now we'll modify the SendToSwitch method again to wait until all 3070 // three shards are initiated before returning a result. We do this by 3071 // signalling when the method has been called, and then stop to wait 3072 // for the test to deliver the final result on the channel below. 3073 waitForResultSignal := make(chan struct{}, numShards) 3074 results := make(chan lntypes.Preimage, numShards) 3075 3076 ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcherOld).setPaymentResult( 3077 func(firstHop lnwire.ShortChannelID) ([32]byte, error) { 3078 3079 // Signal that the shard has been initiated and is 3080 // waiting for a result. 3081 waitForResultSignal <- struct{}{} 3082 3083 // Wait for a result before returning it. 3084 res, ok := <-results 3085 if !ok { 3086 return [32]byte{}, fmt.Errorf("failure") 3087 } 3088 return res, nil 3089 }) 3090 3091 // Launch three shards by calling SendToRoute in three goroutines, 3092 // returning their final error on the channel. 3093 errChan := make(chan error) 3094 successes := make(chan lntypes.Preimage) 3095 3096 for i := 0; i < numShards; i++ { 3097 go func() { 3098 attempt, err := ctx.router.SendToRoute(payment, rt) 3099 if err != nil { 3100 errChan <- err 3101 return 3102 } 3103 3104 successes <- attempt.Settle.Preimage 3105 }() 3106 } 3107 3108 // Wait for all shards to signal they have been initiated. 3109 for i := 0; i < numShards; i++ { 3110 select { 3111 case <-waitForResultSignal: 3112 case <-time.After(5 * time.Second): 3113 t.Fatalf("not waiting for results") 3114 } 3115 } 3116 3117 // Deliver a dummy preimage to all the shard handlers. 3118 preimage := lntypes.Preimage{} 3119 preimage[4] = 42 3120 for i := 0; i < numShards; i++ { 3121 results <- preimage 3122 } 3123 3124 // Finally expect all shards to return with the above preimage. 3125 for i := 0; i < numShards; i++ { 3126 select { 3127 case p := <-successes: 3128 if p != preimage { 3129 t.Fatalf("preimage mismatch") 3130 } 3131 case err := <-errChan: 3132 t.Fatalf("unexpected error from SendToRoute: %v", err) 3133 case <-time.After(5 * time.Second): 3134 t.Fatalf("result not received") 3135 } 3136 } 3137 } 3138 3139 // TestSendToRouteMaxHops asserts that SendToRoute fails when using a route that 3140 // exceeds the maximum number of hops. 3141 func TestSendToRouteMaxHops(t *testing.T) { 3142 t.Parallel() 3143 3144 // Setup a two node network. 3145 chanCapSat := dcrutil.Amount(100000) 3146 testChannels := []*testChannel{ 3147 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 3148 Expiry: 144, 3149 FeeRate: 400, 3150 MinHTLC: 1, 3151 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 3152 }, 1), 3153 } 3154 3155 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 3156 if err != nil { 3157 t.Fatalf("unable to create graph: %v", err) 3158 } 3159 defer testGraph.cleanUp() 3160 3161 const startingBlockHeight = 101 3162 3163 ctx, cleanUp := createTestCtxFromGraphInstance( 3164 t, startingBlockHeight, testGraph, false, 3165 ) 3166 defer cleanUp() 3167 3168 // Create a 30 hop route that exceeds the maximum hop limit. 3169 const payAmt = lnwire.MilliAtom(10000) 3170 hopA := ctx.aliases["a"] 3171 hopB := ctx.aliases["b"] 3172 3173 var hops []*route.Hop 3174 for i := 0; i < 15; i++ { 3175 hops = append(hops, &route.Hop{ 3176 ChannelID: 1, 3177 PubKeyBytes: hopB, 3178 AmtToForward: payAmt, 3179 LegacyPayload: true, 3180 }) 3181 3182 hops = append(hops, &route.Hop{ 3183 ChannelID: 1, 3184 PubKeyBytes: hopA, 3185 AmtToForward: payAmt, 3186 LegacyPayload: true, 3187 }) 3188 } 3189 3190 rt, err := route.NewRouteFromHops(payAmt, 100, ctx.aliases["a"], hops) 3191 if err != nil { 3192 t.Fatalf("unable to create route: %v", err) 3193 } 3194 3195 // Send off the payment request to the router. We expect an error back 3196 // indicating that the route is too long. 3197 var payment lntypes.Hash 3198 _, err = ctx.router.SendToRoute(payment, rt) 3199 if err != route.ErrMaxRouteHopsExceeded { 3200 t.Fatalf("expected ErrMaxRouteHopsExceeded, but got %v", err) 3201 } 3202 } 3203 3204 // TestBuildRoute tests whether correct routes are built. 3205 func TestBuildRoute(t *testing.T) { 3206 // Setup a three node network. 3207 chanCapSat := dcrutil.Amount(100000) 3208 paymentAddrFeatures := lnwire.NewFeatureVector( 3209 lnwire.NewRawFeatureVector(lnwire.PaymentAddrOptional), 3210 lnwire.Features, 3211 ) 3212 testChannels := []*testChannel{ 3213 // Create two local channels from a. The bandwidth is estimated 3214 // in this test as the channel capacity. For building routes, we 3215 // expected the channel with the largest estimated bandwidth to 3216 // be selected. 3217 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 3218 Expiry: 144, 3219 FeeRate: 20000, 3220 MinHTLC: lnwire.NewMAtomsFromAtoms(5), 3221 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 3222 }, 1), 3223 symmetricTestChannel("a", "b", chanCapSat/2, &testChannelPolicy{ 3224 Expiry: 144, 3225 FeeRate: 20000, 3226 MinHTLC: lnwire.NewMAtomsFromAtoms(5), 3227 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat / 2), 3228 }, 6), 3229 3230 // Create two channels from b to c. For building routes, we 3231 // expect the lowest cost channel to be selected. Note that this 3232 // isn't a situation that we are expecting in reality. Routing 3233 // nodes are recommended to keep their channel policies towards 3234 // the same peer identical. 3235 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 3236 Expiry: 144, 3237 FeeRate: 50000, 3238 MinHTLC: lnwire.NewMAtomsFromAtoms(20), 3239 MaxHTLC: lnwire.NewMAtomsFromAtoms(120), 3240 Features: paymentAddrFeatures, 3241 }, 2), 3242 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 3243 Expiry: 144, 3244 FeeRate: 60000, 3245 MinHTLC: lnwire.NewMAtomsFromAtoms(20), 3246 MaxHTLC: lnwire.NewMAtomsFromAtoms(120), 3247 Features: paymentAddrFeatures, 3248 }, 7), 3249 3250 symmetricTestChannel("a", "e", chanCapSat, &testChannelPolicy{ 3251 Expiry: 144, 3252 FeeRate: 80000, 3253 MinHTLC: lnwire.NewMAtomsFromAtoms(5), 3254 MaxHTLC: lnwire.NewMAtomsFromAtoms(10), 3255 Features: paymentAddrFeatures, 3256 }, 5), 3257 symmetricTestChannel("e", "c", chanCapSat, &testChannelPolicy{ 3258 Expiry: 144, 3259 FeeRate: 100000, 3260 MinHTLC: lnwire.NewMAtomsFromAtoms(20), 3261 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 3262 Features: paymentAddrFeatures, 3263 }, 4), 3264 } 3265 3266 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 3267 if err != nil { 3268 t.Fatalf("unable to create graph: %v", err) 3269 } 3270 defer testGraph.cleanUp() 3271 3272 const startingBlockHeight = 101 3273 3274 ctx, cleanUp := createTestCtxFromGraphInstance( 3275 t, startingBlockHeight, testGraph, false, 3276 ) 3277 defer cleanUp() 3278 3279 checkHops := func(rt *route.Route, expected []uint64, 3280 payAddr [32]byte) { 3281 3282 t.Helper() 3283 3284 if len(rt.Hops) != len(expected) { 3285 t.Fatal("hop count mismatch") 3286 } 3287 for i, hop := range rt.Hops { 3288 if hop.ChannelID != expected[i] { 3289 t.Fatalf("expected channel %v at pos %v, but "+ 3290 "got channel %v", 3291 expected[i], i, hop.ChannelID) 3292 } 3293 } 3294 3295 lastHop := rt.Hops[len(rt.Hops)-1] 3296 require.NotNil(t, lastHop.MPP) 3297 require.Equal(t, lastHop.MPP.PaymentAddr(), payAddr) 3298 } 3299 3300 var payAddr [32]byte 3301 _, err = rand.Read(payAddr[:]) 3302 require.NoError(t, err) 3303 3304 // Create hop list from the route node pubkeys. 3305 hops := []route.Vertex{ 3306 ctx.aliases["b"], ctx.aliases["c"], 3307 } 3308 amt := lnwire.NewMAtomsFromAtoms(100) 3309 3310 // Build the route for the given amount. 3311 rt, err := ctx.router.BuildRoute( 3312 &amt, hops, nil, 40, &payAddr, 3313 ) 3314 if err != nil { 3315 t.Fatal(err) 3316 } 3317 3318 // Check that we get the expected route back. The total amount should be 3319 // the amount to deliver to hop c (100 sats) plus the max fee for the 3320 // connection b->c (6 sats). 3321 checkHops(rt, []uint64{1, 7}, payAddr) 3322 if rt.TotalAmount != 106000 { 3323 t.Fatalf("unexpected total amount %v", rt.TotalAmount) 3324 } 3325 3326 // Build the route for the minimum amount. 3327 rt, err = ctx.router.BuildRoute( 3328 nil, hops, nil, 40, &payAddr, 3329 ) 3330 if err != nil { 3331 t.Fatal(err) 3332 } 3333 3334 // Check that we get the expected route back. The minimum that we can 3335 // send from b to c is 20 sats. Hop b charges 1200 msat for the 3336 // forwarding. The channel between hop a and b can carry amounts in the 3337 // range [5, 100], so 21200 msats is the minimum amount for this route. 3338 checkHops(rt, []uint64{1, 7}, payAddr) 3339 if rt.TotalAmount != 21200 { 3340 t.Fatalf("unexpected total amount %v", rt.TotalAmount) 3341 } 3342 3343 // Test a route that contains incompatible channel htlc constraints. 3344 // There is no amount that can pass through both channel 5 and 4. 3345 hops = []route.Vertex{ 3346 ctx.aliases["e"], ctx.aliases["c"], 3347 } 3348 _, err = ctx.router.BuildRoute( 3349 nil, hops, nil, 40, nil, 3350 ) 3351 errNoChannel, ok := err.(ErrNoChannel) 3352 if !ok { 3353 t.Fatalf("expected incompatible policies error, but got %v", 3354 err) 3355 } 3356 if errNoChannel.position != 0 { 3357 t.Fatalf("unexpected no channel error position") 3358 } 3359 if errNoChannel.fromNode != ctx.aliases["a"] { 3360 t.Fatalf("unexpected no channel error node") 3361 } 3362 } 3363 3364 // edgeCreationModifier is an enum-like type used to modify steps that are 3365 // skipped when creating a channel in the test context. 3366 type edgeCreationModifier uint8 3367 3368 const ( 3369 // edgeCreationNoFundingTx is used to skip adding the funding 3370 // transaction of an edge to the chain. 3371 edgeCreationNoFundingTx edgeCreationModifier = iota 3372 3373 // edgeCreationNoUTXO is used to skip adding the UTXO of a channel to 3374 // the UTXO set. 3375 edgeCreationNoUTXO 3376 3377 // edgeCreationBadScript is used to create the edge, but use the wrong 3378 // scrip which should cause it to fail output validation. 3379 edgeCreationBadScript 3380 ) 3381 3382 // newChannelEdgeInfo is a helper function used to create a new channel edge, 3383 // possibly skipping adding it to parts of the chain/state as well. 3384 func newChannelEdgeInfo(ctx *testCtx, fundingHeight uint32, 3385 ecm edgeCreationModifier) (*channeldb.ChannelEdgeInfo, error) { 3386 3387 node1, err := createTestNode() 3388 if err != nil { 3389 return nil, err 3390 } 3391 node2, err := createTestNode() 3392 if err != nil { 3393 return nil, err 3394 } 3395 3396 fundingTx, _, chanID, err := createChannelEdge( 3397 ctx, bitcoinKey1.SerializeCompressed(), 3398 bitcoinKey2.SerializeCompressed(), 100, fundingHeight, 3399 ) 3400 if err != nil { 3401 return nil, fmt.Errorf("unable to create edge: %w", err) 3402 } 3403 3404 edge := &channeldb.ChannelEdgeInfo{ 3405 ChannelID: chanID.ToUint64(), 3406 NodeKey1Bytes: node1.PubKeyBytes, 3407 NodeKey2Bytes: node2.PubKeyBytes, 3408 } 3409 copy(edge.DecredKey1Bytes[:], bitcoinKey1.SerializeCompressed()) 3410 copy(edge.DecredKey2Bytes[:], bitcoinKey2.SerializeCompressed()) 3411 3412 if ecm == edgeCreationNoFundingTx { 3413 return edge, nil 3414 } 3415 3416 fundingBlock := &wire.MsgBlock{ 3417 Transactions: []*wire.MsgTx{fundingTx}, 3418 } 3419 ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) 3420 3421 if ecm == edgeCreationNoUTXO { 3422 ctx.chain.delUtxo(wire.OutPoint{ 3423 Hash: fundingTx.TxHash(), 3424 }) 3425 } 3426 3427 if ecm == edgeCreationBadScript { 3428 fundingTx.TxOut[0].PkScript[0] ^= 1 3429 } 3430 3431 return edge, nil 3432 } 3433 3434 func assertChanChainRejection(t *testing.T, ctx *testCtx, 3435 edge *channeldb.ChannelEdgeInfo, failCode errorCode) { 3436 3437 t.Helper() 3438 3439 err := ctx.router.AddEdge(edge) 3440 if !IsError(err, failCode) { 3441 t.Fatalf("validation should have failed: %v", err) 3442 } 3443 3444 // This channel should now be present in the zombie channel index. 3445 _, _, _, isZombie, err := ctx.graph.HasChannelEdge( 3446 edge.ChannelID, 3447 ) 3448 require.Nil(t, err) 3449 require.True(t, isZombie, "edge should be marked as zombie") 3450 } 3451 3452 // TestChannelOnChainRejectionZombie tests that if we fail validating a channel 3453 // due to some sort of on-chain rejection (no funding transaction, or invalid 3454 // UTXO), then we'll mark the channel as a zombie. 3455 func TestChannelOnChainRejectionZombie(t *testing.T) { 3456 t.Parallel() 3457 3458 ctx, cleanup := createTestCtxSingleNode(t, 0) 3459 defer cleanup() 3460 3461 // To start, we'll make an edge for the channel, but we won't add the 3462 // funding transaction to the mock blockchain, which should cause the 3463 // validation to fail below. 3464 edge, err := newChannelEdgeInfo(ctx, 1, edgeCreationNoFundingTx) 3465 require.Nil(t, err) 3466 3467 // We expect this to fail as the transaction isn't present in the 3468 // chain (nor the block). 3469 assertChanChainRejection(t, ctx, edge, ErrNoFundingTransaction) 3470 3471 // Next, we'll make another channel edge, but actually add it to the 3472 // graph this time. 3473 edge, err = newChannelEdgeInfo(ctx, 2, edgeCreationNoUTXO) 3474 require.Nil(t, err) 3475 3476 // Instead now, we'll remove it from the set of UTXOs which should 3477 // cause the spentness validation to fail. 3478 assertChanChainRejection(t, ctx, edge, ErrChannelSpent) 3479 3480 // If we cause the funding transaction the chain to fail validation, we 3481 // should see similar behavior. 3482 edge, err = newChannelEdgeInfo(ctx, 3, edgeCreationBadScript) 3483 require.Nil(t, err) 3484 assertChanChainRejection(t, ctx, edge, ErrInvalidFundingOutput) 3485 } 3486 3487 func createDummyTestGraph(t *testing.T) *testGraphInstance { 3488 // Setup two simple channels such that we can mock sending along this 3489 // route. 3490 chanCapSat := dcrutil.Amount(100000) 3491 testChannels := []*testChannel{ 3492 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 3493 Expiry: 144, 3494 FeeRate: 400, 3495 MinHTLC: 1, 3496 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 3497 }, 1), 3498 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 3499 Expiry: 144, 3500 FeeRate: 400, 3501 MinHTLC: 1, 3502 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 3503 }, 2), 3504 } 3505 3506 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 3507 require.NoError(t, err, "failed to create graph") 3508 return testGraph 3509 } 3510 3511 func createDummyLightningPayment(t *testing.T, 3512 target route.Vertex, amt lnwire.MilliAtom) *LightningPayment { 3513 3514 var preImage lntypes.Preimage 3515 _, err := rand.Read(preImage[:]) 3516 require.NoError(t, err, "unable to generate preimage") 3517 3518 payHash := preImage.Hash() 3519 3520 return &LightningPayment{ 3521 Target: target, 3522 Amount: amt, 3523 FeeLimit: noFeeLimit, 3524 paymentHash: &payHash, 3525 } 3526 } 3527 3528 // TestSendMPPaymentSucceed tests that we can successfully send a MPPayment via 3529 // router.SendPayment. This test mainly focuses on testing the logic of the 3530 // method resumePayment is implemented as expected. 3531 func TestSendMPPaymentSucceed(t *testing.T) { 3532 const startingBlockHeight = 101 3533 3534 // Create mockers to initialize the router. 3535 controlTower := &mockControlTower{} 3536 sessionSource := &mockPaymentSessionSource{} 3537 missionControl := &mockMissionControl{} 3538 payer := &mockPaymentAttemptDispatcher{} 3539 chain := newMockChain(startingBlockHeight) 3540 chainView := newMockChainView(chain) 3541 testGraph := createDummyTestGraph(t) 3542 3543 // Define the behavior of the mockers to the point where we can 3544 // successfully start the router. 3545 controlTower.On("FetchInFlightPayments").Return( 3546 []*channeldb.MPPayment{}, nil, 3547 ) 3548 payer.On("CleanStore", mock.Anything).Return(nil) 3549 3550 // Create and start the router. 3551 router, err := New(Config{ 3552 Control: controlTower, 3553 SessionSource: sessionSource, 3554 MissionControl: missionControl, 3555 Payer: payer, 3556 3557 // TODO(yy): create new mocks for the chain and chainview. 3558 Chain: chain, 3559 ChainView: chainView, 3560 3561 // TODO(yy): mock the graph once it's changed into interface. 3562 Graph: testGraph.graph, 3563 3564 Clock: clock.NewTestClock(time.Unix(1, 0)), 3565 GraphPruneInterval: time.Hour * 2, 3566 NextPaymentID: func() (uint64, error) { 3567 next := atomic.AddUint64(&uniquePaymentID, 1) 3568 return next, nil 3569 }, 3570 }) 3571 require.NoError(t, err, "failed to create router") 3572 3573 // Make sure the router can start and stop without error. 3574 require.NoError(t, router.Start(), "router failed to start") 3575 defer func() { 3576 require.NoError(t, router.Stop(), "router failed to stop") 3577 }() 3578 3579 // Once the router is started, check that the mocked methods are called 3580 // as expected. 3581 controlTower.AssertExpectations(t) 3582 payer.AssertExpectations(t) 3583 3584 // Mock the methods to the point where we are inside the function 3585 // resumePayment. 3586 paymentAmt := lnwire.MilliAtom(10000) 3587 req := createDummyLightningPayment( 3588 t, testGraph.aliasMap["c"], paymentAmt, 3589 ) 3590 identifier := lntypes.Hash(req.Identifier()) 3591 session := &mockPaymentSession{} 3592 sessionSource.On("NewPaymentSession", req).Return(session, nil) 3593 controlTower.On("InitPayment", identifier, mock.Anything).Return(nil) 3594 3595 // The following mocked methods are called inside resumePayment. Note 3596 // that the payment object below will determine the state of the 3597 // paymentLifecycle. 3598 payment := &channeldb.MPPayment{} 3599 controlTower.On("FetchPayment", identifier).Return(payment, nil) 3600 3601 // Create a route that can send 1/4 of the total amount. This value 3602 // will be returned by calling RequestRoute. 3603 shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap) 3604 require.NoError(t, err, "failed to create route") 3605 session.On("RequestRoute", 3606 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 3607 ).Return(shard, nil) 3608 3609 // Make a new htlc attempt with zero fee and append it to the payment's 3610 // HTLCs when calling RegisterAttempt. 3611 activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0) 3612 controlTower.On("RegisterAttempt", 3613 identifier, mock.Anything, 3614 ).Return(nil).Run(func(args mock.Arguments) { 3615 payment.HTLCs = append(payment.HTLCs, activeAttempt) 3616 }) 3617 3618 // Create a buffered chan and it will be returned by GetPaymentResult. 3619 payer.resultChan = make(chan *htlcswitch.PaymentResult, 10) 3620 payer.On("GetPaymentResult", 3621 mock.Anything, identifier, mock.Anything, 3622 ).Run(func(args mock.Arguments) { 3623 // Before the mock method is returned, we send the result to 3624 // the read-only chan. 3625 payer.resultChan <- &htlcswitch.PaymentResult{} 3626 }) 3627 3628 // Simple mocking the rest. 3629 payer.On("SendHTLC", 3630 mock.Anything, mock.Anything, mock.Anything, 3631 ).Return(nil) 3632 missionControl.On("ReportPaymentSuccess", 3633 mock.Anything, mock.Anything, 3634 ).Return(nil) 3635 3636 // Mock SettleAttempt by changing one of the HTLCs to be settled. 3637 preimage := lntypes.Preimage{1, 2, 3} 3638 settledAttempt := makeSettledAttempt( 3639 int(paymentAmt/4), 0, preimage, 3640 ) 3641 controlTower.On("SettleAttempt", 3642 identifier, mock.Anything, mock.Anything, 3643 ).Return(&settledAttempt, nil).Run(func(args mock.Arguments) { 3644 // Whenever this method is invoked, we will mark the first 3645 // active attempt settled and exit. 3646 for i, attempt := range payment.HTLCs { 3647 if attempt.Settle == nil { 3648 attempt.Settle = &channeldb.HTLCSettleInfo{ 3649 Preimage: preimage, 3650 } 3651 payment.HTLCs[i] = attempt 3652 return 3653 } 3654 } 3655 }) 3656 3657 // Call the actual method SendPayment on router. This is place inside a 3658 // goroutine so we can set a timeout for the whole test, in case 3659 // anything goes wrong and the test never finishes. 3660 done := make(chan struct{}) 3661 var p lntypes.Hash 3662 go func() { 3663 p, _, err = router.SendPayment(req) 3664 close(done) 3665 }() 3666 3667 select { 3668 case <-done: 3669 case <-time.After(testTimeout): 3670 t.Fatalf("SendPayment didn't exit") 3671 } 3672 3673 // Finally, validate the returned values and check that the mock 3674 // methods are called as expected. 3675 require.NoError(t, err, "send payment failed") 3676 require.EqualValues(t, preimage, p, "preimage not match") 3677 3678 // Note that we also implicitly check the methods such as FailAttempt, 3679 // ReportPaymentFail, etc, are not called because we never mocked them 3680 // in this test. If any of the unexpected methods was called, the test 3681 // would fail. 3682 controlTower.AssertExpectations(t) 3683 payer.AssertExpectations(t) 3684 sessionSource.AssertExpectations(t) 3685 session.AssertExpectations(t) 3686 missionControl.AssertExpectations(t) 3687 } 3688 3689 // TestSendMPPaymentSucceedOnExtraShards tests that we need extra attempts if 3690 // there are failed ones,so that a payment is successfully sent. This test 3691 // mainly focuses on testing the logic of the method resumePayment is 3692 // implemented as expected. 3693 func TestSendMPPaymentSucceedOnExtraShards(t *testing.T) { 3694 const startingBlockHeight = 101 3695 3696 // Create mockers to initialize the router. 3697 controlTower := &mockControlTower{} 3698 sessionSource := &mockPaymentSessionSource{} 3699 missionControl := &mockMissionControl{} 3700 payer := &mockPaymentAttemptDispatcher{} 3701 chain := newMockChain(startingBlockHeight) 3702 chainView := newMockChainView(chain) 3703 testGraph := createDummyTestGraph(t) 3704 3705 // Define the behavior of the mockers to the point where we can 3706 // successfully start the router. 3707 controlTower.On("FetchInFlightPayments").Return( 3708 []*channeldb.MPPayment{}, nil, 3709 ) 3710 payer.On("CleanStore", mock.Anything).Return(nil) 3711 3712 // Create and start the router. 3713 router, err := New(Config{ 3714 Control: controlTower, 3715 SessionSource: sessionSource, 3716 MissionControl: missionControl, 3717 Payer: payer, 3718 3719 // TODO(yy): create new mocks for the chain and chainview. 3720 Chain: chain, 3721 ChainView: chainView, 3722 3723 // TODO(yy): mock the graph once it's changed into interface. 3724 Graph: testGraph.graph, 3725 3726 Clock: clock.NewTestClock(time.Unix(1, 0)), 3727 GraphPruneInterval: time.Hour * 2, 3728 NextPaymentID: func() (uint64, error) { 3729 next := atomic.AddUint64(&uniquePaymentID, 1) 3730 return next, nil 3731 }, 3732 }) 3733 require.NoError(t, err, "failed to create router") 3734 3735 // Make sure the router can start and stop without error. 3736 require.NoError(t, router.Start(), "router failed to start") 3737 defer func() { 3738 require.NoError(t, router.Stop(), "router failed to stop") 3739 }() 3740 3741 // Once the router is started, check that the mocked methods are called 3742 // as expected. 3743 controlTower.AssertExpectations(t) 3744 payer.AssertExpectations(t) 3745 3746 // Mock the methods to the point where we are inside the function 3747 // resumePayment. 3748 paymentAmt := lnwire.MilliAtom(20000) 3749 req := createDummyLightningPayment( 3750 t, testGraph.aliasMap["c"], paymentAmt, 3751 ) 3752 identifier := lntypes.Hash(req.Identifier()) 3753 session := &mockPaymentSession{} 3754 sessionSource.On("NewPaymentSession", req).Return(session, nil) 3755 controlTower.On("InitPayment", identifier, mock.Anything).Return(nil) 3756 3757 // The following mocked methods are called inside resumePayment. Note 3758 // that the payment object below will determine the state of the 3759 // paymentLifecycle. 3760 payment := &channeldb.MPPayment{} 3761 controlTower.On("FetchPayment", identifier).Return(payment, nil) 3762 3763 // Create a route that can send 1/4 of the total amount. This value 3764 // will be returned by calling RequestRoute. 3765 shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap) 3766 require.NoError(t, err, "failed to create route") 3767 session.On("RequestRoute", 3768 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 3769 ).Return(shard, nil) 3770 3771 // Make a new htlc attempt with zero fee and append it to the payment's 3772 // HTLCs when calling RegisterAttempt. 3773 activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0) 3774 controlTower.On("RegisterAttempt", 3775 identifier, mock.Anything, 3776 ).Return(nil).Run(func(args mock.Arguments) { 3777 payment.HTLCs = append(payment.HTLCs, activeAttempt) 3778 }) 3779 3780 // Create a buffered chan and it will be returned by GetPaymentResult. 3781 payer.resultChan = make(chan *htlcswitch.PaymentResult, 10) 3782 3783 // We use the failAttemptCount to track how many attempts we want to 3784 // fail. Each time the following mock method is called, the count gets 3785 // updated. 3786 failAttemptCount := 0 3787 payer.On("GetPaymentResult", 3788 mock.Anything, identifier, mock.Anything, 3789 ).Run(func(args mock.Arguments) { 3790 // Before the mock method is returned, we send the result to 3791 // the read-only chan. 3792 3793 // Update the counter. 3794 failAttemptCount++ 3795 3796 // We will make the first two attempts failed with temporary 3797 // error. 3798 if failAttemptCount <= 2 { 3799 payer.resultChan <- &htlcswitch.PaymentResult{ 3800 Error: htlcswitch.NewForwardingError( 3801 &lnwire.FailTemporaryChannelFailure{}, 3802 1, 3803 ), 3804 } 3805 return 3806 } 3807 3808 // Otherwise we will mark the attempt succeeded. 3809 payer.resultChan <- &htlcswitch.PaymentResult{} 3810 }) 3811 3812 // Mock the FailAttempt method to fail one of the attempts. 3813 var failedAttempt channeldb.HTLCAttempt 3814 controlTower.On("FailAttempt", 3815 identifier, mock.Anything, mock.Anything, 3816 ).Return(&failedAttempt, nil).Run(func(args mock.Arguments) { 3817 // Whenever this method is invoked, we will mark the first 3818 // active attempt as failed and exit. 3819 for i, attempt := range payment.HTLCs { 3820 if attempt.Settle != nil || attempt.Failure != nil { 3821 continue 3822 } 3823 3824 attempt.Failure = &channeldb.HTLCFailInfo{} 3825 failedAttempt = attempt 3826 payment.HTLCs[i] = attempt 3827 return 3828 } 3829 3830 }) 3831 3832 // Setup ReportPaymentFail to return nil reason and error so the 3833 // payment won't fail. 3834 missionControl.On("ReportPaymentFail", 3835 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 3836 ).Return(nil, nil) 3837 3838 // Simple mocking the rest. 3839 payer.On("SendHTLC", 3840 mock.Anything, mock.Anything, mock.Anything, 3841 ).Return(nil) 3842 missionControl.On("ReportPaymentSuccess", 3843 mock.Anything, mock.Anything, 3844 ).Return(nil) 3845 3846 // Mock SettleAttempt by changing one of the HTLCs to be settled. 3847 preimage := lntypes.Preimage{1, 2, 3} 3848 settledAttempt := makeSettledAttempt( 3849 int(paymentAmt/4), 0, preimage, 3850 ) 3851 controlTower.On("SettleAttempt", 3852 identifier, mock.Anything, mock.Anything, 3853 ).Return(&settledAttempt, nil).Run(func(args mock.Arguments) { 3854 // Whenever this method is invoked, we will mark the first 3855 // active attempt settled and exit. 3856 for i, attempt := range payment.HTLCs { 3857 if attempt.Settle != nil || attempt.Failure != nil { 3858 continue 3859 } 3860 3861 attempt.Settle = &channeldb.HTLCSettleInfo{ 3862 Preimage: preimage, 3863 } 3864 payment.HTLCs[i] = attempt 3865 return 3866 } 3867 }) 3868 3869 // Call the actual method SendPayment on router. This is place inside a 3870 // goroutine so we can set a timeout for the whole test, in case 3871 // anything goes wrong and the test never finishes. 3872 done := make(chan struct{}) 3873 var p lntypes.Hash 3874 go func() { 3875 p, _, err = router.SendPayment(req) 3876 close(done) 3877 }() 3878 3879 select { 3880 case <-done: 3881 case <-time.After(testTimeout): 3882 t.Fatalf("SendPayment didn't exit") 3883 } 3884 3885 // Finally, validate the returned values and check that the mock 3886 // methods are called as expected. 3887 require.NoError(t, err, "send payment failed") 3888 require.EqualValues(t, preimage, p, "preimage not match") 3889 3890 controlTower.AssertExpectations(t) 3891 payer.AssertExpectations(t) 3892 sessionSource.AssertExpectations(t) 3893 session.AssertExpectations(t) 3894 missionControl.AssertExpectations(t) 3895 } 3896 3897 // TestSendMPPaymentFailed tests that when one of the shard fails with a 3898 // terminal error, the router will stop attempting and the payment will fail. 3899 // This test mainly focuses on testing the logic of the method resumePayment 3900 // is implemented as expected. 3901 func TestSendMPPaymentFailed(t *testing.T) { 3902 const startingBlockHeight = 101 3903 3904 // Create mockers to initialize the router. 3905 controlTower := &mockControlTower{} 3906 sessionSource := &mockPaymentSessionSource{} 3907 missionControl := &mockMissionControl{} 3908 payer := &mockPaymentAttemptDispatcher{} 3909 chain := newMockChain(startingBlockHeight) 3910 chainView := newMockChainView(chain) 3911 testGraph := createDummyTestGraph(t) 3912 3913 // Define the behavior of the mockers to the point where we can 3914 // successfully start the router. 3915 controlTower.On("FetchInFlightPayments").Return( 3916 []*channeldb.MPPayment{}, nil, 3917 ) 3918 payer.On("CleanStore", mock.Anything).Return(nil) 3919 3920 // Create and start the router. 3921 router, err := New(Config{ 3922 Control: controlTower, 3923 SessionSource: sessionSource, 3924 MissionControl: missionControl, 3925 Payer: payer, 3926 3927 // TODO(yy): create new mocks for the chain and chainview. 3928 Chain: chain, 3929 ChainView: chainView, 3930 3931 // TODO(yy): mock the graph once it's changed into interface. 3932 Graph: testGraph.graph, 3933 3934 Clock: clock.NewTestClock(time.Unix(1, 0)), 3935 GraphPruneInterval: time.Hour * 2, 3936 NextPaymentID: func() (uint64, error) { 3937 next := atomic.AddUint64(&uniquePaymentID, 1) 3938 return next, nil 3939 }, 3940 }) 3941 require.NoError(t, err, "failed to create router") 3942 3943 // Make sure the router can start and stop without error. 3944 require.NoError(t, router.Start(), "router failed to start") 3945 defer func() { 3946 require.NoError(t, router.Stop(), "router failed to stop") 3947 }() 3948 3949 // Once the router is started, check that the mocked methods are called 3950 // as expected. 3951 controlTower.AssertExpectations(t) 3952 payer.AssertExpectations(t) 3953 3954 // Mock the methods to the point where we are inside the function 3955 // resumePayment. 3956 paymentAmt := lnwire.MilliAtom(10000) 3957 req := createDummyLightningPayment( 3958 t, testGraph.aliasMap["c"], paymentAmt, 3959 ) 3960 identifier := lntypes.Hash(req.Identifier()) 3961 session := &mockPaymentSession{} 3962 sessionSource.On("NewPaymentSession", req).Return(session, nil) 3963 controlTower.On("InitPayment", identifier, mock.Anything).Return(nil) 3964 3965 // The following mocked methods are called inside resumePayment. Note 3966 // that the payment object below will determine the state of the 3967 // paymentLifecycle. 3968 payment := &channeldb.MPPayment{} 3969 controlTower.On("FetchPayment", identifier).Return(payment, nil) 3970 3971 // Create a route that can send 1/4 of the total amount. This value 3972 // will be returned by calling RequestRoute. 3973 shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap) 3974 require.NoError(t, err, "failed to create route") 3975 session.On("RequestRoute", 3976 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 3977 ).Return(shard, nil) 3978 3979 // Make a new htlc attempt with zero fee and append it to the payment's 3980 // HTLCs when calling RegisterAttempt. 3981 activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0) 3982 controlTower.On("RegisterAttempt", 3983 identifier, mock.Anything, 3984 ).Return(nil).Run(func(args mock.Arguments) { 3985 payment.HTLCs = append(payment.HTLCs, activeAttempt) 3986 }) 3987 3988 // Create a buffered chan and it will be returned by GetPaymentResult. 3989 payer.resultChan = make(chan *htlcswitch.PaymentResult, 10) 3990 3991 // We use the failAttemptCount to track how many attempts we want to 3992 // fail. Each time the following mock method is called, the count gets 3993 // updated. 3994 failAttemptCount := 0 3995 payer.On("GetPaymentResult", 3996 mock.Anything, identifier, mock.Anything, 3997 ).Run(func(args mock.Arguments) { 3998 // Before the mock method is returned, we send the result to 3999 // the read-only chan. 4000 4001 // Update the counter. 4002 failAttemptCount++ 4003 4004 // We fail the first attempt with terminal error. 4005 if failAttemptCount == 1 { 4006 payer.resultChan <- &htlcswitch.PaymentResult{ 4007 Error: htlcswitch.NewForwardingError( 4008 &lnwire.FailIncorrectDetails{}, 4009 1, 4010 ), 4011 } 4012 return 4013 4014 } 4015 4016 // We will make the rest attempts failed with temporary error. 4017 payer.resultChan <- &htlcswitch.PaymentResult{ 4018 Error: htlcswitch.NewForwardingError( 4019 &lnwire.FailTemporaryChannelFailure{}, 4020 1, 4021 ), 4022 } 4023 }) 4024 4025 // Mock the FailAttempt method to fail one of the attempts. 4026 var failedAttempt channeldb.HTLCAttempt 4027 controlTower.On("FailAttempt", 4028 identifier, mock.Anything, mock.Anything, 4029 ).Return(&failedAttempt, nil).Run(func(args mock.Arguments) { 4030 // Whenever this method is invoked, we will mark the first 4031 // active attempt as failed and exit. 4032 for i, attempt := range payment.HTLCs { 4033 if attempt.Settle != nil || attempt.Failure != nil { 4034 continue 4035 } 4036 4037 attempt.Failure = &channeldb.HTLCFailInfo{} 4038 failedAttempt = attempt 4039 payment.HTLCs[i] = attempt 4040 return 4041 } 4042 4043 }) 4044 4045 // Setup ReportPaymentFail to return nil reason and error so the 4046 // payment won't fail. 4047 var called bool 4048 failureReason := channeldb.FailureReasonPaymentDetails 4049 missionControl.On("ReportPaymentFail", 4050 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 4051 ).Return(&failureReason, nil).Run(func(args mock.Arguments) { 4052 // We only return the terminal error once, thus when the method 4053 // is called, we will return it with a nil error. 4054 if called { 4055 args[0] = nil 4056 return 4057 } 4058 4059 // If it's the first time calling this method, we will return a 4060 // terminal error. 4061 payment.FailureReason = &failureReason 4062 called = true 4063 }) 4064 4065 // Simple mocking the rest. 4066 controlTower.On("Fail", identifier, failureReason).Return(nil) 4067 payer.On("SendHTLC", 4068 mock.Anything, mock.Anything, mock.Anything, 4069 ).Return(nil) 4070 4071 // Call the actual method SendPayment on router. This is place inside a 4072 // goroutine so we can set a timeout for the whole test, in case 4073 // anything goes wrong and the test never finishes. 4074 done := make(chan struct{}) 4075 var p lntypes.Hash 4076 go func() { 4077 p, _, err = router.SendPayment(req) 4078 close(done) 4079 }() 4080 4081 select { 4082 case <-done: 4083 case <-time.After(testTimeout): 4084 t.Fatalf("SendPayment didn't exit") 4085 } 4086 4087 // Finally, validate the returned values and check that the mock 4088 // methods are called as expected. 4089 require.Error(t, err, "expected send payment error") 4090 require.EqualValues(t, [32]byte{}, p, "preimage not match") 4091 4092 controlTower.AssertExpectations(t) 4093 payer.AssertExpectations(t) 4094 sessionSource.AssertExpectations(t) 4095 session.AssertExpectations(t) 4096 missionControl.AssertExpectations(t) 4097 } 4098 4099 // TestSendMPPaymentFailedWithShardsInFlight tests that when the payment is in 4100 // terminal state, even if we have shards in flight, we still fail the payment 4101 // and exit. This test mainly focuses on testing the logic of the method 4102 // resumePayment is implemented as expected. 4103 func TestSendMPPaymentFailedWithShardsInFlight(t *testing.T) { 4104 const startingBlockHeight = 101 4105 4106 // Create mockers to initialize the router. 4107 controlTower := &mockControlTower{} 4108 sessionSource := &mockPaymentSessionSource{} 4109 missionControl := &mockMissionControl{} 4110 payer := &mockPaymentAttemptDispatcher{} 4111 chain := newMockChain(startingBlockHeight) 4112 chainView := newMockChainView(chain) 4113 testGraph := createDummyTestGraph(t) 4114 4115 // Define the behavior of the mockers to the point where we can 4116 // successfully start the router. 4117 controlTower.On("FetchInFlightPayments").Return( 4118 []*channeldb.MPPayment{}, nil, 4119 ) 4120 payer.On("CleanStore", mock.Anything).Return(nil) 4121 4122 // Create and start the router. 4123 router, err := New(Config{ 4124 Control: controlTower, 4125 SessionSource: sessionSource, 4126 MissionControl: missionControl, 4127 Payer: payer, 4128 4129 // TODO(yy): create new mocks for the chain and chainview. 4130 Chain: chain, 4131 ChainView: chainView, 4132 4133 // TODO(yy): mock the graph once it's changed into interface. 4134 Graph: testGraph.graph, 4135 4136 Clock: clock.NewTestClock(time.Unix(1, 0)), 4137 GraphPruneInterval: time.Hour * 2, 4138 NextPaymentID: func() (uint64, error) { 4139 next := atomic.AddUint64(&uniquePaymentID, 1) 4140 return next, nil 4141 }, 4142 }) 4143 require.NoError(t, err, "failed to create router") 4144 4145 // Make sure the router can start and stop without error. 4146 require.NoError(t, router.Start(), "router failed to start") 4147 defer func() { 4148 require.NoError(t, router.Stop(), "router failed to stop") 4149 }() 4150 4151 // Once the router is started, check that the mocked methods are called 4152 // as expected. 4153 controlTower.AssertExpectations(t) 4154 payer.AssertExpectations(t) 4155 4156 // Mock the methods to the point where we are inside the function 4157 // resumePayment. 4158 paymentAmt := lnwire.MilliAtom(10000) 4159 req := createDummyLightningPayment( 4160 t, testGraph.aliasMap["c"], paymentAmt, 4161 ) 4162 identifier := lntypes.Hash(req.Identifier()) 4163 session := &mockPaymentSession{} 4164 sessionSource.On("NewPaymentSession", req).Return(session, nil) 4165 controlTower.On("InitPayment", identifier, mock.Anything).Return(nil) 4166 4167 // The following mocked methods are called inside resumePayment. Note 4168 // that the payment object below will determine the state of the 4169 // paymentLifecycle. 4170 payment := &channeldb.MPPayment{} 4171 controlTower.On("FetchPayment", identifier).Return(payment, nil) 4172 4173 // Create a route that can send 1/4 of the total amount. This value 4174 // will be returned by calling RequestRoute. 4175 shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap) 4176 require.NoError(t, err, "failed to create route") 4177 session.On("RequestRoute", 4178 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 4179 ).Return(shard, nil) 4180 4181 // Make a new htlc attempt with zero fee and append it to the payment's 4182 // HTLCs when calling RegisterAttempt. 4183 activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0) 4184 controlTower.On("RegisterAttempt", 4185 identifier, mock.Anything, 4186 ).Return(nil).Run(func(args mock.Arguments) { 4187 payment.HTLCs = append(payment.HTLCs, activeAttempt) 4188 }) 4189 4190 // Create a buffered chan and it will be returned by GetPaymentResult. 4191 payer.resultChan = make(chan *htlcswitch.PaymentResult, 10) 4192 4193 // We use the getPaymentResultCnt to track how many times we called 4194 // GetPaymentResult. As shard launch is sequential, and we fail the 4195 // first shard that calls GetPaymentResult, we may end up with different 4196 // counts since the lifecycle itself is asynchronous. To avoid flakes 4197 // due to this undeterminsitic behavior, we'll compare the final 4198 // getPaymentResultCnt with other counters to create a final test 4199 // expectation. 4200 getPaymentResultCnt := 0 4201 payer.On("GetPaymentResult", 4202 mock.Anything, identifier, mock.Anything, 4203 ).Run(func(args mock.Arguments) { 4204 // Before the mock method is returned, we send the result to 4205 // the read-only chan. 4206 4207 // Update the counter. 4208 getPaymentResultCnt++ 4209 4210 // We fail the first attempt with terminal error. 4211 if getPaymentResultCnt == 1 { 4212 payer.resultChan <- &htlcswitch.PaymentResult{ 4213 Error: htlcswitch.NewForwardingError( 4214 &lnwire.FailIncorrectDetails{}, 4215 1, 4216 ), 4217 } 4218 return 4219 } 4220 4221 // For the rest of the attempts we'll simulate that a network 4222 // result update_fail_htlc has been received. This way the 4223 // payment will fail cleanly. 4224 payer.resultChan <- &htlcswitch.PaymentResult{ 4225 Error: htlcswitch.NewForwardingError( 4226 &lnwire.FailTemporaryChannelFailure{}, 4227 1, 4228 ), 4229 } 4230 }) 4231 4232 // Mock the FailAttempt method to fail (at least once). 4233 var failedAttempt channeldb.HTLCAttempt 4234 controlTower.On("FailAttempt", 4235 identifier, mock.Anything, mock.Anything, 4236 ).Return(&failedAttempt, nil).Run(func(args mock.Arguments) { 4237 // Whenever this method is invoked, we will mark the first 4238 // active attempt as failed and exit. 4239 failedAttempt = payment.HTLCs[0] 4240 failedAttempt.Failure = &channeldb.HTLCFailInfo{} 4241 payment.HTLCs[0] = failedAttempt 4242 }) 4243 4244 // Setup ReportPaymentFail to return nil reason and error so the 4245 // payment won't fail. 4246 failureReason := channeldb.FailureReasonPaymentDetails 4247 cntReportPaymentFail := 0 4248 missionControl.On("ReportPaymentFail", 4249 mock.Anything, mock.Anything, mock.Anything, mock.Anything, 4250 ).Return(&failureReason, nil).Run(func(args mock.Arguments) { 4251 payment.FailureReason = &failureReason 4252 cntReportPaymentFail++ 4253 }) 4254 4255 // Simple mocking the rest. 4256 cntFail := 0 4257 controlTower.On("Fail", identifier, failureReason).Return(nil) 4258 payer.On("SendHTLC", 4259 mock.Anything, mock.Anything, mock.Anything, 4260 ).Return(nil).Run(func(args mock.Arguments) { 4261 cntFail++ 4262 }) 4263 4264 // Call the actual method SendPayment on router. This is place inside a 4265 // goroutine so we can set a timeout for the whole test, in case 4266 // anything goes wrong and the test never finishes. 4267 done := make(chan struct{}) 4268 var p lntypes.Hash 4269 go func() { 4270 p, _, err = router.SendPayment(req) 4271 close(done) 4272 }() 4273 4274 select { 4275 case <-done: 4276 case <-time.After(testTimeout): 4277 t.Fatalf("SendPayment didn't exit") 4278 } 4279 4280 // Finally, validate the returned values and check that the mock 4281 // methods are called as expected. 4282 require.Error(t, err, "expected send payment error") 4283 require.EqualValues(t, [32]byte{}, p, "preimage not match") 4284 require.GreaterOrEqual(t, getPaymentResultCnt, 1) 4285 require.Equal(t, getPaymentResultCnt, cntReportPaymentFail) 4286 require.Equal(t, getPaymentResultCnt, cntFail) 4287 4288 controlTower.AssertExpectations(t) 4289 payer.AssertExpectations(t) 4290 sessionSource.AssertExpectations(t) 4291 session.AssertExpectations(t) 4292 missionControl.AssertExpectations(t) 4293 } 4294 4295 // TestBlockDifferenceFix tests if when the router is behind on blocks, the 4296 // router catches up to the best block head. 4297 func TestBlockDifferenceFix(t *testing.T) { 4298 t.Parallel() 4299 4300 initialBlockHeight := uint32(0) 4301 4302 // Starting height here is set to 0, which is behind where we want to be. 4303 ctx, cleanup := createTestCtxSingleNode(t, initialBlockHeight) 4304 defer cleanup() 4305 4306 // Add initial block to our mini blockchain. 4307 block := &wire.MsgBlock{ 4308 Transactions: []*wire.MsgTx{}, 4309 } 4310 ctx.chain.addBlock(block, initialBlockHeight, rand.Uint32()) 4311 4312 // Let's generate a new block of height 5, 5 above where our node is at. 4313 newBlock := &wire.MsgBlock{ 4314 Transactions: []*wire.MsgTx{}, 4315 } 4316 newBlockHeight := uint32(5) 4317 4318 blockDifference := newBlockHeight - initialBlockHeight 4319 4320 ctx.chainView.notifyBlockAck = make(chan struct{}, 1) 4321 4322 ctx.chain.addBlock(newBlock, newBlockHeight, rand.Uint32()) 4323 ctx.chain.setBestBlock(int32(newBlockHeight)) 4324 ctx.chainView.notifyBlock(block.BlockHash(), newBlockHeight, 4325 []*wire.MsgTx{}, t) 4326 4327 <-ctx.chainView.notifyBlockAck 4328 4329 // At this point, the chain notifier should have noticed that we're 4330 // behind on blocks, and will send the n missing blocks that we 4331 // need to the client's epochs channel. Let's replicate this 4332 // functionality. 4333 for i := 0; i < int(blockDifference); i++ { 4334 currBlockHeight := int32(i + 1) 4335 4336 nonce := rand.Uint32() 4337 4338 newBlock := &wire.MsgBlock{ 4339 Transactions: []*wire.MsgTx{}, 4340 Header: wire.BlockHeader{Nonce: nonce}, 4341 } 4342 ctx.chain.addBlock(newBlock, uint32(currBlockHeight), nonce) 4343 currHash := newBlock.Header.BlockHash() 4344 4345 newEpoch := &chainntnfs.BlockEpoch{ 4346 Height: currBlockHeight, 4347 Hash: &currHash, 4348 } 4349 4350 ctx.notifier.EpochChan <- newEpoch 4351 4352 ctx.chainView.notifyBlock(currHash, 4353 uint32(currBlockHeight), block.Transactions, t) 4354 4355 <-ctx.chainView.notifyBlockAck 4356 } 4357 4358 err := wait.NoError(func() error { 4359 // Then router height should be updated to the latest block. 4360 if atomic.LoadUint32(&ctx.router.bestHeight) != newBlockHeight { 4361 return fmt.Errorf("height should have been updated "+ 4362 "to %v, instead got %v", newBlockHeight, 4363 ctx.router.bestHeight) 4364 } 4365 4366 return nil 4367 }, testTimeout) 4368 if err != nil { 4369 t.Fatalf("block height wasn't updated: %v", err) 4370 } 4371 }