mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
b368e476c5
In this commit, we update the Sig type to support ECDSA and schnorr signatures. We need to do this as the HTLC signatures will become schnorr sigs for taproot channels. The current spec draft opts to overload this field since both the sigs are actually 64 bytes in length. The only consideration with this move is that callers need to "coerce" a sig to the proper type if they need schnorr signatures.
953 lines
20 KiB
Go
953 lines
20 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"image/color"
|
|
"io"
|
|
"math"
|
|
"net"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/go-errors/errors"
|
|
"github.com/lightningnetwork/lnd/tor"
|
|
)
|
|
|
|
const (
|
|
// MaxSliceLength is the maximum allowed length for any opaque byte
|
|
// slices in the wire protocol.
|
|
MaxSliceLength = 65535
|
|
|
|
// MaxMsgBody is the largest payload any message is allowed to provide.
|
|
// This is two less than the MaxSliceLength as each message has a 2
|
|
// byte type that precedes the message body.
|
|
MaxMsgBody = 65533
|
|
)
|
|
|
|
// PkScript is simple type definition which represents a raw serialized public
|
|
// key script.
|
|
type PkScript []byte
|
|
|
|
// addressType specifies the network protocol and version that should be used
|
|
// when connecting to a node at a particular address.
|
|
type addressType uint8
|
|
|
|
const (
|
|
// noAddr denotes a blank address. An address of this type indicates
|
|
// that a node doesn't have any advertised addresses.
|
|
noAddr addressType = 0
|
|
|
|
// tcp4Addr denotes an IPv4 TCP address.
|
|
tcp4Addr addressType = 1
|
|
|
|
// tcp6Addr denotes an IPv6 TCP address.
|
|
tcp6Addr addressType = 2
|
|
|
|
// v2OnionAddr denotes a version 2 Tor onion service address.
|
|
v2OnionAddr addressType = 3
|
|
|
|
// v3OnionAddr denotes a version 3 Tor (prop224) onion service address.
|
|
v3OnionAddr addressType = 4
|
|
)
|
|
|
|
// AddrLen returns the number of bytes that it takes to encode the target
|
|
// address.
|
|
func (a addressType) AddrLen() uint16 {
|
|
switch a {
|
|
case noAddr:
|
|
return 0
|
|
case tcp4Addr:
|
|
return 6
|
|
case tcp6Addr:
|
|
return 18
|
|
case v2OnionAddr:
|
|
return 12
|
|
case v3OnionAddr:
|
|
return 37
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// WriteElement is a one-stop shop to write the big endian representation of
|
|
// any element which is to be serialized for the wire protocol.
|
|
//
|
|
// TODO(yy): rm this method once we finish dereferencing it from other
|
|
// packages.
|
|
func WriteElement(w *bytes.Buffer, element interface{}) error {
|
|
switch e := element.(type) {
|
|
case NodeAlias:
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ShortChanIDEncoding:
|
|
var b [1]byte
|
|
b[0] = uint8(e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case uint8:
|
|
var b [1]byte
|
|
b[0] = e
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case FundingFlag:
|
|
var b [1]byte
|
|
b[0] = uint8(e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case uint16:
|
|
var b [2]byte
|
|
binary.BigEndian.PutUint16(b[:], e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ChanUpdateMsgFlags:
|
|
var b [1]byte
|
|
b[0] = uint8(e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ChanUpdateChanFlags:
|
|
var b [1]byte
|
|
b[0] = uint8(e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case MilliSatoshi:
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], uint64(e))
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case btcutil.Amount:
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], uint64(e))
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case uint32:
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case uint64:
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], e)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *btcec.PublicKey:
|
|
if e == nil {
|
|
return fmt.Errorf("cannot write nil pubkey")
|
|
}
|
|
|
|
var b [33]byte
|
|
serializedPubkey := e.SerializeCompressed()
|
|
copy(b[:], serializedPubkey)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case []Sig:
|
|
var b [2]byte
|
|
numSigs := uint16(len(e))
|
|
binary.BigEndian.PutUint16(b[:], numSigs)
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, sig := range e {
|
|
if err := WriteElement(w, sig); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
case Sig:
|
|
// Write buffer
|
|
if _, err := w.Write(e.bytes[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case PingPayload:
|
|
var l [2]byte
|
|
binary.BigEndian.PutUint16(l[:], uint16(len(e)))
|
|
if _, err := w.Write(l[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case PongPayload:
|
|
var l [2]byte
|
|
binary.BigEndian.PutUint16(l[:], uint16(len(e)))
|
|
if _, err := w.Write(l[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case WarningData:
|
|
var l [2]byte
|
|
binary.BigEndian.PutUint16(l[:], uint16(len(e)))
|
|
if _, err := w.Write(l[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ErrorData:
|
|
var l [2]byte
|
|
binary.BigEndian.PutUint16(l[:], uint16(len(e)))
|
|
if _, err := w.Write(l[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case OpaqueReason:
|
|
var l [2]byte
|
|
binary.BigEndian.PutUint16(l[:], uint16(len(e)))
|
|
if _, err := w.Write(l[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case [33]byte:
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case []byte:
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case PkScript:
|
|
// The largest script we'll accept is a p2wsh which is exactly
|
|
// 34 bytes long.
|
|
scriptLength := len(e)
|
|
if scriptLength > 34 {
|
|
return fmt.Errorf("'PkScript' too long")
|
|
}
|
|
|
|
if err := wire.WriteVarBytes(w, 0, e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *RawFeatureVector:
|
|
if e == nil {
|
|
return fmt.Errorf("cannot write nil feature vector")
|
|
}
|
|
|
|
if err := e.Encode(w); err != nil {
|
|
return err
|
|
}
|
|
|
|
case wire.OutPoint:
|
|
var h [32]byte
|
|
copy(h[:], e.Hash[:])
|
|
if _, err := w.Write(h[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if e.Index > math.MaxUint16 {
|
|
return fmt.Errorf("index for outpoint (%v) is "+
|
|
"greater than max index of %v", e.Index,
|
|
math.MaxUint16)
|
|
}
|
|
|
|
var idx [2]byte
|
|
binary.BigEndian.PutUint16(idx[:], uint16(e.Index))
|
|
if _, err := w.Write(idx[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ChannelID:
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case FailCode:
|
|
if err := WriteElement(w, uint16(e)); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ShortChannelID:
|
|
// Check that field fit in 3 bytes and write the blockHeight
|
|
if e.BlockHeight > ((1 << 24) - 1) {
|
|
return errors.New("block height should fit in 3 bytes")
|
|
}
|
|
|
|
var blockHeight [4]byte
|
|
binary.BigEndian.PutUint32(blockHeight[:], e.BlockHeight)
|
|
|
|
if _, err := w.Write(blockHeight[1:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check that field fit in 3 bytes and write the txIndex
|
|
if e.TxIndex > ((1 << 24) - 1) {
|
|
return errors.New("tx index should fit in 3 bytes")
|
|
}
|
|
|
|
var txIndex [4]byte
|
|
binary.BigEndian.PutUint32(txIndex[:], e.TxIndex)
|
|
if _, err := w.Write(txIndex[1:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Write the txPosition
|
|
var txPosition [2]byte
|
|
binary.BigEndian.PutUint16(txPosition[:], e.TxPosition)
|
|
if _, err := w.Write(txPosition[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *net.TCPAddr:
|
|
if e == nil {
|
|
return fmt.Errorf("cannot write nil TCPAddr")
|
|
}
|
|
|
|
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 *tor.OnionAddr:
|
|
if e == nil {
|
|
return errors.New("cannot write nil onion address")
|
|
}
|
|
|
|
var suffixIndex int
|
|
switch len(e.OnionService) {
|
|
case tor.V2Len:
|
|
descriptor := []byte{byte(v2OnionAddr)}
|
|
if _, err := w.Write(descriptor); err != nil {
|
|
return err
|
|
}
|
|
suffixIndex = tor.V2Len - tor.OnionSuffixLen
|
|
case tor.V3Len:
|
|
descriptor := []byte{byte(v3OnionAddr)}
|
|
if _, err := w.Write(descriptor); err != nil {
|
|
return err
|
|
}
|
|
suffixIndex = tor.V3Len - tor.OnionSuffixLen
|
|
default:
|
|
return errors.New("unknown onion service length")
|
|
}
|
|
|
|
host, err := tor.Base32Encoding.DecodeString(
|
|
e.OnionService[:suffixIndex],
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := w.Write(host); 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:
|
|
// First, we'll encode all the addresses into an intermediate
|
|
// buffer. We need to do this in order to compute the total
|
|
// length of the addresses.
|
|
var addrBuf bytes.Buffer
|
|
for _, address := range e {
|
|
if err := WriteElement(&addrBuf, address); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// With the addresses fully encoded, we can now write out the
|
|
// number of bytes needed to encode them.
|
|
addrLen := addrBuf.Len()
|
|
if err := WriteElement(w, uint16(addrLen)); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Finally, we'll write out the raw addresses themselves, but
|
|
// only if we have any bytes to write.
|
|
if addrLen > 0 {
|
|
if _, err := w.Write(addrBuf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
case color.RGBA:
|
|
if err := WriteElements(w, e.R, e.G, e.B); err != nil {
|
|
return err
|
|
}
|
|
|
|
case DeliveryAddress:
|
|
var length [2]byte
|
|
binary.BigEndian.PutUint16(length[:], uint16(len(e)))
|
|
if _, err := w.Write(length[:]); err != nil {
|
|
return err
|
|
}
|
|
if _, err := w.Write(e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case bool:
|
|
var b [1]byte
|
|
if e {
|
|
b[0] = 1
|
|
}
|
|
if _, err := w.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case ExtraOpaqueData:
|
|
return e.Encode(w)
|
|
|
|
default:
|
|
return fmt.Errorf("unknown type in WriteElement: %T", e)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// WriteElements is writes each element in the elements slice to the passed
|
|
// buffer using WriteElement.
|
|
//
|
|
// TODO(yy): rm this method once we finish dereferencing it from other
|
|
// packages.
|
|
func WriteElements(buf *bytes.Buffer, elements ...interface{}) error {
|
|
for _, element := range elements {
|
|
err := WriteElement(buf, element)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ReadElement is a one-stop utility function to deserialize any datastructure
|
|
// encoded using the serialization format of lnwire.
|
|
func ReadElement(r io.Reader, element interface{}) error {
|
|
var err error
|
|
switch e := element.(type) {
|
|
case *bool:
|
|
var b [1]byte
|
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if b[0] == 1 {
|
|
*e = true
|
|
}
|
|
|
|
case *NodeAlias:
|
|
var a [32]byte
|
|
if _, err := io.ReadFull(r, a[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
alias, err := NewNodeAlias(string(a[:]))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = alias
|
|
|
|
case *ShortChanIDEncoding:
|
|
var b [1]uint8
|
|
if _, err := r.Read(b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = ShortChanIDEncoding(b[0])
|
|
|
|
case *uint8:
|
|
var b [1]uint8
|
|
if _, err := r.Read(b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = b[0]
|
|
|
|
case *FundingFlag:
|
|
var b [1]uint8
|
|
if _, err := r.Read(b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = FundingFlag(b[0])
|
|
|
|
case *uint16:
|
|
var b [2]byte
|
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = binary.BigEndian.Uint16(b[:])
|
|
|
|
case *ChanUpdateMsgFlags:
|
|
var b [1]uint8
|
|
if _, err := r.Read(b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = ChanUpdateMsgFlags(b[0])
|
|
|
|
case *ChanUpdateChanFlags:
|
|
var b [1]uint8
|
|
if _, err := r.Read(b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = ChanUpdateChanFlags(b[0])
|
|
|
|
case *uint32:
|
|
var b [4]byte
|
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = binary.BigEndian.Uint32(b[:])
|
|
|
|
case *uint64:
|
|
var b [8]byte
|
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = binary.BigEndian.Uint64(b[:])
|
|
|
|
case *MilliSatoshi:
|
|
var b [8]byte
|
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = MilliSatoshi(int64(binary.BigEndian.Uint64(b[:])))
|
|
|
|
case *btcutil.Amount:
|
|
var b [8]byte
|
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
*e = btcutil.Amount(int64(binary.BigEndian.Uint64(b[:])))
|
|
|
|
case **btcec.PublicKey:
|
|
var b [btcec.PubKeyBytesLenCompressed]byte
|
|
if _, err = io.ReadFull(r, b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKey, err := btcec.ParsePubKey(b[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = pubKey
|
|
|
|
case **RawFeatureVector:
|
|
f := NewRawFeatureVector()
|
|
err = f.Decode(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = f
|
|
|
|
case *[]Sig:
|
|
var l [2]byte
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
|
return err
|
|
}
|
|
numSigs := binary.BigEndian.Uint16(l[:])
|
|
|
|
var sigs []Sig
|
|
if numSigs > 0 {
|
|
sigs = make([]Sig, numSigs)
|
|
for i := 0; i < int(numSigs); i++ {
|
|
if err := ReadElement(r, &sigs[i]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
*e = sigs
|
|
|
|
case *Sig:
|
|
if _, err := io.ReadFull(r, e.bytes[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *OpaqueReason:
|
|
var l [2]byte
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
|
return err
|
|
}
|
|
reasonLen := binary.BigEndian.Uint16(l[:])
|
|
|
|
*e = OpaqueReason(make([]byte, reasonLen))
|
|
if _, err := io.ReadFull(r, *e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *WarningData:
|
|
var l [2]byte
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
|
return err
|
|
}
|
|
errorLen := binary.BigEndian.Uint16(l[:])
|
|
|
|
*e = WarningData(make([]byte, errorLen))
|
|
if _, err := io.ReadFull(r, *e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *ErrorData:
|
|
var l [2]byte
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
|
return err
|
|
}
|
|
errorLen := binary.BigEndian.Uint16(l[:])
|
|
|
|
*e = ErrorData(make([]byte, errorLen))
|
|
if _, err := io.ReadFull(r, *e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *PingPayload:
|
|
var l [2]byte
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
|
return err
|
|
}
|
|
pingLen := binary.BigEndian.Uint16(l[:])
|
|
|
|
*e = PingPayload(make([]byte, pingLen))
|
|
if _, err := io.ReadFull(r, *e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *PongPayload:
|
|
var l [2]byte
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
|
return err
|
|
}
|
|
pongLen := binary.BigEndian.Uint16(l[:])
|
|
|
|
*e = PongPayload(make([]byte, pongLen))
|
|
if _, err := io.ReadFull(r, *e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *[33]byte:
|
|
if _, err := io.ReadFull(r, e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case []byte:
|
|
if _, err := io.ReadFull(r, e); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *PkScript:
|
|
pkScript, err := wire.ReadVarBytes(r, 0, 34, "pkscript")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = pkScript
|
|
|
|
case *wire.OutPoint:
|
|
var h [32]byte
|
|
if _, err = io.ReadFull(r, h[:]); err != nil {
|
|
return err
|
|
}
|
|
hash, err := chainhash.NewHash(h[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var idxBytes [2]byte
|
|
_, err = io.ReadFull(r, idxBytes[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
index := binary.BigEndian.Uint16(idxBytes[:])
|
|
|
|
*e = wire.OutPoint{
|
|
Hash: *hash,
|
|
Index: uint32(index),
|
|
}
|
|
|
|
case *FailCode:
|
|
if err := ReadElement(r, (*uint16)(e)); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *ChannelID:
|
|
if _, err := io.ReadFull(r, e[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
case *ShortChannelID:
|
|
var blockHeight [4]byte
|
|
if _, err = io.ReadFull(r, blockHeight[1:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
var txIndex [4]byte
|
|
if _, err = io.ReadFull(r, txIndex[1:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
var txPosition [2]byte
|
|
if _, err = io.ReadFull(r, txPosition[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
*e = ShortChannelID{
|
|
BlockHeight: binary.BigEndian.Uint32(blockHeight[:]),
|
|
TxIndex: binary.BigEndian.Uint32(txIndex[:]),
|
|
TxPosition: binary.BigEndian.Uint16(txPosition[:]),
|
|
}
|
|
|
|
case *[]net.Addr:
|
|
// First, we'll read the number of total bytes that have been
|
|
// used to encode the set of addresses.
|
|
var numAddrsBytes [2]byte
|
|
if _, err = io.ReadFull(r, numAddrsBytes[:]); err != nil {
|
|
return err
|
|
}
|
|
addrsLen := binary.BigEndian.Uint16(numAddrsBytes[:])
|
|
|
|
// With the number of addresses, read, we'll now pull in the
|
|
// buffer of the encoded addresses into memory.
|
|
addrs := make([]byte, addrsLen)
|
|
if _, err := io.ReadFull(r, addrs[:]); err != nil {
|
|
return err
|
|
}
|
|
addrBuf := bytes.NewReader(addrs)
|
|
|
|
// Finally, we'll parse the remaining address payload in
|
|
// series, using the first byte to denote how to decode the
|
|
// address itself.
|
|
var (
|
|
addresses []net.Addr
|
|
addrBytesRead uint16
|
|
)
|
|
|
|
for addrBytesRead < addrsLen {
|
|
var descriptor [1]byte
|
|
if _, err = io.ReadFull(addrBuf, descriptor[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
addrBytesRead++
|
|
|
|
var address net.Addr
|
|
switch aType := addressType(descriptor[0]); aType {
|
|
case noAddr:
|
|
addrBytesRead += aType.AddrLen()
|
|
continue
|
|
|
|
case tcp4Addr:
|
|
var ip [4]byte
|
|
if _, err := io.ReadFull(addrBuf, ip[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
var port [2]byte
|
|
if _, err := io.ReadFull(addrBuf, port[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
address = &net.TCPAddr{
|
|
IP: net.IP(ip[:]),
|
|
Port: int(binary.BigEndian.Uint16(port[:])),
|
|
}
|
|
addrBytesRead += aType.AddrLen()
|
|
|
|
case tcp6Addr:
|
|
var ip [16]byte
|
|
if _, err := io.ReadFull(addrBuf, ip[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
var port [2]byte
|
|
if _, err := io.ReadFull(addrBuf, port[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
address = &net.TCPAddr{
|
|
IP: net.IP(ip[:]),
|
|
Port: int(binary.BigEndian.Uint16(port[:])),
|
|
}
|
|
addrBytesRead += aType.AddrLen()
|
|
|
|
case v2OnionAddr:
|
|
var h [tor.V2DecodedLen]byte
|
|
if _, err := io.ReadFull(addrBuf, h[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
var p [2]byte
|
|
if _, err := io.ReadFull(addrBuf, p[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
onionService := tor.Base32Encoding.EncodeToString(h[:])
|
|
onionService += tor.OnionSuffix
|
|
port := int(binary.BigEndian.Uint16(p[:]))
|
|
|
|
address = &tor.OnionAddr{
|
|
OnionService: onionService,
|
|
Port: port,
|
|
}
|
|
addrBytesRead += aType.AddrLen()
|
|
|
|
case v3OnionAddr:
|
|
var h [tor.V3DecodedLen]byte
|
|
if _, err := io.ReadFull(addrBuf, h[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
var p [2]byte
|
|
if _, err := io.ReadFull(addrBuf, p[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
onionService := tor.Base32Encoding.EncodeToString(h[:])
|
|
onionService += tor.OnionSuffix
|
|
port := int(binary.BigEndian.Uint16(p[:]))
|
|
|
|
address = &tor.OnionAddr{
|
|
OnionService: onionService,
|
|
Port: port,
|
|
}
|
|
addrBytesRead += aType.AddrLen()
|
|
|
|
default:
|
|
// If we don't understand this address type,
|
|
// we just store it along with the remaining
|
|
// address bytes as type OpaqueAddrs. We need
|
|
// to hold onto the bytes so that we can still
|
|
// write them back to the wire when we
|
|
// propagate this message.
|
|
payloadLen := 1 + addrsLen - addrBytesRead
|
|
payload := make([]byte, payloadLen)
|
|
|
|
// First write a byte for the address type that
|
|
// we already read.
|
|
payload[0] = byte(aType)
|
|
|
|
// Now append the rest of the address bytes.
|
|
_, err := io.ReadFull(addrBuf, payload[1:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
address = &OpaqueAddrs{
|
|
Payload: payload,
|
|
}
|
|
addrBytesRead = addrsLen
|
|
}
|
|
|
|
addresses = append(addresses, address)
|
|
}
|
|
|
|
*e = addresses
|
|
|
|
case *color.RGBA:
|
|
err := ReadElements(r,
|
|
&e.R,
|
|
&e.G,
|
|
&e.B,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
case *DeliveryAddress:
|
|
var addrLen [2]byte
|
|
if _, err = io.ReadFull(r, addrLen[:]); err != nil {
|
|
return err
|
|
}
|
|
length := binary.BigEndian.Uint16(addrLen[:])
|
|
|
|
var addrBytes [deliveryAddressMaxSize]byte
|
|
|
|
if length > deliveryAddressMaxSize {
|
|
return fmt.Errorf(
|
|
"cannot read %d bytes into addrBytes", length,
|
|
)
|
|
}
|
|
if _, err = io.ReadFull(r, addrBytes[:length]); err != nil {
|
|
return err
|
|
}
|
|
*e = addrBytes[:length]
|
|
|
|
case *ExtraOpaqueData:
|
|
return e.Decode(r)
|
|
|
|
default:
|
|
return fmt.Errorf("unknown type in ReadElement: %T", e)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadElements deserializes a variable number of elements into the passed
|
|
// io.Reader, with each element being deserialized according to the ReadElement
|
|
// function.
|
|
func ReadElements(r io.Reader, elements ...interface{}) error {
|
|
for _, element := range elements {
|
|
err := ReadElement(r, element)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|