walletrpc: make use of custom lock ID and lock duration in FundPsbt
This commit is contained in:
3 files changed
+59
-17
No files matched your search
+18
-7
@@ -6,6 +6,7 @@ package walletrpc
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
base "github.com/btcsuite/btcwallet/wallet"
|
base "github.com/btcsuite/btcwallet/wallet"
|
||||||
@@ -40,10 +41,12 @@ func verifyInputsUnspent(inputs []*wire.TxIn, utxos []*lnwallet.Utxo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// lockInputs requests a lock lease for all inputs specified in a PSBT packet
|
// lockInputs requests lock leases for all inputs specified in a PSBT packet
|
||||||
// by using the internal, static lock ID of lnd's wallet.
|
// (the passed outpoints), using either the optional custom lock ID and duration
|
||||||
func lockInputs(w lnwallet.WalletController,
|
// or the wallet's internal static lock ID with the default 10-minute duration.
|
||||||
outpoints []wire.OutPoint) ([]*base.ListLeasedOutputResult, error) {
|
func lockInputs(w lnwallet.WalletController, outpoints []wire.OutPoint,
|
||||||
|
customLockID *wtxmgr.LockID, customLockDuration time.Duration) (
|
||||||
|
[]*base.ListLeasedOutputResult, error) {
|
||||||
|
|
||||||
locks := make(
|
locks := make(
|
||||||
[]*base.ListLeasedOutputResult, len(outpoints),
|
[]*base.ListLeasedOutputResult, len(outpoints),
|
||||||
@@ -51,11 +54,20 @@ func lockInputs(w lnwallet.WalletController,
|
|||||||
for idx := range outpoints {
|
for idx := range outpoints {
|
||||||
lock := &base.ListLeasedOutputResult{
|
lock := &base.ListLeasedOutputResult{
|
||||||
LockedOutput: &wtxmgr.LockedOutput{
|
LockedOutput: &wtxmgr.LockedOutput{
|
||||||
LockID: chanfunding.LndInternalLockID,
|
|
||||||
Outpoint: outpoints[idx],
|
Outpoint: outpoints[idx],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock.LockID = chanfunding.LndInternalLockID
|
||||||
|
if customLockID != nil {
|
||||||
|
lock.LockID = *customLockID
|
||||||
|
}
|
||||||
|
|
||||||
|
lockDuration := chanfunding.DefaultLockDuration
|
||||||
|
if customLockDuration != 0 {
|
||||||
|
lockDuration = customLockDuration
|
||||||
|
}
|
||||||
|
|
||||||
// Get the details about this outpoint.
|
// Get the details about this outpoint.
|
||||||
utxo, err := w.FetchOutpointInfo(&lock.Outpoint)
|
utxo, err := w.FetchOutpointInfo(&lock.Outpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -63,8 +75,7 @@ func lockInputs(w lnwallet.WalletController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
expiration, err := w.LeaseOutput(
|
expiration, err := w.LeaseOutput(
|
||||||
lock.LockID, lock.Outpoint,
|
lock.LockID, lock.Outpoint, lockDuration,
|
||||||
chanfunding.DefaultLockDuration,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we run into a problem with locking one output, we
|
// If we run into a problem with locking one output, we
|
||||||
|
|||||||
@@ -1600,6 +1600,24 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
account = req.Account
|
account = req.Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var customLockID *wtxmgr.LockID
|
||||||
|
if len(req.CustomLockId) > 0 {
|
||||||
|
lockID := wtxmgr.LockID{}
|
||||||
|
if len(req.CustomLockId) != len(lockID) {
|
||||||
|
return nil, fmt.Errorf("custom lock ID must be " +
|
||||||
|
"exactly 32 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(lockID[:], req.CustomLockId)
|
||||||
|
customLockID = &lockID
|
||||||
|
}
|
||||||
|
|
||||||
|
var customLockDuration time.Duration
|
||||||
|
if req.LockExpirationSeconds != 0 {
|
||||||
|
customLockDuration = time.Duration(req.LockExpirationSeconds) *
|
||||||
|
time.Second
|
||||||
|
}
|
||||||
|
|
||||||
// There are three ways a user can specify what we call the template (a
|
// There are three ways a user can specify what we call the template (a
|
||||||
// list of inputs and outputs to use in the PSBT): Either as a PSBT
|
// list of inputs and outputs to use in the PSBT): Either as a PSBT
|
||||||
// packet directly with no coin selection, a PSBT with coin selection or
|
// packet directly with no coin selection, a PSBT with coin selection or
|
||||||
@@ -1619,6 +1637,7 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
return w.fundPsbtInternalWallet(
|
return w.fundPsbtInternalWallet(
|
||||||
account, keyScopeFromChangeAddressType(req.ChangeType),
|
account, keyScopeFromChangeAddressType(req.ChangeType),
|
||||||
packet, minConfs, feeSatPerKW, coinSelectionStrategy,
|
packet, minConfs, feeSatPerKW, coinSelectionStrategy,
|
||||||
|
customLockID, customLockDuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
// The template is specified as a PSBT with the intention to perform
|
// The template is specified as a PSBT with the intention to perform
|
||||||
@@ -1701,6 +1720,7 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
return w.fundPsbtCoinSelect(
|
return w.fundPsbtCoinSelect(
|
||||||
account, changeIndex, packet, minConfs, changeType,
|
account, changeIndex, packet, minConfs, changeType,
|
||||||
feeSatPerKW, coinSelectionStrategy, maxFeeRatio,
|
feeSatPerKW, coinSelectionStrategy, maxFeeRatio,
|
||||||
|
customLockID, customLockDuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
@@ -1758,6 +1778,7 @@ func (w *WalletKit) FundPsbt(_ context.Context,
|
|||||||
return w.fundPsbtInternalWallet(
|
return w.fundPsbtInternalWallet(
|
||||||
account, keyScopeFromChangeAddressType(req.ChangeType),
|
account, keyScopeFromChangeAddressType(req.ChangeType),
|
||||||
packet, minConfs, feeSatPerKW, coinSelectionStrategy,
|
packet, minConfs, feeSatPerKW, coinSelectionStrategy,
|
||||||
|
customLockID, customLockDuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1770,8 +1791,9 @@ 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,
|
feeSatPerKW chainfee.SatPerKWeight, strategy base.CoinSelectionStrategy,
|
||||||
strategy base.CoinSelectionStrategy) (*FundPsbtResponse, error) {
|
customLockID *wtxmgr.LockID, customLockDuration time.Duration) (
|
||||||
|
*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
|
||||||
@@ -1885,7 +1907,8 @@ func (w *WalletKit) fundPsbtInternalWallet(account string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, err = w.lockAndCreateFundingResponse(
|
response, err = w.lockAndCreateFundingResponse(
|
||||||
packet, outpoints, changeIndex,
|
packet, outpoints, changeIndex, customLockID,
|
||||||
|
customLockDuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@@ -1904,7 +1927,8 @@ 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, strategy base.CoinSelectionStrategy,
|
feeRate chainfee.SatPerKWeight, strategy base.CoinSelectionStrategy,
|
||||||
maxFeeRatio float64) (*FundPsbtResponse, error) {
|
maxFeeRatio float64, customLockID *wtxmgr.LockID,
|
||||||
|
customLockDuration time.Duration) (*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
|
||||||
@@ -2019,7 +2043,10 @@ func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We're done. Let's serialize and return the updated package.
|
// We're done. Let's serialize and return the updated package.
|
||||||
return w.lockAndCreateFundingResponse(packet, nil, changeIndex)
|
return w.lockAndCreateFundingResponse(
|
||||||
|
packet, nil, changeIndex, customLockID,
|
||||||
|
customLockDuration,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The RPC parsing part is now over. Several of the following operations
|
// The RPC parsing part is now over. Several of the following operations
|
||||||
@@ -2091,7 +2118,8 @@ func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, err = w.lockAndCreateFundingResponse(
|
response, err = w.lockAndCreateFundingResponse(
|
||||||
packet, addedOutpoints, changeIndex,
|
packet, addedOutpoints, changeIndex, customLockID,
|
||||||
|
customLockDuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@@ -2136,8 +2164,9 @@ func (w *WalletKit) assertNotAvailable(inputs []*wire.TxIn, minConfs int32,
|
|||||||
// lockAndCreateFundingResponse locks the given outpoints and creates a funding
|
// lockAndCreateFundingResponse locks the given outpoints and creates a funding
|
||||||
// response with the serialized PSBT, the change index and the locked UTXOs.
|
// response with the serialized PSBT, the change index and the locked UTXOs.
|
||||||
func (w *WalletKit) lockAndCreateFundingResponse(packet *psbt.Packet,
|
func (w *WalletKit) lockAndCreateFundingResponse(packet *psbt.Packet,
|
||||||
newOutpoints []wire.OutPoint, changeIndex int32) (*FundPsbtResponse,
|
newOutpoints []wire.OutPoint, changeIndex int32,
|
||||||
error) {
|
customLockID *wtxmgr.LockID, customLockDuration time.Duration) (
|
||||||
|
*FundPsbtResponse, error) {
|
||||||
|
|
||||||
// Make sure we can properly serialize the packet. If this goes wrong
|
// Make sure we can properly serialize the packet. If this goes wrong
|
||||||
// then something isn't right with the inputs, and we probably shouldn't
|
// then something isn't right with the inputs, and we probably shouldn't
|
||||||
@@ -2148,7 +2177,9 @@ func (w *WalletKit) lockAndCreateFundingResponse(packet *psbt.Packet,
|
|||||||
return nil, fmt.Errorf("error serializing funded PSBT: %w", err)
|
return nil, fmt.Errorf("error serializing funded PSBT: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
locks, err := lockInputs(w.cfg.Wallet, newOutpoints)
|
locks, err := lockInputs(
|
||||||
|
w.cfg.Wallet, newOutpoints, customLockID, customLockDuration,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not lock inputs: %w", err)
|
return nil, fmt.Errorf("could not lock inputs: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ func TestFundPsbtCoinSelect(t *testing.T) {
|
|||||||
"", tc.changeIndex, copiedPacket, 0,
|
"", tc.changeIndex, copiedPacket, 0,
|
||||||
tc.changeType, tc.feeRate,
|
tc.changeType, tc.feeRate,
|
||||||
rpcServer.cfg.CoinSelectionStrategy,
|
rpcServer.cfg.CoinSelectionStrategy,
|
||||||
tc.maxFeeRatio,
|
tc.maxFeeRatio, nil, 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
Reference in new issue
Block a user