Taproot hidden spending paths
One of Taproot's headline selling points — MAST (BIP-341) — was hidden spending
paths: commit to several alternative spending conditions, then reveal only the
one you use and keep the rest private. taproot_leafs.py scans a Bitcoin Core
node and measures how often revealed Taproot script spends actually carried a
hidden path.
The script is standalone, stdlib-only, and deterministic — the same code over the same blocks always produces the same numbers, so the result can be reproduced against any node.
Blocks 709,632–956,197 (Taproot activation through the chain tip at time of run): 123,290,805 revealed Taproot script-path spends.
| Category | Count | Share |
|---|---|---|
| No hidden paths (single-leaf) | 121,426,167 | 98.49% |
| Hidden path(s) (multi-leaf) | 1,864,638 | 1.51% |
98.5% of all revealed Taproot scripts had exactly one spending path — nothing was hidden. The multi-branch feature MAST was built for accounts for 1.5% of revealed script spends.
Only revealed spends are observable: a Taproot output exposes a script only when it is spent via the script path. Key-path spends reveal nothing — not even whether a script tree existed — so they are unobservable by design and out of scope. (Of ~306 million total Taproot spends in this range, ~123 million were script-path; the remaining ~183 million were key-path.)
Each revealed script-path spend carries, in its witness, the leaf script plus a control block whose size is a consensus proof of the tree's shape:
- 33-byte control block → the revealed leaf was the only leaf in the tree. The script's own hash is the Merkle root; there are no sibling branches. No hidden paths. (single-leaf)
- larger than 33 bytes → every extra 32 bytes is a sibling hash on the leaf's Merkle path, proving other, unrevealed branches existed. Hidden path(s). (multi-leaf)
This is a proof, not a heuristic. To spend a Taproot script, the network re-derives the committed Merkle root from what the spend reveals. A tree with more than one path can only be spent by revealing the sibling hashes needed to rebuild that root — so a hidden path cannot be concealed at spend time. A spend that reveals zero siblings proves the tree had exactly one leaf.
The tool classifies every script-path spend into single-leaf vs multi-leaf; the
headline is the split above. --verbose additionally reports the key-path spend
count and a Merkle-depth histogram of the multi-leaf spends.
Requires a running Bitcoin Core node with server=1. Python 3, standard library
only — no dependencies to install.
python3 taproot_leafs.py # Taproot activation -> chain tip
python3 taproot_leafs.py --start-block 709632 --end-block 956197
python3 taproot_leafs.py --start-day 2024-01-01 --end-day 2024-12-31
python3 taproot_leafs.py --verbose # also show key-path count + depth histogram
The script auto-discovers the node's cookie/config in common locations; override
with --rpchost / --rpcport / --rpcuser / --rpcpassword / --datadir if needed.
Results are printed and written to an auto-named text file. A full scan from
activation to tip is RPC-bound and takes several hours.
