lnwire: update NodeAnnouncement to handle multiple addresses

This commit modifies address handling in the NodeAnnouncement struct,
switching from net.TCPAddr to []net.Addr. This enables more flexible
address handling with multiple types and multiple addresses for each
node. This commit addresses the first part of issue #131 .
This commit is contained in:
bryanvu authored and Olaoluwa Osuntokun committed 2017-03-29 12:03:43 -07:00
1 parent 65c15c4cb0
commit 9ffac9eae1
16 files changed
+594 -397

No files matched your search

+80 -17
View File
@@ -50,6 +50,16 @@ func (c CreditsAmount) ToSatoshi() int64 {
return int64(c / 1000)
}
// addressType specifies the network protocol and version that should be used
// when connecting to a node at a particular address.
type addressType uint8
const (
tcp4Addr addressType = 1
tcp6Addr addressType = 2
onionAddr addressType = 3
)
// writeElement is a one-stop shop to write the big endian representation of
// any element which is to be serialized for the wire protocol. The passed
// io.Writer should be backed by an appropriatly sized byte slice, or be able
@@ -292,16 +302,46 @@ func writeElement(w io.Writer, element interface{}) error {
}
case *net.TCPAddr:
var ip [16]byte
copy(ip[:], e.IP.To16())
if _, err := w.Write(ip[:]); err != nil {
if e.IP.To4() != nil {
var descriptor [1]byte
descriptor[0] = uint8(tcp4Addr)
if _, err := w.Write(descriptor[:]); err != nil {
return err
}
var ip [4]byte
copy(ip[:], e.IP.To4())
if _, err := w.Write(ip[:]); err != nil {
return err
}
} else {
var descriptor [1]byte
descriptor[0] = uint8(tcp6Addr)
if _, err := w.Write(descriptor[:]); err != nil {
return err
}
var ip [16]byte
copy(ip[:], e.IP.To16())
if _, err := w.Write(ip[:]); err != nil {
return err
}
}
var port [2]byte
binary.BigEndian.PutUint16(port[:], uint16(e.Port))
if _, err := w.Write(port[:]); err != nil {
return err
}
case []net.Addr:
// Write out the number of addresses.
if err := writeElement(w, uint16(len(e))); err != nil {
return err
}
var port [4]byte
binary.BigEndian.PutUint32(port[:], uint32(e.Port))
if _, err := w.Write(port[:]); err != nil {
return err
// Append the actual addresses.
for _, address := range e {
if err := writeElement(w, address); err != nil {
return err
}
}
case RGB:
err := writeElements(w,
@@ -578,21 +618,44 @@ func readElement(r io.Reader, element interface{}) error {
TxPosition: binary.BigEndian.Uint16(txPosition[:]),
}
case **net.TCPAddr:
var ip [16]byte
if _, err = io.ReadFull(r, ip[:]); err != nil {
case *[]net.Addr:
var addresses []net.Addr
var numAddrs [2]byte
if _, err = io.ReadFull(r, numAddrs[:]); err != nil {
return err
}
var port [4]byte
if _, err = io.ReadFull(r, port[:]); err != nil {
return err
}
for i := 0; i < int(binary.BigEndian.Uint16(numAddrs[:])); i++ {
var descriptor [1]byte
if _, err = io.ReadFull(r, descriptor[:]); err != nil {
return err
}
*e = &net.TCPAddr{
IP: (net.IP)(ip[:]),
Port: int(binary.BigEndian.Uint32(port[:])),
address := &net.TCPAddr{}
switch descriptor[0] {
case 1:
var ip [4]byte
if _, err = io.ReadFull(r, ip[:]); err != nil {
return err
}
address.IP = (net.IP)(ip[:])
case 2:
var ip [16]byte
if _, err = io.ReadFull(r, ip[:]); err != nil {
return err
}
address.IP = (net.IP)(ip[:])
}
var port [2]byte
if _, err = io.ReadFull(r, port[:]); err != nil {
return err
}
address.Port = int(binary.BigEndian.Uint16(port[:]))
addresses = append(addresses, address)
}
*e = addresses
case *RGB:
err := readElements(r,
&e.red,
+3 -1
View File
@@ -56,7 +56,9 @@ var (
someSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
someSigBytes = someSig.Serialize()
someAddress = &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}
someAddress = &net.TCPAddr{IP: (net.IP)([]byte{0x7f, 0x0, 0x0, 0x1}), Port: 8333}
someOtherAddress, _ = net.ResolveTCPAddr("tcp", "[2001:db8:85a3:0:0:8a2e:370:7334]:80")
someAddresses = []net.Addr{someAddress, someOtherAddress}
maxUint32 uint32 = (1 << 32) - 1
maxUint24 uint32 = (1 << 24) - 1
+16 -43
View File
@@ -87,27 +87,19 @@ type NodeAnnouncement struct {
// announcements.
Timestamp uint32
// Address includes two specification fields: 'ipv6' and
// 'port' on which the node is accepting incoming connections.
Address *net.TCPAddr
// NodeID is a public key which is used as node
// identification.
// NodeID is a public key which is used as node identification.
NodeID *btcec.PublicKey
// RGBColor is used to customize their node's appearance in
// maps and graphs
RGBColor RGB
// TODO(roasbeef): add the global features here
// pad is used to reserve to additional bytes for future
// usage.
pad uint16
// Alias is used to customize their node's appearance in maps
// and graphs
// Alias is used to customize their node's appearance in maps and graphs
Alias Alias
// Address includes two specification fields: 'ipv6' and 'port' on which
// the node is accepting incoming connections.
Addresses []net.Addr
}
// A compile time check to ensure NodeAnnouncement implements the
@@ -131,27 +123,24 @@ func (a *NodeAnnouncement) Decode(r io.Reader, pver uint32) error {
return readElements(r,
&a.Signature,
&a.Timestamp,
&a.Address,
&a.NodeID,
&a.RGBColor,
&a.pad,
&a.Alias,
&a.Addresses,
)
}
// Encode serializes the target NodeAnnouncement into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (a *NodeAnnouncement) Encode(w io.Writer, pver uint32) error {
return writeElements(w,
a.Signature,
a.Timestamp,
a.Address,
a.NodeID,
a.RGBColor,
a.pad,
a.Alias,
a.Addresses,
)
}
@@ -168,34 +157,19 @@ func (a *NodeAnnouncement) Command() uint32 {
//
// This is part of the lnwire.Message interface.
func (a *NodeAnnouncement) MaxPayloadLength(pver uint32) uint32 {
var length uint32
// Signature - 64 bytes
length += 64
// Timestamp - 4 bytes
length += 4
// Ipv6 - 16 bytes
length += 16
// Port - 4 bytes
length += 4
// NodeID - 33 bytes
length += 33
// RGBColor - 3 bytes
length += 3
// pad - 2 bytes
length += 2
// Alias - 32 bytes
length += 32
// NumAddresses - 2 bytes
// AddressDescriptor - 1 byte
// Ipv4 - 4 bytes (optional)
// Ipv6 - 16 bytes (optional)
// Port - 2 bytes (optional)
// 158
return length
// Base size, 140, but can be variable due to multiple addresses
return 8192
}
// DataToSign returns the part of the message that should be signed.
@@ -205,11 +179,10 @@ func (a *NodeAnnouncement) DataToSign() ([]byte, error) {
var w bytes.Buffer
err := writeElements(&w,
a.Timestamp,
a.Address,
a.NodeID,
a.RGBColor,
a.pad,
a.Alias,
a.Addresses,
)
if err != nil {
return nil, err
+18 -11
View File
@@ -13,11 +13,10 @@ func TestNodeAnnouncementEncodeDecode(t *testing.T) {
cua := &NodeAnnouncement{
Signature: someSig,
Timestamp: maxUint32,
Address: someAddress,
NodeID: pubKey,
RGBColor: someRGB,
pad: maxUint16,
Alias: someAlias,
Addresses: someAddresses,
}
// Next encode the NA message into an empty bytes buffer.
@@ -39,7 +38,7 @@ func TestNodeAnnouncementEncodeDecode(t *testing.T) {
}
}
func TestNodeAnnoucementValidation(t *testing.T) {
func TestNodeAnnouncementValidation(t *testing.T) {
getKeys := func(s string) (*btcec.PrivateKey, *btcec.PublicKey) {
return btcec.PrivKeyFromBytes(btcec.S256(), []byte(s))
}
@@ -47,13 +46,11 @@ func TestNodeAnnoucementValidation(t *testing.T) {
nodePrivKey, nodePubKey := getKeys("node-id-1")
var hash []byte
na := &NodeAnnouncement{
Timestamp: maxUint32,
Address: someAddress,
Addresses: someAddresses,
NodeID: nodePubKey,
RGBColor: someRGB,
pad: maxUint16,
Alias: someAlias,
}
@@ -68,15 +65,14 @@ func TestNodeAnnoucementValidation(t *testing.T) {
}
}
func TestNodeAnnoucementPayloadLength(t *testing.T) {
func TestNodeAnnouncementPayloadLength(t *testing.T) {
na := &NodeAnnouncement{
Signature: someSig,
Timestamp: maxUint32,
Address: someAddress,
NodeID: pubKey,
RGBColor: someRGB,
pad: maxUint16,
Alias: someAlias,
Addresses: someAddresses,
}
var b bytes.Buffer
@@ -85,8 +81,19 @@ func TestNodeAnnoucementPayloadLength(t *testing.T) {
}
serializedLength := uint32(b.Len())
if serializedLength != na.MaxPayloadLength(0) {
if serializedLength != 164 {
t.Fatalf("payload length estimate is incorrect: expected %v "+
"got %v", serializedLength, na.MaxPayloadLength(0))
"got %v", 164, serializedLength)
}
if na.MaxPayloadLength(0) != 8192 {
t.Fatalf("max payload length doesn't match: expected 8192, got %v",
na.MaxPayloadLength(0))
}
}
func TestValidateAlias(t *testing.T) {
if err := someAlias.Validate(); err != nil {
t.Fatalf("alias was invalid: %v", err)
}
}