.md

@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 explains what each check proves.

@secondlayer/verify@0.6.050 functionsfrom source with openpkgVerify
Verify a block
verifyBlockState(input)BlockStateResultVerifies a block's state against an authenticated header.
new TransactionsError(code, message)Thrown for a malformed block body or a transaction root mismatch.
blockTransactions(raw, header)BlockTransaction[] | nullHashes a block's transactions and checks them against the header.
txMerkleRoot(txids)BytesComputes the tx_merkle_root over transaction ids.
describeLinks(r, cp, opts){ lines: LinkLine[]; verdict: { ok:…Describes a verification as one line per link and a verdict.
new BlockVerifier(opts)Verifies blocks from one checkpoint against one source.
BlockVerifier.verify(ref)BlockVerificationVerify one block by id (hex) or height.
BlockVerifier.verifyBitcoinTx(proof, opts)BitcoinTxVerificationProves a Bitcoin tx is in the checkpoint's Bitcoin chain.
verifyBlock(ref, opts)BlockVerificationOne-shot: verify a block from a checkpoint (MAINNET_CHECKPOINT by default).
Proof sources
new NodeRpcProofSource(opts)Reads blocks, epoch 2.x headers and MARF proofs from a Stacks node.
NodeRpcProofSource.getBlock(ref)BytesRaw block bytes, header first, by block id or height.
NodeRpcProofSource.getEpoch2Header(blockId)Epoch2HeaderResponseAn epoch 2.x header and its consensus hash, by index block hash.
NodeRpcProofSource.getMarfProof(pathHex, tipId)MarfProofResponse | nullA MARF inclusion proof for a path at a tip.
new SecondlayerProofSource(opts)Reads every proof input from the Secondlayer API.
SecondlayerProofSource.getBlock(ref)BytesRaw block bytes, header first, by block id or height.
SecondlayerProofSource.getEpoch2Header(blockId)Epoch2HeaderResponseAn epoch 2.x header and its consensus hash, by index block hash.
SecondlayerProofSource.getMarfProof(pathHex, tipId)MarfProofResponse | nullA MARF inclusion proof for a path at a tip.
SecondlayerProofSource.getWitness(blockId)BytesThe state witness for a block.
SecondlayerProofSource.getBurnPreimage(consensusHash)BurnPreimageThe burn preimage behind a consensus hash.
SecondlayerProofSource.getBitcoinHeaders(from, count)string[]Raw 80-byte Bitcoin headers, count of them from height from.
SecondlayerProofSource.getStateWrites(height)StateWrite[] | nullEvery MARF write of a block, in ordinal order.
SecondlayerProofSource.getVmEvents(height)VmEventRow[]The indexed vm_events write rows of a block, from the Index API.
SecondlayerProofSource.getBitcoinTxProof(txid)SpvProofA Bitcoin tx, its merkle branch and header, by txid.
new SourceError(url, status, detail)Thrown when a proof source request fails.
Proofs and headers
hex(b)stringEncodes bytes as a lowercase hex string.
unhex(s)BytesHex to bytes; tolerates a 0x prefix.
blockId(h)BytesComputes a header's block id, also called the index block hash.
isEpoch2Header(h)h is Epoch2HeaderNarrows a Stacks header to an epoch 2.x header.
parseEpoch2Header(raw, consensusHash)Epoch2HeaderParses the epoch 2.x block header at the start of raw.
parseNakamotoHeader(raw)NakamotoHeaderParse the NakamotoBlockHeader at the start of raw block bytes (/v3/blocks/<id>).
signerSignatureHash(h)BytesHashes a Nakamoto header the way its signers sign it.
marfPath(key)BytesHashes a key to its MARF path: sha512/256 of the UTF-8 key.
marfProofAncestors(proof)string[]Lists the ancestor tries a MARF proof crosses.
marfValue(value)BytesHashes a value to its MARF value: sha512/256, padded to 40 bytes.
verifyMarfProof(input)booleanVerifies a MARF inclusion proof.
classifyBlockDiff(input)BlockDiffClassify every leaf of block N's trie against the claimed write set.
parseWitness(bytes)StateWitnessParse a v2 state witness and recompute its root.
decodeSignerSet(value)SignerSetDecodes a cycle-signer-set value from the .signers contract.
verifySignerSignatures(header, set)SignerCheckSums the weight of the signers who signed a block header.
cycleStart(cycle, firstBurnHeight, cycleLength)numberFirst burn height of reward cycle cycle.
rewardCycle(burnHeight, firstBurnHeight, cycleLength)numberReward cycle containing burnHeight.
verifyConsensusPreimage(consensusHash, preimage)string | nullCheck preimage against a 20-byte consensus hash.
dataVarKey(contractId, varName)stringThe MARF key of a data variable: vm::<contract>::1::<var>.
ftBalanceKey(contractId, tokenName, holder)stringThe MARF key of a fungible token balance: vm::<contract>::2::<token>::<principal json>.
mapEntryKey(contractId, mapName, key)stringThe MARF key of a map entry: vm::<contract>::0::<map>::<serialized key hex>.
Bitcoin headers
HeaderChain.fromCheckpoint(checkpoint)HeaderChainStarts a header chain at a checkpoint.
HeaderChain.heightOf(hashHex)number | undefinedHeight of a header in this chain by display-order hash, or undefined.
HeaderChain.headerAt(height)ChainEntry | undefinedThe header entry at a height, if the chain has one.
HeaderChain.append(headers)voidValidates and appends headers in order.
new HeaderValidationError(height, rule, detail)Thrown when a Bitcoin header fails a validation rule.

Verify a block

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

import from @secondlayer/verify

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.

verifyBlockState(input: BlockStateInput): Promise<BlockStateResult>

Parameters

hover a row to find it in the code

Required

heightrequirednumberMARF height of the block (its Stacks chain length).
parentBlockIdrequiredBytesParent block id from the authenticated header.
stateRootrequiredBytesstate_index_root from the authenticated header.
witnessrequiredBytes
writesrequiredStateWrite[] | nullThe block's state_writes; null when the source has none (names unavailable).

Options

rowsVmEventRow[]Indexed rows to prove against the diff.
parentLeavesWitnessLeaf[]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.
Returns Promise<BlockStateResult>
diff
ProvenDiff
rowsChecked
number
notes
string[]
failures
StateFailure[]

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

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

Parameters

hover a row to find it in the code

Required

coderequired"malformed" | "tx-root-mismatch"
messagerequiredstring

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 on a malformed body, trailing bytes or a root mismatch.

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

Parameters

hover a row to find it in the code

Required

rawrequiredBytes
header.versionrequirednumberLow 7 bits = header version; high bit = shadow block.
header.chainLengthrequiredbigint
header.burnSpentrequiredbigint
header.consensusHashrequiredBytes
header.parentBlockIdrequiredBytes
header.txMerkleRootrequiredBytes
header.stateIndexRootrequiredBytes
header.timestamprequiredbigint
header.minerSignaturerequiredBytes
header.signerSignaturesrequiredBytes[]65-byte recoverable signatures: recovery id, r, s.
header.signerSighashPreimagerequiredBytesHeader bytes minus the signer_signature vec: the signer sighash preimage.
header.byteLengthrequirednumberSerialized header length; block bytes after this are the transactions.
Returns BlockTransaction[] | null
txid
sha512/256 of the transaction bytes, hex.
raw
The consensus-serialized transaction.

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).

txMerkleRoot(txids: Bytes[]): Bytes

Parameters

hover a row to find it in the code

Required

txidsrequiredBytes[]

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.

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

Parameters

hover a row to find it in the code

Required

r.okrequiredbooleanEvery 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.notesrequiredstring[]
r.failuresrequiredVerifyFailure[]Empty when ok. The first entry is the first broken link.
cp.stacksrequired{ header: string; cycle: number; signerSet: string }
cp.bitcoinrequiredCheckpointRetarget-boundary Bitcoin header at or below the first burn block of stacks.cycle.

Options

r.heightnumber
r.blockIdstring
r.blockHashstringNakamoto block hash (the header's signer sighash), hex. Absent for epoch 2.x.
r.consensusHashstringThe header's consensus hash, hex.
r.timestampnumberNakamoto header timestamp, Unix seconds. Absent for epoch 2.x.
r.stateRootstringThe header's state_index_root, hex: what the witness must hash to.
r.ancestryAncestrySet for blocks below the checkpoint, which need no signatures.
r.cyclenumber
10 more options
r.burnHeightnumber
r.bitcoinBlockHashstringDisplay-order hex.
r.signerWeightbigint
r.totalWeightbigint
r.thresholdbigint
r.transactionsBlockTransaction[]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.diffProvenDiff
r.writesStateWrite[]Every state_writes row the names step checked, in ordinal order.
r.rowsCheckednumbervm_events rows proven against the diff.
opts.rowsboolean

Verifies blocks from one checkpoint against one source.

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

new BlockVerifier(opts: VerifyOptions)

Parameters

hover a row to find it in the code

Required

sourcerequiredProofSource

Options

checkpointVerifyCheckpointDefaults to MAINNET_CHECKPOINT.
rowsbooleanAlso 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) => voidCalled once per link as it passes, in the order the verifier proves them. Failures arrive in the result, not here.

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

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

Parameters

hover a row to find it in the code

Required

refrequiredstring | number
Returns Promise<BlockVerification>
ok
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
Nakamoto block hash (the header's signer sighash), hex. Absent for epoch 2.x.
consensusHash
The header's consensus hash, hex.
timestamp
Nakamoto header timestamp, Unix seconds. Absent for epoch 2.x.
stateRoot
The header's state_index_root, hex: what the witness must hash to.
ancestry
Set for blocks below the checkpoint, which need no signatures.
cycle
number
burnHeight
number
bitcoinBlockHash
Display-order hex.
signerWeight
bigint
totalWeight
bigint
threshold
bigint
transactions
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
Every state_writes row the names step checked, in ordinal order.
rowsChecked
vm_events rows proven against the diff.
notes
string[]
failures
Empty when ok. The first entry is the first broken link.

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.

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

Parameters

hover a row to find it in the code

Required

proofrequiredstring | SpvProof

Options

opts.expectBitcoinTxExpect
Returns Promise<BitcoinTxVerification>
ok
The tx is in a block of the checkpoint's Bitcoin chain, and any expect matched.
txid
Display-order hex.
height
number
blockHash
Display-order hex.
outputs
BitcoinTxOutputView[]
matched
Index of the first output matching expect, when given.
failures
Empty when ok.

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

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

Parameters

hover a row to find it in the code

Required

refrequiredstring | number
opts.sourcerequiredProofSource

Options

opts.checkpointVerifyCheckpointDefaults to MAINNET_CHECKPOINT.
opts.rowsbooleanAlso 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) => voidCalled once per link as it passes, in the order the verifier proves them. Failures arrive in the result, not here.
Returns Promise<BlockVerification>
ok
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
Nakamoto block hash (the header's signer sighash), hex. Absent for epoch 2.x.
consensusHash
The header's consensus hash, hex.
timestamp
Nakamoto header timestamp, Unix seconds. Absent for epoch 2.x.
stateRoot
The header's state_index_root, hex: what the witness must hash to.
ancestry
Set for blocks below the checkpoint, which need no signatures.
cycle
number
burnHeight
number
bitcoinBlockHash
Display-order hex.
signerWeight
bigint
totalWeight
bigint
threshold
bigint
transactions
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
Every state_writes row the names step checked, in ordinal order.
rowsChecked
vm_events rows proven against the diff.
notes
string[]
failures
Empty when ok. The first entry is the first broken link.

Constants

Proof sources

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

import from @secondlayer/verify

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.

new NodeRpcProofSource(opts: NodeRpcSourceOptions)

Parameters

hover a row to find it in the code

Required

nodeUrlrequiredstringStacks node RPC origin, e.g. http://localhost:20443.

Options

fetchFetch

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

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

Parameters

hover a row to find it in the code

Required

refrequiredstring | number

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

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

Parameters

hover a row to find it in the code

Required

blockIdrequiredstring
Returns Promise<Epoch2HeaderResponse>
header
Consensus-serialized StacksBlockHeader.
consensusHash
Bytes

A MARF inclusion proof for a path at a tip.

It is null when the key is absent.

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

Parameters

hover a row to find it in the code

Required

pathHexrequiredstring
tipIdrequiredstring
Returns Promise<MarfProofResponse | null>
data
Value string as Clarity stored it (hex for Clarity values), 0x prefix tolerated.
proof
Consensus-serialized TrieMerkleProof.

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) }.

new SecondlayerProofSource(opts?: SecondlayerSourceOptions)

Parameters

hover a row to find it in the code

Options

baseUrlstringAPI origin. Defaults to DEFAULT_API_URL.
apiKeystringOptional. Proofs are keyless; a key raises the rate limit. Required for rows: true (metered Index reads). Sent as Authorization: Bearer.
fetchFetch

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

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

Parameters

hover a row to find it in the code

Required

refrequiredstring | number

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

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

Parameters

hover a row to find it in the code

Required

blockIdrequiredstring
Returns Promise<Epoch2HeaderResponse>
header
Consensus-serialized StacksBlockHeader.
consensusHash
Bytes

A MARF inclusion proof for a path at a tip.

It is null when the key is absent.

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

Parameters

hover a row to find it in the code

Required

pathHexrequiredstring
tipIdrequiredstring
Returns Promise<MarfProofResponse | null>
data
Value string as Clarity stored it (hex for Clarity values), 0x prefix tolerated.
proof
Consensus-serialized TrieMerkleProof.

The state witness for a block.

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

Parameters

hover a row to find it in the code

Required

blockIdrequiredstring

The burn preimage behind a consensus hash.

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

Parameters

hover a row to find it in the code

Required

consensusHashrequiredstring
Returns Promise<BurnPreimage>
preimage
Bytes
burnHeight
The source's claimed burn height: a hint for how far to sync Bitcoin headers, never trusted.

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

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

Parameters

hover a row to find it in the code

Required

fromrequirednumber
countrequirednumber

Every MARF write of a block, in ordinal order.

It is null when there are none.

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

Parameters

hover a row to find it in the code

Required

heightrequirednumber
Returns Promise<StateWrite[] | null>
tx_index
Null for block-level writes outside any transaction.
ordinal
number
key
Full MARF key, e.g. vm::<contract>::0::<map>::<key hex>.
value_hex
Hex of the stored value string's UTF-8 bytes.

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

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

Parameters

hover a row to find it in the code

Required

heightrequirednumber
Returns Promise<VmEventRow[]>
event_type
"var_set" | "map_set" | "map_insert" | "map_delete"
event_index
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

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

The txid is display-order hex.

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

Parameters

hover a row to find it in the code

Required

txidrequiredstring

Thrown when a proof source request fails.

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

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

Parameters

hover a row to find it in the code

Required

urlrequiredstring
statusrequirednumber | null
detailrequiredstring

Constants

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

Proofs and headers

The parsers and checks a block verification is built from.

import from @secondlayer/verify

Encodes bytes as a lowercase hex string.

hex(b: Bytes): string

Parameters

hover a row to find it in the code

Required

brequiredBytes

Hex to bytes; tolerates a 0x prefix.

unhex(s: string): Bytes

Parameters

hover a row to find it in the code

Required

srequiredstring

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.

blockId(h: StacksHeader): Bytes

Parameters

hover a row to find it in the code

Required

hrequiredStacksHeader

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

isEpoch2Header(h: StacksHeader): h is Epoch2Header

Parameters

hover a row to find it in the code

Required

hrequiredStacksHeader

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.

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

Parameters

hover a row to find it in the code

Required

rawrequiredBytes
consensusHashrequiredBytes
Returns Epoch2Header
version
number
burnSpent
total_work.burn: burn spent on the fork so far.
chainLength
total_work.work: the Stacks chain length (one per anchored block).
vrfProof
Bytes
parentBlockHash
Bytes
parentMicroblock
Bytes
parentMicroblockSequence
number
txMerkleRoot
Bytes
stateIndexRoot
Covers the block and the parent microblock stream it confirms.
microblockPubkeyHash
Bytes
blockHash
sha512/256 of the serialized header.
consensusHash
Bytes

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

parseNakamotoHeader(raw: Bytes): NakamotoHeader

Parameters

hover a row to find it in the code

Required

rawrequiredBytes
Returns NakamotoHeader
version
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
65-byte recoverable signatures: recovery id, r, s.
signerSighashPreimage
Header bytes minus the signer_signature vec: the signer sighash preimage.
byteLength
Serialized header length; block bytes after this are the transactions.

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.

signerSignatureHash(h: NakamotoHeader): Bytes

Parameters

hover a row to find it in the code

Required

versionrequirednumberLow 7 bits = header version; high bit = shadow block.
chainLengthrequiredbigint
burnSpentrequiredbigint
consensusHashrequiredBytes
parentBlockIdrequiredBytes
txMerkleRootrequiredBytes
stateIndexRootrequiredBytes
timestamprequiredbigint
minerSignaturerequiredBytes
signerSignaturesrequiredBytes[]65-byte recoverable signatures: recovery id, r, s.
signerSighashPreimagerequiredBytesHeader bytes minus the signer_signature vec: the signer sighash preimage.
byteLengthrequirednumberSerialized header length; block bytes after this are the transactions.

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

marfPath(key: string): Bytes

Parameters

hover a row to find it in the code

Required

keyrequiredstring

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.

marfProofAncestors(proof: Bytes): string[]

Parameters

hover a row to find it in the code

Required

proofrequiredBytes

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

marfValue(value: string): Bytes

Parameters

hover a row to find it in the code

Required

valuerequiredstring

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.

verifyMarfProof(input: MarfProofInput): boolean

Parameters

hover a row to find it in the code

Required

proofrequiredBytesConsensus-serialized TrieMerkleProof (/v2/clarity/marf/<path>?proof=1).
pathrequiredBytesLeaf path: marfPath(key).
valuerequiredBytes40-byte MARFValue: marfValue(valueString).
rootrequiredBytesTip state_index_root, from a header the caller authenticated.
headersrequiredStacksHeader[]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).

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.

classifyBlockDiff(input: BlockDiffInput): BlockDiff

Parameters

hover a row to find it in the code

Required

leavesrequiredWitnessLeaf[]parseWitness(bytes).leaves, from a witness whose root was checked.
writesrequired[string, string][]Claimed writes of the block: [key, value string] as stored by Clarity.
internalrequired[string, string][]MARF bookkeeping keys (__MARF_*) with their raw 40-byte MARFValue hex, derived from the header chain.
parentValuerequired(pathHex: string) => string | undefinedValue at pathHex in the PARENT block's state (40-byte MARFValue hex), already proven by the caller.
Returns BlockDiff
writes
Leaves matching a claimed write (path and value).
carried
Unclaimed leaves holding the parent's value: copied forward, not written.
internal
Leaves matching a __MARF_* bookkeeping entry.
hidden
Leaves nothing explains: an unreported write. Non-empty = reject.
missing
Claimed write keys with no leaf holding the claimed value. Non-empty = reject.
complete
No hidden leaves and no missing writes: the claimed writes are the block's complete diff.

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.

parseWitness(bytes: Bytes): StateWitness

Parameters

hover a row to find it in the code

Required

bytesrequiredBytes
Returns StateWitness
root
Recomputed trie root; compare to the authenticated header's state_index_root.
ancestorRoots
Skip-list ancestor trie roots folded into root.
leaves
WitnessLeaf[]
nodes
number

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) ...))).

decodeSignerSet(value: string | Bytes): SignerSet

Parameters

hover a row to find it in the code

Required

valuerequiredstring | Bytes
Returns SignerSet
clear
() => void
delete
(key: string) => boolean
forEach
Executes a provided function once per each key/value pair in the Map, in insertion order.
get
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
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
Returns an iterable of key, value pairs for every entry in the map.
keys
Returns an iterable of keys in the map
values
Returns an iterable of values in the map

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.

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

Parameters

hover a row to find it in the code

Required

header.versionrequirednumberLow 7 bits = header version; high bit = shadow block.
header.chainLengthrequiredbigint
header.burnSpentrequiredbigint
header.consensusHashrequiredBytes
header.parentBlockIdrequiredBytes
header.txMerkleRootrequiredBytes
header.stateIndexRootrequiredBytes
header.timestamprequiredbigint
header.minerSignaturerequiredBytes
header.signerSignaturesrequiredBytes[]65-byte recoverable signatures: recovery id, r, s.
header.signerSighashPreimagerequiredBytesHeader bytes minus the signer_signature vec: the signer sighash preimage.
header.byteLengthrequirednumberSerialized header length; block bytes after this are the transactions.
set.clearrequired() => void
set.deleterequired(key: string) => boolean
set.forEachrequired(callbackfn: (value: bigint, key: string, map: Map<stri…Executes a provided function once per each key/value pair in the Map, in insertion order.
set.getrequired(key: string) => bigint | undefinedReturns 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.hasrequired(key: string) => boolean
set.setrequired(key: string, value: bigint) => SignerSetAdds 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.sizerequirednumber
set.entriesrequired() => MapIterator<[string, bigint]>Returns an iterable of key, value pairs for every entry in the map.
set.keysrequired() => MapIterator<string>Returns an iterable of keys in the map
set.valuesrequired() => MapIterator<bigint>Returns an iterable of values in the map
Returns SignerCheck
valid
Signed weight meets the threshold, and every signature is a distinct known signer.
signedWeight
bigint
totalWeight
bigint
threshold
ceil(total * 7 / 10).
signers
Recovered signer principals that counted, in signature order.
unknown
Recovered principals not in the set.
duplicates
Principals that signed more than once.
invalid
Signatures that do not recover (malformed or high-S).

First burn height of reward cycle cycle.

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

Parameters

hover a row to find it in the code

Required

cyclerequirednumber

Options

firstBurnHeightnumber
cycleLengthnumber

Reward cycle containing burnHeight.

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

Parameters

hover a row to find it in the code

Required

burnHeightrequirednumber

Options

firstBurnHeightnumber
cycleLengthnumber

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.

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

Parameters

hover a row to find it in the code

Required

consensusHashrequiredBytes
preimagerequiredBytes

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

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

Parameters

hover a row to find it in the code

Required

contractIdrequiredstring
varNamerequiredstring

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]]}.

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

Parameters

hover a row to find it in the code

Required

contractIdrequiredstring
tokenNamerequiredstring
holderrequiredstring

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

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

Parameters

hover a row to find it in the code

Required

contractIdrequiredstring
mapNamerequiredstring
keyrequiredClarityValue

Constants

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

Bitcoin headers

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

import from @secondlayer/verify

Starts a header chain at a checkpoint.

HeaderChain.fromCheckpoint(checkpoint: Checkpoint): HeaderChain

Parameters

hover a row to find it in the code

Required

heightrequirednumber
headerrequiredstring | Uint8Array<ArrayBufferLike>Raw 80-byte header, bytes or hex. Trusted without validation.

Options

periodStartTimenumberTimestamp 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.
Returns HeaderChain
tip
ChainEntry
totalWork
Work summed from the checkpoint (inclusive) to the tip; not chainwork since genesis.
checkpointHeight
number

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

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

Parameters

hover a row to find it in the code

Required

hashHexrequiredstring

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

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

Parameters

hover a row to find it in the code

Required

heightrequirednumber
Returns ChainEntry | undefined
height
number
hash
Display-order hex.
header
BlockHeader
raw
Uint8Array

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.

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

Parameters

hover a row to find it in the code

Required

headersrequiredIterable<string | Uint8Array, any, any>

Thrown when a Bitcoin header fails a validation rule.

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

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

Parameters

hover a row to find it in the code

Required

heightrequirednumber
rulerequiredHeaderRule
detailrequiredstring

Constants

MAINNET_CHECKPOINT
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). VerifyCheckpoint
Ancestry
How a block below the checkpoint was tied to it.
BitcoinTxExpect
The output fields a proven transaction must match.
BitcoinTxOutputView
One output of a proven Bitcoin transaction.
BitcoinTxVerification
The result of proving a Bitcoin transaction against the checkpoint's chain.
BlockDiff
A block's witnessed leaves, split into writes, carried, and internal.
BlockDiffInput
The witness leaves, claimed writes, and bookkeeping keys to classify.
BlockHeader
version, prevHash, merkleRoot, time, bits, nonce
BlockStateInput
A block's height, parent, and state root to check rows against.
BlockStateResult
The proven diff, rows checked, notes, and failures.
BlockTransaction
A transaction's id and its consensus-serialized bytes.
BlockVerification
The result of verifying a block, step by step.
BurnPreimage
Sortition preimage behind a consensus hash.
Bytes
A byte string, held as a Uint8Array.
ChainEntry
A Bitcoin header with its height, hash, and raw bytes.
Checkpoint
A trusted Bitcoin header that anchors header validation.
ClassifiedLeaf
key, path, valueHash
DiffLeaf
key, path, valueHash
DiffWrite
key, path, valueHash, txIndex, value, named
Epoch2Header
Epoch 2.x anchored block header.
Epoch2HeaderResponse
An epoch 2.x header and the consensus hash it commits to.
Fetch
(url: string, init?: RequestInit) => Promise<Response>
HeaderChain
A validated chain of Bitcoin headers, grown forward from a checkpoint.
HeaderRule
A Bitcoin header rule a chain check can fail on.
LinkLine
One verification step with its status and what it proved.
LinkStatus
"ok" | "failed" | "skipped"
MarfProofInput
A MARF proof with the leaf path and value it covers.
MarfProofResponse
Node RPC /v2/clarity/marf/<path>?proof=1 answer.
NakamotoHeader
A Nakamoto-era Stacks block header.
NodeRpcSourceOptions
Options for reading proofs from a Stacks node.
ProofSource
getBlock, getEpoch2Header, getMarfProof, getWitness, getBurnPreimage, getBitcoinHeaders, …
ProvenDiff
named, writes, carried, internal
SecondlayerSourceOptions
Options for reading proofs from the Secondlayer API.
SignerCheck
Whether the signed weight meets the threshold with known signers.
SignerSet
Signer principal -> weight.
StacksHeader
A Stacks block header from either era.
StateFailure
step, code, message, key, path, ordinal
StateFailureCode
"malformed" | "root-mismatch" | "bad-write" | "hidden-write" | "missing-write" | "key-not-written" | "value-m…
StateWitness
A recomputed trie root, its ancestor roots, and leaves.
StateWrite
One storage-layer MARF write (state_writes row), in block write order.
VerifyCheckpoint
A trusted Stacks header and signer set to start verification from.
VerifyFailure
step, code, message, cycle, blockId, key, …
VerifyFailureCode
"malformed" | "root-mismatch" | "bad-write" | "hidden-write" | "missing-write" | "key-not-written" | "value-m…
VerifyOptions
The proof source, checkpoint, and row checking for a block verify.
VerifyStep
"witness" | "names" | "rows" | "ancestry" | "block" | "bitcoin" | "bitcoin-tx" | "burn" | "signer-set" | "sig…
VmEventRow
A vm_events write row, as the Index API serves it.
WitnessLeaf
path, valueHash
Edit on GitHub