Skip to content

Commit

Permalink
sweep: allow force sweeps
Browse files Browse the repository at this point in the history
  • Loading branch information
joostjager committed Jan 15, 2020
1 parent 14237f5 commit b0aae13
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 90 deletions.
31 changes: 15 additions & 16 deletions cmd/lncli/walletrpc_active.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package main

import (
"context"
"fmt"
"sort"

"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
Expand Down Expand Up @@ -113,7 +112,13 @@ var bumpFeeCommand = cli.Command{
Note that this command currently doesn't perform any validation checks
on the fee preference being provided. For now, the responsibility of
ensuring that the new fee preference is sufficient is delegated to the
user.`,
user.
The force flag enables sweeping of inputs that are negatively yielding.
Normally it does not make sense to lose money on sweeping, unless a
parent transaction needs to get confirmed and there is only a small
output available to attach the child transaction to.
`,
Flags: []cli.Flag{
cli.Uint64Flag{
Name: "conf_target",
Expand All @@ -125,14 +130,18 @@ var bumpFeeCommand = cli.Command{
Usage: "a manual fee expressed in sat/byte that " +
"should be used when sweeping the output",
},
cli.BoolFlag{
Name: "force",
Usage: "sweep even if the yield is negative",
},
},
Action: actionDecorator(bumpFee),
}

func bumpFee(ctx *cli.Context) error {
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() != 1 || ctx.NumFlags() != 1 {
if ctx.NArg() != 1 {
return cli.ShowCommandHelp(ctx, "bumpfee")
}

Expand All @@ -142,24 +151,14 @@ func bumpFee(ctx *cli.Context) error {
return err
}

var confTarget, satPerByte uint32
switch {
case ctx.IsSet("conf_target") && ctx.IsSet("sat_per_byte"):
return fmt.Errorf("either conf_target or sat_per_byte should " +
"be set, but not both")
case ctx.IsSet("conf_target"):
confTarget = uint32(ctx.Uint64("conf_target"))
case ctx.IsSet("sat_per_byte"):
satPerByte = uint32(ctx.Uint64("sat_per_byte"))
}

client, cleanUp := getWalletClient(ctx)
defer cleanUp()

resp, err := client.BumpFee(context.Background(), &walletrpc.BumpFeeRequest{
Outpoint: protoOutPoint,
TargetConf: confTarget,
SatPerByte: satPerByte,
TargetConf: uint32(ctx.Uint64("conf_target")),
SatPerByte: uint32(ctx.Uint64("sat_per_byte")),
Force: ctx.Bool("force"),
})
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions cmd/lncli/walletrpc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type PendingSweep struct {
NextBroadcastHeight uint32 `json:"next_broadcast_height"`
RequestedSatPerByte uint32 `json:"requested_sat_per_byte"`
RequestedConfTarget uint32 `json:"requested_conf_target"`
Force bool `json:"force"`
}

// NewPendingSweepFromProto converts the walletrpc.PendingSweep proto type into
Expand All @@ -27,5 +28,6 @@ func NewPendingSweepFromProto(pendingSweep *walletrpc.PendingSweep) *PendingSwee
NextBroadcastHeight: pendingSweep.NextBroadcastHeight,
RequestedSatPerByte: pendingSweep.RequestedSatPerByte,
RequestedConfTarget: pendingSweep.RequestedConfTarget,
Force: pendingSweep.Force,
}
}
156 changes: 90 additions & 66 deletions lnrpc/walletrpc/walletkit.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions lnrpc/walletrpc/walletkit.proto
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ message PendingSweep {

// The requested fee rate, expressed in sat/byte, for this output.
uint32 requested_sat_per_byte = 9 [json_name = "requested_sat_per_byte"];

/**
Whether this input must be force-swept. This means that it is swept even
if it has a negative yield.
*/
bool force = 7 [json_name = "force"];
}

message PendingSweepsRequest {
Expand All @@ -221,6 +227,12 @@ message BumpFeeRequest {
with.
*/
uint32 sat_per_byte = 3 [json_name = "sat_per_byte"];

/**
Whether this input must be force-swept. This means that it is swept even
if it has a negative yield.
*/
bool force = 4 [json_name = "force"];
}

message BumpFeeResponse {
Expand Down
4 changes: 3 additions & 1 deletion lnrpc/walletrpc/walletkit_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ func (w *WalletKit) PendingSweeps(ctx context.Context,
NextBroadcastHeight: nextBroadcastHeight,
RequestedSatPerByte: requestedFeeRate,
RequestedConfTarget: requestedFee.ConfTarget,
Force: pendingInput.Params.Force,
})
}

Expand Down Expand Up @@ -486,7 +487,8 @@ func (w *WalletKit) BumpFee(ctx context.Context,
// being broadcast. If it is not aware of the input however,
// lnwallet.ErrNotMine is returned.
params := sweep.Params{
Fee: feePreference,
Fee: feePreference,
Force: in.Force,
}

_, err = w.cfg.Sweeper.UpdateParams(*op, params)
Expand Down
12 changes: 8 additions & 4 deletions sweep/sweeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,15 @@ type Params struct {
// swept. If a confirmation target is specified, then we'll map it into
// a fee rate whenever we attempt to cluster inputs for a sweep.
Fee FeePreference

// Force indicates whether the input should be swept regardless of
// whether it is economical to do so.
Force bool
}

// String returns a human readable interpretation of the sweep parameters.
func (p Params) String() string {
return fmt.Sprintf("fee=%v", p.Fee)
return fmt.Sprintf("fee=%v, force=%v", p.Fee, p.Force)
}

// pendingInput is created when an input reaches the main loop for the first
Expand Down Expand Up @@ -398,10 +402,10 @@ func (s *UtxoSweeper) SweepInput(input input.Input,
}

log.Infof("Sweep request received: out_point=%v, witness_type=%v, "+
"time_lock=%v, amount=%v, fee_preference=%v", input.OutPoint(),
input.WitnessType(), input.BlocksToMaturity(),
"time_lock=%v, amount=%v, fee_preference=%v, force=%v",
input.OutPoint(), input.WitnessType(), input.BlocksToMaturity(),
btcutil.Amount(input.SignDesc().Output.Value),
params.Fee)
params.Fee, params.Force)

sweeperInput := &sweepInputMessage{
input: input,
Expand Down
Loading

0 comments on commit b0aae13

Please sign in to comment.