Esempio n. 1
0
func serializeLinkNode(w io.Writer, l *LinkNode) error {
	var buf [8]byte

	byteOrder.PutUint32(buf[:4], uint32(l.Network))
	if _, err := w.Write(buf[:4]); err != nil {
		return err
	}

	serializedID := l.IdentityPub.SerializeCompressed()
	if _, err := w.Write(serializedID); err != nil {
		return err
	}

	seenUnix := uint64(l.LastSeen.Unix())
	byteOrder.PutUint64(buf[:], seenUnix)
	if _, err := w.Write(buf[:]); err != nil {
		return err
	}

	numAddrs := uint32(len(l.Addresses))
	byteOrder.PutUint32(buf[:4], numAddrs)
	if _, err := w.Write(buf[:4]); err != nil {
		return err
	}

	for _, addr := range l.Addresses {
		addrString := addr.String()
		if err := wire.WriteVarString(w, 0, addrString); err != nil {
			return err
		}
	}

	return nil
}
Esempio n. 2
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. 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
}