Skip to content

Commit b117551

Browse files
authored
Merge pull request #8515 from mohamedawnallah/add-coin-selection-strategy-on-chain-rpc
coin select: add coin selection strategy option to all on-chain RPCs
2 parents b331e73 + 31526a0 commit b117551

23 files changed

+4296
-3880
lines changed

cmd/lncli/cmd_open_channel.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,7 @@ var batchOpenChannelCommand = cli.Command{
817817
"transaction when storing it to the local " +
818818
"wallet after publishing it",
819819
},
820+
coinSelectionStrategyFlag,
820821
},
821822
Action: actionDecorator(batchOpenChannel),
822823
}
@@ -845,13 +846,19 @@ func batchOpenChannel(ctx *cli.Context) error {
845846
return nil
846847
}
847848

849+
coinSelectionStrategy, err := parseCoinSelectionStrategy(ctx)
850+
if err != nil {
851+
return err
852+
}
853+
848854
minConfs := int32(ctx.Uint64("min_confs"))
849855
req := &lnrpc.BatchOpenChannelRequest{
850-
TargetConf: int32(ctx.Int64("conf_target")),
851-
SatPerVbyte: int64(ctx.Uint64("sat_per_vbyte")),
852-
MinConfs: minConfs,
853-
SpendUnconfirmed: minConfs == 0,
854-
Label: ctx.String("label"),
856+
TargetConf: int32(ctx.Int64("conf_target")),
857+
SatPerVbyte: int64(ctx.Uint64("sat_per_vbyte")),
858+
MinConfs: minConfs,
859+
SpendUnconfirmed: minConfs == 0,
860+
Label: ctx.String("label"),
861+
CoinSelectionStrategy: coinSelectionStrategy,
855862
}
856863

857864
// Let's try and parse the JSON part of the CLI now. Fortunately we can

cmd/lncli/commands.go

+49-18
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,16 @@ func newAddress(ctx *cli.Context) error {
200200
return nil
201201
}
202202

203+
var coinSelectionStrategyFlag = cli.StringFlag{
204+
Name: "coin_selection_strategy",
205+
Usage: "(optional) the strategy to use for selecting " +
206+
"coins. Possible values are 'largest', 'random', or " +
207+
"'global-config'. If either 'largest' or 'random' is " +
208+
"specified, it will override the globally configured " +
209+
"strategy in lnd.conf",
210+
Value: "global-config",
211+
}
212+
203213
var estimateFeeCommand = cli.Command{
204214
Name: "estimatefee",
205215
Category: "On-chain",
@@ -215,9 +225,10 @@ var estimateFeeCommand = cli.Command{
215225
Flags: []cli.Flag{
216226
cli.Int64Flag{
217227
Name: "conf_target",
218-
Usage: "(optional) the number of blocks that the transaction *should* " +
219-
"confirm in",
228+
Usage: "(optional) the number of blocks that the " +
229+
"transaction *should* confirm in",
220230
},
231+
coinSelectionStrategyFlag,
221232
},
222233
Action: actionDecorator(estimateFees),
223234
}
@@ -231,12 +242,18 @@ func estimateFees(ctx *cli.Context) error {
231242
return err
232243
}
233244

245+
coinSelectionStrategy, err := parseCoinSelectionStrategy(ctx)
246+
if err != nil {
247+
return err
248+
}
249+
234250
client, cleanUp := getClient(ctx)
235251
defer cleanUp()
236252

237253
resp, err := client.EstimateFee(ctxc, &lnrpc.EstimateFeeRequest{
238-
AddrToAmount: amountToAddr,
239-
TargetConf: int32(ctx.Int64("conf_target")),
254+
AddrToAmount: amountToAddr,
255+
TargetConf: int32(ctx.Int64("conf_target")),
256+
CoinSelectionStrategy: coinSelectionStrategy,
240257
})
241258
if err != nil {
242259
return err
@@ -313,6 +330,7 @@ var sendCoinsCommand = cli.Command{
313330
"terminal avoid breaking existing shell " +
314331
"scripts",
315332
},
333+
coinSelectionStrategyFlag,
316334
txLabelFlag,
317335
},
318336
Action: actionDecorator(sendCoins),
@@ -375,6 +393,11 @@ func sendCoins(ctx *cli.Context) error {
375393
"sweep all coins out of the wallet")
376394
}
377395

396+
coinSelectionStrategy, err := parseCoinSelectionStrategy(ctx)
397+
if err != nil {
398+
return err
399+
}
400+
378401
client, cleanUp := getClient(ctx)
379402
defer cleanUp()
380403
minConfs := int32(ctx.Uint64("min_confs"))
@@ -409,14 +432,15 @@ func sendCoins(ctx *cli.Context) error {
409432
}
410433

411434
req := &lnrpc.SendCoinsRequest{
412-
Addr: addr,
413-
Amount: amt,
414-
TargetConf: int32(ctx.Int64("conf_target")),
415-
SatPerVbyte: ctx.Uint64(feeRateFlag),
416-
SendAll: ctx.Bool("sweepall"),
417-
Label: ctx.String(txLabelFlag.Name),
418-
MinConfs: minConfs,
419-
SpendUnconfirmed: minConfs == 0,
435+
Addr: addr,
436+
Amount: amt,
437+
TargetConf: int32(ctx.Int64("conf_target")),
438+
SatPerVbyte: ctx.Uint64(feeRateFlag),
439+
SendAll: ctx.Bool("sweepall"),
440+
Label: ctx.String(txLabelFlag.Name),
441+
MinConfs: minConfs,
442+
SpendUnconfirmed: minConfs == 0,
443+
CoinSelectionStrategy: coinSelectionStrategy,
420444
}
421445
txid, err := client.SendCoins(ctxc, req)
422446
if err != nil {
@@ -585,6 +609,7 @@ var sendManyCommand = cli.Command{
585609
"must satisfy",
586610
Value: defaultUtxoMinConf,
587611
},
612+
coinSelectionStrategyFlag,
588613
txLabelFlag,
589614
},
590615
Action: actionDecorator(sendMany),
@@ -615,17 +640,23 @@ func sendMany(ctx *cli.Context) error {
615640
return err
616641
}
617642

643+
coinSelectionStrategy, err := parseCoinSelectionStrategy(ctx)
644+
if err != nil {
645+
return err
646+
}
647+
618648
client, cleanUp := getClient(ctx)
619649
defer cleanUp()
620650

621651
minConfs := int32(ctx.Uint64("min_confs"))
622652
txid, err := client.SendMany(ctxc, &lnrpc.SendManyRequest{
623-
AddrToAmount: amountToAddr,
624-
TargetConf: int32(ctx.Int64("conf_target")),
625-
SatPerVbyte: ctx.Uint64(feeRateFlag),
626-
Label: ctx.String(txLabelFlag.Name),
627-
MinConfs: minConfs,
628-
SpendUnconfirmed: minConfs == 0,
653+
AddrToAmount: amountToAddr,
654+
TargetConf: int32(ctx.Int64("conf_target")),
655+
SatPerVbyte: ctx.Uint64(feeRateFlag),
656+
Label: ctx.String(txLabelFlag.Name),
657+
MinConfs: minConfs,
658+
SpendUnconfirmed: minConfs == 0,
659+
CoinSelectionStrategy: coinSelectionStrategy,
629660
})
630661
if err != nil {
631662
return err

cmd/lncli/main.go

+28
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,31 @@ func networkParams(ctx *cli.Context) (*chaincfg.Params, error) {
564564
return nil, fmt.Errorf("unknown network: %v", network)
565565
}
566566
}
567+
568+
// parseCoinSelectionStrategy parses a coin selection strategy string
569+
// from the CLI to its lnrpc.CoinSelectionStrategy counterpart proto type.
570+
func parseCoinSelectionStrategy(ctx *cli.Context) (
571+
lnrpc.CoinSelectionStrategy, error) {
572+
573+
strategy := ctx.String(coinSelectionStrategyFlag.Name)
574+
if !ctx.IsSet(coinSelectionStrategyFlag.Name) {
575+
return lnrpc.CoinSelectionStrategy_STRATEGY_USE_GLOBAL_CONFIG,
576+
nil
577+
}
578+
579+
switch strategy {
580+
case "global-config":
581+
return lnrpc.CoinSelectionStrategy_STRATEGY_USE_GLOBAL_CONFIG,
582+
nil
583+
584+
case "largest":
585+
return lnrpc.CoinSelectionStrategy_STRATEGY_LARGEST, nil
586+
587+
case "random":
588+
return lnrpc.CoinSelectionStrategy_STRATEGY_RANDOM, nil
589+
590+
default:
591+
return 0, fmt.Errorf("unknown coin selection strategy "+
592+
"%v", strategy)
593+
}
594+
}

cmd/lncli/walletrpc_active.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,7 @@ var fundTemplatePsbtCommand = cli.Command{
849849
"if required",
850850
Value: -1,
851851
},
852+
coinSelectionStrategyFlag,
852853
},
853854
Action: actionDecorator(fundTemplatePsbt),
854855
}
@@ -997,6 +998,11 @@ func fundTemplatePsbt(ctx *cli.Context) error {
997998
"inputs/outputs flag")
998999
}
9991000

1001+
coinSelectionStrategy, err := parseCoinSelectionStrategy(ctx)
1002+
if err != nil {
1003+
return err
1004+
}
1005+
10001006
minConfs := int32(ctx.Uint64("min_confs"))
10011007
req := &walletrpc.FundPsbtRequest{
10021008
Account: ctx.String("account"),
@@ -1005,6 +1011,7 @@ func fundTemplatePsbt(ctx *cli.Context) error {
10051011
Template: &walletrpc.FundPsbtRequest_CoinSelect{
10061012
CoinSelect: coinSelect,
10071013
},
1014+
CoinSelectionStrategy: coinSelectionStrategy,
10081015
}
10091016

10101017
// Parse fee flags.
@@ -1167,6 +1174,7 @@ var fundPsbtCommand = cli.Command{
11671174
"transaction must satisfy",
11681175
Value: defaultUtxoMinConf,
11691176
},
1177+
coinSelectionStrategyFlag,
11701178
},
11711179
Action: actionDecorator(fundPsbt),
11721180
}
@@ -1180,11 +1188,17 @@ func fundPsbt(ctx *cli.Context) error {
11801188
return cli.ShowCommandHelp(ctx, "fund")
11811189
}
11821190

1191+
coinSelectionStrategy, err := parseCoinSelectionStrategy(ctx)
1192+
if err != nil {
1193+
return err
1194+
}
1195+
11831196
minConfs := int32(ctx.Uint64("min_confs"))
11841197
req := &walletrpc.FundPsbtRequest{
1185-
Account: ctx.String("account"),
1186-
MinConfs: minConfs,
1187-
SpendUnconfirmed: minConfs == 0,
1198+
Account: ctx.String("account"),
1199+
MinConfs: minConfs,
1200+
SpendUnconfirmed: minConfs == 0,
1201+
CoinSelectionStrategy: coinSelectionStrategy,
11881202
}
11891203

11901204
// Parse template flags.

docs/release-notes/release-notes-0.18.0.md

+4
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ bitcoin peers' feefilter values into account](https://github.com/lightningnetwor
303303
* [Allow callers of `ListSweeps` to specify the start
304304
height](https://github.com/lightningnetwork/lnd/pull/7372).
305305

306+
* [Coin Selection Strategy](https://github.com/lightningnetwork/lnd/pull/8515)
307+
add coin selection strategy option to the following on-chain RPC calls
308+
`EstimateFee`, `SendMany`, `SendCoins`, `BatchOpenChannel`, `SendOutputs`, and `FundPsbt`.
309+
306310
## lncli Updates
307311

308312
* [Documented all available `lncli`

funding/batch.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,10 @@ func (b *Batcher) BatchFund(ctx context.Context,
340340
Fees: &walletrpc.FundPsbtRequest_SatPerVbyte{
341341
SatPerVbyte: uint64(feeRateSatPerVByte),
342342
},
343-
MinConfs: firstReq.MinConfs,
344-
SpendUnconfirmed: firstReq.MinConfs == 0,
345-
ChangeType: changeType,
343+
MinConfs: firstReq.MinConfs,
344+
SpendUnconfirmed: firstReq.MinConfs == 0,
345+
ChangeType: changeType,
346+
CoinSelectionStrategy: req.CoinSelectionStrategy,
346347
}
347348
fundPsbtResp, err := b.cfg.WalletKitServer.FundPsbt(ctx, fundPsbtReq)
348349
if err != nil {

0 commit comments

Comments
 (0)