bitcoin_wire
Bitcoin transaction and block wire formats for Gleam.
bitcoin_wire is a Gleam library for deserializing, inspecting, hashing,
serializing, and performing context-free consensus checks on Bitcoin
transactions and blocks. It preserves exact wire values across Erlang and
JavaScript and reports malformed encodings as structured errors.
Project Status
The following Bitcoin wire-format data structures are currently implemented:
bitcoin_wire/transactiondeserializes and serializes legacy and SegWit transactions, exposes their fields and output script classifications, computes their base sizes, total sizes, weights, and virtual sizes, txids, and wtxids, and runs context-free consensus checks.bitcoin_wire/blockdeserializes and serializes standalone 80-byte headers and computes their block hashes. It also deserializes and serializes complete blocks; exposes their headers and transactions; computes base sizes, total sizes, weights, virtual sizes, and Merkle roots; and runs context-free consensus checks.bitcoin_wire/hash256provides fixed-width wire-order hashes with conversions to raw little-endian bytes and conventional Bitcoin display notation.
Additional domains may be added as the library expands.
Installation
gleam add bitcoin_wire@1
Goals and Philosophy
Correctness over convenience
Malformed or ambiguous encodings are surfaced explicitly rather than being silently normalized or accepted as partial values.
Reference-grade intent
The library is structured so it can be read alongside Bitcoin documentation as a reliable guide to wire formats and protocol data structures.
Faithful protocol modeling
Protocol distinctions and encoded forms are preserved rather than collapsed into convenience abstractions.
Cross-runtime portability
Public behavior remains consistent across the supported runtimes: Erlang and Node.js. However, native integer conversions and decode diagnostics may differ according to runtime representation limits.
Native browser builds are not currently supported. The JavaScript hashing
implementation imports node:crypto, which is available in Node.js but not
through native browser APIs.
Scope
This project deserializes and models caller-provided Bitcoin data. It is not a wallet, full node, RPC client, or networking library. Domain-specific documentation describes the exact deserialization, validation, and policy boundaries for each implemented module.
No security guarantees are provided.
Use Cases
- Explorers and blockchain indexers: Turn externally obtained Bitcoin wire bytes into structured blocks and transactions for display, search, and downstream analysis.
- Monitoring and research: Inspect caller-provided feeds and datasets for transaction shapes, script types, witness usage, block composition, Merkle roots, and context-free consensus violations.
- Protocol and data tooling: Add a portable deserialization, inspection, and context-free validation layer ahead of application-specific processing.
- Testing and education: Study Bitcoin wire encoding and exercise software with valid, malformed, and consensus-invalid block and transaction data.
Development
Run the unit tests on Erlang and Node.js:
gleam test -t erlang
gleam test -t javascript --runtime node
Continuous Integration
Pull requests run one workflow per project:
| Workflow | Checks |
|---|---|
library |
Formatting and unit tests on Erlang and Node |
fuzz |
Formatting, builds, and short transaction/block fuzz runs on Erlang and Node |
benchmarks |
Formatting, builds, and selected fixture benchmark runs on Erlang and Node |
examples |
Formatting and an Erlang build |
Tests, builds, and smoke runs use the compatibility baseline in the shared setup action.
Fuzz smoke runs use a fixed seed and a small number of transaction and block iterations on each runtime. Each run also verifies the original corpus before mutation begins. Benchmark smoke runs exercise fixture loading, measurement, and table reporting for transactions and blocks. They do not enforce performance thresholds; use the performance harness's comparison runner for measured regression claims.
A separate fuzz-nightly workflow runs longer transaction and block fuzz suites
on Erlang and Node with a shared generated seed if main differs from its latest successful scheduled run. Unchanged successful commits are skipped, and failed
runs are retried the following night.
Fuzz Testing
The standalone fuzz harness exercises transaction and block
parser safety against malformed and mutated wire-format inputs. Run a selected
suite with ./fuzz/run -- <suite> <iterations> [seed]; target and runtime
options go before --.
Benchmarking
The standalone performance harness measures public
deserialization and inspection workflows across representative inputs, scaling
dimensions, and fail-fast paths. Run the complete suite with
./benchmarks/run, or pass benchmark arguments after --, for example
./benchmarks/run -- --section transaction.deserialize.fixtures.
Examples
The standalone examples project uses mempool.space raw
mainnet data to demonstrate transaction JSON output, block metrics,
context-free block validation, and structured transaction decode errors. Run an
example from the repository root with, for example,
./examples/run -- block-metrics 0.