package lnwire import ( "bytes" "encoding/binary" "errors" "fmt" "image/color" "math" "net" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/tor" ) var ( // ErrNilFeatureVector is returned when the supplied feature is nil. ErrNilFeatureVector = errors.New("cannot write nil feature vector") // ErrPkScriptTooLong is returned when the length of the provided // script exceeds 34. ErrPkScriptTooLong = errors.New("'PkScript' too long") // ErrNilTCPAddress is returned when the supplied address is nil. ErrNilTCPAddress = errors.New("cannot write nil TCPAddr") // ErrNilOnionAddress is returned when the supplied address is nil. ErrNilOnionAddress = errors.New("cannot write nil onion address") // ErrNilNetAddress is returned when a nil value is used in []net.Addr. ErrNilNetAddress = errors.New("cannot write nil address") // ErrNilOpaqueAddrs is returned when the supplied address is nil. ErrNilOpaqueAddrs = errors.New("cannot write nil OpaqueAddrs") // ErrNilPublicKey is returned when a nil pubkey is used. ErrNilPublicKey = errors.New("cannot write nil pubkey") // ErrUnknownServiceLength is returned when the onion service length is // unknown. ErrUnknownServiceLength = errors.New("unknown onion service length") ) // ErrOutpointIndexTooBig is used when the outpoint index exceeds the max value // of uint16. func ErrOutpointIndexTooBig(index uint32) error { return fmt.Errorf( "index for outpoint (%v) is greater than "+ "max index of %v", index, math.MaxUint16, ) } // WriteBytes appends the given bytes to the provided buffer. func WriteBytes(buf *bytes.Buffer, b []byte) error { _, err := buf.Write(b) return err } // WriteUint8 appends the uint8 to the provided buffer. func WriteUint8(buf *bytes.Buffer, n uint8) error { _, err := buf.Write([]byte{n}) return err } // WriteUint16 appends the uint16 to the provided buffer. It encodes the // integer using big endian byte order. func WriteUint16(buf *bytes.Buffer, n uint16) error { var b [2]byte binary.BigEndian.PutUint16(b[:], n) _, err := buf.Write(b[:]) return err } // WriteUint32 appends the uint32 to the provided buffer. It encodes the // integer using big endian byte order. func WriteUint32(buf *bytes.Buffer, n uint32) error { var b [4]byte binary.BigEndian.PutUint32(b[:], n) _, err := buf.Write(b[:]) return err } // WriteUint64 appends the uint64 to the provided buffer. It encodes the // integer using big endian byte order. func WriteUint64(buf *bytes.Buffer, n uint64) error { var b [8]byte binary.BigEndian.PutUint64(b[:], n) _, err := buf.Write(b[:]) return err } // WriteSatoshi appends the Satoshi value to the provided buffer. func WriteSatoshi(buf *bytes.Buffer, amount btcutil.Amount) error { return WriteUint64(buf, uint64(amount)) } // WriteMilliSatoshi appends the MilliSatoshi value to the provided buffer. func WriteMilliSatoshi(buf *bytes.Buffer, amount MilliSatoshi) error { return WriteUint64(buf, uint64(amount)) } // WritePublicKey appends the compressed public key to the provided buffer. func WritePublicKey(buf *bytes.Buffer, pub *btcec.PublicKey) error { if pub == nil { return ErrNilPublicKey } serializedPubkey := pub.SerializeCompressed() return WriteBytes(buf, serializedPubkey) } // WriteChannelID appends the ChannelID to the provided buffer. func WriteChannelID(buf *bytes.Buffer, channelID ChannelID) error { return WriteBytes(buf, channelID[:]) } // WriteNodeAlias appends the alias to the provided buffer. func WriteNodeAlias(buf *bytes.Buffer, alias NodeAlias) error { return WriteBytes(buf, alias[:]) } // WriteShortChannelID appends the ShortChannelID to the provided buffer. It // encodes the BlockHeight and TxIndex each using 3 bytes with big endian byte // order, and encodes txPosition using 2 bytes with big endian byte order. func WriteShortChannelID(buf *bytes.Buffer, shortChanID ShortChannelID) error { // Check that field fit in 3 bytes and write the blockHeight if shortChanID.BlockHeight > ((1 << 24) - 1) { return errors.New("block height should fit in 3 bytes") } var blockHeight [4]byte binary.BigEndian.PutUint32(blockHeight[:], shortChanID.BlockHeight) if _, err := buf.Write(blockHeight[1:]); err != nil { return err } // Check that field fit in 3 bytes and write the txIndex if shortChanID.TxIndex > ((1 << 24) - 1) { return errors.New("tx index should fit in 3 bytes") } var txIndex [4]byte binary.BigEndian.PutUint32(txIndex[:], shortChanID.TxIndex) if _, err := buf.Write(txIndex[1:]); err != nil { return err } // Write the TxPosition return WriteUint16(buf, shortChanID.TxPosition) } // WriteSig appends the signature to the provided buffer. func WriteSig(buf *bytes.Buffer, sig Sig) error { return WriteBytes(buf, sig.bytes[:]) } // WriteSigs appends the slice of signatures to the provided buffer with its // length. func WriteSigs(buf *bytes.Buffer, sigs []Sig) error { // Write the length of the sigs. if err := WriteUint16(buf, uint16(len(sigs))); err != nil { return err } for _, sig := range sigs { if err := WriteSig(buf, sig); err != nil { return err } } return nil } // WriteFailCode appends the FailCode to the provided buffer. func WriteFailCode(buf *bytes.Buffer, e FailCode) error { return WriteUint16(buf, uint16(e)) } // WriteRawFeatureVector encodes the feature using the feature's Encode method // and appends the data to the provided buffer. An error will return if the // passed feature is nil. func WriteRawFeatureVector(buf *bytes.Buffer, feature *RawFeatureVector) error { if feature == nil { return ErrNilFeatureVector } return feature.Encode(buf) } // WriteColorRGBA appends the RGBA color using three bytes. func WriteColorRGBA(buf *bytes.Buffer, e color.RGBA) error { // Write R if err := WriteUint8(buf, e.R); err != nil { return err } // Write G if err := WriteUint8(buf, e.G); err != nil { return err } // Write B return WriteUint8(buf, e.B) } // WriteQueryEncoding appends the QueryEncoding to the provided buffer. func WriteQueryEncoding(buf *bytes.Buffer, e QueryEncoding) error { return WriteUint8(buf, uint8(e)) } // WriteFundingFlag appends the FundingFlag to the provided buffer. func WriteFundingFlag(buf *bytes.Buffer, flag FundingFlag) error { return WriteUint8(buf, uint8(flag)) } // WriteChanUpdateMsgFlags appends the update flag to the provided buffer. func WriteChanUpdateMsgFlags(buf *bytes.Buffer, f ChanUpdateMsgFlags) error { return WriteUint8(buf, uint8(f)) } // WriteChanUpdateChanFlags appends the update flag to the provided buffer. func WriteChanUpdateChanFlags(buf *bytes.Buffer, f ChanUpdateChanFlags) error { return WriteUint8(buf, uint8(f)) } // WriteDeliveryAddress appends the address to the provided buffer. func WriteDeliveryAddress(buf *bytes.Buffer, addr DeliveryAddress) error { return writeDataWithLength(buf, addr) } // WritePingPayload appends the payload to the provided buffer. func WritePingPayload(buf *bytes.Buffer, payload PingPayload) error { return writeDataWithLength(buf, payload) } // WritePongPayload appends the payload to the provided buffer. func WritePongPayload(buf *bytes.Buffer, payload PongPayload) error { return writeDataWithLength(buf, payload) } // WriteWarningData appends the data to the provided buffer. func WriteWarningData(buf *bytes.Buffer, data WarningData) error { return writeDataWithLength(buf, data) } // WriteErrorData appends the data to the provided buffer. func WriteErrorData(buf *bytes.Buffer, data ErrorData) error { return writeDataWithLength(buf, data) } // WriteOpaqueReason appends the reason to the provided buffer. func WriteOpaqueReason(buf *bytes.Buffer, reason OpaqueReason) error { return writeDataWithLength(buf, reason) } // WriteBool appends the boolean to the provided buffer. func WriteBool(buf *bytes.Buffer, b bool) error { if b { return WriteBytes(buf, []byte{1}) } return WriteBytes(buf, []byte{0}) } // WritePkScript appends the script to the provided buffer. Returns an error if // the provided script exceeds 34 bytes. func WritePkScript(buf *bytes.Buffer, s PkScript) error { // The largest script we'll accept is a p2wsh which is exactly // 34 bytes long. scriptLength := len(s) if scriptLength > 34 { return ErrPkScriptTooLong } return wire.WriteVarBytes(buf, 0, s) } // WriteOutPoint appends the outpoint to the provided buffer. func WriteOutPoint(buf *bytes.Buffer, p wire.OutPoint) error { // Before we write anything to the buffer, check the Index is sane. if p.Index > math.MaxUint16 { return ErrOutpointIndexTooBig(p.Index) } var h [32]byte copy(h[:], p.Hash[:]) if _, err := buf.Write(h[:]); err != nil { return err } // Write the index using two bytes. return WriteUint16(buf, uint16(p.Index)) } // WriteTCPAddr appends the TCP address to the provided buffer, either a IPv4 // or a IPv6. func WriteTCPAddr(buf *bytes.Buffer, addr *net.TCPAddr) error { if addr == nil { return ErrNilTCPAddress } // Make a slice of bytes to hold the data of descriptor and ip. At // most, we need 17 bytes - 1 byte for the descriptor, 16 bytes for // IPv6. data := make([]byte, 0, 17) if addr.IP.To4() != nil { data = append(data, uint8(tcp4Addr)) data = append(data, addr.IP.To4()...) } else { data = append(data, uint8(tcp6Addr)) data = append(data, addr.IP.To16()...) } if _, err := buf.Write(data); err != nil { return err } return WriteUint16(buf, uint16(addr.Port)) } // WriteOnionAddr appends the onion address to the provided buffer. func WriteOnionAddr(buf *bytes.Buffer, addr *tor.OnionAddr) error { if addr == nil { return ErrNilOnionAddress } var ( suffixIndex int descriptor []byte ) // Decide the suffixIndex and descriptor. switch len(addr.OnionService) { case tor.V2Len: descriptor = []byte{byte(v2OnionAddr)} suffixIndex = tor.V2Len - tor.OnionSuffixLen case tor.V3Len: descriptor = []byte{byte(v3OnionAddr)} suffixIndex = tor.V3Len - tor.OnionSuffixLen default: return ErrUnknownServiceLength } // Decode the address. host, err := tor.Base32Encoding.DecodeString( addr.OnionService[:suffixIndex], ) if err != nil { return err } // Perform the actual write when the above checks passed. if _, err := buf.Write(descriptor); err != nil { return err } if _, err := buf.Write(host); err != nil { return err } return WriteUint16(buf, uint16(addr.Port)) } // WriteOpaqueAddrs appends the payload of the given OpaqueAddrs to buffer. func WriteOpaqueAddrs(buf *bytes.Buffer, addr *OpaqueAddrs) error { if addr == nil { return ErrNilOpaqueAddrs } _, err := buf.Write(addr.Payload) return err } // WriteNetAddrs appends a slice of addresses to the provided buffer with the // length info. func WriteNetAddrs(buf *bytes.Buffer, addresses []net.Addr) error { // 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. buffer := make([]byte, 0, MaxMsgBody) addrBuf := bytes.NewBuffer(buffer) for _, address := range addresses { switch a := address.(type) { case *net.TCPAddr: if err := WriteTCPAddr(addrBuf, a); err != nil { return err } case *tor.OnionAddr: if err := WriteOnionAddr(addrBuf, a); err != nil { return err } case *OpaqueAddrs: if err := WriteOpaqueAddrs(addrBuf, a); err != nil { return err } default: return ErrNilNetAddress } } // With the addresses fully encoded, we can now write out data. return writeDataWithLength(buf, addrBuf.Bytes()) } // writeDataWithLength writes the data and its length to the buffer. func writeDataWithLength(buf *bytes.Buffer, data []byte) error { var l [2]byte binary.BigEndian.PutUint16(l[:], uint16(len(data))) if _, err := buf.Write(l[:]); err != nil { return err } _, err := buf.Write(data) return err }