Skip to content

Commit

Permalink
Merge pull request #8843 from ziggie1984/bumpforceclosefee-rpc
Browse files Browse the repository at this point in the history
bumpforceclosefee rpc
  • Loading branch information
guggero authored Aug 12, 2024
2 parents 57a5e49 + 08aba8c commit 2f2efc7
Show file tree
Hide file tree
Showing 19 changed files with 1,479 additions and 657 deletions.
140 changes: 41 additions & 99 deletions cmd/lncli/walletrpc_active.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package main

import (
"bytes"
"context"
"encoding/base64"
"encoding/hex"
"encoding/json"
Expand All @@ -21,7 +20,6 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
Expand Down Expand Up @@ -431,51 +429,50 @@ var bumpForceCloseFeeCommand = cli.Command{
allows the fee of a channel force closing transaction to be increased by
using the child-pays-for-parent mechanism. It will instruct the sweeper
to sweep the anchor outputs of the closing transaction at the requested
fee rate or confirmation target. The specified fee rate will be the
effective fee rate taking the parent fee into account.
confirmation target and limit the fees to the specified budget.
`,
Flags: []cli.Flag{
cli.Uint64Flag{
Name: "conf_target",
Usage: `
The deadline in number of blocks that the input should be spent within.
When not set, for new inputs, the default value (1008) is used; for
exiting inputs, their current values will be retained.`,
The deadline in number of blocks that the anchor output should be spent
within to bump the closing transaction.`,
},
cli.Uint64Flag{
Name: "sat_per_byte",
Usage: "Deprecated, use sat_per_vbyte instead.",
Hidden: true,
},
cli.BoolFlag{
Name: "force",
Usage: "Deprecated, use immediate instead.",
Hidden: true,
},
cli.Uint64Flag{
Name: "sat_per_vbyte",
Usage: `
The starting fee rate, expressed in sat/vbyte, that will be used to
spend the input with initially. This value will be used by the
sweeper's fee function as its starting fee rate. When not set, the
sweeper will use the estimated fee rate using the target_conf as the
The starting fee rate, expressed in sat/vbyte. This value will be used
by the sweeper's fee function as its starting fee rate. When not set,
the sweeper will use the estimated fee rate using the target_conf as the
starting fee rate.`,
},
cli.BoolFlag{
Name: "force",
Usage: "Deprecated, use immediate instead.",
Hidden: true,
},
cli.BoolFlag{
Name: "immediate",
Usage: `
Whether this input will be swept immediately. When set to true, the
sweeper will sweep this input without waiting for the next batch.`,
Whether this cpfp transaction will be triggered immediately. When set to
true, the sweeper will consider all currently pending registered sweeps
and trigger new batch transactions including the sweeping of the anchor
output related to the selected force close transaction.`,
},
cli.Uint64Flag{
Name: "budget",
Usage: `
The max amount in sats that can be used as the fees. Setting this value
greater than the input's value may result in CPFP - one or more wallet
utxos will be used to pay the fees specified by the budget. If not set,
for new inputs, by default 50% of the input's value will be treated as
the budget for fee bumping; for existing inputs, their current budgets
will be retained.`,
The max amount in sats that can be used as the fees. For already
registered anchor outputs if not set explicitly the old value will be
used. For channel force closes which have no HTLCs in their commitment
transaction this value has to be set to an appropriate amount to pay for
the cpfp transaction of the force closed channel otherwise the fee
bumping will fail.`,
},
},
Action: actionDecorator(bumpForceCloseFee),
Expand All @@ -492,97 +489,42 @@ func bumpForceCloseFee(ctx *cli.Context) error {

// Validate the channel point.
channelPoint := ctx.Args().Get(0)
_, err := NewProtoOutPoint(channelPoint)
rpcChannelPoint, err := parseChanPoint(channelPoint)
if err != nil {
return err
}

// Fetch all waiting close channels.
client, cleanUp := getClient(ctx)
defer cleanUp()

// Fetch waiting close channel commitments.
commitments, err := getWaitingCloseCommitments(
ctxc, client, channelPoint,
)
if err != nil {
return err
// `sat_per_byte` was deprecated we only use sats/vbyte now.
if ctx.IsSet("sat_per_byte") {
return fmt.Errorf("deprecated, use sat_per_vbyte instead")
}

// Retrieve pending sweeps.
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()

sweeps, err := walletClient.PendingSweeps(
ctxc, &walletrpc.PendingSweepsRequest{},
)
if err != nil {
return err
}

// Match pending sweeps with commitments of the channel for which a bump
// is requested and bump their fees.
commitSet := map[string]struct{}{
commitments.LocalTxid: {},
commitments.RemoteTxid: {},
}
if commitments.RemotePendingTxid != "" {
commitSet[commitments.RemotePendingTxid] = struct{}{}
}

for _, sweep := range sweeps.PendingSweeps {
// Only bump anchor sweeps.
if sweep.WitnessType != walletrpc.WitnessType_COMMITMENT_ANCHOR {
continue
}

// Skip unrelated sweeps.
sweepTxID, err := chainhash.NewHash(sweep.Outpoint.TxidBytes)
if err != nil {
return err
}
if _, match := commitSet[sweepTxID.String()]; !match {
continue
}

resp, err := walletClient.BumpFee(
ctxc, &walletrpc.BumpFeeRequest{
Outpoint: sweep.Outpoint,
TargetConf: uint32(ctx.Uint64("conf_target")),
Budget: ctx.Uint64("budget"),
Immediate: ctx.Bool("immediate"),
SatPerVbyte: ctx.Uint64("sat_per_vbyte"),
})
if err != nil {
return err
}

// Bump fee of the anchor sweep.
fmt.Printf("Bumping fee of %v:%v: %v\n",
sweepTxID, sweep.Outpoint.OutputIndex, resp.GetStatus())
// Parse immediate flag (force flag was deprecated).
if ctx.IsSet("immediate") && ctx.IsSet("force") {
return fmt.Errorf("cannot set immediate and force flag at " +
"the same time")
}
immediate := ctx.Bool("immediate") || ctx.Bool("force")

return nil
}

func getWaitingCloseCommitments(ctxc context.Context,
client lnrpc.LightningClient, channelPoint string) (
*lnrpc.PendingChannelsResponse_Commitments, error) {

req := &lnrpc.PendingChannelsRequest{}
resp, err := client.PendingChannels(ctxc, req)
resp, err := walletClient.BumpForceCloseFee(
ctxc, &walletrpc.BumpForceCloseFeeRequest{
ChanPoint: rpcChannelPoint,
DeadlineDelta: uint32(ctx.Uint64("conf_target")),
Budget: ctx.Uint64("budget"),
Immediate: immediate,
StartingFeerate: ctx.Uint64("sat_per_vbyte"),
})
if err != nil {
return nil, err
return err
}

// Lookup the channel commit tx hashes.
for _, channel := range resp.WaitingCloseChannels {
if channel.Channel.ChannelPoint == channelPoint {
return channel.Commitments, nil
}
}
fmt.Printf("BumpForceCloseFee result: %s\n", resp.Status)

return nil, errors.New("channel not found")
return nil
}

var listSweepsCommand = cli.Command{
Expand Down
56 changes: 56 additions & 0 deletions docs/release-notes/release-notes-0.19.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Release Notes
- [Bug Fixes](#bug-fixes)
- [New Features](#new-features)
- [Functional Enhancements](#functional-enhancements)
- [RPC Additions](#rpc-additions)
- [lncli Additions](#lncli-additions)
- [Improvements](#improvements)
- [Functional Updates](#functional-updates)
- [RPC Updates](#rpc-updates)
- [lncli Updates](#lncli-updates)
- [Breaking Changes](#breaking-changes)
- [Performance Improvements](#performance-improvements)
- [Technical and Architectural Updates](#technical-and-architectural-updates)
- [BOLT Spec Updates](#bolt-spec-updates)
- [Testing](#testing)
- [Database](#database)
- [Code Health](#code-health)
- [Tooling and Documentation](#tooling-and-documentation)

# Bug Fixes

# New Features
## Functional Enhancements
## RPC Additions

* [Add a new rpc endpoint](https://github.com/lightningnetwork/lnd/pull/8843)
`BumpForceCloseFee` which moves the functionality soley available in the
`lncli` to LND hence making it more universal.

## lncli Additions

# Improvements
## Functional Updates

## RPC Updates

## lncli Updates

## Code Health

## Breaking Changes
## Performance Improvements

# Technical and Architectural Updates
## BOLT Spec Updates

## Testing
## Database

## Code Health

## Tooling and Documentation

# Contributors (Alphabetical Order)

* Ziggie
4 changes: 4 additions & 0 deletions itest/list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,10 @@ var allTestCases = []*lntest.TestCase{
Name: "bumpfee",
TestFunc: testBumpFee,
},
{
Name: "bumpforceclosefee",
TestFunc: testBumpForceCloseFee,
},
{
Name: "taproot",
TestFunc: testTaproot,
Expand Down
26 changes: 0 additions & 26 deletions itest/lnd_multi-hop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1936,17 +1936,6 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,

expectedTxes := 0
switch c {
// With the closing transaction confirmed, we should expect Bob's HTLC
// timeout transactions to be broadcast due to the expiry being reached.
// We will also expect the success transactions, since he learnt the
// preimages from Alice. We also expect Carol to sweep her commitment
// output.
case lnrpc.CommitmentType_LEGACY:
ht.AssertNumPendingSweeps(bob, numInvoices*2+1)
ht.AssertNumPendingSweeps(carol, 1)

expectedTxes = 2*numInvoices + 1

// In case of anchors, all success transactions will be aggregated into
// one, the same is the case for the timeout transactions. In this case
// Carol will also sweep her commitment and anchor output in a single
Expand Down Expand Up @@ -2068,12 +2057,6 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
}

switch c {
// In case this is a non-anchor channel type, we must mine 2 blocks, as
// the nursery waits an extra block before sweeping. Before the blocks
// are mined, we should expect to see Bob's commit sweep in the mempool.
case lnrpc.CommitmentType_LEGACY:
ht.MineBlocksAndAssertNumTxes(2, 1)

// Mining one additional block, Bob's second level tx is mature, and he
// can sweep the output. Before the blocks are mined, we should expect
// to see Bob's commit sweep in the mempool.
Expand Down Expand Up @@ -2478,11 +2461,6 @@ func runExtraPreimageFromRemoteCommit(ht *lntest.HarnessTest,
ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED)

switch c {
// For non-anchor channel type, we should expect to see Bob's commit
// sweep in the mempool.
case lnrpc.CommitmentType_LEGACY:
numTxesMempool++

// For anchor channel type, we should expect to see Bob's commit output
// and his anchor output be swept in a single tx in the mempool.
case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
Expand Down Expand Up @@ -2665,10 +2643,6 @@ func runExtraPreimageFromLocalCommit(ht *lntest.HarnessTest,
// - Bob's local output sweep tx, if this is NOT script enforced lease.
// - Carol's anchor sweep tx cannot be broadcast as it's uneconomical.
switch c {
case lnrpc.CommitmentType_LEGACY:
htlcOutpoint.Index = 0
ht.AssertNumTxsInMempool(2)

case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT:
htlcOutpoint.Index = 2
ht.AssertNumTxsInMempool(2)
Expand Down
Loading

0 comments on commit 2f2efc7

Please sign in to comment.