From 582b83ada3f4009ec08e0a1ccc96f1242f520cc9 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 30 Jun 2016 11:39:57 -0700 Subject: [PATCH] channeldb: update channel state to revocation keys + new elkrem API This commit updates the stored on-disk channel state to store a current revocation key rather than a revocation hash. This change coincides with the new commitment transaction format which uses revocation keys rather than hashes. Additionally, this commit updates the decoding/encoding of local+remote elkrem trees to the latest changes in the elkrem API. --- channeldb/channel.go | 31 ++++++++++++++++++------------- channeldb/channel_test.go | 29 ++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/channeldb/channel.go b/channeldb/channel.go index c3ee0461..e3456194 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -133,9 +133,9 @@ type OpenChannel struct { RemoteCsvDelay uint32 // Current revocation for their commitment transaction. However, since - // this is the hash, and not the pre-image, we can't yet verify that - // it's actually in the chain. - TheirCurrentRevocation [32]byte + // this the derived public key, we don't yet have the pre-image so we + // aren't yet able to verify that it's actually in the hash chain. + TheirCurrentRevocation *btcec.PublicKey LocalElkrem *elkrem.ElkremSender RemoteElkrem *elkrem.ElkremReceiver @@ -1024,15 +1024,14 @@ func putChanEklremState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error var b bytes.Buffer - if _, err := b.Write(channel.TheirCurrentRevocation[:]); err != nil { + revKey := channel.TheirCurrentRevocation.SerializeCompressed() + if err := wire.WriteVarBytes(&b, 0, revKey); err != nil { return err } - // TODO(roasbeef): no longer need to store any sender data - senderBytes, err := channel.LocalElkrem.ToBytes() - if err != nil { - return err - } + // TODO(roasbeef): shouldn't be storing on disk, should re-derive as + // needed + senderBytes := channel.LocalElkrem.ToBytes() if err := wire.WriteVarBytes(&b, 0, senderBytes); err != nil { return err } @@ -1066,19 +1065,25 @@ func fetchChanEklremState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) err elkremStateBytes := bytes.NewReader(nodeChanBucket.Get(elkremKey)) - if _, err := elkremStateBytes.Read(channel.TheirCurrentRevocation[:]); err != nil { + revKeyBytes, err := wire.ReadVarBytes(elkremStateBytes, 0, 1000, "") + if err != nil { + return err + } + channel.TheirCurrentRevocation, err = btcec.ParsePubKey(revKeyBytes, btcec.S256()) + if err != nil { return err } + // TODO(roasbeef): should be rederiving on fly, or encrypting on disk. senderBytes, err := wire.ReadVarBytes(elkremStateBytes, 0, 1000, "") if err != nil { return err } - localE, err := elkrem.ElkremSenderFromBytes(senderBytes) + elkremRoot, err := wire.NewShaHash(senderBytes) if err != nil { return err } - channel.LocalElkrem = &localE + channel.LocalElkrem = elkrem.NewElkremSender(*elkremRoot) reciverBytes, err := wire.ReadVarBytes(elkremStateBytes, 0, 1000, "") if err != nil { @@ -1088,7 +1093,7 @@ func fetchChanEklremState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) err if err != nil { return err } - channel.RemoteElkrem = &remoteE + channel.RemoteElkrem = remoteE return nil } diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index dea8973e..73cd46fc 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -127,8 +127,8 @@ func TestOpenChannelPutGetDelete(t *testing.T) { // Simulate 1000 channel updates via progression of the elkrem // revocation trees. - sender := elkrem.NewElkremSender(32, key) - receiver := elkrem.NewElkremReceiver(32) + sender := elkrem.NewElkremSender(key) + receiver := &elkrem.ElkremReceiver{} for i := 0; i < 1000; i++ { preImage, err := sender.AtIndex(uint64(i)) if err != nil { @@ -151,13 +151,13 @@ func TestOpenChannelPutGetDelete(t *testing.T) { TheirBalance: btcutil.Amount(9000), TheirCommitTx: testTx, OurCommitTx: testTx, - LocalElkrem: &sender, - RemoteElkrem: &receiver, + LocalElkrem: sender, + RemoteElkrem: receiver, FundingOutpoint: testOutpoint, OurMultiSigKey: privKey, TheirMultiSigKey: privKey.PubKey(), FundingRedeemScript: script, - TheirCurrentRevocation: rev, + TheirCurrentRevocation: privKey.PubKey(), OurDeliveryScript: script, TheirDeliveryScript: script, LocalCsvDelay: 5, @@ -289,6 +289,25 @@ func TestOpenChannelPutGetDelete(t *testing.T) { t.Fatalf("creation time doesn't match") } + // The local and remote elkrems should be identical. + if !bytes.Equal(state.LocalElkrem.ToBytes(), newState.LocalElkrem.ToBytes()) { + t.Fatalf("local elkrems don't match") + } + oldRemoteElkrem, err := state.RemoteElkrem.ToBytes() + if err != nil { + t.Fatalf("unable to serialize old remote elkrem: %v", err) + } + newRemoteElkrem, err := newState.RemoteElkrem.ToBytes() + if err != nil { + t.Fatalf("unable to serialize new remote elkrem: %v", err) + } + if !bytes.Equal(oldRemoteElkrem, newRemoteElkrem) { + t.Fatalf("remote elkrems don't match") + } + if !newState.TheirCurrentRevocation.IsEqual(state.TheirCurrentRevocation) { + t.Fatalf("revocation keys don't match") + } + // Finally to wrap up the test, delete the state of the channel within // the database. This involves "closing" the channel which removes all // written state, and creates a small "summary" elsewhere within the