lnd/lnwire/node_announcement.go

233 lines
5.1 KiB
Go

package lnwire
import (
"bytes"
"fmt"
"io"
"net"
"github.com/go-errors/errors"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
)
var (
startPort uint16 = 1024
endPort uint16 = 49151
aliasSpecLen = 21
)
// RGB is used to represent the color.
type RGB struct {
red uint8
green uint8
blue uint8
}
// Alias a hex encoded UTF-8 string that may be displayed
// as an alternative to the node's ID. Notice that aliases are not
// unique and may be freely chosen by the node operators.
type Alias [32]byte
// NewAlias create the alias from string and also checks spec requirements.
func NewAlias(s string) (Alias, error) {
var a Alias
data := []byte(s)
if len(data) > aliasSpecLen {
return a, errors.Errorf("alias too long the size "+
"must be less than %v", aliasSpecLen)
}
copy(a[:], data)
return a, nil
}
func (a *Alias) String() string {
return string(a[:])
}
// Validate check that alias data lenght is lower than spec size.
func (a *Alias) Validate() error {
nonzero := len(a)
for a[nonzero-1] == 0 && nonzero > 0 {
nonzero--
}
if nonzero > aliasSpecLen {
return errors.New("alias should be less then 21 bytes")
}
return nil
}
// NodeAnnouncement message is used to announce the presence of a lightning node
// and signal that the node is accepting incoming connections.
type NodeAnnouncement struct {
// Signature is used to prove the ownership of node id.
Signature *btcec.Signature
// Timestamp allows ordering in the case of multiple 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 *btcec.PublicKey
// RGBColor is used to customize their node's appearance in maps and graphs
RGBColor RGB
// 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 Alias
}
// A compile time check to ensure NodeAnnouncement implements the
// lnwire.Message interface.
var _ Message = (*NodeAnnouncement)(nil)
// Validate performs any necessary sanity checks to ensure all fields present
// on the NodeAnnouncement are valid.
//
// This is part of the lnwire.Message interface.
func (a *NodeAnnouncement) Validate() error {
if err := a.Alias.Validate(); err != nil {
return err
}
data, err := a.DataToSign()
if err != nil {
return err
}
dataHash := wire.DoubleSha256(data)
if !a.Signature.Verify(dataHash, a.NodeID) {
return errors.New("can't check the node annoucement signature")
}
return nil
}
// Decode deserializes a serialized NodeAnnouncement stored in the
// passed io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *NodeAnnouncement) Decode(r io.Reader, pver uint32) error {
err := readElements(r,
&c.Signature,
&c.Timestamp,
&c.Address,
&c.NodeID,
&c.RGBColor,
&c.pad,
&c.Alias,
)
if err != nil {
return err
}
return nil
}
// Encode serializes the target NodeAnnouncement into the passed
// io.Writer observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *NodeAnnouncement) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.Signature,
c.Timestamp,
c.Address,
c.NodeID,
c.RGBColor,
c.pad,
c.Alias,
)
if err != nil {
return err
}
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *NodeAnnouncement) Command() uint32 {
return CmdNodeAnnoucmentMessage
}
// MaxPayloadLength returns the maximum allowed payload size for this message
// observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *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
// 158
return length
}
// String returns the string representation of the target NodeAnnouncement.
//
// This is part of the lnwire.Message interface.
func (c *NodeAnnouncement) String() string {
return fmt.Sprintf("\n--- Begin NodeAnnouncement ---\n") +
fmt.Sprintf("Signature:\t\t%v\n", c.Signature) +
fmt.Sprintf("Timestamp:\t\t%v\n", c.Timestamp) +
fmt.Sprintf("Address:\t\t%v\n", c.Address.String()) +
fmt.Sprintf("NodeID:\t\t%v\n", c.NodeID) +
fmt.Sprintf("RGBColor:\t\t%v\n", c.RGBColor) +
fmt.Sprintf("Alias:\t\t%v\n", c.Alias) +
fmt.Sprintf("--- End NodeAnnouncement ---\n")
}
// dataToSign...
func (c *NodeAnnouncement) DataToSign() ([]byte, error) {
// We should not include the signatures itself.
var w bytes.Buffer
err := writeElements(&w,
c.Timestamp,
c.Address,
c.NodeID,
c.RGBColor,
c.pad,
c.Alias,
)
if err != nil {
return nil, err
}
return w.Bytes(), nil
}