diff --git a/lnwire/announcement_signatures_2.go b/lnwire/announcement_signatures_2.go new file mode 100644 index 000000000..a10447032 --- /dev/null +++ b/lnwire/announcement_signatures_2.go @@ -0,0 +1,97 @@ +package lnwire + +import ( + "bytes" + "io" +) + +// AnnounceSignatures2 is a direct message between two endpoints of a +// channel and serves as an opt-in mechanism to allow the announcement of +// a taproot channel to the rest of the network. It contains the necessary +// signatures by the sender to construct the channel_announcement_2 message. +type AnnounceSignatures2 struct { + // ChannelID is the unique description of the funding transaction. + // Channel id is better for users and debugging and short channel id is + // used for quick test on existence of the particular utxo inside the + // blockchain, because it contains information about block. + ChannelID ChannelID + + // ShortChannelID is the unique description of the funding transaction. + // It is constructed with the most significant 3 bytes as the block + // height, the next 3 bytes indicating the transaction index within the + // block, and the least significant two bytes indicating the output + // index which pays to the channel. + ShortChannelID ShortChannelID + + // PartialSignature is the combination of the partial Schnorr signature + // created for the node's bitcoin key with the partial signature created + // for the node's node ID key. + PartialSignature PartialSig + + // ExtraOpaqueData is the set of data that was appended to this + // message, some of which we may not actually know how to iterate or + // parse. By holding onto this data, we ensure that we're able to + // properly validate the set of signatures that cover these new fields, + // and ensure we're able to make upgrades to the network in a forwards + // compatible manner. + ExtraOpaqueData ExtraOpaqueData +} + +// A compile time check to ensure AnnounceSignatures2 implements the +// lnwire.Message interface. +var _ Message = (*AnnounceSignatures2)(nil) + +// Decode deserializes a serialized AnnounceSignatures2 stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures2) Decode(r io.Reader, _ uint32) error { + return ReadElements(r, + &a.ChannelID, + &a.ShortChannelID, + &a.PartialSignature, + &a.ExtraOpaqueData, + ) +} + +// Encode serializes the target AnnounceSignatures2 into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures2) Encode(w *bytes.Buffer, _ uint32) error { + if err := WriteChannelID(w, a.ChannelID); err != nil { + return err + } + + if err := WriteShortChannelID(w, a.ShortChannelID); err != nil { + return err + } + + if err := WriteElement(w, a.PartialSignature); err != nil { + return err + } + + return WriteBytes(w, a.ExtraOpaqueData) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures2) MsgType() MessageType { + return MsgAnnounceSignatures2 +} + +// SCID returns the ShortChannelID of the channel. +// +// NOTE: this is part of the AnnounceSignatures interface. +func (a *AnnounceSignatures2) SCID() ShortChannelID { + return a.ShortChannelID +} + +// ChanID returns the ChannelID identifying the channel. +// +// NOTE: this is part of the AnnounceSignatures interface. +func (a *AnnounceSignatures2) ChanID() ChannelID { + return a.ChannelID +} diff --git a/lnwire/lnwire.go b/lnwire/lnwire.go index 8ab082b0b..4d2b814e5 100644 --- a/lnwire/lnwire.go +++ b/lnwire/lnwire.go @@ -187,6 +187,11 @@ func WriteElement(w *bytes.Buffer, element interface{}) error { return err } + case PartialSig: + if err := e.Encode(w); err != nil { + return err + } + case PingPayload: var l [2]byte binary.BigEndian.PutUint16(l[:], uint16(len(e))) @@ -936,6 +941,13 @@ func ReadElement(r io.Reader, element interface{}) error { } *e = addrBytes[:length] + case *PartialSig: + var sig PartialSig + if err = sig.Decode(r); err != nil { + return err + } + *e = sig + case *ExtraOpaqueData: return e.Decode(r) diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index 90d338d88..e4ab753f7 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -1509,6 +1509,35 @@ func TestLightningWireProtocol(t *testing.T) { v[0] = reflect.ValueOf(*req) }, + MsgAnnounceSignatures2: func(v []reflect.Value, + r *rand.Rand) { + + req := AnnounceSignatures2{ + ShortChannelID: NewShortChanIDFromInt( + uint64(r.Int63()), + ), + ExtraOpaqueData: make([]byte, 0), + } + + _, err := r.Read(req.ChannelID[:]) + require.NoError(t, err) + + partialSig, err := randPartialSig(r) + require.NoError(t, err) + + req.PartialSignature = *partialSig + + numExtraBytes := r.Int31n(1000) + if numExtraBytes > 0 { + req.ExtraOpaqueData = make( + []byte, numExtraBytes, + ) + _, err := r.Read(req.ExtraOpaqueData[:]) + require.NoError(t, err) + } + + v[0] = reflect.ValueOf(req) + }, } // With the above types defined, we'll now generate a slice of @@ -1737,6 +1766,12 @@ func TestLightningWireProtocol(t *testing.T) { return mainScenario(&m) }, }, + { + msgType: MsgAnnounceSignatures2, + scenario: func(m AnnounceSignatures2) bool { + return mainScenario(&m) + }, + }, } for _, test := range tests { var config *quick.Config diff --git a/lnwire/message.go b/lnwire/message.go index 1d93a2a26..e93357277 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -52,6 +52,7 @@ const ( MsgNodeAnnouncement = 257 MsgChannelUpdate = 258 MsgAnnounceSignatures = 259 + MsgAnnounceSignatures2 = 260 MsgQueryShortChanIDs = 261 MsgReplyShortChanIDsEnd = 262 MsgQueryChannelRange = 263 @@ -155,6 +156,8 @@ func (t MessageType) String() string { return "ClosingComplete" case MsgClosingSig: return "ClosingSig" + case MsgAnnounceSignatures2: + return "MsgAnnounceSignatures2" default: return "" } @@ -284,6 +287,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { msg = &ClosingComplete{} case MsgClosingSig: msg = &ClosingSig{} + case MsgAnnounceSignatures2: + msg = &AnnounceSignatures2{} default: // If the message is not within our custom range and has not // specifically been overridden, return an unknown message.