Skip to content

Hackathon

Chain Lens

A Bitcoin transaction and block analyzer that parses raw Core data files, reconstructs the accounting, and classifies every script, with a CLI and a visual walkthrough sharing one engine.

Feb 2026BitcoinDeveloper tools

Chain Lens takes raw Bitcoin data and produces a report you can check rather than a summary you have to believe. It parses transactions and whole blocks, rebuilds inputs, outputs and fees, classifies every script, and emits either structured JSON or an interactive walkthrough.

Context
Timed developer challenge, with an automated grader
Surfaces
CLI (JSON) and web visualiser
Inputs
Raw transactions and Bitcoin Core blk*.dat / rev*.dat
Role
Author
Repository
VincenzoImp/2026-developer-challenge-1-chain-lens
VincenzoImp/2026-developer-challenge-1-chain-lensBitcoin transaction and block analyzer: CLI and web visualiser over one analysis engine.TypeScript

The problem

A block explorer tells you what a transaction did. It does not tell you how it arrived at that answer, and for anything involving fees, weight or script types the answer depends on rules that changed several times: SegWit’s weight accounting, Taproot’s spend paths, the way a witness discount alters what a transaction actually costs.

The challenge was to compute those from the bytes and be checkable about it, which rules out calling an API and reformatting the reply.

What I built

A single analysis engine with two front ends over it.

For a transaction it derives txid and wtxid, size, weight and vbytes under BIP141, input and output totals, the fee and the fee rate. Every output script is classified – P2PKH, P2SH, P2WPKH, P2WSH, P2TR, OP_RETURN – and rendered as its mainnet address; every input is classified by how it was spent, down to distinguishing a Taproot key-path spend from a script-path one. It disassembles scripts, decodes OP_RETURN payloads and recognises Omni and OpenTimestamps inside them, reports BIP125 replaceability and BIP68 relative timelocks, and compares actual weight against the hypothetical legacy weight to show what SegWit saved.

In block mode it reads Bitcoin Core’s own blk*.dat and rev*.dat files – de-obfuscating them with xor.dat first – verifies the merkle root against the block header, decodes the BIP34 height from the coinbase, and aggregates fees, weight and script-type distribution across the block.

Hard parts

One engine, two surfaces, or the numbers diverge. The CLI and the visualiser both call lib/analyzer.ts, and the repository states the reason plainly: so that the two always produce the same numbers. A visualiser with its own fee calculation is a second implementation of consensus-adjacent arithmetic, and the moment the two disagree neither can be trusted.

Reading Core’s files rather than its RPC. Block files are an internal format, obfuscated on disk and not a stable interface. Parsing them directly removes the dependency on a running node and puts the burden of getting the format right entirely on this code, which is why verifying the merkle root matters: it is the check that the parse was correct, computed from the parsed data against the header.

Being gradeable. The repository carries a grader with expected outputs. Emitting structured JSON rather than prose is what makes the analysis machine-checkable, and it is why the classification vocabulary has to be exhaustive rather than approximate: unknown is a real category and has to be returned honestly.