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

lightningnetwork / lnd / 15736109134

18 Jun 2025 02:46PM UTC coverage: 58.197% (-10.1%) from 68.248%
15736109134

Pull #9752

github

web-flow
Merge d2634a68c into 31c74f20f
Pull Request #9752: routerrpc: reject payment to invoice that don't have payment secret or blinded paths

6 of 13 new or added lines in 2 files covered. (46.15%)

28331 existing lines in 455 files now uncovered.

97860 of 168153 relevant lines covered (58.2%)

1.81 hits per line

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

79.49
/chanbackup/backup.go
1
package chanbackup
2

3
import (
4
        "context"
5
        "fmt"
6

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

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

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

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

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

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

46
        single := NewSingle(openChan, nodeAddrs)
3✔
47

3✔
48
        return &single, nil
3✔
49
}
50

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

3✔
60
        log.Debugf("Crafting CloseTxInputs for ChannelPoint(%v)",
3✔
61
                targetChan.FundingOutpoint)
3✔
62

3✔
63
        localCommit := targetChan.LocalCommitment
3✔
64

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

3✔
70
                return fn.None[CloseTxInputs]()
3✔
71
        }
3✔
72

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

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

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

90
        return fn.Some(inputs)
3✔
91
}
92

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

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

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

116
        return staticChanBackup, nil
3✔
117
}
118

119
// FetchStaticChanBackups will return a plaintext static channel back up for
120
// all known active/open channels within the passed channel source.
121
func FetchStaticChanBackups(ctx context.Context, chanSource LiveChannelSource,
122
        addrSource channeldb.AddrSource) ([]Single, error) {
3✔
123

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

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

141
                staticChanBackups = append(staticChanBackups, *chanBackup)
3✔
142
        }
143

144
        return staticChanBackups, nil
3✔
145
}
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