# BLK-011: Has Block (`has_block`)

| Link | Path |
|------|------|
| **Normative** | [NORMATIVE.md](../NORMATIVE.md) |
| **Verification** | [VERIFICATION.md](../VERIFICATION.md) |
| **Tracking** | [TRACKING.yaml](../TRACKING.yaml) |
| **Spec** | [SPEC.md](../../../../resources/SPEC.md) Section 15.2 |

---

## Summary

`has_block(&self, hash: &Bytes32) -> Result<bool>` checks whether a block with the given hash exists in the store without deserializing or decompressing block data.

---

## Specification

```rust
pub fn has_block(&self, hash: &Bytes32) -> Result<bool> {
    // Check cache first (O(1))
    if self.block_cache.contains(hash) || self.header_cache.contains(hash) {
        return Ok(true);
    }

    // Check CF_HEADERS for existence (key-only, no value read)
    let cf = self.cf_headers();
    Ok(self.db.get_pinned_cf(&cf, hash.as_ref())?.is_some())
}
```

### Key Design Decisions

- Uses `CF_HEADERS` for the existence check because headers are smaller and faster to probe than `CF_BLOCKS`.
- Does NOT deserialize or decompress any data -- this is a pure existence check.
- Cache check first avoids unnecessary RocksDB I/O.

---

## Acceptance Criteria

- [ ] Returns `true` for a block that has been stored via `put()`
- [ ] Returns `false` for an unknown hash
- [ ] Does not deserialize or decompress block data
- [ ] Checks in-memory cache before RocksDB
- [ ] Propagates RocksDB errors

---

## Test Plan

| Test Name | Type | Description |
|-----------|------|-------------|
| `test_has_block_exists` | unit | Store a block, verify has_block returns true |
| `test_has_block_missing` | unit | Verify has_block returns false for unknown hash |
| `test_has_block_cache_hit` | unit | Store a block (populates cache), verify has_block returns true without DB read |

---

## Expected Test Files

- `tests/blk_011_tests.rs`
