func deserializeLinkNode(r io.Reader) (*LinkNode, error) { var ( err error buf [8]byte ) node := &LinkNode{} if _, err := io.ReadFull(r, buf[:4]); err != nil { return nil, err } node.Network = wire.BitcoinNet(byteOrder.Uint32(buf[:4])) var pub [33]byte if _, err := io.ReadFull(r, pub[:]); err != nil { return nil, err } node.IdentityPub, err = btcec.ParsePubKey(pub[:], btcec.S256()) if err != nil { return nil, err } if _, err := io.ReadFull(r, buf[:]); err != nil { return nil, err } node.LastSeen = time.Unix(int64(byteOrder.Uint64(buf[:])), 0) if _, err := io.ReadFull(r, buf[:4]); err != nil { return nil, err } numAddrs := byteOrder.Uint32(buf[:4]) node.Addresses = make([]*net.TCPAddr, numAddrs) for i := uint32(0); i < numAddrs; i++ { addrString, err := wire.ReadVarString(r, 0) if err != nil { return nil, err } addr, err := net.ResolveTCPAddr("tcp", addrString) if err != nil { return nil, err } node.Addresses[i] = addr } return node, nil }
// readElement is a one-stop utility function to deserialize any datastructure // encoded using the serialization format of lnwire. func readElement(r io.Reader, element interface{}) error { var err error switch e := element.(type) { case *uint8: var b [1]uint8 if _, err := r.Read(b[:]); err != nil { return err } *e = b[0] case *uint16: var b [2]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = binary.BigEndian.Uint16(b[:]) case *ErrorCode: var b [2]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = ErrorCode(binary.BigEndian.Uint16(b[:])) case *CreditsAmount: var b [8]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = CreditsAmount(int64(binary.BigEndian.Uint64(b[:]))) case *uint32: var b [4]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = binary.BigEndian.Uint32(b[:]) case *uint64: var b [8]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = binary.BigEndian.Uint64(b[:]) case *HTLCKey: var b [8]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = HTLCKey(int64(binary.BigEndian.Uint64(b[:]))) case *btcutil.Amount: var b [8]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = btcutil.Amount(int64(binary.BigEndian.Uint64(b[:]))) case **wire.ShaHash: var b wire.ShaHash if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = &b case **btcec.PublicKey: var b [33]byte if _, err = io.ReadFull(r, b[:]); err != nil { return err } pubKey, err := btcec.ParsePubKey(b[:], btcec.S256()) if err != nil { return err } *e = pubKey case *[]uint64: var numItems uint16 if err := readElement(r, &numItems); err != nil { return err } // if numItems > 65535 { // return fmt.Errorf("Too many items in []uint64") // } // Read the number of items var items []uint64 for i := uint16(0); i < numItems; i++ { var item uint64 err = readElement(r, &item) if err != nil { return err } items = append(items, item) } *e = items case *[]*btcec.Signature: var numSigs uint8 err = readElement(r, &numSigs) if err != nil { return err } if numSigs > 127 { return fmt.Errorf("Too many signatures!") } // Read that number of signatures var sigs []*btcec.Signature for i := uint8(0); i < numSigs; i++ { sig := new(btcec.Signature) err = readElement(r, &sig) if err != nil { return err } sigs = append(sigs, sig) } *e = sigs return nil case **btcec.Signature: sigBytes, err := wire.ReadVarBytes(r, 0, 73, "signature") if err != nil { return err } sig, err := btcec.ParseSignature(sigBytes, btcec.S256()) if err != nil { return err } *e = sig case *[][32]byte: // How many to read var sliceSize uint16 err = readElement(r, &sliceSize) if err != nil { return err } data := make([][32]byte, 0, sliceSize) // Append the actual for i := uint16(0); i < sliceSize; i++ { var element [32]byte err = readElement(r, &element) if err != nil { return err } data = append(data, element) } *e = data case *[32]byte: if _, err = io.ReadFull(r, e[:]); err != nil { return err } case *wire.BitcoinNet: var b [4]byte if _, err := io.ReadFull(r, b[:]); err != nil { return err } *e = wire.BitcoinNet(binary.BigEndian.Uint32(b[:])) return nil case *[]byte: bytes, err := wire.ReadVarBytes(r, 0, MaxSliceLength, "byte slice") if err != nil { return err } *e = bytes case *PkScript: pkScript, err := wire.ReadVarBytes(r, 0, 25, "pkscript") if err != nil { return err } *e = pkScript case *string: str, err := wire.ReadVarString(r, 0) if err != nil { return err } *e = str case *[]*wire.TxIn: // Read the size (1-byte number of txins) var numScripts uint8 if err := readElement(r, &numScripts); err != nil { return err } if numScripts > 127 { return fmt.Errorf("Too many txins") } // Append the actual TxIns txins := make([]*wire.TxIn, 0, numScripts) for i := uint8(0); i < numScripts; i++ { outpoint := new(wire.OutPoint) txin := wire.NewTxIn(outpoint, nil, nil) if err := readElement(r, &txin); err != nil { return err } txins = append(txins, txin) } *e = txins case **wire.TxIn: // Hash var h [32]byte if _, err = io.ReadFull(r, h[:]); err != nil { return err } hash, err := wire.NewShaHash(h[:]) if err != nil { return err } (*e).PreviousOutPoint.Hash = *hash // Index var idxBytes [4]byte _, err = io.ReadFull(r, idxBytes[:]) if err != nil { return err } (*e).PreviousOutPoint.Index = binary.BigEndian.Uint32(idxBytes[:]) return nil case **wire.OutPoint: // TODO(roasbeef): consolidate with above var h [32]byte if _, err = io.ReadFull(r, h[:]); err != nil { return err } hash, err := wire.NewShaHash(h[:]) if err != nil { return err } // Index var idxBytes [4]byte _, err = io.ReadFull(r, idxBytes[:]) if err != nil { return err } index := binary.BigEndian.Uint32(idxBytes[:]) *e = wire.NewOutPoint(hash, index) default: return fmt.Errorf("Unknown type in readElement: %T", e) } return nil }