github.com/decred/dcrlnd@v0.7.6/contractcourt/htlc_timeout_resolver_test.go (about) 1 package contractcourt 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/decred/dcrd/chaincfg/chainhash" 12 "github.com/decred/dcrd/chaincfg/v3" 13 "github.com/decred/dcrd/dcrutil/v4" 14 "github.com/decred/dcrd/txscript/v4" 15 "github.com/decred/dcrd/wire" 16 "github.com/decred/dcrlnd/chainntnfs" 17 "github.com/decred/dcrlnd/channeldb" 18 "github.com/decred/dcrlnd/input" 19 "github.com/decred/dcrlnd/kvdb" 20 "github.com/decred/dcrlnd/lntest/mock" 21 "github.com/decred/dcrlnd/lntypes" 22 "github.com/decred/dcrlnd/lnwallet" 23 "github.com/stretchr/testify/require" 24 ) 25 26 type mockWitnessBeacon struct { 27 preImageUpdates chan lntypes.Preimage 28 newPreimages chan []lntypes.Preimage 29 lookupPreimage map[lntypes.Hash]lntypes.Preimage 30 } 31 32 func newMockWitnessBeacon() *mockWitnessBeacon { 33 return &mockWitnessBeacon{ 34 preImageUpdates: make(chan lntypes.Preimage, 1), 35 newPreimages: make(chan []lntypes.Preimage), 36 lookupPreimage: make(map[lntypes.Hash]lntypes.Preimage), 37 } 38 } 39 40 func (m *mockWitnessBeacon) SubscribeUpdates() *WitnessSubscription { 41 return &WitnessSubscription{ 42 WitnessUpdates: m.preImageUpdates, 43 CancelSubscription: func() {}, 44 } 45 } 46 47 func (m *mockWitnessBeacon) LookupPreimage(payhash lntypes.Hash) (lntypes.Preimage, bool) { 48 preimage, ok := m.lookupPreimage[payhash] 49 if !ok { 50 return lntypes.Preimage{}, false 51 } 52 return preimage, true 53 } 54 55 func (m *mockWitnessBeacon) AddPreimages(preimages ...lntypes.Preimage) error { 56 m.newPreimages <- preimages 57 return nil 58 } 59 60 // TestHtlcTimeoutResolver tests that the timeout resolver properly handles all 61 // variations of possible local+remote spends. 62 func TestHtlcTimeoutResolver(t *testing.T) { 63 t.Parallel() 64 65 netParams := chaincfg.RegNetParams() 66 67 fakePreimageBytes := bytes.Repeat([]byte{1}, lntypes.HashSize) 68 69 var ( 70 htlcOutpoint wire.OutPoint 71 fakePreimage lntypes.Preimage 72 ) 73 fakeSignDesc := &input.SignDescriptor{ 74 Output: &wire.TxOut{}, 75 } 76 77 copy(fakePreimage[:], fakePreimageBytes) 78 79 signer := &mock.DummySigner{} 80 sweepTx := &wire.MsgTx{ 81 TxIn: []*wire.TxIn{ 82 { 83 PreviousOutPoint: htlcOutpoint, 84 SignatureScript: []byte{0x01, 0x01}, 85 }, 86 }, 87 } 88 fakeTimeout := int32(5) 89 _ = fakeTimeout // XXX 90 91 templateTx := &wire.MsgTx{ 92 TxIn: []*wire.TxIn{ 93 { 94 PreviousOutPoint: htlcOutpoint, 95 }, 96 }, 97 } 98 99 testCases := []struct { 100 // name is a human readable description of the test case. 101 name string 102 103 // remoteCommit denotes if the commitment broadcast was the 104 // remote commitment or not. 105 remoteCommit bool 106 107 // timeout denotes if the HTLC should be let timeout, or if the 108 // "remote" party should sweep it on-chain. This also affects 109 // what type of resolution message we expect. 110 timeout bool 111 112 // txToBroadcast is a function closure that should generate the 113 // transaction that should spend the HTLC output. Test authors 114 // can use this to customize the witness used when spending to 115 // trigger various redemption cases. 116 txToBroadcast func() (*wire.MsgTx, error) 117 118 // outcome is the resolver outcome that we expect to be reported 119 // once the contract is fully resolved. 120 outcome channeldb.ResolverOutcome 121 }{ 122 // Remote commitment is broadcast, we time out the HTLC on 123 // chain, and should expect a fail HTLC resolution. 124 { 125 name: "timeout remote tx", 126 remoteCommit: true, 127 timeout: true, 128 txToBroadcast: func() (*wire.MsgTx, error) { 129 witness, err := input.ReceiverHtlcSpendTimeout( 130 signer, fakeSignDesc, sweepTx, 131 fakeTimeout, 132 ) 133 if err != nil { 134 return nil, err 135 } 136 137 sigScript, err := input.WitnessStackToSigScript(witness) 138 if err != nil { 139 return nil, err 140 } 141 142 // To avoid triggering the race detector by 143 // setting the witness the second time this 144 // method is called during tests, we return 145 // immediately if the witness is already set 146 // correctly. 147 if reflect.DeepEqual( 148 templateTx.TxIn[0].SignatureScript, sigScript, 149 ) { 150 return templateTx, nil 151 } 152 153 templateTx.TxIn[0].SignatureScript = sigScript 154 return templateTx, nil 155 }, 156 outcome: channeldb.ResolverOutcomeTimeout, 157 }, 158 159 // Our local commitment is broadcast, we timeout the HTLC and 160 // still expect an HTLC fail resolution. 161 { 162 name: "timeout local tx", 163 remoteCommit: false, 164 timeout: true, 165 txToBroadcast: func() (*wire.MsgTx, error) { 166 witness, err := input.SenderHtlcSpendTimeout( 167 &mock.DummySignature{}, txscript.SigHashAll, 168 signer, fakeSignDesc, sweepTx, 169 ) 170 if err != nil { 171 return nil, err 172 } 173 174 sigScript, err := input.WitnessStackToSigScript(witness) 175 if err != nil { 176 return nil, err 177 } 178 179 // To avoid triggering the race detector by 180 // setting the witness the second time this 181 // method is called during tests, we return 182 // immediately if the witness is already set 183 // correctly. 184 if reflect.DeepEqual( 185 templateTx.TxIn[0].SignatureScript, sigScript, 186 ) { 187 return templateTx, nil 188 } 189 190 templateTx.TxIn[0].SignatureScript = sigScript 191 192 // Set the outpoint to be on our commitment, 193 // since we need to claim in two stages. 194 templateTx.TxIn[0].PreviousOutPoint = testChanPoint1 195 return templateTx, nil 196 }, 197 outcome: channeldb.ResolverOutcomeTimeout, 198 }, 199 200 // The remote commitment is broadcast, they sweep with the 201 // pre-image, we should get a settle HTLC resolution. 202 { 203 name: "success remote tx", 204 remoteCommit: true, 205 timeout: false, 206 txToBroadcast: func() (*wire.MsgTx, error) { 207 witness, err := input.ReceiverHtlcSpendRedeem( 208 &mock.DummySignature{}, txscript.SigHashAll, 209 fakePreimageBytes, signer, fakeSignDesc, 210 sweepTx, 211 ) 212 if err != nil { 213 return nil, err 214 } 215 216 sigScript, err := input.WitnessStackToSigScript(witness) 217 if err != nil { 218 return nil, err 219 } 220 221 // To avoid triggering the race detector by 222 // setting the witness the second time this 223 // method is called during tests, we return 224 // immediately if the witness is already set 225 // correctly. 226 if reflect.DeepEqual( 227 templateTx.TxIn[0].SignatureScript, sigScript, 228 ) { 229 return templateTx, nil 230 } 231 232 templateTx.TxIn[0].SignatureScript = sigScript 233 return templateTx, nil 234 }, 235 outcome: channeldb.ResolverOutcomeClaimed, 236 }, 237 238 // The local commitment is broadcast, they sweep it with a 239 // timeout from the output, and we should still get the HTLC 240 // settle resolution back. 241 { 242 name: "success local tx", 243 remoteCommit: false, 244 timeout: false, 245 txToBroadcast: func() (*wire.MsgTx, error) { 246 witness, err := input.SenderHtlcSpendRedeem( 247 signer, fakeSignDesc, sweepTx, 248 fakePreimageBytes, 249 ) 250 if err != nil { 251 return nil, err 252 } 253 254 sigScript, err := input.WitnessStackToSigScript(witness) 255 if err != nil { 256 return nil, err 257 } 258 259 // To avoid triggering the race detector by 260 // setting the witness the second time this 261 // method is called during tests, we return 262 // immediately if the witness is already set 263 // correctly. 264 if reflect.DeepEqual( 265 templateTx.TxIn[0].SignatureScript, sigScript, 266 ) { 267 return templateTx, nil 268 } 269 270 templateTx.TxIn[0].SignatureScript = sigScript 271 return templateTx, nil 272 }, 273 outcome: channeldb.ResolverOutcomeClaimed, 274 }, 275 } 276 277 notifier := &mock.ChainNotifier{ 278 EpochChan: make(chan *chainntnfs.BlockEpoch), 279 SpendChan: make(chan *chainntnfs.SpendDetail), 280 ConfChan: make(chan *chainntnfs.TxConfirmation), 281 } 282 witnessBeacon := newMockWitnessBeacon() 283 284 for _, testCase := range testCases { 285 t.Logf("Running test case: %v", testCase.name) 286 287 checkPointChan := make(chan struct{}, 1) 288 incubateChan := make(chan struct{}, 1) 289 resolutionChan := make(chan ResolutionMsg, 1) 290 reportChan := make(chan *channeldb.ResolverReport) 291 292 chainCfg := ChannelArbitratorConfig{ 293 ChainArbitratorConfig: ChainArbitratorConfig{ 294 NetParams: netParams, 295 Notifier: notifier, 296 PreimageDB: witnessBeacon, 297 IncubateOutputs: func(wire.OutPoint, 298 *lnwallet.OutgoingHtlcResolution, 299 *lnwallet.IncomingHtlcResolution, 300 uint32) error { 301 302 incubateChan <- struct{}{} 303 return nil 304 }, 305 DeliverResolutionMsg: func(msgs ...ResolutionMsg) error { 306 if len(msgs) != 1 { 307 return fmt.Errorf("expected 1 "+ 308 "resolution msg, instead got %v", 309 len(msgs)) 310 } 311 312 resolutionChan <- msgs[0] 313 return nil 314 }, 315 }, 316 PutResolverReport: func(_ kvdb.RwTx, 317 _ *channeldb.ResolverReport) error { 318 319 return nil 320 }, 321 } 322 323 cfg := ResolverConfig{ 324 ChannelArbitratorConfig: chainCfg, 325 Checkpoint: func(_ ContractResolver, 326 reports ...*channeldb.ResolverReport) error { 327 328 checkPointChan <- struct{}{} 329 330 // Send all of our reports into the channel. 331 for _, report := range reports { 332 reportChan <- report 333 } 334 335 return nil 336 }, 337 } 338 resolver := &htlcTimeoutResolver{ 339 htlcResolution: lnwallet.OutgoingHtlcResolution{ 340 ClaimOutpoint: testChanPoint2, 341 SweepSignDesc: *fakeSignDesc, 342 }, 343 contractResolverKit: *newContractResolverKit( 344 cfg, 345 ), 346 htlc: channeldb.HTLC{ 347 Amt: testHtlcAmt, 348 }, 349 } 350 351 var reports []*channeldb.ResolverReport 352 353 // If the test case needs the remote commitment to be 354 // broadcast, then we'll set the timeout commit to a fake 355 // transaction to force the code path. 356 if !testCase.remoteCommit { 357 timeoutTx, err := testCase.txToBroadcast() 358 require.NoError(t, err) 359 360 resolver.htlcResolution.SignedTimeoutTx = timeoutTx 361 362 if testCase.timeout { 363 timeoutTxID := timeoutTx.TxHash() 364 reports = append(reports, &channeldb.ResolverReport{ 365 OutPoint: timeoutTx.TxIn[0].PreviousOutPoint, 366 Amount: testHtlcAmt.ToAtoms(), 367 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 368 ResolverOutcome: channeldb.ResolverOutcomeFirstStage, 369 SpendTxID: &timeoutTxID, 370 }) 371 } 372 } 373 374 // With all the setup above complete, we can initiate the 375 // resolution process, and the bulk of our test. 376 var wg sync.WaitGroup 377 resolveErr := make(chan error, 1) 378 wg.Add(1) 379 go func() { 380 defer wg.Done() 381 382 _, err := resolver.Resolve() 383 if err != nil { 384 resolveErr <- err 385 } 386 }() 387 388 // At the output isn't yet in the nursery, we expect that we 389 // should receive an incubation request. 390 select { 391 case <-incubateChan: 392 case err := <-resolveErr: 393 t.Fatalf("unable to resolve HTLC: %v", err) 394 case <-time.After(time.Second * 5): 395 t.Fatalf("failed to receive incubation request") 396 } 397 398 // Next, the resolver should request a spend notification for 399 // the direct HTLC output. We'll use the txToBroadcast closure 400 // for the test case to generate the transaction that we'll 401 // send to the resolver. 402 spendingTx, err := testCase.txToBroadcast() 403 if err != nil { 404 t.Fatalf("unable to generate tx: %v", err) 405 } 406 spendTxHash := spendingTx.TxHash() 407 408 select { 409 case notifier.SpendChan <- &chainntnfs.SpendDetail{ 410 SpendingTx: spendingTx, 411 SpenderTxHash: &spendTxHash, 412 }: 413 case <-time.After(time.Second * 5): 414 t.Fatalf("failed to request spend ntfn") 415 } 416 417 if !testCase.timeout { 418 // If the resolver should settle now, then we'll 419 // extract the pre-image to be extracted and the 420 // resolution message sent. 421 select { 422 case newPreimage := <-witnessBeacon.newPreimages: 423 if newPreimage[0] != fakePreimage { 424 t.Fatalf("wrong pre-image: "+ 425 "expected %v, got %v", 426 fakePreimage, newPreimage) 427 } 428 429 case <-time.After(time.Second * 5): 430 t.Fatalf("pre-image not added") 431 } 432 433 // Finally, we should get a resolution message with the 434 // pre-image set within the message. 435 select { 436 case resolutionMsg := <-resolutionChan: 437 // Once again, the pre-images should match up. 438 if *resolutionMsg.PreImage != fakePreimage { 439 t.Fatalf("wrong pre-image: "+ 440 "expected %v, got %v", 441 fakePreimage, resolutionMsg.PreImage) 442 } 443 case <-time.After(time.Second * 5): 444 t.Fatalf("resolution not sent") 445 } 446 } else { 447 448 // Otherwise, the HTLC should now timeout. First, we 449 // should get a resolution message with a populated 450 // failure message. 451 select { 452 case resolutionMsg := <-resolutionChan: 453 if resolutionMsg.Failure == nil { 454 t.Fatalf("expected failure resolution msg") 455 } 456 case <-time.After(time.Second * 5): 457 t.Fatalf("resolution not sent") 458 } 459 460 // We should also get another request for the spend 461 // notification of the second-level transaction to 462 // indicate that it's been swept by the nursery, but 463 // only if this is a local commitment transaction. 464 if !testCase.remoteCommit { 465 select { 466 case notifier.SpendChan <- &chainntnfs.SpendDetail{ 467 SpendingTx: spendingTx, 468 SpenderTxHash: &spendTxHash, 469 }: 470 case <-time.After(time.Second * 5): 471 t.Fatalf("failed to request spend ntfn") 472 } 473 } 474 } 475 476 // In any case, before the resolver exits, it should checkpoint 477 // its final state. 478 select { 479 case <-checkPointChan: 480 case err := <-resolveErr: 481 t.Fatalf("unable to resolve HTLC: %v", err) 482 case <-time.After(time.Second * 5): 483 t.Fatalf("check point not received") 484 } 485 486 // Add a report to our set of expected reports with the outcome 487 // that the test specifies (either success or timeout). 488 spendTxID := spendingTx.TxHash() 489 amt := dcrutil.Amount(fakeSignDesc.Output.Value) 490 491 reports = append(reports, &channeldb.ResolverReport{ 492 OutPoint: testChanPoint2, 493 Amount: amt, 494 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 495 ResolverOutcome: testCase.outcome, 496 SpendTxID: &spendTxID, 497 }) 498 499 for _, report := range reports { 500 assertResolverReport(t, reportChan, report) 501 } 502 503 wg.Wait() 504 505 // Finally, the resolver should be marked as resolved. 506 if !resolver.resolved { 507 t.Fatalf("resolver should be marked as resolved") 508 } 509 } 510 } 511 512 // NOTE: the following tests essentially checks many of the same scenarios as 513 // the test above, but they expand on it by checking resuming from checkpoints 514 // at every stage. 515 516 // TestHtlcTimeoutSingleStage tests a remote commitment confirming, and the 517 // local node sweeping the HTLC output directly after timeout. 518 func TestHtlcTimeoutSingleStage(t *testing.T) { 519 commitOutpoint := wire.OutPoint{Index: 3} 520 521 sweepTx := &wire.MsgTx{ 522 TxIn: []*wire.TxIn{{}}, 523 TxOut: []*wire.TxOut{{}}, 524 } 525 526 // singleStageResolution is a resolution for a htlc on the remote 527 // party's commitment. 528 singleStageResolution := lnwallet.OutgoingHtlcResolution{ 529 ClaimOutpoint: commitOutpoint, 530 SweepSignDesc: testSignDesc, 531 } 532 533 sweepTxid := sweepTx.TxHash() 534 claim := &channeldb.ResolverReport{ 535 OutPoint: commitOutpoint, 536 Amount: dcrutil.Amount(testSignDesc.Output.Value), 537 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 538 ResolverOutcome: channeldb.ResolverOutcomeTimeout, 539 SpendTxID: &sweepTxid, 540 } 541 542 checkpoints := []checkpoint{ 543 { 544 // Output should be handed off to the nursery. 545 incubating: true, 546 }, 547 { 548 // We send a confirmation the sweep tx from published 549 // by the nursery. 550 preCheckpoint: func(ctx *htlcResolverTestContext, 551 _ bool) error { 552 // The nursery will create and publish a sweep 553 // tx. 554 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 555 SpendingTx: sweepTx, 556 SpenderTxHash: &sweepTxid, 557 } 558 559 // The resolver should deliver a failure 560 // resolition message (indicating we 561 // successfully timed out the HTLC). 562 select { 563 case resolutionMsg := <-ctx.resolutionChan: 564 if resolutionMsg.Failure == nil { 565 t.Fatalf("expected failure resolution msg") 566 } 567 case <-time.After(time.Second * 5): 568 t.Fatalf("resolution not sent") 569 } 570 571 return nil 572 }, 573 574 // After the sweep has confirmed, we expect the 575 // checkpoint to be resolved, and with the above 576 // report. 577 incubating: true, 578 resolved: true, 579 reports: []*channeldb.ResolverReport{ 580 claim, 581 }, 582 }, 583 } 584 585 testHtlcTimeout( 586 t, singleStageResolution, checkpoints, 587 ) 588 } 589 590 // TestHtlcTimeoutSecondStage tests a local commitment being confirmed, and the 591 // local node claiming the HTLC output using the second-level timeout tx. 592 func TestHtlcTimeoutSecondStage(t *testing.T) { 593 commitOutpoint := wire.OutPoint{Index: 2} 594 htlcOutpoint := wire.OutPoint{Index: 3} 595 596 sweepTx := &wire.MsgTx{ 597 TxIn: []*wire.TxIn{{}}, 598 TxOut: []*wire.TxOut{{}}, 599 } 600 sweepHash := sweepTx.TxHash() 601 602 timeoutTx := &wire.MsgTx{ 603 TxIn: []*wire.TxIn{ 604 { 605 PreviousOutPoint: commitOutpoint, 606 }, 607 }, 608 TxOut: []*wire.TxOut{ 609 { 610 Value: 111, 611 PkScript: []byte{0xaa, 0xaa}, 612 }, 613 }, 614 } 615 616 signer := &mock.DummySigner{} 617 witness, err := input.SenderHtlcSpendTimeout( 618 &mock.DummySignature{}, txscript.SigHashAll, 619 signer, &testSignDesc, timeoutTx, 620 ) 621 require.NoError(t, err) 622 timeoutTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(witness) 623 require.NoError(t, err) 624 625 timeoutTxid := timeoutTx.TxHash() 626 627 // twoStageResolution is a resolution for a htlc on the local 628 // party's commitment. 629 twoStageResolution := lnwallet.OutgoingHtlcResolution{ 630 ClaimOutpoint: htlcOutpoint, 631 SignedTimeoutTx: timeoutTx, 632 SweepSignDesc: testSignDesc, 633 } 634 635 firstStage := &channeldb.ResolverReport{ 636 OutPoint: commitOutpoint, 637 Amount: testHtlcAmt.ToAtoms(), 638 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 639 ResolverOutcome: channeldb.ResolverOutcomeFirstStage, 640 SpendTxID: &timeoutTxid, 641 } 642 643 secondState := &channeldb.ResolverReport{ 644 OutPoint: htlcOutpoint, 645 Amount: dcrutil.Amount(testSignDesc.Output.Value), 646 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 647 ResolverOutcome: channeldb.ResolverOutcomeTimeout, 648 SpendTxID: &sweepHash, 649 } 650 651 checkpoints := []checkpoint{ 652 { 653 // Output should be handed off to the nursery. 654 incubating: true, 655 }, 656 { 657 // We send a confirmation for our sweep tx to indicate 658 // that our sweep succeeded. 659 preCheckpoint: func(ctx *htlcResolverTestContext, 660 _ bool) error { 661 // The nursery will publish the timeout tx. 662 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 663 SpendingTx: timeoutTx, 664 SpenderTxHash: &timeoutTxid, 665 } 666 667 // The resolver should deliver a failure 668 // resolution message (indicating we 669 // successfully timed out the HTLC). 670 select { 671 case resolutionMsg := <-ctx.resolutionChan: 672 if resolutionMsg.Failure == nil { 673 t.Fatalf("expected failure resolution msg") 674 } 675 case <-time.After(time.Second * 1): 676 t.Fatalf("resolution not sent") 677 } 678 679 // Deliver spend of timeout tx. 680 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 681 SpendingTx: sweepTx, 682 SpenderTxHash: &sweepHash, 683 } 684 685 return nil 686 }, 687 688 // After the sweep has confirmed, we expect the 689 // checkpoint to be resolved, and with the above 690 // reports. 691 incubating: true, 692 resolved: true, 693 reports: []*channeldb.ResolverReport{ 694 firstStage, secondState, 695 }, 696 }, 697 } 698 699 testHtlcTimeout( 700 t, twoStageResolution, checkpoints, 701 ) 702 } 703 704 // TestHtlcTimeoutSingleStageRemoteSpend tests that when a local commitment 705 // confirms, and the remote spends the HTLC output directly, we detect this and 706 // extract the preimage. 707 func TestHtlcTimeoutSingleStageRemoteSpend(t *testing.T) { 708 commitOutpoint := wire.OutPoint{Index: 2} 709 htlcOutpoint := wire.OutPoint{Index: 3} 710 711 spendTx := &wire.MsgTx{ 712 TxIn: []*wire.TxIn{{}}, 713 TxOut: []*wire.TxOut{{}}, 714 } 715 716 fakePreimageBytes := bytes.Repeat([]byte{1}, lntypes.HashSize) 717 var fakePreimage lntypes.Preimage 718 copy(fakePreimage[:], fakePreimageBytes) 719 720 signer := &mock.DummySigner{} 721 witness, err := input.SenderHtlcSpendRedeem( 722 signer, &testSignDesc, spendTx, 723 fakePreimageBytes, 724 ) 725 require.NoError(t, err) 726 spendTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(witness) 727 require.NoError(t, err) 728 729 spendTxHash := spendTx.TxHash() 730 731 timeoutTx := &wire.MsgTx{ 732 TxIn: []*wire.TxIn{ 733 { 734 PreviousOutPoint: commitOutpoint, 735 }, 736 }, 737 TxOut: []*wire.TxOut{ 738 { 739 Value: 123, 740 PkScript: []byte{0xff, 0xff}, 741 }, 742 }, 743 } 744 745 timeoutWitness, err := input.SenderHtlcSpendTimeout( 746 &mock.DummySignature{}, txscript.SigHashAll, 747 signer, &testSignDesc, timeoutTx, 748 ) 749 require.NoError(t, err) 750 timeoutTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(timeoutWitness) 751 require.NoError(t, err) 752 753 // twoStageResolution is a resolution for a htlc on the local 754 // party's commitment. 755 twoStageResolution := lnwallet.OutgoingHtlcResolution{ 756 ClaimOutpoint: htlcOutpoint, 757 SignedTimeoutTx: timeoutTx, 758 SweepSignDesc: testSignDesc, 759 } 760 761 claim := &channeldb.ResolverReport{ 762 OutPoint: htlcOutpoint, 763 Amount: dcrutil.Amount(testSignDesc.Output.Value), 764 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 765 ResolverOutcome: channeldb.ResolverOutcomeClaimed, 766 SpendTxID: &spendTxHash, 767 } 768 769 checkpoints := []checkpoint{ 770 { 771 // Output should be handed off to the nursery. 772 incubating: true, 773 }, 774 { 775 // We send a spend notification for a remote spend with 776 // the preimage. 777 preCheckpoint: func(ctx *htlcResolverTestContext, 778 _ bool) error { 779 780 witnessBeacon := ctx.resolver.(*htlcTimeoutResolver).PreimageDB.(*mockWitnessBeacon) 781 782 // The remote spends the output direcly with 783 // the preimage. 784 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 785 SpendingTx: spendTx, 786 SpenderTxHash: &spendTxHash, 787 } 788 789 // We should extract the preimage. 790 select { 791 case newPreimage := <-witnessBeacon.newPreimages: 792 if newPreimage[0] != fakePreimage { 793 t.Fatalf("wrong pre-image: "+ 794 "expected %v, got %v", 795 fakePreimage, newPreimage) 796 } 797 798 case <-time.After(time.Second * 5): 799 t.Fatalf("pre-image not added") 800 } 801 802 // Finally, we should get a resolution message 803 // with the pre-image set within the message. 804 select { 805 case resolutionMsg := <-ctx.resolutionChan: 806 if *resolutionMsg.PreImage != fakePreimage { 807 t.Fatalf("wrong pre-image: "+ 808 "expected %v, got %v", 809 fakePreimage, resolutionMsg.PreImage) 810 } 811 case <-time.After(time.Second * 5): 812 t.Fatalf("resolution not sent") 813 } 814 815 return nil 816 }, 817 818 // After the success tx has confirmed, we expect the 819 // checkpoint to be resolved, and with the above 820 // report. 821 incubating: true, 822 resolved: true, 823 reports: []*channeldb.ResolverReport{ 824 claim, 825 }, 826 }, 827 } 828 829 testHtlcTimeout( 830 t, twoStageResolution, checkpoints, 831 ) 832 } 833 834 // TestHtlcTimeoutSecondStageRemoteSpend tests that when a remite commitment 835 // confirms, and the remote spends the output using the success tx, we 836 // properly detect this and extract the preimage. 837 func TestHtlcTimeoutSecondStageRemoteSpend(t *testing.T) { 838 commitOutpoint := wire.OutPoint{Index: 2} 839 840 remoteSuccessTx := &wire.MsgTx{ 841 TxIn: []*wire.TxIn{ 842 { 843 PreviousOutPoint: commitOutpoint, 844 }, 845 }, 846 TxOut: []*wire.TxOut{}, 847 } 848 849 fakePreimageBytes := bytes.Repeat([]byte{1}, lntypes.HashSize) 850 var fakePreimage lntypes.Preimage 851 copy(fakePreimage[:], fakePreimageBytes) 852 853 signer := &mock.DummySigner{} 854 witness, err := input.ReceiverHtlcSpendRedeem( 855 &mock.DummySignature{}, txscript.SigHashAll, 856 fakePreimageBytes, signer, 857 &testSignDesc, remoteSuccessTx, 858 ) 859 require.NoError(t, err) 860 861 remoteSuccessTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(witness) 862 require.NoError(t, err) 863 successTxid := remoteSuccessTx.TxHash() 864 865 // singleStageResolution allwoing the local node to sweep HTLC output 866 // directly from the remote commitment after timeout. 867 singleStageResolution := lnwallet.OutgoingHtlcResolution{ 868 ClaimOutpoint: commitOutpoint, 869 SweepSignDesc: testSignDesc, 870 } 871 872 claim := &channeldb.ResolverReport{ 873 OutPoint: commitOutpoint, 874 Amount: dcrutil.Amount(testSignDesc.Output.Value), 875 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 876 ResolverOutcome: channeldb.ResolverOutcomeClaimed, 877 SpendTxID: &successTxid, 878 } 879 880 checkpoints := []checkpoint{ 881 { 882 // Output should be handed off to the nursery. 883 incubating: true, 884 }, 885 { 886 // We send a confirmation for the remote's second layer 887 // success transcation. 888 preCheckpoint: func(ctx *htlcResolverTestContext, 889 _ bool) error { 890 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 891 SpendingTx: remoteSuccessTx, 892 SpenderTxHash: &successTxid, 893 } 894 895 witnessBeacon := ctx.resolver.(*htlcTimeoutResolver).PreimageDB.(*mockWitnessBeacon) 896 897 // We expect the preimage to be extracted, 898 select { 899 case newPreimage := <-witnessBeacon.newPreimages: 900 if newPreimage[0] != fakePreimage { 901 t.Fatalf("wrong pre-image: "+ 902 "expected %v, got %v", 903 fakePreimage, newPreimage) 904 } 905 906 case <-time.After(time.Second * 5): 907 t.Fatalf("pre-image not added") 908 } 909 910 // Finally, we should get a resolution message with the 911 // pre-image set within the message. 912 select { 913 case resolutionMsg := <-ctx.resolutionChan: 914 if *resolutionMsg.PreImage != fakePreimage { 915 t.Fatalf("wrong pre-image: "+ 916 "expected %v, got %v", 917 fakePreimage, resolutionMsg.PreImage) 918 } 919 case <-time.After(time.Second * 5): 920 t.Fatalf("resolution not sent") 921 } 922 923 return nil 924 }, 925 926 // After the sweep has confirmed, we expect the 927 // checkpoint to be resolved, and with the above 928 // report. 929 incubating: true, 930 resolved: true, 931 reports: []*channeldb.ResolverReport{ 932 claim, 933 }, 934 }, 935 } 936 937 testHtlcTimeout( 938 t, singleStageResolution, checkpoints, 939 ) 940 } 941 942 // TestHtlcTimeoutSecondStageSweeper tests that for anchor channels, when a 943 // local commitment confirms, the timeout tx is handed to the sweeper to claim 944 // the HTLC output. 945 func TestHtlcTimeoutSecondStageSweeper(t *testing.T) { 946 commitOutpoint := wire.OutPoint{Index: 2} 947 htlcOutpoint := wire.OutPoint{Index: 3} 948 949 sweepTx := &wire.MsgTx{ 950 TxIn: []*wire.TxIn{{}}, 951 TxOut: []*wire.TxOut{{}}, 952 } 953 sweepHash := sweepTx.TxHash() 954 955 timeoutTx := &wire.MsgTx{ 956 TxIn: []*wire.TxIn{ 957 { 958 PreviousOutPoint: commitOutpoint, 959 }, 960 }, 961 TxOut: []*wire.TxOut{ 962 { 963 Value: 123, 964 PkScript: []byte{0xff, 0xff}, 965 }, 966 }, 967 } 968 969 // We set the timeout witness since the script is used when subscribing 970 // to spends. 971 signer := &mock.DummySigner{} 972 timeoutWitness, err := input.SenderHtlcSpendTimeout( 973 &mock.DummySignature{}, txscript.SigHashAll, 974 signer, &testSignDesc, timeoutTx, 975 ) 976 require.NoError(t, err) 977 timeoutTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(timeoutWitness) 978 require.NoError(t, err) 979 980 reSignedTimeoutTx := &wire.MsgTx{ 981 TxIn: []*wire.TxIn{ 982 { 983 PreviousOutPoint: wire.OutPoint{ 984 Hash: chainhash.Hash{0xaa, 0xbb}, 985 Index: 0, 986 }, 987 }, 988 timeoutTx.TxIn[0], 989 { 990 PreviousOutPoint: wire.OutPoint{ 991 Hash: chainhash.Hash{0xaa, 0xbb}, 992 Index: 2, 993 }, 994 }, 995 }, 996 997 TxOut: []*wire.TxOut{ 998 { 999 Value: 111, 1000 PkScript: []byte{0xaa, 0xaa}, 1001 }, 1002 timeoutTx.TxOut[0], 1003 }, 1004 } 1005 reSignedHash := reSignedTimeoutTx.TxHash() 1006 reSignedOutPoint := wire.OutPoint{ 1007 Hash: reSignedHash, 1008 Index: 1, 1009 } 1010 1011 // twoStageResolution is a resolution for a htlc on the local 1012 // party's commitment, where the timout tx can be re-signed. 1013 twoStageResolution := lnwallet.OutgoingHtlcResolution{ 1014 ClaimOutpoint: htlcOutpoint, 1015 SignedTimeoutTx: timeoutTx, 1016 SignDetails: &input.SignDetails{ 1017 SignDesc: testSignDesc, 1018 PeerSig: testSig, 1019 }, 1020 SweepSignDesc: testSignDesc, 1021 } 1022 1023 firstStage := &channeldb.ResolverReport{ 1024 OutPoint: commitOutpoint, 1025 Amount: testHtlcAmt.ToAtoms(), 1026 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 1027 ResolverOutcome: channeldb.ResolverOutcomeFirstStage, 1028 SpendTxID: &reSignedHash, 1029 } 1030 1031 secondState := &channeldb.ResolverReport{ 1032 OutPoint: reSignedOutPoint, 1033 Amount: dcrutil.Amount(testSignDesc.Output.Value), 1034 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 1035 ResolverOutcome: channeldb.ResolverOutcomeTimeout, 1036 SpendTxID: &sweepHash, 1037 } 1038 1039 checkpoints := []checkpoint{ 1040 { 1041 // The output should be given to the sweeper. 1042 preCheckpoint: func(ctx *htlcResolverTestContext, 1043 _ bool) error { 1044 1045 resolver := ctx.resolver.(*htlcTimeoutResolver) 1046 inp := <-resolver.Sweeper.(*mockSweeper).sweptInputs 1047 op := inp.OutPoint() 1048 if *op != commitOutpoint { 1049 return fmt.Errorf("outpoint %v swept, "+ 1050 "expected %v", op, 1051 commitOutpoint) 1052 } 1053 1054 // Emulat the sweeper spending using the 1055 // re-signed timeout tx. 1056 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 1057 SpendingTx: reSignedTimeoutTx, 1058 SpenderInputIndex: 1, 1059 SpenderTxHash: &reSignedHash, 1060 SpendingHeight: 10, 1061 } 1062 1063 return nil 1064 }, 1065 // incubating=true is used to signal that the 1066 // second-level transaction was confirmed. 1067 incubating: true, 1068 }, 1069 { 1070 // We send a confirmation for our sweep tx to indicate 1071 // that our sweep succeeded. 1072 preCheckpoint: func(ctx *htlcResolverTestContext, 1073 resumed bool) error { 1074 1075 // If we are resuming from a checkpoing, we 1076 // expect the resolver to re-subscribe to a 1077 // spend, hence we must resend it. 1078 if resumed { 1079 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 1080 SpendingTx: reSignedTimeoutTx, 1081 SpenderInputIndex: 1, 1082 SpenderTxHash: &reSignedHash, 1083 SpendingHeight: 10, 1084 } 1085 } 1086 1087 // The resolver should deliver a failure 1088 // resolution message (indicating we 1089 // successfully timed out the HTLC). 1090 select { 1091 case resolutionMsg := <-ctx.resolutionChan: 1092 if resolutionMsg.Failure == nil { 1093 t.Fatalf("expected failure resolution msg") 1094 } 1095 case <-time.After(time.Second * 1): 1096 t.Fatalf("resolution not sent") 1097 } 1098 1099 // Mimic CSV lock expiring. 1100 ctx.notifier.EpochChan <- &chainntnfs.BlockEpoch{ 1101 Height: 13, 1102 } 1103 1104 // The timout tx output should now be given to 1105 // the sweeper. 1106 resolver := ctx.resolver.(*htlcTimeoutResolver) 1107 inp := <-resolver.Sweeper.(*mockSweeper).sweptInputs 1108 op := inp.OutPoint() 1109 exp := wire.OutPoint{ 1110 Hash: reSignedHash, 1111 Index: 1, 1112 } 1113 if *op != exp { 1114 return fmt.Errorf("wrong outpoint swept") 1115 } 1116 1117 // Notify about the spend, which should resolve 1118 // the resolver. 1119 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 1120 SpendingTx: sweepTx, 1121 SpenderTxHash: &sweepHash, 1122 SpendingHeight: 14, 1123 } 1124 1125 return nil 1126 }, 1127 1128 // After the sweep has confirmed, we expect the 1129 // checkpoint to be resolved, and with the above 1130 // reports. 1131 incubating: true, 1132 resolved: true, 1133 reports: []*channeldb.ResolverReport{ 1134 firstStage, 1135 secondState, 1136 }, 1137 }, 1138 } 1139 1140 testHtlcTimeout( 1141 t, twoStageResolution, checkpoints, 1142 ) 1143 } 1144 1145 // TestHtlcTimeoutSecondStageSweeperRemoteSpend tests that if a local timeout 1146 // tx is offered to the sweeper, but the output is swept by the remote node, we 1147 // properly detect this and extract the preimage. 1148 func TestHtlcTimeoutSecondStageSweeperRemoteSpend(t *testing.T) { 1149 commitOutpoint := wire.OutPoint{Index: 2} 1150 htlcOutpoint := wire.OutPoint{Index: 3} 1151 1152 timeoutTx := &wire.MsgTx{ 1153 TxIn: []*wire.TxIn{ 1154 { 1155 PreviousOutPoint: commitOutpoint, 1156 }, 1157 }, 1158 TxOut: []*wire.TxOut{ 1159 { 1160 Value: 123, 1161 PkScript: []byte{0xff, 0xff}, 1162 }, 1163 }, 1164 } 1165 1166 // We set the timeout witness since the script is used when subscribing 1167 // to spends. 1168 signer := &mock.DummySigner{} 1169 timeoutWitness, err := input.SenderHtlcSpendTimeout( 1170 &mock.DummySignature{}, txscript.SigHashAll, 1171 signer, &testSignDesc, timeoutTx, 1172 ) 1173 require.NoError(t, err) 1174 timeoutTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(timeoutWitness) 1175 require.NoError(t, err) 1176 1177 spendTx := &wire.MsgTx{ 1178 TxIn: []*wire.TxIn{{}}, 1179 TxOut: []*wire.TxOut{{}}, 1180 } 1181 1182 fakePreimageBytes := bytes.Repeat([]byte{1}, lntypes.HashSize) 1183 var fakePreimage lntypes.Preimage 1184 copy(fakePreimage[:], fakePreimageBytes) 1185 1186 witness, err := input.SenderHtlcSpendRedeem( 1187 signer, &testSignDesc, spendTx, 1188 fakePreimageBytes, 1189 ) 1190 require.NoError(t, err) 1191 spendTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(witness) 1192 require.NoError(t, err) 1193 1194 spendTxHash := spendTx.TxHash() 1195 1196 // twoStageResolution is a resolution for a htlc on the local 1197 // party's commitment, where the timout tx can be re-signed. 1198 twoStageResolution := lnwallet.OutgoingHtlcResolution{ 1199 ClaimOutpoint: htlcOutpoint, 1200 SignedTimeoutTx: timeoutTx, 1201 SignDetails: &input.SignDetails{ 1202 SignDesc: testSignDesc, 1203 PeerSig: testSig, 1204 }, 1205 SweepSignDesc: testSignDesc, 1206 } 1207 1208 claim := &channeldb.ResolverReport{ 1209 OutPoint: htlcOutpoint, 1210 Amount: dcrutil.Amount(testSignDesc.Output.Value), 1211 ResolverType: channeldb.ResolverTypeOutgoingHtlc, 1212 ResolverOutcome: channeldb.ResolverOutcomeClaimed, 1213 SpendTxID: &spendTxHash, 1214 } 1215 1216 checkpoints := []checkpoint{ 1217 { 1218 // The output should be given to the sweeper. 1219 preCheckpoint: func(ctx *htlcResolverTestContext, 1220 _ bool) error { 1221 1222 resolver := ctx.resolver.(*htlcTimeoutResolver) 1223 inp := <-resolver.Sweeper.(*mockSweeper).sweptInputs 1224 op := inp.OutPoint() 1225 if *op != commitOutpoint { 1226 return fmt.Errorf("outpoint %v swept, "+ 1227 "expected %v", op, 1228 commitOutpoint) 1229 } 1230 1231 // Emulate the remote sweeping the output with the preimage. 1232 // re-signed timeout tx. 1233 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 1234 SpendingTx: spendTx, 1235 SpenderTxHash: &spendTxHash, 1236 } 1237 1238 return nil 1239 }, 1240 // incubating=true is used to signal that the 1241 // second-level transaction was confirmed. 1242 incubating: true, 1243 }, 1244 { 1245 // We send a confirmation for our sweep tx to indicate 1246 // that our sweep succeeded. 1247 preCheckpoint: func(ctx *htlcResolverTestContext, 1248 resumed bool) error { 1249 1250 // If we are resuming from a checkpoing, we 1251 // expect the resolver to re-subscribe to a 1252 // spend, hence we must resend it. 1253 if resumed { 1254 fmt.Println("resumed") 1255 ctx.notifier.SpendChan <- &chainntnfs.SpendDetail{ 1256 SpendingTx: spendTx, 1257 SpenderTxHash: &spendTxHash, 1258 } 1259 } 1260 1261 witnessBeacon := ctx.resolver.(*htlcTimeoutResolver).PreimageDB.(*mockWitnessBeacon) 1262 1263 // We should extract the preimage. 1264 select { 1265 case newPreimage := <-witnessBeacon.newPreimages: 1266 if newPreimage[0] != fakePreimage { 1267 t.Fatalf("wrong pre-image: "+ 1268 "expected %v, got %v", 1269 fakePreimage, newPreimage) 1270 } 1271 1272 case <-time.After(time.Second * 5): 1273 t.Fatalf("pre-image not added") 1274 } 1275 1276 // Finally, we should get a resolution message 1277 // with the pre-image set within the message. 1278 select { 1279 case resolutionMsg := <-ctx.resolutionChan: 1280 if *resolutionMsg.PreImage != fakePreimage { 1281 t.Fatalf("wrong pre-image: "+ 1282 "expected %v, got %v", 1283 fakePreimage, resolutionMsg.PreImage) 1284 } 1285 case <-time.After(time.Second * 5): 1286 t.Fatalf("resolution not sent") 1287 } 1288 1289 return nil 1290 }, 1291 1292 // After the sweep has confirmed, we expect the 1293 // checkpoint to be resolved, and with the above 1294 // reports. 1295 incubating: true, 1296 resolved: true, 1297 reports: []*channeldb.ResolverReport{ 1298 claim, 1299 }, 1300 }, 1301 } 1302 1303 testHtlcTimeout( 1304 t, twoStageResolution, checkpoints, 1305 ) 1306 } 1307 1308 func testHtlcTimeout(t *testing.T, resolution lnwallet.OutgoingHtlcResolution, 1309 checkpoints []checkpoint) { 1310 1311 defer timeout(t)() 1312 1313 // We first run the resolver from start to finish, ensuring it gets 1314 // checkpointed at every expected stage. We store the checkpointed data 1315 // for the next portion of the test. 1316 ctx := newHtlcResolverTestContext(t, 1317 func(htlc channeldb.HTLC, cfg ResolverConfig) ContractResolver { 1318 return &htlcTimeoutResolver{ 1319 contractResolverKit: *newContractResolverKit(cfg), 1320 htlc: htlc, 1321 htlcResolution: resolution, 1322 } 1323 }, 1324 ) 1325 1326 checkpointedState := runFromCheckpoint(t, ctx, checkpoints) 1327 1328 // Now, from every checkpoint created, we re-create the resolver, and 1329 // run the test from that checkpoint. 1330 for i := range checkpointedState { 1331 cp := bytes.NewReader(checkpointedState[i]) 1332 ctx := newHtlcResolverTestContext(t, 1333 func(htlc channeldb.HTLC, cfg ResolverConfig) ContractResolver { 1334 resolver, err := newTimeoutResolverFromReader(cp, cfg) 1335 if err != nil { 1336 t.Fatal(err) 1337 } 1338 1339 resolver.Supplement(htlc) 1340 resolver.htlcResolution = resolution 1341 return resolver 1342 }, 1343 ) 1344 1345 // Run from the given checkpoint, ensuring we'll hit the rest. 1346 _ = runFromCheckpoint(t, ctx, checkpoints[i+1:]) 1347 } 1348 }