mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-01 10:41:34 +02:00
multi: expand SendOutputs
and CreateSimpleTx
to take utxos
This commit updates the interface methods from `lnwallet.WalletController` to take optional input set which can be used to create the tx.
This commit is contained in:
parent
468ca87499
commit
99339f706f
@ -811,8 +811,8 @@ func (w *WalletKit) SendOutputs(ctx context.Context,
|
||||
// requirement, we can request that the wallet attempts to create this
|
||||
// transaction.
|
||||
tx, err := w.cfg.Wallet.SendOutputs(
|
||||
outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw), minConfs,
|
||||
label, coinSelectionStrategy,
|
||||
nil, outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw),
|
||||
minConfs, label, coinSelectionStrategy,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
base "github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
)
|
||||
@ -33,6 +34,10 @@ type WalletController struct {
|
||||
Utxos []*lnwallet.Utxo
|
||||
}
|
||||
|
||||
// A compile time check to ensure this mocked WalletController implements the
|
||||
// WalletController.
|
||||
var _ lnwallet.WalletController = (*WalletController)(nil)
|
||||
|
||||
// BackEnd returns "mock" to signify a mock wallet controller.
|
||||
func (w *WalletController) BackEnd() string {
|
||||
return "mock"
|
||||
@ -140,15 +145,15 @@ func (w *WalletController) ImportTaprootScript(waddrmgr.KeyScope,
|
||||
}
|
||||
|
||||
// SendOutputs currently returns dummy values.
|
||||
func (w *WalletController) SendOutputs([]*wire.TxOut,
|
||||
chainfee.SatPerKWeight, int32, string,
|
||||
base.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||
func (w *WalletController) SendOutputs(fn.Set[wire.OutPoint], []*wire.TxOut,
|
||||
chainfee.SatPerKWeight, int32, string, base.CoinSelectionStrategy) (
|
||||
*wire.MsgTx, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CreateSimpleTx currently returns dummy values.
|
||||
func (w *WalletController) CreateSimpleTx([]*wire.TxOut,
|
||||
func (w *WalletController) CreateSimpleTx(fn.Set[wire.OutPoint], []*wire.TxOut,
|
||||
chainfee.SatPerKWeight, int32, base.CoinSelectionStrategy,
|
||||
bool) (*txauthor.AuthoredTx, error) {
|
||||
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcwallet/chain"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/wallet"
|
||||
base "github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||
"github.com/btcsuite/btcwallet/wallet/txrules"
|
||||
@ -26,6 +27,7 @@ import (
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/blockcache"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
@ -977,8 +979,9 @@ func (b *BtcWallet) ImportTaprootScript(scope waddrmgr.KeyScope,
|
||||
// NOTE: This method requires the global coin selection lock to be held.
|
||||
//
|
||||
// This is a part of the WalletController interface.
|
||||
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, minConfs int32, label string,
|
||||
func (b *BtcWallet) SendOutputs(inputs fn.Set[wire.OutPoint],
|
||||
outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||
minConfs int32, label string,
|
||||
strategy base.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||
|
||||
// Convert our fee rate from sat/kw to sat/kb since it's required by
|
||||
@ -995,6 +998,14 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
||||
return nil, lnwallet.ErrInvalidMinconf
|
||||
}
|
||||
|
||||
// Use selected UTXOs if specified, otherwise default selection.
|
||||
if len(inputs) != 0 {
|
||||
return b.wallet.SendOutputsWithInput(
|
||||
outputs, nil, defaultAccount, minConfs, feeSatPerKB,
|
||||
strategy, label, inputs.ToSlice(),
|
||||
)
|
||||
}
|
||||
|
||||
return b.wallet.SendOutputs(
|
||||
outputs, nil, defaultAccount, minConfs, feeSatPerKB,
|
||||
strategy, label,
|
||||
@ -1014,10 +1025,10 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
||||
// NOTE: This method requires the global coin selection lock to be held.
|
||||
//
|
||||
// This is a part of the WalletController interface.
|
||||
func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, minConfs int32,
|
||||
strategy base.CoinSelectionStrategy,
|
||||
dryRun bool) (*txauthor.AuthoredTx, error) {
|
||||
func (b *BtcWallet) CreateSimpleTx(inputs fn.Set[wire.OutPoint],
|
||||
outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight, minConfs int32,
|
||||
strategy base.CoinSelectionStrategy, dryRun bool) (
|
||||
*txauthor.AuthoredTx, error) {
|
||||
|
||||
// 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.
|
||||
@ -1047,9 +1058,12 @@ func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
|
||||
}
|
||||
}
|
||||
|
||||
// Add the optional inputs to the transaction.
|
||||
optFunc := wallet.WithCustomSelectUtxos(inputs.ToSlice())
|
||||
|
||||
return b.wallet.CreateSimpleTx(
|
||||
nil, defaultAccount, outputs, minConfs, feeSatPerKB,
|
||||
strategy, dryRun,
|
||||
strategy, dryRun, []wallet.TxCreateOption{optFunc}...,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
base "github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
)
|
||||
@ -344,8 +345,8 @@ type WalletController interface {
|
||||
// be used when crafting the transaction.
|
||||
//
|
||||
// NOTE: This method requires the global coin selection lock to be held.
|
||||
SendOutputs(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||
minConfs int32, label string,
|
||||
SendOutputs(inputs fn.Set[wire.OutPoint], outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, minConfs int32, label string,
|
||||
strategy base.CoinSelectionStrategy) (*wire.MsgTx, error)
|
||||
|
||||
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
|
||||
@ -360,9 +361,10 @@ type WalletController interface {
|
||||
// SHOULD NOT be broadcasted.
|
||||
//
|
||||
// NOTE: This method requires the global coin selection lock to be held.
|
||||
CreateSimpleTx(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||
minConfs int32, strategy base.CoinSelectionStrategy,
|
||||
dryRun bool) (*txauthor.AuthoredTx, error)
|
||||
CreateSimpleTx(inputs fn.Set[wire.OutPoint], outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, minConfs int32,
|
||||
strategy base.CoinSelectionStrategy, dryRun bool) (
|
||||
*txauthor.AuthoredTx, error)
|
||||
|
||||
// GetTransactionDetails returns a detailed description of a transaction
|
||||
// given its transaction hash.
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
)
|
||||
|
||||
@ -35,6 +36,10 @@ type mockWalletController struct {
|
||||
Utxos []*Utxo
|
||||
}
|
||||
|
||||
// A compile time check to ensure that mockWalletController implements the
|
||||
// WalletController.
|
||||
var _ WalletController = (*mockWalletController)(nil)
|
||||
|
||||
// BackEnd returns "mock" to signify a mock wallet controller.
|
||||
func (w *mockWalletController) BackEnd() string {
|
||||
return "mock"
|
||||
@ -145,7 +150,7 @@ func (w *mockWalletController) ImportTaprootScript(waddrmgr.KeyScope,
|
||||
}
|
||||
|
||||
// SendOutputs currently returns dummy values.
|
||||
func (w *mockWalletController) SendOutputs([]*wire.TxOut,
|
||||
func (w *mockWalletController) SendOutputs(fn.Set[wire.OutPoint], []*wire.TxOut,
|
||||
chainfee.SatPerKWeight, int32, string,
|
||||
base.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||
|
||||
@ -153,9 +158,9 @@ func (w *mockWalletController) SendOutputs([]*wire.TxOut,
|
||||
}
|
||||
|
||||
// CreateSimpleTx currently returns dummy values.
|
||||
func (w *mockWalletController) CreateSimpleTx([]*wire.TxOut,
|
||||
chainfee.SatPerKWeight, int32, base.CoinSelectionStrategy,
|
||||
bool) (*txauthor.AuthoredTx, error) {
|
||||
func (w *mockWalletController) CreateSimpleTx(fn.Set[wire.OutPoint],
|
||||
[]*wire.TxOut, chainfee.SatPerKWeight, int32,
|
||||
base.CoinSelectionStrategy, bool) (*txauthor.AuthoredTx, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
basewallet "github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
@ -120,12 +121,13 @@ func (r *RPCKeyRing) NewAddress(addrType lnwallet.AddressType, change bool,
|
||||
// NOTE: This is a part of the WalletController interface.
|
||||
//
|
||||
// NOTE: This method only signs with BIP49/84 keys.
|
||||
func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, minConfs int32, label string,
|
||||
func (r *RPCKeyRing) SendOutputs(inputs fn.Set[wire.OutPoint],
|
||||
outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||
minConfs int32, label string,
|
||||
strategy basewallet.CoinSelectionStrategy) (*wire.MsgTx, error) {
|
||||
|
||||
tx, err := r.WalletController.SendOutputs(
|
||||
outputs, feeRate, minConfs, label, strategy,
|
||||
inputs, outputs, feeRate, minConfs, label, strategy,
|
||||
)
|
||||
if err != nil && err != basewallet.ErrTxUnsigned {
|
||||
return nil, err
|
||||
|
@ -169,7 +169,7 @@ func sendCoins(t *testing.T, miner *rpctest.Harness,
|
||||
t.Helper()
|
||||
|
||||
tx, err := sender.SendOutputs(
|
||||
[]*wire.TxOut{output}, feeRate, minConf, labels.External,
|
||||
nil, []*wire.TxOut{output}, feeRate, minConf, labels.External,
|
||||
sender.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
require.NoError(t, err, "unable to send transaction")
|
||||
@ -1193,7 +1193,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
||||
require.NoError(t, err, "unable to make output script")
|
||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||
burnTX, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||
nil, []*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||
alice.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
require.NoError(t, err, "unable to create burn tx")
|
||||
@ -1453,7 +1453,7 @@ func testTransactionSubscriptions(miner *rpctest.Harness,
|
||||
|
||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||
tx, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||
nil, []*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||
alice.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
require.NoError(t, err, "unable to create tx")
|
||||
@ -1642,7 +1642,7 @@ func newTx(t *testing.T, r *rpctest.Harness, pubKey *btcec.PublicKey,
|
||||
PkScript: keyScript,
|
||||
}
|
||||
tx, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||
nil, []*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||
alice.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
require.NoError(t, err, "unable to create output")
|
||||
@ -1958,7 +1958,7 @@ func testSignOutputUsingTweaks(r *rpctest.Harness,
|
||||
PkScript: keyScript,
|
||||
}
|
||||
tx, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||
nil, []*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||
alice.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
if err != nil {
|
||||
@ -2077,7 +2077,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||
PkScript: script,
|
||||
}
|
||||
tx, err := w.SendOutputs(
|
||||
[]*wire.TxOut{output}, 2500, 1, labels.External,
|
||||
nil, []*wire.TxOut{output}, 2500, 1, labels.External,
|
||||
w.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
require.NoError(t, err, "unable to send outputs")
|
||||
@ -2302,7 +2302,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
|
||||
PkScript: alicePkScript,
|
||||
}
|
||||
_, err = bob.SendOutputs(
|
||||
[]*wire.TxOut{output}, txFeeRate, 0, labels.External,
|
||||
nil, []*wire.TxOut{output}, txFeeRate, 0, labels.External,
|
||||
bob.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
if err == nil {
|
||||
@ -2329,7 +2329,7 @@ func testSpendUnconfirmed(miner *rpctest.Harness,
|
||||
// First, verify that we don't have enough balance to send the coins
|
||||
// using confirmed outputs only.
|
||||
_, err = bob.SendOutputs(
|
||||
[]*wire.TxOut{output}, txFeeRate, 1, labels.External,
|
||||
nil, []*wire.TxOut{output}, txFeeRate, 1, labels.External,
|
||||
bob.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
if err == nil {
|
||||
@ -2571,7 +2571,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||
|
||||
// Now try creating a tx spending to these outputs.
|
||||
createTx, createErr := w.CreateSimpleTx(
|
||||
outputs, feeRate, minConfs,
|
||||
nil, outputs, feeRate, minConfs,
|
||||
w.Cfg.CoinSelectionStrategy, true,
|
||||
)
|
||||
switch {
|
||||
@ -2590,7 +2590,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||
// only difference is that the dry run tx is not signed, and
|
||||
// that the change output position might be different.
|
||||
tx, sendErr := w.SendOutputs(
|
||||
outputs, feeRate, minConfs, labels.External,
|
||||
nil, outputs, feeRate, minConfs, labels.External,
|
||||
w.Cfg.CoinSelectionStrategy,
|
||||
)
|
||||
switch {
|
||||
|
@ -1077,7 +1077,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
||||
// We first do a dry run, to sanity check we won't spend our wallet
|
||||
// balance below the reserved amount.
|
||||
authoredTx, err := r.server.cc.Wallet.CreateSimpleTx(
|
||||
outputs, feeRate, minConfs, strategy, true,
|
||||
nil, outputs, feeRate, minConfs, strategy, true,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1098,7 +1098,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
||||
// If that checks out, we're fairly confident that creating sending to
|
||||
// these outputs will keep the wallet balance above the reserve.
|
||||
tx, err := r.server.cc.Wallet.SendOutputs(
|
||||
outputs, feeRate, minConfs, label, strategy,
|
||||
nil, outputs, feeRate, minConfs, label, strategy,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1207,7 +1207,7 @@ func (r *rpcServer) EstimateFee(ctx context.Context,
|
||||
wallet := r.server.cc.Wallet
|
||||
err = wallet.WithCoinSelectLock(func() error {
|
||||
tx, err = wallet.CreateSimpleTx(
|
||||
outputs, feePerKw, minConfs, coinSelectionStrategy,
|
||||
nil, outputs, feePerKw, minConfs, coinSelectionStrategy,
|
||||
true,
|
||||
)
|
||||
return err
|
||||
|
Loading…
x
Reference in New Issue
Block a user