# BTCRELAY Lookup Service (`ls_btcrelay`)

Query indexed btc-relay state. Spent outputs are **retained** with their
spender recorded, so the beacon lineage stays queryable forever.

## Queries

POST `/lookup` with `{"service": "ls_btcrelay", "query": <one of below>}`:

| Query | Returns |
|-------|---------|
| `{"type":"tip","gid":"<16-hex>"}` | Unspent beacon record(s) for a GID, newest first — normally exactly one. |
| `{"type":"outpoint","txid":"...","vout":0}` | That single record (spent or unspent). |
| `{"type":"txid","txid":"..."}` | All BTCRELAY records of a transaction. |
| `{"type":"spender","txid":"...","vout":0}` | The record; its context's `spentBy` is the spending txid or `null`. Positive answers are trustworthy; `null` is advisory only. |
| `{"type":"chain","gid":"...","limit":100}` | Beacon lineage, oldest → newest. `limit` optional. |
| `{"type":"checkpoints","gid":"...","limit":100}` | Checkpoint records, newest → oldest. `limit` optional. |
| `{"type":"fuel","spent":false}` | Fuel records, newest first. `spent`: `false` = unspent, `true` = spent, `null`/omitted = all. |

## Context

Each returned output carries a JSON context:

```json
{
  "outpoint": "txid.vout",
  "class": "beacon",
  "satoshis": 1,
  "state": { "...parsed fields, see below..." },
  "spentBy": null,
  "createdAt": 1750000000
}
```

`state` per class (`tipHash` / `accWorkHex` are big-endian display hex —
the committed little-endian bytes reversed, matching the btc-relay worker's
`/tip` convention; `gid` / `pkh` are as-committed byte order):

- beacon: `{"class":"beacon","tipHash":hex64,"height":n,"nbits":n,"accWorkHex":hex64,"lastCrank":n,"gid":hex16,"suffixLen":n}`
- checkpoint: `{"class":"checkpoint","gid":hex16,"tipHash":hex64,"height":n,"accWorkHex":hex64,"lastCrank":n}`
- fuel: `{"class":"fuel","pkh":hex40,"satoshis":n}`

Raw transaction bytes and confirmation proofs come from the shared routes
`GET /tx/:txid/hex` and `GET /tx/:txid/bump`.
