github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_revocation_test.go (about) 1 package itest 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/decred/dcrd/chaincfg/chainhash" 12 "github.com/decred/dcrd/dcrutil/v4" 13 jsonrpctypes "github.com/decred/dcrd/rpc/jsonrpc/types/v4" 14 "github.com/decred/dcrlnd/lnrpc" 15 "github.com/decred/dcrlnd/lnrpc/watchtowerrpc" 16 "github.com/decred/dcrlnd/lnrpc/wtclientrpc" 17 "github.com/decred/dcrlnd/lntest" 18 "github.com/decred/dcrlnd/lntest/wait" 19 "github.com/go-errors/errors" 20 "github.com/stretchr/testify/require" 21 "matheusd.com/testctx" 22 ) 23 24 // testRevokedCloseRetribution tests that Carol is able carry out 25 // retribution in the event that she fails immediately after detecting Bob's 26 // breach txn in the mempool. 27 func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) { 28 const ( 29 chanAmt = defaultChanAmt 30 paymentAmt = 10000 31 numInvoices = 6 32 ) 33 34 // Carol will be the breached party. We set --nolisten to ensure Bob 35 // won't be able to connect to her and trigger the channel data 36 // protection logic automatically. We also can't have Carol 37 // automatically re-connect too early, otherwise DLP would be initiated 38 // instead of the breach we want to provoke. 39 carol := net.NewNode( 40 t.t, "Carol", 41 []string{"--hodl.exit-settle", "--nolisten", "--minbackoff=1h"}, 42 ) 43 defer shutdownAndAssert(net, t, carol) 44 45 // We must let Bob communicate with Carol before they are able to open 46 // channel, so we connect Bob and Carol, 47 net.ConnectNodes(t.t, carol, net.Bob) 48 49 // Before we make a channel, we'll load up Carol with some coins sent 50 // directly from the miner. 51 net.SendCoins(t.t, dcrutil.AtomsPerCoin, carol) 52 53 // In order to test Carol's response to an uncooperative channel 54 // closure by Bob, we'll first open up a channel between them with a 55 // 0.5 DCR value. 56 chanPoint := openChannelAndAssert( 57 t, net, carol, net.Bob, 58 lntest.OpenChannelParams{ 59 Amt: chanAmt, 60 }, 61 ) 62 63 // With the channel open, we'll create a few invoices for Bob that 64 // Carol will pay to in order to advance the state of the channel. 65 bobPayReqs, _, _, err := createPayReqs( 66 net.Bob, paymentAmt, numInvoices, 67 ) 68 if err != nil { 69 t.Fatalf("unable to create pay reqs: %v", err) 70 } 71 72 // Wait for Carol to receive the channel edge from the funding manager. 73 err = carol.WaitForNetworkChannelOpen(chanPoint) 74 if err != nil { 75 t.Fatalf("carol didn't see the carol->bob channel before "+ 76 "timeout: %v", err) 77 } 78 79 // Send payments from Carol to Bob using 3 of Bob's payment hashes 80 // generated above. 81 err = completePaymentRequests( 82 carol, carol.RouterClient, bobPayReqs[:numInvoices/2], true, 83 ) 84 if err != nil { 85 t.Fatalf("unable to send payments: %v", err) 86 } 87 88 // Next query for Bob's channel state, as we sent 3 payments of 10k 89 // atoms each, Bob should now see his balance as being 30k atoms. 90 var bobChan *lnrpc.Channel 91 var predErr error 92 err = wait.Predicate(func() bool { 93 bChan, err := getChanInfo(net.Bob) 94 if err != nil { 95 t.Fatalf("unable to get bob's channel info: %v", err) 96 } 97 if bChan.LocalBalance != 30000 { 98 predErr = fmt.Errorf("bob's balance is incorrect, "+ 99 "got %v, expected %v", bChan.LocalBalance, 100 30000) 101 return false 102 } 103 104 bobChan = bChan 105 return true 106 }, defaultTimeout) 107 if err != nil { 108 t.Fatalf("%v", predErr) 109 } 110 111 // Grab Bob's current commitment height (update number), we'll later 112 // revert him to this state after additional updates to force him to 113 // broadcast this soon to be revoked state. 114 bobStateNumPreCopy := bobChan.NumUpdates 115 116 // With the temporary file created, copy Bob's current state into the 117 // temporary file we created above. Later after more updates, we'll 118 // restore this state. 119 if err := net.BackupDb(net.Bob); err != nil { 120 t.Fatalf("unable to copy database files: %v", err) 121 } 122 123 // Reconnect the peers after the restart that was needed for the db 124 // backup. 125 net.EnsureConnected(t.t, carol, net.Bob) 126 127 // Finally, send payments from Carol to Bob, consuming Bob's remaining 128 // payment hashes. 129 err = completePaymentRequests( 130 carol, carol.RouterClient, bobPayReqs[numInvoices/2:], true, 131 ) 132 if err != nil { 133 t.Fatalf("unable to send payments: %v", err) 134 } 135 136 bobChan, err = getChanInfo(net.Bob) 137 if err != nil { 138 t.Fatalf("unable to get bob chan info: %v", err) 139 } 140 141 // Disconnect the nodes to prevent Carol trying to reconnect to Bob after 142 // Bob is restarted and fixing the wrong state. 143 err = net.DisconnectNodes(carol, net.Bob) 144 if err != nil { 145 t.Fatalf("unable to disconnect carol and bob: %v", err) 146 } 147 148 // Now we shutdown Bob, copying over the his temporary database state 149 // which has the *prior* channel state over his current most up to date 150 // state. With this, we essentially force Bob to travel back in time 151 // within the channel's history. 152 if err = net.RestartNode(net.Bob, func() error { 153 return net.RestoreDb(net.Bob) 154 }); err != nil { 155 t.Fatalf("unable to restart node: %v", err) 156 } 157 158 // Now query for Bob's channel state, it should show that he's at a 159 // state number in the past, not the *latest* state. 160 bobChan, err = getChanInfo(net.Bob) 161 if err != nil { 162 t.Fatalf("unable to get bob chan info: %v", err) 163 } 164 if bobChan.NumUpdates != bobStateNumPreCopy { 165 t.Fatalf("db copy failed: %v", bobChan.NumUpdates) 166 } 167 168 // Now force Bob to execute a *force* channel closure by unilaterally 169 // broadcasting his current channel state. This is actually the 170 // commitment transaction of a prior *revoked* state, so he'll soon 171 // feel the wrath of Carol's retribution. 172 force := true 173 closeUpdates, _, err := net.CloseChannel( 174 net.Bob, chanPoint, force, 175 ) 176 require.NoError(t.t, err, "unable to close channel") 177 178 // Wait for Bob's breach transaction to show up in the mempool to ensure 179 // that Carol's node has started waiting for confirmations. 180 _, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 181 if err != nil { 182 t.Fatalf("unable to find Bob's breach tx in mempool: %v", err) 183 } 184 185 // Here, Carol sees Bob's breach transaction in the mempool, but is waiting 186 // for it to confirm before continuing her retribution. We restart Carol to 187 // ensure that she is persisting her retribution state and continues 188 // watching for the breach transaction to confirm even after her node 189 // restarts. 190 if err := net.RestartNode(carol, nil); err != nil { 191 t.Fatalf("unable to restart Carol's node: %v", err) 192 } 193 194 // Finally, generate a single block, wait for the final close status 195 // update, then ensure that the closing transaction was included in the 196 // block. 197 block := mineBlocks(t, net, 1, 1)[0] 198 199 breachTXID, err := net.WaitForChannelClose(closeUpdates) 200 if err != nil { 201 t.Fatalf("error while waiting for channel close: %v", err) 202 } 203 assertTxInBlock(t, block, breachTXID) 204 205 // Query the mempool for Carol's justice transaction, this should be 206 // broadcast as Bob's contract breaching transaction gets confirmed 207 // above. 208 justiceTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 209 if err != nil { 210 t.Fatalf("unable to find Carol's justice tx in mempool: %v", err) 211 } 212 time.Sleep(100 * time.Millisecond) 213 214 // Query for the mempool transaction found above. Then assert that all 215 // the inputs of this transaction are spending outputs generated by 216 // Bob's breach transaction above. 217 justiceTx, err := net.Miner.Node.GetRawTransaction(context.Background(), justiceTXID) 218 if err != nil { 219 t.Fatalf("unable to query for justice tx: %v", err) 220 } 221 for _, txIn := range justiceTx.MsgTx().TxIn { 222 if !bytes.Equal(txIn.PreviousOutPoint.Hash[:], breachTXID[:]) { 223 t.Fatalf("justice tx not spending commitment utxo "+ 224 "instead is: %v", txIn.PreviousOutPoint) 225 } 226 } 227 228 // We restart Carol here to ensure that she persists her retribution state 229 // and successfully continues exacting retribution after restarting. At 230 // this point, Carol has broadcast the justice transaction, but it hasn't 231 // been confirmed yet; when Carol restarts, she should start waiting for 232 // the justice transaction to confirm again. 233 if err := net.RestartNode(carol, nil); err != nil { 234 t.Fatalf("unable to restart Carol's node: %v", err) 235 } 236 237 // Now mine a block, this transaction should include Carol's justice 238 // transaction which was just accepted into the mempool. 239 block = mineBlocks(t, net, 1, 1)[0] 240 241 // The block should have exactly *two* transactions, one of which is 242 // the justice transaction. 243 if len(block.Transactions) != 2 { 244 t.Fatalf("transaction wasn't mined") 245 } 246 justiceSha := block.Transactions[1].TxHash() 247 if !bytes.Equal(justiceTx.Hash()[:], justiceSha[:]) { 248 t.Fatalf("justice tx wasn't mined") 249 } 250 251 assertNodeNumChannels(t, carol, 0) 252 253 // Mine enough blocks for Bob's channel arbitrator to wrap up the 254 // references to the breached channel. The chanarb waits for commitment 255 // tx's confHeight+CSV-1 blocks and since we've already mined one that 256 // included the justice tx we only need to mine extra DefaultCSV-2 257 // blocks to unlock it. 258 mineBlocks(t, net, lntest.DefaultCSV-2, 0) 259 260 assertNumPendingChannels(t, net.Bob, 0, 0, 0, 0) 261 } 262 263 // testRevokedCloseRetributionZeroValueRemoteOutput tests that Dave is able 264 // carry out retribution in the event that he fails in state where the remote 265 // commitment output has zero-value. 266 func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness, 267 t *harnessTest) { 268 269 const ( 270 chanAmt = defaultChanAmt 271 paymentAmt = 10000 272 numInvoices = 6 273 ) 274 275 // Since we'd like to test some multi-hop failure scenarios, we'll 276 // introduce another node into our test network: Carol. 277 carol := net.NewNode(t.t, "Carol", []string{"--hodl.exit-settle"}) 278 defer shutdownAndAssert(net, t, carol) 279 280 // Dave will be the breached party. We set --nolisten to ensure Carol 281 // won't be able to connect to him and trigger the channel data 282 // protection logic automatically. We also can't have Dave automatically 283 // re-connect too early, otherwise DLP would be initiated instead of the 284 // breach we want to provoke. 285 dave := net.NewNode( 286 t.t, "Dave", 287 []string{"--hodl.exit-settle", "--nolisten", "--minbackoff=1h"}, 288 ) 289 defer shutdownAndAssert(net, t, dave) 290 291 // We must let Dave have an open channel before he can send a node 292 // announcement, so we open a channel with Carol, 293 net.ConnectNodes(t.t, dave, carol) 294 295 // Before we make a channel, we'll load up Dave with some coins sent 296 // directly from the miner. 297 net.SendCoins(t.t, dcrutil.AtomsPerCoin, dave) 298 299 // In order to test Dave's response to an uncooperative channel 300 // closure by Carol, we'll first open up a channel between them with a 301 // 0.5 DCR value. 302 chanPoint := openChannelAndAssert( 303 t, net, dave, carol, 304 lntest.OpenChannelParams{ 305 Amt: chanAmt, 306 }, 307 ) 308 309 // With the channel open, we'll create a few invoices for Carol that 310 // Dave will pay to in order to advance the state of the channel. 311 carolPayReqs, _, _, err := createPayReqs( 312 carol, paymentAmt, numInvoices, 313 ) 314 if err != nil { 315 t.Fatalf("unable to create pay reqs: %v", err) 316 } 317 318 // Wait for Dave to receive the channel edge from the funding manager. 319 err = dave.WaitForNetworkChannelOpen(chanPoint) 320 if err != nil { 321 t.Fatalf("dave didn't see the dave->carol channel before "+ 322 "timeout: %v", err) 323 } 324 325 // Next query for Carol's channel state, as we sent 0 payments, Carol 326 // should now see her balance as being 0 atoms. 327 carolChan, err := getChanInfo(carol) 328 if err != nil { 329 t.Fatalf("unable to get carol's channel info: %v", err) 330 } 331 if carolChan.LocalBalance != 0 { 332 t.Fatalf("carol's balance is incorrect, got %v, expected %v", 333 carolChan.LocalBalance, 0) 334 } 335 336 // Grab Carol's current commitment height (update number), we'll later 337 // revert her to this state after additional updates to force her to 338 // broadcast this soon to be revoked state. 339 carolStateNumPreCopy := carolChan.NumUpdates 340 341 // With the temporary file created, copy Carol's current state into the 342 // temporary file we created above. Later after more updates, we'll 343 // restore this state. 344 if err := net.BackupDb(carol); err != nil { 345 t.Fatalf("unable to copy database files: %v", err) 346 } 347 348 // Reconnect the peers after the restart that was needed for the db 349 // backup. 350 net.EnsureConnected(t.t, dave, carol) 351 352 // Finally, send payments from Dave to Carol, consuming Carol's 353 // remaining payment hashes. 354 err = completePaymentRequests( 355 dave, dave.RouterClient, carolPayReqs, false, 356 ) 357 if err != nil { 358 t.Fatalf("unable to send payments: %v", err) 359 } 360 361 _, err = getChanInfo(carol) 362 if err != nil { 363 t.Fatalf("unable to get carol chan info: %v", err) 364 } 365 366 // Disconnect Dave from Carol, so that upon Carol's restart he doesn't 367 // try to automatically reconnect and alert her of the changed state. 368 err = net.DisconnectNodes(dave, carol) 369 if err != nil { 370 t.Fatalf("unable to disconnect dave and carol: %v", err) 371 } 372 373 // Now we shutdown Carol, copying over the her temporary database state 374 // which has the *prior* channel state over her current most up to date 375 // state. With this, we essentially force Carol to travel back in time 376 // within the channel's history. 377 if err = net.RestartNode(carol, func() error { 378 return net.RestoreDb(carol) 379 }); err != nil { 380 t.Fatalf("unable to restart node: %v", err) 381 } 382 383 // Now query for Carol's channel state, it should show that she's at a 384 // state number in the past, not the *latest* state. 385 carolChan, err = getChanInfo(carol) 386 if err != nil { 387 t.Fatalf("unable to get carol chan info: %v", err) 388 } 389 if carolChan.NumUpdates != carolStateNumPreCopy { 390 t.Fatalf("db copy failed: %v", carolChan.NumUpdates) 391 } 392 393 // Now force Carol to execute a *force* channel closure by unilaterally 394 // broadcasting her current channel state. This is actually the 395 // commitment transaction of a prior *revoked* state, so she'll soon 396 // feel the wrath of Dave's retribution. 397 force := true 398 closeUpdates, closeTxID, closeErr := net.CloseChannel( 399 carol, chanPoint, force, 400 ) 401 require.NoError(t.t, closeErr, "unable to close channel") 402 403 // Query the mempool for the breaching closing transaction, this should 404 // be broadcast by Carol when she force closes the channel above. 405 txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 406 if err != nil { 407 t.Fatalf("unable to find Carol's force close tx in mempool: %v", 408 err) 409 } 410 if *txid != *closeTxID { 411 t.Fatalf("expected closeTx(%v) in mempool, instead found %v", 412 closeTxID, txid) 413 } 414 415 // Finally, generate a single block, wait for the final close status 416 // update, then ensure that the closing transaction was included in the 417 // block. 418 block := mineBlocks(t, net, 1, 1)[0] 419 420 // Give Dave some time to process and broadcast the brach transaction 421 time.Sleep(time.Second * 3) 422 423 // Here, Dave receives a confirmation of Carol's breach transaction. 424 // We restart Dave to ensure that he is persisting his retribution 425 // state and continues exacting justice after his node restarts. 426 if err := net.RestartNode(dave, nil); err != nil { 427 t.Fatalf("unable to stop Dave's node: %v", err) 428 } 429 430 breachTXID, err := net.WaitForChannelClose(closeUpdates) 431 if err != nil { 432 t.Fatalf("error while waiting for channel close: %v", err) 433 } 434 assertTxInBlock(t, block, breachTXID) 435 436 // Query the mempool for Dave's justice transaction, this should be 437 // broadcast as Carol's contract breaching transaction gets confirmed 438 // above. 439 justiceTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 440 if err != nil { 441 t.Fatalf("unable to find Dave's justice tx in mempool: %v", 442 err) 443 } 444 time.Sleep(100 * time.Millisecond) 445 446 // Query for the mempool transaction found above. Then assert that all 447 // the inputs of this transaction are spending outputs generated by 448 // Carol's breach transaction above. 449 justiceTx, err := net.Miner.Node.GetRawTransaction(context.Background(), justiceTXID) 450 if err != nil { 451 t.Fatalf("unable to query for justice tx: %v", err) 452 } 453 for _, txIn := range justiceTx.MsgTx().TxIn { 454 if !bytes.Equal(txIn.PreviousOutPoint.Hash[:], breachTXID[:]) { 455 t.Fatalf("justice tx not spending commitment utxo "+ 456 "instead is: %v", txIn.PreviousOutPoint) 457 } 458 } 459 460 // We restart Dave here to ensure that he persists his retribution state 461 // and successfully continues exacting retribution after restarting. At 462 // this point, Dave has broadcast the justice transaction, but it hasn't 463 // been confirmed yet; when Dave restarts, he should start waiting for 464 // the justice transaction to confirm again. 465 if err := net.RestartNode(dave, nil); err != nil { 466 t.Fatalf("unable to restart Dave's node: %v", err) 467 } 468 469 // Now mine a block, this transaction should include Dave's justice 470 // transaction which was just accepted into the mempool. 471 block = mineBlocks(t, net, 1, 1)[0] 472 473 // The block should have exactly *two* transactions, one of which is 474 // the justice transaction. 475 if len(block.Transactions) != 2 { 476 t.Fatalf("transaction wasn't mined") 477 } 478 justiceSha := block.Transactions[1].TxHash() 479 if !bytes.Equal(justiceTx.Hash()[:], justiceSha[:]) { 480 t.Fatalf("justice tx wasn't mined") 481 } 482 483 assertNodeNumChannels(t, dave, 0) 484 } 485 486 // testRevokedCloseRetributionRemoteHodl tests that Dave properly responds to a 487 // channel breach made by the remote party, specifically in the case that the 488 // remote party breaches before settling extended HTLCs. 489 // 490 // This test specifically suspends Carol after she sends her breach commitment 491 // so that we test the scenario where she does _not_ go to the second level 492 // before Dave is able to exact justice. 493 func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness, 494 t *harnessTest) { 495 496 const ( 497 initialBalance = int64(dcrutil.AtomsPerCoin) 498 chanAmt = defaultChanAmt 499 pushAmt = 400000 500 paymentAmt = 20000 501 numInvoices = 6 502 ) 503 504 // Since this test will result in the counterparty being left in a 505 // weird state, we will introduce another node into our test network: 506 // Carol. 507 carol := net.NewNode(t.t, "Carol", []string{"--hodl.exit-settle"}) 508 defer shutdownAndAssert(net, t, carol) 509 510 // We'll also create a new node Dave, who will have a channel with 511 // Carol, and also use similar settings so we can broadcast a commit 512 // with active HTLCs. Dave will be the breached party. We set 513 // --nolisten to ensure Carol won't be able to connect to him and 514 // trigger the channel data protection logic automatically. 515 dave := net.NewNode( 516 t.t, "Dave", 517 []string{"--hodl.exit-settle", "--nolisten"}, 518 ) 519 defer shutdownAndAssert(net, t, dave) 520 521 // We must let Dave communicate with Carol before they are able to open 522 // channel, so we connect Dave and Carol, 523 net.ConnectNodes(t.t, dave, carol) 524 525 // Before we make a channel, we'll load up Dave with some coins sent 526 // directly from the miner. 527 net.SendCoins(t.t, dcrutil.AtomsPerCoin, dave) 528 529 // In order to test Dave's response to an uncooperative channel closure 530 // by Carol, we'll first open up a channel between them with a 531 // defaultChanAmt (2^24) atoms value. 532 chanPoint := openChannelAndAssert( 533 t, net, dave, carol, 534 lntest.OpenChannelParams{ 535 Amt: chanAmt, 536 PushAmt: pushAmt, 537 }, 538 ) 539 540 // Store the channel type for later. 541 cType, err := channelCommitType(carol, chanPoint) 542 if err != nil { 543 t.Fatalf("unable to get channel type: %v", err) 544 } 545 546 // With the channel open, we'll create a few invoices for Carol that 547 // Dave will pay to in order to advance the state of the channel. 548 carolPayReqs, _, _, err := createPayReqs( 549 carol, paymentAmt, numInvoices, 550 ) 551 if err != nil { 552 t.Fatalf("unable to create pay reqs: %v", err) 553 } 554 555 // We'll introduce a closure to validate that Carol's current balance 556 // matches the given expected amount. 557 checkCarolBalance := func(expectedAmt int64) { 558 carolChan, err := getChanInfo(carol) 559 if err != nil { 560 t.Fatalf("unable to get carol's channel info: %v", err) 561 } 562 if carolChan.LocalBalance != expectedAmt { 563 t.Fatalf("carol's balance is incorrect, "+ 564 "got %v, expected %v", carolChan.LocalBalance, 565 expectedAmt) 566 } 567 } 568 569 // We'll introduce another closure to validate that Carol's current 570 // number of updates is at least as large as the provided minimum 571 // number. 572 checkCarolNumUpdatesAtLeast := func(minimum uint64) { 573 carolChan, err := getChanInfo(carol) 574 if err != nil { 575 t.Fatalf("unable to get carol's channel info: %v", err) 576 } 577 if carolChan.NumUpdates < minimum { 578 t.Fatalf("carol's numupdates is incorrect, want %v "+ 579 "to be at least %v", carolChan.NumUpdates, 580 minimum) 581 } 582 } 583 584 // Wait for Dave to receive the channel edge from the funding manager. 585 err = dave.WaitForNetworkChannelOpen(chanPoint) 586 if err != nil { 587 t.Fatalf("dave didn't see the dave->carol channel before "+ 588 "timeout: %v", err) 589 } 590 591 // Ensure that carol's balance starts with the amount we pushed to her. 592 checkCarolBalance(pushAmt) 593 594 // Send payments from Dave to Carol using 3 of Carol's payment hashes 595 // generated above. 596 err = completePaymentRequests( 597 dave, dave.RouterClient, carolPayReqs[:numInvoices/2], false, 598 ) 599 if err != nil { 600 t.Fatalf("unable to send payments: %v", err) 601 } 602 603 // At this point, we'll also send over a set of HTLC's from Carol to 604 // Dave. This ensures that the final revoked transaction has HTLC's in 605 // both directions. 606 davePayReqs, _, _, err := createPayReqs( 607 dave, paymentAmt, numInvoices, 608 ) 609 if err != nil { 610 t.Fatalf("unable to create pay reqs: %v", err) 611 } 612 613 // Send payments from Carol to Dave using 3 of Dave's payment hashes 614 // generated above. 615 err = completePaymentRequests( 616 carol, carol.RouterClient, davePayReqs[:numInvoices/2], false, 617 ) 618 if err != nil { 619 t.Fatalf("unable to send payments: %v", err) 620 } 621 622 // Wait until the channel has acknowledged the pending htlc count. 623 err = waitForPendingHtlcs(carol, chanPoint, numInvoices) 624 if err != nil { 625 t.Fatalf("unable to wait for pending htlcs: %v", err) 626 } 627 628 // Next query for Carol's channel state, as we sent 3 payments of 10k 629 // atoms each, however Carol should now see her balance as being 630 // equal to the push amount in atoms since she has not settled. 631 carolChan, err := getChanInfo(carol) 632 if err != nil { 633 t.Fatalf("unable to get carol's channel info: %v", err) 634 } 635 636 // Grab Carol's current commitment height (update number), we'll later 637 // revert her to this state after additional updates to force her to 638 // broadcast this soon to be revoked state. 639 carolStateNumPreCopy := carolChan.NumUpdates 640 641 // Ensure that carol's balance still reflects the original amount we 642 // pushed to her, minus the HTLCs she just sent to Dave. 643 checkCarolBalance(pushAmt - 3*paymentAmt) 644 645 // Since Carol has not settled, she should only see at least one update 646 // to her channel. 647 checkCarolNumUpdatesAtLeast(1) 648 649 // With the temporary file created, copy Carol's current state into the 650 // temporary file we created above. Later after more updates, we'll 651 // restore this state. 652 if err := net.BackupDb(carol); err != nil { 653 t.Fatalf("unable to copy database files: %v", err) 654 } 655 656 // Reconnect the peers after the restart that was needed for the db 657 // backup. 658 net.EnsureConnected(t.t, dave, carol) 659 660 // Finally, send payments from Dave to Carol, consuming Carol's 661 // remaining payment hashes. 662 err = completePaymentRequests( 663 dave, dave.RouterClient, carolPayReqs[numInvoices/2:], false, 664 ) 665 if err != nil { 666 t.Fatalf("unable to send payments: %v", err) 667 } 668 669 // Ensure that carol's balance still shows the amount we originally 670 // pushed to her (minus the HTLCs she sent to Bob), and that at least 671 // one more update has occurred. 672 time.Sleep(500 * time.Millisecond) 673 checkCarolBalance(pushAmt - 3*paymentAmt) 674 checkCarolNumUpdatesAtLeast(carolStateNumPreCopy + 1) 675 676 // Disconnect Carol and Dave, so that the channel isn't corrected once Carol 677 // is restarted. 678 err = net.DisconnectNodes(dave, carol) 679 if err != nil { 680 t.Fatalf("unable to disconnect dave and carol: %v", err) 681 } 682 683 time.Sleep(500 * time.Millisecond) 684 685 // Now we shutdown Carol, copying over the her temporary database state 686 // which has the *prior* channel state over her current most up to date 687 // state. With this, we essentially force Carol to travel back in time 688 // within the channel's history. 689 if err = net.RestartNode(carol, func() error { 690 return net.RestoreDb(carol) 691 }); err != nil { 692 t.Fatalf("unable to restart node: %v", err) 693 } 694 695 time.Sleep(200 * time.Millisecond) 696 697 // Ensure that Carol's view of the channel is consistent with the state 698 // of the channel just before it was snapshotted. 699 checkCarolBalance(pushAmt - 3*paymentAmt) 700 checkCarolNumUpdatesAtLeast(1) 701 702 // Now query for Carol's channel state, it should show that she's at a 703 // state number in the past, *not* the latest state. 704 carolChan, err = getChanInfo(carol) 705 if err != nil { 706 t.Fatalf("unable to get carol chan info: %v", err) 707 } 708 if carolChan.NumUpdates != carolStateNumPreCopy { 709 t.Fatalf("db copy failed: %v", carolChan.NumUpdates) 710 } 711 712 // Now force Carol to execute a *force* channel closure by unilaterally 713 // broadcasting her current channel state. This is actually the 714 // commitment transaction of a prior *revoked* state, so she'll soon 715 // feel the wrath of Dave's retribution. 716 force := true 717 _, closeTxID, err := net.CloseChannel( 718 carol, chanPoint, force, 719 ) 720 if err != nil { 721 t.Fatalf("unable to close channel: %v", err) 722 } 723 724 // Query the mempool for the breaching closing transaction, this should 725 // be broadcast by Carol when she force closes the channel above. 726 txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 727 if err != nil { 728 t.Fatalf("unable to find Carol's force close tx in mempool: %v", 729 err) 730 } 731 if *txid != *closeTxID { 732 t.Fatalf("expected closeTx(%v) in mempool, instead found %v", 733 closeTxID, txid) 734 } 735 time.Sleep(200 * time.Millisecond) 736 737 // Suspend Carol, so that she won't have a chance to go to the second 738 // level to redeem the coins before Dave sees the breach tx. 739 resumeCarol, err := net.SuspendNode(carol) 740 if err != nil { 741 t.Fatalf("unable to suspend carol: %v", err) 742 } 743 744 // Generate a single block to mine the breach transaction and ensure 745 // that it was mined. 746 block := mineBlocks(t, net, 1, 1)[0] 747 assertTxInBlock(t, block, closeTxID) 748 749 // Wait so Dave receives a confirmation of Carol's breach transaction. 750 time.Sleep(2 * time.Second) 751 752 // We restart Dave to ensure that he is persisting his retribution 753 // state and continues exacting justice after her node restarts. 754 if err := net.RestartNode(dave, nil); err != nil { 755 t.Fatalf("unable to stop Dave's node: %v", err) 756 } 757 758 // Query the mempool for Dave's justice transaction. This should be 759 // broadcast as Carol's contract breaching transaction gets confirmed 760 // above. To find it, we'll search through the mempool for a tx that 761 // matches the number of expected inputs in the justice tx. 762 var predErr error 763 var justiceTxid *chainhash.Hash 764 exNumInputs := 2 + numInvoices 765 errNotFound := fmt.Errorf("justice tx with %d inputs not found", exNumInputs) 766 findJusticeTx := func() (*chainhash.Hash, error) { 767 mempool, err := net.Miner.Node.GetRawMempool(context.Background(), jsonrpctypes.GRMRegular) 768 if err != nil { 769 return nil, fmt.Errorf("unable to get mempool from "+ 770 "miner: %v", err) 771 } 772 773 for _, txid := range mempool { 774 // Check that the justice tx has the appropriate number 775 // of inputs. 776 tx, err := net.Miner.Node.GetRawTransaction(context.Background(), txid) 777 if err != nil { 778 return nil, fmt.Errorf("unable to query for "+ 779 "txs: %v", err) 780 } 781 782 if len(tx.MsgTx().TxIn) == exNumInputs { 783 return txid, nil 784 } 785 } 786 return nil, errNotFound 787 } 788 789 err = wait.Predicate(func() bool { 790 txid, err := findJusticeTx() 791 if err != nil { 792 predErr = err 793 return false 794 } 795 796 justiceTxid = txid 797 return true 798 }, time.Second*10) 799 if err != nil { 800 t.Fatalf("unable to find dave's justice tx: %v", predErr) 801 } 802 803 // Grab some transactions which will be needed for future checks. 804 justiceTx, err := net.Miner.Node.GetRawTransaction(context.Background(), justiceTxid) 805 if err != nil { 806 t.Fatalf("unable to query for justice tx: %v", err) 807 } 808 809 breachTx, err := net.Miner.Node.GetRawTransaction(context.Background(), closeTxID) 810 if err != nil { 811 t.Fatalf("unable to query for breach tx: %v", err) 812 } 813 814 fundingTxId, err := chainhash.NewHash(chanPoint.GetFundingTxidBytes()) 815 if err != nil { 816 t.Fatalf("chainpoint id bytes not a chainhash: %v", err) 817 } 818 fundingTx, err := net.Miner.Node.GetRawTransaction(context.Background(), fundingTxId) 819 if err != nil { 820 t.Fatalf("unable to query for funding tx: %v", err) 821 } 822 823 // Check that all the inputs of the justice transaction are spending 824 // outputs generated by Carol's breach transaction above. We'll track 825 // the total amount sent into the justice tx so we can check for Dave's 826 // balance later on. 827 var totalJusticeIn int64 828 for _, txIn := range justiceTx.MsgTx().TxIn { 829 if bytes.Equal(txIn.PreviousOutPoint.Hash[:], closeTxID[:]) { 830 txo := breachTx.MsgTx().TxOut[txIn.PreviousOutPoint.Index] 831 totalJusticeIn += txo.Value 832 continue 833 } 834 835 t.Fatalf("justice tx not spending commitment utxo "+ 836 "instead is: %v", txIn.PreviousOutPoint) 837 } 838 839 // The amount returned by the justice tx must be the total channel 840 // amount minus the (breached) commitment tx fee and the justice tx fee 841 // itself. 842 jtx := justiceTx.MsgTx() 843 commitFee := int64(calcStaticFee(cType, 6)) 844 justiceFee := totalJusticeIn - jtx.TxOut[0].Value 845 expectedJusticeOut := int64(chanAmt) - commitFee - justiceFee 846 if jtx.TxOut[0].Value != expectedJusticeOut { 847 t.Fatalf("wrong value returned by justice tx; expected=%d "+ 848 "actual=%d chanAmt=%d commitFee=%d justiceFee=%d", 849 expectedJusticeOut, jtx.TxOut[0].Value, chanAmt, 850 commitFee, justiceFee) 851 } 852 853 // Restart Carol. She should not be able to do anything else regarding 854 // the breached channel. 855 err = resumeCarol() 856 if err != nil { 857 t.Fatalf("unable to resume Carol: %v", err) 858 } 859 860 // We restart Dave here to ensure that he persists he retribution state 861 // and successfully continues exacting retribution after restarting. At 862 // this point, Dave has broadcast the justice transaction, but it 863 // hasn't been confirmed yet; when Dave restarts, he should start 864 // waiting for the justice transaction to confirm again. 865 if err := net.RestartNode(dave, nil); err != nil { 866 t.Fatalf("unable to restart Dave's node: %v", err) 867 } 868 869 // Now mine a block. This should include Dave's justice transaction 870 // which was just accepted into the mempool. 871 block = mineBlocks(t, net, 1, 1)[0] 872 assertTxInBlock(t, block, justiceTxid) 873 874 // Dave and Carol should have no open channels. 875 assertNodeNumChannels(t, dave, 0) 876 assertNodeNumChannels(t, carol, 0) 877 878 // We'll now check that the total balance of each party is the one we 879 // expect. Introduce a new test closure. 880 checkTotalBalance := func(node *lntest.HarnessNode, expectedAmt int64) { 881 balances, err := node.WalletBalance(testctx.New(t), &lnrpc.WalletBalanceRequest{}) 882 if err != nil { 883 t.Fatalf("unable to query node balance: %v", err) 884 } 885 if balances.TotalBalance != expectedAmt { 886 t.Fatalf("balance is incorrect, "+ 887 "got %v, expected %v", balances.TotalBalance, 888 expectedAmt) 889 } 890 } 891 892 // Carol should not have any balance, because even though she was sent 893 // coins via an HTLC, she chose to broadcast an older commitment tx and 894 // forfeit her coins. 895 checkTotalBalance(carol, 0) 896 897 // Dave should the initial amount sent to him for funding channels 898 // minus the fees required to broadcast the breached commitment with 6 899 // HTLCs and the justice tx. 900 fundingFee := recordedTxFee(fundingTx.MsgTx()) 901 checkTotalBalance(dave, initialBalance-commitFee-justiceFee-fundingFee) 902 } 903 904 // testRevokedCloseRetributionAltruistWatchtower establishes a channel between 905 // Carol and Dave, where Carol is using a third node Willy as her watchtower. 906 // After sending some payments, Dave reverts his state and force closes to 907 // trigger a breach. Carol is kept offline throughout the process and the test 908 // asserts that Willy responds by broadcasting the justice transaction on 909 // Carol's behalf sweeping her funds without a reward. 910 func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness, 911 t *harnessTest) { 912 913 testCases := []struct { 914 name string 915 anchors bool 916 }{{ 917 name: "anchors", 918 anchors: true, 919 }, { 920 name: "legacy", 921 anchors: false, 922 }} 923 924 for _, tc := range testCases { 925 tc := tc 926 927 success := t.t.Run(tc.name, func(tt *testing.T) { 928 ht := newHarnessTest(tt, net) 929 ht.RunTestCase(&testCase{ 930 name: tc.name, 931 test: func(net1 *lntest.NetworkHarness, t1 *harnessTest) { 932 testRevokedCloseRetributionAltruistWatchtowerCase( 933 net1, t1, tc.anchors, 934 ) 935 }, 936 }) 937 }) 938 939 if !success { 940 // Log failure time to help relate the lnd logs to the 941 // failure. 942 t.Logf("Failure time: %v", time.Now().Format( 943 "2006-01-02 15:04:05.000", 944 )) 945 946 break 947 } 948 } 949 } 950 951 func testRevokedCloseRetributionAltruistWatchtowerCase( 952 net *lntest.NetworkHarness, t *harnessTest, anchors bool) { 953 954 ctxb := context.Background() 955 const ( 956 chanAmt = defaultChanAmt 957 paymentAmt = 10000 958 numInvoices = 6 959 externalIP = "1.2.3.4" 960 ) 961 962 // Since we'd like to test some multi-hop failure scenarios, we'll 963 // introduce another node into our test network: Carol. 964 carolArgs := []string{"--hodl.exit-settle"} 965 if anchors { 966 carolArgs = append(carolArgs, "--protocol.anchors") 967 } 968 carol := net.NewNode(t.t, "Carol", carolArgs) 969 defer shutdownAndAssert(net, t, carol) 970 971 // Willy the watchtower will protect Dave from Carol's breach. He will 972 // remain online in order to punish Carol on Dave's behalf, since the 973 // breach will happen while Dave is offline. 974 willy := net.NewNode(t.t, "Willy", []string{ 975 "--watchtower.active", 976 "--watchtower.externalip=" + externalIP, 977 }) 978 defer shutdownAndAssert(net, t, willy) 979 980 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 981 willyInfo, err := willy.Watchtower.GetInfo( 982 ctxt, &watchtowerrpc.GetInfoRequest{}, 983 ) 984 if err != nil { 985 t.Fatalf("unable to getinfo from willy: %v", err) 986 } 987 988 // Assert that Willy has one listener and it is 0.0.0.0:9911 or 989 // [::]:9911. Since no listener is explicitly specified, one of these 990 // should be the default depending on whether the host supports IPv6 or 991 // not. 992 if len(willyInfo.Listeners) != 1 { 993 t.Fatalf("Willy should have 1 listener, has %d", 994 len(willyInfo.Listeners)) 995 } 996 listener := willyInfo.Listeners[0] 997 if listener != "0.0.0.0:9911" && listener != "[::]:9911" { 998 t.Fatalf("expected listener on 0.0.0.0:9911 or [::]:9911, "+ 999 "got %v", listener) 1000 } 1001 1002 // Assert the Willy's URIs properly display the chosen external IP. 1003 if len(willyInfo.Uris) != 1 { 1004 t.Fatalf("Willy should have 1 uri, has %d", 1005 len(willyInfo.Uris)) 1006 } 1007 if !strings.Contains(willyInfo.Uris[0], externalIP) { 1008 t.Fatalf("expected uri with %v, got %v", 1009 externalIP, willyInfo.Uris[0]) 1010 } 1011 1012 // Dave will be the breached party. We set --nolisten to ensure Carol 1013 // won't be able to connect to him and trigger the channel data 1014 // protection logic automatically. 1015 daveArgs := []string{ 1016 "--nolisten", 1017 "--wtclient.active", 1018 } 1019 if anchors { 1020 daveArgs = append(daveArgs, "--protocol.anchors") 1021 } 1022 dave := net.NewNode(t.t, "Dave", daveArgs) 1023 defer shutdownAndAssert(net, t, dave) 1024 1025 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 1026 addTowerReq := &wtclientrpc.AddTowerRequest{ 1027 Pubkey: willyInfo.Pubkey, 1028 Address: listener, 1029 } 1030 if _, err = dave.WatchtowerClient.AddTower(ctxt, addTowerReq); err != nil { 1031 t.Fatalf("unable to add willy's watchtower: %v", err) 1032 } 1033 1034 // We must let Dave have an open channel before she can send a node 1035 // announcement, so we open a channel with Carol, 1036 net.ConnectNodes(t.t, dave, carol) 1037 1038 // Before we make a channel, we'll load up Dave with some coins sent 1039 // directly from the miner. 1040 net.SendCoins(t.t, dcrutil.AtomsPerCoin, dave) 1041 1042 // In order to test Dave's response to an uncooperative channel 1043 // closure by Carol, we'll first open up a channel between them with a 1044 // 0.5 DCR value. 1045 chanPoint := openChannelAndAssert( 1046 t, net, dave, carol, 1047 lntest.OpenChannelParams{ 1048 Amt: 3 * (chanAmt / 4), 1049 PushAmt: chanAmt / 4, 1050 }, 1051 ) 1052 1053 // With the channel open, we'll create a few invoices for Carol that 1054 // Dave will pay to in order to advance the state of the channel. 1055 carolPayReqs, _, _, err := createPayReqs( 1056 carol, paymentAmt, numInvoices, 1057 ) 1058 if err != nil { 1059 t.Fatalf("unable to create pay reqs: %v", err) 1060 } 1061 1062 // Wait for Dave to receive the channel edge from the funding manager. 1063 err = dave.WaitForNetworkChannelOpen(chanPoint) 1064 if err != nil { 1065 t.Fatalf("dave didn't see the dave->carol channel before "+ 1066 "timeout: %v", err) 1067 } 1068 1069 // Next query for Carol's channel state, as we sent 0 payments, Carol 1070 // should still see her balance as the push amount, which is 1/4 of the 1071 // capacity. 1072 carolChan, err := getChanInfo(carol) 1073 if err != nil { 1074 t.Fatalf("unable to get carol's channel info: %v", err) 1075 } 1076 if carolChan.LocalBalance != int64(chanAmt/4) { 1077 t.Fatalf("carol's balance is incorrect, got %v, expected %v", 1078 carolChan.LocalBalance, chanAmt/4) 1079 } 1080 1081 // Grab Carol's current commitment height (update number), we'll later 1082 // revert her to this state after additional updates to force him to 1083 // broadcast this soon to be revoked state. 1084 carolStateNumPreCopy := carolChan.NumUpdates 1085 1086 // With the temporary file created, copy Carol's current state into the 1087 // temporary file we created above. Later after more updates, we'll 1088 // restore this state. 1089 if err := net.BackupDb(carol); err != nil { 1090 t.Fatalf("unable to copy database files: %v", err) 1091 } 1092 1093 // Reconnect the peers after the restart that was needed for the db 1094 // backup. 1095 net.EnsureConnected(t.t, dave, carol) 1096 1097 // Finally, send payments from Dave to Carol, consuming Carol's remaining 1098 // payment hashes. 1099 err = completePaymentRequests( 1100 dave, dave.RouterClient, carolPayReqs, false, 1101 ) 1102 if err != nil { 1103 t.Fatalf("unable to send payments: %v", err) 1104 } 1105 1106 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 1107 daveBalReq := &lnrpc.WalletBalanceRequest{} 1108 daveBalResp, err := dave.WalletBalance(ctxt, daveBalReq) 1109 if err != nil { 1110 t.Fatalf("unable to get dave's balance: %v", err) 1111 } 1112 1113 davePreSweepBalance := daveBalResp.ConfirmedBalance 1114 1115 // Wait until the backup has been accepted by the watchtower before 1116 // shutting down Dave. 1117 err = wait.NoError(func() error { 1118 ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) 1119 defer cancel() 1120 bkpStats, err := dave.WatchtowerClient.Stats(ctxt, 1121 &wtclientrpc.StatsRequest{}, 1122 ) 1123 if err != nil { 1124 return err 1125 } 1126 if bkpStats == nil { 1127 return errors.New("no active backup sessions") 1128 } 1129 if bkpStats.NumBackups == 0 { 1130 return errors.New("no backups accepted") 1131 } 1132 return nil 1133 }, defaultTimeout) 1134 if err != nil { 1135 t.Fatalf("unable to verify backup task completed: %v", err) 1136 } 1137 1138 // Shutdown Dave to simulate going offline for an extended period of 1139 // time. Once he's not watching, Carol will try to breach the channel. 1140 restart, err := net.SuspendNode(dave) 1141 if err != nil { 1142 t.Fatalf("unable to suspend Dave: %v", err) 1143 } 1144 1145 // Now we shutdown Carol, copying over the his temporary database state 1146 // which has the *prior* channel state over his current most up to date 1147 // state. With this, we essentially force Carol to travel back in time 1148 // within the channel's history. 1149 if err = net.RestartNode(carol, func() error { 1150 return net.RestoreDb(carol) 1151 }); err != nil { 1152 t.Fatalf("unable to restart node: %v", err) 1153 } 1154 1155 // Now query for Carol's channel state, it should show that he's at a 1156 // state number in the past, not the *latest* state. 1157 carolChan, err = getChanInfo(carol) 1158 if err != nil { 1159 t.Fatalf("unable to get carol chan info: %v", err) 1160 } 1161 if carolChan.NumUpdates != carolStateNumPreCopy { 1162 t.Fatalf("db copy failed: %v", carolChan.NumUpdates) 1163 } 1164 1165 // Now force Carol to execute a *force* channel closure by unilaterally 1166 // broadcasting his current channel state. This is actually the 1167 // commitment transaction of a prior *revoked* state, so he'll soon 1168 // feel the wrath of Dave's retribution. 1169 closeUpdates, closeTxID, err := net.CloseChannel(carol, chanPoint, true) 1170 if err != nil { 1171 t.Fatalf("unable to close channel: %v", err) 1172 } 1173 1174 // Query the mempool for the breaching closing transaction, this should 1175 // be broadcast by Carol when she force closes the channel above. 1176 txid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 1177 if err != nil { 1178 t.Fatalf("unable to find Carol's force close tx in mempool: %v", 1179 err) 1180 } 1181 if *txid != *closeTxID { 1182 t.Fatalf("expected closeTx(%v) in mempool, instead found %v", 1183 closeTxID, txid) 1184 } 1185 1186 // Finally, generate a single block, wait for the final close status 1187 // update, then ensure that the closing transaction was included in the 1188 // block. 1189 block := mineBlocks(t, net, 1, 1)[0] 1190 1191 breachTXID, err := net.WaitForChannelClose(closeUpdates) 1192 if err != nil { 1193 t.Fatalf("error while waiting for channel close: %v", err) 1194 } 1195 assertTxInBlock(t, block, breachTXID) 1196 1197 // Query the mempool for Dave's justice transaction, this should be 1198 // broadcast as Carol's contract breaching transaction gets confirmed 1199 // above. 1200 justiceTXID, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) 1201 if err != nil { 1202 t.Fatalf("unable to find Dave's justice tx in mempool: %v", 1203 err) 1204 } 1205 time.Sleep(100 * time.Millisecond) 1206 1207 // Query for the mempool transaction found above. Then assert that all 1208 // the inputs of this transaction are spending outputs generated by 1209 // Carol's breach transaction above. 1210 justiceTx, err := net.Miner.Node.GetRawTransaction(context.Background(), justiceTXID) 1211 if err != nil { 1212 t.Fatalf("unable to query for justice tx: %v", err) 1213 } 1214 for _, txIn := range justiceTx.MsgTx().TxIn { 1215 if !bytes.Equal(txIn.PreviousOutPoint.Hash[:], breachTXID[:]) { 1216 t.Fatalf("justice tx not spending commitment utxo "+ 1217 "instead is: %v", txIn.PreviousOutPoint) 1218 } 1219 } 1220 1221 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 1222 willyBalReq := &lnrpc.WalletBalanceRequest{} 1223 willyBalResp, err := willy.WalletBalance(ctxt, willyBalReq) 1224 if err != nil { 1225 t.Fatalf("unable to get willy's balance: %v", err) 1226 } 1227 1228 if willyBalResp.ConfirmedBalance != 0 { 1229 t.Fatalf("willy should have 0 balance before mining "+ 1230 "justice transaction, instead has %d", 1231 willyBalResp.ConfirmedBalance) 1232 } 1233 1234 // Now mine a block, this transaction should include Dave's justice 1235 // transaction which was just accepted into the mempool. 1236 block = mineBlocks(t, net, 1, 1)[0] 1237 1238 // The block should have exactly *two* transactions, one of which is 1239 // the justice transaction. 1240 if len(block.Transactions) != 2 { 1241 t.Fatalf("transaction wasn't mined") 1242 } 1243 justiceSha := block.Transactions[1].TxHash() 1244 if !bytes.Equal(justiceTx.Hash()[:], justiceSha[:]) { 1245 t.Fatalf("justice tx wasn't mined") 1246 } 1247 1248 // Ensure that Willy doesn't get any funds, as he is acting as an 1249 // altruist watchtower. 1250 var predErr error 1251 err = wait.Invariant(func() bool { 1252 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 1253 willyBalReq := &lnrpc.WalletBalanceRequest{} 1254 willyBalResp, err := willy.WalletBalance(ctxt, willyBalReq) 1255 if err != nil { 1256 t.Fatalf("unable to get willy's balance: %v", err) 1257 } 1258 1259 if willyBalResp.ConfirmedBalance != 0 { 1260 predErr = fmt.Errorf("Expected Willy to have no funds "+ 1261 "after justice transaction was mined, found %v", 1262 willyBalResp) 1263 return false 1264 } 1265 1266 return true 1267 }, time.Second*5) 1268 if err != nil { 1269 t.Fatalf("%v", predErr) 1270 } 1271 1272 // Restart Dave, who will still think his channel with Carol is open. 1273 // We should him to detect the breach, but realize that the funds have 1274 // then been swept to his wallet by Willy. 1275 err = restart() 1276 if err != nil { 1277 t.Fatalf("unable to restart dave: %v", err) 1278 } 1279 1280 err = wait.Predicate(func() bool { 1281 ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) 1282 daveBalReq := &lnrpc.ChannelBalanceRequest{} 1283 daveBalResp, err := dave.ChannelBalance(ctxt, daveBalReq) 1284 if err != nil { 1285 t.Fatalf("unable to get dave's balance: %v", err) 1286 } 1287 1288 if daveBalResp.LocalBalance.Atoms != 0 { 1289 predErr = fmt.Errorf("Dave should end up with zero "+ 1290 "channel balance, instead has %d", 1291 daveBalResp.LocalBalance.Atoms) 1292 return false 1293 } 1294 1295 return true 1296 }, defaultTimeout) 1297 if err != nil { 1298 t.Fatalf("%v", predErr) 1299 } 1300 1301 assertNumPendingChannels(t, dave, 0, 0, 0, 0) 1302 1303 err = wait.Predicate(func() bool { 1304 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 1305 daveBalReq := &lnrpc.WalletBalanceRequest{} 1306 daveBalResp, err := dave.WalletBalance(ctxt, daveBalReq) 1307 if err != nil { 1308 t.Fatalf("unable to get dave's balance: %v", err) 1309 } 1310 1311 if daveBalResp.ConfirmedBalance <= davePreSweepBalance { 1312 predErr = fmt.Errorf("Dave should have more than %d "+ 1313 "after sweep, instead has %d", 1314 davePreSweepBalance, 1315 daveBalResp.ConfirmedBalance) 1316 return false 1317 } 1318 1319 return true 1320 }, defaultTimeout) 1321 if err != nil { 1322 t.Fatalf("%v", predErr) 1323 } 1324 1325 // Dave should have no open channels. 1326 assertNodeNumChannels(t, dave, 0) 1327 }