mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-05 19:23:33 +02:00
lntemp+itest: refactor testCommitmentTransactionDeadline
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
@@ -595,6 +596,14 @@ func (h *HarnessTest) SetFeeEstimate(fee chainfee.SatPerKWeight) {
|
|||||||
h.feeService.SetFeeRate(fee, 1)
|
h.feeService.SetFeeRate(fee, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetFeeEstimateWithConf sets a fee rate of a specified conf target to be
|
||||||
|
// returned from fee estimator.
|
||||||
|
func (h *HarnessTest) SetFeeEstimateWithConf(
|
||||||
|
fee chainfee.SatPerKWeight, conf uint32) {
|
||||||
|
|
||||||
|
h.feeService.SetFeeRate(fee, conf)
|
||||||
|
}
|
||||||
|
|
||||||
// validateNodeState checks that the node doesn't have any uncleaned states
|
// validateNodeState checks that the node doesn't have any uncleaned states
|
||||||
// which will affect its following tests.
|
// which will affect its following tests.
|
||||||
func (h *HarnessTest) validateNodeState(hn *node.HarnessNode) {
|
func (h *HarnessTest) validateNodeState(hn *node.HarnessNode) {
|
||||||
@@ -1475,3 +1484,42 @@ func (h *HarnessTest) ReceiveInvoiceUpdate(
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateTxFee retrieves parent transactions and reconstructs the fee paid.
|
||||||
|
func (h *HarnessTest) CalculateTxFee(tx *wire.MsgTx) btcutil.Amount {
|
||||||
|
var balance btcutil.Amount
|
||||||
|
for _, in := range tx.TxIn {
|
||||||
|
parentHash := in.PreviousOutPoint.Hash
|
||||||
|
rawTx := h.Miner.GetRawTransaction(&parentHash)
|
||||||
|
parent := rawTx.MsgTx()
|
||||||
|
balance += btcutil.Amount(
|
||||||
|
parent.TxOut[in.PreviousOutPoint.Index].Value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, out := range tx.TxOut {
|
||||||
|
balance -= btcutil.Amount(out.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return balance
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalculateTxesFeeRate takes a list of transactions and estimates the fee rate
|
||||||
|
// used to sweep them.
|
||||||
|
//
|
||||||
|
// NOTE: only used in current test file.
|
||||||
|
func (h *HarnessTest) CalculateTxesFeeRate(txns []*wire.MsgTx) int64 {
|
||||||
|
const scale = 1000
|
||||||
|
|
||||||
|
var totalWeight, totalFee int64
|
||||||
|
for _, tx := range txns {
|
||||||
|
utx := btcutil.NewTx(tx)
|
||||||
|
totalWeight += blockchain.GetTransactionWeight(utx)
|
||||||
|
|
||||||
|
fee := h.CalculateTxFee(tx)
|
||||||
|
totalFee += int64(fee)
|
||||||
|
}
|
||||||
|
feeRate := totalFee * scale / totalWeight
|
||||||
|
|
||||||
|
return feeRate
|
||||||
|
}
|
||||||
|
@@ -207,4 +207,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "channel unsettled balance",
|
Name: "channel unsettled balance",
|
||||||
TestFunc: testChannelUnsettledBalance,
|
TestFunc: testChannelUnsettledBalance,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "commitment deadline",
|
||||||
|
TestFunc: testCommitmentTransactionDeadline,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/chainreg"
|
"github.com/lightningnetwork/lnd/chainreg"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
@@ -30,9 +32,7 @@ import (
|
|||||||
//
|
//
|
||||||
// Note that whether the deadline is used or not is implicitly checked by its
|
// Note that whether the deadline is used or not is implicitly checked by its
|
||||||
// corresponding fee rates.
|
// corresponding fee rates.
|
||||||
func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
func testCommitmentTransactionDeadline(ht *lntemp.HarnessTest) {
|
||||||
t *harnessTest) {
|
|
||||||
|
|
||||||
// Get the default max fee rate used in sweeping the commitment
|
// Get the default max fee rate used in sweeping the commitment
|
||||||
// transaction.
|
// transaction.
|
||||||
defaultMax := lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
|
defaultMax := lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
|
||||||
@@ -65,27 +65,27 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
// transaction to CPFP our commitment transaction.
|
// transaction to CPFP our commitment transaction.
|
||||||
feeRateLarge := maxPerKw * 2
|
feeRateLarge := maxPerKw * 2
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
|
|
||||||
// Before we start, set up the default fee rate and we will test the
|
// Before we start, set up the default fee rate and we will test the
|
||||||
// actual fee rate against it to decide whether we are using the
|
// actual fee rate against it to decide whether we are using the
|
||||||
// deadline to perform fee estimation.
|
// deadline to perform fee estimation.
|
||||||
net.SetFeeEstimate(feeRateDefault)
|
ht.SetFeeEstimate(feeRateDefault)
|
||||||
|
|
||||||
// setupNode creates a new node and sends 1 btc to the node.
|
// setupNode creates a new node and sends 1 btc to the node.
|
||||||
setupNode := func(name string) *lntest.HarnessNode {
|
setupNode := func(name string) *node.HarnessNode {
|
||||||
// Create the node.
|
// Create the node.
|
||||||
args := []string{"--hodl.exit-settle"}
|
args := []string{"--hodl.exit-settle"}
|
||||||
args = append(args, nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)...)
|
args = append(args, nodeArgsForCommitType(
|
||||||
node := net.NewNode(t.t, name, args)
|
lnrpc.CommitmentType_ANCHORS)...,
|
||||||
|
)
|
||||||
|
node := ht.NewNode(name, args)
|
||||||
|
|
||||||
// Send some coins to the node.
|
// Send some coins to the node.
|
||||||
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, node)
|
ht.FundCoins(btcutil.SatoshiPerBitcoin, node)
|
||||||
|
|
||||||
// For neutrino backend, we need one additional UTXO to create
|
// For neutrino backend, we need one additional UTXO to create
|
||||||
// the sweeping tx for the remote anchor.
|
// the sweeping tx for the remote anchor.
|
||||||
if net.BackendCfg.Name() == lntest.NeutrinoBackendName {
|
if ht.IsNeutrinoBackend() {
|
||||||
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, node)
|
ht.FundCoins(btcutil.SatoshiPerBitcoin, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
@@ -96,17 +96,17 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
calculateSweepFeeRate := func(expectedSweepTxNum int) int64 {
|
calculateSweepFeeRate := func(expectedSweepTxNum int) int64 {
|
||||||
// Create two nodes, Alice and Bob.
|
// Create two nodes, Alice and Bob.
|
||||||
alice := setupNode("Alice")
|
alice := setupNode("Alice")
|
||||||
defer shutdownAndAssert(net, t, alice)
|
defer ht.Shutdown(alice)
|
||||||
|
|
||||||
bob := setupNode("Bob")
|
bob := setupNode("Bob")
|
||||||
defer shutdownAndAssert(net, t, bob)
|
defer ht.Shutdown(bob)
|
||||||
|
|
||||||
// Connect Alice to Bob.
|
// Connect Alice to Bob.
|
||||||
net.ConnectNodes(t.t, alice, bob)
|
ht.ConnectNodes(alice, bob)
|
||||||
|
|
||||||
// Open a channel between Alice and Bob.
|
// Open a channel between Alice and Bob.
|
||||||
chanPoint := openChannelAndAssert(
|
chanPoint := ht.OpenChannel(
|
||||||
t, net, alice, bob, lntest.OpenChannelParams{
|
alice, bob, lntemp.OpenChannelParams{
|
||||||
Amt: 10e6,
|
Amt: 10e6,
|
||||||
PushAmt: 5e6,
|
PushAmt: 5e6,
|
||||||
},
|
},
|
||||||
@@ -115,64 +115,38 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
// Send a payment with a specified finalCTLVDelta, which will
|
// Send a payment with a specified finalCTLVDelta, which will
|
||||||
// be used as our deadline later on when Alice force closes the
|
// be used as our deadline later on when Alice force closes the
|
||||||
// channel.
|
// channel.
|
||||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
req := &routerrpc.SendPaymentRequest{
|
||||||
defer cancel()
|
|
||||||
_, err := alice.RouterClient.SendPaymentV2(
|
|
||||||
ctxt, &routerrpc.SendPaymentRequest{
|
|
||||||
Dest: bob.PubKey[:],
|
Dest: bob.PubKey[:],
|
||||||
Amt: 10e4,
|
Amt: 10e4,
|
||||||
PaymentHash: makeFakePayHash(t),
|
PaymentHash: ht.Random32Bytes(),
|
||||||
FinalCltvDelta: finalCTLV,
|
FinalCltvDelta: finalCTLV,
|
||||||
TimeoutSeconds: 60,
|
TimeoutSeconds: 60,
|
||||||
FeeLimitMsat: noFeeLimitMsat,
|
FeeLimitMsat: noFeeLimitMsat,
|
||||||
},
|
}
|
||||||
)
|
alice.RPC.SendPayment(req)
|
||||||
require.NoError(t.t, err, "unable to send alice htlc")
|
|
||||||
|
|
||||||
// Once the HTLC has cleared, all the nodes in our mini network
|
// Once the HTLC has cleared, all the nodes in our mini network
|
||||||
// should show that the HTLC has been locked in.
|
// should show that the HTLC has been locked in.
|
||||||
nodes := []*lntest.HarnessNode{alice, bob}
|
ht.AssertNumActiveHtlcs(alice, 1)
|
||||||
err = wait.NoError(func() error {
|
ht.AssertNumActiveHtlcs(bob, 1)
|
||||||
return assertNumActiveHtlcs(nodes, 1)
|
|
||||||
}, defaultTimeout)
|
|
||||||
require.NoError(t.t, err, "htlc mismatch")
|
|
||||||
|
|
||||||
// Alice force closes the channel.
|
// Alice force closes the channel.
|
||||||
_, _, err = net.CloseChannel(alice, chanPoint, true)
|
ht.CloseChannelAssertPending(alice, chanPoint, true)
|
||||||
require.NoError(t.t, err, "unable to force close channel")
|
|
||||||
|
|
||||||
// Now that the channel has been force closed, it should show
|
// Now that the channel has been force closed, it should show
|
||||||
// up in the PendingChannels RPC under the waiting close
|
// up in the PendingChannels RPC under the waiting close
|
||||||
// section.
|
// section.
|
||||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
ht.AssertChannelWaitingClose(alice, chanPoint)
|
||||||
defer cancel()
|
|
||||||
pendingChansRequest := &lnrpc.PendingChannelsRequest{}
|
|
||||||
pendingChanResp, err := alice.PendingChannels(
|
|
||||||
ctxt, pendingChansRequest,
|
|
||||||
)
|
|
||||||
require.NoError(
|
|
||||||
t.t, err, "unable to query for pending channels",
|
|
||||||
)
|
|
||||||
require.NoError(
|
|
||||||
t.t, checkNumWaitingCloseChannels(pendingChanResp, 1),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Check our sweep transactions can be found in mempool.
|
// Check our sweep transactions can be found in mempool.
|
||||||
sweepTxns, err := getNTxsFromMempool(
|
sweepTxns := ht.Miner.GetNumTxsFromMempool(expectedSweepTxNum)
|
||||||
net.Miner.Client,
|
|
||||||
expectedSweepTxNum, minerMempoolTimeout,
|
|
||||||
)
|
|
||||||
require.NoError(
|
|
||||||
t.t, err, "failed to find commitment tx in mempool",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mine a block to confirm these transactions such that they
|
// Mine a block to confirm these transactions such that they
|
||||||
// don't remain in the mempool for any subsequent tests.
|
// don't remain in the mempool for any subsequent tests.
|
||||||
_, err = net.Miner.Client.Generate(1)
|
ht.MineBlocks(1)
|
||||||
require.NoError(t.t, err, "unable to mine blocks")
|
|
||||||
|
|
||||||
// Calculate the fee rate used.
|
// Calculate the fee rate used.
|
||||||
feeRate := calculateTxnsFeeRate(t.t, net.Miner, sweepTxns)
|
feeRate := ht.CalculateTxesFeeRate(sweepTxns)
|
||||||
|
|
||||||
return feeRate
|
return feeRate
|
||||||
}
|
}
|
||||||
@@ -180,7 +154,7 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
// Setup our fee estimation for the deadline. Because the fee rate is
|
// Setup our fee estimation for the deadline. Because the fee rate is
|
||||||
// smaller than the parent tx's fee rate, this value won't be used and
|
// smaller than the parent tx's fee rate, this value won't be used and
|
||||||
// we should see only one sweep tx in the mempool.
|
// we should see only one sweep tx in the mempool.
|
||||||
net.SetFeeEstimateWithConf(feeRateSmall, deadline)
|
ht.SetFeeEstimateWithConf(feeRateSmall, deadline)
|
||||||
|
|
||||||
// Calculate fee rate used.
|
// Calculate fee rate used.
|
||||||
feeRate := calculateSweepFeeRate(1)
|
feeRate := calculateSweepFeeRate(1)
|
||||||
@@ -188,7 +162,7 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
// We expect the default max fee rate is used. Allow some deviation
|
// We expect the default max fee rate is used. Allow some deviation
|
||||||
// because weight estimates during tx generation are estimates.
|
// because weight estimates during tx generation are estimates.
|
||||||
require.InEpsilonf(
|
require.InEpsilonf(
|
||||||
t.t, int64(maxPerKw), feeRate, 0.01,
|
ht, int64(maxPerKw), feeRate, 0.01,
|
||||||
"expected fee rate:%d, got fee rate:%d", maxPerKw, feeRate,
|
"expected fee rate:%d, got fee rate:%d", maxPerKw, feeRate,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -196,7 +170,7 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
// greater than the parent tx's fee rate, this value will be used to
|
// greater than the parent tx's fee rate, this value will be used to
|
||||||
// sweep the anchor transaction and we should see two sweep
|
// sweep the anchor transaction and we should see two sweep
|
||||||
// transactions in the mempool.
|
// transactions in the mempool.
|
||||||
net.SetFeeEstimateWithConf(feeRateLarge, deadline)
|
ht.SetFeeEstimateWithConf(feeRateLarge, deadline)
|
||||||
|
|
||||||
// Calculate fee rate used.
|
// Calculate fee rate used.
|
||||||
feeRate = calculateSweepFeeRate(2)
|
feeRate = calculateSweepFeeRate(2)
|
||||||
@@ -204,31 +178,11 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness,
|
|||||||
// We expect the anchor to be swept with the deadline, which has the
|
// We expect the anchor to be swept with the deadline, which has the
|
||||||
// fee rate of feeRateLarge.
|
// fee rate of feeRateLarge.
|
||||||
require.InEpsilonf(
|
require.InEpsilonf(
|
||||||
t.t, int64(feeRateLarge), feeRate, 0.01,
|
ht, int64(feeRateLarge), feeRate, 0.01,
|
||||||
"expected fee rate:%d, got fee rate:%d", feeRateLarge, feeRate,
|
"expected fee rate:%d, got fee rate:%d", feeRateLarge, feeRate,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateTxnsFeeRate takes a list of transactions and estimates the fee rate
|
|
||||||
// used to sweep them.
|
|
||||||
func calculateTxnsFeeRate(t *testing.T,
|
|
||||||
miner *lntest.HarnessMiner, txns []*wire.MsgTx) int64 {
|
|
||||||
|
|
||||||
var totalWeight, totalFee int64
|
|
||||||
for _, tx := range txns {
|
|
||||||
utx := btcutil.NewTx(tx)
|
|
||||||
totalWeight += blockchain.GetTransactionWeight(utx)
|
|
||||||
|
|
||||||
fee, err := getTxFee(miner.Client, tx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
totalFee += int64(fee)
|
|
||||||
}
|
|
||||||
feeRate := totalFee * 1000 / totalWeight
|
|
||||||
|
|
||||||
return feeRate
|
|
||||||
}
|
|
||||||
|
|
||||||
// testChannelForceClosure performs a test to exercise the behavior of "force"
|
// testChannelForceClosure performs a test to exercise the behavior of "force"
|
||||||
// closing a channel or unilaterally broadcasting the latest local commitment
|
// closing a channel or unilaterally broadcasting the latest local commitment
|
||||||
// state on-chain. The test creates a new channel between Alice and Carol, then
|
// state on-chain. The test creates a new channel between Alice and Carol, then
|
||||||
|
@@ -126,10 +126,6 @@ var allTestCases = []*testCase{
|
|||||||
name: "hold invoice force close",
|
name: "hold invoice force close",
|
||||||
test: testHoldInvoiceForceClose,
|
test: testHoldInvoiceForceClose,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "commitment deadline",
|
|
||||||
test: testCommitmentTransactionDeadline,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "cpfp",
|
name: "cpfp",
|
||||||
test: testCPFP,
|
test: testCPFP,
|
||||||
|
Reference in New Issue
Block a user