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

lightningnetwork / lnd / 13586900447

28 Feb 2025 11:07AM UTC coverage: 58.845% (+0.01%) from 58.834%
13586900447

Pull #9566

github

yyforyongyu
lntest+itest: change the method signature of `AssertPaymentStatus`

So this can be used in other tests when we only care about the payment
hash.
Pull Request #9566: lntest+itest: change the method signature of `AssertPaymentStatus`

0 of 6 new or added lines in 2 files covered. (0.0%)

46 existing lines in 14 files now uncovered.

136449 of 231880 relevant lines covered (58.84%)

19275.5 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/v2"
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) {
3✔
82

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

429
        copy(key[:], resp.SharedKey)
3✔
430
        return key, nil
3✔
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) {
3✔
441

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1018
        var derivation *psbt.Bip32Derivation
3✔
1019

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1379
        case isStatusErr && statusErr.Code() == codes.Unavailable:
×
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