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

lightningnetwork / lnd / 12118348650

02 Dec 2024 11:25AM UTC coverage: 58.552% (-0.4%) from 58.977%
12118348650

Pull #9175

github

ellemouton
lnwire: add NodeAnnouncement2
Pull Request #9175: lnwire+netann: update structure of g175 messages to be pure TLV

405 of 571 new or added lines in 11 files covered. (70.93%)

1754 existing lines in 33 files now uncovered.

133774 of 228469 relevant lines covered (58.55%)

19422.52 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) {
4✔
82

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

92
        return &RPCKeyRing{
4✔
93
                WalletController: watchOnlyWalletController,
4✔
94
                watchOnlyKeyRing: watchOnlyKeyRing,
4✔
95
                netParams:        netParams,
4✔
96
                rpcTimeout:       remoteSigner.Timeout,
4✔
97
                signerClient:     signrpc.NewSignerClient(rpcConn),
4✔
98
                walletClient:     walletrpc.NewWalletKitClient(rpcConn),
4✔
99
        }, nil
4✔
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) {
4✔
111

4✔
112
        return r.WalletController.NewAddress(addrType, change, account)
4✔
113
}
4✔
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) {
4✔
128

4✔
129
        tx, err := r.WalletController.SendOutputs(
4✔
130
                inputs, outputs, feeRate, minConfs, label, strategy,
4✔
131
        )
4✔
132
        if err != nil && err != basewallet.ErrTxUnsigned {
4✔
133
                return nil, err
×
134
        }
×
135
        if err == nil {
4✔
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)
4✔
144
        for i, txIn := range tx.TxIn {
8✔
145
                signDesc := input.SignDescriptor{
4✔
146
                        HashType: txscript.SigHashAll,
4✔
147
                        SigHashes: txscript.NewTxSigHashes(
4✔
148
                                tx, outputFetcher,
4✔
149
                        ),
4✔
150
                        PrevOutputFetcher: outputFetcher,
4✔
151
                }
4✔
152

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

164
                if txscript.IsPayToTaproot(info.PkScript) {
8✔
165
                        signDesc.HashType = txscript.SigHashDefault
4✔
166
                }
4✔
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{
4✔
171
                        Value:    int64(info.Value),
4✔
172
                        PkScript: info.PkScript,
4✔
173
                }
4✔
174
                signDesc.InputIndex = i
4✔
175

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

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

187
        return tx, r.WalletController.PublishTransaction(tx, label)
4✔
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) {
4✔
201
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
202
        defer cancel()
4✔
203

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

209
        resp, err := r.walletClient.SignPsbt(ctxt, &walletrpc.SignPsbtRequest{
4✔
210
                FundedPsbt: buf.Bytes(),
4✔
211
        })
4✔
212
        if err != nil {
4✔
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(
4✔
219
                bytes.NewReader(resp.SignedPsbt), false,
4✔
220
        )
4✔
221
        if err != nil {
4✔
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
4✔
229
        packet.Inputs = signedPacket.Inputs
4✔
230
        packet.Outputs = signedPacket.Outputs
4✔
231
        packet.Unknowns = signedPacket.Unknowns
4✔
232

4✔
233
        return resp.SignedInputs, nil
4✔
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 {
4✔
259
        // Let's check that this is actually something we can and want to sign.
4✔
260
        // We need at least one input and one output. In addition each
4✔
261
        // input needs nonWitness Utxo or witness Utxo data specified.
4✔
262
        err := psbt.InputsReadyToSign(packet)
4✔
263
        if err != nil {
4✔
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
4✔
272
        prevOutFetcher := basewallet.PsbtPrevOutputFetcher(packet)
4✔
273
        sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
4✔
274
        for idx, txIn := range tx.TxIn {
8✔
275
                in := packet.Inputs[idx]
4✔
276

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

284
                // Skip this input if it's got final witness data attached.
285
                if len(in.FinalScriptWitness) > 0 {
4✔
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)
4✔
293
                if err != nil {
4✔
294
                        continue
×
295
                }
296
                fullTx := utxo.PrevTx
4✔
297
                signDesc := &input.SignDescriptor{
4✔
298
                        KeyDesc: keychain.KeyDescriptor{},
4✔
299
                        Output: &wire.TxOut{
4✔
300
                                Value:    int64(utxo.Value),
4✔
301
                                PkScript: utxo.PkScript,
4✔
302
                        },
4✔
303
                        HashType:          in.SighashType,
4✔
304
                        SigHashes:         sigHashes,
4✔
305
                        InputIndex:        idx,
4✔
306
                        PrevOutputFetcher: prevOutFetcher,
4✔
307
                }
4✔
308

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

4✔
316
                        if !psbt.TxOutsEqual(signDesc.Output, signOutput) {
4✔
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 {
4✔
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 {
8✔
332
                        signOutput = in.WitnessUtxo
4✔
333

4✔
334
                        if !psbt.TxOutsEqual(signDesc.Output, signOutput) {
4✔
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)
4✔
344
                if err != nil {
4✔
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
4✔
352
                err = psbt.WriteTxWitness(&witnessBytes, script.Witness)
4✔
353
                if err != nil {
4✔
354
                        return fmt.Errorf("error serializing witness: %w", err)
×
355
                }
×
356
                packet.Inputs[idx].FinalScriptWitness = witnessBytes.Bytes()
4✔
357
                packet.Inputs[idx].FinalScriptSig = script.SigScript
4✔
358
        }
359

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

367
        return nil
4✔
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) {
4✔
377

4✔
378
        return r.watchOnlyKeyRing.DeriveNextKey(keyFam)
4✔
379
}
4✔
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) {
4✔
388

4✔
389
        return r.watchOnlyKeyRing.DeriveKey(keyLoc)
4✔
390
}
4✔
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) {
4✔
403

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

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

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

422
        resp, err := r.signerClient.DeriveSharedKey(ctxt, req)
4✔
423
        if err != nil {
4✔
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)
4✔
430
        return key, nil
4✔
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) {
4✔
441

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

4✔
445
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
4✔
446
                Msg: msg,
4✔
447
                KeyLoc: &signrpc.KeyLocator{
4✔
448
                        KeyFamily: int32(keyLoc.Family),
4✔
449
                        KeyIndex:  int32(keyLoc.Index),
4✔
450
                },
4✔
451
                DoubleHash: doubleHash,
4✔
452
        })
4✔
453
        if err != nil {
4✔
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)
4✔
460
        if err != nil {
4✔
461
                return nil, fmt.Errorf("unable to create sig: %w", err)
×
462
        }
×
463
        sig, err := wireSig.ToSignature()
4✔
464
        if err != nil {
4✔
465
                return nil, fmt.Errorf("unable to parse sig: %w", err)
×
466
        }
×
467
        ecdsaSig, ok := sig.(*ecdsa.Signature)
4✔
468
        if !ok {
4✔
469
                return nil, fmt.Errorf("unexpected signature type: %T", sig)
×
470
        }
×
471

472
        return ecdsaSig, nil
4✔
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) {
4✔
482

4✔
483
        if keyLoc.Family != keychain.KeyFamilyNodeKey {
4✔
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)
4✔
489
        defer cancel()
4✔
490

4✔
491
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
4✔
492
                Msg: msg,
4✔
493
                KeyLoc: &signrpc.KeyLocator{
4✔
494
                        KeyFamily: int32(keyLoc.Family),
4✔
495
                        KeyIndex:  int32(keyLoc.Index),
4✔
496
                },
4✔
497
                DoubleHash: doubleHash,
4✔
498
                CompactSig: true,
4✔
499
        })
4✔
500
        if err != nil {
4✔
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
4✔
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) {
4✔
520

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

4✔
524
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
4✔
525
                Msg: msg,
4✔
526
                KeyLoc: &signrpc.KeyLocator{
4✔
527
                        KeyFamily: int32(keyLoc.Family),
4✔
528
                        KeyIndex:  int32(keyLoc.Index),
4✔
529
                },
4✔
530
                DoubleHash:         doubleHash,
4✔
531
                SchnorrSig:         true,
4✔
532
                SchnorrSigTapTweak: taprootTweak,
4✔
533
                Tag:                tag,
4✔
534
        })
4✔
535
        if err != nil {
4✔
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)
4✔
542
        if err != nil {
4✔
543
                return nil, fmt.Errorf("can't parse schnorr signature: %w",
×
544
                        err)
×
545
        }
×
546
        return sigParsed, nil
4✔
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) {
4✔
577

4✔
578
        // Forward the call to the remote signing instance. This call is only
4✔
579
        // ever called for signing witness (p2pkh or p2wsh) inputs and never
4✔
580
        // nested witness inputs, so the sigScript is always nil.
4✔
581
        return r.remoteSign(tx, signDesc, nil)
4✔
582
}
4✔
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) {
4✔
597

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

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

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

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

624
                return &input.Script{
4✔
625
                        Witness: wire.TxWitness{
4✔
626
                                rawSig,
4✔
627
                        },
4✔
628
                }, nil
4✔
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)
4✔
638
        if err != nil {
4✔
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{
4✔
647
                Witness: wire.TxWitness{
4✔
648
                        append(sig.Serialize(), byte(signDesc.HashType)),
4✔
649
                        addr.PubKey().SerializeCompressed(),
4✔
650
                },
4✔
651
                SigScript: sigScript,
4✔
652
        }, nil
4✔
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) {
4✔
664

4✔
665
        apiVersion, err := signrpc.MarshalMuSig2Version(bipVersion)
4✔
666
        if err != nil {
4✔
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{
4✔
673
                KeyLoc: &signrpc.KeyLocator{
4✔
674
                        KeyFamily: int32(keyLoc.Family),
4✔
675
                        KeyIndex:  int32(keyLoc.Index),
4✔
676
                },
4✔
677
                AllSignerPubkeys: make([][]byte, len(pubKeys)),
4✔
678
                Tweaks: make(
4✔
679
                        []*signrpc.TweakDesc, len(tweaks.GenericTweaks),
4✔
680
                ),
4✔
681
                OtherSignerPublicNonces: make([][]byte, len(otherNonces)),
4✔
682
                Version:                 apiVersion,
4✔
683
        }
4✔
684
        for idx, pubKey := range pubKeys {
8✔
685
                switch bipVersion {
4✔
686
                case input.MuSig2Version040:
4✔
687
                        req.AllSignerPubkeys[idx] = schnorr.SerializePubKey(
4✔
688
                                pubKey,
4✔
689
                        )
4✔
690

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

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

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

4✔
719
        resp, err := r.signerClient.MuSig2CreateSession(ctxt, req)
4✔
720
        if err != nil {
4✔
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{
4✔
728
                Version:       bipVersion,
4✔
729
                TaprootTweak:  tweaks.HasTaprootTweak(),
4✔
730
                HaveAllNonces: resp.HaveAllNonces,
4✔
731
        }
4✔
732
        copy(info.SessionID[:], resp.SessionId)
4✔
733
        copy(info.PublicNonce[:], resp.LocalPublicNonces)
4✔
734

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

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

750
        return info, nil
4✔
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) {
4✔
758

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

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

4✔
773
        resp, err := r.signerClient.MuSig2RegisterNonces(ctxt, req)
4✔
774
        if err != nil {
4✔
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
4✔
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) {
4✔
792

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

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

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

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

819
        return partialSig, nil
4✔
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) {
4✔
829

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

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

4✔
848
        resp, err := r.signerClient.MuSig2CombineSig(ctxt, req)
4✔
849
        if err != nil {
4✔
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 {
8✔
858
                return nil, resp.HaveAllSignatures, nil
4✔
859
        }
4✔
860

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

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

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

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

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

886
        return nil
4✔
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) {
4✔
893

4✔
894
        packet, err := packetFromTx(tx)
4✔
895
        if err != nil {
4✔
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 {
8✔
902
                // Skip the input we're signing for, that will get a special
4✔
903
                // treatment later on.
4✔
904
                if idx == signDesc.InputIndex {
8✔
905
                        continue
4✔
906
                }
907

908
                txIn := tx.TxIn[idx]
4✔
909
                info, err := r.WalletController.FetchOutpointInfo(
4✔
910
                        &txIn.PreviousOutPoint,
4✔
911
                )
4✔
912
                if err != nil {
4✔
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{
4✔
933
                        Value:    int64(info.Value),
4✔
934
                        PkScript: info.PkScript,
4✔
935
                }
4✔
936
        }
937

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

4✔
945
        // Things are a bit tricky with the sign descriptor. There basically are
4✔
946
        // four ways to describe a key:
4✔
947
        //   1. By public key only. To match this case both family and index
4✔
948
        //      must be set to 0.
4✔
949
        //   2. By family and index only. To match this case the public key
4✔
950
        //      must be nil and either the family or index must be non-zero.
4✔
951
        //   3. All values are set and locator is non-empty. To match this case
4✔
952
        //      the public key must be set and either the family or index must
4✔
953
        //      be non-zero.
4✔
954
        //   4. All values are set and locator is empty. This is a special case
4✔
955
        //      for the very first channel ever created (with the multi-sig key
4✔
956
        //      family which is 0 and the index which is 0 as well). This looks
4✔
957
        //      identical to case 1 and will also be handled like that case.
4✔
958
        // We only really handle case 1 and 2 here, since 3 is no problem and 4
4✔
959
        // is identical to 1.
4✔
960
        switch {
4✔
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():
4✔
966
                pubKeyBytes := signDesc.KeyDesc.PubKey.SerializeCompressed()
4✔
967
                addr, err := btcutil.NewAddressWitnessPubKeyHash(
4✔
968
                        btcutil.Hash160(pubKeyBytes), r.netParams,
4✔
969
                )
4✔
970
                if err != nil {
4✔
971
                        return nil, fmt.Errorf("error deriving address from "+
×
972
                                "public key %x: %v", pubKeyBytes, err)
×
973
                }
×
974

975
                managedAddr, err := r.AddressInfo(addr)
4✔
976
                if err != nil {
4✔
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)
4✔
982
                if !ok {
4✔
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()
4✔
988
                if scope.Purpose != keychain.BIP0043Purpose {
4✔
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{
4✔
997
                        Family: keychain.KeyFamily(path.InternalAccount),
4✔
998
                        Index:  path.Index,
4✔
999
                }
4✔
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():
4✔
1005
                fullDesc, err := r.watchOnlyKeyRing.DeriveKey(
4✔
1006
                        signDesc.KeyDesc.KeyLocator,
4✔
1007
                )
4✔
1008
                if err != nil {
4✔
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
4✔
1016
        }
1017

1018
        var derivation *psbt.Bip32Derivation
4✔
1019

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

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

1035
        switch {
4✔
1036
        // No error, we do have the full UTXO info available.
1037
        case err == nil:
4✔
1038
                in.WitnessUtxo = &wire.TxOut{
4✔
1039
                        Value:    int64(info.Value),
4✔
1040
                        PkScript: info.PkScript,
4✔
1041
                }
4✔
1042
                in.NonWitnessUtxo = info.PrevTx
4✔
1043
                in.Bip32Derivation = []*psbt.Bip32Derivation{derivation}
4✔
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:
4✔
1053
                in.WitnessUtxo = signDesc.Output
4✔
1054
                in.Bip32Derivation = []*psbt.Bip32Derivation{{
4✔
1055
                        Bip32Path: []uint32{
4✔
1056
                                keychain.BIP0043Purpose +
4✔
1057
                                        hdkeychain.HardenedKeyStart,
4✔
1058
                                r.netParams.HDCoinType +
4✔
1059
                                        hdkeychain.HardenedKeyStart,
4✔
1060
                                uint32(signDesc.KeyDesc.Family) +
4✔
1061
                                        hdkeychain.HardenedKeyStart,
4✔
1062
                                0,
4✔
1063
                                signDesc.KeyDesc.Index,
4✔
1064
                        },
4✔
1065
                        PubKey: signDesc.KeyDesc.PubKey.SerializeCompressed(),
4✔
1066
                }}
4✔
1067

4✔
1068
                // We need to specify a pk script in the witness UTXO, otherwise
4✔
1069
                // the field becomes invalid when serialized as a PSBT. To avoid
4✔
1070
                // running into a generic "Invalid PSBT serialization format"
4✔
1071
                // error later, we return a more descriptive error now.
4✔
1072
                if len(in.WitnessUtxo.PkScript) == 0 {
4✔
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
4✔
1086
        in.SighashType = signDesc.HashType
4✔
1087
        in.WitnessScript = signDesc.WitnessScript
4✔
1088

4✔
1089
        if len(signDesc.SingleTweak) > 0 {
8✔
1090
                in.Unknowns = append(in.Unknowns, &psbt.Unknown{
4✔
1091
                        Key:   btcwallet.PsbtKeyTypeInputSignatureTweakSingle,
4✔
1092
                        Value: signDesc.SingleTweak,
4✔
1093
                })
4✔
1094
        }
4✔
1095
        if signDesc.DoubleTweak != nil {
4✔
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 {
4✔
1104
        case input.TaprootKeySpendBIP0086SignMethod,
1105
                input.TaprootKeySpendSignMethod:
4✔
1106

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

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

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

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

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

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

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

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

1178
        resp, err := r.walletClient.SignPsbt(
4✔
1179
                ctxt, &walletrpc.SignPsbtRequest{FundedPsbt: buf.Bytes()},
4✔
1180
        )
4✔
1181
        if err != nil {
4✔
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(
4✔
1188
                bytes.NewReader(resp.SignedPsbt), false,
4✔
1189
        )
4✔
1190
        if err != nil {
4✔
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) {
4✔
1196
                return nil, fmt.Errorf("remote signer returned invalid PSBT")
×
1197
        }
×
1198
        in = &signedPacket.Inputs[signDesc.InputIndex]
4✔
1199

4✔
1200
        return extractSignature(in, signDesc.SignMethod)
4✔
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) {
4✔
1207

4✔
1208
        switch signMethod {
4✔
1209
        case input.WitnessV0SignMethod:
4✔
1210
                if len(in.PartialSigs) != 1 {
4✔
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]
4✔
1216
                if sigWithSigHash == nil {
4✔
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)
4✔
1224
                if sigLen < ecdsa.MinSigLen+1 {
4✔
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]
4✔
1233
                return ecdsa.ParseDERSignature(sig)
4✔
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:
4✔
1239

4✔
1240
                sigLen := len(in.TaprootKeySpendSig)
4✔
1241
                if sigLen < schnorr.SignatureSize {
4✔
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(
4✔
1248
                        in.TaprootKeySpendSig[:schnorr.SignatureSize],
4✔
1249
                )
4✔
1250

1251
        case input.TaprootScriptSpendSignMethod:
4✔
1252
                if len(in.TaprootScriptSpendSig) != 1 {
4✔
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]
4✔
1259
                if scriptSpendSig == nil {
4✔
1260
                        return nil, fmt.Errorf("remote signer returned nil " +
×
1261
                                "taproot script spend signature")
×
1262
                }
×
1263

1264
                return schnorr.ParseSignature(scriptSpendSig.Signature)
4✔
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) {
4✔
1276

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

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

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

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

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

1319
        return conn, nil
4✔
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) {
4✔
1325
        // The psbt.NewFromUnsignedTx function complains if there are any
4✔
1326
        // scripts or witness content on a TX. So we create a copy of the TX and
4✔
1327
        // nil out all the offending data, but also keep a backup around that we
4✔
1328
        // add to the PSBT afterwards.
4✔
1329
        noSigs := original.Copy()
4✔
1330
        for idx := range noSigs.TxIn {
8✔
1331
                noSigs.TxIn[idx].SignatureScript = nil
4✔
1332
                noSigs.TxIn[idx].Witness = nil
4✔
1333
        }
4✔
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)
4✔
1338
        if err != nil {
4✔
1339
                return nil, err
×
1340
        }
×
1341

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

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

1358
        return packet, nil
4✔
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) {
4✔
1366
        statusErr, isStatusErr := status.FromError(err)
4✔
1367
        switch {
4✔
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