cnct: cpfp-sweep anchors
For unconfirmed commit tx anchors, supply the sweeper with cpfp info and a confirmation target fee estimate. The sweeper will try to pay for the parent commit tx as long as the current fee estimate exceeds the pre-signed commit tx fee rate.
This commit is contained in:
parent
681496b474
commit
29602e88e8
@ -89,6 +89,9 @@ func (c *anchorResolver) Resolve() (ContractResolver, error) {
|
|||||||
// An exclusive group is not necessary anymore, because we know that
|
// An exclusive group is not necessary anymore, because we know that
|
||||||
// this is the only anchor that can be swept.
|
// this is the only anchor that can be swept.
|
||||||
//
|
//
|
||||||
|
// We also clear the parent tx information for cpfp, because the
|
||||||
|
// commitment tx is confirmed.
|
||||||
|
//
|
||||||
// After a restart or when the remote force closes, the sweeper is not
|
// After a restart or when the remote force closes, the sweeper is not
|
||||||
// yet aware of the anchor. In that case, it will be added as new input
|
// yet aware of the anchor. In that case, it will be added as new input
|
||||||
// to the sweeper.
|
// to the sweeper.
|
||||||
|
@ -30,6 +30,12 @@ var (
|
|||||||
"process of being force closed")
|
"process of being force closed")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// anchorSweepConfTarget is the conf target used when sweeping
|
||||||
|
// commitment anchors.
|
||||||
|
anchorSweepConfTarget = 6
|
||||||
|
)
|
||||||
|
|
||||||
// WitnessSubscription represents an intent to be notified once new witnesses
|
// WitnessSubscription represents an intent to be notified once new witnesses
|
||||||
// are discovered by various active contract resolvers. A contract resolver may
|
// are discovered by various active contract resolvers. A contract resolver may
|
||||||
// use this to be notified of when it can satisfy an incoming contract after we
|
// use this to be notified of when it can satisfy an incoming contract after we
|
||||||
@ -1060,9 +1066,6 @@ func (c *ChannelArbitrator) sweepAnchors(anchors []*lnwallet.AnchorResolution,
|
|||||||
// anchors from being batched together.
|
// anchors from being batched together.
|
||||||
exclusiveGroup := c.cfg.ShortChanID.ToUint64()
|
exclusiveGroup := c.cfg.ShortChanID.ToUint64()
|
||||||
|
|
||||||
// Retrieve the current minimum fee rate from the sweeper.
|
|
||||||
minFeeRate := c.cfg.Sweeper.RelayFeePerKW()
|
|
||||||
|
|
||||||
for _, anchor := range anchors {
|
for _, anchor := range anchors {
|
||||||
log.Debugf("ChannelArbitrator(%v): pre-confirmation sweep of "+
|
log.Debugf("ChannelArbitrator(%v): pre-confirmation sweep of "+
|
||||||
"anchor of tx %v", c.cfg.ChanPoint, anchor.CommitAnchor)
|
"anchor of tx %v", c.cfg.ChanPoint, anchor.CommitAnchor)
|
||||||
@ -1073,19 +1076,25 @@ func (c *ChannelArbitrator) sweepAnchors(anchors []*lnwallet.AnchorResolution,
|
|||||||
input.CommitmentAnchor,
|
input.CommitmentAnchor,
|
||||||
&anchor.AnchorSignDescriptor,
|
&anchor.AnchorSignDescriptor,
|
||||||
heightHint,
|
heightHint,
|
||||||
nil,
|
&input.TxInfo{
|
||||||
|
Fee: anchor.CommitFee,
|
||||||
|
Weight: anchor.CommitWeight,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sweep anchor output with the minimum fee rate. This usually
|
// Sweep anchor output with a confirmation target fee
|
||||||
// (up to a min relay fee of 3 sat/b) means that the anchor
|
// preference. Because this is a cpfp-operation, the anchor will
|
||||||
// sweep will be economical. Also signal that this is a force
|
// only be attempted to sweep when the current fee estimate for
|
||||||
// sweep. If the user decides to bump the fee on the anchor
|
// the confirmation target exceeds the commit fee rate.
|
||||||
// sweep, it will be swept even if it isn't economical.
|
//
|
||||||
|
// Also signal that this is a force sweep, so that the anchor
|
||||||
|
// will be swept even if it isn't economical purely based on the
|
||||||
|
// anchor value.
|
||||||
_, err := c.cfg.Sweeper.SweepInput(
|
_, err := c.cfg.Sweeper.SweepInput(
|
||||||
&anchorInput,
|
&anchorInput,
|
||||||
sweep.Params{
|
sweep.Params{
|
||||||
Fee: sweep.FeePreference{
|
Fee: sweep.FeePreference{
|
||||||
FeeRate: minFeeRate,
|
ConfTarget: anchorSweepConfTarget,
|
||||||
},
|
},
|
||||||
Force: true,
|
Force: true,
|
||||||
ExclusiveGroup: &exclusiveGroup,
|
ExclusiveGroup: &exclusiveGroup,
|
||||||
|
@ -368,6 +368,10 @@ func testChannelBackupRestore(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
success := t.t.Run(testCase.name, func(t *testing.T) {
|
success := t.t.Run(testCase.name, func(t *testing.T) {
|
||||||
h := newHarnessTest(t, net)
|
h := newHarnessTest(t, net)
|
||||||
|
|
||||||
|
// Start each test with the default static fee estimate.
|
||||||
|
net.SetFeeEstimate(12500)
|
||||||
|
|
||||||
testChanRestoreScenario(h, net, &testCase, password)
|
testChanRestoreScenario(h, net, &testCase, password)
|
||||||
})
|
})
|
||||||
if !success {
|
if !success {
|
||||||
|
@ -96,6 +96,10 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// hop logic.
|
// hop logic.
|
||||||
waitForInvoiceAccepted(t, carol, payHash)
|
waitForInvoiceAccepted(t, carol, payHash)
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// At this point, Bob decides that he wants to exit the channel
|
// At this point, Bob decides that he wants to exit the channel
|
||||||
// immediately, so he force closes his commitment transaction.
|
// immediately, so he force closes his commitment transaction.
|
||||||
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
||||||
|
@ -105,6 +105,10 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
t.Fatalf("htlc mismatch: %v", predErr)
|
t.Fatalf("htlc mismatch: %v", predErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// We'll now mine enough blocks to trigger Bob's broadcast of his
|
// We'll now mine enough blocks to trigger Bob's broadcast of his
|
||||||
// commitment transaction due to the fact that the HTLC is about to
|
// commitment transaction due to the fact that the HTLC is about to
|
||||||
// timeout. With the default outgoing broadcast delta of zero, this will
|
// timeout. With the default outgoing broadcast delta of zero, this will
|
||||||
|
@ -117,6 +117,10 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
t.Fatalf("settle invoice: %v", err)
|
t.Fatalf("settle invoice: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// Now we'll mine enough blocks to prompt carol to actually go to the
|
// Now we'll mine enough blocks to prompt carol to actually go to the
|
||||||
// chain in order to sweep her HTLC since the value is high enough.
|
// chain in order to sweep her HTLC since the value is high enough.
|
||||||
// TODO(roasbeef): modify once go to chain policy changes
|
// TODO(roasbeef): modify once go to chain policy changes
|
||||||
|
@ -96,6 +96,10 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
|
|||||||
// hop logic.
|
// hop logic.
|
||||||
waitForInvoiceAccepted(t, carol, payHash)
|
waitForInvoiceAccepted(t, carol, payHash)
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// Next, Alice decides that she wants to exit the channel, so she'll
|
// Next, Alice decides that she wants to exit the channel, so she'll
|
||||||
// immediately force close the channel by broadcast her commitment
|
// immediately force close the channel by broadcast her commitment
|
||||||
// transaction.
|
// transaction.
|
||||||
|
@ -79,6 +79,10 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
|||||||
t.Fatalf("htlc mismatch: %v", err)
|
t.Fatalf("htlc mismatch: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// Now that all parties have the HTLC locked in, we'll immediately
|
// Now that all parties have the HTLC locked in, we'll immediately
|
||||||
// force close the Bob -> Carol channel. This should trigger contract
|
// force close the Bob -> Carol channel. This should trigger contract
|
||||||
// resolution mode for both of them.
|
// resolution mode for both of them.
|
||||||
|
@ -80,6 +80,10 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
|
|||||||
t.Fatalf("htlc mismatch: %v", predErr)
|
t.Fatalf("htlc mismatch: %v", predErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// At this point, we'll now instruct Carol to force close the
|
// At this point, we'll now instruct Carol to force close the
|
||||||
// transaction. This will let us exercise that Bob is able to sweep the
|
// transaction. This will let us exercise that Bob is able to sweep the
|
||||||
// expired HTLC on Carol's version of the commitment transaction. If
|
// expired HTLC on Carol's version of the commitment transaction. If
|
||||||
|
@ -101,6 +101,10 @@ func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
success := ht.t.Run(subTest.name, func(t *testing.T) {
|
success := ht.t.Run(subTest.name, func(t *testing.T) {
|
||||||
ht := newHarnessTest(t, net)
|
ht := newHarnessTest(t, net)
|
||||||
|
|
||||||
|
// Start each test with the default
|
||||||
|
// static fee estimate.
|
||||||
|
net.SetFeeEstimate(12500)
|
||||||
|
|
||||||
subTest.test(net, ht, alice, bob, commitType)
|
subTest.test(net, ht, alice, bob, commitType)
|
||||||
})
|
})
|
||||||
if !success {
|
if !success {
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/btcsuite/btcd/btcjson"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
@ -3460,6 +3461,9 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
numInvoices = 6
|
numInvoices = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const commitFeeRate = 20000
|
||||||
|
net.SetFeeEstimate(commitFeeRate)
|
||||||
|
|
||||||
// TODO(roasbeef): should check default value in config here
|
// TODO(roasbeef): should check default value in config here
|
||||||
// instead, or make delay a param
|
// instead, or make delay a param
|
||||||
defaultCLTV := uint32(lnd.DefaultBitcoinTimeLockDelta)
|
defaultCLTV := uint32(lnd.DefaultBitcoinTimeLockDelta)
|
||||||
@ -3574,6 +3578,9 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// execute a force closure of the channel. This will also assert that
|
// execute a force closure of the channel. This will also assert that
|
||||||
// the commitment transaction was immediately broadcast in order to
|
// the commitment transaction was immediately broadcast in order to
|
||||||
// fulfill the force closure request.
|
// fulfill the force closure request.
|
||||||
|
const actualFeeRate = 30000
|
||||||
|
net.SetFeeEstimate(actualFeeRate)
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
||||||
_, closingTxID, err := net.CloseChannel(ctxt, alice, chanPoint, true)
|
_, closingTxID, err := net.CloseChannel(ctxt, alice, chanPoint, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -3635,17 +3642,35 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// broadcast as a result of the force closure. If there are anchors, we
|
// broadcast as a result of the force closure. If there are anchors, we
|
||||||
// also expect the anchor sweep tx to be in the mempool.
|
// also expect the anchor sweep tx to be in the mempool.
|
||||||
expectedTxes := 1
|
expectedTxes := 1
|
||||||
|
expectedFeeRate := commitFeeRate
|
||||||
if channelType == commitTypeAnchors {
|
if channelType == commitTypeAnchors {
|
||||||
expectedTxes = 2
|
expectedTxes = 2
|
||||||
|
expectedFeeRate = actualFeeRate
|
||||||
}
|
}
|
||||||
|
|
||||||
sweepTxns, err := waitForNTxsInMempool(
|
sweepTxns, err := getNTxsFromMempool(
|
||||||
net.Miner.Node, expectedTxes, minerMempoolTimeout,
|
net.Miner.Node, expectedTxes, minerMempoolTimeout,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to find commitment in miner mempool: %v", err)
|
t.Fatalf("failed to find commitment in miner mempool: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify fee rate of the commitment tx plus anchor if present.
|
||||||
|
var totalWeight, totalFee int64
|
||||||
|
for _, tx := range sweepTxns {
|
||||||
|
utx := btcutil.NewTx(tx)
|
||||||
|
totalWeight += blockchain.GetTransactionWeight(utx)
|
||||||
|
|
||||||
|
fee, err := getTxFee(net.Miner.Node, tx)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
totalFee += int64(fee)
|
||||||
|
}
|
||||||
|
feeRate := totalFee * 1000 / totalWeight
|
||||||
|
|
||||||
|
// Allow some deviation because weight estimates during tx generation
|
||||||
|
// are estimates.
|
||||||
|
require.InEpsilon(t.t, expectedFeeRate, feeRate, 0.005)
|
||||||
|
|
||||||
// Find alice's commit sweep and anchor sweep (if present) in the
|
// Find alice's commit sweep and anchor sweep (if present) in the
|
||||||
// mempool.
|
// mempool.
|
||||||
aliceCloseTx := waitingClose.Commitments.LocalTxid
|
aliceCloseTx := waitingClose.Commitments.LocalTxid
|
||||||
@ -3737,7 +3762,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
// Carol's sweep tx should be in the mempool already, as her output is
|
// Carol's sweep tx should be in the mempool already, as her output is
|
||||||
// not timelocked. If there are anchors, we also expect Carol's anchor
|
// not timelocked. If there are anchors, we also expect Carol's anchor
|
||||||
// sweep now.
|
// sweep now.
|
||||||
sweepTxns, err = waitForNTxsInMempool(
|
sweepTxns, err = getNTxsFromMempool(
|
||||||
net.Miner.Node, expectedTxes, minerMempoolTimeout,
|
net.Miner.Node, expectedTxes, minerMempoolTimeout,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -4416,12 +4441,13 @@ type sweptOutput struct {
|
|||||||
// we have to bring another input to add fees to the anchor. Note that the
|
// we have to bring another input to add fees to the anchor. Note that the
|
||||||
// anchor swept output may be nil if the channel did not have anchors.
|
// anchor swept output may be nil if the channel did not have anchors.
|
||||||
func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
|
func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
|
||||||
sweepTxns []*chainhash.Hash, closeTx string) (*sweptOutput, *sweptOutput) {
|
sweepTxns []*wire.MsgTx, closeTx string) (*sweptOutput, *sweptOutput) {
|
||||||
|
|
||||||
var commitSweep, anchorSweep *sweptOutput
|
var commitSweep, anchorSweep *sweptOutput
|
||||||
|
|
||||||
for _, tx := range sweepTxns {
|
for _, tx := range sweepTxns {
|
||||||
sweepTx, err := net.Miner.Node.GetRawTransaction(tx)
|
txHash := tx.TxHash()
|
||||||
|
sweepTx, err := net.Miner.Node.GetRawTransaction(&txHash)
|
||||||
require.NoError(t.t, err)
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
// We expect our commitment sweep to have a single input, and,
|
// We expect our commitment sweep to have a single input, and,
|
||||||
@ -4434,7 +4460,7 @@ func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
if len(inputs) == 1 {
|
if len(inputs) == 1 {
|
||||||
commitSweep = &sweptOutput{
|
commitSweep = &sweptOutput{
|
||||||
OutPoint: inputs[0].PreviousOutPoint,
|
OutPoint: inputs[0].PreviousOutPoint,
|
||||||
SweepTx: tx.String(),
|
SweepTx: txHash.String(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Since we have more than one input, we run through
|
// Since we have more than one input, we run through
|
||||||
@ -4445,7 +4471,7 @@ func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
if outpointStr == closeTx {
|
if outpointStr == closeTx {
|
||||||
anchorSweep = &sweptOutput{
|
anchorSweep = &sweptOutput{
|
||||||
OutPoint: txin.PreviousOutPoint,
|
OutPoint: txin.PreviousOutPoint,
|
||||||
SweepTx: tx.String(),
|
SweepTx: txHash.String(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7574,6 +7600,28 @@ func getNTxsFromMempool(miner *rpcclient.Client, n int,
|
|||||||
return txes, nil
|
return txes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getTxFee retrieves parent transactions and reconstructs the fee paid.
|
||||||
|
func getTxFee(miner *rpcclient.Client, tx *wire.MsgTx) (btcutil.Amount, error) {
|
||||||
|
var balance btcutil.Amount
|
||||||
|
for _, in := range tx.TxIn {
|
||||||
|
parentHash := in.PreviousOutPoint.Hash
|
||||||
|
rawTx, err := miner.GetRawTransaction(&parentHash)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
parent := rawTx.MsgTx()
|
||||||
|
balance += btcutil.Amount(
|
||||||
|
parent.TxOut[in.PreviousOutPoint.Index].Value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, out := range tx.TxOut {
|
||||||
|
balance -= btcutil.Amount(out.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return balance, nil
|
||||||
|
}
|
||||||
|
|
||||||
// testFailingChannel tests that we will fail the channel by force closing ii
|
// testFailingChannel tests that we will fail the channel by force closing ii
|
||||||
// in the case where a counterparty tries to settle an HTLC with the wrong
|
// in the case where a counterparty tries to settle an HTLC with the wrong
|
||||||
// preimage.
|
// preimage.
|
||||||
@ -9423,6 +9471,10 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
|
|||||||
dave *lntest.HarnessNode, daveStartingBalance int64,
|
dave *lntest.HarnessNode, daveStartingBalance int64,
|
||||||
anchors bool) {
|
anchors bool) {
|
||||||
|
|
||||||
|
// Increase the fee estimate so that the following force close tx will
|
||||||
|
// be cpfp'ed.
|
||||||
|
net.SetFeeEstimate(30000)
|
||||||
|
|
||||||
// We disabled auto-reconnect for some tests to avoid timing issues.
|
// We disabled auto-reconnect for some tests to avoid timing issues.
|
||||||
// To make sure the nodes are initiating DLP now, we have to manually
|
// To make sure the nodes are initiating DLP now, we have to manually
|
||||||
// re-connect them.
|
// re-connect them.
|
||||||
@ -14527,6 +14579,9 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
|||||||
t.Fatalf("unable to add to log: %v", err)
|
t.Fatalf("unable to add to log: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start every test with the default static fee estimate.
|
||||||
|
lndHarness.SetFeeEstimate(12500)
|
||||||
|
|
||||||
success := t.Run(testCase.name, func(t1 *testing.T) {
|
success := t.Run(testCase.name, func(t1 *testing.T) {
|
||||||
ht := newHarnessTest(t1, lndHarness)
|
ht := newHarnessTest(t1, lndHarness)
|
||||||
ht.RunTestCase(testCase)
|
ht.RunTestCase(testCase)
|
||||||
|
@ -5961,6 +5961,12 @@ type AnchorResolution struct {
|
|||||||
|
|
||||||
// CommitAnchor is the anchor outpoint on the commit tx.
|
// CommitAnchor is the anchor outpoint on the commit tx.
|
||||||
CommitAnchor wire.OutPoint
|
CommitAnchor wire.OutPoint
|
||||||
|
|
||||||
|
// CommitFee is the fee of the commit tx.
|
||||||
|
CommitFee btcutil.Amount
|
||||||
|
|
||||||
|
// CommitWeight is the weight of the commit tx.
|
||||||
|
CommitWeight int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalForceCloseSummary describes the final commitment state before the
|
// LocalForceCloseSummary describes the final commitment state before the
|
||||||
@ -6399,9 +6405,24 @@ func NewAnchorResolution(chanState *channeldb.OpenChannel,
|
|||||||
HashType: txscript.SigHashAll,
|
HashType: txscript.SigHashAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate commit tx weight. This commit tx doesn't yet include the
|
||||||
|
// witness spending the funding output, so we add the (worst case)
|
||||||
|
// weight for that too.
|
||||||
|
utx := btcutil.NewTx(commitTx)
|
||||||
|
weight := blockchain.GetTransactionWeight(utx) +
|
||||||
|
input.WitnessCommitmentTxWeight
|
||||||
|
|
||||||
|
// Calculate commit tx fee.
|
||||||
|
fee := chanState.Capacity
|
||||||
|
for _, out := range commitTx.TxOut {
|
||||||
|
fee -= btcutil.Amount(out.Value)
|
||||||
|
}
|
||||||
|
|
||||||
return &AnchorResolution{
|
return &AnchorResolution{
|
||||||
CommitAnchor: *outPoint,
|
CommitAnchor: *outPoint,
|
||||||
AnchorSignDescriptor: *signDesc,
|
AnchorSignDescriptor: *signDesc,
|
||||||
|
CommitWeight: weight,
|
||||||
|
CommitFee: fee,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user