@secondlayer/verify 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,664 @@
1
+ type Bytes = Uint8Array;
2
+ declare const hex: (b: Bytes) => string;
3
+ /** Hex to bytes; tolerates a 0x prefix. */
4
+ declare const unhex: (s: string) => Bytes;
5
+ interface NakamotoHeader {
6
+ /** Low 7 bits = header version; high bit = shadow block. */
7
+ version: number;
8
+ chainLength: bigint;
9
+ burnSpent: bigint;
10
+ consensusHash: Bytes;
11
+ parentBlockId: Bytes;
12
+ txMerkleRoot: Bytes;
13
+ stateIndexRoot: Bytes;
14
+ timestamp: bigint;
15
+ minerSignature: Bytes;
16
+ /** 65-byte recoverable signatures: recovery id, r, s. */
17
+ signerSignatures: Bytes[];
18
+ /** Header bytes minus the signer_signature vec: the signer sighash preimage. */
19
+ signerSighashPreimage: Bytes;
20
+ /** Serialized header length; block bytes after this are the transactions. */
21
+ byteLength: number;
22
+ }
23
+ /**
24
+ * Parse the NakamotoBlockHeader at the start of raw block bytes
25
+ * (`/v3/blocks/<id>`). Handles v0 and v1 (v1 appends `problematic_txs`).
26
+ */
27
+ declare function parseNakamotoHeader(raw: Bytes): NakamotoHeader;
28
+ /**
29
+ * NakamotoBlockHeader::signer_signature_hash: sha512/256 over every header field
30
+ * except the signer signatures. Also the header's block_hash.
31
+ */
32
+ declare const signerSignatureHash: (h: NakamotoHeader) => Bytes;
33
+ /**
34
+ * Epoch 2.x anchored block header. It commits to the parent's block hash, not
35
+ * its index block hash, and carries no consensus hash: the source supplies
36
+ * that, and `blockId` binds it to an id proven elsewhere.
37
+ */
38
+ interface Epoch2Header {
39
+ version: number;
40
+ /** total_work.burn: burn spent on the fork so far. */
41
+ burnSpent: bigint;
42
+ /** total_work.work: the Stacks chain length (one per anchored block). */
43
+ chainLength: bigint;
44
+ vrfProof: Bytes;
45
+ parentBlockHash: Bytes;
46
+ parentMicroblock: Bytes;
47
+ parentMicroblockSequence: number;
48
+ txMerkleRoot: Bytes;
49
+ /** Covers the block and the parent microblock stream it confirms. */
50
+ stateIndexRoot: Bytes;
51
+ microblockPubkeyHash: Bytes;
52
+ /** sha512/256 of the serialized header. */
53
+ blockHash: Bytes;
54
+ consensusHash: Bytes;
55
+ }
56
+ type StacksHeader = NakamotoHeader | Epoch2Header;
57
+ /**
58
+ * Parse the epoch 2.x StacksBlockHeader at the start of `raw` (a header from
59
+ * `/v2/headers`, or block bytes from `/v2/blocks/<id>`), with the 20-byte
60
+ * consensus hash of the sortition that elected it.
61
+ */
62
+ declare function parseEpoch2Header(raw: Bytes, consensusHash: Bytes): Epoch2Header;
63
+ declare const isEpoch2Header: (h: StacksHeader) => h is Epoch2Header;
64
+ /**
65
+ * StacksBlockId (index block hash) = sha512/256(block_hash || consensus_hash).
66
+ * A Nakamoto block hash is its signer signature hash; a 2.x one hashes the
67
+ * whole header.
68
+ */
69
+ declare const blockId2: (h: StacksHeader) => Bytes;
70
+ /** TrieHash::from_key: sha512/256(utf8(key)). */
71
+ declare const marfPath: (key: string) => Bytes;
72
+ /** MARFValue::from_value: sha512/256(utf8(value)) padded to 40 bytes. */
73
+ declare function marfValue(value: string): Bytes;
74
+ /**
75
+ * Block ids of the ancestor tries a proof crosses: each one is the backptr a
76
+ * descendant trie follows toward the leaf. `verifyMarfProof` needs every one's
77
+ * header. Read from untrusted proof bytes, so they are only fetch hints; the
78
+ * proof still fails unless each header hashes to the id the trie committed.
79
+ * Malformed proofs yield no ids.
80
+ */
81
+ declare function marfProofAncestors(proof: Bytes): string[];
82
+ interface MarfProofInput {
83
+ /** Consensus-serialized TrieMerkleProof (`/v2/clarity/marf/<path>?proof=1`). */
84
+ proof: Bytes;
85
+ /** Leaf path: `marfPath(key)`. */
86
+ path: Bytes;
87
+ /** 40-byte MARFValue: `marfValue(valueString)`. */
88
+ value: Bytes;
89
+ /** Tip state_index_root, from a header the caller authenticated. */
90
+ root: Bytes;
91
+ /**
92
+ * Tip header plus every ancestor header the proof crosses. Each contributes
93
+ * state_index_root -> recomputed block id, so ancestor roots are only ever
94
+ * vouched for by header bytes (a bare root->id map would let a forged
95
+ * ancestor trie through).
96
+ */
97
+ headers: StacksHeader[];
98
+ }
99
+ /**
100
+ * TrieMerkleProof::verify. True iff `value` is stored at `path` in the MARF
101
+ * whose tip root is `root`. Inclusion only: MARF proofs cannot prove absence.
102
+ * Malformed proof bytes verify false.
103
+ */
104
+ declare function verifyMarfProof(input: MarfProofInput): boolean;
105
+ interface WitnessLeaf {
106
+ /** Full 32-byte trie path: `marfPath(key)`. */
107
+ path: Bytes;
108
+ /** 32-byte value hash (first 32 bytes of the MARFValue; the tail is zero). */
109
+ valueHash: Bytes;
110
+ }
111
+ interface StateWitness {
112
+ /** Recomputed trie root; compare to the authenticated header's state_index_root. */
113
+ root: Bytes;
114
+ /** Skip-list ancestor trie roots folded into `root`. */
115
+ ancestorRoots: Bytes[];
116
+ leaves: WitnessLeaf[];
117
+ nodes: number;
118
+ }
119
+ /**
120
+ * Parse a v2 state witness and recompute its root. Throws on malformed input.
121
+ * The result proves nothing until `root` equals a header's state_index_root.
122
+ */
123
+ declare function parseWitness(bytes: Bytes): StateWitness;
124
+ interface BlockDiffInput {
125
+ /** `parseWitness(bytes).leaves`, from a witness whose root was checked. */
126
+ leaves: WitnessLeaf[];
127
+ /** Claimed writes of the block: [key, value string] as stored by Clarity. */
128
+ writes: [key: string, value: string][];
129
+ /** MARF bookkeeping keys (`__MARF_*`) with their raw 40-byte MARFValue hex, derived from the header chain. */
130
+ internal: [key: string, valueHex: string][];
131
+ /** Value at `pathHex` in the PARENT block's state (40-byte MARFValue hex), already proven by the caller. */
132
+ parentValue: (pathHex: string) => string | undefined;
133
+ }
134
+ interface ClassifiedLeaf extends WitnessLeaf {
135
+ key: string;
136
+ }
137
+ interface BlockDiff {
138
+ /** Leaves matching a claimed write (path and value). */
139
+ writes: ClassifiedLeaf[];
140
+ /** Unclaimed leaves holding the parent's value: copied forward, not written. */
141
+ carried: WitnessLeaf[];
142
+ /** Leaves matching a `__MARF_*` bookkeeping entry. */
143
+ internal: ClassifiedLeaf[];
144
+ /** Leaves nothing explains: an unreported write. Non-empty = reject. */
145
+ hidden: WitnessLeaf[];
146
+ /** Claimed write keys with no leaf holding the claimed value. Non-empty = reject. */
147
+ missing: string[];
148
+ /** No hidden leaves and no missing writes: the claimed writes are the block's complete diff. */
149
+ complete: boolean;
150
+ }
151
+ /**
152
+ * Classify every leaf of block N's trie against the claimed write set.
153
+ * Each leaf must be a claimed write, a carried (unchanged) parent value, or a
154
+ * MARF-internal key; anything else is a hidden write.
155
+ */
156
+ declare function classifyBlockDiff(input: BlockDiffInput): BlockDiff;
157
+ /** Boot contract holding `cycle-signer-set`, one entry per reward cycle. */
158
+ declare const SIGNERS_CONTRACT = "SP000000000000000000002Q6VF78.signers";
159
+ /** Signer principal -> weight. */
160
+ type SignerSet = Map<string, bigint>;
161
+ /**
162
+ * Decode the `.signers` `cycle-signer-set` map value (hex or bytes, as stored
163
+ * in the MARF): `(some (list (tuple (signer principal) (weight uint) ...)))`.
164
+ */
165
+ declare function decodeSignerSet(value: string | Bytes): SignerSet;
166
+ interface SignerCheck {
167
+ /** Signed weight meets the threshold, and every signature is a distinct known signer. */
168
+ valid: boolean;
169
+ signedWeight: bigint;
170
+ totalWeight: bigint;
171
+ /** ceil(total * 7 / 10). */
172
+ threshold: bigint;
173
+ /** Recovered signer principals that counted, in signature order. */
174
+ signers: string[];
175
+ /** Recovered principals not in the set. */
176
+ unknown: string[];
177
+ /** Principals that signed more than once. */
178
+ duplicates: string[];
179
+ /** Signatures that do not recover (malformed or high-S). */
180
+ invalid: number;
181
+ }
182
+ /**
183
+ * Recover each header signature's key over signer_signature_hash, map it to
184
+ * its mainnet p2pkh principal, and sum weights from `set`. The set must be the
185
+ * one for the reward cycle of the tenure-electing burn block.
186
+ */
187
+ declare function verifySignerSignatures(header: NakamotoHeader, set: SignerSet): SignerCheck;
188
+ /**
189
+ * Check `preimage` against a 20-byte consensus hash. Returns the burn block
190
+ * hash as hex, already in Bitcoin display order (as `bitcoin-cli
191
+ * getblockhash` prints it), or null when the preimage does not match.
192
+ */
193
+ declare function verifyConsensusPreimage(consensusHash: Bytes, preimage: Bytes): string | null;
194
+ /** Mainnet PoX parameters (first_burnchain_block_height, reward_cycle_length). */
195
+ declare const MAINNET_FIRST_BURN_HEIGHT = 666050;
196
+ declare const MAINNET_REWARD_CYCLE_LENGTH = 2100;
197
+ /** Mainnet prepare phase: the last 100 burn blocks of a cycle pick the next cycle's signers. */
198
+ declare const MAINNET_PREPARE_LENGTH = 100;
199
+ /** First burn height of reward cycle `cycle`. */
200
+ declare const cycleStart: (cycle: number, firstBurnHeight?: number, cycleLength?: number) => number;
201
+ /** Reward cycle containing `burnHeight`. */
202
+ declare function rewardCycle(burnHeight: number, firstBurnHeight?: number, cycleLength?: number): number;
203
+ import { ClarityValue } from "@secondlayer/stacks/clarity";
204
+ /** `vm::<contract>::0::<map>::<serialized key hex>` (make_key_for_data_map_entry). */
205
+ declare function mapEntryKey(contractId: string, mapName: string, key: ClarityValue): string;
206
+ /** `vm::<contract>::1::<var>` (make_key_for_trip, StoreType::Variable). */
207
+ declare function dataVarKey(contractId: string, varName: string): string;
208
+ /**
209
+ * `vm::<contract>::2::<token>::<principal json>` (get_ft_balance). The holder
210
+ * is serde-JSON PrincipalData, e.g. `{"Standard":[22,[...20 bytes]]}`.
211
+ */
212
+ declare function ftBalanceKey(contractId: string, tokenName: string, holder: string): string;
213
+ interface BlockHeader {
214
+ /** Signed 32-bit version field. */
215
+ version: number;
216
+ /** Display-order hex of the previous block hash. */
217
+ prevHash: string;
218
+ /** Display-order hex of the merkle root. */
219
+ merkleRoot: string;
220
+ /** Unix timestamp, seconds. */
221
+ time: number;
222
+ /** Compact-encoded target. */
223
+ bits: number;
224
+ nonce: number;
225
+ }
226
+ type HeaderRule = "checkpoint" | "format" | "prev-link" | "bits" | "retarget" | "median-time-past" | "version" | "proof-of-work";
227
+ declare class HeaderValidationError extends Error {
228
+ readonly height: number;
229
+ readonly rule: HeaderRule;
230
+ readonly name = "HeaderValidationError";
231
+ constructor(height: number, rule: HeaderRule, detail: string);
232
+ }
233
+ interface Checkpoint {
234
+ height: number;
235
+ /** Raw 80-byte header, bytes or hex. Trusted without validation. */
236
+ header: Uint8Array | string;
237
+ /**
238
+ * Timestamp of the first block of the checkpoint's difficulty period
239
+ * (height − height % 2016). Required when the checkpoint is not itself a
240
+ * period start; needed to verify the next retarget.
241
+ */
242
+ periodStartTime?: number;
243
+ }
244
+ interface ChainEntry {
245
+ height: number;
246
+ /** Display-order hex. */
247
+ hash: string;
248
+ header: BlockHeader;
249
+ raw: Uint8Array;
250
+ }
251
+ declare class HeaderChain {
252
+ private readonly base;
253
+ private readonly periodStartTime;
254
+ private readonly entries;
255
+ private readonly heights;
256
+ private work;
257
+ private constructor();
258
+ static fromCheckpoint(checkpoint: Checkpoint): HeaderChain;
259
+ get tip(): ChainEntry;
260
+ /** Work summed from the checkpoint (inclusive) to the tip; not chainwork since genesis. */
261
+ get totalWork(): bigint;
262
+ get checkpointHeight(): number;
263
+ /** Height of a header in this chain by display-order hash, or undefined. */
264
+ heightOf(hashHex: string): number | undefined;
265
+ headerAt(height: number): ChainEntry | undefined;
266
+ /**
267
+ * Validates and appends headers in order. All-or-nothing: if any header
268
+ * fails, the chain is left exactly as it was and the error is thrown.
269
+ */
270
+ append(headers: Iterable<Uint8Array | string>): void;
271
+ private validate;
272
+ private expectedBits;
273
+ /**
274
+ * Median of the last 11 timestamps. Right after the checkpoint fewer are
275
+ * known; like Core near genesis, the median of what is available is used.
276
+ */
277
+ private medianTimePast;
278
+ private push;
279
+ }
280
+ interface VerifyCheckpoint {
281
+ stacks: {
282
+ /** Raw Nakamoto header (hex) of a trusted block whose state holds `signerSet`. */
283
+ header: string
284
+ /** Reward cycle `signerSet` belongs to. */
285
+ cycle: number
286
+ /** `.signers` `cycle-signer-set[cycle]` as stored: hex of `(some (list ...))`. */
287
+ signerSet: string
288
+ };
289
+ /** Retarget-boundary Bitcoin header at or below the first burn block of `stacks.cycle`. */
290
+ bitcoin: Checkpoint;
291
+ }
292
+ /**
293
+ * Mainnet: Stacks block 8,956,304 (`3914ea5f…74bb`) holding the cycle 143
294
+ * signer set (29 signers, weight 4000), and Bitcoin block 967,680 (a
295
+ * retarget-period start inside cycle 143). Later blocks verify forward
296
+ * (burn height 967,680 or later); earlier ones by hash chain from 8,956,304.
297
+ */
298
+ declare const MAINNET_CHECKPOINT: VerifyCheckpoint;
299
+ /** Sortition preimage behind a consensus hash. */
300
+ interface BurnPreimage {
301
+ preimage: Bytes;
302
+ /** The source's claimed burn height: a hint for how far to sync Bitcoin headers, never trusted. */
303
+ burnHeight: number;
304
+ }
305
+ /** Node RPC `/v2/clarity/marf/<path>?proof=1` answer. */
306
+ interface MarfProofResponse {
307
+ /** Value string as Clarity stored it (hex for Clarity values), 0x prefix tolerated. */
308
+ data: string;
309
+ /** Consensus-serialized TrieMerkleProof. */
310
+ proof: Bytes;
311
+ }
312
+ /** One storage-layer MARF write (`state_writes` row), in block write order. */
313
+ interface StateWrite {
314
+ /** Null for block-level writes outside any transaction. */
315
+ tx_index: number | null;
316
+ ordinal: number;
317
+ /** Full MARF key, e.g. `vm::<contract>::0::<map>::<key hex>`. */
318
+ key: string;
319
+ /** Hex of the stored value string's UTF-8 bytes. */
320
+ value_hex: string;
321
+ }
322
+ /** A `vm_events` write row, as the Index API serves it. */
323
+ interface VmEventRow {
324
+ event_type: "var_set" | "map_set" | "map_insert" | "map_delete";
325
+ /** The row's ordinal within the block. */
326
+ event_index: number;
327
+ tx_id?: string;
328
+ tx_index?: number;
329
+ contract_id: string;
330
+ var_name?: string | null;
331
+ map?: string | null;
332
+ raw_key?: string | null;
333
+ raw_value?: string | null;
334
+ }
335
+ /** An epoch 2.x header and the consensus hash its index block hash commits to. */
336
+ interface Epoch2HeaderResponse {
337
+ /** Consensus-serialized StacksBlockHeader. */
338
+ header: Bytes;
339
+ consensusHash: Bytes;
340
+ }
341
+ interface ProofSource {
342
+ /** Raw Nakamoto block bytes (header first), by block id or height. */
343
+ getBlock(ref: string | number): Promise<Bytes>;
344
+ /**
345
+ * Epoch 2.x block header by index block hash: blocks below the checkpoint
346
+ * from before Nakamoto. Without it only Nakamoto blocks verify.
347
+ */
348
+ getEpoch2Header?(blockId: string): Promise<Epoch2HeaderResponse>;
349
+ /**
350
+ * MARF inclusion proof for a 32-byte path at `tipId`; null when the key is
351
+ * absent. Blocks below the checkpoint also ask for
352
+ * `__MARF_BLOCK_HEIGHT_TO_HASH::<height>`, whose value is no stored string:
353
+ * only `proof` is read for it.
354
+ */
355
+ getMarfProof(pathHex: string, tipId: string): Promise<MarfProofResponse | null>;
356
+ /** State witness (wire v3) for a block. */
357
+ getWitness(blockId: string): Promise<Bytes>;
358
+ getBurnPreimage(consensusHash: string): Promise<BurnPreimage>;
359
+ /** Raw 80-byte Bitcoin headers (hex or bytes) from height `from`. */
360
+ getBitcoinHeaders(from: number, count: number): Promise<(string | Bytes)[]>;
361
+ /** Every MARF write of the block; null when the source has none for it. */
362
+ getStateWrites?(height: number): Promise<StateWrite[] | null>;
363
+ /** Indexed vm_events write rows of the block, checked against its proven diff. */
364
+ getVmEvents?(height: number): Promise<VmEventRow[]>;
365
+ }
366
+ declare class SourceError extends Error {
367
+ readonly url: string;
368
+ readonly status: number | null;
369
+ readonly name = "SourceError";
370
+ constructor(url: string, status: number | null, detail: string);
371
+ }
372
+ type Fetch = (url: string, init?: RequestInit) => Promise<Response>;
373
+ interface SecondlayerSourceOptions {
374
+ /** API origin, e.g. `https://api.secondlayer.tools`. */
375
+ baseUrl: string;
376
+ /** Account key, sent as `Authorization: Bearer`. */
377
+ apiKey: string;
378
+ fetch?: Fetch;
379
+ }
380
+ /**
381
+ * Every proof input from the Secondlayer API: `/v1/proofs/*` for blocks, epoch
382
+ * 2.x headers, MARF proofs, witnesses, burn preimages and Bitcoin headers; the Index API for
383
+ * state_writes and vm_events, read only when verifyBlock gets `rows: true`.
384
+ * Methods are own properties, so a partial source spreads over it:
385
+ * `{ ...new SecondlayerProofSource(o), ...new NodeRpcProofSource(n) }`.
386
+ */
387
+ declare class SecondlayerProofSource implements ProofSource {
388
+ getBlock: (ref: string | number) => Promise<Bytes>;
389
+ getEpoch2Header: (blockId: string) => Promise<Epoch2HeaderResponse>;
390
+ getMarfProof: (pathHex: string, tipId: string) => Promise<MarfProofResponse | null>;
391
+ getWitness: (blockId: string) => Promise<Bytes>;
392
+ getBurnPreimage: (consensusHash: string) => Promise<BurnPreimage>;
393
+ getBitcoinHeaders: (from: number, count: number) => Promise<string[]>;
394
+ getStateWrites: (height: number) => Promise<StateWrite[] | null>;
395
+ getVmEvents: (height: number) => Promise<VmEventRow[]>;
396
+ constructor(opts: SecondlayerSourceOptions);
397
+ }
398
+ interface NodeRpcSourceOptions {
399
+ /** Stacks node RPC origin, e.g. `http://localhost:20443`. */
400
+ nodeUrl: string;
401
+ fetch?: Fetch;
402
+ }
403
+ /**
404
+ * Blocks, epoch 2.x headers and MARF proofs straight from a Stacks node's RPC.
405
+ * Witnesses, burn preimages and Bitcoin headers need another source: spread
406
+ * this over one.
407
+ */
408
+ declare class NodeRpcProofSource implements Pick<ProofSource, "getBlock" | "getEpoch2Header" | "getMarfProof"> {
409
+ getBlock: (ref: string | number) => Promise<Bytes>;
410
+ getEpoch2Header: (blockId: string) => Promise<Epoch2HeaderResponse>;
411
+ getMarfProof: (pathHex: string, tipId: string) => Promise<MarfProofResponse | null>;
412
+ constructor(opts: NodeRpcSourceOptions);
413
+ }
414
+ interface DiffWrite {
415
+ /** MARF key, when a state_writes row names the leaf. */
416
+ key?: string;
417
+ /** Leaf path, hex. */
418
+ path: string;
419
+ /** sha512/256 of the stored value string, hex. */
420
+ valueHash: string;
421
+ /** Transaction of the last write; null for block-level writes. */
422
+ txIndex?: number | null;
423
+ /** False when the source had no state_writes: the leaf may also be a carried copy. */
424
+ named: boolean;
425
+ }
426
+ interface DiffLeaf {
427
+ key?: string;
428
+ path: string;
429
+ valueHash: string;
430
+ }
431
+ interface ProvenDiff {
432
+ /** Every leaf is named (state_writes served) and classified. */
433
+ named: boolean;
434
+ writes: DiffWrite[];
435
+ /** Unchanged values copied forward from the parent (proven at the parent). */
436
+ carried: DiffLeaf[];
437
+ /** `__MARF_BLOCK_*` bookkeeping. */
438
+ internal: DiffLeaf[];
439
+ }
440
+ type StateFailureCode = "malformed" | "root-mismatch" | "bad-write" | "hidden-write" | "missing-write" | "key-not-written" | "value-mismatch" | "bad-row";
441
+ interface StateFailure {
442
+ step: "witness" | "names" | "rows";
443
+ code: StateFailureCode;
444
+ message: string;
445
+ key?: string;
446
+ path?: string;
447
+ ordinal?: number;
448
+ }
449
+ interface BlockStateInput {
450
+ /** MARF height of the block (its Stacks chain length). */
451
+ height: number;
452
+ /** Parent block id from the authenticated header. */
453
+ parentBlockId: Bytes;
454
+ /** state_index_root from the authenticated header. */
455
+ stateRoot: Bytes;
456
+ witness: Bytes;
457
+ /** The block's state_writes; null when the source has none (names unavailable). */
458
+ writes: StateWrite[] | null;
459
+ /** Indexed rows to prove against the diff. */
460
+ rows?: VmEventRow[];
461
+ /**
462
+ * Leaves of the parent's own trie, from a parent witness whose root the
463
+ * caller checked against the parent header: each is the parent state's
464
+ * value at its path. Resolves carried leaves without a proof per leaf.
465
+ */
466
+ parentLeaves?: WitnessLeaf[];
467
+ /**
468
+ * True iff the leaf's value is stored at its path in the parent's state
469
+ * (proven by the caller). Asked only with state_writes, for leaves the
470
+ * parent's own trie does not explain.
471
+ */
472
+ parentHolds?: (leaf: WitnessLeaf) => Promise<boolean>;
473
+ }
474
+ interface BlockStateResult {
475
+ diff?: ProvenDiff;
476
+ rowsChecked: number;
477
+ notes: string[];
478
+ failures: StateFailure[];
479
+ }
480
+ /**
481
+ * Verify block state against an authenticated header: the witness must
482
+ * recompute `stateRoot`, then every leaf is classified. With state_writes,
483
+ * any leaf that is not a named write, a carried parent value or MARF
484
+ * bookkeeping is a hidden write. Without them the diff is still proven
485
+ * (every leaf is in the block): carried leaves are told apart only through
486
+ * `parentLeaves`, and the remaining writes come back unnamed.
487
+ */
488
+ declare function verifyBlockState(input: BlockStateInput): Promise<BlockStateResult>;
489
+ type VerifyStep = "ancestry" | "block" | "bitcoin" | "burn" | "signer-set" | "signatures" | "witness" | "names" | "rows";
490
+ type VerifyFailureCode = StateFailureCode | "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";
491
+ interface VerifyFailure {
492
+ step: VerifyStep;
493
+ code: VerifyFailureCode;
494
+ message: string;
495
+ /** Reward cycle being proven (signer-set step). */
496
+ cycle?: number;
497
+ /** Block the failure is about, when not the target. */
498
+ blockId?: string;
499
+ key?: string;
500
+ path?: string;
501
+ ordinal?: number;
502
+ }
503
+ /** How a block below the checkpoint was tied to it. */
504
+ interface Ancestry {
505
+ /** Trusted descendant it was proven from: the checkpoint, or a block proven below it earlier. */
506
+ fromHeight: number;
507
+ fromBlockId: string;
508
+ /**
509
+ * `parents`: each header hashes to the parent id its child commits to.
510
+ * `marf`: one MARF proof of `__MARF_BLOCK_HEIGHT_TO_HASH::<height>` against
511
+ * the descendant's state root.
512
+ */
513
+ via: "parents" | "marf";
514
+ }
515
+ interface BlockVerification {
516
+ /**
517
+ * Every step passed. At or above the checkpoint: header, burn binding,
518
+ * signatures, state root, names and rows. Below it: ancestry, header,
519
+ * state root, names and rows (and the burn binding when Bitcoin reaches it).
520
+ */
521
+ ok: boolean;
522
+ height?: number;
523
+ blockId?: string;
524
+ /** The header's state_index_root, hex: what the witness must hash to. */
525
+ stateRoot?: string;
526
+ /** Set for blocks below the checkpoint, which need no signatures. */
527
+ ancestry?: Ancestry;
528
+ cycle?: number;
529
+ burnHeight?: number;
530
+ /** Display-order hex. */
531
+ bitcoinBlockHash?: string;
532
+ signerWeight?: bigint;
533
+ totalWeight?: bigint;
534
+ threshold?: bigint;
535
+ diff?: ProvenDiff;
536
+ /** vm_events rows proven against the diff. */
537
+ rowsChecked?: number;
538
+ notes: string[];
539
+ /** Empty when ok. The first entry is the first broken link. */
540
+ failures: VerifyFailure[];
541
+ }
542
+ interface VerifyOptions {
543
+ source: ProofSource;
544
+ /** Defaults to MAINNET_CHECKPOINT. */
545
+ checkpoint?: VerifyCheckpoint;
546
+ /**
547
+ * Also name the block's writes and prove its indexed rows: reads the
548
+ * source's `getStateWrites` and `getVmEvents`, which bill as Index rows on
549
+ * the Secondlayer API. Off by default, so verification reads proofs only.
550
+ */
551
+ rows?: boolean;
552
+ }
553
+ /**
554
+ * Verifies blocks from one checkpoint against one source, caching the Bitcoin
555
+ * header chain, proven signer sets and fetched headers across calls.
556
+ */
557
+ declare class BlockVerifier {
558
+ private readonly source;
559
+ private readonly checkpoint;
560
+ private readonly rows;
561
+ private readonly chain;
562
+ /** Proven signer sets by cycle. */
563
+ private readonly sets;
564
+ /** Where each proven set was anchored: the lower bound for the next search. */
565
+ private readonly anchors;
566
+ /** Headers fetched by id, each checked to hash to it. */
567
+ private readonly headers;
568
+ /** Blocks proven on the checkpoint's chain below it, by height. */
569
+ private readonly below;
570
+ private readonly burns;
571
+ /** Unverified source answers by consensus hash. */
572
+ private readonly preimages;
573
+ private readonly start;
574
+ constructor(opts: VerifyOptions);
575
+ /** Verify one block by id (hex) or height. Never throws for bad source data. */
576
+ verify(ref: string | number): Promise<BlockVerification>;
577
+ private run;
578
+ /** At or above the checkpoint: Bitcoin, burn binding, signer set, signatures, state. */
579
+ private runForward;
580
+ /**
581
+ * Below the checkpoint: prove the checkpoint chain's id at `height` (and
582
+ * that it is `claimed`, when the caller asked by id), then the header that
583
+ * hashes to it, then its state. Signatures add nothing to a header pinned
584
+ * by hash from a trusted descendant.
585
+ */
586
+ private runBelow;
587
+ /**
588
+ * The checkpoint chain's block id at `height`, from the nearest trusted
589
+ * block above it: parent links when within MAX_WALK, else one MARF proof.
590
+ */
591
+ private ancestor;
592
+ /** The lowest trusted block above `height`: the checkpoint or one proven below it. */
593
+ private nearestAbove;
594
+ /**
595
+ * Follow parent ids down from `from`: each parent header must hash to the
596
+ * id its child committed to. Null when a 2.x header stops the walk: it
597
+ * commits to its parent's block hash, not the parent's id.
598
+ */
599
+ private walk;
600
+ /**
601
+ * Read the id at `height` from `from`'s state: block `height + 1` wrote it
602
+ * to `__MARF_BLOCK_HEIGHT_TO_HASH::<height>`, and the proof must recompute
603
+ * `from`'s state root through the header of every trie it crosses.
604
+ */
605
+ private jump;
606
+ /**
607
+ * Below the checkpoint the hash chain already pins the block; still bind
608
+ * its burn block when the Bitcoin checkpoint reaches it. The burn height
609
+ * here is the source's hint, so a low one only skips this extra check.
610
+ */
611
+ private bindBurnBelow;
612
+ /** Witness against the authenticated header's root, then the named diff and rows. */
613
+ private verifyState;
614
+ /** Header by id, from the cache or the source; it must hash to `id`. */
615
+ private header;
616
+ /**
617
+ * A Nakamoto block by id, or when the source has none (epoch 2.x blocks are
618
+ * not served as Nakamoto blocks) its epoch 2.x header.
619
+ */
620
+ private fetchHeader;
621
+ /**
622
+ * Prove `value` at `path` in `tip`'s state, fetching the header of every
623
+ * ancestor trie the proof crosses.
624
+ */
625
+ private proveAt;
626
+ /**
627
+ * The parent's own trie leaves, from its witness checked against the
628
+ * parent header. Optional evidence: when the source cannot serve it,
629
+ * carried leaves fall back to per-leaf proofs (named) or stay unlabeled.
630
+ */
631
+ private parentLeaves;
632
+ /**
633
+ * A carried leaf holds the parent's value. The parent header is
634
+ * authenticated by hash: its id is committed in the authenticated child
635
+ * (its header, or for 2.x its own trie).
636
+ */
637
+ private parentHolds;
638
+ /** Consensus hash -> PoW-verified burn block, via the sortition preimage. */
639
+ private bindBurn;
640
+ /** Extend the Bitcoin chain to `height`, validating PoW, retarget and MTP. */
641
+ private syncBitcoin;
642
+ /**
643
+ * The proven signer set for `cycle`. Walks forward from the checkpoint:
644
+ * set c+1 is read from an anchor block in c+1's prepare phase, whose
645
+ * header set c signed.
646
+ */
647
+ private signerSet;
648
+ /** The checkpoint block as a search bound; its burn height is a source hint. */
649
+ private startPoint;
650
+ private burnHint;
651
+ private preimage;
652
+ private locateAnchor;
653
+ /**
654
+ * Set `cycle` from `anchor`: the anchor must be bound to a burn block in
655
+ * `cycle`'s prepare phase, be signed by the set of the cycle that burn
656
+ * height dictates (`cycle - 1`), and hold set `cycle` in its state (MARF
657
+ * proof). Adjacent sets overlap enough that one block can clear both, so
658
+ * the set is always chosen by proven burn height, never by which passes.
659
+ */
660
+ private proveNextSet;
661
+ }
662
+ /** One-shot: verify a block from a checkpoint (MAINNET_CHECKPOINT by default). */
663
+ declare const verifyBlock: (ref: string | number, opts: VerifyOptions) => Promise<BlockVerification>;
664
+ export { Ancestry, BlockDiff, BlockDiffInput, BlockStateInput, BlockStateResult, BlockVerification, BlockVerifier, BurnPreimage, Bytes, Checkpoint, ClassifiedLeaf, DiffLeaf, DiffWrite, Epoch2Header, Epoch2HeaderResponse, HeaderChain, HeaderRule, HeaderValidationError, MAINNET_CHECKPOINT, MAINNET_FIRST_BURN_HEIGHT, MAINNET_PREPARE_LENGTH, MAINNET_REWARD_CYCLE_LENGTH, MarfProofInput, MarfProofResponse, NakamotoHeader, NodeRpcProofSource, NodeRpcSourceOptions, ProofSource, ProvenDiff, SIGNERS_CONTRACT, SecondlayerProofSource, SecondlayerSourceOptions, SignerCheck, SignerSet, SourceError, StacksHeader, StateFailure, StateFailureCode, StateWitness, StateWrite, VerifyCheckpoint, VerifyFailure, VerifyFailureCode, VerifyOptions, VerifyStep, VmEventRow, WitnessLeaf, blockId2 as blockId, classifyBlockDiff, cycleStart, dataVarKey, decodeSignerSet, ftBalanceKey, hex, isEpoch2Header, mapEntryKey, marfPath, marfProofAncestors, marfValue, parseEpoch2Header, parseNakamotoHeader, parseWitness, rewardCycle, signerSignatureHash, unhex, verifyBlock, verifyBlockState, verifyConsensusPreimage, verifyMarfProof, verifySignerSignatures };