channeldb: add InsertNextRevocation method to OpenChannel

This commit adds a new method to the OpenChannel struct:
InsertNextRevocation. This functionality is required in order to
properly implement the new funding workflow and commitment transaction
state machine.

In the prior state machine, we utilized the “initial revocation window”
which would provide both sides with the necessary revocation keys that
they needed to create new commitment states. The version of the
commitment state machine within the specification has been simplified a
bit, and instead essentially incorporates a revocation window of 1. The
window is initially filled at the _opening_ of the commitment
transaction, then never extended, only “slid down” from there on.
This commit is contained in:
Olaoluwa Osuntokun 2017-07-29 11:24:03 -07:00
parent a14072a47e
commit 5854ffb644
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2

@ -595,6 +595,34 @@ type ChannelDelta struct {
Htlcs []*HTLC Htlcs []*HTLC
} }
// InsertNextRevocation inserts the _next_ commitment point (revocation) into
// the database, and also modifies the internal RemoteNextRevocation attribute
// to point to the passed key. This method is to be using during final channel
// set up, _after_ the channel has been fully confirmed.
//
// NOTE: If this method isn't called, then the target channel won't be able to
// propose new states for the commitment state of the remote party.
func (c *OpenChannel) InsertNextRevocation(revKey *btcec.PublicKey) error {
c.Lock()
defer c.Unlock()
return c.Db.Update(func(tx *bolt.Tx) error {
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket)
if err != nil {
return err
}
id := c.IdentityPub.SerializeCompressed()
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(id)
if err != nil {
return err
}
c.RemoteNextRevocation = revKey
return putChanRevocationState(nodeChanBucket, c)
})
}
// AppendToRevocationLog records the new state transition within an on-disk // AppendToRevocationLog records the new state transition within an on-disk
// append-only log which records all state transitions by the remote peer. In // append-only log which records all state transitions by the remote peer. In
// the case of an uncooperative broadcast of a prior state by the remote peer, // the case of an uncooperative broadcast of a prior state by the remote peer,
@ -1923,9 +1951,16 @@ func putChanRevocationState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) e
return err return err
} }
var bc bytes.Buffer // We place the next revocation key at the very end, as under certain
if err := writeOutpoint(&bc, channel.ChanID); err != nil { // circumstances (when a channel is initially funded), this value will
return err // not yet have been set.
//
// TODO(roasbeef): segment the storage?
if channel.RemoteNextRevocation != nil {
nextRevKey := channel.RemoteNextRevocation.SerializeCompressed()
if err := wire.WriteVarBytes(&b, 0, nextRevKey); err != nil {
return err
}
} }
revocationKey := make([]byte, len(revocationStateKey)+bc.Len()) revocationKey := make([]byte, len(revocationStateKey)+bc.Len())
@ -1976,8 +2011,23 @@ func fetchChanRevocationState(nodeChanBucket *bolt.Bucket, channel *OpenChannel)
return err return err
} }
_, err = io.ReadFull(reader, channel.StateHintObsfucator[:]) // We'll attempt to see if the remote party's next revocation key is
return err // currently set, if so then we'll read and deserialize it. Otherwise,
// we can exit early.
if reader.Len() != 0 {
nextRevKeyBytes, err := wire.ReadVarBytes(reader, 0, 1000, "")
if err != nil {
return err
}
channel.RemoteNextRevocation, err = btcec.ParsePubKey(
nextRevKeyBytes, btcec.S256(),
)
if err != nil {
return err
}
}
return nil
} }
func serializeHTLC(w io.Writer, h *HTLC) error { func serializeHTLC(w io.Writer, h *HTLC) error {