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

lightningnetwork / lnd / 13035292482

29 Jan 2025 03:59PM UTC coverage: 49.3% (-9.5%) from 58.777%
13035292482

Pull #9456

github

mohamedawnallah
docs: update release-notes-0.19.0.md

In this commit, we warn users about the removal
of RPCs `SendToRoute`, `SendToRouteSync`, `SendPayment`,
and `SendPaymentSync` in the next release 0.20.
Pull Request #9456: lnrpc+docs: deprecate warning `SendToRoute`, `SendToRouteSync`, `SendPayment`, and `SendPaymentSync` in Release 0.19

100634 of 204126 relevant lines covered (49.3%)

1.54 hits per line

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

0.0
/channeldb/migration25/migration.go
1
package migration25
2

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

7
        mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
8
        "github.com/lightningnetwork/lnd/kvdb"
9
)
10

11
var (
12
        // openChanBucket stores all the currently open channels. This bucket
13
        // has a second, nested bucket which is keyed by a node's ID. Within
14
        // that node ID bucket, all attributes required to track, update, and
15
        // close a channel are stored.
16
        openChannelBucket = []byte("open-chan-bucket")
17

18
        // chanInfoKey can be accessed within the bucket for a channel
19
        // (identified by its chanPoint). This key stores all the static
20
        // information for a channel which is decided at the end of  the
21
        // funding flow.
22
        chanInfoKey = []byte("chan-info-key")
23

24
        // ErrNoChanDBExists is returned when a channel bucket hasn't been
25
        // created.
26
        ErrNoChanDBExists = fmt.Errorf("channel db has not yet been created")
27

28
        // ErrNoActiveChannels  is returned when there is no active (open)
29
        // channels within the database.
30
        ErrNoActiveChannels = fmt.Errorf("no active channels exist")
31

32
        // ErrChannelNotFound is returned when we attempt to locate a channel
33
        // for a specific chain, but it is not found.
34
        ErrChannelNotFound = fmt.Errorf("channel not found")
35
)
36

37
// MigrateInitialBalances patches the two new fields, InitialLocalBalance and
38
// InitialRemoteBalance, for all the open channels. It does so by reading the
39
// revocation log at height 0 to learn the initial balances and then updates
40
// the channel's info.
41
// The channel info is saved in the nested bucket which is accessible via
42
// nodePub:chainHash:chanPoint. If any of the sub-buckets turns out to be nil,
43
// we will log the error and continue to process the rest.
44
func MigrateInitialBalances(tx kvdb.RwTx) error {
×
45
        log.Infof("Migrating initial local and remote balances...")
×
46

×
47
        openChanBucket := tx.ReadWriteBucket(openChannelBucket)
×
48

×
49
        // If no bucket is found, we can exit early.
×
50
        if openChanBucket == nil {
×
51
                return nil
×
52
        }
×
53

54
        // Read a list of open channels.
55
        channels, err := findOpenChannels(openChanBucket)
×
56
        if err != nil {
×
57
                return err
×
58
        }
×
59

60
        // Migrate the balances.
61
        for _, c := range channels {
×
62
                if err := migrateBalances(tx, c); err != nil {
×
63
                        return err
×
64
                }
×
65
        }
66

67
        return err
×
68
}
69

70
// findOpenChannels finds all open channels.
71
func findOpenChannels(openChanBucket kvdb.RBucket) ([]*OpenChannel, error) {
×
72
        channels := []*OpenChannel{}
×
73

×
74
        // readChannel is a helper closure that reads the channel info from the
×
75
        // channel bucket.
×
76
        readChannel := func(chainBucket kvdb.RBucket, cp []byte) error {
×
77
                c := &OpenChannel{}
×
78

×
79
                // Read the sub-bucket level 3.
×
80
                chanBucket := chainBucket.NestedReadBucket(
×
81
                        cp,
×
82
                )
×
83
                if chanBucket == nil {
×
84
                        log.Errorf("unable to read bucket for chanPoint=%x", cp)
×
85
                        return nil
×
86
                }
×
87
                // Get the old channel info.
88
                if err := fetchChanInfo(chanBucket, c, true); err != nil {
×
89
                        return fmt.Errorf("unable to fetch chan info: %w", err)
×
90
                }
×
91

92
                // Fetch the channel commitments, which are useful for freshly
93
                // open channels as they don't have any revocation logs and
94
                // their current commitments reflect the initial balances.
95
                if err := FetchChanCommitments(chanBucket, c); err != nil {
×
96
                        return fmt.Errorf("unable to fetch chan commits: %w",
×
97
                                err)
×
98
                }
×
99

100
                channels = append(channels, c)
×
101

×
102
                return nil
×
103
        }
104

105
        // Iterate the root bucket.
106
        err := openChanBucket.ForEach(func(nodePub, v []byte) error {
×
107
                // Ensure that this is a key the same size as a pubkey, and
×
108
                // also that it leads directly to a bucket.
×
109
                if len(nodePub) != 33 || v != nil {
×
110
                        return nil
×
111
                }
×
112

113
                // Read the sub-bucket level 1.
114
                nodeChanBucket := openChanBucket.NestedReadBucket(nodePub)
×
115
                if nodeChanBucket == nil {
×
116
                        log.Errorf("no bucket for node %x", nodePub)
×
117
                        return nil
×
118
                }
×
119

120
                // Iterate the bucket.
121
                return nodeChanBucket.ForEach(func(chainHash, _ []byte) error {
×
122
                        // Read the sub-bucket level 2.
×
123
                        chainBucket := nodeChanBucket.NestedReadBucket(
×
124
                                chainHash,
×
125
                        )
×
126
                        if chainBucket == nil {
×
127
                                log.Errorf("unable to read bucket for chain=%x",
×
128
                                        chainHash)
×
129
                                return nil
×
130
                        }
×
131

132
                        // Iterate the bucket.
133
                        return chainBucket.ForEach(func(cp, _ []byte) error {
×
134
                                return readChannel(chainBucket, cp)
×
135
                        })
×
136
                })
137
        })
138

139
        if err != nil {
×
140
                return nil, err
×
141
        }
×
142

143
        return channels, nil
×
144
}
145

146
// migrateBalances queries the revocation log at height 0 to find the initial
147
// balances and save them to the channel info.
148
func migrateBalances(tx kvdb.RwTx, c *OpenChannel) error {
×
149
        // Get the bucket.
×
150
        chanBucket, err := FetchChanBucket(tx, c)
×
151
        if err != nil {
×
152
                return err
×
153
        }
×
154
        // Get the initial balances.
155
        localAmt, remoteAmt, err := c.balancesAtHeight(chanBucket, 0)
×
156
        if err != nil {
×
157
                return fmt.Errorf("unable to get initial balances: %w", err)
×
158
        }
×
159

160
        c.InitialLocalBalance = localAmt
×
161
        c.InitialRemoteBalance = remoteAmt
×
162

×
163
        // Update the channel info.
×
164
        if err := putChanInfo(chanBucket, c, false); err != nil {
×
165
                return fmt.Errorf("unable to put chan info: %w", err)
×
166
        }
×
167

168
        return nil
×
169
}
170

171
// FetchChanBucket is a helper function that returns the bucket where a
172
// channel's data resides in given: the public key for the node, the outpoint,
173
// and the chainhash that the channel resides on.
174
func FetchChanBucket(tx kvdb.RwTx, c *OpenChannel) (kvdb.RwBucket, error) {
×
175
        // First fetch the top level bucket which stores all data related to
×
176
        // current, active channels.
×
177
        openChanBucket := tx.ReadWriteBucket(openChannelBucket)
×
178
        if openChanBucket == nil {
×
179
                return nil, ErrNoChanDBExists
×
180
        }
×
181

182
        // Within this top level bucket, fetch the bucket dedicated to storing
183
        // open channel data specific to the remote node.
184
        nodePub := c.IdentityPub.SerializeCompressed()
×
185
        nodeChanBucket := openChanBucket.NestedReadWriteBucket(nodePub)
×
186
        if nodeChanBucket == nil {
×
187
                return nil, ErrNoActiveChannels
×
188
        }
×
189

190
        // We'll then recurse down an additional layer in order to fetch the
191
        // bucket for this particular chain.
192
        chainBucket := nodeChanBucket.NestedReadWriteBucket(c.ChainHash[:])
×
193
        if chainBucket == nil {
×
194
                return nil, ErrNoActiveChannels
×
195
        }
×
196

197
        // With the bucket for the node and chain fetched, we can now go down
198
        // another level, for this channel itself.
199
        var chanPointBuf bytes.Buffer
×
200
        err := mig.WriteOutpoint(&chanPointBuf, &c.FundingOutpoint)
×
201
        if err != nil {
×
202
                return nil, err
×
203
        }
×
204

205
        chanBucket := chainBucket.NestedReadWriteBucket(chanPointBuf.Bytes())
×
206
        if chanBucket == nil {
×
207
                return nil, ErrChannelNotFound
×
208
        }
×
209

210
        return chanBucket, nil
×
211
}
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