231 lines
5.1 KiB
Go
231 lines
5.1 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/go-errors/errors"
|
|
"github.com/roasbeef/btcd/btcec"
|
|
"github.com/roasbeef/btcd/wire"
|
|
"io"
|
|
"net"
|
|
)
|
|
|
|
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 identificator.
|
|
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 - 2 bytes
|
|
length += 2
|
|
|
|
// NodeID - 32 bytes
|
|
length += 32
|
|
|
|
// RGBColor - 3 bytes
|
|
length += 3
|
|
|
|
// pad - 2 bytes
|
|
length += 2
|
|
|
|
// Alias - 32 bytes
|
|
length += 32
|
|
|
|
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
|
|
}
|