lnwire: define NodeAnnouncement2
In this commit, the lnwire.NodeAnnouncement2 type is defined. This will be used to represent the `node_announcement_2` message used in the Gossip 2 (1.75) protocol.
This commit is contained in:
6 files changed
+873
No files matched your search
@@ -244,6 +244,30 @@ func FuzzNodeAnnouncement(f *testing.F) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FuzzNodeAnnouncement2(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
// We can't use require.Equal for Features, since we consider
|
||||||
|
// the empty map and nil to be equivalent.
|
||||||
|
assertEq := func(t *testing.T, x, y any) {
|
||||||
|
require.IsType(t, &NodeAnnouncement2{}, x)
|
||||||
|
first, _ := x.(*NodeAnnouncement2)
|
||||||
|
require.IsType(t, &NodeAnnouncement2{}, y)
|
||||||
|
second, _ := y.(*NodeAnnouncement2)
|
||||||
|
|
||||||
|
require.True(
|
||||||
|
t,
|
||||||
|
first.Features.Val.Equals(&second.Features.Val),
|
||||||
|
)
|
||||||
|
first.Features.Val = *NewRawFeatureVector()
|
||||||
|
second.Features.Val = *NewRawFeatureVector()
|
||||||
|
|
||||||
|
require.Equal(t, first, second)
|
||||||
|
}
|
||||||
|
|
||||||
|
wireMsgHarnessCustom(t, data, MsgNodeAnnouncement2, assertEq)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func FuzzOpenChannel(f *testing.F) {
|
func FuzzOpenChannel(f *testing.F) {
|
||||||
f.Fuzz(func(t *testing.T, data []byte) {
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
// We can't use require.Equal for UpfrontShutdownScript, since
|
// We can't use require.Equal for UpfrontShutdownScript, since
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ const (
|
|||||||
MsgReplyChannelRange = 264
|
MsgReplyChannelRange = 264
|
||||||
MsgGossipTimestampRange = 265
|
MsgGossipTimestampRange = 265
|
||||||
MsgChannelAnnouncement2 = 267
|
MsgChannelAnnouncement2 = 267
|
||||||
|
MsgNodeAnnouncement2 = 269
|
||||||
MsgChannelUpdate2 = 271
|
MsgChannelUpdate2 = 271
|
||||||
MsgKickoffSig = 777
|
MsgKickoffSig = 777
|
||||||
|
|
||||||
@@ -193,6 +194,8 @@ func (t MessageType) String() string {
|
|||||||
return "MsgAnnounceSignatures2"
|
return "MsgAnnounceSignatures2"
|
||||||
case MsgChannelAnnouncement2:
|
case MsgChannelAnnouncement2:
|
||||||
return "ChannelAnnouncement2"
|
return "ChannelAnnouncement2"
|
||||||
|
case MsgNodeAnnouncement2:
|
||||||
|
return "NodeAnnouncement2"
|
||||||
case MsgChannelUpdate2:
|
case MsgChannelUpdate2:
|
||||||
return "ChannelUpdate2"
|
return "ChannelUpdate2"
|
||||||
default:
|
default:
|
||||||
@@ -355,6 +358,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) {
|
|||||||
msg = &AnnounceSignatures2{}
|
msg = &AnnounceSignatures2{}
|
||||||
case MsgChannelAnnouncement2:
|
case MsgChannelAnnouncement2:
|
||||||
msg = &ChannelAnnouncement2{}
|
msg = &ChannelAnnouncement2{}
|
||||||
|
case MsgNodeAnnouncement2:
|
||||||
|
msg = &NodeAnnouncement2{}
|
||||||
case MsgChannelUpdate2:
|
case MsgChannelUpdate2:
|
||||||
msg = &ChannelUpdate2{}
|
msg = &ChannelUpdate2{}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -0,0 +1,581 @@
|
|||||||
|
package lnwire
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
|
"github.com/lightningnetwork/lnd/tor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeAnnouncement2 message is used to announce the presence of a Lightning
|
||||||
|
// node and also to signal that the node is accepting incoming connections.
|
||||||
|
// Each NodeAnnouncement2 authenticating the advertised information within the
|
||||||
|
// announcement via a signature using the advertised node pubkey.
|
||||||
|
type NodeAnnouncement2 struct {
|
||||||
|
// Features is the feature vector that encodes the features supported
|
||||||
|
// by the target node.
|
||||||
|
Features tlv.RecordT[tlv.TlvType0, RawFeatureVector]
|
||||||
|
|
||||||
|
// Color is an optional field used to customize a node's appearance in
|
||||||
|
// maps and graphs.
|
||||||
|
Color tlv.OptionalRecordT[tlv.TlvType1, Color]
|
||||||
|
|
||||||
|
// BlockHeight allows ordering in the case of multiple announcements. We
|
||||||
|
// should ignore the message if block height is not greater than the
|
||||||
|
// last-received. The block height must always be greater or equal to
|
||||||
|
// the block height that the channel funding transaction was confirmed
|
||||||
|
// in.
|
||||||
|
BlockHeight tlv.RecordT[tlv.TlvType2, uint32]
|
||||||
|
|
||||||
|
// Alias is used to customize their node's appearance in maps and
|
||||||
|
// graphs.
|
||||||
|
Alias tlv.OptionalRecordT[tlv.TlvType3, NodeAlias2]
|
||||||
|
|
||||||
|
// NodeID is the public key of the node creating the announcement.
|
||||||
|
NodeID tlv.RecordT[tlv.TlvType4, [33]byte]
|
||||||
|
|
||||||
|
// IPV4Addrs is an optional list of ipv4 addresses that the node is
|
||||||
|
// reachable at.
|
||||||
|
IPV4Addrs tlv.OptionalRecordT[tlv.TlvType5, IPV4Addrs]
|
||||||
|
|
||||||
|
// IPV6Addrs is an optional list of ipv6 addresses that the node is
|
||||||
|
// reachable at.
|
||||||
|
IPV6Addrs tlv.OptionalRecordT[tlv.TlvType7, IPV6Addrs]
|
||||||
|
|
||||||
|
// TorV3Addrs is an optional list of tor v3 addresses that the node is
|
||||||
|
// reachable at.
|
||||||
|
TorV3Addrs tlv.OptionalRecordT[tlv.TlvType9, TorV3Addrs]
|
||||||
|
|
||||||
|
// DNSHostName is an optional DNS hostname that the node is reachable
|
||||||
|
// at.
|
||||||
|
DNSHostName tlv.OptionalRecordT[tlv.TlvType11, DNSAddress]
|
||||||
|
|
||||||
|
// Signature is used to validate the announced data and prove the
|
||||||
|
// ownership of node id.
|
||||||
|
Signature tlv.RecordT[tlv.TlvType160, Sig]
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializedSize returns the serialized size of the message in bytes.
|
||||||
|
//
|
||||||
|
// This is part of the lnwire.SizeableMessage interface.
|
||||||
|
func (n *NodeAnnouncement2) SerializedSize() (uint32, error) {
|
||||||
|
return MessageSerializedSize(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (n *NodeAnnouncement2) AllRecords() []tlv.Record {
|
||||||
|
recordProducers := []tlv.RecordProducer{
|
||||||
|
&n.Features,
|
||||||
|
&n.BlockHeight,
|
||||||
|
&n.NodeID,
|
||||||
|
&n.Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
n.Color.WhenSome(func(r tlv.RecordT[tlv.TlvType1, Color]) {
|
||||||
|
recordProducers = append(recordProducers, &r)
|
||||||
|
})
|
||||||
|
|
||||||
|
n.Alias.WhenSome(func(a tlv.RecordT[tlv.TlvType3, NodeAlias2]) {
|
||||||
|
recordProducers = append(recordProducers, &a)
|
||||||
|
})
|
||||||
|
|
||||||
|
n.IPV4Addrs.WhenSome(func(r tlv.RecordT[tlv.TlvType5, IPV4Addrs]) {
|
||||||
|
recordProducers = append(recordProducers, &r)
|
||||||
|
})
|
||||||
|
|
||||||
|
n.IPV6Addrs.WhenSome(func(r tlv.RecordT[tlv.TlvType7, IPV6Addrs]) {
|
||||||
|
recordProducers = append(recordProducers, &r)
|
||||||
|
})
|
||||||
|
|
||||||
|
n.TorV3Addrs.WhenSome(func(r tlv.RecordT[tlv.TlvType9, TorV3Addrs]) {
|
||||||
|
recordProducers = append(recordProducers, &r)
|
||||||
|
})
|
||||||
|
|
||||||
|
n.DNSHostName.WhenSome(func(r tlv.RecordT[tlv.TlvType11, DNSAddress]) {
|
||||||
|
recordProducers = append(recordProducers, &r)
|
||||||
|
})
|
||||||
|
|
||||||
|
recordProducers = append(recordProducers, RecordsAsProducers(
|
||||||
|
tlv.MapToRecords(n.ExtraSignedFields),
|
||||||
|
)...)
|
||||||
|
|
||||||
|
return ProduceRecordsSorted(recordProducers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode deserializes a serialized NodeAnnouncement2 stored in the passed
|
||||||
|
// io.Reader observing the specified protocol version.
|
||||||
|
//
|
||||||
|
// This is part of the lnwire.Message interface.
|
||||||
|
func (n *NodeAnnouncement2) Decode(r io.Reader, _ uint32) error {
|
||||||
|
var (
|
||||||
|
color = tlv.ZeroRecordT[tlv.TlvType1, Color]()
|
||||||
|
alias = tlv.ZeroRecordT[tlv.TlvType3, NodeAlias2]()
|
||||||
|
ipv4 = tlv.ZeroRecordT[tlv.TlvType5, IPV4Addrs]()
|
||||||
|
ipv6 = tlv.ZeroRecordT[tlv.TlvType7, IPV6Addrs]()
|
||||||
|
torV3 = tlv.ZeroRecordT[tlv.TlvType9, TorV3Addrs]()
|
||||||
|
dns = tlv.ZeroRecordT[tlv.TlvType11, DNSAddress]()
|
||||||
|
)
|
||||||
|
|
||||||
|
stream, err := tlv.NewStream(ProduceRecordsSorted(
|
||||||
|
&n.Features,
|
||||||
|
&n.BlockHeight,
|
||||||
|
&n.NodeID,
|
||||||
|
&n.Signature,
|
||||||
|
&alias,
|
||||||
|
&color,
|
||||||
|
&ipv4,
|
||||||
|
&ipv6,
|
||||||
|
&torV3,
|
||||||
|
&dns,
|
||||||
|
)...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.Signature.Val.ForceSchnorr()
|
||||||
|
|
||||||
|
typeMap, err := stream.DecodeWithParsedTypesP2P(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := typeMap[n.Alias.TlvType()]; ok {
|
||||||
|
n.Alias = tlv.SomeRecordT(alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := typeMap[n.Color.TlvType()]; ok {
|
||||||
|
n.Color = tlv.SomeRecordT(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := typeMap[n.IPV4Addrs.TlvType()]; ok {
|
||||||
|
n.IPV4Addrs = tlv.SomeRecordT(ipv4)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := typeMap[n.IPV6Addrs.TlvType()]; ok {
|
||||||
|
n.IPV6Addrs = tlv.SomeRecordT(ipv6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := typeMap[n.TorV3Addrs.TlvType()]; ok {
|
||||||
|
n.TorV3Addrs = tlv.SomeRecordT(torV3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := typeMap[n.DNSHostName.TlvType()]; ok {
|
||||||
|
n.DNSHostName = tlv.SomeRecordT(dns)
|
||||||
|
}
|
||||||
|
|
||||||
|
n.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode serializes the target NodeAnnouncement2 into the passed io.Writer
|
||||||
|
// observing the protocol version specified.
|
||||||
|
//
|
||||||
|
// This is part of the lnwire.Message interface.
|
||||||
|
func (n *NodeAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error {
|
||||||
|
return EncodePureTLVMessage(n, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgType returns the integer uniquely identifying this message type on the
|
||||||
|
// wire.
|
||||||
|
//
|
||||||
|
// This is part of the lnwire.Message interface.
|
||||||
|
func (n *NodeAnnouncement2) MsgType() MessageType {
|
||||||
|
return MsgNodeAnnouncement2
|
||||||
|
}
|
||||||
|
|
||||||
|
// A compile-time check to ensure NodeAnnouncement2 implements the Message
|
||||||
|
// interface.
|
||||||
|
var _ Message = (*NodeAnnouncement2)(nil)
|
||||||
|
|
||||||
|
// A compile-time check to ensure NodeAnnouncement2 implements the
|
||||||
|
// PureTLVMessage interface.
|
||||||
|
var _ PureTLVMessage = (*NodeAnnouncement2)(nil)
|
||||||
|
|
||||||
|
// A compile time check to ensure ChannelAnnouncement2 implements the
|
||||||
|
// lnwire.SizeableMessage interface.
|
||||||
|
var _ SizeableMessage = (*NodeAnnouncement2)(nil)
|
||||||
|
|
||||||
|
// NodeAlias2 represents a UTF-8 encoded node alias with a maximum length of 32
|
||||||
|
// bytes.
|
||||||
|
type NodeAlias2 []byte
|
||||||
|
|
||||||
|
// Record returns a TLV record for encoding/decoding NodeAlias2.
|
||||||
|
func (n *NodeAlias2) Record() tlv.Record {
|
||||||
|
sizeFunc := func() uint64 {
|
||||||
|
return uint64(len(*n))
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.MakeDynamicRecord(
|
||||||
|
0, n, sizeFunc, nodeAlias2Encoder, nodeAlias2Decoder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateNodeAlias2 validates that the node alias is valid UTF-8 and within
|
||||||
|
// the 32-byte limit.
|
||||||
|
func ValidateNodeAlias2(alias []byte) error {
|
||||||
|
if len(alias) == 0 {
|
||||||
|
return errors.New("node alias cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(alias) > 32 {
|
||||||
|
return fmt.Errorf("node alias exceeds 32 bytes: length %d",
|
||||||
|
len(alias))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utf8.Valid(alias) {
|
||||||
|
return errors.New("node alias contains invalid UTF-8")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeAlias2Encoder encodes a NodeAlias2 as raw UTF-8 bytes.
|
||||||
|
func nodeAlias2Encoder(w io.Writer, val any, _ *[8]byte) error {
|
||||||
|
if v, ok := val.(*NodeAlias2); ok {
|
||||||
|
if err := ValidateNodeAlias2(*v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := w.Write(*v)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "NodeAlias2")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeAlias2Decoder decodes raw bytes into a NodeAlias2.
|
||||||
|
func nodeAlias2Decoder(r io.Reader, val any, _ *[8]byte, l uint64) error {
|
||||||
|
if v, ok := val.(*NodeAlias2); ok {
|
||||||
|
if l > 32 {
|
||||||
|
return fmt.Errorf("node alias exceeds 32 bytes: %d", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasBytes := make([]byte, l)
|
||||||
|
if _, err := io.ReadFull(r, aliasBytes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ValidateNodeAlias2(aliasBytes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = aliasBytes
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForDecodingErr(val, "NodeAlias2", l, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color is a custom type to represent a color.RGBA that can be encoded/decoded
|
||||||
|
// as a TLV record.
|
||||||
|
type Color color.RGBA
|
||||||
|
|
||||||
|
// Record returns a TLV record for encoding/decoding Color.
|
||||||
|
func (c *Color) Record() tlv.Record {
|
||||||
|
return tlv.MakeStaticRecord(0, c, 3, rgbEncoder, rgbDecoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// rgbEncoder encodes a Color as RGB bytes.
|
||||||
|
func rgbEncoder(w io.Writer, val any, _ *[8]byte) error {
|
||||||
|
if v, ok := val.(*Color); ok {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := WriteColorRGBA(buf, color.RGBA(*v))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = w.Write(buf.Bytes())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "Color")
|
||||||
|
}
|
||||||
|
|
||||||
|
// rgbDecoder decodes RGB bytes into a Color.
|
||||||
|
func rgbDecoder(r io.Reader, val any, _ *[8]byte, l uint64) error {
|
||||||
|
if v, ok := val.(*Color); ok {
|
||||||
|
return ReadElements(r, &v.R, &v.G, &v.B)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForDecodingErr(val, "Color", l, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4AddrEncodedSize is the number of bytes required to encode a single ipv4
|
||||||
|
// address. Four bytes are used to encode the IP address and two bytes for the
|
||||||
|
// port number.
|
||||||
|
const ipv4AddrEncodedSize = 4 + 2
|
||||||
|
|
||||||
|
// IPV4Addrs is a list of ipv4 addresses that can be encoded as a TLV record.
|
||||||
|
type IPV4Addrs []*net.TCPAddr
|
||||||
|
|
||||||
|
// Record returns a Record that can be used to encode/decode a IPV4Addrs
|
||||||
|
// to/from a TLV stream.
|
||||||
|
func (a *IPV4Addrs) Record() tlv.Record {
|
||||||
|
return tlv.MakeDynamicRecord(
|
||||||
|
0, a, a.encodedSize, ipv4AddrsEncoder, ipv4AddrsDecoder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodedSize returns the number of bytes required to encode an IPV4Addrs
|
||||||
|
// variable.
|
||||||
|
func (a *IPV4Addrs) encodedSize() uint64 {
|
||||||
|
return uint64(len(*a) * ipv4AddrEncodedSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4AddrsEncoder encodes IPv4 addresses as TLV bytes.
|
||||||
|
func ipv4AddrsEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
|
||||||
|
if v, ok := val.(*IPV4Addrs); ok {
|
||||||
|
for _, ip := range *v {
|
||||||
|
_, err := w.Write(ip.IP.To4())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var port [2]byte
|
||||||
|
binary.BigEndian.PutUint16(port[:], uint16(ip.Port))
|
||||||
|
_, err = w.Write(port[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "lnwire.IPV4Addrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4AddrsDecoder decodes TLV bytes into IPv4 addresses.
|
||||||
|
func ipv4AddrsDecoder(r io.Reader, val interface{}, _ *[8]byte,
|
||||||
|
l uint64) error {
|
||||||
|
|
||||||
|
if v, ok := val.(*IPV4Addrs); ok {
|
||||||
|
if l%(ipv4AddrEncodedSize) != 0 {
|
||||||
|
return fmt.Errorf("invalid ipv4 list encoding")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
numAddrs = int(l / ipv4AddrEncodedSize)
|
||||||
|
addrs = make([]*net.TCPAddr, 0, numAddrs)
|
||||||
|
ip [4]byte
|
||||||
|
port [2]byte
|
||||||
|
)
|
||||||
|
for len(addrs) < numAddrs {
|
||||||
|
_, err := r.Read(ip[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = r.Read(port[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addrs = append(addrs, &net.TCPAddr{
|
||||||
|
IP: ip[:],
|
||||||
|
Port: int(binary.BigEndian.Uint16(port[:])),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*v = addrs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "lnwire.IPV4Addrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPV6Addrs is a list of ipv6 addresses that can be encoded as a TLV record.
|
||||||
|
type IPV6Addrs []*net.TCPAddr
|
||||||
|
|
||||||
|
// Record returns a Record that can be used to encode/decode a IPV4Addrs
|
||||||
|
// to/from a TLV stream.
|
||||||
|
func (a *IPV6Addrs) Record() tlv.Record {
|
||||||
|
return tlv.MakeDynamicRecord(
|
||||||
|
0, a, a.encodedSize, ipv6AddrsEncoder, ipv6AddrsDecoder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv6AddrEncodedSize is the number of bytes required to encode a single ipv6
|
||||||
|
// address. Sixteen bytes are used to encode the IP address and two bytes for
|
||||||
|
// the port number.
|
||||||
|
const ipv6AddrEncodedSize = 16 + 2
|
||||||
|
|
||||||
|
// encodedSize returns the number of bytes required to encode an IPV6Addrs
|
||||||
|
// variable.
|
||||||
|
func (a *IPV6Addrs) encodedSize() uint64 {
|
||||||
|
return uint64(len(*a) * ipv6AddrEncodedSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv6AddrsEncoder encodes IPv6 addresses as TLV bytes.
|
||||||
|
func ipv6AddrsEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
|
||||||
|
if v, ok := val.(*IPV6Addrs); ok {
|
||||||
|
for _, ip := range *v {
|
||||||
|
_, err := w.Write(ip.IP.To16())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var port [2]byte
|
||||||
|
binary.BigEndian.PutUint16(port[:], uint16(ip.Port))
|
||||||
|
_, err = w.Write(port[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "lnwire.IPV6Addrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv6AddrsDecoder decodes TLV bytes into IPv6 addresses.
|
||||||
|
func ipv6AddrsDecoder(r io.Reader, val interface{}, _ *[8]byte,
|
||||||
|
l uint64) error {
|
||||||
|
|
||||||
|
if v, ok := val.(*IPV6Addrs); ok {
|
||||||
|
if l%(ipv6AddrEncodedSize) != 0 {
|
||||||
|
return fmt.Errorf("invalid ipv6 list encoding")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
numAddrs = int(l / ipv6AddrEncodedSize)
|
||||||
|
addrs = make([]*net.TCPAddr, 0, numAddrs)
|
||||||
|
ip [16]byte
|
||||||
|
port [2]byte
|
||||||
|
)
|
||||||
|
for len(addrs) < numAddrs {
|
||||||
|
_, err := r.Read(ip[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = r.Read(port[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addrs = append(addrs, &net.TCPAddr{
|
||||||
|
IP: ip[:],
|
||||||
|
Port: int(binary.BigEndian.Uint16(port[:])),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*v = addrs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "lnwire.IPV6Addrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TorV3Addrs is a list of tor v3 addresses that can be encoded as a TLV record.
|
||||||
|
type TorV3Addrs []*tor.OnionAddr
|
||||||
|
|
||||||
|
// torV3AddrEncodedSize is the number of bytes required to encode a single tor
|
||||||
|
// v3 address.
|
||||||
|
const torV3AddrEncodedSize = tor.V3DecodedLen + 2
|
||||||
|
|
||||||
|
// encodedSize returns the number of bytes required to encode an TorV3Addrs
|
||||||
|
// variable.
|
||||||
|
func (a *TorV3Addrs) encodedSize() uint64 {
|
||||||
|
return uint64(len(*a) * torV3AddrEncodedSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record returns a Record that can be used to encode/decode a IPV4Addrs
|
||||||
|
// to/from a TLV stream.
|
||||||
|
func (a *TorV3Addrs) Record() tlv.Record {
|
||||||
|
return tlv.MakeDynamicRecord(
|
||||||
|
0, a, a.encodedSize, torV3AddrsEncoder, torV3AddrsDecoder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// torV3AddrsEncoder encodes Tor v3 addresses as TLV bytes.
|
||||||
|
func torV3AddrsEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
|
||||||
|
if v, ok := val.(*TorV3Addrs); ok {
|
||||||
|
for _, addr := range *v {
|
||||||
|
encodedHostLen := tor.V3Len - tor.OnionSuffixLen
|
||||||
|
host, err := tor.Base32Encoding.DecodeString(
|
||||||
|
addr.OnionService[:encodedHostLen],
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(host) != tor.V3DecodedLen {
|
||||||
|
return fmt.Errorf("expected a tor v3 host "+
|
||||||
|
"length of %d, got: %d",
|
||||||
|
tor.V3DecodedLen, len(host))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = w.Write(host); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var port [2]byte
|
||||||
|
binary.BigEndian.PutUint16(port[:], uint16(addr.Port))
|
||||||
|
if _, err = w.Write(port[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "lnwire.TorV3Addrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// torV3AddrsDecoder decodes TLV bytes into Tor v3 addresses.
|
||||||
|
func torV3AddrsDecoder(r io.Reader, val interface{}, _ *[8]byte,
|
||||||
|
l uint64) error {
|
||||||
|
|
||||||
|
if v, ok := val.(*TorV3Addrs); ok {
|
||||||
|
if l%torV3AddrEncodedSize != 0 {
|
||||||
|
return fmt.Errorf("invalid tor v3 list encoding")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
numAddrs = int(l / torV3AddrEncodedSize)
|
||||||
|
addrs = make([]*tor.OnionAddr, 0, numAddrs)
|
||||||
|
ip [tor.V3DecodedLen]byte
|
||||||
|
p [2]byte
|
||||||
|
)
|
||||||
|
for len(addrs) < numAddrs {
|
||||||
|
_, err := r.Read(ip[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = r.Read(p[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
onionService := tor.Base32Encoding.EncodeToString(ip[:])
|
||||||
|
onionService += tor.OnionSuffix
|
||||||
|
|
||||||
|
if len(onionService) != tor.V3Len {
|
||||||
|
return fmt.Errorf("expected a tor v3 onion "+
|
||||||
|
"service length of %d, got: %d",
|
||||||
|
tor.V3Len, len(onionService))
|
||||||
|
}
|
||||||
|
|
||||||
|
port := int(binary.BigEndian.Uint16(p[:]))
|
||||||
|
addrs = append(addrs, &tor.OnionAddr{
|
||||||
|
OnionService: onionService,
|
||||||
|
Port: port,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*v = addrs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "lnwire.TorV3Addrs")
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package lnwire
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestNodeAnn2EncodeDecode tests the encoding and decoding of the
|
||||||
|
// NodeAnnouncement2 message using hardcoded byte slices.
|
||||||
|
func TestNodeAnn2EncodeDecode(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// We'll create a raw byte stream that represents a valid
|
||||||
|
// NodeAnnouncement2 message with various known and unknown fields in
|
||||||
|
// the signed TLV ranges along with the signature in the unsigned range.
|
||||||
|
rawBytes := []byte{
|
||||||
|
// Features record.
|
||||||
|
0x00, // type.
|
||||||
|
0x02, // length.
|
||||||
|
0x1, 0x2, // value.
|
||||||
|
|
||||||
|
// Color record (optional).
|
||||||
|
0x01, // type.
|
||||||
|
0x03, // length.
|
||||||
|
0xff, 0x00, 0x80, // value: RGB(255, 0, 128).
|
||||||
|
|
||||||
|
// BlockHeight record.
|
||||||
|
0x02, // type.
|
||||||
|
0x04, // length.
|
||||||
|
0x00, 0x01, 0x86, 0xa0, // value: 100000.
|
||||||
|
|
||||||
|
// Alias record (optional).
|
||||||
|
0x03, // type.
|
||||||
|
0x20, // length (32).
|
||||||
|
0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e,
|
||||||
|
0x67, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x54,
|
||||||
|
0x65, 0x73, 0x74, 0x20, 0x41, 0x6c, 0x69, 0x61,
|
||||||
|
0x73, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x21, 0x00, // value.
|
||||||
|
|
||||||
|
// NodeID record.
|
||||||
|
0x04, // type.
|
||||||
|
0x21, // length.
|
||||||
|
0x02, 0x28, 0xf2, 0xaf, 0xa, 0xbe, 0x32, 0x24, 0x3, 0x48, 0xf,
|
||||||
|
0xb3, 0xee, 0x17, 0x2f, 0x7f, 0x16, 0x1, 0xe6, 0x7d, 0x1d, 0xa6,
|
||||||
|
0xca, 0xd4, 0xb, 0x54, 0xc4, 0x46, 0x8d, 0x48, 0x23, 0x6c, 0x39,
|
||||||
|
|
||||||
|
// IPV4Addrs record (optional).
|
||||||
|
0x05, // type.
|
||||||
|
0x0c, // length (12 bytes).
|
||||||
|
0x0a, 0x00, 0x00, 0x01, 0x23, 0x28, // 10.0.0.1:9000
|
||||||
|
0x0a, 0x00, 0x00, 0x01, 0x1f, 0x90, // 10.0.0.1:8080
|
||||||
|
|
||||||
|
// IPV6Addrs record (optional).
|
||||||
|
0x07, // type.
|
||||||
|
0x12, // length.
|
||||||
|
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, // IPv6 address
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // 2001:db8::1
|
||||||
|
0x1f, 0x40, // port 8000
|
||||||
|
|
||||||
|
// TorV3Addrs record (optional).
|
||||||
|
0x09, // type.
|
||||||
|
0x25, // length (37 bytes = 1 address).
|
||||||
|
// value: 35-byte tor v3 address + 2-byte port.
|
||||||
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||||
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||||
|
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||||
|
0x21, 0x22, 0x23,
|
||||||
|
0x23, 0x28, // port 9000.
|
||||||
|
|
||||||
|
// DNSHostName record (optional).
|
||||||
|
0x0b, // type (11).
|
||||||
|
0x17, // length (23).
|
||||||
|
0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e,
|
||||||
|
0x67, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, // value.
|
||||||
|
0x65, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
|
0x23, 0x28, // port 9000.
|
||||||
|
|
||||||
|
// Signature.
|
||||||
|
0xa0, // type.
|
||||||
|
0x40, // length.
|
||||||
|
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
|
||||||
|
0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||||
|
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||||
|
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
||||||
|
0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
|
||||||
|
0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
|
||||||
|
0x3f, // value.
|
||||||
|
}
|
||||||
|
secondSignedRangeType := new(bytes.Buffer)
|
||||||
|
var buf [8]byte
|
||||||
|
err := tlv.WriteVarInt(
|
||||||
|
secondSignedRangeType, pureTLVSignedSecondRangeStart+1, &buf,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
rawBytes = append(rawBytes, secondSignedRangeType.Bytes()...) // type.
|
||||||
|
rawBytes = append(rawBytes, []byte{
|
||||||
|
0x02, // length.
|
||||||
|
0x79, 0x79, // value.
|
||||||
|
}...)
|
||||||
|
|
||||||
|
// Now, create a new empty message and decode the raw bytes into it.
|
||||||
|
msg := &NodeAnnouncement2{}
|
||||||
|
r := bytes.NewReader(rawBytes)
|
||||||
|
err = msg.Decode(r, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Next, encode the message back into a new byte buffer.
|
||||||
|
var b bytes.Buffer
|
||||||
|
err = msg.Encode(&b, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// The re-encoded bytes should be exactly the same as the original raw
|
||||||
|
// bytes.
|
||||||
|
require.Equal(t, rawBytes, b.Bytes())
|
||||||
|
}
|
||||||
@@ -5,12 +5,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"math"
|
"math"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/fn/v2"
|
"github.com/lightningnetwork/lnd/fn/v2"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
|
"github.com/lightningnetwork/lnd/tor"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"pgregory.net/rapid"
|
"pgregory.net/rapid"
|
||||||
)
|
)
|
||||||
@@ -1231,6 +1233,10 @@ func (ks *KickoffSig) RandTestMessage(t *rapid.T) Message {
|
|||||||
// lnwire.TestMessage interface.
|
// lnwire.TestMessage interface.
|
||||||
var _ TestMessage = (*NodeAnnouncement1)(nil)
|
var _ TestMessage = (*NodeAnnouncement1)(nil)
|
||||||
|
|
||||||
|
// A compile time check to ensure NodeAnnouncement2 implements the
|
||||||
|
// lnwire.TestMessage interface.
|
||||||
|
var _ TestMessage = (*NodeAnnouncement2)(nil)
|
||||||
|
|
||||||
// RandTestMessage populates the message with random data suitable for testing.
|
// RandTestMessage populates the message with random data suitable for testing.
|
||||||
// It uses the rapid testing framework to generate random values.
|
// It uses the rapid testing framework to generate random values.
|
||||||
//
|
//
|
||||||
@@ -1262,6 +1268,131 @@ func (a *NodeAnnouncement1) RandTestMessage(t *rapid.T) Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandTestMessage populates the message with random data suitable for testing.
|
||||||
|
// It uses the rapid testing framework to generate random values.
|
||||||
|
//
|
||||||
|
// This is part of the TestMessage interface.
|
||||||
|
func (n *NodeAnnouncement2) RandTestMessage(t *rapid.T) Message {
|
||||||
|
features := RandFeatureVector(t)
|
||||||
|
blockHeight := uint32(rapid.IntRange(0, 1000000).Draw(t, "blockHeight"))
|
||||||
|
|
||||||
|
// Generate random compressed public key for node ID
|
||||||
|
pubKey := RandPubKey(t)
|
||||||
|
var nodeID [33]byte
|
||||||
|
copy(nodeID[:], pubKey.SerializeCompressed())
|
||||||
|
|
||||||
|
msg := &NodeAnnouncement2{
|
||||||
|
Features: tlv.NewRecordT[tlv.TlvType0](*features),
|
||||||
|
BlockHeight: tlv.NewPrimitiveRecord[tlv.TlvType2](
|
||||||
|
blockHeight,
|
||||||
|
),
|
||||||
|
NodeID: tlv.NewPrimitiveRecord[tlv.TlvType4](nodeID),
|
||||||
|
ExtraSignedFields: make(map[uint64][]byte),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Signature.Val = RandSignature(t)
|
||||||
|
msg.Signature.Val.ForceSchnorr()
|
||||||
|
|
||||||
|
// Test optional fields one by one
|
||||||
|
if rapid.Bool().Draw(t, "includeColor") {
|
||||||
|
rgbColor := Color{
|
||||||
|
R: uint8(rapid.IntRange(0, 255).Draw(t, "rgbR")),
|
||||||
|
G: uint8(rapid.IntRange(0, 255).Draw(t, "rgbG")),
|
||||||
|
B: uint8(rapid.IntRange(0, 255).Draw(t, "rgbB")),
|
||||||
|
}
|
||||||
|
colorRecord := tlv.ZeroRecordT[tlv.TlvType1, Color]()
|
||||||
|
colorRecord.Val = rgbColor
|
||||||
|
msg.Color = tlv.SomeRecordT(colorRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rapid.Bool().Draw(t, "includeAlias") {
|
||||||
|
aliasBytes := RandNodeAlias2(t)
|
||||||
|
aliasRecord := tlv.ZeroRecordT[tlv.TlvType3, NodeAlias2]()
|
||||||
|
aliasRecord.Val = aliasBytes
|
||||||
|
msg.Alias = tlv.SomeRecordT(aliasRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rapid.Bool().Draw(t, "includeIPV4Addrs") {
|
||||||
|
ipv4Addrs := make(IPV4Addrs, 1)
|
||||||
|
ip := make(net.IP, 4)
|
||||||
|
ip[0] = uint8(rapid.IntRange(1, 223).Draw(t, "ip4_0"))
|
||||||
|
ip[1] = uint8(rapid.IntRange(0, 255).Draw(t, "ip4_1"))
|
||||||
|
ip[2] = uint8(rapid.IntRange(0, 255).Draw(t, "ip4_2"))
|
||||||
|
ip[3] = uint8(rapid.IntRange(1, 254).Draw(t, "ip4_3"))
|
||||||
|
|
||||||
|
ipv4Addrs[0] = &net.TCPAddr{
|
||||||
|
IP: ip,
|
||||||
|
Port: rapid.IntRange(1, 65535).Draw(t, "port4"),
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv4Record := tlv.ZeroRecordT[tlv.TlvType5, IPV4Addrs]()
|
||||||
|
ipv4Record.Val = ipv4Addrs
|
||||||
|
msg.IPV4Addrs = tlv.SomeRecordT(ipv4Record)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rapid.Bool().Draw(t, "includeIPV6Addrs") {
|
||||||
|
ipv6Addrs := make(IPV6Addrs, 1)
|
||||||
|
ip := make(net.IP, 16)
|
||||||
|
// Generate random IPv6 address.
|
||||||
|
for j := 0; j < 16; j++ {
|
||||||
|
ip[j] = uint8(rapid.IntRange(0, 255).Draw(
|
||||||
|
t, fmt.Sprintf("ip6_%d", j)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6Addrs[0] = &net.TCPAddr{
|
||||||
|
IP: ip,
|
||||||
|
Port: rapid.IntRange(1, 65535).Draw(t, "port6"),
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6Record := tlv.ZeroRecordT[tlv.TlvType7, IPV6Addrs]()
|
||||||
|
ipv6Record.Val = ipv6Addrs
|
||||||
|
msg.IPV6Addrs = tlv.SomeRecordT(ipv6Record)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rapid.Bool().Draw(t, "includeTorV3Addrs") {
|
||||||
|
torV3Addrs := make(TorV3Addrs, 1)
|
||||||
|
onionBytes := rapid.SliceOfN(rapid.Byte(), 35, 35).Draw(
|
||||||
|
t, "onion",
|
||||||
|
)
|
||||||
|
onionService := tor.Base32Encoding.EncodeToString(onionBytes) +
|
||||||
|
tor.OnionSuffix
|
||||||
|
|
||||||
|
torV3Addrs[0] = &tor.OnionAddr{
|
||||||
|
OnionService: onionService,
|
||||||
|
Port: rapid.IntRange(1, 65535).Draw(
|
||||||
|
t, "torPort",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
torV3Record := tlv.ZeroRecordT[tlv.TlvType9, TorV3Addrs]()
|
||||||
|
torV3Record.Val = torV3Addrs
|
||||||
|
msg.TorV3Addrs = tlv.SomeRecordT(torV3Record)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rapid.Bool().Draw(t, "includeDNSHostName") {
|
||||||
|
// Generate a valid DNS hostname.
|
||||||
|
hostname := genValidHostname(t)
|
||||||
|
port := rapid.Uint16Range(1, 65535).Draw(t, "dnsPort")
|
||||||
|
|
||||||
|
dnsAddr := DNSAddress{
|
||||||
|
Hostname: hostname,
|
||||||
|
Port: port,
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsRecord := tlv.ZeroRecordT[tlv.TlvType11, DNSAddress]()
|
||||||
|
dnsRecord.Val = dnsAddr
|
||||||
|
msg.DNSHostName = tlv.SomeRecordT(dnsRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
randRecs, _ := RandSignedRangeRecords(t)
|
||||||
|
if len(randRecs) > 0 {
|
||||||
|
msg.ExtraSignedFields = ExtraSignedFields(randRecs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
// A compile time check to ensure OpenChannel implements the TestMessage
|
// A compile time check to ensure OpenChannel implements the TestMessage
|
||||||
// interface.
|
// interface.
|
||||||
var _ TestMessage = (*OpenChannel)(nil)
|
var _ TestMessage = (*OpenChannel)(nil)
|
||||||
|
|||||||
@@ -152,6 +152,19 @@ func RandNodeAlias(t *rapid.T) NodeAlias {
|
|||||||
return alias
|
return alias
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandNodeAlias2 generates a random node alias that is compatible with
|
||||||
|
// NodeAlias2 validation (non-empty, max 32 bytes, valid UTF-8).
|
||||||
|
func RandNodeAlias2(t *rapid.T) NodeAlias2 {
|
||||||
|
// Ensure length is at least 1 to satisfy NodeAlias2 validation
|
||||||
|
aliasLength := rapid.IntRange(1, 32).Draw(t, "aliasLength")
|
||||||
|
|
||||||
|
aliasBytes := rapid.SliceOfN(
|
||||||
|
rapid.SampledFrom([]rune(charset)), aliasLength, aliasLength,
|
||||||
|
).Draw(t, "alias")
|
||||||
|
|
||||||
|
return []byte(string(aliasBytes))
|
||||||
|
}
|
||||||
|
|
||||||
// RandNetAddrs generates random network addresses.
|
// RandNetAddrs generates random network addresses.
|
||||||
func RandNetAddrs(t *rapid.T) []net.Addr {
|
func RandNetAddrs(t *rapid.T) []net.Addr {
|
||||||
numAddresses := rapid.IntRange(0, 5).Draw(t, "numAddresses")
|
numAddresses := rapid.IntRange(0, 5).Draw(t, "numAddresses")
|
||||||
|
|||||||
Reference in new issue
Block a user