mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
lnwire: add musig2 taproot execution messages for dynamic commitments
This commit is contained in:
parent
9b1c04c210
commit
9793fbb94b
@ -3,6 +3,17 @@ package lnwire
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
const (
|
||||
// DALocalMusig2Pubnonce is the TLV type number that identifies the
|
||||
// musig2 public nonce that we need to verify the commitment transaction
|
||||
// signature.
|
||||
DALocalMusig2Pubnonce tlv.Type = 0
|
||||
)
|
||||
|
||||
// DynAck is the message used to accept the parameters of a dynamic commitment
|
||||
@ -13,6 +24,13 @@ type DynAck struct {
|
||||
// a dynamic commitment negotiation
|
||||
ChanID ChannelID
|
||||
|
||||
// LocalNonce is an optional field that is transmitted when accepting
|
||||
// a dynamic commitment upgrade to Taproot Channels. This nonce will be
|
||||
// used to verify the first commitment transaction signature. This will
|
||||
// only be populated if the DynPropose we are responding to specifies
|
||||
// taproot channels in the ChannelType field.
|
||||
LocalNonce fn.Option[Musig2Nonce]
|
||||
|
||||
// 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.
|
||||
@ -32,6 +50,30 @@ func (da *DynAck) Encode(w *bytes.Buffer, _ uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var tlvRecords []tlv.Record
|
||||
da.LocalNonce.WhenSome(func(nonce Musig2Nonce) {
|
||||
tlvRecords = append(
|
||||
tlvRecords, tlv.MakeStaticRecord(
|
||||
DALocalMusig2Pubnonce, &nonce,
|
||||
musig2.PubNonceSize, nonceTypeEncoder,
|
||||
nonceTypeDecoder,
|
||||
),
|
||||
)
|
||||
})
|
||||
tlv.SortRecords(tlvRecords)
|
||||
|
||||
tlvStream, err := tlv.NewStream(tlvRecords...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var extraBytesWriter bytes.Buffer
|
||||
if err := tlvStream.Encode(&extraBytesWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
da.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes())
|
||||
|
||||
return WriteBytes(w, da.ExtraData)
|
||||
}
|
||||
|
||||
@ -41,7 +83,50 @@ func (da *DynAck) Encode(w *bytes.Buffer, _ uint32) error {
|
||||
//
|
||||
// This is a part of the lnwire.Message interface.
|
||||
func (da *DynAck) Decode(r io.Reader, _ uint32) error {
|
||||
return ReadElements(r, &da.ChanID, &da.ExtraData)
|
||||
// Parse out main message.
|
||||
if err := ReadElements(r, &da.ChanID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse out TLV records.
|
||||
var tlvRecords ExtraOpaqueData
|
||||
if err := ReadElement(r, &tlvRecords); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepare receiving buffers to be filled by TLV extraction.
|
||||
var localNonceScratch Musig2Nonce
|
||||
localNonce := tlv.MakeStaticRecord(
|
||||
DALocalMusig2Pubnonce, &localNonceScratch, musig2.PubNonceSize,
|
||||
nonceTypeEncoder, nonceTypeDecoder,
|
||||
)
|
||||
|
||||
// Create set of Records to read TLV bytestream into.
|
||||
records := []tlv.Record{localNonce}
|
||||
tlv.SortRecords(records)
|
||||
|
||||
// Read TLV stream into record set.
|
||||
extraBytesReader := bytes.NewReader(tlvRecords)
|
||||
tlvStream, err := tlv.NewStream(records...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check the results of the TLV Stream decoding and appropriately set
|
||||
// message fields.
|
||||
if val, ok := typeMap[DALocalMusig2Pubnonce]; ok && val == nil {
|
||||
da.LocalNonce = fn.Some(localNonceScratch)
|
||||
}
|
||||
|
||||
if len(tlvRecords) != 0 {
|
||||
da.ExtraData = tlvRecords
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MsgType returns the MessageType code which uniquely identifies this message
|
||||
|
@ -610,6 +610,17 @@ func FuzzDynAck(f *testing.F) {
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzKickoffSig(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
// Prefix with KickoffSig
|
||||
data = prefixWithMsgType(data, MsgKickoffSig)
|
||||
|
||||
// Pass the message into our general fuzz harness for wire
|
||||
// messages!
|
||||
harness(t, data)
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzCustomMessage(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte, customMessageType uint16) {
|
||||
if customMessageType < uint16(CustomTypeStart) {
|
||||
|
56
lnwire/kickoff_sig.go
Normal file
56
lnwire/kickoff_sig.go
Normal file
@ -0,0 +1,56 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// KickoffSig is the message used to transmit the signature for a kickoff
|
||||
// transaction during the execution phase of a dynamic commitment negotiation
|
||||
// that requires a reanchoring step.
|
||||
type KickoffSig struct {
|
||||
// ChanID identifies the channel id for which this signature is
|
||||
// intended.
|
||||
ChanID ChannelID
|
||||
|
||||
// Signature contains the ECDSA signature that signs the kickoff
|
||||
// transaction.
|
||||
Signature Sig
|
||||
|
||||
// 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 that KickoffSig implements the lnwire.Message
|
||||
// interface.
|
||||
var _ Message = (*KickoffSig)(nil)
|
||||
|
||||
// Encode serializes the target KickoffSig into the passed bytes.Buffer
|
||||
// observing the specified protocol version.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (ks *KickoffSig) Encode(w *bytes.Buffer, _ uint32) error {
|
||||
if err := WriteChannelID(w, ks.ChanID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := WriteSig(w, ks.Signature); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteBytes(w, ks.ExtraData)
|
||||
}
|
||||
|
||||
// Decode deserializes a serialized KickoffSig message stored in the passed
|
||||
// io.Reader observing the specified protocol version.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (ks *KickoffSig) Decode(r io.Reader, _ uint32) error {
|
||||
return ReadElements(r, &ks.ChanID, &ks.Signature, &ks.ExtraData)
|
||||
}
|
||||
|
||||
// MsgType returns the integer uniquely identifying KickoffSig on the wire.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (ks *KickoffSig) MsgType() MessageType { return MsgKickoffSig }
|
@ -804,9 +804,24 @@ func TestLightningWireProtocol(t *testing.T) {
|
||||
var da DynAck
|
||||
|
||||
rand.Read(da.ChanID[:])
|
||||
if rand.Uint32()%2 == 0 {
|
||||
var nonce Musig2Nonce
|
||||
rand.Read(nonce[:])
|
||||
da.LocalNonce = fn.Some(nonce)
|
||||
}
|
||||
|
||||
v[0] = reflect.ValueOf(da)
|
||||
},
|
||||
MsgKickoffSig: func(v []reflect.Value, r *rand.Rand) {
|
||||
ks := KickoffSig{
|
||||
ExtraData: make([]byte, 0),
|
||||
}
|
||||
|
||||
rand.Read(ks.ChanID[:])
|
||||
rand.Read(ks.Signature.bytes[:])
|
||||
|
||||
v[0] = reflect.ValueOf(ks)
|
||||
},
|
||||
MsgCommitSig: func(v []reflect.Value, r *rand.Rand) {
|
||||
req := NewCommitSig()
|
||||
if _, err := r.Read(req.ChanID[:]); err != nil {
|
||||
@ -1270,6 +1285,12 @@ func TestLightningWireProtocol(t *testing.T) {
|
||||
return mainScenario(&m)
|
||||
},
|
||||
},
|
||||
{
|
||||
msgType: MsgKickoffSig,
|
||||
scenario: func(m KickoffSig) bool {
|
||||
return mainScenario(&m)
|
||||
},
|
||||
},
|
||||
{
|
||||
msgType: MsgUpdateAddHTLC,
|
||||
scenario: func(m UpdateAddHTLC) bool {
|
||||
|
@ -54,6 +54,7 @@ const (
|
||||
MsgQueryChannelRange = 263
|
||||
MsgReplyChannelRange = 264
|
||||
MsgGossipTimestampRange = 265
|
||||
MsgKickoffSig = 777
|
||||
)
|
||||
|
||||
// ErrorEncodeMessage is used when failed to encode the message payload.
|
||||
@ -103,6 +104,8 @@ func (t MessageType) String() string {
|
||||
return "DynAck"
|
||||
case MsgDynReject:
|
||||
return "DynReject"
|
||||
case MsgKickoffSig:
|
||||
return "KickoffSig"
|
||||
case MsgUpdateAddHTLC:
|
||||
return "UpdateAddHTLC"
|
||||
case MsgUpdateFailHTLC:
|
||||
@ -211,6 +214,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) {
|
||||
msg = &DynAck{}
|
||||
case MsgDynReject:
|
||||
msg = &DynReject{}
|
||||
case MsgKickoffSig:
|
||||
msg = &KickoffSig{}
|
||||
case MsgUpdateAddHTLC:
|
||||
msg = &UpdateAddHTLC{}
|
||||
case MsgUpdateFailHTLC:
|
||||
|
Loading…
Reference in New Issue
Block a user