mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-05 20:43:06 +02:00
channeldb: switch to using a full public key to identity channel->node
This commit slightly modifies the existing structure of the channeldb scheme to replace the former concept of a “nodeID” with simply the compressed public key of the remote node. This change paves the way for adding useful indexes mapping a node to all it’s active channels and the other way around. Additionally, the current channeldb code was written before it was agreed by many of those implementing Lightning that a node’s ID will simply be its compressed public key.
This commit is contained in:
@@ -40,10 +40,12 @@ var (
|
|||||||
// channelLogBucket is dedicated for storing the necessary delta state
|
// channelLogBucket is dedicated for storing the necessary delta state
|
||||||
// between channel updates required to re-construct a past state in
|
// between channel updates required to re-construct a past state in
|
||||||
// order to punish a counter party attempting a non-cooperative channel
|
// order to punish a counter party attempting a non-cooperative channel
|
||||||
// closure.
|
// closure. A channel log bucket is created for each node and is nested
|
||||||
|
// within a node's ID bucket.
|
||||||
channelLogBucket = []byte("clb")
|
channelLogBucket = []byte("clb")
|
||||||
|
|
||||||
// identityKey is the key for storing this node's current LD identity key.
|
// identityKey is the key for storing this node's current LD identity
|
||||||
|
// key.
|
||||||
identityKey = []byte("idk")
|
identityKey = []byte("idk")
|
||||||
|
|
||||||
// The following prefixes are stored at the base level within the
|
// The following prefixes are stored at the base level within the
|
||||||
@@ -100,8 +102,9 @@ var (
|
|||||||
// to an on-disk log, which can then subsequently be queried in order to
|
// to an on-disk log, which can then subsequently be queried in order to
|
||||||
// "time-travel" to a prior state.
|
// "time-travel" to a prior state.
|
||||||
type OpenChannel struct {
|
type OpenChannel struct {
|
||||||
// Hash? or Their current pubKey?
|
// IdentityPub is the identity public key of the remote node this
|
||||||
TheirLNID [wire.HashSize]byte
|
// channel has been established with.
|
||||||
|
IdentityPub *btcec.PublicKey
|
||||||
|
|
||||||
// The ID of a channel is the txid of the funding transaction.
|
// The ID of a channel is the txid of the funding transaction.
|
||||||
ChanID *wire.OutPoint
|
ChanID *wire.OutPoint
|
||||||
@@ -181,7 +184,8 @@ func (c *OpenChannel) FullSync() error {
|
|||||||
|
|
||||||
// Within this top level bucket, fetch the bucket dedicated to storing
|
// Within this top level bucket, fetch the bucket dedicated to storing
|
||||||
// open channel data specific to the remote node.
|
// open channel data specific to the remote node.
|
||||||
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(c.TheirLNID[:])
|
nodePub := c.IdentityPub.SerializeCompressed()
|
||||||
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(nodePub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -222,7 +226,7 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *wire.MsgTx,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.TheirLNID[:]
|
id := c.IdentityPub.SerializeCompressed()
|
||||||
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -322,7 +326,7 @@ func (c *OpenChannel) AppendToRevocationLog(delta *ChannelDelta) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.TheirLNID[:]
|
id := c.IdentityPub.SerializeCompressed()
|
||||||
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -361,7 +365,8 @@ func (c *OpenChannel) FindPreviousState(updateNum uint64) (*ChannelDelta, error)
|
|||||||
err := c.Db.store.View(func(tx *bolt.Tx) error {
|
err := c.Db.store.View(func(tx *bolt.Tx) error {
|
||||||
chanBucket := tx.Bucket(openChannelBucket)
|
chanBucket := tx.Bucket(openChannelBucket)
|
||||||
|
|
||||||
nodeChanBucket := chanBucket.Bucket(c.TheirLNID[:])
|
nodePub := c.IdentityPub.SerializeCompressed()
|
||||||
|
nodeChanBucket := chanBucket.Bucket(nodePub)
|
||||||
if nodeChanBucket == nil {
|
if nodeChanBucket == nil {
|
||||||
return ErrNoActiveChannels
|
return ErrNoActiveChannels
|
||||||
}
|
}
|
||||||
@@ -400,7 +405,8 @@ func (c *OpenChannel) CloseChannel() error {
|
|||||||
|
|
||||||
// Within this top level bucket, fetch the bucket dedicated to storing
|
// Within this top level bucket, fetch the bucket dedicated to storing
|
||||||
// open channel data specific to the remote node.
|
// open channel data specific to the remote node.
|
||||||
nodeChanBucket := chanBucket.Bucket(c.TheirLNID[:])
|
nodePub := c.IdentityPub.SerializeCompressed()
|
||||||
|
nodeChanBucket := chanBucket.Bucket(nodePub)
|
||||||
if nodeChanBucket == nil {
|
if nodeChanBucket == nil {
|
||||||
return ErrNoActiveChannels
|
return ErrNoActiveChannels
|
||||||
}
|
}
|
||||||
@@ -436,7 +442,7 @@ func (c *OpenChannel) CloseChannel() error {
|
|||||||
// snapshot is detached from the original channel that generated it, providing
|
// snapshot is detached from the original channel that generated it, providing
|
||||||
// read-only access to the current or prior state of an active channel.
|
// read-only access to the current or prior state of an active channel.
|
||||||
type ChannelSnapshot struct {
|
type ChannelSnapshot struct {
|
||||||
RemoteID [wire.HashSize]byte
|
RemoteIdentity btcec.PublicKey
|
||||||
|
|
||||||
ChannelPoint *wire.OutPoint
|
ChannelPoint *wire.OutPoint
|
||||||
|
|
||||||
@@ -460,6 +466,7 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot {
|
|||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
|
|
||||||
snapshot := &ChannelSnapshot{
|
snapshot := &ChannelSnapshot{
|
||||||
|
RemoteIdentity: *c.IdentityPub,
|
||||||
ChannelPoint: c.ChanID,
|
ChannelPoint: c.ChanID,
|
||||||
Capacity: c.Capacity,
|
Capacity: c.Capacity,
|
||||||
LocalBalance: c.OurBalance,
|
LocalBalance: c.OurBalance,
|
||||||
@@ -468,7 +475,6 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot {
|
|||||||
TotalSatoshisSent: c.TotalSatoshisSent,
|
TotalSatoshisSent: c.TotalSatoshisSent,
|
||||||
TotalSatoshisReceived: c.TotalSatoshisReceived,
|
TotalSatoshisReceived: c.TotalSatoshisReceived,
|
||||||
}
|
}
|
||||||
copy(snapshot.RemoteID[:], c.TheirLNID[:])
|
|
||||||
|
|
||||||
// Copy over the current set of HTLC's to ensure the caller can't
|
// Copy over the current set of HTLC's to ensure the caller can't
|
||||||
// mutate our internal state.
|
// mutate our internal state.
|
||||||
@@ -907,7 +913,8 @@ func putChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|||||||
copy(idKey[:3], chanIDKey)
|
copy(idKey[:3], chanIDKey)
|
||||||
copy(idKey[3:], b.Bytes())
|
copy(idKey[3:], b.Bytes())
|
||||||
|
|
||||||
return nodeChanBucket.Put(idKey, channel.TheirLNID[:])
|
idBytes := channel.IdentityPub.SerializeCompressed()
|
||||||
|
return nodeChanBucket.Put(idKey, idBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteChannelIDs(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
func deleteChannelIDs(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
||||||
@@ -918,8 +925,12 @@ func deleteChannelIDs(nodeChanBucket *bolt.Bucket, chanID []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fetchChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
func fetchChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||||
var b bytes.Buffer
|
var (
|
||||||
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
err error
|
||||||
|
b bytes.Buffer
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = writeOutpoint(&b, channel.ChanID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,7 +940,10 @@ func fetchChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
|||||||
copy(idKey[3:], b.Bytes())
|
copy(idKey[3:], b.Bytes())
|
||||||
|
|
||||||
idBytes := nodeChanBucket.Get(idKey)
|
idBytes := nodeChanBucket.Get(idKey)
|
||||||
copy(channel.TheirLNID[:], idBytes)
|
channel.IdentityPub, err = btcec.ParsePubKey(idBytes, btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -133,7 +133,7 @@ func createTestChannelState(cdb *DB) (*OpenChannel, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &OpenChannel{
|
return &OpenChannel{
|
||||||
TheirLNID: key,
|
IdentityPub: pubKey,
|
||||||
ChanID: id,
|
ChanID: id,
|
||||||
MinFeePerKb: btcutil.Amount(5000),
|
MinFeePerKb: btcutil.Amount(5000),
|
||||||
OurCommitKey: privKey.PubKey(),
|
OurCommitKey: privKey.PubKey(),
|
||||||
@@ -190,8 +190,7 @@ func TestOpenChannelPutGetDelete(t *testing.T) {
|
|||||||
t.Fatalf("unable to save and serialize channel state: %v", err)
|
t.Fatalf("unable to save and serialize channel state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeID := wire.ShaHash(state.TheirLNID)
|
openChannels, err := cdb.FetchOpenChannels(state.IdentityPub)
|
||||||
openChannels, err := cdb.FetchOpenChannels(&nodeID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to fetch open channel: %v", err)
|
t.Fatalf("unable to fetch open channel: %v", err)
|
||||||
}
|
}
|
||||||
@@ -200,7 +199,7 @@ func TestOpenChannelPutGetDelete(t *testing.T) {
|
|||||||
|
|
||||||
// The decoded channel state should be identical to what we stored
|
// The decoded channel state should be identical to what we stored
|
||||||
// above.
|
// above.
|
||||||
if !bytes.Equal(state.TheirLNID[:], newState.TheirLNID[:]) {
|
if !state.IdentityPub.IsEqual(newState.IdentityPub) {
|
||||||
t.Fatalf("their id doesn't match")
|
t.Fatalf("their id doesn't match")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(state.ChanID, newState.ChanID) {
|
if !reflect.DeepEqual(state.ChanID, newState.ChanID) {
|
||||||
@@ -328,7 +327,7 @@ func TestOpenChannelPutGetDelete(t *testing.T) {
|
|||||||
|
|
||||||
// As the channel is now closed, attempting to fetch all open channels
|
// As the channel is now closed, attempting to fetch all open channels
|
||||||
// for our fake node ID should return an empty slice.
|
// for our fake node ID should return an empty slice.
|
||||||
openChans, err := cdb.FetchOpenChannels(&nodeID)
|
openChans, err := cdb.FetchOpenChannels(state.IdentityPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to fetch open channels: %v", err)
|
t.Fatalf("unable to fetch open channels: %v", err)
|
||||||
}
|
}
|
||||||
@@ -396,8 +395,7 @@ func TestChannelStateTransition(t *testing.T) {
|
|||||||
// The balances, new update, the HTLC's and the changes to the fake
|
// The balances, new update, the HTLC's and the changes to the fake
|
||||||
// commitment transaction along with the modified signature should all
|
// commitment transaction along with the modified signature should all
|
||||||
// have been updated.
|
// have been updated.
|
||||||
nodeID := wire.ShaHash(channel.TheirLNID)
|
updatedChannel, err := cdb.FetchOpenChannels(channel.IdentityPub)
|
||||||
updatedChannel, err := cdb.FetchOpenChannels(&nodeID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to fetch updated channel: %v", err)
|
t.Fatalf("unable to fetch updated channel: %v", err)
|
||||||
}
|
}
|
||||||
@@ -469,7 +467,7 @@ func TestChannelStateTransition(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The revocation state stored on-disk should now also be identical.
|
// The revocation state stored on-disk should now also be identical.
|
||||||
updatedChannel, err = cdb.FetchOpenChannels(&nodeID)
|
updatedChannel, err = cdb.FetchOpenChannels(channel.IdentityPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to fetch updated channel: %v", err)
|
t.Fatalf("unable to fetch updated channel: %v", err)
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/chaincfg"
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
)
|
)
|
||||||
@@ -143,7 +144,7 @@ func fileExists(path string) bool {
|
|||||||
// associated with the target nodeID. In the case that no active channels are
|
// associated with the target nodeID. In the case that no active channels are
|
||||||
// known to have been created with this node, then a zero-length slice is
|
// known to have been created with this node, then a zero-length slice is
|
||||||
// returned.
|
// returned.
|
||||||
func (d *DB) FetchOpenChannels(nodeID *wire.ShaHash) ([]*OpenChannel, error) {
|
func (d *DB) FetchOpenChannels(nodeID *btcec.PublicKey) ([]*OpenChannel, error) {
|
||||||
var channels []*OpenChannel
|
var channels []*OpenChannel
|
||||||
err := d.store.View(func(tx *bolt.Tx) error {
|
err := d.store.View(func(tx *bolt.Tx) error {
|
||||||
// Get the bucket dedicated to storing the meta-data for open
|
// Get the bucket dedicated to storing the meta-data for open
|
||||||
@@ -155,7 +156,8 @@ func (d *DB) FetchOpenChannels(nodeID *wire.ShaHash) ([]*OpenChannel, error) {
|
|||||||
|
|
||||||
// Within this top level bucket, fetch the bucket dedicated to storing
|
// Within this top level bucket, fetch the bucket dedicated to storing
|
||||||
// open channel data specific to the remote node.
|
// open channel data specific to the remote node.
|
||||||
nodeChanBucket := openChanBucket.Bucket(nodeID[:])
|
pub := nodeID.SerializeCompressed()
|
||||||
|
nodeChanBucket := openChanBucket.Bucket(pub)
|
||||||
if nodeChanBucket == nil {
|
if nodeChanBucket == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user