2015-12-28 14:24:16 +03:00
|
|
|
package lnwire
|
|
|
|
|
2017-02-23 22:56:47 +03:00
|
|
|
// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go
|
|
|
|
|
2015-12-28 14:24:16 +03:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2015-12-31 19:38:33 +03:00
|
|
|
|
2016-05-15 17:17:44 +03:00
|
|
|
"github.com/roasbeef/btcd/wire"
|
2015-12-31 19:38:33 +03:00
|
|
|
)
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// MessageHeaderSize is the number of bytes in a lightning message header.
|
|
|
|
// The bytes are allocated as follows: network magic 4 bytes + command 4
|
|
|
|
// bytes + payload length 4 bytes. Note that a checksum is omitted as lightning
|
|
|
|
// messages are assumed to be transmitted over an AEAD secured connection which
|
|
|
|
// provides integrity over the entire message.
|
2015-12-28 14:24:16 +03:00
|
|
|
const MessageHeaderSize = 12
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// MaxMessagePayload is the maximum bytes a message can be regardless of other
|
|
|
|
// individual limits imposed by messages themselves.
|
2016-01-17 04:14:35 +03:00
|
|
|
const MaxMessagePayload = 1024 * 1024 * 32 // 32MB
|
2015-12-28 14:24:16 +03:00
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Commands used in lightning message headers which detail the type of message.
|
2017-02-10 02:28:32 +03:00
|
|
|
// TODO(roasbeef): update with latest type numbering from spec
|
2015-12-28 14:24:16 +03:00
|
|
|
const (
|
2017-02-16 15:31:19 +03:00
|
|
|
CmdInit = uint32(1)
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Commands for opening a channel funded by one party (single funder).
|
|
|
|
CmdSingleFundingRequest = uint32(100)
|
|
|
|
CmdSingleFundingResponse = uint32(110)
|
|
|
|
CmdSingleFundingComplete = uint32(120)
|
|
|
|
CmdSingleFundingSignComplete = uint32(130)
|
2017-01-31 05:45:28 +03:00
|
|
|
|
|
|
|
// Command for locking a funded channel
|
|
|
|
CmdFundingLocked = uint32(200)
|
2016-05-23 23:49:10 +03:00
|
|
|
|
|
|
|
// Commands for the workflow of cooperatively closing an active channel.
|
2015-12-31 12:19:54 +03:00
|
|
|
CmdCloseRequest = uint32(300)
|
|
|
|
CmdCloseComplete = uint32(310)
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Commands for negotiating HTLCs.
|
2017-02-16 15:08:34 +03:00
|
|
|
CmdUpdateAddHTLC = uint32(1000)
|
2017-02-16 15:34:09 +03:00
|
|
|
CmdUpdateFufillHTLC = uint32(1010)
|
2017-02-16 15:25:36 +03:00
|
|
|
CmdUpdateFailHTLC = uint32(1020)
|
2016-01-05 19:19:22 +03:00
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Commands for modifying commitment transactions.
|
2017-02-16 15:04:58 +03:00
|
|
|
CmdCommitSig = uint32(2000)
|
2017-02-10 02:28:32 +03:00
|
|
|
CmdRevokeAndAck = uint32(2010)
|
2016-01-05 19:53:42 +03:00
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Commands for reporting protocol errors.
|
2017-04-17 01:23:40 +03:00
|
|
|
CmdError = uint32(4000)
|
2016-11-11 04:09:14 +03:00
|
|
|
|
2016-12-07 18:46:22 +03:00
|
|
|
// Commands for discovery service.
|
2017-03-27 18:22:37 +03:00
|
|
|
CmdChannelAnnouncement = uint32(5000)
|
|
|
|
CmdChannelUpdateAnnouncement = uint32(5010)
|
|
|
|
CmdNodeAnnouncement = uint32(5020)
|
|
|
|
CmdAnnounceSignatures = uint32(5030)
|
2016-12-07 18:46:22 +03:00
|
|
|
|
2016-11-11 04:09:14 +03:00
|
|
|
// Commands for connection keep-alive.
|
2016-12-07 18:46:22 +03:00
|
|
|
CmdPing = uint32(6000)
|
|
|
|
CmdPong = uint32(6010)
|
2015-12-28 14:24:16 +03:00
|
|
|
)
|
|
|
|
|
2017-01-17 05:03:34 +03:00
|
|
|
// UnknownMessage is an implementation of the error interface that allows the
|
|
|
|
// creation of an error in response to an unknown message.
|
|
|
|
type UnknownMessage struct {
|
|
|
|
messageType uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error returns a human readable string describing the error.
|
|
|
|
//
|
|
|
|
// This is part of the error interface.
|
|
|
|
func (u *UnknownMessage) Error() string {
|
|
|
|
return fmt.Sprintf("unable to parse message of unknown type: %v",
|
|
|
|
u.messageType)
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Message is an interface that defines a lightning wire protocol message. The
|
|
|
|
// interface is general in order to allow implementing types full control over
|
|
|
|
// the representation of its data.
|
2015-12-28 14:24:16 +03:00
|
|
|
type Message interface {
|
2016-05-23 23:49:10 +03:00
|
|
|
Decode(io.Reader, uint32) error
|
|
|
|
Encode(io.Writer, uint32) error
|
|
|
|
Command() uint32
|
|
|
|
MaxPayloadLength(uint32) uint32
|
|
|
|
Validate() error
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// makeEmptyMessage creates a new empty message of the proper concrete type
|
|
|
|
// based on the command ID.
|
2015-12-28 14:24:16 +03:00
|
|
|
func makeEmptyMessage(command uint32) (Message, error) {
|
|
|
|
var msg Message
|
|
|
|
|
|
|
|
switch command {
|
2017-02-16 15:31:19 +03:00
|
|
|
case CmdInit:
|
|
|
|
msg = &Init{}
|
2016-05-23 23:49:10 +03:00
|
|
|
case CmdSingleFundingRequest:
|
|
|
|
msg = &SingleFundingRequest{}
|
|
|
|
case CmdSingleFundingResponse:
|
|
|
|
msg = &SingleFundingResponse{}
|
|
|
|
case CmdSingleFundingComplete:
|
|
|
|
msg = &SingleFundingComplete{}
|
|
|
|
case CmdSingleFundingSignComplete:
|
|
|
|
msg = &SingleFundingSignComplete{}
|
2017-01-31 05:45:28 +03:00
|
|
|
case CmdFundingLocked:
|
|
|
|
msg = &FundingLocked{}
|
2015-12-31 13:42:25 +03:00
|
|
|
case CmdCloseRequest:
|
|
|
|
msg = &CloseRequest{}
|
|
|
|
case CmdCloseComplete:
|
|
|
|
msg = &CloseComplete{}
|
2017-02-16 15:08:34 +03:00
|
|
|
case CmdUpdateAddHTLC:
|
|
|
|
msg = &UpdateAddHTLC{}
|
2017-02-16 15:25:36 +03:00
|
|
|
case CmdUpdateFailHTLC:
|
|
|
|
msg = &UpdateFailHTLC{}
|
2017-02-16 15:34:09 +03:00
|
|
|
case CmdUpdateFufillHTLC:
|
|
|
|
msg = &UpdateFufillHTLC{}
|
2017-02-16 15:04:58 +03:00
|
|
|
case CmdCommitSig:
|
|
|
|
msg = &CommitSig{}
|
2017-02-10 02:28:32 +03:00
|
|
|
case CmdRevokeAndAck:
|
|
|
|
msg = &RevokeAndAck{}
|
2017-04-17 01:23:40 +03:00
|
|
|
case CmdError:
|
|
|
|
msg = &Error{}
|
2017-03-27 18:22:37 +03:00
|
|
|
case CmdChannelAnnouncement:
|
2016-12-07 18:46:22 +03:00
|
|
|
msg = &ChannelAnnouncement{}
|
2017-03-27 18:22:37 +03:00
|
|
|
case CmdChannelUpdateAnnouncement:
|
2016-12-07 18:46:22 +03:00
|
|
|
msg = &ChannelUpdateAnnouncement{}
|
2017-03-27 18:22:37 +03:00
|
|
|
case CmdNodeAnnouncement:
|
2016-12-07 18:46:22 +03:00
|
|
|
msg = &NodeAnnouncement{}
|
2016-11-11 04:09:14 +03:00
|
|
|
case CmdPing:
|
|
|
|
msg = &Ping{}
|
2017-03-27 18:07:18 +03:00
|
|
|
case CmdAnnounceSignatures:
|
|
|
|
msg = &AnnounceSignatures{}
|
2016-11-11 04:09:14 +03:00
|
|
|
case CmdPong:
|
|
|
|
msg = &Pong{}
|
2015-12-28 14:24:16 +03:00
|
|
|
default:
|
2015-12-30 16:38:57 +03:00
|
|
|
return nil, fmt.Errorf("unhandled command [%d]", command)
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// messageHeader represents the header structure for all lightning protocol
|
|
|
|
// messages.
|
2015-12-28 14:24:16 +03:00
|
|
|
type messageHeader struct {
|
2016-05-23 23:49:10 +03:00
|
|
|
// magic represents Which Blockchain Technology(TM) to use.
|
2016-01-17 04:14:35 +03:00
|
|
|
// NOTE(j): We don't need to worry about the magic overlapping with
|
|
|
|
// bitcoin since this is inside encrypted comms anyway, but maybe we
|
|
|
|
// should use the XOR (^wire.TestNet3) just in case???
|
2016-05-23 23:49:10 +03:00
|
|
|
magic wire.BitcoinNet // 4 bytes
|
|
|
|
command uint32 // 4 bytes
|
|
|
|
length uint32 // 4 bytes
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// readMessageHeader reads a lightning protocol message header from r.
|
2015-12-28 14:24:16 +03:00
|
|
|
func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
|
2016-05-23 23:49:10 +03:00
|
|
|
// As the message header is a fixed size structure, read bytes for the
|
|
|
|
// entire header at once.
|
2015-12-28 14:24:16 +03:00
|
|
|
var headerBytes [MessageHeaderSize]byte
|
|
|
|
n, err := io.ReadFull(r, headerBytes[:])
|
|
|
|
if err != nil {
|
|
|
|
return n, nil, err
|
|
|
|
}
|
|
|
|
hr := bytes.NewReader(headerBytes[:])
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Create and populate the message header from the raw header bytes.
|
2015-12-28 14:24:16 +03:00
|
|
|
hdr := messageHeader{}
|
2015-12-31 10:34:40 +03:00
|
|
|
err = readElements(hr,
|
2015-12-28 14:24:16 +03:00
|
|
|
&hdr.magic,
|
|
|
|
&hdr.command,
|
|
|
|
&hdr.length)
|
|
|
|
if err != nil {
|
|
|
|
return n, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, &hdr, nil
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// discardInput reads n bytes from reader r in chunks and discards the read
|
|
|
|
// bytes. This is used to skip payloads when various errors occur and helps
|
|
|
|
// prevent rogue nodes from causing massive memory allocation through forging
|
|
|
|
// header length.
|
2015-12-28 14:24:16 +03:00
|
|
|
func discardInput(r io.Reader, n uint32) {
|
2016-01-17 04:14:35 +03:00
|
|
|
maxSize := uint32(10 * 1024) // 10k at a time
|
2015-12-28 14:24:16 +03:00
|
|
|
numReads := n / maxSize
|
|
|
|
bytesRemaining := n % maxSize
|
|
|
|
if n > 0 {
|
|
|
|
buf := make([]byte, maxSize)
|
|
|
|
for i := uint32(0); i < numReads; i++ {
|
|
|
|
io.ReadFull(r, buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if bytesRemaining > 0 {
|
|
|
|
buf := make([]byte, bytesRemaining)
|
|
|
|
io.ReadFull(r, buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// WriteMessage writes a lightning Message to w including the necessary header
|
|
|
|
// information and returns the number of bytes written.
|
2016-05-31 01:42:53 +03:00
|
|
|
func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet wire.BitcoinNet) (int, error) {
|
2015-12-28 14:24:16 +03:00
|
|
|
totalBytes := 0
|
|
|
|
|
|
|
|
cmd := msg.Command()
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Encode the message payload
|
2015-12-28 14:24:16 +03:00
|
|
|
var bw bytes.Buffer
|
|
|
|
err := msg.Encode(&bw, pver)
|
|
|
|
if err != nil {
|
|
|
|
return totalBytes, err
|
|
|
|
}
|
|
|
|
payload := bw.Bytes()
|
|
|
|
lenp := len(payload)
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Enforce maximum overall message payload
|
2015-12-28 14:24:16 +03:00
|
|
|
if lenp > MaxMessagePayload {
|
2016-05-23 23:49:10 +03:00
|
|
|
return totalBytes, fmt.Errorf("message payload is too large - "+
|
|
|
|
"encoded %d bytes, but maximum message payload is %d bytes",
|
|
|
|
lenp, MaxMessagePayload)
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Enforce maximum message payload on the message type
|
2015-12-28 14:24:16 +03:00
|
|
|
mpl := msg.MaxPayloadLength(pver)
|
|
|
|
if uint32(lenp) > mpl {
|
2016-05-23 23:49:10 +03:00
|
|
|
return totalBytes, fmt.Errorf("message payload is too large - "+
|
|
|
|
"encoded %d bytes, but maximum message payload of "+
|
|
|
|
"type %x is %d bytes", lenp, cmd, mpl)
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Create header for the message.
|
|
|
|
hdr := messageHeader{magic: btcnet, command: cmd, length: uint32(lenp)}
|
2015-12-28 14:24:16 +03:00
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Encode the header for the message. This is done to a buffer
|
|
|
|
// rather than directly to the writer since writeElements doesn't
|
|
|
|
// return the number of bytes written.
|
2015-12-28 14:24:16 +03:00
|
|
|
hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
|
2016-05-23 23:49:10 +03:00
|
|
|
if err := writeElements(hw, hdr.magic, hdr.command, hdr.length); err != nil {
|
|
|
|
return 0, nil
|
|
|
|
}
|
2015-12-28 14:24:16 +03:00
|
|
|
|
2016-10-16 00:41:11 +03:00
|
|
|
// Write the header first.
|
2015-12-28 14:24:16 +03:00
|
|
|
n, err := w.Write(hw.Bytes())
|
|
|
|
totalBytes += n
|
|
|
|
if err != nil {
|
|
|
|
return totalBytes, err
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Write payload the payload itself after the header.
|
2015-12-28 14:24:16 +03:00
|
|
|
n, err = w.Write(payload)
|
|
|
|
totalBytes += n
|
2017-02-23 21:59:50 +03:00
|
|
|
return totalBytes, err
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2017-02-23 22:56:47 +03:00
|
|
|
// ReadMessage reads, validates, and parses the next bitcoin Message from r for
|
2016-05-23 23:49:10 +03:00
|
|
|
// the provided protocol version and bitcoin network. It returns the number of
|
|
|
|
// bytes read in addition to the parsed Message and raw bytes which comprise the
|
|
|
|
// message. This function is the same as ReadMessage except it also returns the
|
|
|
|
// number of bytes read.
|
2015-12-28 14:24:16 +03:00
|
|
|
func ReadMessage(r io.Reader, pver uint32, btcnet wire.BitcoinNet) (int, Message, []byte, error) {
|
|
|
|
totalBytes := 0
|
|
|
|
n, hdr, err := readMessageHeader(r)
|
|
|
|
totalBytes += n
|
|
|
|
if err != nil {
|
|
|
|
return totalBytes, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Enforce maximum message payload
|
2015-12-28 14:24:16 +03:00
|
|
|
if hdr.length > MaxMessagePayload {
|
2016-05-23 23:49:10 +03:00
|
|
|
return totalBytes, nil, nil, fmt.Errorf("message payload is "+
|
|
|
|
"too large - header indicates %d bytes, but max "+
|
|
|
|
"message payload is %d bytes.", hdr.length,
|
|
|
|
MaxMessagePayload)
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Check for messages in the wrong network.
|
2015-12-28 14:24:16 +03:00
|
|
|
if hdr.magic != btcnet {
|
|
|
|
discardInput(r, hdr.length)
|
2016-05-23 23:49:10 +03:00
|
|
|
return totalBytes, nil, nil, fmt.Errorf("message from other "+
|
|
|
|
"network [%v]", hdr.magic)
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Create struct of appropriate message type based on the command.
|
2015-12-28 14:24:16 +03:00
|
|
|
command := hdr.command
|
|
|
|
msg, err := makeEmptyMessage(command)
|
|
|
|
if err != nil {
|
|
|
|
discardInput(r, hdr.length)
|
2017-01-17 05:03:34 +03:00
|
|
|
return totalBytes, nil, nil, &UnknownMessage{
|
|
|
|
messageType: command,
|
|
|
|
}
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Check for maximum length based on the message type.
|
2015-12-28 14:24:16 +03:00
|
|
|
mpl := msg.MaxPayloadLength(pver)
|
|
|
|
if hdr.length > mpl {
|
|
|
|
discardInput(r, hdr.length)
|
2016-05-23 23:49:10 +03:00
|
|
|
return totalBytes, nil, nil, fmt.Errorf("payload exceeds max "+
|
|
|
|
"length. indicates %v bytes, but max of message type %v is %v.",
|
|
|
|
hdr.length, command, mpl)
|
2015-12-28 14:24:16 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Read payload.
|
2015-12-28 14:24:16 +03:00
|
|
|
payload := make([]byte, hdr.length)
|
|
|
|
n, err = io.ReadFull(r, payload)
|
|
|
|
totalBytes += n
|
|
|
|
if err != nil {
|
|
|
|
return totalBytes, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Unmarshal message.
|
2015-12-28 14:24:16 +03:00
|
|
|
pr := bytes.NewBuffer(payload)
|
2016-05-23 23:49:10 +03:00
|
|
|
if err = msg.Decode(pr, pver); err != nil {
|
2015-12-28 14:24:16 +03:00
|
|
|
return totalBytes, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2016-05-23 23:49:10 +03:00
|
|
|
// Validate the data.
|
|
|
|
if err = msg.Validate(); err != nil {
|
2015-12-28 14:24:16 +03:00
|
|
|
return totalBytes, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return totalBytes, msg, payload, nil
|
|
|
|
}
|