mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-19 05:45:21 +01:00
cd566eb097
Refactor fmt.Errorf usage to correctly wrap errors instead of using non-wrapping format verbs.
230 lines
6.9 KiB
Go
230 lines
6.9 KiB
Go
package migration27
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
|
mig25 "github.com/lightningnetwork/lnd/channeldb/migration25"
|
|
mig26 "github.com/lightningnetwork/lnd/channeldb/migration26"
|
|
mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
|
|
"github.com/lightningnetwork/lnd/kvdb"
|
|
"github.com/lightningnetwork/lnd/tlv"
|
|
)
|
|
|
|
const (
|
|
// A tlv type definition used to serialize and deserialize a KeyLocator
|
|
// from the database.
|
|
keyLocType tlv.Type = 1
|
|
|
|
// A tlv type used to serialize and deserialize the
|
|
// `InitialLocalBalance` field.
|
|
initialLocalBalanceType tlv.Type = 2
|
|
|
|
// A tlv type used to serialize and deserialize the
|
|
// `InitialRemoteBalance` field.
|
|
initialRemoteBalanceType tlv.Type = 3
|
|
)
|
|
|
|
var (
|
|
// chanInfoKey can be accessed within the bucket for a channel
|
|
// (identified by its chanPoint). This key stores all the static
|
|
// information for a channel which is decided at the end of the
|
|
// funding flow.
|
|
chanInfoKey = []byte("chan-info-key")
|
|
|
|
// localUpfrontShutdownKey can be accessed within the bucket for a
|
|
// channel (identified by its chanPoint). This key stores an optional
|
|
// upfront shutdown script for the local peer.
|
|
localUpfrontShutdownKey = []byte("local-upfront-shutdown-key")
|
|
|
|
// remoteUpfrontShutdownKey can be accessed within the bucket for a
|
|
// channel (identified by its chanPoint). This key stores an optional
|
|
// upfront shutdown script for the remote peer.
|
|
remoteUpfrontShutdownKey = []byte("remote-upfront-shutdown-key")
|
|
|
|
// lastWasRevokeKey is a key that stores true when the last update we
|
|
// sent was a revocation and false when it was a commitment signature.
|
|
// This is nil in the case of new channels with no updates exchanged.
|
|
lastWasRevokeKey = []byte("last-was-revoke")
|
|
|
|
// ErrNoChanInfoFound is returned when a particular channel does not
|
|
// have any channels state.
|
|
ErrNoChanInfoFound = fmt.Errorf("no chan info found")
|
|
)
|
|
|
|
// OpenChannel embeds a mig26.OpenChannel with the extra update-to-date
|
|
// serialization and deserialization methods.
|
|
//
|
|
// NOTE: doesn't have the Packager field as it's not used in current migration.
|
|
type OpenChannel struct {
|
|
mig26.OpenChannel
|
|
}
|
|
|
|
// FetchChanInfo deserializes the channel info based on the legacy boolean.
|
|
func FetchChanInfo(chanBucket kvdb.RBucket, c *OpenChannel, legacy bool) error {
|
|
infoBytes := chanBucket.Get(chanInfoKey)
|
|
if infoBytes == nil {
|
|
return ErrNoChanInfoFound
|
|
}
|
|
r := bytes.NewReader(infoBytes)
|
|
|
|
var (
|
|
chanType mig.ChannelType
|
|
chanStatus mig.ChannelStatus
|
|
)
|
|
|
|
if err := mig.ReadElements(r,
|
|
&chanType, &c.ChainHash, &c.FundingOutpoint,
|
|
&c.ShortChannelID, &c.IsPending, &c.IsInitiator,
|
|
&chanStatus, &c.FundingBroadcastHeight,
|
|
&c.NumConfsRequired, &c.ChannelFlags,
|
|
&c.IdentityPub, &c.Capacity, &c.TotalMSatSent,
|
|
&c.TotalMSatReceived,
|
|
); err != nil {
|
|
return fmt.Errorf("ReadElements got: %w", err)
|
|
}
|
|
|
|
c.ChanType = mig25.ChannelType(chanType)
|
|
c.ChanStatus = mig25.ChannelStatus(chanStatus)
|
|
|
|
// For single funder channels that we initiated and have the funding
|
|
// transaction to, read the funding txn.
|
|
if c.FundingTxPresent() {
|
|
if err := mig.ReadElement(r, &c.FundingTxn); err != nil {
|
|
return fmt.Errorf("read FundingTxn got: %w", err)
|
|
}
|
|
}
|
|
|
|
if err := mig.ReadChanConfig(r, &c.LocalChanCfg); err != nil {
|
|
return fmt.Errorf("read LocalChanCfg got: %w", err)
|
|
}
|
|
if err := mig.ReadChanConfig(r, &c.RemoteChanCfg); err != nil {
|
|
return fmt.Errorf("read RemoteChanCfg got: %w", err)
|
|
}
|
|
|
|
// Retrieve the boolean stored under lastWasRevokeKey.
|
|
lastWasRevokeBytes := chanBucket.Get(lastWasRevokeKey)
|
|
if lastWasRevokeBytes == nil {
|
|
// If nothing has been stored under this key, we store false in
|
|
// the OpenChannel struct.
|
|
c.LastWasRevoke = false
|
|
} else {
|
|
// Otherwise, read the value into the LastWasRevoke field.
|
|
revokeReader := bytes.NewReader(lastWasRevokeBytes)
|
|
err := mig.ReadElements(revokeReader, &c.LastWasRevoke)
|
|
if err != nil {
|
|
return fmt.Errorf("read LastWasRevoke got: %w", err)
|
|
}
|
|
}
|
|
|
|
// Make the tlv stream based on the legacy param.
|
|
var (
|
|
ts *tlv.Stream
|
|
err error
|
|
localBalance uint64
|
|
remoteBalance uint64
|
|
)
|
|
|
|
keyLocRecord := mig25.MakeKeyLocRecord(
|
|
keyLocType, &c.RevocationKeyLocator,
|
|
)
|
|
|
|
// If it's legacy, create the stream with a single tlv record.
|
|
if legacy {
|
|
ts, err = tlv.NewStream(keyLocRecord)
|
|
} else {
|
|
// Otherwise, for the new format, we will encode the balance
|
|
// fields in the tlv stream too.
|
|
ts, err = tlv.NewStream(
|
|
keyLocRecord,
|
|
tlv.MakePrimitiveRecord(
|
|
initialLocalBalanceType, &localBalance,
|
|
),
|
|
tlv.MakePrimitiveRecord(
|
|
initialRemoteBalanceType, &remoteBalance,
|
|
),
|
|
)
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("create tlv stream got: %w", err)
|
|
}
|
|
|
|
if err := ts.Decode(r); err != nil {
|
|
return fmt.Errorf("decode tlv stream got: %w", err)
|
|
}
|
|
|
|
// For the new format, attach the balance fields.
|
|
if !legacy {
|
|
c.InitialLocalBalance = lnwire.MilliSatoshi(localBalance)
|
|
c.InitialRemoteBalance = lnwire.MilliSatoshi(remoteBalance)
|
|
}
|
|
|
|
// Finally, read the optional shutdown scripts.
|
|
if err := mig25.GetOptionalUpfrontShutdownScript(
|
|
chanBucket, localUpfrontShutdownKey, &c.LocalShutdownScript,
|
|
); err != nil {
|
|
return fmt.Errorf("local shutdown script got: %w", err)
|
|
}
|
|
|
|
return mig25.GetOptionalUpfrontShutdownScript(
|
|
chanBucket, remoteUpfrontShutdownKey, &c.RemoteShutdownScript,
|
|
)
|
|
}
|
|
|
|
// PutChanInfo serializes the channel info based on the legacy boolean.
|
|
func PutChanInfo(chanBucket kvdb.RwBucket, c *OpenChannel, legacy bool) error {
|
|
var w bytes.Buffer
|
|
if err := mig.WriteElements(&w,
|
|
mig.ChannelType(c.ChanType), c.ChainHash, c.FundingOutpoint,
|
|
c.ShortChannelID, c.IsPending, c.IsInitiator,
|
|
mig.ChannelStatus(c.ChanStatus), c.FundingBroadcastHeight,
|
|
c.NumConfsRequired, c.ChannelFlags,
|
|
c.IdentityPub, c.Capacity, c.TotalMSatSent,
|
|
c.TotalMSatReceived,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
// For single funder channels that we initiated, and we have the
|
|
// funding transaction, then write the funding txn.
|
|
if c.FundingTxPresent() {
|
|
if err := mig.WriteElement(&w, c.FundingTxn); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := mig.WriteChanConfig(&w, &c.LocalChanCfg); err != nil {
|
|
return err
|
|
}
|
|
if err := mig.WriteChanConfig(&w, &c.RemoteChanCfg); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Make the tlv stream based on the legacy param.
|
|
tlvStream, err := mig26.MakeTlvStream(&c.OpenChannel, legacy)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tlvStream.Encode(&w); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := chanBucket.Put(chanInfoKey, w.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Finally, add optional shutdown scripts for the local and remote peer
|
|
// if they are present.
|
|
if err := mig25.PutOptionalUpfrontShutdownScript(
|
|
chanBucket, localUpfrontShutdownKey, c.LocalShutdownScript,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
return mig25.PutOptionalUpfrontShutdownScript(
|
|
chanBucket, remoteUpfrontShutdownKey, c.RemoteShutdownScript,
|
|
)
|
|
}
|