Skip to content

Commit 3458b2e

Browse files
committed
channeldb+migration27: patch balance fields for historical chan
This commit adds a new migration to patch the two balance fields, `InitialLocalBalance` and `InitialRemoteBalance` for the historical channels. Because they are not saved previously, for historical channels prior to the revocation log PR, these fields will be empty.
1 parent 55746e4 commit 3458b2e

File tree

5 files changed

+606
-0
lines changed

5 files changed

+606
-0
lines changed

channeldb/db.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/lightningnetwork/lnd/channeldb/migration24"
2222
"github.com/lightningnetwork/lnd/channeldb/migration25"
2323
"github.com/lightningnetwork/lnd/channeldb/migration26"
24+
"github.com/lightningnetwork/lnd/channeldb/migration27"
2425
"github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
2526
"github.com/lightningnetwork/lnd/clock"
2627
"github.com/lightningnetwork/lnd/kvdb"
@@ -219,6 +220,12 @@ var (
219220
number: 26,
220221
migration: migration26.MigrateBalancesToTlvRecords,
221222
},
223+
{
224+
// Patch the initial local/remote balance fields with
225+
// empty values for historical channels.
226+
number: 27,
227+
migration: migration27.MigrateHistoricalBalances,
228+
},
222229
}
223230

224231
// Big endian is the preferred byte order, due to cursor scans over

channeldb/migration27/channel.go

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
package migration27
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
7+
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
8+
mig25 "github.com/lightningnetwork/lnd/channeldb/migration25"
9+
mig26 "github.com/lightningnetwork/lnd/channeldb/migration26"
10+
mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
11+
"github.com/lightningnetwork/lnd/kvdb"
12+
"github.com/lightningnetwork/lnd/tlv"
13+
)
14+
15+
const (
16+
// A tlv type definition used to serialize and deserialize a KeyLocator
17+
// from the database.
18+
keyLocType tlv.Type = 1
19+
20+
// A tlv type used to serialize and deserialize the
21+
// `InitialLocalBalance` field.
22+
initialLocalBalanceType tlv.Type = 2
23+
24+
// A tlv type used to serialize and deserialize the
25+
// `InitialRemoteBalance` field.
26+
initialRemoteBalanceType tlv.Type = 3
27+
)
28+
29+
var (
30+
// chanInfoKey can be accessed within the bucket for a channel
31+
// (identified by its chanPoint). This key stores all the static
32+
// information for a channel which is decided at the end of the
33+
// funding flow.
34+
chanInfoKey = []byte("chan-info-key")
35+
36+
// localUpfrontShutdownKey can be accessed within the bucket for a
37+
// channel (identified by its chanPoint). This key stores an optional
38+
// upfront shutdown script for the local peer.
39+
localUpfrontShutdownKey = []byte("local-upfront-shutdown-key")
40+
41+
// remoteUpfrontShutdownKey can be accessed within the bucket for a
42+
// channel (identified by its chanPoint). This key stores an optional
43+
// upfront shutdown script for the remote peer.
44+
remoteUpfrontShutdownKey = []byte("remote-upfront-shutdown-key")
45+
46+
// lastWasRevokeKey is a key that stores true when the last update we
47+
// sent was a revocation and false when it was a commitment signature.
48+
// This is nil in the case of new channels with no updates exchanged.
49+
lastWasRevokeKey = []byte("last-was-revoke")
50+
51+
// ErrNoChanInfoFound is returned when a particular channel does not
52+
// have any channels state.
53+
ErrNoChanInfoFound = fmt.Errorf("no chan info found")
54+
)
55+
56+
// OpenChannel embeds a mig26.OpenChannel with the extra update-to-date
57+
// serialization and deserialization methods.
58+
//
59+
// NOTE: doesn't have the Packager field as it's not used in current migration.
60+
type OpenChannel struct {
61+
mig26.OpenChannel
62+
63+
// chanStatus is the current status of this channel. If it is not in
64+
// the state Default, it should not be used for forwarding payments.
65+
chanStatus mig25.ChannelStatus
66+
}
67+
68+
// FetchChanInfo deserializes the channel info based on the legacy boolean.
69+
func FetchChanInfo(chanBucket kvdb.RBucket, c *OpenChannel, legacy bool) error {
70+
infoBytes := chanBucket.Get(chanInfoKey)
71+
if infoBytes == nil {
72+
return ErrNoChanInfoFound
73+
}
74+
r := bytes.NewReader(infoBytes)
75+
76+
var (
77+
chanType mig.ChannelType
78+
chanStatus mig.ChannelStatus
79+
)
80+
81+
if err := mig.ReadElements(r,
82+
&chanType, &c.ChainHash, &c.FundingOutpoint,
83+
&c.ShortChannelID, &c.IsPending, &c.IsInitiator,
84+
&chanStatus, &c.FundingBroadcastHeight,
85+
&c.NumConfsRequired, &c.ChannelFlags,
86+
&c.IdentityPub, &c.Capacity, &c.TotalMSatSent,
87+
&c.TotalMSatReceived,
88+
); err != nil {
89+
return fmt.Errorf("ReadElements got: %v", err)
90+
}
91+
92+
c.ChanType = mig25.ChannelType(chanType)
93+
c.chanStatus = mig25.ChannelStatus(chanStatus)
94+
95+
// For single funder channels that we initiated and have the funding
96+
// transaction to, read the funding txn.
97+
if c.FundingTxPresent() {
98+
if err := mig.ReadElement(r, &c.FundingTxn); err != nil {
99+
return fmt.Errorf("read FundingTxn got: %v", err)
100+
}
101+
}
102+
103+
if err := mig.ReadChanConfig(r, &c.LocalChanCfg); err != nil {
104+
return fmt.Errorf("read LocalChanCfg got: %v", err)
105+
}
106+
if err := mig.ReadChanConfig(r, &c.RemoteChanCfg); err != nil {
107+
return fmt.Errorf("read RemoteChanCfg got: %v", err)
108+
}
109+
110+
// Retrieve the boolean stored under lastWasRevokeKey.
111+
lastWasRevokeBytes := chanBucket.Get(lastWasRevokeKey)
112+
if lastWasRevokeBytes == nil {
113+
// If nothing has been stored under this key, we store false in
114+
// the OpenChannel struct.
115+
c.LastWasRevoke = false
116+
} else {
117+
// Otherwise, read the value into the LastWasRevoke field.
118+
revokeReader := bytes.NewReader(lastWasRevokeBytes)
119+
err := mig.ReadElements(revokeReader, &c.LastWasRevoke)
120+
if err != nil {
121+
return fmt.Errorf("read LastWasRevoke got: %v", err)
122+
}
123+
}
124+
125+
// Make the tlv stream based on the legacy param.
126+
var (
127+
ts *tlv.Stream
128+
err error
129+
localBalance uint64
130+
remoteBalance uint64
131+
)
132+
133+
keyLocRecord := mig25.MakeKeyLocRecord(
134+
keyLocType, &c.RevocationKeyLocator,
135+
)
136+
137+
// If it's legacy, create the stream with a single tlv record.
138+
if legacy {
139+
ts, err = tlv.NewStream(keyLocRecord)
140+
} else {
141+
// Otherwise, for the new format, we will encode the balance
142+
// fields in the tlv stream too.
143+
ts, err = tlv.NewStream(
144+
keyLocRecord,
145+
tlv.MakePrimitiveRecord(
146+
initialLocalBalanceType, &localBalance,
147+
),
148+
tlv.MakePrimitiveRecord(
149+
initialRemoteBalanceType, &remoteBalance,
150+
),
151+
)
152+
}
153+
if err != nil {
154+
return fmt.Errorf("create tlv stream got: %v", err)
155+
}
156+
157+
if err := ts.Decode(r); err != nil {
158+
return fmt.Errorf("decode tlv stream got: %v", err)
159+
}
160+
161+
// For the new format, attach the balance fields.
162+
if !legacy {
163+
c.InitialLocalBalance = lnwire.MilliSatoshi(localBalance)
164+
c.InitialRemoteBalance = lnwire.MilliSatoshi(remoteBalance)
165+
}
166+
167+
// Finally, read the optional shutdown scripts.
168+
if err := mig25.GetOptionalUpfrontShutdownScript(
169+
chanBucket, localUpfrontShutdownKey, &c.LocalShutdownScript,
170+
); err != nil {
171+
return fmt.Errorf("local shutdown script got: %v", err)
172+
}
173+
174+
return mig25.GetOptionalUpfrontShutdownScript(
175+
chanBucket, remoteUpfrontShutdownKey, &c.RemoteShutdownScript,
176+
)
177+
}
178+
179+
// PutChanInfo serializes the channel info based on the legacy boolean.
180+
func PutChanInfo(chanBucket kvdb.RwBucket, c *OpenChannel, legacy bool) error {
181+
var w bytes.Buffer
182+
if err := mig.WriteElements(&w,
183+
mig.ChannelType(c.ChanType), c.ChainHash, c.FundingOutpoint,
184+
c.ShortChannelID, c.IsPending, c.IsInitiator,
185+
mig.ChannelStatus(c.chanStatus), c.FundingBroadcastHeight,
186+
c.NumConfsRequired, c.ChannelFlags,
187+
c.IdentityPub, c.Capacity, c.TotalMSatSent,
188+
c.TotalMSatReceived,
189+
); err != nil {
190+
return err
191+
}
192+
193+
// For single funder channels that we initiated, and we have the
194+
// funding transaction, then write the funding txn.
195+
if c.FundingTxPresent() {
196+
if err := mig.WriteElement(&w, c.FundingTxn); err != nil {
197+
return err
198+
}
199+
}
200+
201+
if err := mig.WriteChanConfig(&w, &c.LocalChanCfg); err != nil {
202+
return err
203+
}
204+
if err := mig.WriteChanConfig(&w, &c.RemoteChanCfg); err != nil {
205+
return err
206+
}
207+
208+
// Make the tlv stream based on the legacy param.
209+
tlvStream, err := mig26.MakeTlvStream(&c.OpenChannel, legacy)
210+
if err != nil {
211+
return err
212+
}
213+
214+
if err := tlvStream.Encode(&w); err != nil {
215+
return err
216+
}
217+
218+
if err := chanBucket.Put(chanInfoKey, w.Bytes()); err != nil {
219+
return err
220+
}
221+
222+
// Finally, add optional shutdown scripts for the local and remote peer
223+
// if they are present.
224+
if err := mig25.PutOptionalUpfrontShutdownScript(
225+
chanBucket, localUpfrontShutdownKey, c.LocalShutdownScript,
226+
); err != nil {
227+
return err
228+
}
229+
230+
return mig25.PutOptionalUpfrontShutdownScript(
231+
chanBucket, remoteUpfrontShutdownKey, c.RemoteShutdownScript,
232+
)
233+
}

channeldb/migration27/log.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package migration27
2+
3+
import (
4+
"github.com/btcsuite/btclog"
5+
)
6+
7+
// log is a logger that is initialized as disabled. This means the package will
8+
// not perform any logging by default until a logger is set.
9+
var log = btclog.Disabled
10+
11+
// UseLogger uses a specified Logger to output package logging info.
12+
func UseLogger(logger btclog.Logger) {
13+
log = logger
14+
}

0 commit comments

Comments
 (0)