github.com/decred/dcrlnd@v0.7.6/htlcswitch/circuit_test.go (about) 1 package htlcswitch_test 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "reflect" 7 "testing" 8 9 "github.com/decred/dcrd/chaincfg/v3" 10 "github.com/decred/dcrd/dcrec/secp256k1/v4" 11 "github.com/decred/dcrd/dcrutil/v4" 12 "github.com/decred/dcrlnd/channeldb" 13 "github.com/decred/dcrlnd/htlcswitch" 14 "github.com/decred/dcrlnd/htlcswitch/hop" 15 "github.com/decred/dcrlnd/keychain" 16 "github.com/decred/dcrlnd/lnwire" 17 sphinx "github.com/decred/lightning-onion/v4" 18 ) 19 20 var ( 21 hash1 = [32]byte{0x01} 22 hash2 = [32]byte{0x02} 23 hash3 = [32]byte{0x03} 24 25 // sphinxPrivKey is the private key given to freshly created sphinx 26 // routers. 27 sphinxPrivKey *secp256k1.PrivateKey 28 29 // testEphemeralKey is the ephemeral key that will be extracted to 30 // create onion obfuscators. 31 testEphemeralKey *secp256k1.PublicKey 32 33 // testExtracter is a precomputed extraction of testEphemeralKey, using 34 // the sphinxPrivKey. 35 testExtracter *hop.SphinxErrorEncrypter 36 ) 37 38 func init() { 39 // Generate a fresh key for our sphinx router. 40 var err error 41 sphinxPrivKey, err = secp256k1.GeneratePrivateKey() 42 if err != nil { 43 panic(err) 44 } 45 46 // And another, whose public key will serve as the test ephemeral key. 47 testEphemeralPriv, err := secp256k1.GeneratePrivateKey() 48 if err != nil { 49 panic(err) 50 } 51 testEphemeralKey = testEphemeralPriv.PubKey() 52 53 // Finally, properly initialize the test extracter 54 initTestExtracter() 55 } 56 57 // initTestExtracter spins up a new onion processor specifically for the purpose 58 // of generating our testExtracter, which should be derived from the 59 // testEphemeralKey, and which randomly-generated key is used to init the sphinx 60 // router. 61 // 62 // NOTE: This should be called in init(), after testEphemeralKey has been 63 // properly initialized. 64 func initTestExtracter() { 65 onionProcessor := newOnionProcessor(nil) 66 defer onionProcessor.Stop() 67 68 obfuscator, _ := onionProcessor.ExtractErrorEncrypter( 69 testEphemeralKey, 70 ) 71 72 sphinxExtracter, ok := obfuscator.(*hop.SphinxErrorEncrypter) 73 if !ok { 74 panic("did not extract sphinx error encrypter") 75 } 76 77 testExtracter = sphinxExtracter 78 79 // We also set this error extracter on startup, otherwise it will be nil 80 // at compile-time. 81 halfCircuitTests[2].encrypter = testExtracter 82 } 83 84 // newOnionProcessor creates starts a new htlcswitch.OnionProcessor using a temp 85 // db and no garbage collection. 86 func newOnionProcessor(t *testing.T) *hop.OnionProcessor { 87 sphinxRouter := sphinx.NewRouter( 88 &keychain.PrivKeyECDH{PrivKey: sphinxPrivKey}, 89 chaincfg.SimNetParams(), 90 sphinx.NewMemoryReplayLog(), 91 ) 92 93 if err := sphinxRouter.Start(); err != nil { 94 t.Fatalf("unable to start sphinx router: %v", err) 95 } 96 97 return hop.NewOnionProcessor(sphinxRouter) 98 } 99 100 // newCircuitMap creates a new htlcswitch.CircuitMap using a temp db and a 101 // fresh sphinx router. 102 func newCircuitMap(t *testing.T) (*htlcswitch.CircuitMapConfig, 103 htlcswitch.CircuitMap) { 104 105 onionProcessor := newOnionProcessor(t) 106 107 db := makeCircuitDB(t, "") 108 circuitMapCfg := &htlcswitch.CircuitMapConfig{ 109 DB: db, 110 FetchAllOpenChannels: db.ChannelStateDB().FetchAllOpenChannels, 111 FetchClosedChannels: db.ChannelStateDB().FetchClosedChannels, 112 ExtractErrorEncrypter: onionProcessor.ExtractErrorEncrypter, 113 } 114 115 circuitMap, err := htlcswitch.NewCircuitMap(circuitMapCfg) 116 if err != nil { 117 t.Fatalf("unable to create persistent circuit map: %v", err) 118 } 119 120 return circuitMapCfg, circuitMap 121 } 122 123 // TestCircuitMapInit is a quick check to ensure that we can start and restore 124 // the circuit map, as this will be used extensively in this suite. 125 func TestCircuitMapInit(t *testing.T) { 126 t.Parallel() 127 128 cfg, _ := newCircuitMap(t) 129 restartCircuitMap(t, cfg) 130 } 131 132 var halfCircuitTests = []struct { 133 hash [32]byte 134 inValue dcrutil.Amount 135 outValue dcrutil.Amount 136 chanID lnwire.ShortChannelID 137 htlcID uint64 138 encrypter hop.ErrorEncrypter 139 }{ 140 { 141 hash: hash1, 142 inValue: 0, 143 outValue: 1000, 144 chanID: lnwire.NewShortChanIDFromInt(1), 145 htlcID: 1, 146 encrypter: nil, 147 }, 148 { 149 hash: hash2, 150 inValue: 2100, 151 outValue: 2000, 152 chanID: lnwire.NewShortChanIDFromInt(2), 153 htlcID: 2, 154 encrypter: htlcswitch.NewMockObfuscator(), 155 }, 156 { 157 hash: hash3, 158 inValue: 10000, 159 outValue: 9000, 160 chanID: lnwire.NewShortChanIDFromInt(3), 161 htlcID: 3, 162 // NOTE: The value of testExtracter is nil at compile-time, it 163 // is fully-initialized in initTestExtracter, which should 164 // repopulate this encrypter. 165 encrypter: testExtracter, 166 }, 167 } 168 169 // TestHalfCircuitSerialization checks that the half circuits can be properly 170 // encoded and decoded properly. A critical responsibility of this test is to 171 // verify that the various ErrorEncrypter implementations can be properly 172 // reconstructed from a serialized half circuit. 173 func TestHalfCircuitSerialization(t *testing.T) { 174 t.Parallel() 175 176 onionProcessor := newOnionProcessor(t) 177 178 for i, test := range halfCircuitTests { 179 circuit := &htlcswitch.PaymentCircuit{ 180 PaymentHash: test.hash, 181 IncomingAmount: lnwire.NewMAtomsFromAtoms(test.inValue), 182 OutgoingAmount: lnwire.NewMAtomsFromAtoms(test.outValue), 183 Incoming: htlcswitch.CircuitKey{ 184 ChanID: test.chanID, 185 HtlcID: test.htlcID, 186 }, 187 ErrorEncrypter: test.encrypter, 188 } 189 190 // Write the half circuit to our buffer. 191 var b bytes.Buffer 192 if err := circuit.Encode(&b); err != nil { 193 t.Fatalf("unable to encode half payment circuit test=%d: %v", i, err) 194 } 195 196 // Then try to decode the serialized bytes. 197 var circuit2 htlcswitch.PaymentCircuit 198 circuitReader := bytes.NewReader(b.Bytes()) 199 if err := circuit2.Decode(circuitReader); err != nil { 200 t.Fatalf("unable to decode half payment circuit test=%d: %v", i, err) 201 } 202 203 // If the error encrypter is initialized, we will need to 204 // reextract it from it's decoded state, as this requires an 205 // ECDH with the onion processor's private key. For mock error 206 // encrypters, this will be a NOP. 207 if circuit2.ErrorEncrypter != nil { 208 err := circuit2.ErrorEncrypter.Reextract( 209 onionProcessor.ExtractErrorEncrypter, 210 ) 211 if err != nil { 212 t.Fatalf("unable to reextract sphinx error "+ 213 "encrypter: %v", err) 214 } 215 } 216 217 // Reconstructed half circuit should match the original. 218 if !equalIgnoreLFD(circuit, &circuit2) { 219 t.Fatalf("unexpected half circuit test=%d, want %v, got %v", 220 i, circuit, circuit2) 221 } 222 } 223 } 224 225 func TestCircuitMapPersistence(t *testing.T) { 226 t.Parallel() 227 228 var ( 229 chan1 = lnwire.NewShortChanIDFromInt(1) 230 chan2 = lnwire.NewShortChanIDFromInt(2) 231 circuitMap htlcswitch.CircuitMap 232 err error 233 ) 234 235 cfg, circuitMap := newCircuitMap(t) 236 237 circuit := circuitMap.LookupCircuit(htlcswitch.CircuitKey{ 238 ChanID: chan1, 239 HtlcID: 0, 240 }) 241 if circuit != nil { 242 t.Fatalf("LookupByHTLC returned a circuit before any were added: %v", 243 circuit) 244 } 245 246 circuit1 := &htlcswitch.PaymentCircuit{ 247 Incoming: htlcswitch.CircuitKey{ 248 ChanID: chan2, 249 HtlcID: 1, 250 }, 251 PaymentHash: hash1, 252 ErrorEncrypter: htlcswitch.NewMockObfuscator(), 253 } 254 if _, err := circuitMap.CommitCircuits(circuit1); err != nil { 255 t.Fatalf("unable to add half circuit: %v", err) 256 } 257 258 // Circuit map should have one circuit that has not been fully opened. 259 assertNumCircuitsWithHash(t, circuitMap, hash1, 0) 260 assertHasCircuit(t, circuitMap, circuit1) 261 262 cfg, circuitMap = restartCircuitMap(t, cfg) 263 264 assertNumCircuitsWithHash(t, circuitMap, hash1, 0) 265 assertHasCircuit(t, circuitMap, circuit1) 266 267 // Add multiple circuits with same destination channel but different HTLC 268 // IDs and payment hashes. 269 keystone1 := htlcswitch.Keystone{ 270 InKey: circuit1.Incoming, 271 OutKey: htlcswitch.CircuitKey{ 272 ChanID: chan1, 273 HtlcID: 0, 274 }, 275 } 276 circuit1.Outgoing = &keystone1.OutKey 277 if err := circuitMap.OpenCircuits(keystone1); err != nil { 278 t.Fatalf("unable to add full circuit: %v", err) 279 } 280 281 // Circuit map should reflect addition of circuit1, and the change 282 // should survive a restart. 283 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 284 assertHasCircuit(t, circuitMap, circuit1) 285 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 286 287 cfg, circuitMap = restartCircuitMap(t, cfg) 288 289 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 290 assertHasCircuit(t, circuitMap, circuit1) 291 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 292 293 circuit2 := &htlcswitch.PaymentCircuit{ 294 Incoming: htlcswitch.CircuitKey{ 295 ChanID: chan2, 296 HtlcID: 2, 297 }, 298 PaymentHash: hash2, 299 ErrorEncrypter: htlcswitch.NewMockObfuscator(), 300 } 301 if _, err := circuitMap.CommitCircuits(circuit2); err != nil { 302 t.Fatalf("unable to add half circuit: %v", err) 303 } 304 305 assertHasCircuit(t, circuitMap, circuit2) 306 307 keystone2 := htlcswitch.Keystone{ 308 InKey: circuit2.Incoming, 309 OutKey: htlcswitch.CircuitKey{ 310 ChanID: chan1, 311 HtlcID: 1, 312 }, 313 } 314 circuit2.Outgoing = &keystone2.OutKey 315 if err := circuitMap.OpenCircuits(keystone2); err != nil { 316 t.Fatalf("unable to add full circuit: %v", err) 317 } 318 319 // Should have two full circuits, one under hash1 and another under 320 // hash2. Both half payment circuits should have been removed when the 321 // full circuits were added. 322 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 323 assertHasCircuit(t, circuitMap, circuit1) 324 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 325 326 assertNumCircuitsWithHash(t, circuitMap, hash2, 1) 327 assertHasCircuit(t, circuitMap, circuit2) 328 assertHasKeystone(t, circuitMap, keystone2.OutKey, circuit2) 329 330 assertNumCircuitsWithHash(t, circuitMap, hash3, 0) 331 332 cfg, circuitMap = restartCircuitMap(t, cfg) 333 334 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 335 assertHasCircuit(t, circuitMap, circuit1) 336 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 337 338 assertNumCircuitsWithHash(t, circuitMap, hash2, 1) 339 assertHasCircuit(t, circuitMap, circuit2) 340 assertHasKeystone(t, circuitMap, keystone2.OutKey, circuit2) 341 342 assertNumCircuitsWithHash(t, circuitMap, hash3, 0) 343 344 circuit3 := &htlcswitch.PaymentCircuit{ 345 Incoming: htlcswitch.CircuitKey{ 346 ChanID: chan1, 347 HtlcID: 2, 348 }, 349 PaymentHash: hash3, 350 ErrorEncrypter: htlcswitch.NewMockObfuscator(), 351 } 352 if _, err := circuitMap.CommitCircuits(circuit3); err != nil { 353 t.Fatalf("unable to add half circuit: %v", err) 354 } 355 356 assertHasCircuit(t, circuitMap, circuit3) 357 cfg, circuitMap = restartCircuitMap(t, cfg) 358 assertHasCircuit(t, circuitMap, circuit3) 359 360 // Add another circuit with an already-used HTLC ID but different 361 // destination channel. 362 keystone3 := htlcswitch.Keystone{ 363 InKey: circuit3.Incoming, 364 OutKey: htlcswitch.CircuitKey{ 365 ChanID: chan2, 366 HtlcID: 0, 367 }, 368 } 369 circuit3.Outgoing = &keystone3.OutKey 370 if err := circuitMap.OpenCircuits(keystone3); err != nil { 371 t.Fatalf("unable to add full circuit: %v", err) 372 } 373 374 // Check that all have been marked as full circuits, and that no half 375 // circuits are currently being tracked. 376 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 377 assertHasKeystone(t, circuitMap, keystone2.OutKey, circuit2) 378 assertHasKeystone(t, circuitMap, keystone3.OutKey, circuit3) 379 cfg, circuitMap = restartCircuitMap(t, cfg) 380 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 381 assertHasKeystone(t, circuitMap, keystone2.OutKey, circuit2) 382 assertHasKeystone(t, circuitMap, keystone3.OutKey, circuit3) 383 384 // Even though a circuit was added with chan1, HTLC ID 2 as the source, 385 // the lookup should go by destination channel, HTLC ID. 386 invalidKeystone := htlcswitch.CircuitKey{ 387 ChanID: chan1, 388 HtlcID: 2, 389 } 390 circuit = circuitMap.LookupOpenCircuit(invalidKeystone) 391 if circuit != nil { 392 t.Fatalf("LookupByHTLC returned a circuit without being added: %v", 393 circuit) 394 } 395 396 circuit4 := &htlcswitch.PaymentCircuit{ 397 Incoming: htlcswitch.CircuitKey{ 398 ChanID: chan2, 399 HtlcID: 3, 400 }, 401 PaymentHash: hash1, 402 ErrorEncrypter: htlcswitch.NewMockObfuscator(), 403 } 404 if _, err := circuitMap.CommitCircuits(circuit4); err != nil { 405 t.Fatalf("unable to add half circuit: %v", err) 406 } 407 408 // Circuit map should still only show one circuit with hash1, since we 409 // have not set the keystone for circuit4. 410 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 411 assertHasCircuit(t, circuitMap, circuit4) 412 413 cfg, circuitMap = restartCircuitMap(t, cfg) 414 415 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 416 assertHasCircuit(t, circuitMap, circuit4) 417 418 // Add a circuit with a destination channel and payment hash that are 419 // already added but a different HTLC ID. 420 keystone4 := htlcswitch.Keystone{ 421 InKey: circuit4.Incoming, 422 OutKey: htlcswitch.CircuitKey{ 423 ChanID: chan1, 424 HtlcID: 3, 425 }, 426 } 427 circuit4.Outgoing = &keystone4.OutKey 428 if err := circuitMap.OpenCircuits(keystone4); err != nil { 429 t.Fatalf("unable to add full circuit: %v", err) 430 } 431 432 // Verify that all circuits have been fully added. 433 assertHasCircuit(t, circuitMap, circuit1) 434 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 435 assertHasCircuit(t, circuitMap, circuit2) 436 assertHasKeystone(t, circuitMap, keystone2.OutKey, circuit2) 437 assertHasCircuit(t, circuitMap, circuit3) 438 assertHasKeystone(t, circuitMap, keystone3.OutKey, circuit3) 439 assertHasCircuit(t, circuitMap, circuit4) 440 assertHasKeystone(t, circuitMap, keystone4.OutKey, circuit4) 441 442 // Verify that each circuit is exposed via the proper hash bucketing. 443 assertNumCircuitsWithHash(t, circuitMap, hash1, 2) 444 assertHasCircuitForHash(t, circuitMap, hash1, circuit1) 445 assertHasCircuitForHash(t, circuitMap, hash1, circuit4) 446 447 assertNumCircuitsWithHash(t, circuitMap, hash2, 1) 448 assertHasCircuitForHash(t, circuitMap, hash2, circuit2) 449 450 assertNumCircuitsWithHash(t, circuitMap, hash3, 1) 451 assertHasCircuitForHash(t, circuitMap, hash3, circuit3) 452 453 // Restart, then run checks again. 454 cfg, circuitMap = restartCircuitMap(t, cfg) 455 456 // Verify that all circuits have been fully added. 457 assertHasCircuit(t, circuitMap, circuit1) 458 assertHasKeystone(t, circuitMap, keystone1.OutKey, circuit1) 459 assertHasCircuit(t, circuitMap, circuit2) 460 assertHasKeystone(t, circuitMap, keystone2.OutKey, circuit2) 461 assertHasCircuit(t, circuitMap, circuit3) 462 assertHasKeystone(t, circuitMap, keystone3.OutKey, circuit3) 463 assertHasCircuit(t, circuitMap, circuit4) 464 assertHasKeystone(t, circuitMap, keystone4.OutKey, circuit4) 465 466 // Verify that each circuit is exposed via the proper hash bucketing. 467 assertNumCircuitsWithHash(t, circuitMap, hash1, 2) 468 assertHasCircuitForHash(t, circuitMap, hash1, circuit1) 469 assertHasCircuitForHash(t, circuitMap, hash1, circuit4) 470 471 assertNumCircuitsWithHash(t, circuitMap, hash2, 1) 472 assertHasCircuitForHash(t, circuitMap, hash2, circuit2) 473 474 assertNumCircuitsWithHash(t, circuitMap, hash3, 1) 475 assertHasCircuitForHash(t, circuitMap, hash3, circuit3) 476 477 // Test removing circuits and the subsequent lookups. 478 err = circuitMap.DeleteCircuits(circuit1.Incoming) 479 if err != nil { 480 t.Fatalf("Remove returned unexpected error: %v", err) 481 } 482 483 // There should be exactly one remaining circuit with hash1, and it 484 // should be circuit4. 485 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 486 assertHasCircuitForHash(t, circuitMap, hash1, circuit4) 487 cfg, circuitMap = restartCircuitMap(t, cfg) 488 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 489 assertHasCircuitForHash(t, circuitMap, hash1, circuit4) 490 491 // Removing already-removed circuit should return an error. 492 err = circuitMap.DeleteCircuits(circuit1.Incoming) 493 if err != nil { 494 t.Fatalf("Unexpected failure when deleting already "+ 495 "deleted circuit: %v", err) 496 } 497 498 // Verify that nothing related to hash1 has changed 499 assertNumCircuitsWithHash(t, circuitMap, hash1, 1) 500 assertHasCircuitForHash(t, circuitMap, hash1, circuit4) 501 502 // Remove last remaining circuit with payment hash hash1. 503 err = circuitMap.DeleteCircuits(circuit4.Incoming) 504 if err != nil { 505 t.Fatalf("Remove returned unexpected error: %v", err) 506 } 507 508 assertNumCircuitsWithHash(t, circuitMap, hash1, 0) 509 assertNumCircuitsWithHash(t, circuitMap, hash2, 1) 510 assertNumCircuitsWithHash(t, circuitMap, hash3, 1) 511 cfg, circuitMap = restartCircuitMap(t, cfg) 512 assertNumCircuitsWithHash(t, circuitMap, hash1, 0) 513 assertNumCircuitsWithHash(t, circuitMap, hash2, 1) 514 assertNumCircuitsWithHash(t, circuitMap, hash3, 1) 515 516 // Remove last remaining circuit with payment hash hash2. 517 err = circuitMap.DeleteCircuits(circuit2.Incoming) 518 if err != nil { 519 t.Fatalf("Remove returned unexpected error: %v", err) 520 } 521 522 // There should now only be one remaining circuit, with hash3. 523 assertNumCircuitsWithHash(t, circuitMap, hash2, 0) 524 assertNumCircuitsWithHash(t, circuitMap, hash3, 1) 525 cfg, circuitMap = restartCircuitMap(t, cfg) 526 assertNumCircuitsWithHash(t, circuitMap, hash2, 0) 527 assertNumCircuitsWithHash(t, circuitMap, hash3, 1) 528 529 // In removing the final circuit, we will try and remove all other known 530 // circuits as well. Any circuits that are unknown to the circuit map 531 // will be ignored, and only circuit 3 should be cause any change in the 532 // state. 533 err = circuitMap.DeleteCircuits( 534 circuit1.Incoming, circuit2.Incoming, 535 circuit3.Incoming, circuit4.Incoming, 536 ) 537 if err != nil { 538 t.Fatalf("Unexpected failure when removing circuit while also "+ 539 "deleting already deleted circuits: %v", err) 540 } 541 542 // Check that the circuit map is empty, even after restarting. 543 assertNumCircuitsWithHash(t, circuitMap, hash3, 0) 544 _, circuitMap = restartCircuitMap(t, cfg) 545 assertNumCircuitsWithHash(t, circuitMap, hash3, 0) 546 } 547 548 // assertHasKeystone tests that the circuit map contains the provided payment 549 // circuit. 550 func assertHasKeystone(t *testing.T, cm htlcswitch.CircuitMap, 551 outKey htlcswitch.CircuitKey, c *htlcswitch.PaymentCircuit) { 552 553 circuit := cm.LookupOpenCircuit(outKey) 554 if !equalIgnoreLFD(circuit, c) { 555 t.Fatalf("unexpected circuit, want: %v, got %v", c, circuit) 556 } 557 } 558 559 // assertHasCircuitForHash tests that the provided circuit appears in the list 560 // of circuits for the given hash. 561 func assertHasCircuitForHash(t *testing.T, cm htlcswitch.CircuitMap, hash [32]byte, 562 circuit *htlcswitch.PaymentCircuit) { 563 564 circuits := cm.LookupByPaymentHash(hash) 565 for _, c := range circuits { 566 if equalIgnoreLFD(c, circuit) { 567 return 568 } 569 } 570 571 t.Fatalf("unable to find circuit: %v by hash: %v", circuit, hash) 572 } 573 574 // assertNumCircuitsWithHash tests that the circuit has the right number of full 575 // circuits, indexed by the given hash. 576 func assertNumCircuitsWithHash(t *testing.T, cm htlcswitch.CircuitMap, 577 hash [32]byte, expectedNum int) { 578 579 circuits := cm.LookupByPaymentHash(hash) 580 if len(circuits) != expectedNum { 581 t.Fatalf("LookupByPaymentHash returned wrong number of circuits for "+ 582 "hash=%v: expecected %d, got %d", hash, expectedNum, 583 len(circuits)) 584 } 585 } 586 587 // assertHasCircuit queries the circuit map using the half-circuit's half 588 // key, and fails if the returned half-circuit differs from the provided one. 589 func assertHasCircuit(t *testing.T, cm htlcswitch.CircuitMap, 590 c *htlcswitch.PaymentCircuit) { 591 592 c2 := cm.LookupCircuit(c.Incoming) 593 if !equalIgnoreLFD(c, c2) { 594 t.Fatalf("expected circuit: %v, got %v", c, c2) 595 } 596 } 597 598 // equalIgnoreLFD compares two payment circuits, but ignores the current value 599 // of LoadedFromDisk. The value is temporarily set to false for the comparison 600 // and then restored. 601 func equalIgnoreLFD(c, c2 *htlcswitch.PaymentCircuit) bool { 602 ogLFD := c.LoadedFromDisk 603 ogLFD2 := c2.LoadedFromDisk 604 605 c.LoadedFromDisk = false 606 c2.LoadedFromDisk = false 607 608 isEqual := reflect.DeepEqual(c, c2) 609 610 c.LoadedFromDisk = ogLFD 611 c2.LoadedFromDisk = ogLFD2 612 613 return isEqual 614 } 615 616 // makeCircuitDB initializes a new test channeldb for testing the persistence 617 // of the circuit map. If an empty string is provided as a path, a temp 618 // directory will be created. 619 func makeCircuitDB(t *testing.T, path string) *channeldb.DB { 620 if path == "" { 621 var err error 622 path, err = ioutil.TempDir("", "circuitdb") 623 if err != nil { 624 t.Fatalf("unable to create temp path: %v", err) 625 } 626 } 627 628 db, err := channeldb.Open(path) 629 if err != nil { 630 t.Fatalf("unable to open channel db: %v", err) 631 } 632 633 return db 634 } 635 636 // Creates a new circuit map, backed by a freshly opened channeldb. The existing 637 // channeldb is closed in order to simulate a complete restart. 638 func restartCircuitMap(t *testing.T, cfg *htlcswitch.CircuitMapConfig) ( 639 *htlcswitch.CircuitMapConfig, htlcswitch.CircuitMap) { 640 641 // Record the current temp path and close current db. We know we have 642 // a full channeldb.DB here since we created it just above. 643 dbPath := cfg.DB.(*channeldb.DB).Path() 644 cfg.DB.Close() 645 646 // Reinitialize circuit map with same db path. 647 db := makeCircuitDB(t, dbPath) 648 cfg2 := &htlcswitch.CircuitMapConfig{ 649 DB: db, 650 FetchAllOpenChannels: db.ChannelStateDB().FetchAllOpenChannels, 651 FetchClosedChannels: db.ChannelStateDB().FetchClosedChannels, 652 ExtractErrorEncrypter: cfg.ExtractErrorEncrypter, 653 } 654 cm2, err := htlcswitch.NewCircuitMap(cfg2) 655 if err != nil { 656 t.Fatalf("unable to recreate persistent circuit map: %v", err) 657 } 658 659 return cfg2, cm2 660 } 661 662 // TestCircuitMapCommitCircuits tests the following behavior of CommitCircuits: 663 // 1. New circuits are successfully added. 664 // 2. Duplicate circuits are dropped anytime before circuit map shutsdown. 665 // 3. Duplicate circuits are failed anytime after circuit map restarts. 666 func TestCircuitMapCommitCircuits(t *testing.T) { 667 t.Parallel() 668 669 var ( 670 chan1 = lnwire.NewShortChanIDFromInt(1) 671 circuitMap htlcswitch.CircuitMap 672 err error 673 ) 674 675 cfg, circuitMap := newCircuitMap(t) 676 677 circuit := &htlcswitch.PaymentCircuit{ 678 Incoming: htlcswitch.CircuitKey{ 679 ChanID: chan1, 680 HtlcID: 3, 681 }, 682 ErrorEncrypter: testExtracter, 683 } 684 685 // First we will try to add an new circuit to the circuit map, this 686 // should succeed. 687 actions, err := circuitMap.CommitCircuits(circuit) 688 if err != nil { 689 t.Fatalf("failed to commit circuits: %v", err) 690 } 691 if len(actions.Drops) > 0 { 692 t.Fatalf("new circuit should not have been dropped") 693 } 694 if len(actions.Fails) > 0 { 695 t.Fatalf("new circuit should not have failed") 696 } 697 if len(actions.Adds) != 1 { 698 t.Fatalf("only one circuit should have been added, found %d", 699 len(actions.Adds)) 700 } 701 702 circuit2 := circuitMap.LookupCircuit(circuit.Incoming) 703 if !reflect.DeepEqual(circuit, circuit2) { 704 t.Fatalf("unexpected committed circuit: got %v, want %v", 705 circuit2, circuit) 706 } 707 708 // Then we will try to readd the same circuit again, this should result 709 // in the circuit being dropped. This can happen if the incoming link 710 // flaps. 711 actions, err = circuitMap.CommitCircuits(circuit) 712 if err != nil { 713 t.Fatalf("failed to commit circuits: %v", err) 714 } 715 if len(actions.Adds) > 0 { 716 t.Fatalf("duplicate circuit should not have been added to circuit map") 717 } 718 if len(actions.Fails) > 0 { 719 t.Fatalf("duplicate circuit should not have failed") 720 } 721 if len(actions.Drops) != 1 { 722 t.Fatalf("only one circuit should have been dropped, found %d", 723 len(actions.Drops)) 724 } 725 726 // Finally, restart the circuit map, which will cause the added circuit 727 // to be loaded from disk. Since the keystone was never set, subsequent 728 // attempts to commit the circuit should cause the circuit map to 729 // indicate that the HTLC should be failed back. 730 _, circuitMap = restartCircuitMap(t, cfg) 731 732 actions, err = circuitMap.CommitCircuits(circuit) 733 if err != nil { 734 t.Fatalf("failed to commit circuits: %v", err) 735 } 736 if len(actions.Adds) > 0 { 737 t.Fatalf("duplicate circuit with incomplete forwarding " + 738 "decision should not have been added to circuit map") 739 } 740 if len(actions.Drops) > 0 { 741 t.Fatalf("duplicate circuit with incomplete forwarding " + 742 "decision should not have been dropped by circuit map") 743 } 744 if len(actions.Fails) != 1 { 745 t.Fatalf("only one duplicate circuit with incomplete "+ 746 "forwarding decision should have been failed, found: "+ 747 "%d", len(actions.Fails)) 748 } 749 750 // Lookup the committed circuit again, it should be identical apart from 751 // the loaded from disk flag. 752 circuit2 = circuitMap.LookupCircuit(circuit.Incoming) 753 if !equalIgnoreLFD(circuit, circuit2) { 754 t.Fatalf("unexpected committed circuit: got %v, want %v", 755 circuit2, circuit) 756 } 757 } 758 759 // TestCircuitMapOpenCircuits checks that circuits are properly opened, and that 760 // duplicate attempts to open a circuit will result in an error. 761 func TestCircuitMapOpenCircuits(t *testing.T) { 762 t.Parallel() 763 764 var ( 765 chan1 = lnwire.NewShortChanIDFromInt(1) 766 chan2 = lnwire.NewShortChanIDFromInt(2) 767 circuitMap htlcswitch.CircuitMap 768 err error 769 ) 770 771 cfg, circuitMap := newCircuitMap(t) 772 773 circuit := &htlcswitch.PaymentCircuit{ 774 Incoming: htlcswitch.CircuitKey{ 775 ChanID: chan1, 776 HtlcID: 3, 777 }, 778 ErrorEncrypter: testExtracter, 779 } 780 781 // First we will try to add an new circuit to the circuit map, this 782 // should succeed. 783 _, err = circuitMap.CommitCircuits(circuit) 784 if err != nil { 785 t.Fatalf("failed to commit circuits: %v", err) 786 } 787 788 keystone := htlcswitch.Keystone{ 789 InKey: circuit.Incoming, 790 OutKey: htlcswitch.CircuitKey{ 791 ChanID: chan2, 792 HtlcID: 2, 793 }, 794 } 795 796 // Open the circuit for the first time. 797 err = circuitMap.OpenCircuits(keystone) 798 if err != nil { 799 t.Fatalf("failed to open circuits: %v", err) 800 } 801 802 // Check that we can retrieve the open circuit if the circuit map before 803 // the circuit map is restarted. 804 circuit2 := circuitMap.LookupOpenCircuit(keystone.OutKey) 805 if !reflect.DeepEqual(circuit, circuit2) { 806 t.Fatalf("unexpected open circuit: got %v, want %v", 807 circuit2, circuit) 808 } 809 810 if !circuit2.HasKeystone() { 811 t.Fatalf("open circuit should have keystone") 812 } 813 if !reflect.DeepEqual(&keystone.OutKey, circuit2.Outgoing) { 814 t.Fatalf("expected open circuit to have outgoing key: %v, found %v", 815 &keystone.OutKey, circuit2.Outgoing) 816 } 817 818 // Open the circuit for a second time, which should fail due to a 819 // duplicate keystone 820 err = circuitMap.OpenCircuits(keystone) 821 if err != htlcswitch.ErrDuplicateKeystone { 822 t.Fatalf("failed to open circuits: %v", err) 823 } 824 825 // Then we will try to readd the same circuit again, this should result 826 // in the circuit being dropped. This can happen if the incoming link 827 // flaps OR the switch is entirely restarted and the outgoing link has 828 // not received a response. 829 actions, err := circuitMap.CommitCircuits(circuit) 830 if err != nil { 831 t.Fatalf("failed to commit circuits: %v", err) 832 } 833 if len(actions.Adds) > 0 { 834 t.Fatalf("duplicate circuit should not have been added to circuit map") 835 } 836 if len(actions.Fails) > 0 { 837 t.Fatalf("duplicate circuit should not have failed") 838 } 839 if len(actions.Drops) != 1 { 840 t.Fatalf("only one circuit should have been dropped, found %d", 841 len(actions.Drops)) 842 } 843 844 // Now, restart the circuit map, which will cause the opened circuit to 845 // be loaded from disk. Since we set the keystone on this circuit, it 846 // should be restored as such in memory. 847 // 848 // NOTE: The channel db doesn't have any channel data, so no keystones 849 // will be trimmed. 850 _, circuitMap = restartCircuitMap(t, cfg) 851 852 // Check that we can still query for the open circuit. 853 circuit2 = circuitMap.LookupOpenCircuit(keystone.OutKey) 854 if !equalIgnoreLFD(circuit, circuit2) { 855 t.Fatalf("unexpected open circuit: got %v, want %v", 856 circuit2, circuit) 857 } 858 859 // Try to open the circuit again, we expect this to fail since the open 860 // circuit was restored. 861 err = circuitMap.OpenCircuits(keystone) 862 if err != htlcswitch.ErrDuplicateKeystone { 863 t.Fatalf("failed to open circuits: %v", err) 864 } 865 866 // Lastly, with the circuit map restarted, try one more time to recommit 867 // the open circuit. This should be dropped, and is expected to happen 868 // if the incoming link flaps OR the switch is entirely restarted and 869 // the outgoing link has not received a response. 870 actions, err = circuitMap.CommitCircuits(circuit) 871 if err != nil { 872 t.Fatalf("failed to commit circuits: %v", err) 873 } 874 if len(actions.Adds) > 0 { 875 t.Fatalf("duplicate circuit should not have been added to circuit map") 876 } 877 if len(actions.Fails) > 0 { 878 t.Fatalf("duplicate circuit should not have failed") 879 } 880 if len(actions.Drops) != 1 { 881 t.Fatalf("only one circuit should have been dropped, found %d", 882 len(actions.Drops)) 883 } 884 } 885 886 func assertCircuitsOpenedPreRestart(t *testing.T, 887 circuitMap htlcswitch.CircuitMap, 888 circuits []*htlcswitch.PaymentCircuit, 889 keystones []htlcswitch.Keystone) { 890 891 for i, circuit := range circuits { 892 keystone := keystones[i] 893 894 openCircuit := circuitMap.LookupOpenCircuit(keystone.OutKey) 895 if !reflect.DeepEqual(circuit, openCircuit) { 896 t.Fatalf("unexpected open circuit %d: got %v, want %v", 897 i, openCircuit, circuit) 898 } 899 900 if !openCircuit.HasKeystone() { 901 t.Fatalf("open circuit %d should have keystone", i) 902 } 903 if !reflect.DeepEqual(&keystone.OutKey, openCircuit.Outgoing) { 904 t.Fatalf("expected open circuit %d to have outgoing "+ 905 "key: %v, found %v", i, 906 &keystone.OutKey, openCircuit.Outgoing) 907 } 908 } 909 } 910 911 func assertCircuitsOpenedPostRestart(t *testing.T, 912 circuitMap htlcswitch.CircuitMap, 913 circuits []*htlcswitch.PaymentCircuit, 914 keystones []htlcswitch.Keystone) { 915 916 for i, circuit := range circuits { 917 keystone := keystones[i] 918 919 openCircuit := circuitMap.LookupOpenCircuit(keystone.OutKey) 920 if !equalIgnoreLFD(circuit, openCircuit) { 921 t.Fatalf("unexpected open circuit %d: got %v, want %v", 922 i, openCircuit, circuit) 923 } 924 925 if !openCircuit.HasKeystone() { 926 t.Fatalf("open circuit %d should have keystone", i) 927 } 928 if !reflect.DeepEqual(&keystone.OutKey, openCircuit.Outgoing) { 929 t.Fatalf("expected open circuit %d to have outgoing "+ 930 "key: %v, found %v", i, 931 &keystone.OutKey, openCircuit.Outgoing) 932 } 933 } 934 } 935 936 func assertCircuitsNotOpenedPreRestart(t *testing.T, 937 circuitMap htlcswitch.CircuitMap, 938 circuits []*htlcswitch.PaymentCircuit, 939 keystones []htlcswitch.Keystone, 940 offset int) { 941 942 for i := range circuits { 943 keystone := keystones[i] 944 945 openCircuit := circuitMap.LookupOpenCircuit(keystone.OutKey) 946 if openCircuit != nil { 947 t.Fatalf("expected circuit %d not to be open", 948 offset+i) 949 } 950 951 circuit := circuitMap.LookupCircuit(keystone.InKey) 952 if circuit == nil { 953 t.Fatalf("expected to find unopened circuit %d", 954 offset+i) 955 } 956 if circuit.HasKeystone() { 957 t.Fatalf("circuit %d should not have keystone", 958 offset+i) 959 } 960 } 961 } 962 963 // TestCircuitMapTrimOpenCircuits verifies that the circuit map properly removes 964 // circuits from disk and the in-memory state when TrimOpenCircuits is used. 965 // This test checks that a successful trim survives a restart, and that circuits 966 // added before the restart can also be trimmed. 967 func TestCircuitMapTrimOpenCircuits(t *testing.T) { 968 t.Parallel() 969 970 var ( 971 chan1 = lnwire.NewShortChanIDFromInt(1) 972 chan2 = lnwire.NewShortChanIDFromInt(2) 973 circuitMap htlcswitch.CircuitMap 974 err error 975 ) 976 977 cfg, circuitMap := newCircuitMap(t) 978 979 const nCircuits = 10 980 const firstTrimIndex = 7 981 const secondTrimIndex = 3 982 983 // Create a list of all circuits that will be committed in the circuit 984 // map. The incoming HtlcIDs are chosen so that there is overlap with 985 // the outgoing HtlcIDs, but ensures that the test is not dependent on 986 // them being equal. 987 circuits := make([]*htlcswitch.PaymentCircuit, nCircuits) 988 for i := range circuits { 989 circuits[i] = &htlcswitch.PaymentCircuit{ 990 Incoming: htlcswitch.CircuitKey{ 991 ChanID: chan1, 992 HtlcID: uint64(i + 3), 993 }, 994 ErrorEncrypter: htlcswitch.NewMockObfuscator(), 995 } 996 } 997 998 // First we will try to add an new circuit to the circuit map, this 999 // should succeed. 1000 _, err = circuitMap.CommitCircuits(circuits...) 1001 if err != nil { 1002 t.Fatalf("failed to commit circuits: %v", err) 1003 } 1004 1005 // Now create a list of the keystones that we will use to preemptively 1006 // open the circuits. We set the index as the outgoing HtlcID to i 1007 // simplify the indexing logic of the test. 1008 keystones := make([]htlcswitch.Keystone, nCircuits) 1009 for i := range keystones { 1010 keystones[i] = htlcswitch.Keystone{ 1011 InKey: circuits[i].Incoming, 1012 OutKey: htlcswitch.CircuitKey{ 1013 ChanID: chan2, 1014 HtlcID: uint64(i), 1015 }, 1016 } 1017 } 1018 1019 // Open the circuits for the first time. 1020 err = circuitMap.OpenCircuits(keystones...) 1021 if err != nil { 1022 t.Fatalf("failed to open circuits: %v", err) 1023 } 1024 1025 // Check that all circuits are marked open. 1026 assertCircuitsOpenedPreRestart(t, circuitMap, circuits, keystones) 1027 1028 // Now trim up above outgoing htlcid `firstTrimIndex` (7). This should 1029 // leave the first 7 circuits open, and the rest should be reverted to 1030 // an unopened state. 1031 err = circuitMap.TrimOpenCircuits(chan2, firstTrimIndex) 1032 if err != nil { 1033 t.Fatalf("unable to trim circuits") 1034 } 1035 1036 assertCircuitsOpenedPreRestart(t, 1037 circuitMap, 1038 circuits[:firstTrimIndex], 1039 keystones[:firstTrimIndex], 1040 ) 1041 1042 assertCircuitsNotOpenedPreRestart( 1043 t, 1044 circuitMap, 1045 circuits[firstTrimIndex:], 1046 keystones[firstTrimIndex:], 1047 firstTrimIndex, 1048 ) 1049 1050 // Restart the circuit map, verify that the trim is reflected on 1051 // startup. 1052 cfg, circuitMap = restartCircuitMap(t, cfg) 1053 1054 assertCircuitsOpenedPostRestart( 1055 t, 1056 circuitMap, 1057 circuits[:firstTrimIndex], 1058 keystones[:firstTrimIndex], 1059 ) 1060 1061 assertCircuitsNotOpenedPreRestart( 1062 t, 1063 circuitMap, 1064 circuits[firstTrimIndex:], 1065 keystones[firstTrimIndex:], 1066 firstTrimIndex, 1067 ) 1068 1069 // Now, trim above outgoing htlcid `secondTrimIndex` (3). Only the first 1070 // three circuits should be open, with any others being reverted back to 1071 // unopened. 1072 err = circuitMap.TrimOpenCircuits(chan2, secondTrimIndex) 1073 if err != nil { 1074 t.Fatalf("unable to trim circuits") 1075 } 1076 1077 assertCircuitsOpenedPostRestart( 1078 t, 1079 circuitMap, 1080 circuits[:secondTrimIndex], 1081 keystones[:secondTrimIndex], 1082 ) 1083 1084 assertCircuitsNotOpenedPreRestart( 1085 t, 1086 circuitMap, 1087 circuits[secondTrimIndex:], 1088 keystones[secondTrimIndex:], 1089 secondTrimIndex, 1090 ) 1091 1092 // Restart the circuit map one last time to make sure the changes are 1093 // persisted. 1094 _, circuitMap = restartCircuitMap(t, cfg) 1095 1096 assertCircuitsOpenedPostRestart( 1097 t, 1098 circuitMap, 1099 circuits[:secondTrimIndex], 1100 keystones[:secondTrimIndex], 1101 ) 1102 1103 assertCircuitsNotOpenedPreRestart( 1104 t, 1105 circuitMap, 1106 circuits[secondTrimIndex:], 1107 keystones[secondTrimIndex:], 1108 secondTrimIndex, 1109 ) 1110 } 1111 1112 // TestCircuitMapCloseOpenCircuits asserts that the circuit map can properly 1113 // close open circuits, and that it allows at most one response to do so 1114 // successfully. It also checks that a circuit is reopened if the close was not 1115 // persisted via DeleteCircuits, and can again be closed. 1116 func TestCircuitMapCloseOpenCircuits(t *testing.T) { 1117 t.Parallel() 1118 1119 var ( 1120 chan1 = lnwire.NewShortChanIDFromInt(1) 1121 chan2 = lnwire.NewShortChanIDFromInt(2) 1122 circuitMap htlcswitch.CircuitMap 1123 err error 1124 ) 1125 1126 cfg, circuitMap := newCircuitMap(t) 1127 1128 circuit := &htlcswitch.PaymentCircuit{ 1129 Incoming: htlcswitch.CircuitKey{ 1130 ChanID: chan1, 1131 HtlcID: 3, 1132 }, 1133 ErrorEncrypter: &hop.SphinxErrorEncrypter{ 1134 EphemeralKey: testEphemeralKey, 1135 }, 1136 } 1137 1138 // First we will try to add an new circuit to the circuit map, this 1139 // should succeed. 1140 _, err = circuitMap.CommitCircuits(circuit) 1141 if err != nil { 1142 t.Fatalf("failed to commit circuits: %v", err) 1143 } 1144 1145 keystone := htlcswitch.Keystone{ 1146 InKey: circuit.Incoming, 1147 OutKey: htlcswitch.CircuitKey{ 1148 ChanID: chan2, 1149 HtlcID: 2, 1150 }, 1151 } 1152 1153 // Open the circuit for the first time. 1154 err = circuitMap.OpenCircuits(keystone) 1155 if err != nil { 1156 t.Fatalf("failed to open circuits: %v", err) 1157 } 1158 1159 // Check that we can retrieve the open circuit if the circuit map before 1160 // the circuit map is restarted. 1161 circuit2 := circuitMap.LookupOpenCircuit(keystone.OutKey) 1162 if !reflect.DeepEqual(circuit, circuit2) { 1163 t.Fatalf("unexpected open circuit: got %v, want %v", 1164 circuit2, circuit) 1165 } 1166 1167 // Open the circuit for a second time, which should fail due to a 1168 // duplicate keystone 1169 err = circuitMap.OpenCircuits(keystone) 1170 if err != htlcswitch.ErrDuplicateKeystone { 1171 t.Fatalf("failed to open circuits: %v", err) 1172 } 1173 1174 // Close the open circuit for the first time, which should succeed. 1175 _, err = circuitMap.FailCircuit(circuit.Incoming) 1176 if err != nil { 1177 t.Fatalf("unable to close unopened circuit") 1178 } 1179 1180 // Closing the circuit a second time should result in a failure. 1181 _, err = circuitMap.FailCircuit(circuit.Incoming) 1182 if err != htlcswitch.ErrCircuitClosing { 1183 t.Fatalf("unable to close unopened circuit") 1184 } 1185 1186 // Now, restart the circuit map, which will cause the opened circuit to 1187 // be loaded from disk. Since we set the keystone on this circuit, it 1188 // should be restored as such in memory. 1189 // 1190 // NOTE: The channel db doesn't have any channel data, so no keystones 1191 // will be trimmed. 1192 _, circuitMap = restartCircuitMap(t, cfg) 1193 1194 // Close the open circuit for the first time, which should succeed. 1195 _, err = circuitMap.FailCircuit(circuit.Incoming) 1196 if err != nil { 1197 t.Fatalf("unable to close unopened circuit") 1198 } 1199 1200 // Closing the circuit a second time should result in a failure. 1201 _, err = circuitMap.FailCircuit(circuit.Incoming) 1202 if err != htlcswitch.ErrCircuitClosing { 1203 t.Fatalf("unable to close unopened circuit") 1204 } 1205 } 1206 1207 // TestCircuitMapCloseUnopenedCircuit tests that closing an unopened circuit 1208 // allows at most semantics, and that the close is not persisted across 1209 // restarts. 1210 func TestCircuitMapCloseUnopenedCircuit(t *testing.T) { 1211 t.Parallel() 1212 1213 var ( 1214 chan1 = lnwire.NewShortChanIDFromInt(1) 1215 circuitMap htlcswitch.CircuitMap 1216 err error 1217 ) 1218 1219 cfg, circuitMap := newCircuitMap(t) 1220 1221 circuit := &htlcswitch.PaymentCircuit{ 1222 Incoming: htlcswitch.CircuitKey{ 1223 ChanID: chan1, 1224 HtlcID: 3, 1225 }, 1226 ErrorEncrypter: testExtracter, 1227 } 1228 1229 // First we will try to add an new circuit to the circuit map, this 1230 // should succeed. 1231 _, err = circuitMap.CommitCircuits(circuit) 1232 if err != nil { 1233 t.Fatalf("failed to commit circuits: %v", err) 1234 } 1235 1236 // Close the open circuit for the first time, which should succeed. 1237 _, err = circuitMap.FailCircuit(circuit.Incoming) 1238 if err != nil { 1239 t.Fatalf("unable to close unopened circuit") 1240 } 1241 1242 // Closing the circuit a second time should result in a failure. 1243 _, err = circuitMap.FailCircuit(circuit.Incoming) 1244 if err != htlcswitch.ErrCircuitClosing { 1245 t.Fatalf("unable to close unopened circuit") 1246 } 1247 1248 // Now, restart the circuit map, which will result in the circuit being 1249 // reopened, since no attempt to delete the circuit was made. 1250 _, circuitMap = restartCircuitMap(t, cfg) 1251 1252 // Close the open circuit for the first time, which should succeed. 1253 _, err = circuitMap.FailCircuit(circuit.Incoming) 1254 if err != nil { 1255 t.Fatalf("unable to close unopened circuit") 1256 } 1257 1258 // Closing the circuit a second time should result in a failure. 1259 _, err = circuitMap.FailCircuit(circuit.Incoming) 1260 if err != htlcswitch.ErrCircuitClosing { 1261 t.Fatalf("unable to close unopened circuit") 1262 } 1263 } 1264 1265 // TestCircuitMapDeleteUnopenedCircuit checks that an unopened circuit can be 1266 // removed persistently from the circuit map. 1267 func TestCircuitMapDeleteUnopenedCircuit(t *testing.T) { 1268 t.Parallel() 1269 1270 var ( 1271 chan1 = lnwire.NewShortChanIDFromInt(1) 1272 circuitMap htlcswitch.CircuitMap 1273 err error 1274 ) 1275 1276 cfg, circuitMap := newCircuitMap(t) 1277 1278 circuit := &htlcswitch.PaymentCircuit{ 1279 Incoming: htlcswitch.CircuitKey{ 1280 ChanID: chan1, 1281 HtlcID: 3, 1282 }, 1283 ErrorEncrypter: testExtracter, 1284 } 1285 1286 // First we will try to add an new circuit to the circuit map, this 1287 // should succeed. 1288 _, err = circuitMap.CommitCircuits(circuit) 1289 if err != nil { 1290 t.Fatalf("failed to commit circuits: %v", err) 1291 } 1292 1293 // Close the open circuit for the first time, which should succeed. 1294 _, err = circuitMap.FailCircuit(circuit.Incoming) 1295 if err != nil { 1296 t.Fatalf("unable to close unopened circuit") 1297 } 1298 1299 err = circuitMap.DeleteCircuits(circuit.Incoming) 1300 if err != nil { 1301 t.Fatalf("unable to close unopened circuit") 1302 } 1303 1304 // Check that we can retrieve the open circuit if the circuit map before 1305 // the circuit map is restarted. 1306 circuit2 := circuitMap.LookupCircuit(circuit.Incoming) 1307 if circuit2 != nil { 1308 t.Fatalf("unexpected open circuit: got %v, want %v", 1309 circuit2, nil) 1310 } 1311 1312 // Now, restart the circuit map, and check that the deletion survived 1313 // the restart. 1314 _, circuitMap = restartCircuitMap(t, cfg) 1315 1316 circuit2 = circuitMap.LookupCircuit(circuit.Incoming) 1317 if circuit2 != nil { 1318 t.Fatalf("unexpected open circuit: got %v, want %v", 1319 circuit2, nil) 1320 } 1321 } 1322 1323 // TestCircuitMapDeleteOpenCircuit checks that an open circuit can be removed 1324 // persistently from the circuit map. 1325 func TestCircuitMapDeleteOpenCircuit(t *testing.T) { 1326 t.Parallel() 1327 1328 var ( 1329 chan1 = lnwire.NewShortChanIDFromInt(1) 1330 chan2 = lnwire.NewShortChanIDFromInt(2) 1331 circuitMap htlcswitch.CircuitMap 1332 err error 1333 ) 1334 1335 cfg, circuitMap := newCircuitMap(t) 1336 1337 circuit := &htlcswitch.PaymentCircuit{ 1338 Incoming: htlcswitch.CircuitKey{ 1339 ChanID: chan1, 1340 HtlcID: 3, 1341 }, 1342 ErrorEncrypter: testExtracter, 1343 } 1344 1345 // First we will try to add an new circuit to the circuit map, this 1346 // should succeed. 1347 _, err = circuitMap.CommitCircuits(circuit) 1348 if err != nil { 1349 t.Fatalf("failed to commit circuits: %v", err) 1350 } 1351 1352 keystone := htlcswitch.Keystone{ 1353 InKey: circuit.Incoming, 1354 OutKey: htlcswitch.CircuitKey{ 1355 ChanID: chan2, 1356 HtlcID: 2, 1357 }, 1358 } 1359 1360 // Open the circuit for the first time. 1361 err = circuitMap.OpenCircuits(keystone) 1362 if err != nil { 1363 t.Fatalf("failed to open circuits: %v", err) 1364 } 1365 1366 // Close the open circuit for the first time, which should succeed. 1367 _, err = circuitMap.FailCircuit(circuit.Incoming) 1368 if err != nil { 1369 t.Fatalf("unable to close unopened circuit") 1370 } 1371 1372 // Persistently remove the circuit identified by incoming chan id. 1373 err = circuitMap.DeleteCircuits(circuit.Incoming) 1374 if err != nil { 1375 t.Fatalf("unable to close unopened circuit") 1376 } 1377 1378 // Check that we can no longer retrieve the open circuit. 1379 circuit2 := circuitMap.LookupOpenCircuit(keystone.OutKey) 1380 if circuit2 != nil { 1381 t.Fatalf("unexpected open circuit: got %v, want %v", 1382 circuit2, nil) 1383 } 1384 1385 // Now, restart the circuit map, and check that the deletion survived 1386 // the restart. 1387 _, circuitMap = restartCircuitMap(t, cfg) 1388 1389 circuit2 = circuitMap.LookupOpenCircuit(keystone.OutKey) 1390 if circuit2 != nil { 1391 t.Fatalf("unexpected open circuit: got %v, want %v", 1392 circuit2, nil) 1393 } 1394 }