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.
This commit is contained in:
Olaoluwa Osuntokun 2016-06-30 11:39:57 -07:00
parent 381474fc8e
commit 582b83ada3
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
2 changed files with 42 additions and 18 deletions

@ -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
}

@ -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