<!-- source: https://secondlayer.tools/docs/verify-reference -->

# `@secondlayer/verify`

The client-side verifier: check a Stacks block, its transactions and its state against a Bitcoin-anchored checkpoint, trusting no one. The [Verify page](/docs/verification) explains what each check proves.

## Verify a block

Check one block against a checkpoint, with no trust in the node that served it.

Import from `@secondlayer/verify`.

### verifyBlockState(input)

Verifies a block's state against an authenticated header.

The witness must recompute `stateRoot`, then every leaf is classified. With
state writes, any leaf that is not a named write, a carried parent value or
MARF bookkeeping is a hidden write. Without them the diff is still proven,
since every leaf is in the block: carried leaves are told apart only through
`parentLeaves`, and the remaining writes come back unnamed.

```ts
verifyBlockState(input: BlockStateInput): Promise<BlockStateResult>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `height` | `number` | yes | MARF height of the block (its Stacks chain length). |
| `parentBlockId` | `Bytes` | yes | Parent block id from the authenticated header. |
| `stateRoot` | `Bytes` | yes | state_index_root from the authenticated header. |
| `witness` | `Bytes` | yes |  |
| `writes` | `StateWrite[] \| null` | yes | The block's state_writes; null when the source has none (names unavailable). |
| `rows` | `VmEventRow[]` | no | Indexed rows to prove against the diff. |
| `parentLeaves` | `WitnessLeaf[]` | no | Leaves of the parent's own trie, from a parent witness whose root the caller checked against the parent header: each is the parent state's value at its path. Resolves carried leaves without a proof per leaf. |
| `parentHolds` | `(leaf: WitnessLeaf) => Promise<boolean>` | no | True iff the leaf's value is stored at its path in the parent's state (proven by the caller). Asked only with state_writes, for leaves the parent's own trie does not explain. |

### new TransactionsError(code, message)

Thrown for a malformed block body or a transaction root mismatch.

```ts
new TransactionsError(code: "malformed" | "tx-root-mismatch", message: string)
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `code` | `"malformed" \| "tx-root-mismatch"` | yes |  |
| `message` | `string` | yes |  |

### blockTransactions(raw, header)

Hashes a block's transactions and checks them against the header.

Each transaction is hashed to its txid and checked against the header's
`tx_merkle_root`. The body after `header.byteLength` is a u32 count, then the
transactions back to back. It returns null when the bytes are the header
alone, as a source that serves headers only does. It throws [`TransactionsError`](/docs/verify-reference#m-TransactionsError) on a malformed body, trailing bytes or a root
mismatch.

```ts
blockTransactions(raw: Bytes, header: NakamotoHeader): BlockTransaction[] | null
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `raw` | `Bytes` | yes |  |
| `header.version` | `number` | yes | Low 7 bits = header version; high bit = shadow block. |
| `header.chainLength` | `bigint` | yes |  |
| `header.burnSpent` | `bigint` | yes |  |
| `header.consensusHash` | `Bytes` | yes |  |
| `header.parentBlockId` | `Bytes` | yes |  |
| `header.txMerkleRoot` | `Bytes` | yes |  |
| `header.stateIndexRoot` | `Bytes` | yes |  |
| `header.timestamp` | `bigint` | yes |  |
| `header.minerSignature` | `Bytes` | yes |  |
| `header.signerSignatures` | `Bytes[]` | yes | 65-byte recoverable signatures: recovery id, r, s. |
| `header.signerSighashPreimage` | `Bytes` | yes | Header bytes minus the signer_signature vec: the signer sighash preimage. |
| `header.byteLength` | `number` | yes | Serialized header length; block bytes after this are the transactions. |

### txMerkleRoot(txids)

Computes the `tx_merkle_root` over transaction ids.

A leaf is H(0x00 ‖ txid) and a node is H(0x01 ‖ l ‖ r). An odd level
duplicates its last node, and a lone leaf is still paired with itself, so a
one-transaction block hashes H(0x01 ‖ leaf ‖ leaf).

```ts
txMerkleRoot(txids: Bytes[]): Bytes
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `txids` | `Bytes[]` | yes |  |

### describeLinks(r, cp, opts)

Describes a verification as one line per link and a verdict.

It is the human view, shared by the CLI and the browser checker. Ancestry
appears only below the checkpoint. `rows` says whether the caller asked for
the rows link.

```ts
describeLinks(
  r: BlockVerification,
  cp: VerifyCheckpoint,
  opts?: { rows?: boolean },
): { lines: LinkLine[]; verdict: { ok: boolean; text: string } }
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `r.ok` | `boolean` | yes | Every step passed. At or above the checkpoint: header, burn binding, signatures, state root, names and rows. Below it: ancestry, header, state root, names and rows (and the burn binding when Bitcoin reaches it). |
| `r.height` | `number` | no |  |
| `r.blockId` | `string` | no |  |
| `r.blockHash` | `string` | no | Nakamoto block hash (the header's signer sighash), hex. Absent for epoch 2.x. |
| `r.consensusHash` | `string` | no | The header's consensus hash, hex. |
| `r.timestamp` | `number` | no | Nakamoto header timestamp, Unix seconds. Absent for epoch 2.x. |
| `r.stateRoot` | `string` | no | The header's state_index_root, hex: what the witness must hash to. |
| `r.ancestry` | `Ancestry` | no | Set for blocks below the checkpoint, which need no signatures. |
| `r.cycle` | `number` | no |  |
| `r.burnHeight` | `number` | no |  |
| `r.bitcoinBlockHash` | `string` | no | Display-order hex. |
| `r.signerWeight` | `bigint` | no |  |
| `r.totalWeight` | `bigint` | no |  |
| `r.threshold` | `bigint` | no |  |
| `r.transactions` | `BlockTransaction[]` | no | The block's transactions, checked against the header's tx_merkle_root. Absent for epoch 2.x blocks and when the source served the header only. |
| `r.diff` | `ProvenDiff` | no |  |
| `r.writes` | `StateWrite[]` | no | Every state_writes row the names step checked, in ordinal order. |
| `r.rowsChecked` | `number` | no | vm_events rows proven against the diff. |
| `r.notes` | `string[]` | yes |  |
| `r.failures` | `VerifyFailure[]` | yes | Empty when ok. The first entry is the first broken link. |
| `cp.stacks` | `{ header: string; cycle: number; signerSet: string }` | yes |  |
| `cp.bitcoin` | `Checkpoint` | yes | Retarget-boundary Bitcoin header at or below the first burn block of `stacks.cycle`. |
| `opts.rows` | `boolean` | no |  |

### new BlockVerifier(opts)

Verifies blocks from one checkpoint against one source.

It caches the Bitcoin header chain, proven signer sets and fetched headers
across calls.

```ts
new BlockVerifier(opts: VerifyOptions)
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `source` | `ProofSource` | yes |  |
| `checkpoint` | `VerifyCheckpoint` | no | Defaults to MAINNET_CHECKPOINT. |
| `rows` | `boolean` | no | Also prove the block's indexed vm_events rows against its diff: reads the source's `getVmEvents`, which bill as Index rows on the Secondlayer API. Off by default. Naming the diff's writes (`getStateWrites`, free on `/v1/proofs`) is always on when the source has them. |
| `onStep` | `(step: VerifyStep) => void` | no | Called once per link as it passes, in the order the verifier proves them. Failures arrive in the result, not here. |

### BlockVerifier.verify(ref)

Verify one block by id (hex) or height. Never throws for bad source data.

```ts
BlockVerifier.verify(ref: string | number): Promise<BlockVerification>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | `string \| number` | yes |  |

### BlockVerifier.verifyBitcoinTx(proof, opts)

Proves a Bitcoin tx is in the checkpoint's Bitcoin chain.

It can also prove that one output pays `expect`. Pass an `SpvProof`, or a
txid for the source's `getBitcoinTxProof` to fetch. It never throws for bad
source data.

```ts
BlockVerifier.verifyBitcoinTx(
  proof: string | SpvProof,
  opts?: { expect?: BitcoinTxExpect },
): Promise<BitcoinTxVerification>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `proof` | `string \| SpvProof` | yes |  |
| `opts.expect` | `BitcoinTxExpect` | no |  |

### verifyBlock(ref, opts)

One-shot: verify a block from a checkpoint (MAINNET_CHECKPOINT by default).

```ts
verifyBlock(ref: string | number, opts: VerifyOptions): Promise<BlockVerification>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | `string \| number` | yes |  |
| `opts.source` | `ProofSource` | yes |  |
| `opts.checkpoint` | `VerifyCheckpoint` | no | Defaults to MAINNET_CHECKPOINT. |
| `opts.rows` | `boolean` | no | Also prove the block's indexed vm_events rows against its diff: reads the source's `getVmEvents`, which bill as Index rows on the Secondlayer API. Off by default. Naming the diff's writes (`getStateWrites`, free on `/v1/proofs`) is always on when the source has them. |
| `opts.onStep` | `(step: VerifyStep) => void` | no | Called once per link as it passes, in the order the verifier proves them. Failures arrive in the result, not here. |

### Constants

- `LINKS`: `readonly { step: VerifyStep; label: string }[]`. The chain of links, in the order verifyBlock walks them.

## Proof sources

Where proofs come from: the Secondlayer API or a Stacks node.

Import from `@secondlayer/verify`.

### new NodeRpcProofSource(opts)

Reads blocks, epoch 2.x headers and MARF proofs from a Stacks node.

It uses the node's RPC. Witnesses, burn preimages and Bitcoin headers need
another source: spread this over one.

```ts
new NodeRpcProofSource(opts: NodeRpcSourceOptions)
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `nodeUrl` | `string` | yes | Stacks node RPC origin, e.g. `http://localhost:20443`. |
| `fetch` | `Fetch` | no |  |

### NodeRpcProofSource.getBlock(ref)

Raw block bytes, header first, by block id or height.

```ts
NodeRpcProofSource.getBlock(ref: string | number): Promise<Bytes>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | `string \| number` | yes |  |

### NodeRpcProofSource.getEpoch2Header(blockId)

An epoch 2.x header and its consensus hash, by index block hash.

```ts
NodeRpcProofSource.getEpoch2Header(blockId: string): Promise<Epoch2HeaderResponse>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `blockId` | `string` | yes |  |

### NodeRpcProofSource.getMarfProof(pathHex, tipId)

A MARF inclusion proof for a path at a tip.

It is null when the key is absent.

```ts
NodeRpcProofSource.getMarfProof(
  pathHex: string,
  tipId: string,
): Promise<MarfProofResponse | null>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `pathHex` | `string` | yes |  |
| `tipId` | `string` | yes |  |

### new SecondlayerProofSource(opts)

Reads every proof input from the Secondlayer API.

Blocks, epoch 2.x headers, MARF proofs, witnesses, burn preimages, Bitcoin
headers and each block's state writes come from `/v1/proofs/*`, which is free
and rate limited. Indexed `vm_events` rows come from the Index API as metered
rows, and are read only when `verifyBlock` gets `rows: true`. Methods are own
properties, so a partial source spreads over it:
`{ ...new SecondlayerProofSource(o), ...new NodeRpcProofSource(n) }`.

```ts
new SecondlayerProofSource(opts?: SecondlayerSourceOptions)
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `baseUrl` | `string` | no | API origin. Defaults to [`DEFAULT_API_URL`](/docs/verify-reference#c-DEFAULT_API_URL). |
| `apiKey` | `string` | no | Optional. Proofs are keyless; a key raises the rate limit. Required for `rows: true` (metered Index reads). Sent as `Authorization: Bearer`. |
| `fetch` | `Fetch` | no |  |

### SecondlayerProofSource.getBlock(ref)

Raw block bytes, header first, by block id or height.

```ts
SecondlayerProofSource.getBlock(ref: string | number): Promise<Bytes>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | `string \| number` | yes |  |

### SecondlayerProofSource.getEpoch2Header(blockId)

An epoch 2.x header and its consensus hash, by index block hash.

```ts
SecondlayerProofSource.getEpoch2Header(blockId: string): Promise<Epoch2HeaderResponse>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `blockId` | `string` | yes |  |

### SecondlayerProofSource.getMarfProof(pathHex, tipId)

A MARF inclusion proof for a path at a tip.

It is null when the key is absent.

```ts
SecondlayerProofSource.getMarfProof(
  pathHex: string,
  tipId: string,
): Promise<MarfProofResponse | null>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `pathHex` | `string` | yes |  |
| `tipId` | `string` | yes |  |

### SecondlayerProofSource.getWitness(blockId)

The state witness for a block.

```ts
SecondlayerProofSource.getWitness(blockId: string): Promise<Bytes>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `blockId` | `string` | yes |  |

### SecondlayerProofSource.getBurnPreimage(consensusHash)

The burn preimage behind a consensus hash.

```ts
SecondlayerProofSource.getBurnPreimage(consensusHash: string): Promise<BurnPreimage>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `consensusHash` | `string` | yes |  |

### SecondlayerProofSource.getBitcoinHeaders(from, count)

Raw 80-byte Bitcoin headers, `count` of them from height `from`.

```ts
SecondlayerProofSource.getBitcoinHeaders(from: number, count: number): Promise<string[]>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `from` | `number` | yes |  |
| `count` | `number` | yes |  |

### SecondlayerProofSource.getStateWrites(height)

Every MARF write of a block, in ordinal order.

It is null when there are none.

```ts
SecondlayerProofSource.getStateWrites(height: number): Promise<StateWrite[] | null>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `height` | `number` | yes |  |

### SecondlayerProofSource.getVmEvents(height)

The indexed `vm_events` write rows of a block, from the Index API.

```ts
SecondlayerProofSource.getVmEvents(height: number): Promise<VmEventRow[]>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `height` | `number` | yes |  |

### SecondlayerProofSource.getBitcoinTxProof(txid)

A Bitcoin tx, its merkle branch and header, by txid.

The txid is display-order hex.

```ts
SecondlayerProofSource.getBitcoinTxProof(txid: string): Promise<SpvProof>
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `txid` | `string` | yes |  |

### new SourceError(url, status, detail)

Thrown when a proof source request fails.

It carries the request `url`, the HTTP `status` (null when there was none)
and the detail.

```ts
new SourceError(url: string, status: number | null, detail: string)
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | `string` | yes |  |
| `status` | `number \| null` | yes |  |
| `detail` | `string` | yes |  |

### Constants

- `DEFAULT_API_URL`: `"https://api.secondlayer.tools"`. The hosted API.

## Proofs and headers

The parsers and checks a block verification is built from.

Import from `@secondlayer/verify`.

### hex(b)

Encodes bytes as a lowercase hex string.

```ts
hex(b: Bytes): string
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `b` | `Bytes` | yes |  |

### unhex(s)

Hex to bytes; tolerates a 0x prefix.

```ts
unhex(s: string): Bytes
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `s` | `string` | yes |  |

### blockId(h)

Computes a header's block id, also called the index block hash.

The id is sha512/256(block_hash || consensus_hash). A Nakamoto block hash is
its signer signature hash; a 2.x one hashes the whole header.

```ts
blockId(h: StacksHeader): Bytes
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `h` | `StacksHeader` | yes |  |

### isEpoch2Header(h)

Narrows a Stacks header to an epoch 2.x header.

```ts
isEpoch2Header(h: StacksHeader): h is Epoch2Header
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `h` | `StacksHeader` | yes |  |

### parseEpoch2Header(raw, consensusHash)

Parses the epoch 2.x block header at the start of `raw`.

`raw` is a header from `/v2/headers`, or block bytes from `/v2/blocks/<id>`.
`consensusHash` is the 20-byte hash of the sortition that elected the block.

```ts
parseEpoch2Header(raw: Bytes, consensusHash: Bytes): Epoch2Header
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `raw` | `Bytes` | yes |  |
| `consensusHash` | `Bytes` | yes |  |

### parseNakamotoHeader(raw)

Parse the NakamotoBlockHeader at the start of raw block bytes
(`/v3/blocks/<id>`). Handles v0 and v1 (v1 appends `problematic_txs`).

```ts
parseNakamotoHeader(raw: Bytes): NakamotoHeader
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `raw` | `Bytes` | yes |  |

### signerSignatureHash(h)

Hashes a Nakamoto header the way its signers sign it.

It is sha512/256 over every header field except the signer signatures, which
is also the header's `block_hash`.

```ts
signerSignatureHash(h: NakamotoHeader): Bytes
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `version` | `number` | yes | Low 7 bits = header version; high bit = shadow block. |
| `chainLength` | `bigint` | yes |  |
| `burnSpent` | `bigint` | yes |  |
| `consensusHash` | `Bytes` | yes |  |
| `parentBlockId` | `Bytes` | yes |  |
| `txMerkleRoot` | `Bytes` | yes |  |
| `stateIndexRoot` | `Bytes` | yes |  |
| `timestamp` | `bigint` | yes |  |
| `minerSignature` | `Bytes` | yes |  |
| `signerSignatures` | `Bytes[]` | yes | 65-byte recoverable signatures: recovery id, r, s. |
| `signerSighashPreimage` | `Bytes` | yes | Header bytes minus the signer_signature vec: the signer sighash preimage. |
| `byteLength` | `number` | yes | Serialized header length; block bytes after this are the transactions. |

### marfPath(key)

Hashes a key to its MARF path: sha512/256 of the UTF-8 key.

```ts
marfPath(key: string): Bytes
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `key` | `string` | yes |  |

### marfProofAncestors(proof)

Lists the ancestor tries a MARF proof crosses.

Each id is the backptr a descendant trie follows toward the leaf, and
`verifyMarfProof` needs every one's header. They are read from untrusted
proof bytes, so they are only fetch hints: the proof still fails unless each
header hashes to the id the trie committed. Malformed proofs yield no ids.

```ts
marfProofAncestors(proof: Bytes): string[]
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `proof` | `Bytes` | yes |  |

### marfValue(value)

Hashes a value to its MARF value: sha512/256, padded to 40 bytes.

```ts
marfValue(value: string): Bytes
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string` | yes |  |

### verifyMarfProof(input)

Verifies a MARF inclusion proof.

It is true only when `value` is stored at `path` in the MARF whose tip root
is `root`. Inclusion only: MARF proofs cannot prove absence. Malformed proof
bytes verify false.

```ts
verifyMarfProof(input: MarfProofInput): boolean
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `proof` | `Bytes` | yes | Consensus-serialized TrieMerkleProof (`/v2/clarity/marf/<path>?proof=1`). |
| `path` | `Bytes` | yes | Leaf path: `marfPath(key)`. |
| `value` | `Bytes` | yes | 40-byte MARFValue: `marfValue(valueString)`. |
| `root` | `Bytes` | yes | Tip state_index_root, from a header the caller authenticated. |
| `headers` | `StacksHeader[]` | yes | Tip header plus every ancestor header the proof crosses. Each contributes state_index_root -> recomputed block id, so ancestor roots are only ever vouched for by header bytes (a bare root->id map would let a forged ancestor trie through). |

### classifyBlockDiff(input)

Classify every leaf of block N's trie against the claimed write set.
Each leaf must be a claimed write, a carried (unchanged) parent value, or a
MARF-internal key; anything else is a hidden write.

```ts
classifyBlockDiff(input: BlockDiffInput): BlockDiff
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `leaves` | `WitnessLeaf[]` | yes | `parseWitness(bytes).leaves`, from a witness whose root was checked. |
| `writes` | `[string, string][]` | yes | Claimed writes of the block: [key, value string] as stored by Clarity. |
| `internal` | `[string, string][]` | yes | MARF bookkeeping keys (`__MARF_*`) with their raw 40-byte MARFValue hex, derived from the header chain. |
| `parentValue` | `(pathHex: string) => string \| undefined` | yes | Value at `pathHex` in the PARENT block's state (40-byte MARFValue hex), already proven by the caller. |

### parseWitness(bytes)

Parse a v2 state witness and recompute its root. Throws on malformed input.
The result proves nothing until `root` equals a header's state_index_root.

```ts
parseWitness(bytes: Bytes): StateWitness
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `bytes` | `Bytes` | yes |  |

### decodeSignerSet(value)

Decodes a `cycle-signer-set` value from the `.signers` contract.

The value is hex or bytes, as stored in the MARF:
`(some (list (tuple (signer principal) (weight uint) ...)))`.

```ts
decodeSignerSet(value: string | Bytes): SignerSet
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string \| Bytes` | yes |  |

### verifySignerSignatures(header, set)

Sums the weight of the signers who signed a block header.

It recovers each header signature's key over `signer_signature_hash`, maps it
to its mainnet p2pkh principal, and sums weights from `set`. The set must be
the one for the reward cycle of the tenure-electing burn block.

```ts
verifySignerSignatures(header: NakamotoHeader, set: SignerSet): SignerCheck
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `header.version` | `number` | yes | Low 7 bits = header version; high bit = shadow block. |
| `header.chainLength` | `bigint` | yes |  |
| `header.burnSpent` | `bigint` | yes |  |
| `header.consensusHash` | `Bytes` | yes |  |
| `header.parentBlockId` | `Bytes` | yes |  |
| `header.txMerkleRoot` | `Bytes` | yes |  |
| `header.stateIndexRoot` | `Bytes` | yes |  |
| `header.timestamp` | `bigint` | yes |  |
| `header.minerSignature` | `Bytes` | yes |  |
| `header.signerSignatures` | `Bytes[]` | yes | 65-byte recoverable signatures: recovery id, r, s. |
| `header.signerSighashPreimage` | `Bytes` | yes | Header bytes minus the signer_signature vec: the signer sighash preimage. |
| `header.byteLength` | `number` | yes | Serialized header length; block bytes after this are the transactions. |
| `set.clear` | `() => void` | yes |  |
| `set.delete` | `(key: string) => boolean` | yes |  |
| `set.forEach` | `(callbackfn: (value: bigint, key: string, map: Map<string, bigint>) => void, thisArg?: any) => void` | yes | Executes a provided function once per each key/value pair in the Map, in insertion order. |
| `set.get` | `(key: string) => bigint \| undefined` | yes | Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map. |
| `set.has` | `(key: string) => boolean` | yes |  |
| `set.set` | `(key: string, value: bigint) => SignerSet` | yes | Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated. |
| `set.size` | `number` | yes |  |
| `set.entries` | `() => MapIterator<[string, bigint]>` | yes | Returns an iterable of key, value pairs for every entry in the map. |
| `set.keys` | `() => MapIterator<string>` | yes | Returns an iterable of keys in the map |
| `set.values` | `() => MapIterator<bigint>` | yes | Returns an iterable of values in the map |

### cycleStart(cycle, firstBurnHeight, cycleLength)

First burn height of reward cycle `cycle`.

```ts
cycleStart(cycle: number, firstBurnHeight?: number, cycleLength?: number): number
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `cycle` | `number` | yes |  |
| `firstBurnHeight` | `number` | no |  |
| `cycleLength` | `number` | no |  |

### rewardCycle(burnHeight, firstBurnHeight, cycleLength)

Reward cycle containing `burnHeight`.

```ts
rewardCycle(burnHeight: number, firstBurnHeight?: number, cycleLength?: number): number
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `burnHeight` | `number` | yes |  |
| `firstBurnHeight` | `number` | no |  |
| `cycleLength` | `number` | no |  |

### verifyConsensusPreimage(consensusHash, preimage)

Check `preimage` against a 20-byte consensus hash. Returns the burn block
hash as hex, already in Bitcoin display order (as `bitcoin-cli
getblockhash` prints it), or null when the preimage does not match.

```ts
verifyConsensusPreimage(consensusHash: Bytes, preimage: Bytes): string | null
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `consensusHash` | `Bytes` | yes |  |
| `preimage` | `Bytes` | yes |  |

### dataVarKey(contractId, varName)

The MARF key of a data variable: `vm::<contract>::1::<var>`.

```ts
dataVarKey(contractId: string, varName: string): string
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `contractId` | `string` | yes |  |
| `varName` | `string` | yes |  |

### ftBalanceKey(contractId, tokenName, holder)

The MARF key of a fungible token balance: `vm::<contract>::2::<token>::<principal json>`.

The holder is serde-JSON PrincipalData, e.g. `{"Standard":[22,[...20 bytes]]}`.

```ts
ftBalanceKey(contractId: string, tokenName: string, holder: string): string
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `contractId` | `string` | yes |  |
| `tokenName` | `string` | yes |  |
| `holder` | `string` | yes |  |

### mapEntryKey(contractId, mapName, key)

The MARF key of a map entry: `vm::<contract>::0::<map>::<serialized key hex>`.

```ts
mapEntryKey(contractId: string, mapName: string, key: ClarityValue): string
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `contractId` | `string` | yes |  |
| `mapName` | `string` | yes |  |
| `key` | `ClarityValue` | yes |  |

### Constants

- `SIGNERS_CONTRACT`: `"SP000000000000000000002Q6VF78.signers"`. Boot contract holding `cycle-signer-set`, one entry per reward cycle.
- `MAINNET_FIRST_BURN_HEIGHT`: `666050`. Mainnet PoX parameters (first_burnchain_block_height, reward_cycle_length).
- `MAINNET_PREPARE_LENGTH`: `100`. Mainnet prepare phase: the last 100 burn blocks of a cycle pick the next cycle's signers.
- `MAINNET_REWARD_CYCLE_LENGTH`: `2100`. Burn blocks in a mainnet reward cycle.

## Bitcoin headers

The Bitcoin header chain a Stacks block anchors to, and its checkpoint.

Import from `@secondlayer/verify`.

### HeaderChain.fromCheckpoint(checkpoint)

Starts a header chain at a checkpoint.

```ts
HeaderChain.fromCheckpoint(checkpoint: Checkpoint): HeaderChain
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `height` | `number` | yes |  |
| `header` | `string \| Uint8Array<ArrayBufferLike>` | yes | Raw 80-byte header, bytes or hex. Trusted without validation. |
| `periodStartTime` | `number` | no | Timestamp of the first block of the checkpoint's difficulty period (height − height % 2016). Required when the checkpoint is not itself a period start; needed to verify the next retarget. |

### HeaderChain.heightOf(hashHex)

Height of a header in this chain by display-order hash, or undefined.

```ts
HeaderChain.heightOf(hashHex: string): number | undefined
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `hashHex` | `string` | yes |  |

### HeaderChain.headerAt(height)

The header entry at a height, if the chain has one.

```ts
HeaderChain.headerAt(height: number): ChainEntry | undefined
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `height` | `number` | yes |  |

### HeaderChain.append(headers)

Validates and appends headers in order. All-or-nothing: if any header
fails, the chain is left exactly as it was and the error is thrown.

```ts
HeaderChain.append(headers: Iterable<string | Uint8Array, any, any>): void
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `headers` | `Iterable<string \| Uint8Array, any, any>` | yes |  |

### new HeaderValidationError(height, rule, detail)

Thrown when a Bitcoin header fails a validation rule.

`rule` names the rule and `height` the header that failed it.

```ts
new HeaderValidationError(height: number, rule: HeaderRule, detail: string)
```

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `height` | `number` | yes |  |
| `rule` | `HeaderRule` | yes |  |
| `detail` | `string` | yes |  |

### Constants

- `MAINNET_CHECKPOINT`: `VerifyCheckpoint`. Mainnet: Stacks block 9,055,251 (`10cb4e95…c5be`) holding the cycle 144 signer set (31 signers, weight 4000), and Bitcoin block 967,680 (a retarget-period start at or below cycle 144's first burn block 968,450).

## Types

- `Ancestry`: How a block below the checkpoint was tied to it.
  - `fromHeight`: `number`. Trusted descendant it was proven from: the checkpoint, or a block proven below it earlier.
  - `fromBlockId`: `string`
  - `via`: `"parents" \| "marf"`. `parents`: each header hashes to the parent id its child commits to. `marf`: one MARF proof of `__MARF_BLOCK_HEIGHT_TO_HASH::<height>` against the descendant's state root.
- `BitcoinTxExpect`: The output fields a proven transaction must match.
  - `address`?: `string`
  - `script`?: `Bytes`
  - `amount`?: `bigint`
- `BitcoinTxOutputView`: One output of a proven Bitcoin transaction.
  - `vout`: `number`
  - `amount`: `bigint`. Satoshis.
  - `script`: `Bytes`
  - `type`: `OutputScriptType`
  - `address`?: `string`. Mainnet address, when the script has one.
- `BitcoinTxVerification`: The result of proving a Bitcoin transaction against the checkpoint's chain.
  - `ok`: `boolean`. The tx is in a block of the checkpoint's Bitcoin chain, and any `expect` matched.
  - `txid`?: `string`. Display-order hex.
  - `height`?: `number`
  - `blockHash`?: `string`. Display-order hex.
  - `outputs`?: `BitcoinTxOutputView[]`
  - `matched`?: `number`. Index of the first output matching `expect`, when given.
  - `failures`: `VerifyFailure[]`. Empty when ok.
- `BlockDiff`: A block's witnessed leaves, split into writes, carried, and internal.
  - `writes`: `ClassifiedLeaf[]`. Leaves matching a claimed write (path and value).
  - `carried`: `WitnessLeaf[]`. Unclaimed leaves holding the parent's value: copied forward, not written.
  - `internal`: `ClassifiedLeaf[]`. Leaves matching a `__MARF_*` bookkeeping entry.
  - `hidden`: `WitnessLeaf[]`. Leaves nothing explains: an unreported write. Non-empty = reject.
  - `missing`: `string[]`. Claimed write keys with no leaf holding the claimed value. Non-empty = reject.
  - `complete`: `boolean`. No hidden leaves and no missing writes: the claimed writes are the block's complete diff.
- `BlockDiffInput`: The witness leaves, claimed writes, and bookkeeping keys to classify.
  - `leaves`: `WitnessLeaf[]`. `parseWitness(bytes).leaves`, from a witness whose root was checked.
  - `writes`: `[string, string][]`. Claimed writes of the block: [key, value string] as stored by Clarity.
  - `internal`: `[string, string][]`. MARF bookkeeping keys (`__MARF_*`) with their raw 40-byte MARFValue hex, derived from the header chain.
  - `parentValue`: `(pathHex: string) => string \| undefined`. Value at `pathHex` in the PARENT block's state (40-byte MARFValue hex), already proven by the caller.
- `BlockHeader`
  - `version`: `number`. Signed 32-bit version field.
  - `prevHash`: `string`. Display-order hex of the previous block hash.
  - `merkleRoot`: `string`. Display-order hex of the merkle root.
  - `time`: `number`. Unix timestamp, seconds.
  - `bits`: `number`. Compact-encoded target.
  - `nonce`: `number`
- `BlockStateInput`: A block's height, parent, and state root to check rows against.
  - `height`: `number`. MARF height of the block (its Stacks chain length).
  - `parentBlockId`: `Bytes`. Parent block id from the authenticated header.
  - `stateRoot`: `Bytes`. state_index_root from the authenticated header.
  - `witness`: `Bytes`
  - `writes`: `StateWrite[] \| null`. The block's state_writes; null when the source has none (names unavailable).
  - `rows`?: `VmEventRow[]`. Indexed rows to prove against the diff.
  - `parentLeaves`?: `WitnessLeaf[]`. Leaves of the parent's own trie, from a parent witness whose root the caller checked against the parent header: each is the parent state's value at its path. Resolves carried leaves without a proof per leaf.
  - `parentHolds`?: `(leaf: WitnessLeaf) => Promise<boolean>`. True iff the leaf's value is stored at its path in the parent's state (proven by the caller). Asked only with state_writes, for leaves the parent's own trie does not explain.
- `BlockStateResult`: The proven diff, rows checked, notes, and failures.
  - `diff`?: `ProvenDiff`
  - `rowsChecked`: `number`
  - `notes`: `string[]`
  - `failures`: `StateFailure[]`
- `BlockTransaction`: A transaction's id and its consensus-serialized bytes.
  - `txid`: `string`. sha512/256 of the transaction bytes, hex.
  - `raw`: `Bytes`. The consensus-serialized transaction.
- `BlockVerification`: The result of verifying a block, step by step.
  - `ok`: `boolean`. Every step passed. At or above the checkpoint: header, burn binding, signatures, state root, names and rows. Below it: ancestry, header, state root, names and rows (and the burn binding when Bitcoin reaches it).
  - `height`?: `number`
  - `blockId`?: `string`
  - `blockHash`?: `string`. Nakamoto block hash (the header's signer sighash), hex. Absent for epoch 2.x.
  - `consensusHash`?: `string`. The header's consensus hash, hex.
  - `timestamp`?: `number`. Nakamoto header timestamp, Unix seconds. Absent for epoch 2.x.
  - `stateRoot`?: `string`. The header's state_index_root, hex: what the witness must hash to.
  - `ancestry`?: `Ancestry`. Set for blocks below the checkpoint, which need no signatures.
  - `cycle`?: `number`
  - `burnHeight`?: `number`
  - `bitcoinBlockHash`?: `string`. Display-order hex.
  - `signerWeight`?: `bigint`
  - `totalWeight`?: `bigint`
  - `threshold`?: `bigint`
  - `transactions`?: `BlockTransaction[]`. The block's transactions, checked against the header's tx_merkle_root. Absent for epoch 2.x blocks and when the source served the header only.
  - `diff`?: `ProvenDiff`
  - `writes`?: `StateWrite[]`. Every state_writes row the names step checked, in ordinal order.
  - `rowsChecked`?: `number`. vm_events rows proven against the diff.
  - `notes`: `string[]`
  - `failures`: `VerifyFailure[]`. Empty when ok. The first entry is the first broken link.
- `BurnPreimage`: Sortition preimage behind a consensus hash.
  - `preimage`: `Bytes`
  - `burnHeight`: `number`. The source's claimed burn height: a hint for how far to sync Bitcoin headers, never trusted.
- `Bytes`: A byte string, held as a Uint8Array.
- `ChainEntry`: A Bitcoin header with its height, hash, and raw bytes.
  - `height`: `number`
  - `hash`: `string`. Display-order hex.
  - `header`: `BlockHeader`
  - `raw`: `Uint8Array`
- `Checkpoint`: A trusted Bitcoin header that anchors header validation.
  - `height`: `number`
  - `header`: `string \| Uint8Array<ArrayBufferLike>`. Raw 80-byte header, bytes or hex. Trusted without validation.
  - `periodStartTime`?: `number`. Timestamp of the first block of the checkpoint's difficulty period (height − height % 2016). Required when the checkpoint is not itself a period start; needed to verify the next retarget.
- `ClassifiedLeaf`
  - `key`: `string`
  - `path`: `Bytes`. Full 32-byte trie path: `marfPath(key)`.
  - `valueHash`: `Bytes`. 32-byte value hash (first 32 bytes of the MARFValue; the tail is zero).
- `DiffLeaf`
  - `key`?: `string`
  - `path`: `string`
  - `valueHash`: `string`
- `DiffWrite`
  - `key`?: `string`. MARF key, when a state_writes row names the leaf.
  - `path`: `string`. Leaf path, hex.
  - `valueHash`: `string`. sha512/256 of the stored value string, hex.
  - `txIndex`?: `number \| null`. Transaction of the last write; null for block-level writes.
  - `value`?: `string`. The stored value string (hex of a Clarity value) the leaf holds; named writes only.
  - `named`: `boolean`. False when the source had no state_writes: the leaf may also be a carried copy.
- `Epoch2Header`: Epoch 2.x anchored block header.
  - `version`: `number`
  - `burnSpent`: `bigint`. total_work.burn: burn spent on the fork so far.
  - `chainLength`: `bigint`. total_work.work: the Stacks chain length (one per anchored block).
  - `vrfProof`: `Bytes`
  - `parentBlockHash`: `Bytes`
  - `parentMicroblock`: `Bytes`
  - `parentMicroblockSequence`: `number`
  - `txMerkleRoot`: `Bytes`
  - `stateIndexRoot`: `Bytes`. Covers the block and the parent microblock stream it confirms.
  - `microblockPubkeyHash`: `Bytes`
  - `blockHash`: `Bytes`. sha512/256 of the serialized header.
  - `consensusHash`: `Bytes`
- `Epoch2HeaderResponse`: An epoch 2.x header and the consensus hash it commits to.
  - `header`: `Bytes`. Consensus-serialized StacksBlockHeader.
  - `consensusHash`: `Bytes`
- `Fetch`: `(url: string, init?: RequestInit) => Promise<Response>`
- `HeaderChain`: A validated chain of Bitcoin headers, grown forward from a checkpoint.
  - `tip`: `ChainEntry`
  - `totalWork`: `bigint`. Work summed from the checkpoint (inclusive) to the tip; not chainwork since genesis.
  - `checkpointHeight`: `number`
- `HeaderRule`: A Bitcoin header rule a chain check can fail on.
- `LinkLine`: One verification step with its status and what it proved.
  - `step`: `VerifyStep`
  - `label`: `string`
  - `status`: `LinkStatus`
  - `detail`: `string`. What the link proved, why it failed, or why it was not checked.
- `LinkStatus`: `"ok" \| "failed" \| "skipped"`
- `MarfProofInput`: A MARF proof with the leaf path and value it covers.
  - `proof`: `Bytes`. Consensus-serialized TrieMerkleProof (`/v2/clarity/marf/<path>?proof=1`).
  - `path`: `Bytes`. Leaf path: `marfPath(key)`.
  - `value`: `Bytes`. 40-byte MARFValue: `marfValue(valueString)`.
  - `root`: `Bytes`. Tip state_index_root, from a header the caller authenticated.
  - `headers`: `StacksHeader[]`. Tip header plus every ancestor header the proof crosses. Each contributes state_index_root -> recomputed block id, so ancestor roots are only ever vouched for by header bytes (a bare root->id map would let a forged ancestor trie through).
- `MarfProofResponse`: Node RPC `/v2/clarity/marf/<path>?proof=1` answer.
  - `data`: `string`. Value string as Clarity stored it (hex for Clarity values), 0x prefix tolerated.
  - `proof`: `Bytes`. Consensus-serialized TrieMerkleProof.
- `NakamotoHeader`: A Nakamoto-era Stacks block header.
  - `version`: `number`. Low 7 bits = header version; high bit = shadow block.
  - `chainLength`: `bigint`
  - `burnSpent`: `bigint`
  - `consensusHash`: `Bytes`
  - `parentBlockId`: `Bytes`
  - `txMerkleRoot`: `Bytes`
  - `stateIndexRoot`: `Bytes`
  - `timestamp`: `bigint`
  - `minerSignature`: `Bytes`
  - `signerSignatures`: `Bytes[]`. 65-byte recoverable signatures: recovery id, r, s.
  - `signerSighashPreimage`: `Bytes`. Header bytes minus the signer_signature vec: the signer sighash preimage.
  - `byteLength`: `number`. Serialized header length; block bytes after this are the transactions.
- `NodeRpcSourceOptions`: Options for reading proofs from a Stacks node.
  - `nodeUrl`: `string`. Stacks node RPC origin, e.g. `http://localhost:20443`.
  - `fetch`?: `Fetch`
- `ProofSource`
  - `getBlock`: `(ref: string \| number) => Promise<Bytes>`. Raw Nakamoto block bytes (header first), by block id or height.
  - `getEpoch2Header`?: `(blockId: string) => Promise<Epoch2HeaderResponse>`. Epoch 2.x block header by index block hash: blocks below the checkpoint from before Nakamoto. Without it only Nakamoto blocks verify.
  - `getMarfProof`: `(pathHex: string, tipId: string) => Promise<MarfProofResponse \| null>`. MARF inclusion proof for a 32-byte path at `tipId`; null when the key is absent. Blocks below the checkpoint also ask for `__MARF_BLOCK_HEIGHT_TO_HASH::<height>`, whose value is no stored string: only `proof` is read for it.
  - `getWitness`: `(blockId: string) => Promise<Bytes>`. State witness (wire v3) for a block.
  - `getBurnPreimage`: `(consensusHash: string) => Promise<BurnPreimage>`
  - `getBitcoinHeaders`: `(from: number, count: number) => Promise<(string \| Bytes)[]>`. Raw 80-byte Bitcoin headers (hex or bytes) from height `from`.
  - `getStateWrites`?: `(height: number) => Promise<StateWrite[] \| null>`. Every MARF write of the block, in ordinal order; null (or empty) when the source has none for it. Names the block's diff.
  - `getVmEvents`?: `(height: number) => Promise<VmEventRow[]>`. Indexed vm_events write rows of the block, checked against its proven diff.
  - `getBitcoinTxProof`?: `(txid: string) => Promise<SpvProof>`. A Bitcoin tx, its merkle branch and block header, by display-order txid. Untrusted: `verifyBitcoinTx` re-checks every byte.
- `ProvenDiff`
  - `named`: `boolean`. Every leaf is named (state_writes served) and classified.
  - `writes`: `DiffWrite[]`
  - `carried`: `DiffLeaf[]`. Unchanged values copied forward from the parent (proven at the parent).
  - `internal`: `DiffLeaf[]`. `__MARF_BLOCK_*` bookkeeping.
- `SecondlayerSourceOptions`: Options for reading proofs from the Secondlayer API.
  - `baseUrl`?: `string`. API origin. Defaults to [`DEFAULT_API_URL`](/docs/verify-reference#c-DEFAULT_API_URL).
  - `apiKey`?: `string`. Optional. Proofs are keyless; a key raises the rate limit. Required for `rows: true` (metered Index reads). Sent as `Authorization: Bearer`.
  - `fetch`?: `Fetch`
- `SignerCheck`: Whether the signed weight meets the threshold with known signers.
  - `valid`: `boolean`. Signed weight meets the threshold, and every signature is a distinct known signer.
  - `signedWeight`: `bigint`
  - `totalWeight`: `bigint`
  - `threshold`: `bigint`. ceil(total * 7 / 10).
  - `signers`: `string[]`. Recovered signer principals that counted, in signature order.
  - `unknown`: `string[]`. Recovered principals not in the set.
  - `duplicates`: `string[]`. Principals that signed more than once.
  - `invalid`: `number`. Signatures that do not recover (malformed or high-S).
- `SignerSet`: Signer principal -> weight.
  - `clear`: `() => void`
  - `delete`: `(key: string) => boolean`
  - `forEach`: `(callbackfn: (value: bigint, key: string, map: Map<string, bigint>) => void, thisArg?: any) => void`. Executes a provided function once per each key/value pair in the Map, in insertion order.
  - `get`: `(key: string) => bigint \| undefined`. Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
  - `has`: `(key: string) => boolean`
  - `set`: `(key: string, value: bigint) => SignerSet`. Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
  - `size`: `number`
  - `entries`: `() => MapIterator<[string, bigint]>`. Returns an iterable of key, value pairs for every entry in the map.
  - `keys`: `() => MapIterator<string>`. Returns an iterable of keys in the map
  - `values`: `() => MapIterator<bigint>`. Returns an iterable of values in the map
- `StacksHeader`: A Stacks block header from either era.
- `StateFailure`
  - `step`: `"witness" \| "names" \| "rows"`
  - `code`: `StateFailureCode`
  - `message`: `string`
  - `key`?: `string`
  - `path`?: `string`
  - `ordinal`?: `number`
- `StateFailureCode`: `"malformed" \| "root-mismatch" \| "bad-write" \| "hidden-write" \| "missing-write" \| "key-not-written" \| "value-mismatch" \| "bad-row"`
- `StateWitness`: A recomputed trie root, its ancestor roots, and leaves.
  - `root`: `Bytes`. Recomputed trie root; compare to the authenticated header's state_index_root.
  - `ancestorRoots`: `Bytes[]`. Skip-list ancestor trie roots folded into `root`.
  - `leaves`: `WitnessLeaf[]`
  - `nodes`: `number`
- `StateWrite`: One storage-layer MARF write (`state_writes` row), in block write order.
  - `tx_index`: `number \| null`. Null for block-level writes outside any transaction.
  - `ordinal`: `number`
  - `key`: `string`. Full MARF key, e.g. `vm::<contract>::0::<map>::<key hex>`.
  - `value_hex`: `string`. Hex of the stored value string's UTF-8 bytes.
- `VerifyCheckpoint`: A trusted Stacks header and signer set to start verification from.
  - `stacks`: `{ header: string; cycle: number; signerSet: string }`
  - `bitcoin`: `Checkpoint`. Retarget-boundary Bitcoin header at or below the first burn block of `stacks.cycle`.
- `VerifyFailure`
  - `step`: `VerifyStep`
  - `code`: `VerifyFailureCode`
  - `message`: `string`
  - `cycle`?: `number`. Reward cycle being proven (signer-set step).
  - `blockId`?: `string`. Block the failure is about, when not the target.
  - `key`?: `string`
  - `path`?: `string`
  - `ordinal`?: `number`
- `VerifyFailureCode`: `"malformed" \| "root-mismatch" \| "bad-write" \| "hidden-write" \| "missing-write" \| "key-not-written" \| "value-mismatch" \| "bad-row" \| "tx-root-mismatch" \| "unavailable" \| "id-mismatch" \| "height-mismatch" \| "invalid-header" \| "preimage-mismatch" \| "burn-not-in-chain" \| "before-checkpoint" \| "not-ancestor" \| "ancestry-proof-invalid" \| "anchor-not-found" \| "anchor-outside-window" \| "anchor-unsigned" \| "set-proof-invalid" \| "below-threshold" \| "unknown-signer" \| "duplicate-signer" \| "bad-signature" \| "tx-parse" \| "txid-mismatch" \| "merkle-mismatch" \| "bitcoin-header-not-in-chain" \| "output-not-fou…`
- `VerifyOptions`: The proof source, checkpoint, and row checking for a block verify.
  - `source`: `ProofSource`
  - `checkpoint`?: `VerifyCheckpoint`. Defaults to MAINNET_CHECKPOINT.
  - `rows`?: `boolean`. Also prove the block's indexed vm_events rows against its diff: reads the source's `getVmEvents`, which bill as Index rows on the Secondlayer API. Off by default. Naming the diff's writes (`getStateWrites`, free on `/v1/proofs`) is always on when the source has them.
  - `onStep`?: `(step: VerifyStep) => void`. Called once per link as it passes, in the order the verifier proves them. Failures arrive in the result, not here.
- `VerifyStep`: `"witness" \| "names" \| "rows" \| "ancestry" \| "block" \| "bitcoin" \| "bitcoin-tx" \| "burn" \| "signer-set" \| "signatures" \| "txs"`
- `VmEventRow`: A `vm_events` write row, as the Index API serves it.
  - `event_type`: `"var_set" \| "map_set" \| "map_insert" \| "map_delete"`
  - `event_index`: `number`. The row's ordinal within the block.
  - `tx_id`?: `string`
  - `tx_index`?: `number`
  - `contract_id`: `string`
  - `var_name`?: `string \| null`
  - `map`?: `string \| null`
  - `raw_key`?: `string \| null`
  - `raw_value`?: `string \| null`
- `WitnessLeaf`
  - `path`: `Bytes`. Full 32-byte trie path: `marfPath(key)`.
  - `valueHash`: `Bytes`. 32-byte value hash (first 32 bytes of the MARFValue; the tail is zero).

## Notes for agents

- Import from '@secondlayer/verify'. 'verifyBlock(ref, { source })' is the one-shot check; 'new BlockVerifier({ source })' keeps a cache across many blocks.
- A proof source supplies the bytes: 'new SecondlayerProofSource({ apiKey })' reads the Secondlayer API, 'new NodeRpcProofSource({ nodeUrl })' reads a Stacks node. Both can be spread into one source.
- Every name on this page is a real export read from the package source, so a signature here is the one the installed version ships.

## Setup

Ensure setup once, skipping any step already done:
- Skill: `bunx skills add ryanwaits/secondlayer --skill secondlayer -y`
- CLI: `bun add -g @secondlayer/cli`
- Instance: `secondlayer init` writes `INSTANCE_TOKEN`. Loopback `/v1` reads need no key.
- Hosted/archive: export `SECONDLAYER_API_KEY` (`sk-sl_*`) or buy credits with `secondlayer credits buy` (`balance`, `refill`), then `secondlayer whoami`
