multi: add coin selection strategy option to all on-chain rpcs
In this commit, we add the coin selection strategy option to the following on-chain RPCs `fundpsbt`, `batchopenchannel`, `estimatefee`, `sendcoins`, `sendmany`, and `sendoutputs`.
This commit is contained in:
11 files changed
+107
-40
No files matched your search
+4
-3
@@ -340,9 +340,10 @@ func (b *Batcher) BatchFund(ctx context.Context,
|
|||||||
Fees: &walletrpc.FundPsbtRequest_SatPerVbyte{
|
Fees: &walletrpc.FundPsbtRequest_SatPerVbyte{
|
||||||
SatPerVbyte: uint64(feeRateSatPerVByte),
|
SatPerVbyte: uint64(feeRateSatPerVByte),
|
||||||
},
|
},
|
||||||
MinConfs: firstReq.MinConfs,
|
MinConfs: firstReq.MinConfs,
|
||||||
SpendUnconfirmed: firstReq.MinConfs == 0,
|
SpendUnconfirmed: firstReq.MinConfs == 0,
|
||||||
ChangeType: changeType,
|
ChangeType: changeType,
|
||||||
|
CoinSelectionStrategy: req.CoinSelectionStrategy,
|
||||||
}
|
}
|
||||||
fundPsbtResp, err := b.cfg.WalletKitServer.FundPsbt(ctx, fundPsbtReq)
|
fundPsbtResp, err := b.cfg.WalletKitServer.FundPsbt(ctx, fundPsbtReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -799,12 +799,19 @@ func (w *WalletKit) SendOutputs(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
|
||||||
|
req.CoinSelectionStrategy, w.cfg.CoinSelectionStrategy,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we have the outputs mapped and checked for the reserve
|
// Now that we have the outputs mapped and checked for the reserve
|
||||||
// requirement, we can request that the wallet attempts to create this
|
// requirement, we can request that the wallet attempts to create this
|
||||||
// transaction.
|
// transaction.
|
||||||
tx, err := w.cfg.Wallet.SendOutputs(
|
tx, err := w.cfg.Wallet.SendOutputs(
|
||||||
outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw), minConfs,
|
outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw), minConfs,
|
||||||
label,
|
label, coinSelectionStrategy,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1173,12 +1180,15 @@ func (w *WalletKit) LabelTransaction(ctx context.Context,
|
|||||||
func (w *WalletKit) FundPsbt(_ context.Context,
|
func (w *WalletKit) FundPsbt(_ context.Context,
|
||||||
req *FundPsbtRequest) (*FundPsbtResponse, error) {
|
req *FundPsbtRequest) (*FundPsbtResponse, error) {
|
||||||
|
|
||||||
var (
|
coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
|
||||||
err error
|
req.CoinSelectionStrategy, w.cfg.CoinSelectionStrategy,
|
||||||
feeSatPerKW chainfee.SatPerKWeight
|
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the desired transaction fee.
|
// Determine the desired transaction fee.
|
||||||
|
var feeSatPerKW chainfee.SatPerKWeight
|
||||||
switch {
|
switch {
|
||||||
// Estimate the fee by the target number of blocks to confirmation.
|
// Estimate the fee by the target number of blocks to confirmation.
|
||||||
case req.GetTargetConf() != 0:
|
case req.GetTargetConf() != 0:
|
||||||
@@ -1241,7 +1251,7 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
// wallet.
|
// wallet.
|
||||||
return w.fundPsbtInternalWallet(
|
return w.fundPsbtInternalWallet(
|
||||||
account, keyScopeFromChangeAddressType(req.ChangeType),
|
account, keyScopeFromChangeAddressType(req.ChangeType),
|
||||||
packet, minConfs, feeSatPerKW,
|
packet, minConfs, feeSatPerKW, coinSelectionStrategy,
|
||||||
)
|
)
|
||||||
|
|
||||||
// The template is specified as a PSBT with the intention to perform
|
// The template is specified as a PSBT with the intention to perform
|
||||||
@@ -1317,7 +1327,7 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
// coin selection algorithm.
|
// coin selection algorithm.
|
||||||
return w.fundPsbtCoinSelect(
|
return w.fundPsbtCoinSelect(
|
||||||
account, changeIndex, packet, minConfs, changeType,
|
account, changeIndex, packet, minConfs, changeType,
|
||||||
feeSatPerKW,
|
feeSatPerKW, coinSelectionStrategy,
|
||||||
)
|
)
|
||||||
|
|
||||||
// The template is specified as a RPC message. We need to create a new
|
// The template is specified as a RPC message. We need to create a new
|
||||||
@@ -1374,7 +1384,7 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
// wallet.
|
// wallet.
|
||||||
return w.fundPsbtInternalWallet(
|
return w.fundPsbtInternalWallet(
|
||||||
account, keyScopeFromChangeAddressType(req.ChangeType),
|
account, keyScopeFromChangeAddressType(req.ChangeType),
|
||||||
packet, minConfs, feeSatPerKW,
|
packet, minConfs, feeSatPerKW, coinSelectionStrategy,
|
||||||
)
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1387,7 +1397,8 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
// wallet that does not allow specifying custom inputs while selecting coins.
|
// wallet that does not allow specifying custom inputs while selecting coins.
|
||||||
func (w *WalletKit) fundPsbtInternalWallet(account string,
|
func (w *WalletKit) fundPsbtInternalWallet(account string,
|
||||||
keyScope *waddrmgr.KeyScope, packet *psbt.Packet, minConfs int32,
|
keyScope *waddrmgr.KeyScope, packet *psbt.Packet, minConfs int32,
|
||||||
feeSatPerKW chainfee.SatPerKWeight) (*FundPsbtResponse, error) {
|
feeSatPerKW chainfee.SatPerKWeight,
|
||||||
|
strategy base.CoinSelectionStrategy) (*FundPsbtResponse, error) {
|
||||||
|
|
||||||
// The RPC parsing part is now over. Several of the following operations
|
// The RPC parsing part is now over. Several of the following operations
|
||||||
// require us to hold the global coin selection lock, so we do the rest
|
// require us to hold the global coin selection lock, so we do the rest
|
||||||
@@ -1419,7 +1430,8 @@ func (w *WalletKit) fundPsbtInternalWallet(account string,
|
|||||||
// lock any coins but might still change the wallet DB by
|
// lock any coins but might still change the wallet DB by
|
||||||
// generating a new change address.
|
// generating a new change address.
|
||||||
changeIndex, err := w.cfg.Wallet.FundPsbt(
|
changeIndex, err := w.cfg.Wallet.FundPsbt(
|
||||||
packet, minConfs, feeSatPerKW, account, keyScope,
|
packet, minConfs, feeSatPerKW, account,
|
||||||
|
keyScope, strategy,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("wallet couldn't fund PSBT: %w", err)
|
return fmt.Errorf("wallet couldn't fund PSBT: %w", err)
|
||||||
@@ -1454,10 +1466,13 @@ func (w *WalletKit) fundPsbtInternalWallet(account string,
|
|||||||
// fundPsbtCoinSelect uses the "new" PSBT funding method using the channel
|
// fundPsbtCoinSelect uses the "new" PSBT funding method using the channel
|
||||||
// funding coin selection algorithm that allows specifying custom inputs while
|
// funding coin selection algorithm that allows specifying custom inputs while
|
||||||
// selecting coins.
|
// selecting coins.
|
||||||
|
//
|
||||||
|
//nolint:funlen
|
||||||
func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
|
func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
|
||||||
packet *psbt.Packet, minConfs int32,
|
packet *psbt.Packet, minConfs int32,
|
||||||
changeType chanfunding.ChangeAddressType,
|
changeType chanfunding.ChangeAddressType,
|
||||||
feeRate chainfee.SatPerKWeight) (*FundPsbtResponse, error) {
|
feeRate chainfee.SatPerKWeight, strategy base.CoinSelectionStrategy) (
|
||||||
|
*FundPsbtResponse, error) {
|
||||||
|
|
||||||
// We want to make sure we don't select any inputs that are already
|
// We want to make sure we don't select any inputs that are already
|
||||||
// specified in the template. To do that, we require those inputs to
|
// specified in the template. To do that, we require those inputs to
|
||||||
@@ -1603,7 +1618,7 @@ func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
|
|||||||
|
|
||||||
selectedCoins, changeAmount, err := chanfunding.CoinSelect(
|
selectedCoins, changeAmount, err := chanfunding.CoinSelect(
|
||||||
feeRate, fundingAmount, changeDustLimit, coins,
|
feeRate, fundingAmount, changeDustLimit, coins,
|
||||||
w.cfg.CoinSelectionStrategy, estimator, changeType,
|
strategy, estimator, changeType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error selecting coins: %w", err)
|
return fmt.Errorf("error selecting coins: %w", err)
|
||||||
|
|||||||
@@ -574,6 +574,7 @@ func TestFundPsbtCoinSelect(t *testing.T) {
|
|||||||
resp, err := rpcServer.fundPsbtCoinSelect(
|
resp, err := rpcServer.fundPsbtCoinSelect(
|
||||||
"", tc.changeIndex, copiedPacket, 0,
|
"", tc.changeIndex, copiedPacket, 0,
|
||||||
tc.changeType, tc.feeRate,
|
tc.changeType, tc.feeRate,
|
||||||
|
rpcServer.cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -141,14 +141,16 @@ func (w *WalletController) ImportTaprootScript(waddrmgr.KeyScope,
|
|||||||
|
|
||||||
// SendOutputs currently returns dummy values.
|
// SendOutputs currently returns dummy values.
|
||||||
func (w *WalletController) SendOutputs([]*wire.TxOut,
|
func (w *WalletController) SendOutputs([]*wire.TxOut,
|
||||||
chainfee.SatPerKWeight, int32, string) (*wire.MsgTx, error) {
|
chainfee.SatPerKWeight, int32, string,
|
||||||
|
base.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSimpleTx currently returns dummy values.
|
// CreateSimpleTx currently returns dummy values.
|
||||||
func (w *WalletController) CreateSimpleTx([]*wire.TxOut,
|
func (w *WalletController) CreateSimpleTx([]*wire.TxOut,
|
||||||
chainfee.SatPerKWeight, int32, bool) (*txauthor.AuthoredTx, error) {
|
chainfee.SatPerKWeight, int32, base.CoinSelectionStrategy,
|
||||||
|
bool) (*txauthor.AuthoredTx, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -206,7 +208,7 @@ func (w *WalletController) ListLeasedOutputs() ([]*base.ListLeasedOutputResult,
|
|||||||
|
|
||||||
// FundPsbt currently does nothing.
|
// FundPsbt currently does nothing.
|
||||||
func (w *WalletController) FundPsbt(*psbt.Packet, int32, chainfee.SatPerKWeight,
|
func (w *WalletController) FundPsbt(*psbt.Packet, int32, chainfee.SatPerKWeight,
|
||||||
string, *waddrmgr.KeyScope) (int32, error) {
|
string, *waddrmgr.KeyScope, base.CoinSelectionStrategy) (int32, error) {
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -978,8 +978,8 @@ func (b *BtcWallet) ImportTaprootScript(scope waddrmgr.KeyScope,
|
|||||||
//
|
//
|
||||||
// This is a part of the WalletController interface.
|
// This is a part of the WalletController interface.
|
||||||
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
||||||
feeRate chainfee.SatPerKWeight, minConfs int32,
|
feeRate chainfee.SatPerKWeight, minConfs int32, label string,
|
||||||
label string) (*wire.MsgTx, error) {
|
strategy base.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
// Convert our fee rate from sat/kw to sat/kb since it's required by
|
// Convert our fee rate from sat/kw to sat/kb since it's required by
|
||||||
// SendOutputs.
|
// SendOutputs.
|
||||||
@@ -997,7 +997,7 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
|||||||
|
|
||||||
return b.wallet.SendOutputs(
|
return b.wallet.SendOutputs(
|
||||||
outputs, nil, defaultAccount, minConfs, feeSatPerKB,
|
outputs, nil, defaultAccount, minConfs, feeSatPerKB,
|
||||||
b.cfg.CoinSelectionStrategy, label,
|
strategy, label,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,6 +1016,7 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
|||||||
// This is a part of the WalletController interface.
|
// This is a part of the WalletController interface.
|
||||||
func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
|
func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
|
||||||
feeRate chainfee.SatPerKWeight, minConfs int32,
|
feeRate chainfee.SatPerKWeight, minConfs int32,
|
||||||
|
strategy base.CoinSelectionStrategy,
|
||||||
dryRun bool) (*txauthor.AuthoredTx, error) {
|
dryRun bool) (*txauthor.AuthoredTx, error) {
|
||||||
|
|
||||||
// The fee rate is passed in using units of sat/kw, so we'll convert
|
// The fee rate is passed in using units of sat/kw, so we'll convert
|
||||||
@@ -1048,7 +1049,7 @@ func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
|
|||||||
|
|
||||||
return b.wallet.CreateSimpleTx(
|
return b.wallet.CreateSimpleTx(
|
||||||
nil, defaultAccount, outputs, minConfs, feeSatPerKB,
|
nil, defaultAccount, outputs, minConfs, feeSatPerKB,
|
||||||
b.cfg.CoinSelectionStrategy, dryRun,
|
strategy, dryRun,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ var (
|
|||||||
// This is a part of the WalletController interface.
|
// This is a part of the WalletController interface.
|
||||||
func (b *BtcWallet) FundPsbt(packet *psbt.Packet, minConfs int32,
|
func (b *BtcWallet) FundPsbt(packet *psbt.Packet, minConfs int32,
|
||||||
feeRate chainfee.SatPerKWeight, accountName string,
|
feeRate chainfee.SatPerKWeight, accountName string,
|
||||||
changeScope *waddrmgr.KeyScope) (int32, error) {
|
changeScope *waddrmgr.KeyScope,
|
||||||
|
strategy wallet.CoinSelectionStrategy) (int32, error) {
|
||||||
|
|
||||||
// The fee rate is passed in using units of sat/kw, so we'll convert
|
// The fee rate is passed in using units of sat/kw, so we'll convert
|
||||||
// this to sat/KB as the CreateSimpleTx method requires this unit.
|
// this to sat/KB as the CreateSimpleTx method requires this unit.
|
||||||
@@ -134,7 +135,7 @@ func (b *BtcWallet) FundPsbt(packet *psbt.Packet, minConfs int32,
|
|||||||
// the partial TX information in the packet.
|
// the partial TX information in the packet.
|
||||||
return b.wallet.FundPsbt(
|
return b.wallet.FundPsbt(
|
||||||
packet, keyScope, minConfs, accountNum, feeSatPerKB,
|
packet, keyScope, minConfs, accountNum, feeSatPerKB,
|
||||||
b.cfg.CoinSelectionStrategy, opts...,
|
strategy, opts...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -345,7 +345,8 @@ type WalletController interface {
|
|||||||
//
|
//
|
||||||
// NOTE: This method requires the global coin selection lock to be held.
|
// NOTE: This method requires the global coin selection lock to be held.
|
||||||
SendOutputs(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
SendOutputs(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||||
minConfs int32, label string) (*wire.MsgTx, error)
|
minConfs int32, label string,
|
||||||
|
strategy base.CoinSelectionStrategy) (*wire.MsgTx, error)
|
||||||
|
|
||||||
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
|
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
|
||||||
// outputs. The transaction is not broadcasted to the network. In the
|
// outputs. The transaction is not broadcasted to the network. In the
|
||||||
@@ -360,7 +361,8 @@ type WalletController interface {
|
|||||||
//
|
//
|
||||||
// NOTE: This method requires the global coin selection lock to be held.
|
// NOTE: This method requires the global coin selection lock to be held.
|
||||||
CreateSimpleTx(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
CreateSimpleTx(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||||
minConfs int32, dryRun bool) (*txauthor.AuthoredTx, error)
|
minConfs int32, strategy base.CoinSelectionStrategy,
|
||||||
|
dryRun bool) (*txauthor.AuthoredTx, error)
|
||||||
|
|
||||||
// GetTransactionDetails returns a detailed description of a transaction
|
// GetTransactionDetails returns a detailed description of a transaction
|
||||||
// given its transaction hash.
|
// given its transaction hash.
|
||||||
@@ -465,7 +467,8 @@ type WalletController interface {
|
|||||||
// to lock the inputs before handing them out.
|
// to lock the inputs before handing them out.
|
||||||
FundPsbt(packet *psbt.Packet, minConfs int32,
|
FundPsbt(packet *psbt.Packet, minConfs int32,
|
||||||
feeRate chainfee.SatPerKWeight, account string,
|
feeRate chainfee.SatPerKWeight, account string,
|
||||||
changeScope *waddrmgr.KeyScope) (int32, error)
|
changeScope *waddrmgr.KeyScope,
|
||||||
|
strategy base.CoinSelectionStrategy) (int32, error)
|
||||||
|
|
||||||
// SignPsbt expects a partial transaction with all inputs and outputs
|
// SignPsbt expects a partial transaction with all inputs and outputs
|
||||||
// fully declared and tries to sign all unsigned inputs that have all
|
// fully declared and tries to sign all unsigned inputs that have all
|
||||||
|
|||||||
+6
-3
@@ -146,14 +146,16 @@ func (w *mockWalletController) ImportTaprootScript(waddrmgr.KeyScope,
|
|||||||
|
|
||||||
// SendOutputs currently returns dummy values.
|
// SendOutputs currently returns dummy values.
|
||||||
func (w *mockWalletController) SendOutputs([]*wire.TxOut,
|
func (w *mockWalletController) SendOutputs([]*wire.TxOut,
|
||||||
chainfee.SatPerKWeight, int32, string) (*wire.MsgTx, error) {
|
chainfee.SatPerKWeight, int32, string,
|
||||||
|
base.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSimpleTx currently returns dummy values.
|
// CreateSimpleTx currently returns dummy values.
|
||||||
func (w *mockWalletController) CreateSimpleTx([]*wire.TxOut,
|
func (w *mockWalletController) CreateSimpleTx([]*wire.TxOut,
|
||||||
chainfee.SatPerKWeight, int32, bool) (*txauthor.AuthoredTx, error) {
|
chainfee.SatPerKWeight, int32, base.CoinSelectionStrategy,
|
||||||
|
bool) (*txauthor.AuthoredTx, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -214,7 +216,8 @@ func (w *mockWalletController) ListLeasedOutputs() (
|
|||||||
|
|
||||||
// FundPsbt currently does nothing.
|
// FundPsbt currently does nothing.
|
||||||
func (w *mockWalletController) FundPsbt(*psbt.Packet, int32,
|
func (w *mockWalletController) FundPsbt(*psbt.Packet, int32,
|
||||||
chainfee.SatPerKWeight, string, *waddrmgr.KeyScope) (int32, error) {
|
chainfee.SatPerKWeight, string, *waddrmgr.KeyScope,
|
||||||
|
base.CoinSelectionStrategy) (int32, error) {
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,11 +121,11 @@ func (r *RPCKeyRing) NewAddress(addrType lnwallet.AddressType, change bool,
|
|||||||
//
|
//
|
||||||
// NOTE: This method only signs with BIP49/84 keys.
|
// NOTE: This method only signs with BIP49/84 keys.
|
||||||
func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut,
|
func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut,
|
||||||
feeRate chainfee.SatPerKWeight, minConfs int32,
|
feeRate chainfee.SatPerKWeight, minConfs int32, label string,
|
||||||
label string) (*wire.MsgTx, error) {
|
strategy basewallet.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
tx, err := r.WalletController.SendOutputs(
|
tx, err := r.WalletController.SendOutputs(
|
||||||
outputs, feeRate, minConfs, label,
|
outputs, feeRate, minConfs, label, strategy,
|
||||||
)
|
)
|
||||||
if err != nil && err != basewallet.ErrTxUnsigned {
|
if err != nil && err != basewallet.ErrTxUnsigned {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ func sendCoins(t *testing.T, miner *rpctest.Harness,
|
|||||||
|
|
||||||
tx, err := sender.SendOutputs(
|
tx, err := sender.SendOutputs(
|
||||||
[]*wire.TxOut{output}, feeRate, minConf, labels.External,
|
[]*wire.TxOut{output}, feeRate, minConf, labels.External,
|
||||||
|
sender.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to send transaction")
|
require.NoError(t, err, "unable to send transaction")
|
||||||
|
|
||||||
@@ -1189,6 +1190,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
|||||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||||
burnTX, err := alice.SendOutputs(
|
burnTX, err := alice.SendOutputs(
|
||||||
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||||
|
alice.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to create burn tx")
|
require.NoError(t, err, "unable to create burn tx")
|
||||||
burnTXID := burnTX.TxHash()
|
burnTXID := burnTX.TxHash()
|
||||||
@@ -1448,6 +1450,7 @@ func testTransactionSubscriptions(miner *rpctest.Harness,
|
|||||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||||
tx, err := alice.SendOutputs(
|
tx, err := alice.SendOutputs(
|
||||||
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||||
|
alice.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to create tx")
|
require.NoError(t, err, "unable to create tx")
|
||||||
txid := tx.TxHash()
|
txid := tx.TxHash()
|
||||||
@@ -1636,6 +1639,7 @@ func newTx(t *testing.T, r *rpctest.Harness, pubKey *btcec.PublicKey,
|
|||||||
}
|
}
|
||||||
tx, err := alice.SendOutputs(
|
tx, err := alice.SendOutputs(
|
||||||
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||||
|
alice.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to create output")
|
require.NoError(t, err, "unable to create output")
|
||||||
|
|
||||||
@@ -1951,6 +1955,7 @@ func testSignOutputUsingTweaks(r *rpctest.Harness,
|
|||||||
}
|
}
|
||||||
tx, err := alice.SendOutputs(
|
tx, err := alice.SendOutputs(
|
||||||
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||||
|
alice.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create output: %v", err)
|
t.Fatalf("unable to create output: %v", err)
|
||||||
@@ -2069,6 +2074,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
}
|
}
|
||||||
tx, err := w.SendOutputs(
|
tx, err := w.SendOutputs(
|
||||||
[]*wire.TxOut{output}, 2500, 1, labels.External,
|
[]*wire.TxOut{output}, 2500, 1, labels.External,
|
||||||
|
w.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to send outputs")
|
require.NoError(t, err, "unable to send outputs")
|
||||||
txid := tx.TxHash()
|
txid := tx.TxHash()
|
||||||
@@ -2293,6 +2299,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
|
|||||||
}
|
}
|
||||||
_, err = bob.SendOutputs(
|
_, err = bob.SendOutputs(
|
||||||
[]*wire.TxOut{output}, txFeeRate, 0, labels.External,
|
[]*wire.TxOut{output}, txFeeRate, 0, labels.External,
|
||||||
|
bob.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
|
t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
|
||||||
@@ -2319,6 +2326,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
|
|||||||
// using confirmed outputs only.
|
// using confirmed outputs only.
|
||||||
_, err = bob.SendOutputs(
|
_, err = bob.SendOutputs(
|
||||||
[]*wire.TxOut{output}, txFeeRate, 1, labels.External,
|
[]*wire.TxOut{output}, txFeeRate, 1, labels.External,
|
||||||
|
bob.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
|
t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
|
||||||
@@ -2559,7 +2567,8 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
|
|
||||||
// Now try creating a tx spending to these outputs.
|
// Now try creating a tx spending to these outputs.
|
||||||
createTx, createErr := w.CreateSimpleTx(
|
createTx, createErr := w.CreateSimpleTx(
|
||||||
outputs, feeRate, minConfs, true,
|
outputs, feeRate, minConfs,
|
||||||
|
w.Cfg.CoinSelectionStrategy, true,
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case test.valid && createErr != nil:
|
case test.valid && createErr != nil:
|
||||||
@@ -2578,6 +2587,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
// that the change output position might be different.
|
// that the change output position might be different.
|
||||||
tx, sendErr := w.SendOutputs(
|
tx, sendErr := w.SendOutputs(
|
||||||
outputs, feeRate, minConfs, labels.External,
|
outputs, feeRate, minConfs, labels.External,
|
||||||
|
w.Cfg.CoinSelectionStrategy,
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case test.valid && sendErr != nil:
|
case test.valid && sendErr != nil:
|
||||||
|
|||||||
+37
-7
@@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||||
|
"github.com/btcsuite/btcwallet/wallet"
|
||||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
@@ -1067,8 +1068,8 @@ func allowCORS(handler http.Handler, origins []string) http.Handler {
|
|||||||
// more addresses specified in the passed payment map. The payment map maps an
|
// more addresses specified in the passed payment map. The payment map maps an
|
||||||
// address to a specified output value to be sent to that address.
|
// address to a specified output value to be sent to that address.
|
||||||
func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
||||||
feeRate chainfee.SatPerKWeight, minConfs int32,
|
feeRate chainfee.SatPerKWeight, minConfs int32, label string,
|
||||||
label string) (*chainhash.Hash, error) {
|
strategy wallet.CoinSelectionStrategy) (*chainhash.Hash, error) {
|
||||||
|
|
||||||
outputs, err := addrPairsToOutputs(paymentMap, r.cfg.ActiveNetParams.Params)
|
outputs, err := addrPairsToOutputs(paymentMap, r.cfg.ActiveNetParams.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1078,7 +1079,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
|||||||
// We first do a dry run, to sanity check we won't spend our wallet
|
// We first do a dry run, to sanity check we won't spend our wallet
|
||||||
// balance below the reserved amount.
|
// balance below the reserved amount.
|
||||||
authoredTx, err := r.server.cc.Wallet.CreateSimpleTx(
|
authoredTx, err := r.server.cc.Wallet.CreateSimpleTx(
|
||||||
outputs, feeRate, minConfs, true,
|
outputs, feeRate, minConfs, strategy, true,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1099,7 +1100,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
|||||||
// If that checks out, we're fairly confident that creating sending to
|
// If that checks out, we're fairly confident that creating sending to
|
||||||
// these outputs will keep the wallet balance above the reserve.
|
// these outputs will keep the wallet balance above the reserve.
|
||||||
tx, err := r.server.cc.Wallet.SendOutputs(
|
tx, err := r.server.cc.Wallet.SendOutputs(
|
||||||
outputs, feeRate, minConfs, label,
|
outputs, feeRate, minConfs, label, strategy,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1192,12 +1193,23 @@ func (r *rpcServer) EstimateFee(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
|
||||||
|
in.CoinSelectionStrategy,
|
||||||
|
r.server.cc.Wallet.Cfg.CoinSelectionStrategy,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// We will ask the wallet to create a tx using this fee rate. We set
|
// We will ask the wallet to create a tx using this fee rate. We set
|
||||||
// dryRun=true to avoid inflating the change addresses in the db.
|
// dryRun=true to avoid inflating the change addresses in the db.
|
||||||
var tx *txauthor.AuthoredTx
|
var tx *txauthor.AuthoredTx
|
||||||
wallet := r.server.cc.Wallet
|
wallet := r.server.cc.Wallet
|
||||||
err = wallet.WithCoinSelectLock(func() error {
|
err = wallet.WithCoinSelectLock(func() error {
|
||||||
tx, err = wallet.CreateSimpleTx(outputs, feePerKw, minConfs, true)
|
tx, err = wallet.CreateSimpleTx(
|
||||||
|
outputs, feePerKw, minConfs, coinSelectionStrategy,
|
||||||
|
true,
|
||||||
|
)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1281,6 +1293,14 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
|
||||||
|
in.CoinSelectionStrategy,
|
||||||
|
r.server.cc.Wallet.Cfg.CoinSelectionStrategy,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var txid *chainhash.Hash
|
var txid *chainhash.Hash
|
||||||
|
|
||||||
wallet := r.server.cc.Wallet
|
wallet := r.server.cc.Wallet
|
||||||
@@ -1417,7 +1437,8 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||||||
paymentMap := map[string]int64{targetAddr.String(): in.Amount}
|
paymentMap := map[string]int64{targetAddr.String(): in.Amount}
|
||||||
err := wallet.WithCoinSelectLock(func() error {
|
err := wallet.WithCoinSelectLock(func() error {
|
||||||
newTXID, err := r.sendCoinsOnChain(
|
newTXID, err := r.sendCoinsOnChain(
|
||||||
paymentMap, feePerKw, minConfs, label,
|
paymentMap, feePerKw, minConfs,
|
||||||
|
label, coinSelectionStrategy,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1463,6 +1484,14 @@ func (r *rpcServer) SendMany(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
|
||||||
|
in.CoinSelectionStrategy,
|
||||||
|
r.server.cc.Wallet.Cfg.CoinSelectionStrategy,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
rpcsLog.Infof("[sendmany] outputs=%v, sat/kw=%v",
|
rpcsLog.Infof("[sendmany] outputs=%v, sat/kw=%v",
|
||||||
spew.Sdump(in.AddrToAmount), int64(feePerKw))
|
spew.Sdump(in.AddrToAmount), int64(feePerKw))
|
||||||
|
|
||||||
@@ -1474,7 +1503,8 @@ func (r *rpcServer) SendMany(ctx context.Context,
|
|||||||
wallet := r.server.cc.Wallet
|
wallet := r.server.cc.Wallet
|
||||||
err = wallet.WithCoinSelectLock(func() error {
|
err = wallet.WithCoinSelectLock(func() error {
|
||||||
sendManyTXID, err := r.sendCoinsOnChain(
|
sendManyTXID, err := r.sendCoinsOnChain(
|
||||||
in.AddrToAmount, feePerKw, minConfs, label,
|
in.AddrToAmount, feePerKw, minConfs,
|
||||||
|
label, coinSelectionStrategy,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in new issue
Block a user