lntemp+itest: refactor testCommitmentTransactionDeadline

This commit is contained in:
yyforyongyu
2022-08-04 20:15:01 +08:00
parent f7f259b92a
commit 61364c0d9d
4 changed files with 89 additions and 87 deletions

View File

@@ -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
}

View File

@@ -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,
},
} }

View File

@@ -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

View File

@@ -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,