From cb328e65c498ac16bcaf39e2f3226a3cbc1c5cd6 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 25 Oct 2016 16:11:23 -0700 Subject: [PATCH] channeldb: switch to using a full public key to identity channel->node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- channeldb/channel.go | 48 +++++++++++++++++++++++++-------------- channeldb/channel_test.go | 16 ++++++------- channeldb/db.go | 6 +++-- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/channeldb/channel.go b/channeldb/channel.go index 0796c868..148e4f0c 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -40,10 +40,12 @@ var ( // channelLogBucket is dedicated for storing the necessary delta state // between channel updates required to re-construct a past state in // 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") - // 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") // 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 // "time-travel" to a prior state. type OpenChannel struct { - // Hash? or Their current pubKey? - TheirLNID [wire.HashSize]byte + // IdentityPub is the identity public key of the remote node this + // channel has been established with. + IdentityPub *btcec.PublicKey // The ID of a channel is the txid of the funding transaction. ChanID *wire.OutPoint @@ -125,8 +128,8 @@ type OpenChannel struct { // The outpoint of the final funding transaction. FundingOutpoint *wire.OutPoint - OurMultiSigKey *btcec.PublicKey - TheirMultiSigKey *btcec.PublicKey + OurMultiSigKey *btcec.PublicKey + TheirMultiSigKey *btcec.PublicKey FundingWitnessScript []byte // In blocks @@ -181,7 +184,8 @@ func (c *OpenChannel) FullSync() error { // Within this top level bucket, fetch the bucket dedicated to storing // 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 { return err } @@ -222,7 +226,7 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *wire.MsgTx, return err } - id := c.TheirLNID[:] + id := c.IdentityPub.SerializeCompressed() nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id) if err != nil { return err @@ -322,7 +326,7 @@ func (c *OpenChannel) AppendToRevocationLog(delta *ChannelDelta) error { return err } - id := c.TheirLNID[:] + id := c.IdentityPub.SerializeCompressed() nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id) if err != nil { return err @@ -361,7 +365,8 @@ func (c *OpenChannel) FindPreviousState(updateNum uint64) (*ChannelDelta, error) err := c.Db.store.View(func(tx *bolt.Tx) error { chanBucket := tx.Bucket(openChannelBucket) - nodeChanBucket := chanBucket.Bucket(c.TheirLNID[:]) + nodePub := c.IdentityPub.SerializeCompressed() + nodeChanBucket := chanBucket.Bucket(nodePub) if nodeChanBucket == nil { return ErrNoActiveChannels } @@ -400,7 +405,8 @@ func (c *OpenChannel) CloseChannel() error { // Within this top level bucket, fetch the bucket dedicated to storing // open channel data specific to the remote node. - nodeChanBucket := chanBucket.Bucket(c.TheirLNID[:]) + nodePub := c.IdentityPub.SerializeCompressed() + nodeChanBucket := chanBucket.Bucket(nodePub) if nodeChanBucket == nil { return ErrNoActiveChannels } @@ -436,7 +442,7 @@ func (c *OpenChannel) CloseChannel() error { // snapshot is detached from the original channel that generated it, providing // read-only access to the current or prior state of an active channel. type ChannelSnapshot struct { - RemoteID [wire.HashSize]byte + RemoteIdentity btcec.PublicKey ChannelPoint *wire.OutPoint @@ -460,6 +466,7 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot { defer c.RUnlock() snapshot := &ChannelSnapshot{ + RemoteIdentity: *c.IdentityPub, ChannelPoint: c.ChanID, Capacity: c.Capacity, LocalBalance: c.OurBalance, @@ -468,7 +475,6 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot { TotalSatoshisSent: c.TotalSatoshisSent, TotalSatoshisReceived: c.TotalSatoshisReceived, } - copy(snapshot.RemoteID[:], c.TheirLNID[:]) // Copy over the current set of HTLC's to ensure the caller can't // mutate our internal state. @@ -907,7 +913,8 @@ func putChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { copy(idKey[:3], chanIDKey) 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 { @@ -918,8 +925,12 @@ func deleteChannelIDs(nodeChanBucket *bolt.Bucket, chanID []byte) error { } func fetchChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { - var b bytes.Buffer - if err := writeOutpoint(&b, channel.ChanID); err != nil { + var ( + err error + b bytes.Buffer + ) + + if err = writeOutpoint(&b, channel.ChanID); err != nil { return err } @@ -929,7 +940,10 @@ func fetchChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { copy(idKey[3:], b.Bytes()) idBytes := nodeChanBucket.Get(idKey) - copy(channel.TheirLNID[:], idBytes) + channel.IdentityPub, err = btcec.ParsePubKey(idBytes, btcec.S256()) + if err != nil { + return err + } return nil } diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index dc4b94b0..4845de06 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -133,7 +133,7 @@ func createTestChannelState(cdb *DB) (*OpenChannel, error) { } return &OpenChannel{ - TheirLNID: key, + IdentityPub: pubKey, ChanID: id, MinFeePerKb: btcutil.Amount(5000), OurCommitKey: privKey.PubKey(), @@ -148,7 +148,7 @@ func createTestChannelState(cdb *DB) (*OpenChannel, error) { FundingOutpoint: testOutpoint, OurMultiSigKey: privKey.PubKey(), TheirMultiSigKey: privKey.PubKey(), - FundingWitnessScript: script, + FundingWitnessScript: script, TheirCurrentRevocation: privKey.PubKey(), TheirCurrentRevocationHash: key, OurDeliveryScript: script, @@ -190,8 +190,7 @@ func TestOpenChannelPutGetDelete(t *testing.T) { t.Fatalf("unable to save and serialize channel state: %v", err) } - nodeID := wire.ShaHash(state.TheirLNID) - openChannels, err := cdb.FetchOpenChannels(&nodeID) + openChannels, err := cdb.FetchOpenChannels(state.IdentityPub) if err != nil { 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 // above. - if !bytes.Equal(state.TheirLNID[:], newState.TheirLNID[:]) { + if !state.IdentityPub.IsEqual(newState.IdentityPub) { t.Fatalf("their id doesn't match") } 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 // for our fake node ID should return an empty slice. - openChans, err := cdb.FetchOpenChannels(&nodeID) + openChans, err := cdb.FetchOpenChannels(state.IdentityPub) if err != nil { 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 // commitment transaction along with the modified signature should all // have been updated. - nodeID := wire.ShaHash(channel.TheirLNID) - updatedChannel, err := cdb.FetchOpenChannels(&nodeID) + updatedChannel, err := cdb.FetchOpenChannels(channel.IdentityPub) if err != nil { 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. - updatedChannel, err = cdb.FetchOpenChannels(&nodeID) + updatedChannel, err = cdb.FetchOpenChannels(channel.IdentityPub) if err != nil { t.Fatalf("unable to fetch updated channel: %v", err) } diff --git a/channeldb/db.go b/channeldb/db.go index 38bad1fd..0b0c2af8 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -9,6 +9,7 @@ import ( "sync" "github.com/boltdb/bolt" + "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/chaincfg" "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 // known to have been created with this node, then a zero-length slice is // returned. -func (d *DB) FetchOpenChannels(nodeID *wire.ShaHash) ([]*OpenChannel, error) { +func (d *DB) FetchOpenChannels(nodeID *btcec.PublicKey) ([]*OpenChannel, error) { var channels []*OpenChannel err := d.store.View(func(tx *bolt.Tx) error { // 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 // open channel data specific to the remote node. - nodeChanBucket := openChanBucket.Bucket(nodeID[:]) + pub := nodeID.SerializeCompressed() + nodeChanBucket := openChanBucket.Bucket(pub) if nodeChanBucket == nil { return nil }