code: func (s *attrStore) BlockData(i uint64) (m map[uint64]map[string]interface{}, err error) {
  	m = make(map[uint64]map[string]interface{})
  
  	// Start read-only transaction.
  	err = s.db.View(func(tx *bolt.Tx) error {
  		// Move to the start of the block.
  		min := u64tob(i * attrBlockSize)
  		max := u64tob((i + 1) * attrBlockSize)
  		cur := tx.Bucket([]byte("attrs")).Cursor()
  		for k, v := cur.Seek(min); k != nil; k, v = cur.Next() {
  			// Exit if we're past the end of the block.
  			if bytes.Compare(k, max) != -1 {
  				break
  			}
  
  			// Decode attribute map and associate with id.
  			attrs, err := pilosa.DecodeAttrs(v)
  			if err != nil {
  				return errors.Wrap(err, "decoding attrs")
  			}
  			m[btou64(k)] = attrs
  
  		}
  		return nil
  	})
  	if err != nil {
  		return nil, errors.Wrap(err, "getting block data")
  	}
  	return m, nil
  }
docs: // BlockData returns all data for a single block.