lnwire+netann: update ChannelAnnouncement2 structure

Such that all fields are now TLV (including the signature).
This commit is contained in:
Elle Mouton committed 2025-09-01 12:06:18 +02:00
1 parent 5e7ca548aa
commit 1f71f14587
6 files changed
+292 -109

No files matched your search

+147 -86
View File
@@ -12,9 +12,6 @@ import (
// ChannelAnnouncement2 message is used to announce the existence of a taproot
// channel between two peers in the network.
type ChannelAnnouncement2 struct {
// Signature is a Schnorr signature over the TLV stream of the message.
Signature Sig
// ChainHash denotes the target chain that this channel was opened
// within. This value should be the genesis hash of the target chain.
ChainHash tlv.RecordT[tlv.TlvType0, chainhash.Hash]
@@ -59,74 +56,14 @@ type ChannelAnnouncement2 struct {
// the funding output is a pure 2-of-2 MuSig aggregate public key.
MerkleRootHash tlv.OptionalRecordT[tlv.TlvType16, [32]byte]
// 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
}
// Signature is a Schnorr signature over serialised signed-range TLV
// stream of the message.
Signature tlv.RecordT[tlv.TlvType160, Sig]
// Decode deserializes a serialized AnnounceSignatures1 stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *ChannelAnnouncement2) Decode(r io.Reader, _ uint32) error {
err := ReadElement(r, &c.Signature)
if err != nil {
return err
}
c.Signature.ForceSchnorr()
return c.DecodeTLVRecords(r)
}
// DecodeTLVRecords decodes only the TLV section of the message.
func (c *ChannelAnnouncement2) DecodeTLVRecords(r io.Reader) error {
// First extract into extra opaque data.
var tlvRecords ExtraOpaqueData
if err := ReadElements(r, &tlvRecords); err != nil {
return err
}
var (
chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
btcKey1 = tlv.ZeroRecordT[tlv.TlvType12, [33]byte]()
btcKey2 = tlv.ZeroRecordT[tlv.TlvType14, [33]byte]()
merkleRootHash = tlv.ZeroRecordT[tlv.TlvType16, [32]byte]()
)
typeMap, err := tlvRecords.ExtractRecords(
&chainHash, &c.Features, &c.ShortChannelID, &c.Capacity,
&c.NodeID1, &c.NodeID2, &btcKey1, &btcKey2, &merkleRootHash,
)
if err != nil {
return err
}
// By default, the chain-hash is the bitcoin mainnet genesis block hash.
c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if _, ok := typeMap[c.ChainHash.TlvType()]; ok {
c.ChainHash.Val = chainHash.Val
}
if _, ok := typeMap[c.BitcoinKey1.TlvType()]; ok {
c.BitcoinKey1 = tlv.SomeRecordT(btcKey1)
}
if _, ok := typeMap[c.BitcoinKey2.TlvType()]; ok {
c.BitcoinKey2 = tlv.SomeRecordT(btcKey2)
}
if _, ok := typeMap[c.MerkleRootHash.TlvType()]; ok {
c.MerkleRootHash = tlv.SomeRecordT(merkleRootHash)
}
if len(tlvRecords) != 0 {
c.ExtraOpaqueData = tlvRecords
}
return c.ExtraOpaqueData.ValidateTLV()
// Any extra fields in the signed range that we do not yet know about,
// but we need to keep them for signature validation and to produce a
// valid message.
ExtraSignedFields
}
// Encode serializes the target AnnounceSignatures1 into the passed io.Writer
@@ -134,21 +71,27 @@ func (c *ChannelAnnouncement2) DecodeTLVRecords(r io.Reader) error {
//
// This is part of the lnwire.Message interface.
func (c *ChannelAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error {
_, err := w.Write(c.Signature.RawBytes())
if err != nil {
return err
}
_, err = c.DataToSign()
if err != nil {
return err
}
return WriteBytes(w, c.ExtraOpaqueData)
return EncodePureTLVMessage(c, w)
}
// DataToSign encodes the data to be signed into the ExtraOpaqueData member and
// returns it.
func (c *ChannelAnnouncement2) DataToSign() ([]byte, error) {
// AllRecords returns all the TLV records for the message. This will include all
// the records we know about along with any that we don't know about but that
// fall in the signed TLV range.
//
// NOTE: this is part of the PureTLVMessage interface.
func (c *ChannelAnnouncement2) AllRecords() []tlv.Record {
recordProducers := append(
c.allNonSignatureRecordProducers(), &c.Signature,
)
return ProduceRecordsSorted(recordProducers...)
}
// allNonSignatureRecordProducers returns all the TLV record producers for the
// message except the signature record producer.
//
//nolint:ll
func (c *ChannelAnnouncement2) allNonSignatureRecordProducers() []tlv.RecordProducer {
// The chain-hash record is only included if it is _not_ equal to the
// bitcoin mainnet genisis block hash.
var recordProducers []tlv.RecordProducer
@@ -178,12 +121,126 @@ func (c *ChannelAnnouncement2) DataToSign() ([]byte, error) {
},
)
err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...)
recordProducers = append(recordProducers, RecordsAsProducers(
tlv.MapToRecords(c.ExtraSignedFields),
)...)
return recordProducers
}
// Decode deserializes a serialized AnnounceSignatures1 stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *ChannelAnnouncement2) Decode(r io.Reader, _ uint32) error {
var (
chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
btcKey1 = tlv.ZeroRecordT[tlv.TlvType12, [33]byte]()
btcKey2 = tlv.ZeroRecordT[tlv.TlvType14, [33]byte]()
merkleRootHash = tlv.ZeroRecordT[tlv.TlvType16, [32]byte]()
)
stream, err := tlv.NewStream(ProduceRecordsSorted(
&chainHash,
&c.Features,
&c.ShortChannelID,
&c.Capacity,
&c.NodeID1,
&c.NodeID2,
&btcKey1,
&btcKey2,
&merkleRootHash,
&c.Signature,
)...)
if err != nil {
return nil, err
return err
}
c.Signature.Val.ForceSchnorr()
typeMap, err := stream.DecodeWithParsedTypesP2P(r)
if err != nil {
return err
}
return c.ExtraOpaqueData, nil
// By default, the chain-hash is the bitcoin mainnet genesis block hash.
c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if _, ok := typeMap[c.ChainHash.TlvType()]; ok {
c.ChainHash.Val = chainHash.Val
}
if _, ok := typeMap[c.BitcoinKey1.TlvType()]; ok {
c.BitcoinKey1 = tlv.SomeRecordT(btcKey1)
}
if _, ok := typeMap[c.BitcoinKey2.TlvType()]; ok {
c.BitcoinKey2 = tlv.SomeRecordT(btcKey2)
}
if _, ok := typeMap[c.MerkleRootHash.TlvType()]; ok {
c.MerkleRootHash = tlv.SomeRecordT(merkleRootHash)
}
c.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap)
return nil
}
// DecodeNonSigTLVRecords decodes only the TLV section of the message.
func (c *ChannelAnnouncement2) DecodeNonSigTLVRecords(r io.Reader) error {
var (
chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
btcKey1 = tlv.ZeroRecordT[tlv.TlvType12, [33]byte]()
btcKey2 = tlv.ZeroRecordT[tlv.TlvType14, [33]byte]()
merkleRootHash = tlv.ZeroRecordT[tlv.TlvType16, [32]byte]()
)
stream, err := tlv.NewStream(ProduceRecordsSorted(
&chainHash,
&c.Features,
&c.ShortChannelID,
&c.Capacity,
&c.NodeID1,
&c.NodeID2,
&btcKey1,
&btcKey2,
&merkleRootHash,
)...)
if err != nil {
return err
}
typeMap, err := stream.DecodeWithParsedTypesP2P(r)
if err != nil {
return err
}
// By default, the chain-hash is the bitcoin mainnet genesis block hash.
c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
if _, ok := typeMap[c.ChainHash.TlvType()]; ok {
c.ChainHash.Val = chainHash.Val
}
if _, ok := typeMap[c.BitcoinKey1.TlvType()]; ok {
c.BitcoinKey1 = tlv.SomeRecordT(btcKey1)
}
if _, ok := typeMap[c.BitcoinKey2.TlvType()]; ok {
c.BitcoinKey2 = tlv.SomeRecordT(btcKey2)
}
if _, ok := typeMap[c.MerkleRootHash.TlvType()]; ok {
c.MerkleRootHash = tlv.SomeRecordT(merkleRootHash)
}
c.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap)
return nil
}
// EncodeAllNonSigFields encodes the entire message to the given writer but
// excludes the signature field.
func (c *ChannelAnnouncement2) EncodeAllNonSigFields(w io.Writer) error {
return EncodeRecordsTo(
w, ProduceRecordsSorted(c.allNonSignatureRecordProducers()...),
)
}
// MsgType returns the integer uniquely identifying this message type on the
@@ -209,6 +266,10 @@ var _ Message = (*ChannelAnnouncement2)(nil)
// lnwire.SizeableMessage interface.
var _ SizeableMessage = (*ChannelAnnouncement2)(nil)
// A compile time check to ensure ChannelAnnouncement2 implements the
// lnwire.PureTLVMessage interface.
var _ PureTLVMessage = (*ChannelAnnouncement2)(nil)
// Node1KeyBytes returns the bytes representing the public key of node 1 in the
// channel.
//