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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

0.0
/lntest/mock/signer.go
1
package mock
2

3
import (
4
        "crypto/sha256"
5
        "fmt"
6

7
        "github.com/btcsuite/btcd/btcec/v2"
8
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
9
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
10
        "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
11
        "github.com/btcsuite/btcd/chaincfg/chainhash"
12
        "github.com/btcsuite/btcd/txscript"
13
        "github.com/btcsuite/btcd/wire"
14
        "github.com/lightningnetwork/lnd/input"
15
        "github.com/lightningnetwork/lnd/keychain"
16
)
17

18
var (
19
        idKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
20
)
21

22
// DummySignature is a dummy Signature implementation.
23
type DummySignature struct{}
24

25
// Serialize returns an empty byte slice.
UNCOV
26
func (d *DummySignature) Serialize() []byte {
×
UNCOV
27
        return []byte{}
×
UNCOV
28
}
×
29

30
// Verify always returns true.
31
func (d *DummySignature) Verify(_ []byte, _ *btcec.PublicKey) bool {
×
32
        return true
×
33
}
×
34

35
// DummySigner is an implementation of the Signer interface that returns
36
// dummy values when called.
37
type DummySigner struct{}
38

39
// SignOutputRaw returns a dummy signature.
40
func (d *DummySigner) SignOutputRaw(tx *wire.MsgTx,
UNCOV
41
        signDesc *input.SignDescriptor) (input.Signature, error) {
×
UNCOV
42

×
UNCOV
43
        return &DummySignature{}, nil
×
UNCOV
44
}
×
45

46
// ComputeInputScript returns nil for both values.
47
func (d *DummySigner) ComputeInputScript(tx *wire.MsgTx,
UNCOV
48
        signDesc *input.SignDescriptor) (*input.Script, error) {
×
UNCOV
49

×
UNCOV
50
        return &input.Script{}, nil
×
UNCOV
51
}
×
52

53
// MuSig2CreateSession creates a new MuSig2 signing session using the local
54
// key identified by the key locator. The complete list of all public keys of
55
// all signing parties must be provided, including the public key of the local
56
// signing key. If nonces of other parties are already known, they can be
57
// submitted as well to reduce the number of method calls necessary later on.
58
func (d *DummySigner) MuSig2CreateSession(input.MuSig2Version,
59
        keychain.KeyLocator, []*btcec.PublicKey, *input.MuSig2Tweaks,
60
        [][musig2.PubNonceSize]byte, *musig2.Nonces,
61
) (*input.MuSig2SessionInfo, error) {
×
62

×
63
        return nil, nil
×
64
}
×
65

66
// MuSig2RegisterNonces registers one or more public nonces of other signing
67
// participants for a session identified by its ID. This method returns true
68
// once we have all nonces for all other signing participants.
69
func (d *DummySigner) MuSig2RegisterNonces(input.MuSig2SessionID,
70
        [][musig2.PubNonceSize]byte) (bool, error) {
×
71

×
72
        return false, nil
×
73
}
×
74

75
// MuSig2Sign creates a partial signature using the local signing key
76
// that was specified when the session was created. This can only be
77
// called when all public nonces of all participants are known and have
78
// been registered with the session. If this node isn't responsible for
79
// combining all the partial signatures, then the cleanup parameter
80
// should be set, indicating that the session can be removed from memory
81
// once the signature was produced.
82
func (d *DummySigner) MuSig2Sign(input.MuSig2SessionID,
83
        [sha256.Size]byte, bool) (*musig2.PartialSignature, error) {
×
84

×
85
        return nil, nil
×
86
}
×
87

88
// MuSig2CombineSig combines the given partial signature(s) with the
89
// local one, if it already exists. Once a partial signature of all
90
// participants is registered, the final signature will be combined and
91
// returned.
92
func (d *DummySigner) MuSig2CombineSig(input.MuSig2SessionID,
93
        []*musig2.PartialSignature) (*schnorr.Signature, bool, error) {
×
94

×
95
        return nil, false, nil
×
96
}
×
97

98
// MuSig2Cleanup removes a session from memory to free up resources.
99
func (d *DummySigner) MuSig2Cleanup(input.MuSig2SessionID) error {
×
100
        return nil
×
101
}
×
102

103
// SingleSigner is an implementation of the Signer interface that signs
104
// everything with a single private key.
105
type SingleSigner struct {
106
        Privkey *btcec.PrivateKey
107
        KeyLoc  keychain.KeyLocator
108

109
        *input.MusigSessionManager
110
}
111

UNCOV
112
func NewSingleSigner(privkey *btcec.PrivateKey) *SingleSigner {
×
UNCOV
113
        signer := &SingleSigner{
×
UNCOV
114
                Privkey: privkey,
×
UNCOV
115
                KeyLoc:  idKeyLoc,
×
UNCOV
116
        }
×
UNCOV
117

×
UNCOV
118
        keyFetcher := func(*keychain.KeyDescriptor) (*btcec.PrivateKey, error) {
×
UNCOV
119
                return signer.Privkey, nil
×
UNCOV
120
        }
×
UNCOV
121
        signer.MusigSessionManager = input.NewMusigSessionManager(keyFetcher)
×
UNCOV
122

×
UNCOV
123
        return signer
×
124
}
125

126
// SignOutputRaw generates a signature for the passed transaction using the
127
// stored private key.
128
func (s *SingleSigner) SignOutputRaw(tx *wire.MsgTx,
UNCOV
129
        signDesc *input.SignDescriptor) (input.Signature, error) {
×
UNCOV
130

×
UNCOV
131
        amt := signDesc.Output.Value
×
UNCOV
132
        witnessScript := signDesc.WitnessScript
×
UNCOV
133
        privKey := s.Privkey
×
UNCOV
134

×
UNCOV
135
        if !privKey.PubKey().IsEqual(signDesc.KeyDesc.PubKey) {
×
136
                return nil, fmt.Errorf("incorrect key passed")
×
137
        }
×
138

UNCOV
139
        switch {
×
140
        case signDesc.SingleTweak != nil:
×
141
                privKey = input.TweakPrivKey(privKey,
×
142
                        signDesc.SingleTweak)
×
143
        case signDesc.DoubleTweak != nil:
×
144
                privKey = input.DeriveRevocationPrivKey(privKey,
×
145
                        signDesc.DoubleTweak)
×
146
        }
147

UNCOV
148
        sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes,
×
UNCOV
149
                signDesc.InputIndex, amt, witnessScript, signDesc.HashType,
×
UNCOV
150
                privKey)
×
UNCOV
151
        if err != nil {
×
152
                return nil, err
×
153
        }
×
154

UNCOV
155
        return ecdsa.ParseDERSignature(sig[:len(sig)-1])
×
156
}
157

158
// ComputeInputScript computes an input script with the stored private key
159
// given a transaction and a SignDescriptor.
160
func (s *SingleSigner) ComputeInputScript(tx *wire.MsgTx,
UNCOV
161
        signDesc *input.SignDescriptor) (*input.Script, error) {
×
UNCOV
162

×
UNCOV
163
        privKey := s.Privkey
×
UNCOV
164

×
UNCOV
165
        switch {
×
166
        case signDesc.SingleTweak != nil:
×
167
                privKey = input.TweakPrivKey(privKey,
×
168
                        signDesc.SingleTweak)
×
169
        case signDesc.DoubleTweak != nil:
×
170
                privKey = input.DeriveRevocationPrivKey(privKey,
×
171
                        signDesc.DoubleTweak)
×
172
        }
173

UNCOV
174
        witnessScript, err := txscript.WitnessSignature(tx, signDesc.SigHashes,
×
UNCOV
175
                signDesc.InputIndex, signDesc.Output.Value, signDesc.Output.PkScript,
×
UNCOV
176
                signDesc.HashType, privKey, true)
×
UNCOV
177
        if err != nil {
×
178
                return nil, err
×
179
        }
×
180

UNCOV
181
        return &input.Script{
×
UNCOV
182
                Witness: witnessScript,
×
UNCOV
183
        }, nil
×
184
}
185

186
// SignMessage takes a public key and a message and only signs the message
187
// with the stored private key if the public key matches the private key.
188
func (s *SingleSigner) SignMessage(keyLoc keychain.KeyLocator,
UNCOV
189
        msg []byte, doubleHash bool) (*ecdsa.Signature, error) {
×
UNCOV
190

×
UNCOV
191
        mockKeyLoc := s.KeyLoc
×
UNCOV
192
        if s.KeyLoc.IsEmpty() {
×
UNCOV
193
                mockKeyLoc = idKeyLoc
×
UNCOV
194
        }
×
195

UNCOV
196
        if keyLoc != mockKeyLoc {
×
197
                return nil, fmt.Errorf("unknown public key")
×
198
        }
×
199

UNCOV
200
        var digest []byte
×
UNCOV
201
        if doubleHash {
×
UNCOV
202
                digest = chainhash.DoubleHashB(msg)
×
UNCOV
203
        } else {
×
204
                digest = chainhash.HashB(msg)
×
205
        }
×
UNCOV
206
        return ecdsa.Sign(s.Privkey, digest), nil
×
207
}
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