channeldb: BigSize migration, store zero-conf, scid-alias bits
This introduces a BigSize migration that is used to expand the width of the ChannelStatus and ChannelType fields. Three channel "types" are added - ZeroConfBit, ScidAliasChanBit, and ScidAliasFeatureBit. ScidAliasChanBit denotes that the scid-alias channel type was negotiated for the channel. ScidAliasFeatureBit denotes that the scid-alias feature bit was negotiated during the *lifetime* of the channel. Several helper functions on the OpenChannel struct are exposed to aid callers from different packages. The RefreshShortChanID has been renamed to Refresh. A new function BroadcastHeight is used to guard access to the mutable FundingBroadcastHeight member. This prevents data races.
This commit is contained in:
13 files changed
+503
-28
No files matched your search
@@ -0,0 +1,66 @@
|
||||
package migration29
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
var (
|
||||
byteOrder = binary.BigEndian
|
||||
)
|
||||
|
||||
// ChannelID is a series of 32-bytes that uniquely identifies all channels
|
||||
// within the network. The ChannelID is computed using the outpoint of the
|
||||
// funding transaction (the txid, and output index). Given a funding output the
|
||||
// ChannelID can be calculated by XOR'ing the big-endian serialization of the
|
||||
// txid and the big-endian serialization of the output index, truncated to
|
||||
// 2 bytes.
|
||||
type ChannelID [32]byte
|
||||
|
||||
// String returns the string representation of the ChannelID. This is just the
|
||||
// hex string encoding of the ChannelID itself.
|
||||
func (c ChannelID) String() string {
|
||||
return hex.EncodeToString(c[:])
|
||||
}
|
||||
|
||||
// NewChanIDFromOutPoint converts a target OutPoint into a ChannelID that is
|
||||
// usable within the network. In order to convert the OutPoint into a ChannelID,
|
||||
// we XOR the lower 2-bytes of the txid within the OutPoint with the big-endian
|
||||
// serialization of the Index of the OutPoint, truncated to 2-bytes.
|
||||
func NewChanIDFromOutPoint(op *wire.OutPoint) ChannelID {
|
||||
// First we'll copy the txid of the outpoint into our channel ID slice.
|
||||
var cid ChannelID
|
||||
copy(cid[:], op.Hash[:])
|
||||
|
||||
// With the txid copied over, we'll now XOR the lower 2-bytes of the
|
||||
// partial channelID with big-endian serialization of output index.
|
||||
xorTxid(&cid, uint16(op.Index))
|
||||
|
||||
return cid
|
||||
}
|
||||
|
||||
// xorTxid performs the transformation needed to transform an OutPoint into a
|
||||
// ChannelID. To do this, we expect the cid parameter to contain the txid
|
||||
// unaltered and the outputIndex to be the output index
|
||||
func xorTxid(cid *ChannelID, outputIndex uint16) {
|
||||
var buf [2]byte
|
||||
binary.BigEndian.PutUint16(buf[:], outputIndex)
|
||||
|
||||
cid[30] ^= buf[0]
|
||||
cid[31] ^= buf[1]
|
||||
}
|
||||
|
||||
// readOutpoint reads an outpoint from the passed reader.
|
||||
func readOutpoint(r io.Reader, o *wire.OutPoint) error {
|
||||
if _, err := io.ReadFull(r, o.Hash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(r, byteOrder, &o.Index); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package migration29
|
||||
|
||||
import "github.com/btcsuite/btclog"
|
||||
|
||||
// log is a logger that is initialized as disabled. This means the package will
|
||||
// not perform any logging by default until a logger is set.
|
||||
var log = btclog.Disabled
|
||||
|
||||
// UseLogger uses a specific Logger to output package logging info.
|
||||
func UseLogger(logger btclog.Logger) {
|
||||
log = logger
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package migration29
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
)
|
||||
|
||||
var (
|
||||
// outpointBucket is the bucket that stores the set of outpoints we
|
||||
// know about.
|
||||
outpointBucket = []byte("outpoint-bucket")
|
||||
|
||||
// chanIDBucket is the bucket that stores the set of ChannelID's we
|
||||
// know about.
|
||||
chanIDBucket = []byte("chan-id-bucket")
|
||||
)
|
||||
|
||||
// MigrateChanID populates the ChannelID index by using the set of outpoints
|
||||
// retrieved from the outpoint bucket.
|
||||
func MigrateChanID(tx kvdb.RwTx) error {
|
||||
log.Info("Populating ChannelID index")
|
||||
|
||||
// First we'll retrieve the set of outpoints we know about.
|
||||
ops, err := fetchOutPoints(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return populateChanIDIndex(tx, ops)
|
||||
}
|
||||
|
||||
// fetchOutPoints loops through the outpointBucket and returns each stored
|
||||
// outpoint.
|
||||
func fetchOutPoints(tx kvdb.RwTx) ([]*wire.OutPoint, error) {
|
||||
var ops []*wire.OutPoint
|
||||
|
||||
bucket := tx.ReadBucket(outpointBucket)
|
||||
|
||||
err := bucket.ForEach(func(k, _ []byte) error {
|
||||
var op wire.OutPoint
|
||||
r := bytes.NewReader(k)
|
||||
if err := readOutpoint(r, &op); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ops = append(ops, &op)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ops, nil
|
||||
}
|
||||
|
||||
// populateChanIDIndex uses the set of retrieved outpoints and populates the
|
||||
// ChannelID index.
|
||||
func populateChanIDIndex(tx kvdb.RwTx, ops []*wire.OutPoint) error {
|
||||
bucket := tx.ReadWriteBucket(chanIDBucket)
|
||||
|
||||
for _, op := range ops {
|
||||
chanID := NewChanIDFromOutPoint(op)
|
||||
|
||||
if err := bucket.Put(chanID[:], []byte{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package migration29
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb/migtest"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
)
|
||||
|
||||
var (
|
||||
hexStr = migtest.Hex
|
||||
|
||||
outpoint1 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec58ce90fb463ad")
|
||||
outpoint2 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec58ce952d6c6c7")
|
||||
|
||||
chanID1 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec5ef44")
|
||||
chanID2 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec54a2e")
|
||||
|
||||
// These tlv streams are used to populate the outpoint bucket at the
|
||||
// start of the test.
|
||||
tlvOutpointOpen = hexStr("000100")
|
||||
tlvOutpointClosed = hexStr("000101")
|
||||
|
||||
// outpointData is used to populate the outpoint bucket.
|
||||
outpointData = map[string]interface{}{
|
||||
outpoint1: tlvOutpointOpen,
|
||||
outpoint2: tlvOutpointClosed,
|
||||
}
|
||||
|
||||
// chanIDBefore is the ChannelID bucket before the migration.
|
||||
chanIDBefore = map[string]interface{}{}
|
||||
|
||||
// post is the expected data in the ChannelID bucket after the
|
||||
// migration.
|
||||
post = map[string]interface{}{
|
||||
chanID1: "",
|
||||
chanID2: "",
|
||||
}
|
||||
)
|
||||
|
||||
// TestMigrateChannelIDIndex asserts that the ChannelID index is properly
|
||||
// populated.
|
||||
func TestMigrateChannelIDIndex(t *testing.T) {
|
||||
// Prime the database with the populated outpoint bucket. We create the
|
||||
// ChannelID bucket since the prior migration creates it anyways.
|
||||
before := func(tx kvdb.RwTx) error {
|
||||
err := migtest.RestoreDB(tx, outpointBucket, outpointData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return migtest.RestoreDB(tx, chanIDBucket, chanIDBefore)
|
||||
}
|
||||
|
||||
// After the migration, ensure that the ChannelID bucket is properly
|
||||
// populated.
|
||||
after := func(tx kvdb.RwTx) error {
|
||||
err := migtest.VerifyDB(tx, outpointBucket, outpointData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return migtest.VerifyDB(tx, chanIDBucket, post)
|
||||
}
|
||||
|
||||
migtest.ApplyMigration(t, before, after, MigrateChanID, false)
|
||||
}
|
||||
Reference in new issue
Block a user