itest: test backup restore of script enforced lease channel type
This commit is contained in:
1 parent
0b0dd65c93
commit
e891dd0fd3
3 files changed
+148
-52
No files matched your search
+88
-29
@@ -1109,7 +1109,7 @@ func assertNumPendingChannels(t *harnessTest, node *lntest.HarnessNode,
|
|||||||
func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
||||||
carol *lntest.HarnessNode, carolStartingBalance int64,
|
carol *lntest.HarnessNode, carolStartingBalance int64,
|
||||||
dave *lntest.HarnessNode, daveStartingBalance int64,
|
dave *lntest.HarnessNode, daveStartingBalance int64,
|
||||||
anchors bool) {
|
commitType lnrpc.CommitmentType) {
|
||||||
|
|
||||||
// Increase the fee estimate so that the following force close tx will
|
// Increase the fee estimate so that the following force close tx will
|
||||||
// be cpfp'ed.
|
// be cpfp'ed.
|
||||||
@@ -1124,7 +1124,7 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// Upon reconnection, the nodes should detect that Dave is out of sync.
|
// Upon reconnection, the nodes should detect that Dave is out of sync.
|
||||||
// Carol should force close the channel using her latest commitment.
|
// Carol should force close the channel using her latest commitment.
|
||||||
expectedTxes := 1
|
expectedTxes := 1
|
||||||
if anchors {
|
if commitTypeHasAnchors(commitType) {
|
||||||
expectedTxes = 2
|
expectedTxes = 2
|
||||||
}
|
}
|
||||||
_, err := waitForNTxsInMempool(
|
_, err := waitForNTxsInMempool(
|
||||||
@@ -1151,13 +1151,6 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// Generate a single block, which should confirm the closing tx.
|
// Generate a single block, which should confirm the closing tx.
|
||||||
_ = mineBlocks(t, net, 1, expectedTxes)[0]
|
_ = mineBlocks(t, net, 1, expectedTxes)[0]
|
||||||
|
|
||||||
// Dave should sweep his funds immediately, as they are not timelocked.
|
|
||||||
// We also expect Dave to sweep his anchor, if present.
|
|
||||||
_, err = waitForNTxsInMempool(
|
|
||||||
net.Miner.Client, expectedTxes, minerMempoolTimeout,
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err, "unable to find Dave's sweep tx in mempool")
|
|
||||||
|
|
||||||
// Dave should consider the channel pending force close (since he is
|
// Dave should consider the channel pending force close (since he is
|
||||||
// waiting for his sweep to confirm).
|
// waiting for his sweep to confirm).
|
||||||
assertNumPendingChannels(t, dave, 0, 1)
|
assertNumPendingChannels(t, dave, 0, 1)
|
||||||
@@ -1166,11 +1159,93 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// before she can sweep her outputs.
|
// before she can sweep her outputs.
|
||||||
assertNumPendingChannels(t, carol, 0, 1)
|
assertNumPendingChannels(t, carol, 0, 1)
|
||||||
|
|
||||||
// Mine the sweep tx.
|
if commitType == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE {
|
||||||
_ = mineBlocks(t, net, 1, expectedTxes)[0]
|
// Dave should sweep his anchor only, since he still has the
|
||||||
|
// lease CLTV constraint on his commitment output.
|
||||||
|
_, err = waitForNTxsInMempool(
|
||||||
|
net.Miner.Client, 1, minerMempoolTimeout,
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err, "unable to find Dave's anchor sweep "+
|
||||||
|
"tx in mempool")
|
||||||
|
|
||||||
// Now Dave should consider the channel fully closed.
|
// Mine Dave's anchor sweep tx.
|
||||||
assertNumPendingChannels(t, dave, 0, 0)
|
_ = mineBlocks(t, net, 1, 1)[0]
|
||||||
|
|
||||||
|
// After Carol's output matures, she should also reclaim her
|
||||||
|
// funds.
|
||||||
|
//
|
||||||
|
// The commit sweep resolver publishes the sweep tx at
|
||||||
|
// defaultCSV-1 and we already mined one block after the
|
||||||
|
// commitmment was published, so take that into account.
|
||||||
|
mineBlocks(t, net, defaultCSV-1-1, 0)
|
||||||
|
carolSweep, err := waitForTxInMempool(
|
||||||
|
net.Miner.Client, minerMempoolTimeout,
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err, "unable to find Carol's sweep tx in "+
|
||||||
|
"mempool")
|
||||||
|
block := mineBlocks(t, net, 1, 1)[0]
|
||||||
|
assertTxInBlock(t, block, carolSweep)
|
||||||
|
|
||||||
|
// Now the channel should be fully closed also from Carol's POV.
|
||||||
|
assertNumPendingChannels(t, carol, 0, 0)
|
||||||
|
|
||||||
|
// We'll now mine the remaining blocks to prompt Dave to sweep
|
||||||
|
// his CLTV-constrained output.
|
||||||
|
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
resp, err := dave.PendingChannels(
|
||||||
|
ctxt, &lnrpc.PendingChannelsRequest{},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
blocksTilMaturity :=
|
||||||
|
resp.PendingForceClosingChannels[0].BlocksTilMaturity
|
||||||
|
require.Positive(t.t, blocksTilMaturity)
|
||||||
|
|
||||||
|
mineBlocks(t, net, uint32(blocksTilMaturity), 0)
|
||||||
|
daveSweep, err := waitForTxInMempool(
|
||||||
|
net.Miner.Client, minerMempoolTimeout,
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err, "unable to find Dave's sweep tx in "+
|
||||||
|
"mempool")
|
||||||
|
block = mineBlocks(t, net, 1, 1)[0]
|
||||||
|
assertTxInBlock(t, block, daveSweep)
|
||||||
|
|
||||||
|
// Now Dave should consider the channel fully closed.
|
||||||
|
assertNumPendingChannels(t, dave, 0, 0)
|
||||||
|
} else {
|
||||||
|
// Dave should sweep his funds immediately, as they are not
|
||||||
|
// timelocked. We also expect Dave to sweep his anchor, if
|
||||||
|
// present.
|
||||||
|
_, err = waitForNTxsInMempool(
|
||||||
|
net.Miner.Client, expectedTxes, minerMempoolTimeout,
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err, "unable to find Dave's sweep tx in "+
|
||||||
|
"mempool")
|
||||||
|
|
||||||
|
// Mine the sweep tx.
|
||||||
|
_ = mineBlocks(t, net, 1, expectedTxes)[0]
|
||||||
|
|
||||||
|
// Now Dave should consider the channel fully closed.
|
||||||
|
assertNumPendingChannels(t, dave, 0, 0)
|
||||||
|
|
||||||
|
// After Carol's output matures, she should also reclaim her
|
||||||
|
// funds.
|
||||||
|
//
|
||||||
|
// The commit sweep resolver publishes the sweep tx at
|
||||||
|
// defaultCSV-1 and we already mined one block after the
|
||||||
|
// commitmment was published, so take that into account.
|
||||||
|
mineBlocks(t, net, defaultCSV-1-1, 0)
|
||||||
|
carolSweep, err := waitForTxInMempool(
|
||||||
|
net.Miner.Client, minerMempoolTimeout,
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err, "unable to find Carol's sweep tx in "+
|
||||||
|
"mempool")
|
||||||
|
block := mineBlocks(t, net, 1, 1)[0]
|
||||||
|
assertTxInBlock(t, block, carolSweep)
|
||||||
|
|
||||||
|
// Now the channel should be fully closed also from Carol's POV.
|
||||||
|
assertNumPendingChannels(t, carol, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// We query Dave's balance to make sure it increased after the channel
|
// We query Dave's balance to make sure it increased after the channel
|
||||||
// closed. This checks that he was able to sweep the funds he had in
|
// closed. This checks that he was able to sweep the funds he had in
|
||||||
@@ -1185,22 +1260,6 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
t.t, daveBalance, daveStartingBalance, "balance not increased",
|
t.t, daveBalance, daveStartingBalance, "balance not increased",
|
||||||
)
|
)
|
||||||
|
|
||||||
// After the Carol's output matures, she should also reclaim her funds.
|
|
||||||
//
|
|
||||||
// The commit sweep resolver publishes the sweep tx at defaultCSV-1 and
|
|
||||||
// we already mined one block after the commitment was published, so
|
|
||||||
// take that into account.
|
|
||||||
mineBlocks(t, net, defaultCSV-1-1, 0)
|
|
||||||
carolSweep, err := waitForTxInMempool(
|
|
||||||
net.Miner.Client, minerMempoolTimeout,
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err, "unable to find Carol's sweep tx in mempool")
|
|
||||||
block := mineBlocks(t, net, 1, 1)[0]
|
|
||||||
assertTxInBlock(t, block, carolSweep)
|
|
||||||
|
|
||||||
// Now the channel should be fully closed also from Carol's POV.
|
|
||||||
assertNumPendingChannels(t, carol, 0, 0)
|
|
||||||
|
|
||||||
// Make sure Carol got her balance back.
|
// Make sure Carol got her balance back.
|
||||||
err = wait.NoError(func() error {
|
err = wait.NoError(func() error {
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
|||||||
@@ -337,10 +337,37 @@ func testChannelBackupRestore(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Restore the backup from the on-disk file, using the RPC
|
// Restore the backup from the on-disk file, using the RPC
|
||||||
// interface, for anchor commitment channels.
|
// interface, for anchor commitment channels.
|
||||||
{
|
{
|
||||||
name: "restore from backup file anchors",
|
name: "restore from backup file anchors",
|
||||||
initiator: true,
|
initiator: true,
|
||||||
private: false,
|
private: false,
|
||||||
anchorCommit: true,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
|
restoreMethod: func(oldNode *lntest.HarnessNode,
|
||||||
|
backupFilePath string,
|
||||||
|
mnemonic []string) (nodeRestorer, error) {
|
||||||
|
|
||||||
|
// Read the entire Multi backup stored within
|
||||||
|
// this node's channels.backup file.
|
||||||
|
multi, err := ioutil.ReadFile(backupFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have Dave's backup file, we'll
|
||||||
|
// create a new nodeRestorer that will restore
|
||||||
|
// using the on-disk channels.backup.
|
||||||
|
return chanRestoreViaRPC(
|
||||||
|
net, password, mnemonic, multi, oldNode,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Restore the backup from the on-disk file, using the RPC
|
||||||
|
// interface, for script-enforced leased channels.
|
||||||
|
{
|
||||||
|
name: "restore from backup file script enforced lease",
|
||||||
|
initiator: true,
|
||||||
|
private: false,
|
||||||
|
commitmentType: lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE,
|
||||||
restoreMethod: func(oldNode *lntest.HarnessNode,
|
restoreMethod: func(oldNode *lntest.HarnessNode,
|
||||||
backupFilePath string,
|
backupFilePath string,
|
||||||
mnemonic []string) (nodeRestorer, error) {
|
mnemonic []string) (nodeRestorer, error) {
|
||||||
@@ -399,7 +426,7 @@ func testChannelBackupRestore(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
"anchors",
|
"anchors",
|
||||||
initiator: true,
|
initiator: true,
|
||||||
private: false,
|
private: false,
|
||||||
anchorCommit: true,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
localForceClose: true,
|
localForceClose: true,
|
||||||
restoreMethod: func(oldNode *lntest.HarnessNode,
|
restoreMethod: func(oldNode *lntest.HarnessNode,
|
||||||
backupFilePath string,
|
backupFilePath string,
|
||||||
@@ -814,9 +841,9 @@ type chanRestoreTestCase struct {
|
|||||||
// confirmed or not.
|
// confirmed or not.
|
||||||
unconfirmed bool
|
unconfirmed bool
|
||||||
|
|
||||||
// anchorCommit is true, then the new anchor commitment type will be
|
// commitmentType specifies the commitment type that should be used for
|
||||||
// used for the channels created in the test.
|
// the channel from Dave to Carol.
|
||||||
anchorCommit bool
|
commitmentType lnrpc.CommitmentType
|
||||||
|
|
||||||
// legacyRevocation signals if a channel with the legacy revocation
|
// legacyRevocation signals if a channel with the legacy revocation
|
||||||
// producer format should also be created before restoring.
|
// producer format should also be created before restoring.
|
||||||
@@ -854,11 +881,9 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
"--minbackoff=50ms",
|
"--minbackoff=50ms",
|
||||||
"--maxbackoff=1s",
|
"--maxbackoff=1s",
|
||||||
}
|
}
|
||||||
if testCase.anchorCommit {
|
if testCase.commitmentType != lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE {
|
||||||
anchorNodeArgs := nodeArgsForCommitType(
|
args := nodeArgsForCommitType(testCase.commitmentType)
|
||||||
lnrpc.CommitmentType_ANCHORS,
|
nodeArgs = append(nodeArgs, args...)
|
||||||
)
|
|
||||||
nodeArgs = append(nodeArgs, anchorNodeArgs...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, we'll create a brand new node we'll use within the test. If
|
// First, we'll create a brand new node we'll use within the test. If
|
||||||
@@ -884,7 +909,7 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
|
|
||||||
// For the anchor output case we need two UTXOs for Carol so she can
|
// For the anchor output case we need two UTXOs for Carol so she can
|
||||||
// sweep both the local and remote anchor.
|
// sweep both the local and remote anchor.
|
||||||
if testCase.anchorCommit {
|
if commitTypeHasAnchors(testCase.commitmentType) {
|
||||||
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, carol)
|
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, carol)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,12 +961,23 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
)
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
var fundingShim *lnrpc.FundingShim
|
||||||
|
if testCase.commitmentType == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE {
|
||||||
|
_, minerHeight, err := net.Miner.Client.GetBestBlock()
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
thawHeight := uint32(minerHeight + 144)
|
||||||
|
|
||||||
|
fundingShim, _, _ = deriveFundingShim(
|
||||||
|
net, t, from, to, chanAmt, thawHeight, true,
|
||||||
|
)
|
||||||
|
}
|
||||||
chanPoint = openChannelAndAssert(
|
chanPoint = openChannelAndAssert(
|
||||||
t, net, from, to,
|
t, net, from, to, lntest.OpenChannelParams{
|
||||||
lntest.OpenChannelParams{
|
Amt: chanAmt,
|
||||||
Amt: chanAmt,
|
PushAmt: pushAmt,
|
||||||
PushAmt: pushAmt,
|
Private: testCase.private,
|
||||||
Private: testCase.private,
|
FundingShim: fundingShim,
|
||||||
|
CommitmentType: testCase.commitmentType,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1086,7 +1122,8 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
|
|
||||||
assertTimeLockSwept(
|
assertTimeLockSwept(
|
||||||
net, t, carol, carolStartingBalance, dave,
|
net, t, carol, carolStartingBalance, dave,
|
||||||
daveStartingBalance, testCase.anchorCommit,
|
daveStartingBalance,
|
||||||
|
commitTypeHasAnchors(testCase.commitmentType),
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -1167,7 +1204,7 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
require.NoError(t.t, err)
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
numUTXOs := 1
|
numUTXOs := 1
|
||||||
if testCase.anchorCommit {
|
if commitTypeHasAnchors(testCase.commitmentType) {
|
||||||
numUTXOs = 2
|
numUTXOs = 2
|
||||||
}
|
}
|
||||||
assertNumUTXOs(t.t, carol, numUTXOs)
|
assertNumUTXOs(t.t, carol, numUTXOs)
|
||||||
@@ -1183,7 +1220,7 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
// end of the protocol.
|
// end of the protocol.
|
||||||
assertDLPExecuted(
|
assertDLPExecuted(
|
||||||
net, t, carol, carolStartingBalance, dave, daveStartingBalance,
|
net, t, carol, carolStartingBalance, dave, daveStartingBalance,
|
||||||
testCase.anchorCommit,
|
testCase.commitmentType,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1014,7 +1014,7 @@ func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// on chain, and both of them properly carry out the DLP protocol.
|
// on chain, and both of them properly carry out the DLP protocol.
|
||||||
assertDLPExecuted(
|
assertDLPExecuted(
|
||||||
net, t, carol, carolStartingBalance, dave, daveStartingBalance,
|
net, t, carol, carolStartingBalance, dave, daveStartingBalance,
|
||||||
false,
|
lnrpc.CommitmentType_STATIC_REMOTE_KEY,
|
||||||
)
|
)
|
||||||
|
|
||||||
// As a second part of this test, we will test the scenario where a
|
// As a second part of this test, we will test the scenario where a
|
||||||
|
|||||||
Reference in new issue
Block a user