From fc9ebb52f34dee170b1daf30f7899fe851329df5 Mon Sep 17 00:00:00 2001 From: Joseph Poon Date: Wed, 23 Dec 2015 00:08:34 -0800 Subject: [PATCH] Refactor funding request, will separate to multiple files later --- lnwire/lnwire.go | 236 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 lnwire/lnwire.go diff --git a/lnwire/lnwire.go b/lnwire/lnwire.go new file mode 100644 index 00000000..5d941598 --- /dev/null +++ b/lnwire/lnwire.go @@ -0,0 +1,236 @@ +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 +}