• 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

78.95
/chanbackup/backup.go
1
package chanbackup
2

3
import (
4
        "fmt"
5

6
        "github.com/btcsuite/btcd/wire"
7
        "github.com/lightningnetwork/lnd/channeldb"
8
        "github.com/lightningnetwork/lnd/fn/v2"
9
)
10

11
// LiveChannelSource is an interface that allows us to query for the set of
12
// live channels. A live channel is one that is open, and has not had a
13
// commitment transaction broadcast.
14
type LiveChannelSource interface {
15
        // FetchAllChannels returns all known live channels.
16
        FetchAllChannels() ([]*channeldb.OpenChannel, error)
17

18
        // FetchChannel attempts to locate a live channel identified by the
19
        // passed chanPoint. Optionally an existing db tx can be supplied.
20
        FetchChannel(chanPoint wire.OutPoint) (*channeldb.OpenChannel, error)
21
}
22

23
// assembleChanBackup attempts to assemble a static channel backup for the
24
// passed open channel. The backup includes all information required to restore
25
// the channel, as well as addressing information so we can find the peer and
26
// reconnect to them to initiate the protocol.
27
func assembleChanBackup(addrSource channeldb.AddrSource,
28
        openChan *channeldb.OpenChannel) (*Single, error) {
3✔
29

3✔
30
        log.Debugf("Crafting backup for ChannelPoint(%v)",
3✔
31
                openChan.FundingOutpoint)
3✔
32

3✔
33
        // First, we'll query the channel source to obtain all the addresses
3✔
34
        // that are associated with the peer for this channel.
3✔
35
        known, nodeAddrs, err := addrSource.AddrsForNode(openChan.IdentityPub)
3✔
36
        if err != nil {
3✔
37
                return nil, err
×
38
        }
×
39
        if !known {
3✔
UNCOV
40
                return nil, fmt.Errorf("node unknown by address source")
×
UNCOV
41
        }
×
42

43
        single := NewSingle(openChan, nodeAddrs)
3✔
44

3✔
45
        return &single, nil
3✔
46
}
47

48
// buildCloseTxInputs generates inputs needed to force close a channel from
49
// an open channel. Anyone having these inputs and the signer, can sign the
50
// force closure transaction. Warning! If the channel state updates, an attempt
51
// to close the channel using this method with outdated CloseTxInputs can result
52
// in loss of funds! This may happen if an outdated channel backup is attempted
53
// to be used to force close the channel.
54
func buildCloseTxInputs(
55
        targetChan *channeldb.OpenChannel) fn.Option[CloseTxInputs] {
3✔
56

3✔
57
        log.Debugf("Crafting CloseTxInputs for ChannelPoint(%v)",
3✔
58
                targetChan.FundingOutpoint)
3✔
59

3✔
60
        localCommit := targetChan.LocalCommitment
3✔
61

3✔
62
        if localCommit.CommitTx == nil {
6✔
63
                log.Infof("CommitTx is nil for ChannelPoint(%v), "+
3✔
64
                        "skipping CloseTxInputs. This is possible when "+
3✔
65
                        "DLP is active.", targetChan.FundingOutpoint)
3✔
66

3✔
67
                return fn.None[CloseTxInputs]()
3✔
68
        }
3✔
69

70
        // We need unsigned force close tx and the counterparty's signature.
71
        inputs := CloseTxInputs{
3✔
72
                CommitTx:  localCommit.CommitTx,
3✔
73
                CommitSig: localCommit.CommitSig,
3✔
74
        }
3✔
75

3✔
76
        // In case of a taproot channel, commit height is needed as well to
3✔
77
        // produce verification nonce for the taproot channel using shachain.
3✔
78
        if targetChan.ChanType.IsTaproot() {
6✔
79
                inputs.CommitHeight = localCommit.CommitHeight
3✔
80
        }
3✔
81

82
        // In case of a custom taproot channel, TapscriptRoot is needed as well.
83
        if targetChan.ChanType.HasTapscriptRoot() {
3✔
UNCOV
84
                inputs.TapscriptRoot = targetChan.TapscriptRoot
×
UNCOV
85
        }
×
86

87
        return fn.Some(inputs)
3✔
88
}
89

90
// FetchBackupForChan attempts to create a plaintext static channel backup for
91
// the target channel identified by its channel point. If we're unable to find
92
// the target channel, then an error will be returned.
93
func FetchBackupForChan(chanPoint wire.OutPoint, chanSource LiveChannelSource,
94
        addrSource channeldb.AddrSource) (*Single, error) {
3✔
95

3✔
96
        // First, we'll query the channel source to see if the channel is known
3✔
97
        // and open within the database.
3✔
98
        targetChan, err := chanSource.FetchChannel(chanPoint)
3✔
99
        if err != nil {
3✔
UNCOV
100
                // If we can't find the channel, then we return with an error,
×
UNCOV
101
                // as we have nothing to  backup.
×
UNCOV
102
                return nil, fmt.Errorf("unable to find target channel")
×
UNCOV
103
        }
×
104

105
        // Once we have the target channel, we can assemble the backup using
106
        // the source to obtain any extra information that we may need.
107
        staticChanBackup, err := assembleChanBackup(addrSource, targetChan)
3✔
108
        if err != nil {
3✔
UNCOV
109
                return nil, fmt.Errorf("unable to create chan backup: %w", err)
×
UNCOV
110
        }
×
111

112
        return staticChanBackup, nil
3✔
113
}
114

115
// FetchStaticChanBackups will return a plaintext static channel back up for
116
// all known active/open channels within the passed channel source.
117
func FetchStaticChanBackups(chanSource LiveChannelSource,
118
        addrSource channeldb.AddrSource) ([]Single, error) {
3✔
119

3✔
120
        // First, we'll query the backup source for information concerning all
3✔
121
        // currently open and available channels.
3✔
122
        openChans, err := chanSource.FetchAllChannels()
3✔
123
        if err != nil {
3✔
UNCOV
124
                return nil, err
×
UNCOV
125
        }
×
126

127
        // Now that we have all the channels, we'll use the chanSource to
128
        // obtain any auxiliary information we need to craft a backup for each
129
        // channel.
130
        staticChanBackups := make([]Single, 0, len(openChans))
3✔
131
        for _, openChan := range openChans {
6✔
132
                chanBackup, err := assembleChanBackup(addrSource, openChan)
3✔
133
                if err != nil {
3✔
UNCOV
134
                        return nil, err
×
UNCOV
135
                }
×
136

137
                staticChanBackups = append(staticChanBackups, *chanBackup)
3✔
138
        }
139

140
        return staticChanBackups, nil
3✔
141
}
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