mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-11 01:11:02 +02: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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"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
|
// DynAck is the message used to accept the parameters of a dynamic commitment
|
||||||
@ -13,6 +24,13 @@ type DynAck struct {
|
|||||||
// a dynamic commitment negotiation
|
// a dynamic commitment negotiation
|
||||||
ChanID ChannelID
|
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
|
// ExtraData is the set of data that was appended to this message to
|
||||||
// fill out the full maximum transport message size. These fields can
|
// fill out the full maximum transport message size. These fields can
|
||||||
// be used to specify optional data such as custom TLV fields.
|
// 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
|
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)
|
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.
|
// This is a part of the lnwire.Message interface.
|
||||||
func (da *DynAck) Decode(r io.Reader, _ uint32) error {
|
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
|
// 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) {
|
func FuzzCustomMessage(f *testing.F) {
|
||||||
f.Fuzz(func(t *testing.T, data []byte, customMessageType uint16) {
|
f.Fuzz(func(t *testing.T, data []byte, customMessageType uint16) {
|
||||||
if customMessageType < uint16(CustomTypeStart) {
|
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
|
var da DynAck
|
||||||
|
|
||||||
rand.Read(da.ChanID[:])
|
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)
|
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) {
|
MsgCommitSig: func(v []reflect.Value, r *rand.Rand) {
|
||||||
req := NewCommitSig()
|
req := NewCommitSig()
|
||||||
if _, err := r.Read(req.ChanID[:]); err != nil {
|
if _, err := r.Read(req.ChanID[:]); err != nil {
|
||||||
@ -1270,6 +1285,12 @@ func TestLightningWireProtocol(t *testing.T) {
|
|||||||
return mainScenario(&m)
|
return mainScenario(&m)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
msgType: MsgKickoffSig,
|
||||||
|
scenario: func(m KickoffSig) bool {
|
||||||
|
return mainScenario(&m)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
msgType: MsgUpdateAddHTLC,
|
msgType: MsgUpdateAddHTLC,
|
||||||
scenario: func(m UpdateAddHTLC) bool {
|
scenario: func(m UpdateAddHTLC) bool {
|
||||||
|
@ -54,6 +54,7 @@ const (
|
|||||||
MsgQueryChannelRange = 263
|
MsgQueryChannelRange = 263
|
||||||
MsgReplyChannelRange = 264
|
MsgReplyChannelRange = 264
|
||||||
MsgGossipTimestampRange = 265
|
MsgGossipTimestampRange = 265
|
||||||
|
MsgKickoffSig = 777
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrorEncodeMessage is used when failed to encode the message payload.
|
// ErrorEncodeMessage is used when failed to encode the message payload.
|
||||||
@ -103,6 +104,8 @@ func (t MessageType) String() string {
|
|||||||
return "DynAck"
|
return "DynAck"
|
||||||
case MsgDynReject:
|
case MsgDynReject:
|
||||||
return "DynReject"
|
return "DynReject"
|
||||||
|
case MsgKickoffSig:
|
||||||
|
return "KickoffSig"
|
||||||
case MsgUpdateAddHTLC:
|
case MsgUpdateAddHTLC:
|
||||||
return "UpdateAddHTLC"
|
return "UpdateAddHTLC"
|
||||||
case MsgUpdateFailHTLC:
|
case MsgUpdateFailHTLC:
|
||||||
@ -211,6 +214,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) {
|
|||||||
msg = &DynAck{}
|
msg = &DynAck{}
|
||||||
case MsgDynReject:
|
case MsgDynReject:
|
||||||
msg = &DynReject{}
|
msg = &DynReject{}
|
||||||
|
case MsgKickoffSig:
|
||||||
|
msg = &KickoffSig{}
|
||||||
case MsgUpdateAddHTLC:
|
case MsgUpdateAddHTLC:
|
||||||
msg = &UpdateAddHTLC{}
|
msg = &UpdateAddHTLC{}
|
||||||
case MsgUpdateFailHTLC:
|
case MsgUpdateFailHTLC:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user