package lnwire import ( "bytes" "io" "github.com/btcsuite/btcd/btcec/v2" ) // ChannelReestablish is a message sent between peers that have an existing // open channel upon connection reestablishment. This message allows both sides // to report their local state, and their current knowledge of the state of the // remote commitment chain. If a deviation is detected and can be recovered // from, then the necessary messages will be retransmitted. If the level of // desynchronization is irreconcilable, then the channel will be force closed. type ChannelReestablish struct { // ChanID is the channel ID of the channel state we're attempting to // synchronize with the remote party. ChanID ChannelID // NextLocalCommitHeight is the next local commitment height of the // sending party. If the height of the sender's commitment chain from // the receiver's Pov is one less that this number, then the sender // should re-send the *exact* same proposed commitment. // // In other words, the receiver should re-send their last sent // commitment iff: // // * NextLocalCommitHeight == remoteCommitChain.Height // // This covers the case of a lost commitment which was sent by the // sender of this message, but never received by the receiver of this // message. NextLocalCommitHeight uint64 // RemoteCommitTailHeight is the height of the receiving party's // unrevoked commitment from the PoV of the sender of this message. If // the height of the receiver's commitment is *one more* than this // value, then their prior RevokeAndAck message should be // retransmitted. // // In other words, the receiver should re-send their last sent // RevokeAndAck message iff: // // * localCommitChain.tail().Height == RemoteCommitTailHeight + 1 // // This covers the case of a lost revocation, wherein the receiver of // the message sent a revocation for a prior state, but the sender of // the message never fully processed it. RemoteCommitTailHeight uint64 // LastRemoteCommitSecret is the last commitment secret that the // receiving node has sent to the sending party. This will be the // secret of the last revoked commitment transaction. Including this // provides proof that the sending node at least knows of this state, // as they couldn't have produced it if it wasn't sent, as the value // can be authenticated by querying the shachain or the receiving // party. LastRemoteCommitSecret [32]byte // LocalUnrevokedCommitPoint is the commitment point used in the // current un-revoked commitment transaction of the sending party. LocalUnrevokedCommitPoint *btcec.PublicKey // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can // be used to specify optional data such as custom TLV fields. ExtraData ExtraOpaqueData } // A compile time check to ensure ChannelReestablish implements the // lnwire.Message interface. var _ Message = (*ChannelReestablish)(nil) // Encode serializes the target ChannelReestablish into the passed io.Writer // observing the protocol version specified. // // This is part of the lnwire.Message interface. func (a *ChannelReestablish) Encode(w *bytes.Buffer, pver uint32) error { if err := WriteChannelID(w, a.ChanID); err != nil { return err } if err := WriteUint64(w, a.NextLocalCommitHeight); err != nil { return err } if err := WriteUint64(w, a.RemoteCommitTailHeight); err != nil { return err } // If the commit point wasn't sent, then we won't write out any of the // remaining fields as they're optional. if a.LocalUnrevokedCommitPoint == nil { // However, we'll still write out the extra data if it's // present. // // NOTE: This is here primarily for the quickcheck tests, in // practice, we'll always populate this field. return WriteBytes(w, a.ExtraData) } // Otherwise, we'll write out the remaining elements. if err := WriteBytes(w, a.LastRemoteCommitSecret[:]); err != nil { return err } if err := WritePublicKey(w, a.LocalUnrevokedCommitPoint); err != nil { return err } return WriteBytes(w, a.ExtraData) } // Decode deserializes a serialized ChannelReestablish stored in the passed // io.Reader observing the specified protocol version. // // This is part of the lnwire.Message interface. func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error { err := ReadElements(r, &a.ChanID, &a.NextLocalCommitHeight, &a.RemoteCommitTailHeight, ) if err != nil { return err } // This message has currently defined optional fields. As a result, // we'll only proceed if there's still bytes remaining within the // reader. // // We'll manually parse out the optional fields in order to be able to // still utilize the io.Reader interface. // We'll first attempt to read the optional commit secret, if we're at // the EOF, then this means the field wasn't included so we can exit // early. var buf [32]byte _, err = io.ReadFull(r, buf[:32]) if err == io.EOF { // If there aren't any more bytes, then we'll emplace an empty // extra data to make our quickcheck tests happy. a.ExtraData = make([]byte, 0) return nil } else if err != nil { return err } // If the field is present, then we'll copy it over and proceed. copy(a.LastRemoteCommitSecret[:], buf[:]) // We'll conclude by parsing out the commitment point. We don't check // the error in this case, as it has included the commit secret, then // they MUST also include the commit point. if err = ReadElement(r, &a.LocalUnrevokedCommitPoint); err != nil { return err } return a.ExtraData.Decode(r) } // MsgType returns the integer uniquely identifying this message type on the // wire. // // This is part of the lnwire.Message interface. func (a *ChannelReestablish) MsgType() MessageType { return MsgChannelReestablish }