func putChanCommitTxns(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { var bc bytes.Buffer if err := writeOutpoint(&bc, channel.ChanID); err != nil { return err } txnsKey := make([]byte, len(commitTxnsKey)+bc.Len()) copy(txnsKey[:3], commitTxnsKey) copy(txnsKey[3:], bc.Bytes()) var b bytes.Buffer if err := channel.OurCommitTx.Serialize(&b); err != nil { return err } if err := wire.WriteVarBytes(&b, 0, channel.OurCommitSig); err != nil { return err } // TODO(roasbeef): should move this into putChanFundingInfo scratch := make([]byte, 4) byteOrder.PutUint32(scratch, channel.LocalCsvDelay) if _, err := b.Write(scratch); err != nil { return err } byteOrder.PutUint32(scratch, channel.RemoteCsvDelay) if _, err := b.Write(scratch); err != nil { return err } return nodeChanBucket.Put(txnsKey, b.Bytes()) }
func putChanDeliveryScripts(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { var bc bytes.Buffer if err := writeOutpoint(&bc, channel.ChanID); err != nil { return err } deliveryKey := make([]byte, len(deliveryScriptsKey)+bc.Len()) copy(deliveryKey[:3], deliveryScriptsKey) copy(deliveryKey[3:], bc.Bytes()) var b bytes.Buffer if err := wire.WriteVarBytes(&b, 0, channel.OurDeliveryScript); err != nil { return err } if err := wire.WriteVarBytes(&b, 0, channel.TheirDeliveryScript); err != nil { return err } return nodeChanBucket.Put(deliveryScriptsKey, b.Bytes()) }
func putChanElkremState(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { var bc bytes.Buffer if err := writeOutpoint(&bc, channel.ChanID); err != nil { return err } elkremKey := make([]byte, len(elkremStateKey)+bc.Len()) copy(elkremKey[:3], elkremStateKey) copy(elkremKey[3:], bc.Bytes()) var b bytes.Buffer revKey := channel.TheirCurrentRevocation.SerializeCompressed() if err := wire.WriteVarBytes(&b, 0, revKey); err != nil { return err } if _, err := b.Write(channel.TheirCurrentRevocationHash[:]); err != nil { return err } // TODO(roasbeef): shouldn't be storing on disk, should re-derive as // needed senderBytes := channel.LocalElkrem.ToBytes() if err := wire.WriteVarBytes(&b, 0, senderBytes); err != nil { return err } reciverBytes, err := channel.RemoteElkrem.ToBytes() if err != nil { return err } if err := wire.WriteVarBytes(&b, 0, reciverBytes); err != nil { return err } return nodeChanBucket.Put(elkremKey, b.Bytes()) }
func putChanFundingInfo(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { var bc bytes.Buffer if err := writeOutpoint(&bc, channel.ChanID); err != nil { return err } fundTxnKey := make([]byte, len(fundingTxnKey)+bc.Len()) copy(fundTxnKey[:3], fundingTxnKey) copy(fundTxnKey[3:], bc.Bytes()) var b bytes.Buffer if err := writeOutpoint(&b, channel.FundingOutpoint); err != nil { return err } ourSerKey := channel.OurMultiSigKey.SerializeCompressed() if err := wire.WriteVarBytes(&b, 0, ourSerKey); err != nil { return err } theirSerKey := channel.TheirMultiSigKey.SerializeCompressed() if err := wire.WriteVarBytes(&b, 0, theirSerKey); err != nil { return err } if err := wire.WriteVarBytes(&b, 0, channel.FundingWitnessScript[:]); err != nil { return err } scratch := make([]byte, 8) byteOrder.PutUint64(scratch, uint64(channel.CreationTime.Unix())) if _, err := b.Write(scratch); err != nil { return err } return nodeChanBucket.Put(fundTxnKey, b.Bytes()) }
func serializeInvoice(w io.Writer, i *Invoice) error { if err := wire.WriteVarBytes(w, 0, i.Memo[:]); err != nil { return err } if err := wire.WriteVarBytes(w, 0, i.Receipt[:]); err != nil { return err } birthBytes, err := i.CreationDate.MarshalBinary() if err != nil { return err } if err := wire.WriteVarBytes(w, 0, birthBytes); err != nil { return err } if _, err := w.Write(i.Terms.PaymentPreimage[:]); err != nil { return err } var scratch [8]byte byteOrder.PutUint64(scratch[:], uint64(i.Terms.Value)) if _, err := w.Write(scratch[:]); err != nil { return err } var settleByte [1]byte if i.Terms.Settled { settleByte[0] = 1 } if _, err := w.Write(settleByte[:]); err != nil { return err } return nil }
func writeOutpoint(w io.Writer, o *wire.OutPoint) error { // TODO(roasbeef): make all scratch buffers on the stack scratch := make([]byte, 4) // TODO(roasbeef): write raw 32 bytes instead of wasting the extra // byte. if err := wire.WriteVarBytes(w, 0, o.Hash[:]); err != nil { return err } byteOrder.PutUint32(scratch, o.Index) if _, err := w.Write(scratch); err != nil { return err } return nil }
// writeElement is a one-stop shop to write the big endian representation of // any element which is to be serialized for the wire protocol. The passed // io.Writer should be backed by an appropriatly sized byte slice, or be able // to dynamically expand to accomdate additional data. // // TODO(roasbeef): this should eventually draw from a buffer pool for // serialization. // TODO(roasbeef): switch to var-ints for all? func writeElement(w io.Writer, element interface{}) error { switch e := element.(type) { case uint8: var b [1]byte b[0] = byte(e) if _, err := w.Write(b[:]); err != nil { return err } case uint16: var b [2]byte binary.BigEndian.PutUint16(b[:], uint16(e)) if _, err := w.Write(b[:]); err != nil { return err } case ErrorCode: var b [2]byte binary.BigEndian.PutUint16(b[:], uint16(e)) if _, err := w.Write(b[:]); err != nil { return err } case CreditsAmount: if err := binary.Write(w, binary.BigEndian, int64(e)); err != nil { return err } case uint32: var b [4]byte binary.BigEndian.PutUint32(b[:], uint32(e)) if _, err := w.Write(b[:]); err != nil { return err } case uint64: var b [8]byte binary.BigEndian.PutUint64(b[:], uint64(e)) if _, err := w.Write(b[:]); err != nil { return err } case HTLCKey: if err := binary.Write(w, binary.BigEndian, int64(e)); err != nil { return err } case btcutil.Amount: if err := binary.Write(w, binary.BigEndian, int64(e)); err != nil { return err } case *btcec.PublicKey: var b [33]byte serializedPubkey := e.SerializeCompressed() copy(b[:], serializedPubkey) // TODO(roasbeef): use WriteVarBytes here? if _, err := w.Write(b[:]); err != nil { return err } case []uint64: // Enforce a max number of elements in a uint64 slice. numItems := len(e) if numItems > 65535 { return fmt.Errorf("Too many []uint64s") } // First write out the the number of elements in the slice as a // length prefix. if err := writeElement(w, uint16(numItems)); err != nil { return err } // After the prefix detailing the number of elements, write out // each uint64 in series. for i := 0; i < numItems; i++ { if err := writeElement(w, e[i]); err != nil { return err } } case []*btcec.Signature: // Enforce a sane number for the maximum number of signatures. numSigs := len(e) if numSigs > 127 { return fmt.Errorf("Too many signatures!") } // First write out the the number of elements in the slice as a // length prefix. if err := writeElement(w, uint8(numSigs)); err != nil { return err } // After the prefix detailing the number of elements, write out // each signature in series. for i := 0; i < numSigs; i++ { if err := writeElement(w, e[i]); err != nil { return err } } case *btcec.Signature: sig := e.Serialize() if len(sig) > 73 { return fmt.Errorf("Signature too long!") } if err := wire.WriteVarBytes(w, 0, sig); err != nil { return err } case *wire.ShaHash: if _, err := w.Write(e[:]); err != nil { return err } case [][32]byte: // First write out the number of elements in the slice. sliceSize := len(e) if err := writeElement(w, uint16(sliceSize)); err != nil { return err } // Then write each out sequentially. for _, element := range e { if err := writeElement(w, element); err != nil { return err } } case [32]byte: // TODO(roasbeef): should be factor out to caller logic... if _, err := w.Write(e[:]); err != nil { return err } case wire.BitcoinNet: var b [4]byte binary.BigEndian.PutUint32(b[:], uint32(e)) if _, err := w.Write(b[:]); err != nil { return err } case []byte: // Enforce the maxmium length of all slices used in the wire // protocol. sliceLength := len(e) if sliceLength > MaxSliceLength { return fmt.Errorf("Slice length too long!") } if err := wire.WriteVarBytes(w, 0, e); err != nil { return err } case PkScript: // Make sure it's P2PKH or P2SH size or less. scriptLength := len(e) if scriptLength > 25 { return fmt.Errorf("PkScript too long!") } if err := wire.WriteVarBytes(w, 0, e); err != nil { return err } case string: strlen := len(e) if strlen > MaxSliceLength { return fmt.Errorf("String too long!") } if err := wire.WriteVarString(w, 0, e); err != nil { return err } case []*wire.TxIn: // Write the size (1-byte) if len(e) > 127 { return fmt.Errorf("Too many txins") } // Write out the number of txins. if err := writeElement(w, uint8(len(e))); err != nil { return err } // Append the actual TxIns (Size: NumOfTxins * 36) // During serialization we leave out the sequence number to // eliminate any funny business. for _, in := range e { if err := writeElement(w, in); err != nil { return err } } case *wire.TxIn: // First write out the previous txid. var h [32]byte copy(h[:], e.PreviousOutPoint.Hash[:]) if _, err := w.Write(h[:]); err != nil { return err } // Then the exact index of the previous out point. var idx [4]byte binary.BigEndian.PutUint32(idx[:], e.PreviousOutPoint.Index) if _, err := w.Write(idx[:]); err != nil { return err } case *wire.OutPoint: // TODO(roasbeef): consolidate with above // First write out the previous txid. var h [32]byte copy(h[:], e.Hash[:]) if _, err := w.Write(h[:]); err != nil { return err } // Then the exact index of this output. var idx [4]byte binary.BigEndian.PutUint32(idx[:], e.Index) if _, err := w.Write(idx[:]); err != nil { return err } // TODO(roasbeef): *MsgTx default: return fmt.Errorf("Unknown type in writeElement: %T", e) } return nil }