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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

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

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

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

12
var (
13
        // historicalChannelBucket stores all channels that have seen their
14
        // commitment tx confirm. All information from their previous open state
15
        // is retained.
16
        historicalChannelBucket = []byte("historical-chan-bucket")
17
)
18

19
// MigrateHistoricalBalances patches the two new fields, `InitialLocalBalance`
20
// and `InitialRemoteBalance`, for all the open channels saved in historical
21
// channel bucket. Unlike migration 25, it will only read the old channel info
22
// first and then patch the new tlv records with empty values. For historical
23
// channels, we previously didn't save the initial balances anywhere and since
24
// it's corresponding open channel bucket is deleted after closure, we have
25
// lost that balance info.
UNCOV
26
func MigrateHistoricalBalances(tx kvdb.RwTx) error {
×
UNCOV
27
        log.Infof("Migrating historical local and remote balances...")
×
UNCOV
28

×
UNCOV
29
        // First fetch the top level bucket which stores all data related to
×
UNCOV
30
        // historically stored channels.
×
UNCOV
31
        rootBucket := tx.ReadWriteBucket(historicalChannelBucket)
×
UNCOV
32

×
UNCOV
33
        // If no bucket is found, we can exit early.
×
UNCOV
34
        if rootBucket == nil {
×
35
                return nil
×
36
        }
×
37

38
        // Read a list of historical channels.
UNCOV
39
        channels, err := findHistoricalChannels(rootBucket)
×
UNCOV
40
        if err != nil {
×
41
                return err
×
42
        }
×
43

44
        // Migrate the balances.
UNCOV
45
        for _, c := range channels {
×
UNCOV
46
                if err := migrateBalances(rootBucket, c); err != nil {
×
47
                        return err
×
48
                }
×
49
        }
50

UNCOV
51
        return err
×
52
}
53

54
// findHistoricalChannels finds all historical channels.
55
func findHistoricalChannels(historicalBucket kvdb.RBucket) ([]*OpenChannel,
UNCOV
56
        error) {
×
UNCOV
57

×
UNCOV
58
        channels := []*OpenChannel{}
×
UNCOV
59

×
UNCOV
60
        // readChannel is a helper closure that reads the channel info from the
×
UNCOV
61
        // historical sub-bucket.
×
UNCOV
62
        readChannel := func(rootBucket kvdb.RBucket, cp []byte) error {
×
UNCOV
63
                c := &OpenChannel{}
×
UNCOV
64

×
UNCOV
65
                chanPointBuf := bytes.NewBuffer(cp)
×
UNCOV
66
                err := mig.ReadOutpoint(chanPointBuf, &c.FundingOutpoint)
×
UNCOV
67
                if err != nil {
×
68
                        return fmt.Errorf("read funding outpoint got: %w", err)
×
69
                }
×
70

71
                // Read the sub-bucket.
UNCOV
72
                chanBucket := rootBucket.NestedReadBucket(cp)
×
UNCOV
73
                if chanBucket == nil {
×
74
                        log.Errorf("unable to read bucket for chanPoint=%s",
×
75
                                c.FundingOutpoint)
×
76
                        return nil
×
77
                }
×
78

79
                // Try to fetch channel info in old format.
UNCOV
80
                err = fetchChanInfoCompatible(chanBucket, c, true)
×
UNCOV
81
                if err != nil {
×
82
                        return fmt.Errorf("%s: fetch chan info got: %w",
×
83
                                c.FundingOutpoint, err)
×
84
                }
×
85

UNCOV
86
                channels = append(channels, c)
×
UNCOV
87

×
UNCOV
88
                return nil
×
89
        }
90

91
        // Iterate the root bucket.
UNCOV
92
        err := historicalBucket.ForEach(func(cp, _ []byte) error {
×
UNCOV
93
                return readChannel(historicalBucket, cp)
×
UNCOV
94
        })
×
95

UNCOV
96
        if err != nil {
×
97
                return nil, err
×
98
        }
×
99

UNCOV
100
        return channels, nil
×
101
}
102

103
// fetchChanInfoCompatible tries to fetch the channel info for a historical
104
// channel. It will first fetch the info assuming `InitialLocalBalance` and
105
// `InitialRemoteBalance` are not serialized. Upon receiving an error, it will
106
// then fetch it again assuming the two fields are present in db.
107
func fetchChanInfoCompatible(chanBucket kvdb.RBucket, c *OpenChannel,
UNCOV
108
        legacy bool) error {
×
UNCOV
109

×
UNCOV
110
        // Try to fetch the channel info assuming the historical channel in in
×
UNCOV
111
        // the old format, where the two fields, `InitialLocalBalance` and
×
UNCOV
112
        // `InitialRemoteBalance` are not saved to db.
×
UNCOV
113
        err := FetchChanInfo(chanBucket, c, legacy)
×
UNCOV
114
        if err == nil {
×
UNCOV
115
                return err
×
UNCOV
116
        }
×
117

118
        // If we got an error above, the historical channel may already have
119
        // the new fields saved. This could happen when a channel is closed
120
        // after applying migration 25. In this case, we'll borrow the
121
        // `FetchChanInfo` info method from migration 26 where we assume the
122
        // two fields are saved.
UNCOV
123
        return mig26.FetchChanInfo(chanBucket, &c.OpenChannel, legacy)
×
124
}
125

126
// migrateBalances serializes the channel info using the new tlv format where
127
// the two fields, `InitialLocalBalance` and `InitialRemoteBalance` are patched
128
// with empty values.
UNCOV
129
func migrateBalances(rootBucket kvdb.RwBucket, c *OpenChannel) error {
×
UNCOV
130
        var chanPointBuf bytes.Buffer
×
UNCOV
131
        err := mig.WriteOutpoint(&chanPointBuf, &c.FundingOutpoint)
×
UNCOV
132
        if err != nil {
×
133
                return err
×
134
        }
×
135

136
        // Get the channel bucket.
UNCOV
137
        chanBucket := rootBucket.NestedReadWriteBucket(chanPointBuf.Bytes())
×
UNCOV
138
        if chanBucket == nil {
×
139
                return fmt.Errorf("empty historical chan bucket")
×
140
        }
×
141

142
        // Update the channel info.
UNCOV
143
        if err := PutChanInfo(chanBucket, c, false); err != nil {
×
144
                return fmt.Errorf("unable to put chan info: %w", err)
×
145
        }
×
146

UNCOV
147
        return nil
×
148
}
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