github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_onchain_test.go (about) 1 package itest 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 "time" 8 9 "golang.org/x/net/context" 10 "matheusd.com/testctx" 11 12 "github.com/decred/dcrd/chaincfg/chainhash" 13 "github.com/decred/dcrd/dcrutil/v4" 14 "github.com/decred/dcrd/txscript/v4/stdscript" 15 "github.com/decred/dcrd/wire" 16 "github.com/decred/dcrlnd/input" 17 "github.com/decred/dcrlnd/lnrpc" 18 "github.com/decred/dcrlnd/lnrpc/walletrpc" 19 "github.com/decred/dcrlnd/lntest" 20 "github.com/decred/dcrlnd/lntest/wait" 21 "github.com/decred/dcrlnd/lnwallet" 22 "github.com/decred/dcrlnd/sweep" 23 "github.com/stretchr/testify/require" 24 ) 25 26 // testCPFP ensures that the daemon can bump an unconfirmed transaction's fee 27 // rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction. 28 // 29 // TODO(wilmer): Add RBF case once btcd supports it. 30 func testCPFP(net *lntest.NetworkHarness, t *harnessTest) { 31 runCPFP(net, t, net.Alice, net.Bob) 32 } 33 34 // runCPFP ensures that the daemon can bump an unconfirmed transaction's fee 35 // rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction. 36 func runCPFP(net *lntest.NetworkHarness, t *harnessTest, 37 alice, bob *lntest.HarnessNode) { 38 39 // Skip this test for neutrino, as it's not aware of mempool 40 // transactions. 41 if net.BackendCfg.Name() == "spv" { 42 t.Skipf("skipping CPFP test for spv backend") 43 } 44 45 // We'll start the test by sending Alice some coins, which she'll use to 46 // send to Bob. 47 ctxb := context.Background() 48 net.SendCoins(t.t, dcrutil.AtomsPerCoin, alice) 49 50 // Create an address for Bob to send the coins to. 51 addrReq := &lnrpc.NewAddressRequest{ 52 Type: lnrpc.AddressType_PUBKEY_HASH, 53 } 54 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 55 resp, err := bob.NewAddress(ctxt, addrReq) 56 if err != nil { 57 t.Fatalf("unable to get new address for bob: %v", err) 58 } 59 60 // Send the coins from Alice to Bob. We should expect a transaction to 61 // be broadcast and seen in the mempool. 62 sendReq := &lnrpc.SendCoinsRequest{ 63 Addr: resp.Address, 64 Amount: dcrutil.AtomsPerCoin, 65 } 66 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 67 if _, err = alice.SendCoins(ctxt, sendReq); err != nil { 68 t.Fatalf("unable to send coins to bob: %v", err) 69 } 70 71 txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 72 if err != nil { 73 t.Fatalf("expected one mempool transaction: %v", err) 74 } 75 76 // We'll then extract the raw transaction from the mempool in order to 77 // determine the index of Bob's output. 78 tx, err := net.Miner.Node.GetRawTransaction(ctxt, txid) 79 if err != nil { 80 t.Fatalf("unable to extract raw transaction from mempool: %v", 81 err) 82 } 83 bobOutputIdx := -1 84 for i, txOut := range tx.MsgTx().TxOut { 85 _, addrs := stdscript.ExtractAddrs( 86 txOut.Version, txOut.PkScript, net.Miner.ActiveNet, 87 ) 88 if len(addrs) != 1 { 89 t.Fatalf("wrong nb of addresses from pkScript=%x: "+ 90 "%v", txOut.PkScript, err) 91 } 92 if addrs[0].String() == resp.Address { 93 bobOutputIdx = i 94 } 95 } 96 if bobOutputIdx == -1 { 97 t.Fatalf("bob's output was not found within the transaction") 98 } 99 100 // Wait until bob has seen the tx and considers it as owned. 101 op := &lnrpc.OutPoint{ 102 TxidBytes: txid[:], 103 OutputIndex: uint32(bobOutputIdx), 104 } 105 assertWalletUnspent(t, bob, op) 106 107 // We'll attempt to bump the fee of this transaction by performing a 108 // CPFP from Alice's point of view. 109 bumpFeeReq := &walletrpc.BumpFeeRequest{ 110 Outpoint: op, 111 AtomsPerByte: uint32(sweep.DefaultMaxFeeRate / 1000), 112 } 113 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 114 _, err = bob.WalletKitClient.BumpFee(ctxt, bumpFeeReq) 115 if err != nil { 116 t.Fatalf("unable to bump fee: %v", err) 117 } 118 119 // We should now expect to see two transactions within the mempool, a 120 // parent and its child. 121 _, err = waitForNTxsInMempool(net.Miner.Node, 2, minerMempoolTimeout) 122 if err != nil { 123 t.Fatalf("expected two mempool transactions: %v", err) 124 } 125 126 // We should also expect to see the output being swept by the 127 // UtxoSweeper. We'll ensure it's using the fee rate specified. 128 pendingSweepsReq := &walletrpc.PendingSweepsRequest{} 129 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 130 pendingSweepsResp, err := bob.WalletKitClient.PendingSweeps( 131 ctxt, pendingSweepsReq, 132 ) 133 if err != nil { 134 t.Fatalf("unable to retrieve pending sweeps: %v", err) 135 } 136 if len(pendingSweepsResp.PendingSweeps) != 1 { 137 t.Fatalf("expected to find %v pending sweep(s), found %v", 1, 138 len(pendingSweepsResp.PendingSweeps)) 139 } 140 pendingSweep := pendingSweepsResp.PendingSweeps[0] 141 if !bytes.Equal(pendingSweep.Outpoint.TxidBytes, op.TxidBytes) { 142 t.Fatalf("expected output txid %x, got %x", op.TxidBytes, 143 pendingSweep.Outpoint.TxidBytes) 144 } 145 if pendingSweep.Outpoint.OutputIndex != op.OutputIndex { 146 t.Fatalf("expected output index %v, got %v", op.OutputIndex, 147 pendingSweep.Outpoint.OutputIndex) 148 } 149 if pendingSweep.AtomsPerByte != bumpFeeReq.AtomsPerByte { 150 t.Fatalf("expected sweep atoms per byte %v, got %v", 151 bumpFeeReq.AtomsPerByte, pendingSweep.AtomsPerByte) 152 } 153 154 // Mine a block to clean up the unconfirmed transactions. 155 mineBlocks(t, net, 1, 2) 156 157 // The input used to CPFP should no longer be pending. 158 err = wait.NoError(func() error { 159 req := &walletrpc.PendingSweepsRequest{} 160 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 161 resp, err := bob.WalletKitClient.PendingSweeps(ctxt, req) 162 if err != nil { 163 return fmt.Errorf("unable to retrieve bob's pending "+ 164 "sweeps: %v", err) 165 } 166 if len(resp.PendingSweeps) != 0 { 167 return fmt.Errorf("expected 0 pending sweeps, found %d", 168 len(resp.PendingSweeps)) 169 } 170 return nil 171 }, defaultTimeout) 172 if err != nil { 173 t.Fatalf(err.Error()) 174 } 175 } 176 177 // testAnchorReservedValue tests that we won't allow sending transactions when 178 // that would take the value we reserve for anchor fee bumping out of our 179 // wallet. 180 func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) { 181 // Start two nodes supporting anchor channels. 182 args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) 183 alice := net.NewNode(t.t, "Alice", args) 184 defer shutdownAndAssert(net, t, alice) 185 186 bob := net.NewNode(t.t, "Bob", args) 187 defer shutdownAndAssert(net, t, bob) 188 189 ctxb := context.Background() 190 net.ConnectNodes(t.t, alice, bob) 191 192 // Send just enough coins for Alice to open a channel without a change 193 // output. 194 const ( 195 chanAmt = 1000000 196 feeEst = 8000 197 ) 198 199 net.SendCoins(t.t, chanAmt+feeEst, alice) 200 201 // wallet, without a change output. This should not be allowed. 202 resErr := lnwallet.ErrReservedValueInvalidated.Error() 203 204 _, err := net.OpenChannel( 205 alice, bob, lntest.OpenChannelParams{ 206 Amt: chanAmt, 207 }, 208 ) 209 if err == nil || !strings.Contains(err.Error(), resErr) { 210 t.Fatalf("expected failure, got: %v", err) 211 } 212 213 // Alice opens a smaller channel. This works since it will have a 214 // change output. 215 aliceChanPoint1 := openChannelAndAssert( 216 t, net, alice, bob, lntest.OpenChannelParams{ 217 Amt: chanAmt / 4, 218 }, 219 ) 220 221 // If Alice tries to open another anchor channel to Bob, Bob should not 222 // reject it as he is not contributing any funds. 223 aliceChanPoint2 := openChannelAndAssert( 224 t, net, alice, bob, lntest.OpenChannelParams{ 225 Amt: chanAmt / 4, 226 }, 227 ) 228 229 // Similarly, if Alice tries to open a legacy channel to Bob, Bob should 230 // not reject it as he is not contributing any funds. We'll restart Bob 231 // to remove his support for anchors. 232 err = net.RestartNode(bob, nil) 233 require.NoError(t.t, err) 234 aliceChanPoint3 := openChannelAndAssert( 235 t, net, alice, bob, lntest.OpenChannelParams{ 236 Amt: chanAmt / 4, 237 }, 238 ) 239 240 chanPoints := []*lnrpc.ChannelPoint{ 241 aliceChanPoint1, aliceChanPoint2, aliceChanPoint3, 242 } 243 for _, chanPoint := range chanPoints { 244 err = alice.WaitForNetworkChannelOpen(chanPoint) 245 require.NoError(t.t, err) 246 247 err = bob.WaitForNetworkChannelOpen(chanPoint) 248 require.NoError(t.t, err) 249 } 250 251 // Alice tries to send all coins to an internal address. This is 252 // allowed, since the final wallet balance will still be above the 253 // reserved value. 254 addrReq := &lnrpc.NewAddressRequest{ 255 Type: lnrpc.AddressType_PUBKEY_HASH, 256 } 257 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 258 resp, err := alice.NewAddress(ctxt, addrReq) 259 require.NoError(t.t, err) 260 261 sweepReq := &lnrpc.SendCoinsRequest{ 262 Addr: resp.Address, 263 SendAll: true, 264 } 265 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 266 _, err = alice.SendCoins(ctxt, sweepReq) 267 require.NoError(t.t, err) 268 269 block := mineBlocks(t, net, 1, 1)[0] 270 271 // The sweep transaction should have exactly one input, the change from 272 // the previous SendCoins call. 273 sweepTx := block.Transactions[1] 274 if len(sweepTx.TxIn) != 1 { 275 t.Fatalf("expected 1 inputs instead have %v", len(sweepTx.TxIn)) 276 } 277 278 // It should have a single output. 279 if len(sweepTx.TxOut) != 1 { 280 t.Fatalf("expected 1 output instead have %v", len(sweepTx.TxOut)) 281 } 282 283 // Wait for Alice to see her balance as confirmed. 284 waitForConfirmedBalance := func() int64 { 285 var balance int64 286 err := wait.NoError(func() error { 287 req := &lnrpc.WalletBalanceRequest{} 288 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 289 resp, err := alice.WalletBalance(ctxt, req) 290 if err != nil { 291 return err 292 } 293 294 if resp.TotalBalance == 0 { 295 return fmt.Errorf("no balance") 296 } 297 298 if resp.UnconfirmedBalance > 0 { 299 return fmt.Errorf("unconfirmed balance") 300 } 301 302 balance = resp.TotalBalance 303 return nil 304 }, defaultTimeout) 305 require.NoError(t.t, err) 306 307 return balance 308 } 309 310 _ = waitForConfirmedBalance() 311 312 // Alice tries to send all funds to an external address, the reserved 313 // value must stay in her wallet. 314 minerAddr, err := net.Miner.NewAddress(testctx.New(t)) 315 require.NoError(t.t, err) 316 317 sweepReq = &lnrpc.SendCoinsRequest{ 318 Addr: minerAddr.String(), 319 SendAll: true, 320 } 321 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 322 _, err = alice.SendCoins(ctxt, sweepReq) 323 require.NoError(t.t, err) 324 325 // We'll mine a block which should include the sweep transaction we 326 // generated above. 327 block = mineBlocks(t, net, 1, 1)[0] 328 329 // The sweep transaction should have exactly one inputs as we only had 330 // the single output from above in the wallet. 331 sweepTx = block.Transactions[1] 332 if len(sweepTx.TxIn) != 1 { 333 t.Fatalf("expected 1 inputs instead have %v", len(sweepTx.TxIn)) 334 } 335 336 // It should have two outputs, one being the miner address, the other 337 // one being the reserve going back to our wallet. 338 if len(sweepTx.TxOut) != 2 { 339 t.Fatalf("expected 2 outputs instead have %v", len(sweepTx.TxOut)) 340 } 341 342 // The reserved value is now back in Alice's wallet. 343 aliceBalance := waitForConfirmedBalance() 344 345 // Alice closes channel, should now be allowed to send everything to an 346 // external address. 347 for _, chanPoint := range chanPoints { 348 closeChannelAndAssert(t, net, alice, chanPoint, false) 349 } 350 351 newBalance := waitForConfirmedBalance() 352 if newBalance <= aliceBalance { 353 t.Fatalf("Alice's balance did not increase after channel close") 354 } 355 356 // Assert there are no open or pending channels anymore. 357 assertNumPendingChannels(t, alice, 0, 0, 0, 0) 358 assertNodeNumChannels(t, alice, 0) 359 360 // We'll wait for the balance to reflect that the channel has been 361 // closed and the funds are in the wallet. 362 sweepReq = &lnrpc.SendCoinsRequest{ 363 Addr: minerAddr.String(), 364 SendAll: true, 365 } 366 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 367 _, err = alice.SendCoins(ctxt, sweepReq) 368 require.NoError(t.t, err) 369 370 // We'll mine a block which should include the sweep transaction we 371 // generated above. 372 block = mineBlocks(t, net, 1, 1)[0] 373 374 // The sweep transaction should have four inputs, the change output from 375 // the previous sweep, and the outputs from the coop closed channels. 376 sweepTx = block.Transactions[1] 377 if len(sweepTx.TxIn) != 4 { 378 t.Fatalf("expected 4 inputs instead have %v", len(sweepTx.TxIn)) 379 } 380 381 // It should have a single output. 382 if len(sweepTx.TxOut) != 1 { 383 t.Fatalf("expected 1 output instead have %v", len(sweepTx.TxOut)) 384 } 385 } 386 387 // genAnchorSweep generates a "3rd party" anchor sweeping from an existing one. 388 // In practice, we just re-use the existing witness, and track on our own 389 // output producing a 1-in-1-out transaction. 390 func genAnchorSweep(t *harnessTest, net *lntest.NetworkHarness, 391 aliceAnchor *sweptOutput, anchorCsv uint32) *dcrutil.Tx { 392 393 // At this point, we have the transaction that Alice used to try to 394 // sweep her anchor. As this is actually just something anyone can 395 // spend, just need to find the input spending the anchor output, then 396 // we can swap the output address. 397 aliceAnchorTxIn := func() wire.TxIn { 398 for _, txIn := range aliceAnchor.SweepTx.TxIn { 399 if txIn.PreviousOutPoint == aliceAnchor.OutPoint { 400 return *txIn 401 } 402 } 403 404 t.Fatalf("anchor op not found") 405 return wire.TxIn{} 406 }() 407 408 // We'll set the signature on the input to nil, and then set the 409 // sequence to 16 (the anchor CSV period). 410 aliceAnchorTxIn.SignatureScript = nil 411 aliceAnchorTxIn.Sequence = anchorCsv 412 413 minerAddr, err := net.Miner.NewAddress(testctx.New(t)) 414 if err != nil { 415 t.Fatalf("unable to get miner addr: %v", err) 416 } 417 scriptVersion, addrScript := minerAddr.PaymentScript() 418 419 // Now that we have the txIn, we can just make a new transaction that 420 // uses a different script for the output. 421 tx := wire.NewMsgTx() 422 tx.Version = input.LNTxVersion 423 tx.AddTxIn(&aliceAnchorTxIn) 424 tx.AddTxOut(&wire.TxOut{ 425 Version: scriptVersion, 426 PkScript: addrScript, 427 Value: anchorSize - 1, 428 }) 429 430 return dcrutil.NewTx(tx) 431 } 432 433 // testAnchorThirdPartySpend tests that if we force close a channel, but then 434 // don't sweep the anchor in time and a 3rd party spends it, that we remove any 435 // transactions that are a descendent of that sweep. 436 func testAnchorThirdPartySpend(net *lntest.NetworkHarness, t *harnessTest) { 437 // This test requires an rpctest func (GenerateAndSubmitBlock) to 438 // perform something that is not currently available in decred: namely, 439 // to mine a block with _only_ a specific set of transactions. This is 440 // hard to do in decred, due to the requirements of the staking 441 // subsystem. 442 // 443 // This function is used so that the test can enforce that the 444 // transaction that redeems the anchor output from the force-closed 445 // channel is NOT mined (along with the force-close) and instead is 446 // double spent by someone else. 447 // 448 // Given that anchor outputs are currently disabled in mainnet, this 449 // test is skipped. 450 t.Skipf("Test disabled in dcrlnd") 451 452 // First, we'll create two new nodes that both default to anchor 453 // channels. 454 // 455 // NOTE: The itests differ here as anchors is default off vs the normal 456 // lnd binary. 457 args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) 458 alice := net.NewNode(t.t, "Alice", args) 459 defer shutdownAndAssert(net, t, alice) 460 461 bob := net.NewNode(t.t, "Bob", args) 462 defer shutdownAndAssert(net, t, bob) 463 464 ctxb := context.Background() 465 net.ConnectNodes(t.t, alice, bob) 466 467 // We'll fund our Alice with coins, as she'll be opening the channel. 468 // We'll fund her with *just* enough coins to open the channel. 469 const ( 470 firstChanSize = 1_000_000 471 anchorFeeBuffer = 500_000 472 ) 473 net.SendCoins(t.t, firstChanSize, alice) 474 475 // We'll give Alice another spare UTXO as well so she can use it to 476 // help sweep all coins. 477 net.SendCoins(t.t, anchorFeeBuffer, alice) 478 479 // Open the channel between the two nodes and wait for it to confirm 480 // fully. 481 aliceChanPoint1 := openChannelAndAssert( 482 t, net, alice, bob, lntest.OpenChannelParams{ 483 Amt: firstChanSize, 484 }, 485 ) 486 487 // With the channel open, we'll actually immediately force close it. We 488 // don't care about network announcements here since there's no routing 489 // in this test. 490 _, _, err := net.CloseChannel(alice, aliceChanPoint1, true) 491 if err != nil { 492 t.Fatalf("unable to execute force channel closure: %v", err) 493 } 494 495 // Now that the channel has been force closed, it should show up in the 496 // PendingChannels RPC under the waiting close section. 497 pendingChansRequest := &lnrpc.PendingChannelsRequest{} 498 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 499 pendingChanResp, err := alice.PendingChannels(ctxt, pendingChansRequest) 500 if err != nil { 501 t.Fatalf("unable to query for pending channels: %v", err) 502 } 503 err = checkNumWaitingCloseChannels(pendingChanResp, 1) 504 if err != nil { 505 t.Fatalf(err.Error()) 506 } 507 508 // Get the normal channel outpoint so we can track it in the set of 509 // channels that are waiting to be closed. 510 fundingTxID, err := lnrpc.GetChanPointFundingTxid(aliceChanPoint1) 511 if err != nil { 512 t.Fatalf("unable to get txid: %v", err) 513 } 514 chanPoint := wire.OutPoint{ 515 Hash: *fundingTxID, 516 Index: aliceChanPoint1.OutputIndex, 517 } 518 waitingClose, err := findWaitingCloseChannel(pendingChanResp, &chanPoint) 519 if err != nil { 520 t.Fatalf(err.Error()) 521 } 522 523 // At this point, the channel is waiting close, and we have both the 524 // commitment transaction and anchor sweep in the mempool. 525 const expectedTxns = 2 526 sweepTxns, err := getNTxsFromMempool( 527 net.Miner.Node, expectedTxns, minerMempoolTimeout, 528 ) 529 require.NoError(t.t, err, "no sweep txns in miner mempool") 530 aliceCloseTx := waitingClose.Commitments.LocalTxid 531 _, aliceAnchor := findCommitAndAnchor(t, net, sweepTxns, aliceCloseTx) 532 533 // We'll now mine _only_ the commitment force close transaction, as we 534 // want the anchor sweep to stay unconfirmed. 535 var emptyTime time.Time 536 forceCloseTxID, _ := chainhash.NewHashFromStr(aliceCloseTx) 537 commitTxn, err := net.Miner.Node.GetRawTransaction( 538 testctx.New(t), forceCloseTxID, 539 ) 540 if err != nil { 541 t.Fatalf("unable to get transaction: %v", err) 542 } 543 544 _, err = net.Miner.GenerateAndSubmitBlock( 545 []*dcrutil.Tx{commitTxn}, -1, emptyTime, 546 ) 547 if err != nil { 548 t.Fatalf("unable to generate block: %v", err) 549 } 550 551 // With the anchor output located, and the main commitment mined we'll 552 // instruct the wallet to send all coins in the wallet to a new address 553 // (to the miner), including unconfirmed change. 554 minerAddr, err := net.Miner.NewAddress(testctx.New(t)) 555 if err != nil { 556 t.Fatalf("unable to create new miner addr: %v", err) 557 } 558 sweepReq := &lnrpc.SendCoinsRequest{ 559 Addr: minerAddr.String(), 560 SendAll: true, 561 MinConfs: 0, 562 SpendUnconfirmed: true, 563 } 564 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 565 sweepAllResp, err := alice.SendCoins(ctxt, sweepReq) 566 if err != nil { 567 t.Fatalf("unable to sweep coins: %v", err) 568 } 569 570 // Both the original anchor sweep transaction, as well as the 571 // transaction we created to sweep all the coins from Alice's wallet 572 // should be found in her transaction store. 573 sweepAllTxID, _ := chainhash.NewHashFromStr(sweepAllResp.Txid) 574 assertTransactionInWallet(t.t, alice, aliceAnchor.SweepTx.TxHash()) 575 assertTransactionInWallet(t.t, alice, *sweepAllTxID) 576 577 // Next, we'll shutdown Alice, and allow 16 blocks to pass so that the 578 // anchor output can be swept by anyone. Rather than use the normal API 579 // call, we'll generate a series of _empty_ blocks here. 580 aliceRestart, err := net.SuspendNode(alice) 581 if err != nil { 582 t.Fatalf("unable to shutdown alice: %v", err) 583 } 584 const anchorCsv = 16 585 for i := 0; i < anchorCsv; i++ { 586 _, err := net.Miner.GenerateAndSubmitBlock(nil, -1, emptyTime) 587 if err != nil { 588 t.Fatalf("unable to generate block: %v", err) 589 } 590 } 591 592 // Before we sweep the anchor, we'll restart Alice. 593 if err := aliceRestart(); err != nil { 594 t.Fatalf("unable to restart alice: %v", err) 595 } 596 597 // Now that the channel has been closed, and Alice has an unconfirmed 598 // transaction spending the output produced by her anchor sweep, we'll 599 // mine a transaction that double spends the output. 600 thirdPartyAnchorSweep := genAnchorSweep(t, net, aliceAnchor, anchorCsv) 601 _, err = net.Miner.GenerateAndSubmitBlock( 602 []*dcrutil.Tx{thirdPartyAnchorSweep}, -1, emptyTime, 603 ) 604 if err != nil { 605 t.Fatalf("unable to generate block: %v", err) 606 } 607 608 // At this point, we should no longer find Alice's transaction that 609 // tried to sweep the anchor in her wallet. 610 assertTransactionNotInWallet(t.t, alice, aliceAnchor.SweepTx.TxHash()) 611 612 // In addition, the transaction she sent to sweep all her coins to the 613 // miner also should no longer be found. 614 assertTransactionNotInWallet(t.t, alice, *sweepAllTxID) 615 616 // The anchor should now show as being "lost", while the force close 617 // response is still present. 618 assertAnchorOutputLost(t, alice, chanPoint) 619 620 // At this point Alice's CSV output should already be fully spent and 621 // the channel marked as being resolved. We mine a block first, as so 622 // far we've been generating custom blocks this whole time.. 623 commitSweepOp := wire.OutPoint{ 624 Hash: *forceCloseTxID, 625 Index: 1, 626 } 627 assertSpendingTxInMempool( 628 t, net.Miner.Node, minerMempoolTimeout, commitSweepOp, 629 ) 630 _, err = net.Generate(1) 631 if err != nil { 632 t.Fatalf("unable to generate block: %v", err) 633 } 634 assertNumPendingChannels(t, alice, 0, 0, 0, 0) 635 }