STATUS · Built and tested locally. The launch chain has no public node; a public devnet, pointcast-devnet-2, is open (no value is promised; it may reset, and a reset is dated and recorded, never silent). Mainnet anchoring waits on a funded key. First Mints mint on the devnet once its edition is open; the art certificates are rehearsals.
CHAIN · LESSON · VERIFY A BLOCK · PUBLIC DEVNET-2 · NO VALUE · MAY RESET, NEVER SILENTLY
Verify a block by hand.
A block on the PointCast devnet is a header and a list of signed transactions. Pick one and your browser walks the same
steps the chain’s own verifier walks: recompute the hash, check the link to its neighbours, check the sequencer’s
signature, rebuild the transaction tree, check every signature. Then flip one byte and watch exactly which check goes red.
devnet · no value · may reset. This is pointcast-devnet-2: one server runs it and holds its sequencer key. A reset is dated and
recorded, never silent: devnet-1 was reset on 2026-10-08 and its recording is still checkable at
/chain/yard/devnet-1/. A signature here is an accountable claim by a key, not proof that
what it says is true. A witness or a stamp is the same.
01 · PICK A BLOCK · READ LIVE FROM THE DEVNET, IN YOUR BROWSER
Which block do you want to check?
The lesson opens on a block a few behind the tip, so both neighbours exist. Type a number, roll a random block, or jump to
a block that carries transactions: the signature steps have more to show there.
The lesson reads GET /status and the blocks from the devnet once this section is on screen, then only when you ask.
TAMPERED COPY · IN MEMORY ONLY · THE DEVNET WAS NOT TOUCHED
1
Fetch the block and its neighbours
·WAITING
The page asks the devnet for three blocks: the one you picked and the two beside it, plus the genesis parameters. A block is a header (its height, the previous block’s hash, a timestamp, a Merkle root over its transactions, the state root and the sequencer’s seal) and a list of signed transactions. Nothing is checked yet beyond this: the server answered with the heights you asked for. From here on the server is out of the picture. Every check below is arithmetic on bytes you already hold.
Tool: your browser’s fetch, reading GET /raw/block/N−1, N and N+1, /params and /status.
2
Recompute the header hash and check the links
·WAITING
A block’s hash is BLAKE2b-256 over one fixed byte string: the domain name pointcast-chain/header/v1, then the height, the previous block’s hash, the timestamp, the tx_root and the state_root. The seal is not part of it. The next block must carry this hash as its prev_hash, and this block must carry the hash of the one before it. Change a single byte of any field in any of the three headers and a hash changes, and a link no longer matches.
Tool: blockHeaderHash from the PointCast Chain SDK, over the bytes shown here; blake2b is the SDK’s.
3
Check the sequencer’s seal
·WAITING
The sequencer signs one thing per block: BLAKE2b-256 over the domain pointcast-chain/seal/v2, the genesis hash and the header hash, with an ed25519 key. Binding in the genesis hash means a seal made for one chain cannot pass as another’s. The key comes from /params, so first the page hashes /params and compares the result with the genesis hash it trusts. Without that comparison the key could be anyone’s.
Tool: paramsHash, sealDigest and verifyEd25519 (your browser’s WebCrypto) from the SDK.
4
Recompute every transaction id and the tx_root
·WAITING
A transaction id is BLAKE2b-256 over the domain pointcast-chain/txid/v1 and the signed transaction’s canonical bytes: the transaction, then the key scheme, the key and the signature. Each id becomes a leaf, BLAKE2b-256 of 0x00 and the id. Two neighbours combine as BLAKE2b-256 of 0x01 and both; an odd one moves up unchanged; an empty block has one fixed root. The result must equal the tx_root in the header. That is how a sealed header commits to exactly these transactions, in exactly this order, signatures included.
Tool: encodeTx, txHash and txRoot from the SDK. The tree drawn here is built with the SDK’s blake2b and compared with its txRoot.
5
Check each signature and where the sender comes from
·WAITING
A sender signs BLAKE2b-256 over the domain pointcast-chain/tx/v2, the chain id, the genesis hash and the transaction’s canonical bytes. The page checks that ed25519 signature with the key carried in the transaction, then derives an address from the key (a BLAKE2b-160 hash of it, with the address prefix) and compares it with the sender field. A wallet-signed transaction signs a packed text message instead. A passkey transaction signs with P-256 and is not checked here. With the pinned wasm verifier loaded, the chain’s own Rust code computes the signing digest too.
Tool: signingHash, verifyEd25519, tezosAddress and agentAddress from the SDK; optionally tx.wallet in the pinned wasm verifier.
Loads the Block Yard’s verifier, only if its sha256 is 7467bfd9afb3…, and has it compute each signing digest with the chain’s own Rust code.
03 · STEP SIX: WHAT THIS PROVES, AND WHAT IT DOES NOT
What a green run means.
A green run shows this one copy of this one block is a sealed link, correctly signed, as far as these five checks go. It
says nothing about the rest of the chain until you walk it, and nothing about state at all.
It proves
The header of the block you hold is exactly what the sequencer key named in the pinned genesis signed, with this chain’s genesis bound into the signature.
Its header names the hash of the block before it, and the block after it names its hash, so the three headers hold together.
Its transactions are the ones that header commits to through the tx_root, and each is signed by the key it carries, with the sender’s address derived from that key.
After the walk below: every header from block 1 to this one links and is sealed, so the block sits on one unbroken chain from the genesis you pinned.
It does not prove
The state root is not recomputed. A balance, an owner or a count follows only from replaying every block through the chain’s rules. That is what VERIFY in the Block Yard does, in your browser, and what pcv.py and verify.mjs do from a terminal.
No rule is checked: nonces, who may do what, mandates, limits. A correctly signed transaction can still be one the chain’s rules would refuse.
A seal is one server’s accountable claim. A sequencer that wanted to could seal two different versions of a block for two readers, and this page sees only the one it was served. Witnesses compare notes on the Daily Net, and a witness is a claim, not proof.
The seal is checked against the key in the genesis parameters. After a sequencer rotation takes effect, later blocks carry the new key’s seal, and following that needs the key schedule the Block Yard replays.
A passkey (P-256) signature is not checked here, and a transaction kind this page cannot encode leaves its block’s tx_root unchecked. Both are named when they happen.
Nothing is anchored to Tezos. This is a devnet.
Connect it to genesis
The five steps hold three headers together. This walks every header from block 1 to the block you picked: each prev_hash
against the hash before it, each seal under the genesis key, each tx_root rebuilt where the page can encode the
transactions. It reads the blocks in pages of 500 and replays no state.
One read per 500 blocks; nothing is written.
Replay it all: VERIFY in the Block Yardpcv.pyverify.mjsThe Yard replays every block through the chain’s own rules, state root included. pcv.py checks the same commitments in plain Python; verify.mjs replays with the wasm.
04 · SAME STEPS, IN CODE
The same checks in fifteen lines.
This file does steps 2 to 5 for raw ed25519 transactions and prints one line per check. Keep the SDK beside it
(pointcast-chain.js; the older file at /chain/sdk/ has no blockHeaderHash, sealDigest or txRoot) and run it with Node 22 or newer.
For the whole chain and its state, verify.mjs replays from genesis with the pinned wasm.
verify-a-block.mjs · pins this devnet’s genesis
// verify-a-block.mjs · Node 22+ · keep pointcast-chain.js (the SDK) beside this file
import * as pcc from "./pointcast-chain.js";
const DEVNET = "https://pointcast-devnet.mhoydich.workers.dev", GENESIS = "a720735b473383057ee11e885b2d32e1565470612364f13c0265c1a1c66f4280";
const N = Number(process.argv[2] ?? 100); // 2 or more, and at least one block behind the tip
const get = async (path) => pcc.parseJsonExact(await (await fetch(DEVNET + path)).text());
const params = await get("/params");
if (pcc.paramsHash(params) !== GENESIS) throw new Error("params do not hash to the pinned genesis");
const [prev, blk, next] = await Promise.all([N - 1, N, N + 1].map((n) => get("/raw/block/" + n)));
const h = blk.header, check = (ok, what) => console.log(ok ? "ok " : "FAIL", what);
check(pcc.blockHeaderHash(prev.header) === h.prev_hash, "block " + N + " names the hash of block " + (N - 1));
check(pcc.blockHeaderHash(h) === next.header.prev_hash, "block " + (N + 1) + " names the hash of block " + N);
check(await pcc.verifyEd25519(params.sequencer.bytes, pcc.hexToBytes(pcc.sealDigest(h, GENESIS)), h.sequencer_sig), "sequencer seal");
check(pcc.txRoot(blk.txs) === h.tx_root, "tx_root rebuilds from the " + blk.txs.length + " transactions");
const domain = pcc.domainOf(params.chain_id, GENESIS); // raw ed25519 signatures; the page also reads wallet-signed ones
for (const t of blk.txs) check(await pcc.verifyEd25519(t.public_key.bytes, pcc.hexToBytes(pcc.signingHash(t.tx, domain)), t.signature), "signature of tx " + pcc.txHash(t).slice(0, 12));
Which tool did which step, and what it cannot do
Step
Tool
Limit
1 · Fetch
the browser’s fetch
It reads one server. Nothing it returns is believed until the steps below.
2 · Links
SDK blockHeaderHash
Shows three headers hold together, not that they reach genesis (the walk does that).
3 · Seal
SDK paramsHash, sealDigest, WebCrypto ed25519
Checks the genesis key only; a rotated key needs the Block Yard’s replay.
4 · tx_root
SDK encodeTx, txHash, txRoot
Names any transaction kind it cannot encode and leaves that block’s tx_root unchecked.
5 · Signatures
SDK signingHash, verifyEd25519, tezosAddress; optionally the pinned wasm’s tx.wallet
Skips passkey (P-256) signatures and checks no rule or balance.