code: func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
  	fullLen := r.Len()
  
  	// At the current time, there is no difference between the wire encoding
  	// at protocol version 0 and the stable long-term storage format.  As
  	// a result, make use of existing wire protocol functions.
  	err := readBlockHeader(r, 0, &msg.Header)
  	if err != nil {
  		return nil, err
  	}
  
  	txCount, err := ReadVarInt(r, 0)
  	if err != nil {
  		return nil, err
  	}
  
  	// Prevent more transactions than could possibly fit into a block.
  	// It would be possible to cause memory exhaustion and panics without
  	// a sane upper bound on this count.
  	if txCount > maxTxPerBlock {
  		str := fmt.Sprintf("too many transactions to fit into a block "+
  			"[count %d, max %d]", txCount, maxTxPerBlock)
  		return nil, messageError("MsgBlock.DeserializeTxLoc", str)
  	}
  
  	// Deserialize each transaction while keeping track of its location
  	// within the byte stream.
  	msg.Transactions = make([]*MsgTx, 0, txCount)
  	txLocs := make([]TxLoc, txCount)
  	for i := uint64(0); i < txCount; i++ {
  		txLocs[i].TxStart = fullLen - r.Len()
  		tx := MsgTx{}
  		err := tx.Deserialize(r)
  		if err != nil {
  			return nil, err
  		}
  		msg.Transactions = append(msg.Transactions, &tx)
  		txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart
  	}
  
  	return txLocs, nil
  }
docs: // DeserializeTxLoc decodes r in the same manner Deserialize does, but it takes
  // a byte buffer instead of a generic reader and returns a slice containing the
  // start and length of each transaction within the raw data that is being
  // deserialized.