lnd.xprv/lnwire/lnwire.go

237 lines
4.7 KiB
Go
Raw Normal View History

package lnwire
import (
"encoding/binary"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"io"
)
//Actual pkScript, not redeemScript
type PkScript []byte
type CreateChannel struct {
ChannelType uint8
OurFundingAmount btcutil.Amount
OurReserveAmount btcutil.Amount
MinFeePerKb btcutil.Amount //higher of both parties
MinTotalFundingAmount btcutil.Amount
//CLTV lock-time to use
LockTime uint32
//Who pays the fees
//0: (default) channel initiator
//1: split
//2: channel responder
FeePayer uint8
OurRevocationHash [20]byte
TheirRevocationHash [20]byte
OurPubkey *btcec.PublicKey
TheirPubkey *btcec.PublicKey
DeliveryPkScript PkScript //*MUST* be either P2PKH or P2SH
OurInputs []*wire.TxIn
TheirInputs []*wire.TxIn
}
//Writes the big endian representation of element
//Unified function to call when writing different types
//Pre-allocate a byte-array of the correct size for cargo-cult security
//More copies but whatever...
func writeElement(w io.Writer, element interface{}) error {
var err error
switch e := element.(type) {
case uint8:
var b [1]byte
b[0] = byte(e)
_, err = w.Write(b[:])
if err != nil {
return err
}
case uint32:
var b [4]byte
binary.BigEndian.PutUint32(b[:], uint32(e))
_, err = w.Write(b[:])
if err != nil {
return err
}
case btcutil.Amount:
var b [8]byte
binary.BigEndian.PutUint64(b[:], uint64(e))
_, err = w.Write(b[:])
if err != nil {
return err
}
case *btcec.PublicKey:
var b [33]byte
serializedPubkey := e.SerializeCompressed()
if len(serializedPubkey) != 33 {
return fmt.Errorf("Wrong size pubkey")
}
copy(b[:], serializedPubkey)
_, err = w.Write(b[:])
if err != nil {
return err
}
case [20]byte:
_, err = w.Write(e[:])
if err != nil {
return err
}
case PkScript:
scriptLength := len(e)
//Make sure it's P2PKH or P2SH size or less
if scriptLength > 25 {
return fmt.Errorf("PkScript too long!")
}
//Write the size (1-byte)
err = binary.Write(w, binary.BigEndian, uint8(scriptLength))
if err != nil {
return err
}
//Write the data
_, err = w.Write(e)
if err != nil {
return err
}
case []*wire.TxIn:
//Append the unsigned(!!!) txins
//Write the size (1-byte)
if len(e) > 127 {
return fmt.Errorf("Too many txins")
}
err = binary.Write(w, binary.BigEndian, uint8(len(e)))
if err != nil {
return err
}
//Append the actual TxIns (Size: NumOfTxins * 36)
//Do not include the sequence number to eliminate funny business
for _, in := range e {
//Hash
var h [32]byte
copy(h[:], in.PreviousOutPoint.Hash.Bytes())
_, err = w.Write(h[:])
if err != nil {
return err
}
//Index
var idx [4]byte
binary.BigEndian.PutUint32(idx[:], in.PreviousOutPoint.Index)
_, err = w.Write(idx[:])
if err != nil {
return err
}
}
default:
return fmt.Errorf("Unknown type in writeElement: %T", e)
}
return nil
}
func readElement(r io.Reader, element interface{}) error {
var err error
switch e := element.(type) {
case *uint32:
var b [4]byte
_, err = io.ReadFull(r, b[:])
if err != nil {
return err
}
*e = binary.BigEndian.Uint32(b[:])
}
return nil
}
//Serializes the fundingRequest from the CreateChannel struct
//Writes the data to w
func (c *CreateChannel) SerializeFundingRequest(w io.Writer) error {
var err error
//Fund request byte
err = binary.Write(w, binary.BigEndian, uint8(0x30))
if err != nil {
return err
}
//Channel Type
//default to 0 for CLTV-only
err = writeElement(w, c.ChannelType)
if err != nil {
return err
}
//Our Funding Amont
err = writeElement(w, c.OurFundingAmount)
if err != nil {
return err
}
//Our Channel Minimum Capacity
err = writeElement(w, c.MinTotalFundingAmount)
if err != nil {
return err
}
//Our Revocation Hash
err = writeElement(w, c.OurRevocationHash)
if err != nil {
return err
}
//Our Commitment Pubkey
err = writeElement(w, c.OurPubkey)
if err != nil {
return err
}
//Our Delivery PkHash
err = writeElement(w, c.OurRevocationHash)
if err != nil {
return err
}
//Our Reserve Amount
err = writeElement(w, c.OurReserveAmount)
if err != nil {
return err
}
//Minimum Transaction Fee Per KB
err = writeElement(w, c.MinFeePerKb)
if err != nil {
return err
}
//LockTime
err = writeElement(w, c.LockTime)
if err != nil {
return err
}
//FeePayer
err = writeElement(w, c.FeePayer)
if err != nil {
return err
}
//Delivery PkScript
err = writeElement(w, c.DeliveryPkScript)
if err != nil {
return err
}
//Append the actual Txins
err = writeElement(w, c.OurInputs)
if err != nil {
return err
}
return nil
}