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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

53.17
/input/signdescriptor.go
1
package input
2

3
import (
4
        "encoding/binary"
5
        "errors"
6
        "fmt"
7
        "io"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/btcsuite/btcd/txscript"
11
        "github.com/btcsuite/btcd/wire"
12
        "github.com/lightningnetwork/lnd/keychain"
13
)
14

15
var (
16
        // ErrTweakOverdose signals a SignDescriptor is invalid because both of its
17
        // SingleTweak and DoubleTweak are non-nil.
18
        ErrTweakOverdose = errors.New("sign descriptor should only have one tweak")
19
)
20

21
// SignDescriptor houses the necessary information required to successfully
22
// sign a given segwit output. This struct is used by the Signer interface in
23
// order to gain access to critical data needed to generate a valid signature.
24
type SignDescriptor struct {
25
        // KeyDesc is a descriptor that precisely describes *which* key to use
26
        // for signing. This may provide the raw public key directly, or
27
        // require the Signer to re-derive the key according to the populated
28
        // derivation path.
29
        KeyDesc keychain.KeyDescriptor
30

31
        // SingleTweak is a scalar value that will be added to the private key
32
        // corresponding to the above public key to obtain the private key to
33
        // be used to sign this input. This value is typically derived via the
34
        // following computation:
35
        //
36
        //  * derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
37
        //
38
        // NOTE: If this value is nil, then the input can be signed using only
39
        // the above public key. Either a SingleTweak should be set or a
40
        // DoubleTweak, not both.
41
        SingleTweak []byte
42

43
        // DoubleTweak is a private key that will be used in combination with
44
        // its corresponding private key to derive the private key that is to
45
        // be used to sign the target input. Within the Lightning protocol,
46
        // this value is typically the commitment secret from a previously
47
        // revoked commitment transaction. This value is in combination with
48
        // two hash values, and the original private key to derive the private
49
        // key to be used when signing.
50
        //
51
        //  * k = (privKey*sha256(pubKey || tweakPub) +
52
        //        tweakPriv*sha256(tweakPub || pubKey)) mod N
53
        //
54
        // NOTE: If this value is nil, then the input can be signed using only
55
        // the above public key. Either a SingleTweak should be set or a
56
        // DoubleTweak, not both.
57
        DoubleTweak *btcec.PrivateKey
58

59
        // TapTweak is a 32-byte value that will be used to derive a taproot
60
        // output public key (or the corresponding private key) from an
61
        // internal key and this tweak. The transformation applied is:
62
        //  * outputKey = internalKey +
63
        //        tagged_hash("tapTweak", internalKey || tapTweak)
64
        //
65
        // When attempting to sign an output derived via BIP 86, then this
66
        // field should be an empty byte array.
67
        //
68
        // When attempting to sign for the key spend path of an output key that
69
        // commits to an actual script tree, the script root should be used.
70
        TapTweak []byte
71

72
        // WitnessScript is the full script required to properly redeem the
73
        // output. This field should be set to the full script if a p2wsh
74
        // output is being signed. For p2wkh it should be set to the hashed
75
        // script (PkScript).
76
        WitnessScript []byte
77

78
        // SignMethod specifies how the input should be signed. Depending on the
79
        // selected method, either the TapTweak, WitnessScript or both need to
80
        // be specified.
81
        SignMethod SignMethod
82

83
        // Output is the target output which should be signed. The PkScript and
84
        // Value fields within the output should be properly populated,
85
        // otherwise an invalid signature may be generated.
86
        Output *wire.TxOut
87

88
        // HashType is the target sighash type that should be used when
89
        // generating the final sighash, and signature.
90
        HashType txscript.SigHashType
91

92
        // SigHashes is the pre-computed sighash midstate to be used when
93
        // generating the final sighash for signing.
94
        SigHashes *txscript.TxSigHashes
95

96
        // PrevOutputFetcher is an interface that can return the output
97
        // information on all UTXOs that are being spent in this transaction.
98
        // This MUST be set when spending Taproot outputs.
99
        PrevOutputFetcher txscript.PrevOutputFetcher
100

101
        // ControlBlock is a fully serialized control block that contains the
102
        // merkle proof necessary to spend a taproot output. This may
103
        // optionally be set if the SignMethod is
104
        // input.TaprootScriptSpendSignMethod. In which case, this should be an
105
        // inclusion proof for the WitnessScript.
106
        ControlBlock []byte
107

108
        // InputIndex is the target input within the transaction that should be
109
        // signed.
110
        InputIndex int
111
}
112

113
// SignMethod defines the different ways a signer can sign, given a specific
114
// input.
115
type SignMethod uint8
116

117
const (
118
        // WitnessV0SignMethod denotes that a SegWit v0 (p2wkh, np2wkh, p2wsh)
119
        // input script should be signed.
120
        WitnessV0SignMethod SignMethod = 0
121

122
        // TaprootKeySpendBIP0086SignMethod denotes that a SegWit v1 (p2tr)
123
        // input should be signed by using the BIP0086 method (commit to
124
        // internal key only).
125
        TaprootKeySpendBIP0086SignMethod SignMethod = 1
126

127
        // TaprootKeySpendSignMethod denotes that a SegWit v1 (p2tr)
128
        // input should be signed by using a given taproot hash to commit to in
129
        // addition to the internal key.
130
        TaprootKeySpendSignMethod SignMethod = 2
131

132
        // TaprootScriptSpendSignMethod denotes that a SegWit v1 (p2tr) input
133
        // should be spent using the script path and that a specific leaf script
134
        // should be signed for.
135
        TaprootScriptSpendSignMethod SignMethod = 3
136
)
137

138
// String returns a human-readable representation of the signing method.
139
func (s SignMethod) String() string {
3,849✔
140
        switch s {
3,849✔
141
        case WitnessV0SignMethod:
3,780✔
142
                return "witness_v0"
3,780✔
143
        case TaprootKeySpendBIP0086SignMethod:
×
144
                return "taproot_key_spend_bip86"
×
145
        case TaprootKeySpendSignMethod:
×
146
                return "taproot_key_spend"
×
147
        case TaprootScriptSpendSignMethod:
69✔
148
                return "taproot_script_spend"
69✔
149
        default:
×
150
                return fmt.Sprintf("unknown<%d>", s)
×
151
        }
152
}
153

154
// PkScriptCompatible returns true if the given public key script is compatible
155
// with the sign method.
156
func (s SignMethod) PkScriptCompatible(pkScript []byte) bool {
×
157
        switch s {
×
158
        // SegWit v0 can be p2wkh, np2wkh, p2wsh.
159
        case WitnessV0SignMethod:
×
160
                return txscript.IsPayToWitnessPubKeyHash(pkScript) ||
×
161
                        txscript.IsPayToWitnessScriptHash(pkScript) ||
×
162
                        txscript.IsPayToScriptHash(pkScript)
×
163

164
        case TaprootKeySpendBIP0086SignMethod, TaprootKeySpendSignMethod,
165
                TaprootScriptSpendSignMethod:
×
166

×
167
                return txscript.IsPayToTaproot(pkScript)
×
168

169
        default:
×
170
                return false
×
171
        }
172
}
173

174
// WriteSignDescriptor serializes a SignDescriptor struct into the passed
175
// io.Writer stream.
176
//
177
// NOTE: We assume the SigHashes and InputIndex fields haven't been assigned
178
// yet, since that is usually done just before broadcast by the witness
179
// generator.
180
func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
170✔
181
        err := binary.Write(w, binary.BigEndian, sd.KeyDesc.Family)
170✔
182
        if err != nil {
170✔
183
                return err
×
184
        }
×
185
        err = binary.Write(w, binary.BigEndian, sd.KeyDesc.Index)
170✔
186
        if err != nil {
170✔
187
                return err
×
188
        }
×
189

190
        err = binary.Write(w, binary.BigEndian, sd.KeyDesc.PubKey != nil)
170✔
191
        if err != nil {
170✔
192
                return err
×
193
        }
×
194

195
        if sd.KeyDesc.PubKey != nil {
279✔
196
                serializedPubKey := sd.KeyDesc.PubKey.SerializeCompressed()
109✔
197
                if err := wire.WriteVarBytes(w, 0, serializedPubKey); err != nil {
109✔
198
                        return err
×
199
                }
×
200
        }
201

202
        if err := wire.WriteVarBytes(w, 0, sd.SingleTweak); err != nil {
170✔
203
                return err
×
204
        }
×
205

206
        var doubleTweakBytes []byte
170✔
207
        if sd.DoubleTweak != nil {
178✔
208
                doubleTweakBytes = sd.DoubleTweak.Serialize()
8✔
209
        }
8✔
210
        if err := wire.WriteVarBytes(w, 0, doubleTweakBytes); err != nil {
170✔
211
                return err
×
212
        }
×
213

214
        if err := wire.WriteVarBytes(w, 0, sd.WitnessScript); err != nil {
170✔
215
                return err
×
216
        }
×
217

218
        if err := writeTxOut(w, sd.Output); err != nil {
170✔
219
                return err
×
220
        }
×
221

222
        var scratch [4]byte
170✔
223
        binary.BigEndian.PutUint32(scratch[:], uint32(sd.HashType))
170✔
224
        if _, err := w.Write(scratch[:]); err != nil {
170✔
225
                return err
×
226
        }
×
227

228
        return nil
170✔
229
}
230

231
// ReadSignDescriptor deserializes a SignDescriptor struct from the passed
232
// io.Reader stream.
233
func ReadSignDescriptor(r io.Reader, sd *SignDescriptor) error {
261✔
234
        err := binary.Read(r, binary.BigEndian, &sd.KeyDesc.Family)
261✔
235
        if err != nil {
261✔
236
                return err
×
237
        }
×
238
        err = binary.Read(r, binary.BigEndian, &sd.KeyDesc.Index)
261✔
239
        if err != nil {
261✔
240
                return err
×
241
        }
×
242

243
        var hasKey bool
261✔
244
        err = binary.Read(r, binary.BigEndian, &hasKey)
261✔
245
        if err != nil {
261✔
246
                return err
×
247
        }
×
248

249
        if hasKey {
431✔
250
                pubKeyBytes, err := wire.ReadVarBytes(r, 0, 34, "pubkey")
170✔
251
                if err != nil {
170✔
252
                        return err
×
253
                }
×
254
                sd.KeyDesc.PubKey, err = btcec.ParsePubKey(pubKeyBytes)
170✔
255
                if err != nil {
170✔
256
                        return err
×
257
                }
×
258
        }
259

260
        singleTweak, err := wire.ReadVarBytes(r, 0, 32, "singleTweak")
261✔
261
        if err != nil {
261✔
262
                return err
×
263
        }
×
264

265
        // Serializing a SignDescriptor with a nil-valued SingleTweak results
266
        // in deserializing a zero-length slice. Since a nil-valued SingleTweak
267
        // has special meaning and a zero-length slice for a SingleTweak is
268
        // invalid, we can use the zero-length slice as the flag for a
269
        // nil-valued SingleTweak.
270
        if len(singleTweak) == 0 {
392✔
271
                sd.SingleTweak = nil
131✔
272
        } else {
261✔
273
                sd.SingleTweak = singleTweak
130✔
274
        }
130✔
275

276
        doubleTweakBytes, err := wire.ReadVarBytes(r, 0, 32, "doubleTweak")
261✔
277
        if err != nil {
261✔
278
                return err
×
279
        }
×
280

281
        // Serializing a SignDescriptor with a nil-valued DoubleTweak results
282
        // in deserializing a zero-length slice. Since a nil-valued DoubleTweak
283
        // has special meaning and a zero-length slice for a DoubleTweak is
284
        // invalid, we can use the zero-length slice as the flag for a
285
        // nil-valued DoubleTweak.
286
        if len(doubleTweakBytes) == 0 {
522✔
287
                sd.DoubleTweak = nil
261✔
288
        } else {
261✔
289
                sd.DoubleTweak, _ = btcec.PrivKeyFromBytes(doubleTweakBytes)
×
290
        }
×
291

292
        // Only one tweak should ever be set, fail if both are present.
293
        if sd.SingleTweak != nil && sd.DoubleTweak != nil {
261✔
294
                return ErrTweakOverdose
×
295
        }
×
296

297
        witnessScript, err := wire.ReadVarBytes(r, 0, 500, "witnessScript")
261✔
298
        if err != nil {
261✔
299
                return err
×
300
        }
×
301
        sd.WitnessScript = witnessScript
261✔
302

261✔
303
        txOut := &wire.TxOut{}
261✔
304
        if err := readTxOut(r, txOut); err != nil {
261✔
305
                return err
×
306
        }
×
307
        sd.Output = txOut
261✔
308

261✔
309
        var hashType [4]byte
261✔
310
        if _, err := io.ReadFull(r, hashType[:]); err != nil {
261✔
311
                return err
×
312
        }
×
313
        sd.HashType = txscript.SigHashType(binary.BigEndian.Uint32(hashType[:]))
261✔
314

261✔
315
        return nil
261✔
316
}
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