multi: forward SendCoins call over RPC

This commit is contained in:
Oliver Gugger committed 2021-10-14 15:42:52 +02:00
1 parent 19db382e24
commit a3addcc927
8 files changed
+117 -14

No files matched your search

+4 -3
View File
@@ -642,7 +642,8 @@ func (b *BtcWallet) ImportPublicKey(pubKey *btcec.PublicKey,
//
// This is a part of the WalletController interface.
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
feeRate chainfee.SatPerKWeight, minConfs int32, label string) (*wire.MsgTx, error) {
feeRate chainfee.SatPerKWeight, minConfs int32,
label string) (*wire.MsgTx, error) {
// Convert our fee rate from sat/kw to sat/kb since it's required by
// SendOutputs.
@@ -1080,7 +1081,7 @@ func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
// responsibility to lock the inputs before handing them out.
//
// This is a part of the WalletController interface.
func (b *BtcWallet) FundPsbt(packet *psbt.Packet,
func (b *BtcWallet) FundPsbt(packet *psbt.Packet, minConfs int32,
feeRate chainfee.SatPerKWeight, accountName string) (int32, error) {
// The fee rate is passed in using units of sat/kw, so we'll convert
@@ -1115,7 +1116,7 @@ func (b *BtcWallet) FundPsbt(packet *psbt.Packet,
// Let the wallet handle coin selection and/or fee estimation based on
// the partial TX information in the packet.
return b.wallet.FundPsbt(
packet, keyScope, accountNum, feeSatPerKB,
packet, keyScope, minConfs, accountNum, feeSatPerKB,
b.cfg.CoinSelectionStrategy,
)
}
+2 -2
View File
@@ -350,8 +350,8 @@ type WalletController interface {
// fee rate, an error is returned. No lock lease is acquired for any of
// the selected/validated inputs. It is in the caller's responsibility
// to lock the inputs before handing them out.
FundPsbt(packet *psbt.Packet, feeRate chainfee.SatPerKWeight,
account string) (int32, error)
FundPsbt(packet *psbt.Packet, minConfs int32,
feeRate chainfee.SatPerKWeight, account string) (int32, error)
// FinalizePsbt expects a partial transaction with all inputs and
// outputs fully declared and tries to sign all inputs that belong to
+105
View File
@@ -11,16 +11,20 @@ import (
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcwallet/waddrmgr"
btcwallet "github.com/btcsuite/btcwallet/wallet"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/macaroons"
"google.golang.org/grpc"
@@ -139,6 +143,26 @@ func (r *RPCKeyRing) NewAddress(addrType lnwallet.AddressType, change bool,
return localAddr, nil
}
// LastUnusedAddress returns the last *unused* address known by the wallet. An
// address is unused if it hasn't received any payments. This can be useful in
// UIs in order to continually show the "freshest" address without having to
// worry about "address inflation" caused by continual refreshing. Similar to
// NewAddress it can derive a specified address type, and also optionally a
// change address. The account parameter must be non-empty as it determines
// which account the address should be generated from.
func (r *RPCKeyRing) LastUnusedAddress(lnwallet.AddressType,
string) (btcutil.Address, error) {
// Because the underlying wallet will create a new address if the last
// derived address has been used in the meantime, we would need to proxy
// that call as well. But since that's deep within the btcwallet code,
// we cannot easily proxy it without more refactoring. Since this is an
// address type that is probably not widely used we can probably get
// away with not supporting it.
return nil, fmt.Errorf("unused address types are not supported when " +
"remote signing is enabled")
}
// ImportAccount imports an account backed by an account extended public key.
// The master key fingerprint denotes the fingerprint of the root key
// corresponding to the account public key (also known as the key with
@@ -265,6 +289,67 @@ func (r *RPCKeyRing) ImportPublicKey(pubKey *btcec.PublicKey,
return nil
}
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying out to
// the specified outputs. In the case the wallet has insufficient funds, or the
// outputs are non-standard, a non-nil error will be returned.
//
// NOTE: This method requires the global coin selection lock to be held.
//
// This is a part of the WalletController interface.
func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut,
feeRate chainfee.SatPerKWeight, minConfs int32,
label string) (*wire.MsgTx, error) {
tx, err := r.WalletController.SendOutputs(
outputs, feeRate, minConfs, label,
)
if err != nil && err != btcwallet.ErrTxUnsigned {
return nil, err
}
if err == nil {
// This shouldn't happen since our wallet controller is watch-
// only and can't sign the TX.
return tx, nil
}
// We know at this point that we only have inputs from our own wallet.
// So we can just compute the input script using the remote signer.
signDesc := input.SignDescriptor{
HashType: txscript.SigHashAll,
SigHashes: txscript.NewTxSigHashes(tx),
}
for i, txIn := range tx.TxIn {
// We can only sign this input if it's ours, so we'll ask the
// watch-only wallet if it can map this outpoint into a coin we
// own. If not, then we can't continue because our wallet state
// is out of sync.
info, err := r.coinFromOutPoint(txIn.PreviousOutPoint)
if err != nil {
return nil, fmt.Errorf("error looking up utxo: %v", err)
}
// Now that we know the input is ours, we'll populate the
// signDesc with the per input unique information.
signDesc.Output = &wire.TxOut{
Value: info.Value,
PkScript: info.PkScript,
}
signDesc.InputIndex = i
// Finally, we'll sign the input as is, and populate the input
// with the witness and sigScript (if needed).
inputScript, err := r.ComputeInputScript(tx, &signDesc)
if err != nil {
return nil, err
}
txIn.SignatureScript = inputScript.SigScript
txIn.Witness = inputScript.Witness
}
return tx, r.WalletController.PublishTransaction(tx, label)
}
// DeriveNextKey attempts to derive the *next* key within the key family
// (account in BIP43) specified. This method should return the next external
// child within this branch.
@@ -534,6 +619,26 @@ func (r *RPCKeyRing) ComputeInputScript(tx *wire.MsgTx,
}, nil
}
// coinFromOutPoint attempts to locate details pertaining to a coin based on
// its outpoint. If the coin isn't under the control of the backing watch-only
// wallet, then an error is returned.
func (r *RPCKeyRing) coinFromOutPoint(op wire.OutPoint) (*chanfunding.Coin,
error) {
inputInfo, err := r.WalletController.FetchInputInfo(&op)
if err != nil {
return nil, err
}
return &chanfunding.Coin{
TxOut: wire.TxOut{
Value: int64(inputInfo.Value),
PkScript: inputInfo.PkScript,
},
OutPoint: inputInfo.OutPoint,
}, nil
}
// toRPCSignReq converts the given raw transaction and sign descriptors into
// their corresponding RPC counterparts.
func toRPCSignReq(tx *wire.MsgTx,