• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 11170835610

03 Oct 2024 10:41PM UTC coverage: 49.188% (-9.6%) from 58.738%
11170835610

push

github

web-flow
Merge pull request #9154 from ziggie1984/master

multi: bump btcd version.

3 of 6 new or added lines in 6 files covered. (50.0%)

26110 existing lines in 428 files now uncovered.

97359 of 197934 relevant lines covered (49.19%)

1.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.48
/lnwallet/rpcwallet/rpcwallet.go
1
package rpcwallet
2

3
import (
4
        "bytes"
5
        "context"
6
        "crypto/sha256"
7
        "crypto/x509"
8
        "errors"
9
        "fmt"
10
        "os"
11
        "time"
12

13
        "github.com/btcsuite/btcd/btcec/v2"
14
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
15
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
16
        "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
17
        "github.com/btcsuite/btcd/btcutil"
18
        "github.com/btcsuite/btcd/btcutil/hdkeychain"
19
        "github.com/btcsuite/btcd/btcutil/psbt"
20
        "github.com/btcsuite/btcd/chaincfg"
21
        "github.com/btcsuite/btcd/txscript"
22
        "github.com/btcsuite/btcd/wire"
23
        "github.com/btcsuite/btcwallet/waddrmgr"
24
        basewallet "github.com/btcsuite/btcwallet/wallet"
25
        "github.com/lightningnetwork/lnd/fn"
26
        "github.com/lightningnetwork/lnd/input"
27
        "github.com/lightningnetwork/lnd/keychain"
28
        "github.com/lightningnetwork/lnd/lncfg"
29
        "github.com/lightningnetwork/lnd/lnrpc/signrpc"
30
        "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
31
        "github.com/lightningnetwork/lnd/lnwallet"
32
        "github.com/lightningnetwork/lnd/lnwallet/btcwallet"
33
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
34
        "github.com/lightningnetwork/lnd/lnwire"
35
        "github.com/lightningnetwork/lnd/macaroons"
36
        "google.golang.org/grpc"
37
        "google.golang.org/grpc/codes"
38
        "google.golang.org/grpc/credentials"
39
        "google.golang.org/grpc/status"
40
        "gopkg.in/macaroon.v2"
41
)
42

43
var (
44
        // ErrRemoteSigningPrivateKeyNotAvailable is the error that is returned
45
        // if an operation is requested from the RPC wallet that is not
46
        // supported in remote signing mode.
47
        ErrRemoteSigningPrivateKeyNotAvailable = errors.New("deriving " +
48
                "private key is not supported by RPC based key ring")
49
)
50

51
// RPCKeyRing is an implementation of the SecretKeyRing interface that uses a
52
// local watch-only wallet for keeping track of addresses and transactions but
53
// delegates any signing or ECDH operations to a remote node through RPC.
54
type RPCKeyRing struct {
55
        // WalletController is the embedded wallet controller of the watch-only
56
        // base wallet. We need to overwrite/shadow certain of the implemented
57
        // methods to make sure we can mirror them to the remote wallet.
58
        lnwallet.WalletController
59

60
        watchOnlyKeyRing keychain.SecretKeyRing
61

62
        netParams *chaincfg.Params
63

64
        rpcTimeout time.Duration
65

66
        signerClient signrpc.SignerClient
67
        walletClient walletrpc.WalletKitClient
68
}
69

70
var _ keychain.SecretKeyRing = (*RPCKeyRing)(nil)
71
var _ input.Signer = (*RPCKeyRing)(nil)
72
var _ keychain.MessageSignerRing = (*RPCKeyRing)(nil)
73
var _ lnwallet.WalletController = (*RPCKeyRing)(nil)
74

75
// NewRPCKeyRing creates a new remote signing secret key ring that uses the
76
// given watch-only base wallet to keep track of addresses and transactions but
77
// delegates any signing or ECDH operations to the remove signer through RPC.
78
func NewRPCKeyRing(watchOnlyKeyRing keychain.SecretKeyRing,
79
        watchOnlyWalletController lnwallet.WalletController,
80
        remoteSigner *lncfg.RemoteSigner,
81
        netParams *chaincfg.Params) (*RPCKeyRing, error) {
2✔
82

2✔
83
        rpcConn, err := connectRPC(
2✔
84
                remoteSigner.RPCHost, remoteSigner.TLSCertPath,
2✔
85
                remoteSigner.MacaroonPath, remoteSigner.Timeout,
2✔
86
        )
2✔
87
        if err != nil {
2✔
88
                return nil, fmt.Errorf("error connecting to the remote "+
×
89
                        "signing node through RPC: %v", err)
×
90
        }
×
91

92
        return &RPCKeyRing{
2✔
93
                WalletController: watchOnlyWalletController,
2✔
94
                watchOnlyKeyRing: watchOnlyKeyRing,
2✔
95
                netParams:        netParams,
2✔
96
                rpcTimeout:       remoteSigner.Timeout,
2✔
97
                signerClient:     signrpc.NewSignerClient(rpcConn),
2✔
98
                walletClient:     walletrpc.NewWalletKitClient(rpcConn),
2✔
99
        }, nil
2✔
100
}
101

102
// NewAddress returns the next external or internal address for the
103
// wallet dictated by the value of the `change` parameter. If change is
104
// true, then an internal address should be used, otherwise an external
105
// address should be returned. The type of address returned is dictated
106
// by the wallet's capabilities, and may be of type: p2sh, p2wkh,
107
// p2wsh, etc. The account parameter must be non-empty as it determines
108
// which account the address should be generated from.
109
func (r *RPCKeyRing) NewAddress(addrType lnwallet.AddressType, change bool,
110
        account string) (btcutil.Address, error) {
2✔
111

2✔
112
        return r.WalletController.NewAddress(addrType, change, account)
2✔
113
}
2✔
114

115
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying out to
116
// the specified outputs. In the case the wallet has insufficient funds, or the
117
// outputs are non-standard, a non-nil error will be returned.
118
//
119
// NOTE: This method requires the global coin selection lock to be held.
120
//
121
// NOTE: This is a part of the WalletController interface.
122
//
123
// NOTE: This method only signs with BIP49/84 keys.
124
func (r *RPCKeyRing) SendOutputs(inputs fn.Set[wire.OutPoint],
125
        outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
126
        minConfs int32, label string,
127
        strategy basewallet.CoinSelectionStrategy) (*wire.MsgTx, error) {
2✔
128

2✔
129
        tx, err := r.WalletController.SendOutputs(
2✔
130
                inputs, outputs, feeRate, minConfs, label, strategy,
2✔
131
        )
2✔
132
        if err != nil && err != basewallet.ErrTxUnsigned {
2✔
133
                return nil, err
×
134
        }
×
135
        if err == nil {
2✔
136
                // This shouldn't happen since our wallet controller is watch-
×
137
                // only and can't sign the TX.
×
138
                return tx, nil
×
139
        }
×
140

141
        // We know at this point that we only have inputs from our own wallet.
142
        // So we can just compute the input script using the remote signer.
143
        outputFetcher := lnwallet.NewWalletPrevOutputFetcher(r.WalletController)
2✔
144
        for i, txIn := range tx.TxIn {
4✔
145
                signDesc := input.SignDescriptor{
2✔
146
                        HashType: txscript.SigHashAll,
2✔
147
                        SigHashes: txscript.NewTxSigHashes(
2✔
148
                                tx, outputFetcher,
2✔
149
                        ),
2✔
150
                        PrevOutputFetcher: outputFetcher,
2✔
151
                }
2✔
152

2✔
153
                // We can only sign this input if it's ours, so we'll ask the
2✔
154
                // watch-only wallet if it can map this outpoint into a coin we
2✔
155
                // own. If not, then we can't continue because our wallet state
2✔
156
                // is out of sync.
2✔
157
                info, err := r.WalletController.FetchOutpointInfo(
2✔
158
                        &txIn.PreviousOutPoint,
2✔
159
                )
2✔
160
                if err != nil {
2✔
161
                        return nil, fmt.Errorf("error looking up utxo: %w", err)
×
162
                }
×
163

164
                if txscript.IsPayToTaproot(info.PkScript) {
4✔
165
                        signDesc.HashType = txscript.SigHashDefault
2✔
166
                }
2✔
167

168
                // Now that we know the input is ours, we'll populate the
169
                // signDesc with the per input unique information.
170
                signDesc.Output = &wire.TxOut{
2✔
171
                        Value:    int64(info.Value),
2✔
172
                        PkScript: info.PkScript,
2✔
173
                }
2✔
174
                signDesc.InputIndex = i
2✔
175

2✔
176
                // Finally, we'll sign the input as is, and populate the input
2✔
177
                // with the witness and sigScript (if needed).
2✔
178
                inputScript, err := r.ComputeInputScript(tx, &signDesc)
2✔
179
                if err != nil {
2✔
180
                        return nil, err
×
181
                }
×
182

183
                txIn.SignatureScript = inputScript.SigScript
2✔
184
                txIn.Witness = inputScript.Witness
2✔
185
        }
186

187
        return tx, r.WalletController.PublishTransaction(tx, label)
2✔
188
}
189

190
// SignPsbt expects a partial transaction with all inputs and outputs fully
191
// declared and tries to sign all unsigned inputs that have all required fields
192
// (UTXO information, BIP32 derivation information, witness or sig scripts) set.
193
// If no error is returned, the PSBT is ready to be given to the next signer or
194
// to be finalized if lnd was the last signer.
195
//
196
// NOTE: This RPC only signs inputs (and only those it can sign), it does not
197
// perform any other tasks (such as coin selection, UTXO locking or
198
// input/output/fee value validation, PSBT finalization). Any input that is
199
// incomplete will be skipped.
200
func (r *RPCKeyRing) SignPsbt(packet *psbt.Packet) ([]uint32, error) {
2✔
201
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
202
        defer cancel()
2✔
203

2✔
204
        var buf bytes.Buffer
2✔
205
        if err := packet.Serialize(&buf); err != nil {
2✔
206
                return nil, fmt.Errorf("error serializing PSBT: %w", err)
×
207
        }
×
208

209
        resp, err := r.walletClient.SignPsbt(ctxt, &walletrpc.SignPsbtRequest{
2✔
210
                FundedPsbt: buf.Bytes(),
2✔
211
        })
2✔
212
        if err != nil {
2✔
213
                considerShutdown(err)
×
214
                return nil, fmt.Errorf("error signing PSBT in remote signer "+
×
215
                        "instance: %v", err)
×
216
        }
×
217

218
        signedPacket, err := psbt.NewFromRawBytes(
2✔
219
                bytes.NewReader(resp.SignedPsbt), false,
2✔
220
        )
2✔
221
        if err != nil {
2✔
222
                return nil, fmt.Errorf("error parsing signed PSBT: %w", err)
×
223
        }
×
224

225
        // The caller expects the packet to be modified instead of a new
226
        // instance to be returned. So we just overwrite all fields in the
227
        // original packet.
228
        packet.UnsignedTx = signedPacket.UnsignedTx
2✔
229
        packet.Inputs = signedPacket.Inputs
2✔
230
        packet.Outputs = signedPacket.Outputs
2✔
231
        packet.Unknowns = signedPacket.Unknowns
2✔
232

2✔
233
        return resp.SignedInputs, nil
2✔
234
}
235

236
// FinalizePsbt expects a partial transaction with all inputs and outputs fully
237
// declared and tries to sign all inputs that belong to the specified account.
238
// Lnd must be the last signer of the transaction. That means, if there are any
239
// unsigned non-witness inputs or inputs without UTXO information attached or
240
// inputs without witness data that do not belong to lnd's wallet, this method
241
// will fail. If no error is returned, the PSBT is ready to be extracted and the
242
// final TX within to be broadcast.
243
//
244
// NOTE: This method does NOT publish the transaction after it's been
245
// finalized successfully.
246
//
247
// NOTE: This is a part of the WalletController interface.
248
//
249
// NOTE: We need to overwrite this method because we need to redirect the call
250
// to ComputeInputScript to the RPC key ring's implementation. If we forward
251
// the call to the default WalletController implementation, we get an error
252
// since that wallet is watch-only. If we forward the call to the remote signer,
253
// we get an error because the signer doesn't know the UTXO information required
254
// in ComputeInputScript.
255
//
256
// TODO(guggero): Refactor btcwallet to accept ComputeInputScript as a function
257
// parameter in FinalizePsbt so we can get rid of this code duplication.
258
func (r *RPCKeyRing) FinalizePsbt(packet *psbt.Packet, _ string) error {
2✔
259
        // Let's check that this is actually something we can and want to sign.
2✔
260
        // We need at least one input and one output. In addition each
2✔
261
        // input needs nonWitness Utxo or witness Utxo data specified.
2✔
262
        err := psbt.InputsReadyToSign(packet)
2✔
263
        if err != nil {
2✔
264
                return err
×
265
        }
×
266

267
        // Go through each input that doesn't have final witness data attached
268
        // to it already and try to sign it. We do expect that we're the last
269
        // ones to sign. If there is any input without witness data that we
270
        // cannot sign because it's not our UTXO, this will be a hard failure.
271
        tx := packet.UnsignedTx
2✔
272
        prevOutFetcher := basewallet.PsbtPrevOutputFetcher(packet)
2✔
273
        sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
2✔
274
        for idx, txIn := range tx.TxIn {
4✔
275
                in := packet.Inputs[idx]
2✔
276

2✔
277
                // We can only sign if we have UTXO information available. We
2✔
278
                // can just continue here as a later step will fail with a more
2✔
279
                // precise error message.
2✔
280
                if in.WitnessUtxo == nil && in.NonWitnessUtxo == nil {
2✔
281
                        continue
×
282
                }
283

284
                // Skip this input if it's got final witness data attached.
285
                if len(in.FinalScriptWitness) > 0 {
2✔
286
                        continue
×
287
                }
288

289
                // We can only sign this input if it's ours, so we try to map it
290
                // to a coin we own. If we can't, then we'll continue as it
291
                // isn't our input.
292
                utxo, err := r.FetchOutpointInfo(&txIn.PreviousOutPoint)
2✔
293
                if err != nil {
2✔
294
                        continue
×
295
                }
296
                fullTx := utxo.PrevTx
2✔
297
                signDesc := &input.SignDescriptor{
2✔
298
                        KeyDesc: keychain.KeyDescriptor{},
2✔
299
                        Output: &wire.TxOut{
2✔
300
                                Value:    int64(utxo.Value),
2✔
301
                                PkScript: utxo.PkScript,
2✔
302
                        },
2✔
303
                        HashType:          in.SighashType,
2✔
304
                        SigHashes:         sigHashes,
2✔
305
                        InputIndex:        idx,
2✔
306
                        PrevOutputFetcher: prevOutFetcher,
2✔
307
                }
2✔
308

2✔
309
                // Find out what UTXO we are signing. Wallets _should_ always
2✔
310
                // provide the full non-witness UTXO for segwit v0.
2✔
311
                var signOutput *wire.TxOut
2✔
312
                if in.NonWitnessUtxo != nil {
4✔
313
                        prevIndex := txIn.PreviousOutPoint.Index
2✔
314
                        signOutput = in.NonWitnessUtxo.TxOut[prevIndex]
2✔
315

2✔
316
                        if !psbt.TxOutsEqual(signDesc.Output, signOutput) {
2✔
317
                                return fmt.Errorf("found UTXO %#v but it "+
×
318
                                        "doesn't match PSBT's input %v",
×
319
                                        signDesc.Output, signOutput)
×
320
                        }
×
321

322
                        if fullTx.TxHash() != txIn.PreviousOutPoint.Hash {
2✔
323
                                return fmt.Errorf("found UTXO tx %v but it "+
×
324
                                        "doesn't match PSBT's input %v",
×
325
                                        fullTx.TxHash(),
×
326
                                        txIn.PreviousOutPoint.Hash)
×
327
                        }
×
328
                }
329

330
                // Fall back to witness UTXO only for older wallets.
331
                if in.WitnessUtxo != nil {
4✔
332
                        signOutput = in.WitnessUtxo
2✔
333

2✔
334
                        if !psbt.TxOutsEqual(signDesc.Output, signOutput) {
2✔
335
                                return fmt.Errorf("found UTXO %#v but it "+
×
336
                                        "doesn't match PSBT's input %v",
×
337
                                        signDesc.Output, signOutput)
×
338
                        }
×
339
                }
340

341
                // Do the actual signing in ComputeInputScript which in turn
342
                // will invoke the remote signer.
343
                script, err := r.ComputeInputScript(tx, signDesc)
2✔
344
                if err != nil {
2✔
345
                        return fmt.Errorf("error computing input script for "+
×
346
                                "input %d: %v", idx, err)
×
347
                }
×
348

349
                // Serialize the witness format from the stack representation to
350
                // the wire representation.
351
                var witnessBytes bytes.Buffer
2✔
352
                err = psbt.WriteTxWitness(&witnessBytes, script.Witness)
2✔
353
                if err != nil {
2✔
354
                        return fmt.Errorf("error serializing witness: %w", err)
×
355
                }
×
356
                packet.Inputs[idx].FinalScriptWitness = witnessBytes.Bytes()
2✔
357
                packet.Inputs[idx].FinalScriptSig = script.SigScript
2✔
358
        }
359

360
        // Make sure the PSBT itself thinks it's finalized and ready to be
361
        // broadcast.
362
        err = psbt.MaybeFinalizeAll(packet)
2✔
363
        if err != nil {
2✔
364
                return fmt.Errorf("error finalizing PSBT: %w", err)
×
365
        }
×
366

367
        return nil
2✔
368
}
369

370
// DeriveNextKey attempts to derive the *next* key within the key family
371
// (account in BIP43) specified. This method should return the next external
372
// child within this branch.
373
//
374
// NOTE: This method is part of the keychain.KeyRing interface.
375
func (r *RPCKeyRing) DeriveNextKey(
376
        keyFam keychain.KeyFamily) (keychain.KeyDescriptor, error) {
2✔
377

2✔
378
        return r.watchOnlyKeyRing.DeriveNextKey(keyFam)
2✔
379
}
2✔
380

381
// DeriveKey attempts to derive an arbitrary key specified by the passed
382
// KeyLocator. This may be used in several recovery scenarios, or when manually
383
// rotating something like our current default node key.
384
//
385
// NOTE: This method is part of the keychain.KeyRing interface.
386
func (r *RPCKeyRing) DeriveKey(
387
        keyLoc keychain.KeyLocator) (keychain.KeyDescriptor, error) {
2✔
388

2✔
389
        return r.watchOnlyKeyRing.DeriveKey(keyLoc)
2✔
390
}
2✔
391

392
// ECDH performs a scalar multiplication (ECDH-like operation) between the
393
// target key descriptor and remote public key. The output returned will be the
394
// sha256 of the resulting shared point serialized in compressed format. If k is
395
// our private key, and P is the public key, we perform the following operation:
396
//
397
//        sx := k*P
398
//        s := sha256(sx.SerializeCompressed())
399
//
400
// NOTE: This method is part of the keychain.ECDHRing interface.
401
func (r *RPCKeyRing) ECDH(keyDesc keychain.KeyDescriptor,
402
        pubKey *btcec.PublicKey) ([32]byte, error) {
2✔
403

2✔
404
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
405
        defer cancel()
2✔
406

2✔
407
        key := [32]byte{}
2✔
408
        req := &signrpc.SharedKeyRequest{
2✔
409
                EphemeralPubkey: pubKey.SerializeCompressed(),
2✔
410
                KeyDesc: &signrpc.KeyDescriptor{
2✔
411
                        KeyLoc: &signrpc.KeyLocator{
2✔
412
                                KeyFamily: int32(keyDesc.Family),
2✔
413
                                KeyIndex:  int32(keyDesc.Index),
2✔
414
                        },
2✔
415
                },
2✔
416
        }
2✔
417

2✔
418
        if keyDesc.Index == 0 && keyDesc.PubKey != nil {
4✔
419
                req.KeyDesc.RawKeyBytes = keyDesc.PubKey.SerializeCompressed()
2✔
420
        }
2✔
421

422
        resp, err := r.signerClient.DeriveSharedKey(ctxt, req)
2✔
423
        if err != nil {
2✔
UNCOV
424
                considerShutdown(err)
×
UNCOV
425
                return key, fmt.Errorf("error deriving shared key in remote "+
×
UNCOV
426
                        "signer instance: %v", err)
×
UNCOV
427
        }
×
428

429
        copy(key[:], resp.SharedKey)
2✔
430
        return key, nil
2✔
431
}
432

433
// SignMessage attempts to sign a target message with the private key described
434
// in the key locator. If the target private key is unable to be found, then an
435
// error will be returned. The actual digest signed is the single or double
436
// SHA-256 of the passed message.
437
//
438
// NOTE: This method is part of the keychain.MessageSignerRing interface.
439
func (r *RPCKeyRing) SignMessage(keyLoc keychain.KeyLocator,
440
        msg []byte, doubleHash bool) (*ecdsa.Signature, error) {
2✔
441

2✔
442
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
443
        defer cancel()
2✔
444

2✔
445
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
2✔
446
                Msg: msg,
2✔
447
                KeyLoc: &signrpc.KeyLocator{
2✔
448
                        KeyFamily: int32(keyLoc.Family),
2✔
449
                        KeyIndex:  int32(keyLoc.Index),
2✔
450
                },
2✔
451
                DoubleHash: doubleHash,
2✔
452
        })
2✔
453
        if err != nil {
2✔
454
                considerShutdown(err)
×
455
                return nil, fmt.Errorf("error signing message in remote "+
×
456
                        "signer instance: %v", err)
×
457
        }
×
458

459
        wireSig, err := lnwire.NewSigFromECDSARawSignature(resp.Signature)
2✔
460
        if err != nil {
2✔
461
                return nil, fmt.Errorf("unable to create sig: %w", err)
×
462
        }
×
463
        sig, err := wireSig.ToSignature()
2✔
464
        if err != nil {
2✔
465
                return nil, fmt.Errorf("unable to parse sig: %w", err)
×
466
        }
×
467
        ecdsaSig, ok := sig.(*ecdsa.Signature)
2✔
468
        if !ok {
2✔
469
                return nil, fmt.Errorf("unexpected signature type: %T", sig)
×
470
        }
×
471

472
        return ecdsaSig, nil
2✔
473
}
474

475
// SignMessageCompact signs the given message, single or double SHA256 hashing
476
// it first, with the private key described in the key locator and returns the
477
// signature in the compact, public key recoverable format.
478
//
479
// NOTE: This method is part of the keychain.MessageSignerRing interface.
480
func (r *RPCKeyRing) SignMessageCompact(keyLoc keychain.KeyLocator,
481
        msg []byte, doubleHash bool) ([]byte, error) {
2✔
482

2✔
483
        if keyLoc.Family != keychain.KeyFamilyNodeKey {
2✔
484
                return nil, fmt.Errorf("error compact signing with key "+
×
485
                        "locator %v, can only sign with node key", keyLoc)
×
486
        }
×
487

488
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
489
        defer cancel()
2✔
490

2✔
491
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
2✔
492
                Msg: msg,
2✔
493
                KeyLoc: &signrpc.KeyLocator{
2✔
494
                        KeyFamily: int32(keyLoc.Family),
2✔
495
                        KeyIndex:  int32(keyLoc.Index),
2✔
496
                },
2✔
497
                DoubleHash: doubleHash,
2✔
498
                CompactSig: true,
2✔
499
        })
2✔
500
        if err != nil {
2✔
501
                considerShutdown(err)
×
502
                return nil, fmt.Errorf("error signing message in remote "+
×
503
                        "signer instance: %v", err)
×
504
        }
×
505

506
        // The signature in the response is zbase32 encoded, so we need to
507
        // decode it before returning.
508
        return resp.Signature, nil
2✔
509
}
510

511
// SignMessageSchnorr attempts to sign a target message with the private key
512
// described in the key locator. If the target private key is unable to be
513
// found, then an error will be returned. The actual digest signed is the
514
// single or double SHA-256 of the passed message.
515
//
516
// NOTE: This method is part of the keychain.MessageSignerRing interface.
517
func (r *RPCKeyRing) SignMessageSchnorr(keyLoc keychain.KeyLocator,
518
        msg []byte, doubleHash bool, taprootTweak []byte,
519
        tag []byte) (*schnorr.Signature, error) {
2✔
520

2✔
521
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
522
        defer cancel()
2✔
523

2✔
524
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
2✔
525
                Msg: msg,
2✔
526
                KeyLoc: &signrpc.KeyLocator{
2✔
527
                        KeyFamily: int32(keyLoc.Family),
2✔
528
                        KeyIndex:  int32(keyLoc.Index),
2✔
529
                },
2✔
530
                DoubleHash:         doubleHash,
2✔
531
                SchnorrSig:         true,
2✔
532
                SchnorrSigTapTweak: taprootTweak,
2✔
533
                Tag:                tag,
2✔
534
        })
2✔
535
        if err != nil {
2✔
536
                considerShutdown(err)
×
537
                return nil, fmt.Errorf("error signing message in remote "+
×
538
                        "signer instance: %w", err)
×
539
        }
×
540

541
        sigParsed, err := schnorr.ParseSignature(resp.Signature)
2✔
542
        if err != nil {
2✔
543
                return nil, fmt.Errorf("can't parse schnorr signature: %w",
×
544
                        err)
×
545
        }
×
546
        return sigParsed, nil
2✔
547
}
548

549
// DerivePrivKey attempts to derive the private key that corresponds to the
550
// passed key descriptor.  If the public key is set, then this method will
551
// perform an in-order scan over the key set, with a max of MaxKeyRangeScan
552
// keys. In order for this to work, the caller MUST set the KeyFamily within the
553
// partially populated KeyLocator.
554
//
555
// NOTE: This method is part of the keychain.SecretKeyRing interface.
556
func (r *RPCKeyRing) DerivePrivKey(_ keychain.KeyDescriptor) (*btcec.PrivateKey,
557
        error) {
×
558

×
559
        // This operation is not supported with remote signing. There should be
×
560
        // no need for invoking this method unless a channel backup (SCB) file
×
561
        // for pre-0.13.0 channels are attempted to be restored. In that case
×
562
        // it is recommended to restore the channels using a node with the full
×
563
        // seed available.
×
564
        return nil, ErrRemoteSigningPrivateKeyNotAvailable
×
565
}
×
566

567
// SignOutputRaw generates a signature for the passed transaction
568
// according to the data within the passed SignDescriptor.
569
//
570
// NOTE: The resulting signature should be void of a sighash byte.
571
//
572
// NOTE: This method is part of the input.Signer interface.
573
//
574
// NOTE: This method only signs with BIP1017 (internal) keys!
575
func (r *RPCKeyRing) SignOutputRaw(tx *wire.MsgTx,
576
        signDesc *input.SignDescriptor) (input.Signature, error) {
2✔
577

2✔
578
        // Forward the call to the remote signing instance. This call is only
2✔
579
        // ever called for signing witness (p2pkh or p2wsh) inputs and never
2✔
580
        // nested witness inputs, so the sigScript is always nil.
2✔
581
        return r.remoteSign(tx, signDesc, nil)
2✔
582
}
2✔
583

584
// ComputeInputScript generates a complete InputIndex for the passed
585
// transaction with the signature as defined within the passed
586
// SignDescriptor. This method should be capable of generating the
587
// proper input script for both regular p2wkh output and p2wkh outputs
588
// nested within a regular p2sh output.
589
//
590
// NOTE: This method will ignore any tweak parameters set within the
591
// passed SignDescriptor as it assumes a set of typical script
592
// templates (p2wkh, np2wkh, BIP0086 p2tr, etc).
593
//
594
// NOTE: This method is part of the input.Signer interface.
595
func (r *RPCKeyRing) ComputeInputScript(tx *wire.MsgTx,
596
        signDesc *input.SignDescriptor) (*input.Script, error) {
2✔
597

2✔
598
        addr, witnessProgram, sigScript, err := r.WalletController.ScriptForOutput(
2✔
599
                signDesc.Output,
2✔
600
        )
2✔
601
        if err != nil {
2✔
602
                return nil, err
×
603
        }
×
604
        signDesc.WitnessScript = witnessProgram
2✔
605

2✔
606
        // If this is a p2tr address, then it must be a BIP0086 key spend if we
2✔
607
        // are coming through this path (instead of SignOutputRaw).
2✔
608
        switch addr.AddrType() {
2✔
609
        case waddrmgr.TaprootPubKey:
2✔
610
                signDesc.SignMethod = input.TaprootKeySpendBIP0086SignMethod
2✔
611
                signDesc.WitnessScript = nil
2✔
612

2✔
613
                sig, err := r.remoteSign(tx, signDesc, nil)
2✔
614
                if err != nil {
2✔
615
                        return nil, fmt.Errorf("error signing with remote"+
×
616
                                "instance: %v", err)
×
617
                }
×
618

619
                rawSig := sig.Serialize()
2✔
620
                if signDesc.HashType != txscript.SigHashDefault {
2✔
621
                        rawSig = append(rawSig, byte(signDesc.HashType))
×
622
                }
×
623

624
                return &input.Script{
2✔
625
                        Witness: wire.TxWitness{
2✔
626
                                rawSig,
2✔
627
                        },
2✔
628
                }, nil
2✔
629

630
        case waddrmgr.TaprootScript:
×
631
                return nil, fmt.Errorf("computing input script for taproot " +
×
632
                        "script address not supported")
×
633
        }
634

635
        // Let's give the TX to the remote instance now, so it can sign the
636
        // input.
637
        sig, err := r.remoteSign(tx, signDesc, witnessProgram)
2✔
638
        if err != nil {
2✔
639
                return nil, fmt.Errorf("error signing with remote instance: %w",
×
640
                        err)
×
641
        }
×
642

643
        // ComputeInputScript currently is only used for P2WKH and NP2WKH
644
        // addresses. So the last item on the stack is always the compressed
645
        // public key.
646
        return &input.Script{
2✔
647
                Witness: wire.TxWitness{
2✔
648
                        append(sig.Serialize(), byte(signDesc.HashType)),
2✔
649
                        addr.PubKey().SerializeCompressed(),
2✔
650
                },
2✔
651
                SigScript: sigScript,
2✔
652
        }, nil
2✔
653
}
654

655
// MuSig2CreateSession creates a new MuSig2 signing session using the local
656
// key identified by the key locator. The complete list of all public keys of
657
// all signing parties must be provided, including the public key of the local
658
// signing key. If nonces of other parties are already known, they can be
659
// submitted as well to reduce the number of method calls necessary later on.
660
func (r *RPCKeyRing) MuSig2CreateSession(bipVersion input.MuSig2Version,
661
        keyLoc keychain.KeyLocator, pubKeys []*btcec.PublicKey,
662
        tweaks *input.MuSig2Tweaks, otherNonces [][musig2.PubNonceSize]byte,
663
        localNonces *musig2.Nonces) (*input.MuSig2SessionInfo, error) {
2✔
664

2✔
665
        apiVersion, err := signrpc.MarshalMuSig2Version(bipVersion)
2✔
666
        if err != nil {
2✔
667
                return nil, err
×
668
        }
×
669

670
        // We need to serialize all data for the RPC call. We can do that by
671
        // putting everything directly into the request struct.
672
        req := &signrpc.MuSig2SessionRequest{
2✔
673
                KeyLoc: &signrpc.KeyLocator{
2✔
674
                        KeyFamily: int32(keyLoc.Family),
2✔
675
                        KeyIndex:  int32(keyLoc.Index),
2✔
676
                },
2✔
677
                AllSignerPubkeys: make([][]byte, len(pubKeys)),
2✔
678
                Tweaks: make(
2✔
679
                        []*signrpc.TweakDesc, len(tweaks.GenericTweaks),
2✔
680
                ),
2✔
681
                OtherSignerPublicNonces: make([][]byte, len(otherNonces)),
2✔
682
                Version:                 apiVersion,
2✔
683
        }
2✔
684
        for idx, pubKey := range pubKeys {
4✔
685
                switch bipVersion {
2✔
686
                case input.MuSig2Version040:
2✔
687
                        req.AllSignerPubkeys[idx] = schnorr.SerializePubKey(
2✔
688
                                pubKey,
2✔
689
                        )
2✔
690

691
                case input.MuSig2Version100RC2:
2✔
692
                        req.AllSignerPubkeys[idx] = pubKey.SerializeCompressed()
2✔
693
                }
694
        }
695
        for idx, genericTweak := range tweaks.GenericTweaks {
2✔
696
                req.Tweaks[idx] = &signrpc.TweakDesc{
×
697
                        Tweak:   genericTweak.Tweak[:],
×
698
                        IsXOnly: genericTweak.IsXOnly,
×
699
                }
×
700
        }
×
701
        for idx, nonce := range otherNonces {
4✔
702
                req.OtherSignerPublicNonces[idx] = make([]byte, len(nonce))
2✔
703
                copy(req.OtherSignerPublicNonces[idx], nonce[:])
2✔
704
        }
2✔
705
        if tweaks.HasTaprootTweak() {
4✔
706
                req.TaprootTweak = &signrpc.TaprootTweakDesc{
2✔
707
                        KeySpendOnly: tweaks.TaprootBIP0086Tweak,
2✔
708
                        ScriptRoot:   tweaks.TaprootTweak,
2✔
709
                }
2✔
710
        }
2✔
711

712
        if localNonces != nil {
4✔
713
                req.PregeneratedLocalNonce = localNonces.SecNonce[:]
2✔
714
        }
2✔
715

716
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
717
        defer cancel()
2✔
718

2✔
719
        resp, err := r.signerClient.MuSig2CreateSession(ctxt, req)
2✔
720
        if err != nil {
2✔
721
                considerShutdown(err)
×
722
                return nil, fmt.Errorf("error creating MuSig2 session in "+
×
723
                        "remote signer instance: %v", err)
×
724
        }
×
725

726
        // De-Serialize all the info back into our native struct.
727
        info := &input.MuSig2SessionInfo{
2✔
728
                Version:       bipVersion,
2✔
729
                TaprootTweak:  tweaks.HasTaprootTweak(),
2✔
730
                HaveAllNonces: resp.HaveAllNonces,
2✔
731
        }
2✔
732
        copy(info.SessionID[:], resp.SessionId)
2✔
733
        copy(info.PublicNonce[:], resp.LocalPublicNonces)
2✔
734

2✔
735
        info.CombinedKey, err = schnorr.ParsePubKey(resp.CombinedKey)
2✔
736
        if err != nil {
2✔
737
                return nil, fmt.Errorf("error parsing combined key: %w", err)
×
738
        }
×
739

740
        if tweaks.HasTaprootTweak() {
4✔
741
                info.TaprootInternalKey, err = schnorr.ParsePubKey(
2✔
742
                        resp.TaprootInternalKey,
2✔
743
                )
2✔
744
                if err != nil {
2✔
745
                        return nil, fmt.Errorf("error parsing internal key: %w",
×
746
                                err)
×
747
                }
×
748
        }
749

750
        return info, nil
2✔
751
}
752

753
// MuSig2RegisterNonces registers one or more public nonces of other signing
754
// participants for a session identified by its ID. This method returns true
755
// once we have all nonces for all other signing participants.
756
func (r *RPCKeyRing) MuSig2RegisterNonces(sessionID input.MuSig2SessionID,
757
        pubNonces [][musig2.PubNonceSize]byte) (bool, error) {
2✔
758

2✔
759
        // We need to serialize all data for the RPC call. We can do that by
2✔
760
        // putting everything directly into the request struct.
2✔
761
        req := &signrpc.MuSig2RegisterNoncesRequest{
2✔
762
                SessionId:               sessionID[:],
2✔
763
                OtherSignerPublicNonces: make([][]byte, len(pubNonces)),
2✔
764
        }
2✔
765
        for idx, nonce := range pubNonces {
4✔
766
                req.OtherSignerPublicNonces[idx] = make([]byte, len(nonce))
2✔
767
                copy(req.OtherSignerPublicNonces[idx], nonce[:])
2✔
768
        }
2✔
769

770
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
771
        defer cancel()
2✔
772

2✔
773
        resp, err := r.signerClient.MuSig2RegisterNonces(ctxt, req)
2✔
774
        if err != nil {
2✔
775
                considerShutdown(err)
×
776
                return false, fmt.Errorf("error registering MuSig2 nonces in "+
×
777
                        "remote signer instance: %v", err)
×
778
        }
×
779

780
        return resp.HaveAllNonces, nil
2✔
781
}
782

783
// MuSig2Sign creates a partial signature using the local signing key
784
// that was specified when the session was created. This can only be
785
// called when all public nonces of all participants are known and have
786
// been registered with the session. If this node isn't responsible for
787
// combining all the partial signatures, then the cleanup parameter
788
// should be set, indicating that the session can be removed from memory
789
// once the signature was produced.
790
func (r *RPCKeyRing) MuSig2Sign(sessionID input.MuSig2SessionID,
791
        msg [sha256.Size]byte, cleanUp bool) (*musig2.PartialSignature, error) {
2✔
792

2✔
793
        // We need to serialize all data for the RPC call. We can do that by
2✔
794
        // putting everything directly into the request struct.
2✔
795
        req := &signrpc.MuSig2SignRequest{
2✔
796
                SessionId:     sessionID[:],
2✔
797
                MessageDigest: msg[:],
2✔
798
                Cleanup:       cleanUp,
2✔
799
        }
2✔
800

2✔
801
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
802
        defer cancel()
2✔
803

2✔
804
        resp, err := r.signerClient.MuSig2Sign(ctxt, req)
2✔
805
        if err != nil {
4✔
806
                considerShutdown(err)
2✔
807
                return nil, fmt.Errorf("error signing MuSig2 session in "+
2✔
808
                        "remote signer instance: %v", err)
2✔
809
        }
2✔
810

811
        partialSig, err := input.DeserializePartialSignature(
2✔
812
                resp.LocalPartialSignature,
2✔
813
        )
2✔
814
        if err != nil {
2✔
815
                return nil, fmt.Errorf("error parsing partial signature from "+
×
816
                        "remote signer: %v", err)
×
817
        }
×
818

819
        return partialSig, nil
2✔
820
}
821

822
// MuSig2CombineSig combines the given partial signature(s) with the
823
// local one, if it already exists. Once a partial signature of all
824
// participants is registered, the final signature will be combined and
825
// returned.
826
func (r *RPCKeyRing) MuSig2CombineSig(sessionID input.MuSig2SessionID,
827
        partialSigs []*musig2.PartialSignature) (*schnorr.Signature, bool,
828
        error) {
2✔
829

2✔
830
        // We need to serialize all data for the RPC call. We can do that by
2✔
831
        // putting everything directly into the request struct.
2✔
832
        req := &signrpc.MuSig2CombineSigRequest{
2✔
833
                SessionId:              sessionID[:],
2✔
834
                OtherPartialSignatures: make([][]byte, len(partialSigs)),
2✔
835
        }
2✔
836
        for idx, partialSig := range partialSigs {
4✔
837
                rawSig, err := input.SerializePartialSignature(partialSig)
2✔
838
                if err != nil {
2✔
839
                        return nil, false, fmt.Errorf("error serializing "+
×
840
                                "partial signature: %v", err)
×
841
                }
×
842
                req.OtherPartialSignatures[idx] = rawSig[:]
2✔
843
        }
844

845
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
846
        defer cancel()
2✔
847

2✔
848
        resp, err := r.signerClient.MuSig2CombineSig(ctxt, req)
2✔
849
        if err != nil {
2✔
850
                considerShutdown(err)
×
851
                return nil, false, fmt.Errorf("error combining MuSig2 "+
×
852
                        "signatures in remote signer instance: %v", err)
×
853
        }
×
854

855
        // The final signature is only available when we have all the other
856
        // partial signatures from all participants.
857
        if !resp.HaveAllSignatures {
4✔
858
                return nil, resp.HaveAllSignatures, nil
2✔
859
        }
2✔
860

861
        finalSig, err := schnorr.ParseSignature(resp.FinalSignature)
2✔
862
        if err != nil {
2✔
863
                return nil, false, fmt.Errorf("error parsing final signature: "+
×
864
                        "%v", err)
×
865
        }
×
866

867
        return finalSig, resp.HaveAllSignatures, nil
2✔
868
}
869

870
// MuSig2Cleanup removes a session from memory to free up resources.
871
func (r *RPCKeyRing) MuSig2Cleanup(sessionID input.MuSig2SessionID) error {
2✔
872
        req := &signrpc.MuSig2CleanupRequest{
2✔
873
                SessionId: sessionID[:],
2✔
874
        }
2✔
875

2✔
876
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
877
        defer cancel()
2✔
878

2✔
879
        _, err := r.signerClient.MuSig2Cleanup(ctxt, req)
2✔
880
        if err != nil {
2✔
881
                considerShutdown(err)
×
882
                return fmt.Errorf("error cleaning up MuSig2 session in remote "+
×
883
                        "signer instance: %v", err)
×
884
        }
×
885

886
        return nil
2✔
887
}
888

889
// remoteSign signs the input specified in signDesc of the given transaction tx
890
// using the remote signing instance.
891
func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor,
892
        sigScript []byte) (input.Signature, error) {
2✔
893

2✔
894
        packet, err := packetFromTx(tx)
2✔
895
        if err != nil {
2✔
896
                return nil, fmt.Errorf("error converting TX into PSBT: %w", err)
×
897
        }
×
898

899
        // We need to add witness information for all inputs! Otherwise, we'll
900
        // have a problem when attempting to sign a taproot input!
901
        for idx := range packet.Inputs {
4✔
902
                // Skip the input we're signing for, that will get a special
2✔
903
                // treatment later on.
2✔
904
                if idx == signDesc.InputIndex {
4✔
905
                        continue
2✔
906
                }
907

908
                txIn := tx.TxIn[idx]
2✔
909
                info, err := r.WalletController.FetchOutpointInfo(
2✔
910
                        &txIn.PreviousOutPoint,
2✔
911
                )
2✔
912
                if err != nil {
2✔
913
                        // Maybe we have an UTXO in the previous output fetcher?
×
914
                        if signDesc.PrevOutputFetcher != nil {
×
915
                                utxo := signDesc.PrevOutputFetcher.FetchPrevOutput(
×
916
                                        txIn.PreviousOutPoint,
×
917
                                )
×
918
                                if utxo != nil && utxo.Value != 0 &&
×
919
                                        len(utxo.PkScript) > 0 {
×
920

×
921
                                        packet.Inputs[idx].WitnessUtxo = utxo
×
922
                                        continue
×
923
                                }
924
                        }
925

926
                        log.Warnf("No UTXO info found for index %d "+
×
927
                                "(prev_outpoint=%v), won't be able to sign "+
×
928
                                "for taproot output!", idx,
×
929
                                txIn.PreviousOutPoint)
×
930
                        continue
×
931
                }
932
                packet.Inputs[idx].WitnessUtxo = &wire.TxOut{
2✔
933
                        Value:    int64(info.Value),
2✔
934
                        PkScript: info.PkScript,
2✔
935
                }
2✔
936
        }
937

938
        // Catch incorrect signing input index, just in case.
939
        if signDesc.InputIndex < 0 || signDesc.InputIndex >= len(packet.Inputs) {
2✔
940
                return nil, fmt.Errorf("invalid input index in sign descriptor")
×
941
        }
×
942
        in := &packet.Inputs[signDesc.InputIndex]
2✔
943
        txIn := tx.TxIn[signDesc.InputIndex]
2✔
944

2✔
945
        // Things are a bit tricky with the sign descriptor. There basically are
2✔
946
        // four ways to describe a key:
2✔
947
        //   1. By public key only. To match this case both family and index
2✔
948
        //      must be set to 0.
2✔
949
        //   2. By family and index only. To match this case the public key
2✔
950
        //      must be nil and either the family or index must be non-zero.
2✔
951
        //   3. All values are set and locator is non-empty. To match this case
2✔
952
        //      the public key must be set and either the family or index must
2✔
953
        //      be non-zero.
2✔
954
        //   4. All values are set and locator is empty. This is a special case
2✔
955
        //      for the very first channel ever created (with the multi-sig key
2✔
956
        //      family which is 0 and the index which is 0 as well). This looks
2✔
957
        //      identical to case 1 and will also be handled like that case.
2✔
958
        // We only really handle case 1 and 2 here, since 3 is no problem and 4
2✔
959
        // is identical to 1.
2✔
960
        switch {
2✔
961
        // Case 1: Public key only. We need to find out the derivation path for
962
        // this public key by asking the wallet. This is only possible for our
963
        // internal, custom 1017 scope since we know all keys derived there are
964
        // internally stored as p2wkh addresses.
965
        case signDesc.KeyDesc.PubKey != nil && signDesc.KeyDesc.IsEmpty():
2✔
966
                pubKeyBytes := signDesc.KeyDesc.PubKey.SerializeCompressed()
2✔
967
                addr, err := btcutil.NewAddressWitnessPubKeyHash(
2✔
968
                        btcutil.Hash160(pubKeyBytes), r.netParams,
2✔
969
                )
2✔
970
                if err != nil {
2✔
971
                        return nil, fmt.Errorf("error deriving address from "+
×
972
                                "public key %x: %v", pubKeyBytes, err)
×
973
                }
×
974

975
                managedAddr, err := r.AddressInfo(addr)
2✔
976
                if err != nil {
2✔
977
                        return nil, fmt.Errorf("error fetching address info "+
×
978
                                "for public key %x: %v", pubKeyBytes, err)
×
979
                }
×
980

981
                pubKeyAddr, ok := managedAddr.(waddrmgr.ManagedPubKeyAddress)
2✔
982
                if !ok {
2✔
983
                        return nil, fmt.Errorf("address derived for public "+
×
984
                                "key %x is not a p2wkh address", pubKeyBytes)
×
985
                }
×
986

987
                scope, path, _ := pubKeyAddr.DerivationInfo()
2✔
988
                if scope.Purpose != keychain.BIP0043Purpose {
2✔
989
                        return nil, fmt.Errorf("address derived for public "+
×
990
                                "key %x is not in custom key scope %d'",
×
991
                                pubKeyBytes, keychain.BIP0043Purpose)
×
992
                }
×
993

994
                // We now have all the information we need to complete our key
995
                // locator information.
996
                signDesc.KeyDesc.KeyLocator = keychain.KeyLocator{
2✔
997
                        Family: keychain.KeyFamily(path.InternalAccount),
2✔
998
                        Index:  path.Index,
2✔
999
                }
2✔
1000

1001
        // Case 2: Family and index only. This case is easy, we can just go
1002
        // ahead and derive the public key from the family and index and then
1003
        // supply that information in the BIP32 derivation field.
1004
        case signDesc.KeyDesc.PubKey == nil && !signDesc.KeyDesc.IsEmpty():
2✔
1005
                fullDesc, err := r.watchOnlyKeyRing.DeriveKey(
2✔
1006
                        signDesc.KeyDesc.KeyLocator,
2✔
1007
                )
2✔
1008
                if err != nil {
2✔
1009
                        return nil, fmt.Errorf("error deriving key with "+
×
1010
                                "family %d and index %d from the watch-only "+
×
1011
                                "wallet: %v",
×
1012
                                signDesc.KeyDesc.KeyLocator.Family,
×
1013
                                signDesc.KeyDesc.KeyLocator.Index, err)
×
1014
                }
×
1015
                signDesc.KeyDesc.PubKey = fullDesc.PubKey
2✔
1016
        }
1017

1018
        var derivation *psbt.Bip32Derivation
2✔
1019

2✔
1020
        // Make sure we actually know about the input. We either have been
2✔
1021
        // watching the UTXO on-chain or we have been given all the required
2✔
1022
        // info in the sign descriptor.
2✔
1023
        info, err := r.WalletController.FetchOutpointInfo(
2✔
1024
                &txIn.PreviousOutPoint,
2✔
1025
        )
2✔
1026

2✔
1027
        // If the wallet is aware of this outpoint, we go ahead and fetch the
2✔
1028
        // derivation info.
2✔
1029
        if err == nil {
4✔
1030
                derivation, err = r.WalletController.FetchDerivationInfo(
2✔
1031
                        info.PkScript,
2✔
1032
                )
2✔
1033
        }
2✔
1034

1035
        switch {
2✔
1036
        // No error, we do have the full UTXO info available.
1037
        case err == nil:
2✔
1038
                in.WitnessUtxo = &wire.TxOut{
2✔
1039
                        Value:    int64(info.Value),
2✔
1040
                        PkScript: info.PkScript,
2✔
1041
                }
2✔
1042
                in.NonWitnessUtxo = info.PrevTx
2✔
1043
                in.Bip32Derivation = []*psbt.Bip32Derivation{derivation}
2✔
1044

1045
        // The wallet doesn't know about this UTXO, so it's probably a TX that
1046
        // we haven't published yet (e.g. a channel funding TX). So we need to
1047
        // assemble everything from the sign descriptor. We won't be able to
1048
        // supply a non-witness UTXO (=full TX of the input being spent) in this
1049
        // case. That is no problem if the signing instance is another lnd
1050
        // instance since we don't require it for pure witness inputs. But a
1051
        // hardware wallet might require it for security reasons.
1052
        case signDesc.KeyDesc.PubKey != nil && signDesc.Output != nil:
2✔
1053
                in.WitnessUtxo = signDesc.Output
2✔
1054
                in.Bip32Derivation = []*psbt.Bip32Derivation{{
2✔
1055
                        Bip32Path: []uint32{
2✔
1056
                                keychain.BIP0043Purpose +
2✔
1057
                                        hdkeychain.HardenedKeyStart,
2✔
1058
                                r.netParams.HDCoinType +
2✔
1059
                                        hdkeychain.HardenedKeyStart,
2✔
1060
                                uint32(signDesc.KeyDesc.Family) +
2✔
1061
                                        hdkeychain.HardenedKeyStart,
2✔
1062
                                0,
2✔
1063
                                signDesc.KeyDesc.Index,
2✔
1064
                        },
2✔
1065
                        PubKey: signDesc.KeyDesc.PubKey.SerializeCompressed(),
2✔
1066
                }}
2✔
1067

2✔
1068
                // We need to specify a pk script in the witness UTXO, otherwise
2✔
1069
                // the field becomes invalid when serialized as a PSBT. To avoid
2✔
1070
                // running into a generic "Invalid PSBT serialization format"
2✔
1071
                // error later, we return a more descriptive error now.
2✔
1072
                if len(in.WitnessUtxo.PkScript) == 0 {
2✔
1073
                        return nil, fmt.Errorf("error assembling UTXO " +
×
1074
                                "information, output not known to wallet and " +
×
1075
                                "no UTXO pk script provided in sign descriptor")
×
1076
                }
×
1077

1078
        default:
×
1079
                return nil, fmt.Errorf("error assembling UTXO information, "+
×
1080
                        "wallet returned err='%v' and sign descriptor is "+
×
1081
                        "incomplete", err)
×
1082
        }
1083

1084
        // Assemble all other information about the input we have.
1085
        in.RedeemScript = sigScript
2✔
1086
        in.SighashType = signDesc.HashType
2✔
1087
        in.WitnessScript = signDesc.WitnessScript
2✔
1088

2✔
1089
        if len(signDesc.SingleTweak) > 0 {
4✔
1090
                in.Unknowns = append(in.Unknowns, &psbt.Unknown{
2✔
1091
                        Key:   btcwallet.PsbtKeyTypeInputSignatureTweakSingle,
2✔
1092
                        Value: signDesc.SingleTweak,
2✔
1093
                })
2✔
1094
        }
2✔
1095
        if signDesc.DoubleTweak != nil {
2✔
1096
                in.Unknowns = append(in.Unknowns, &psbt.Unknown{
×
1097
                        Key:   btcwallet.PsbtKeyTypeInputSignatureTweakDouble,
×
1098
                        Value: signDesc.DoubleTweak.Serialize(),
×
1099
                })
×
1100
        }
×
1101

1102
        // Add taproot specific fields.
1103
        switch signDesc.SignMethod {
2✔
1104
        case input.TaprootKeySpendBIP0086SignMethod,
1105
                input.TaprootKeySpendSignMethod:
2✔
1106

2✔
1107
                // The key identifying factor for a key spend is that we don't
2✔
1108
                // provide any leaf hashes to signal we want a signature for the
2✔
1109
                // key spend path (with the internal key).
2✔
1110
                d := in.Bip32Derivation[0]
2✔
1111
                in.TaprootBip32Derivation = []*psbt.TaprootBip32Derivation{{
2✔
1112
                        // The x-only public key is just our compressed public
2✔
1113
                        // key without the first byte (type/parity).
2✔
1114
                        XOnlyPubKey:          d.PubKey[1:],
2✔
1115
                        LeafHashes:           nil,
2✔
1116
                        MasterKeyFingerprint: d.MasterKeyFingerprint,
2✔
1117
                        Bip32Path:            d.Bip32Path,
2✔
1118
                }}
2✔
1119

2✔
1120
                // If this is a BIP0086 key spend then the tap tweak is empty,
2✔
1121
                // otherwise it's set to the Taproot root hash.
2✔
1122
                in.TaprootMerkleRoot = signDesc.TapTweak
2✔
1123

1124
        case input.TaprootScriptSpendSignMethod:
2✔
1125
                // The script spend path is a bit more involved when doing it
2✔
1126
                // through the PSBT method. We need to specify the leaf hash
2✔
1127
                // that the signer should sign for.
2✔
1128
                leaf := txscript.TapLeaf{
2✔
1129
                        LeafVersion: txscript.BaseLeafVersion,
2✔
1130
                        Script:      signDesc.WitnessScript,
2✔
1131
                }
2✔
1132
                leafHash := leaf.TapHash()
2✔
1133

2✔
1134
                d := in.Bip32Derivation[0]
2✔
1135
                in.TaprootBip32Derivation = []*psbt.TaprootBip32Derivation{{
2✔
1136
                        XOnlyPubKey:          d.PubKey[1:],
2✔
1137
                        LeafHashes:           [][]byte{leafHash[:]},
2✔
1138
                        MasterKeyFingerprint: d.MasterKeyFingerprint,
2✔
1139
                        Bip32Path:            d.Bip32Path,
2✔
1140
                }}
2✔
1141

2✔
1142
                // We also need to supply a control block. But because we don't
2✔
1143
                // know the internal key nor the merkle proofs (both is not
2✔
1144
                // supplied through the SignOutputRaw RPC) and is technically
2✔
1145
                // not really needed by the signer (since we only want a
2✔
1146
                // signature, the full witness stack is assembled by the caller
2✔
1147
                // of this RPC), we can get by with faking certain information
2✔
1148
                // that we don't have.
2✔
1149
                fakeInternalKey, _ := btcec.ParsePubKey(d.PubKey)
2✔
1150
                fakeKeyIsOdd := d.PubKey[0] == input.PubKeyFormatCompressedOdd
2✔
1151
                controlBlock := txscript.ControlBlock{
2✔
1152
                        InternalKey:     fakeInternalKey,
2✔
1153
                        OutputKeyYIsOdd: fakeKeyIsOdd,
2✔
1154
                        LeafVersion:     leaf.LeafVersion,
2✔
1155
                }
2✔
1156
                blockBytes, err := controlBlock.ToBytes()
2✔
1157
                if err != nil {
2✔
1158
                        return nil, fmt.Errorf("error serializing control "+
×
1159
                                "block: %v", err)
×
1160
                }
×
1161

1162
                in.TaprootLeafScript = []*psbt.TaprootTapLeafScript{{
2✔
1163
                        ControlBlock: blockBytes,
2✔
1164
                        Script:       leaf.Script,
2✔
1165
                        LeafVersion:  leaf.LeafVersion,
2✔
1166
                }}
2✔
1167
        }
1168

1169
        // Okay, let's sign the input by the remote signer now.
1170
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
2✔
1171
        defer cancel()
2✔
1172

2✔
1173
        var buf bytes.Buffer
2✔
1174
        if err := packet.Serialize(&buf); err != nil {
2✔
1175
                return nil, fmt.Errorf("error serializing PSBT: %w", err)
×
1176
        }
×
1177

1178
        resp, err := r.walletClient.SignPsbt(
2✔
1179
                ctxt, &walletrpc.SignPsbtRequest{FundedPsbt: buf.Bytes()},
2✔
1180
        )
2✔
1181
        if err != nil {
2✔
1182
                considerShutdown(err)
×
1183
                return nil, fmt.Errorf("error signing PSBT in remote signer "+
×
1184
                        "instance: %v", err)
×
1185
        }
×
1186

1187
        signedPacket, err := psbt.NewFromRawBytes(
2✔
1188
                bytes.NewReader(resp.SignedPsbt), false,
2✔
1189
        )
2✔
1190
        if err != nil {
2✔
1191
                return nil, fmt.Errorf("error parsing signed PSBT: %w", err)
×
1192
        }
×
1193

1194
        // We expect a signature in the input now.
1195
        if signDesc.InputIndex >= len(signedPacket.Inputs) {
2✔
1196
                return nil, fmt.Errorf("remote signer returned invalid PSBT")
×
1197
        }
×
1198
        in = &signedPacket.Inputs[signDesc.InputIndex]
2✔
1199

2✔
1200
        return extractSignature(in, signDesc.SignMethod)
2✔
1201
}
1202

1203
// extractSignature attempts to extract the signature from the PSBT input,
1204
// looking at different fields depending on the signing method that was used.
1205
func extractSignature(in *psbt.PInput,
1206
        signMethod input.SignMethod) (input.Signature, error) {
2✔
1207

2✔
1208
        switch signMethod {
2✔
1209
        case input.WitnessV0SignMethod:
2✔
1210
                if len(in.PartialSigs) != 1 {
2✔
1211
                        return nil, fmt.Errorf("remote signer returned "+
×
1212
                                "invalid partial signature, wanted 1, got %d",
×
1213
                                len(in.PartialSigs))
×
1214
                }
×
1215
                sigWithSigHash := in.PartialSigs[0]
2✔
1216
                if sigWithSigHash == nil {
2✔
1217
                        return nil, fmt.Errorf("remote signer returned nil " +
×
1218
                                "signature")
×
1219
                }
×
1220

1221
                // The remote signer always adds the sighash type, so we need to
1222
                // account for that.
1223
                sigLen := len(sigWithSigHash.Signature)
2✔
1224
                if sigLen < ecdsa.MinSigLen+1 {
2✔
1225
                        return nil, fmt.Errorf("remote signer returned "+
×
1226
                                "invalid partial signature: signature too "+
×
1227
                                "short with %d bytes", sigLen)
×
1228
                }
×
1229

1230
                // Parse the signature, but chop off the last byte which is the
1231
                // sighash type.
1232
                sig := sigWithSigHash.Signature[0 : sigLen-1]
2✔
1233
                return ecdsa.ParseDERSignature(sig)
2✔
1234

1235
        // The type of key spend doesn't matter, the signature should be in the
1236
        // same field for both of those signing methods.
1237
        case input.TaprootKeySpendBIP0086SignMethod,
1238
                input.TaprootKeySpendSignMethod:
2✔
1239

2✔
1240
                sigLen := len(in.TaprootKeySpendSig)
2✔
1241
                if sigLen < schnorr.SignatureSize {
2✔
1242
                        return nil, fmt.Errorf("remote signer returned "+
×
1243
                                "invalid key spend signature: signature too "+
×
1244
                                "short with %d bytes", sigLen)
×
1245
                }
×
1246

1247
                return schnorr.ParseSignature(
2✔
1248
                        in.TaprootKeySpendSig[:schnorr.SignatureSize],
2✔
1249
                )
2✔
1250

1251
        case input.TaprootScriptSpendSignMethod:
2✔
1252
                if len(in.TaprootScriptSpendSig) != 1 {
2✔
1253
                        return nil, fmt.Errorf("remote signer returned "+
×
1254
                                "invalid taproot script spend signature, "+
×
1255
                                "wanted 1, got %d",
×
1256
                                len(in.TaprootScriptSpendSig))
×
1257
                }
×
1258
                scriptSpendSig := in.TaprootScriptSpendSig[0]
2✔
1259
                if scriptSpendSig == nil {
2✔
1260
                        return nil, fmt.Errorf("remote signer returned nil " +
×
1261
                                "taproot script spend signature")
×
1262
                }
×
1263

1264
                return schnorr.ParseSignature(scriptSpendSig.Signature)
2✔
1265

1266
        default:
×
1267
                return nil, fmt.Errorf("can't extract signature, unsupported "+
×
1268
                        "signing method: %v", signMethod)
×
1269
        }
1270
}
1271

1272
// connectRPC tries to establish an RPC connection to the given host:port with
1273
// the supplied certificate and macaroon.
1274
func connectRPC(hostPort, tlsCertPath, macaroonPath string,
1275
        timeout time.Duration) (*grpc.ClientConn, error) {
2✔
1276

2✔
1277
        certBytes, err := os.ReadFile(tlsCertPath)
2✔
1278
        if err != nil {
2✔
1279
                return nil, fmt.Errorf("error reading TLS cert file %v: %w",
×
1280
                        tlsCertPath, err)
×
1281
        }
×
1282

1283
        cp := x509.NewCertPool()
2✔
1284
        if !cp.AppendCertsFromPEM(certBytes) {
2✔
1285
                return nil, fmt.Errorf("credentials: failed to append " +
×
1286
                        "certificate")
×
1287
        }
×
1288

1289
        macBytes, err := os.ReadFile(macaroonPath)
2✔
1290
        if err != nil {
2✔
1291
                return nil, fmt.Errorf("error reading macaroon file %v: %w",
×
1292
                        macaroonPath, err)
×
1293
        }
×
1294
        mac := &macaroon.Macaroon{}
2✔
1295
        if err := mac.UnmarshalBinary(macBytes); err != nil {
2✔
1296
                return nil, fmt.Errorf("error decoding macaroon: %w", err)
×
1297
        }
×
1298

1299
        macCred, err := macaroons.NewMacaroonCredential(mac)
2✔
1300
        if err != nil {
2✔
1301
                return nil, fmt.Errorf("error creating creds: %w", err)
×
1302
        }
×
1303

1304
        opts := []grpc.DialOption{
2✔
1305
                grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(
2✔
1306
                        cp, "",
2✔
1307
                )),
2✔
1308
                grpc.WithPerRPCCredentials(macCred),
2✔
1309
                grpc.WithBlock(),
2✔
1310
        }
2✔
1311
        ctxt, cancel := context.WithTimeout(context.Background(), timeout)
2✔
1312
        defer cancel()
2✔
1313
        conn, err := grpc.DialContext(ctxt, hostPort, opts...)
2✔
1314
        if err != nil {
2✔
1315
                return nil, fmt.Errorf("unable to connect to RPC server: %w",
×
1316
                        err)
×
1317
        }
×
1318

1319
        return conn, nil
2✔
1320
}
1321

1322
// packetFromTx creates a PSBT from a tx that potentially already contains
1323
// signed inputs.
1324
func packetFromTx(original *wire.MsgTx) (*psbt.Packet, error) {
2✔
1325
        // The psbt.NewFromUnsignedTx function complains if there are any
2✔
1326
        // scripts or witness content on a TX. So we create a copy of the TX and
2✔
1327
        // nil out all the offending data, but also keep a backup around that we
2✔
1328
        // add to the PSBT afterwards.
2✔
1329
        noSigs := original.Copy()
2✔
1330
        for idx := range noSigs.TxIn {
4✔
1331
                noSigs.TxIn[idx].SignatureScript = nil
2✔
1332
                noSigs.TxIn[idx].Witness = nil
2✔
1333
        }
2✔
1334

1335
        // With all the data that is seen as "signed", we can now create the
1336
        // empty packet.
1337
        packet, err := psbt.NewFromUnsignedTx(noSigs)
2✔
1338
        if err != nil {
2✔
1339
                return nil, err
×
1340
        }
×
1341

1342
        var buf bytes.Buffer
2✔
1343
        for idx, txIn := range original.TxIn {
4✔
1344
                if len(txIn.SignatureScript) > 0 {
2✔
1345
                        packet.Inputs[idx].FinalScriptSig = txIn.SignatureScript
×
1346
                }
×
1347

1348
                if len(txIn.Witness) > 0 {
4✔
1349
                        buf.Reset()
2✔
1350
                        err = psbt.WriteTxWitness(&buf, txIn.Witness)
2✔
1351
                        if err != nil {
2✔
1352
                                return nil, err
×
1353
                        }
×
1354
                        packet.Inputs[idx].FinalScriptWitness = buf.Bytes()
2✔
1355
                }
1356
        }
1357

1358
        return packet, nil
2✔
1359
}
1360

1361
// considerShutdown inspects the error and issues a shutdown (through logging
1362
// a critical error, which will cause the logger to issue a clean shutdown
1363
// request) if the error looks like a connection or general availability error
1364
// and not some application specific problem.
1365
func considerShutdown(err error) {
2✔
1366
        statusErr, isStatusErr := status.FromError(err)
2✔
1367
        switch {
2✔
1368
        // The context attached to the client request has timed out. This can be
1369
        // due to not being able to reach the signing server, or it's taking too
1370
        // long to respond. In either case, request a shutdown.
1371
        case err == context.DeadlineExceeded:
×
1372
                fallthrough
×
1373

1374
        // The signing server's context timed out before the client's due to
1375
        // clock skew, request a shutdown anyway.
1376
        case isStatusErr && statusErr.Code() == codes.DeadlineExceeded:
×
1377
                log.Critical("RPC signing timed out: %v", err)
×
1378

UNCOV
1379
        case isStatusErr && statusErr.Code() == codes.Unavailable:
×
UNCOV
1380
                log.Critical("RPC signing server not available: %v", err)
×
1381
        }
1382
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc