📚 Part 8 of 8, the final part of the "Bitcoin Deep Dive" series. New here? Part 1 gives you the full overview of the whole series.

A Bitcoin node by default stores only as much as it genuinely needs to check the rules and serve its own wallet. Certain genuinely useful questions ("exactly where in the last 17 years of history does this one transaction show up?") would otherwise only be answerable via an extremely expensive, complete pass through the entire chain history. For exactly these cases, Bitcoin Core offers additional, entirely optional records you can switch on selectively. This final post in the series introduces the three most important ones.

A Recap: What a Node Can Already Do With No Extra Index at All

Before we get to the extensions, it's worth a quick reminder of what an entirely ordinary node already does "out of the box," with none of the following optional indexes enabled: it can, at any time, fully independently verify whether a new transaction or a new block satisfies every rule described in Part 2 and Part 3 of this series. It can reliably determine the current balance of every address managed in its own wallet. And it can tell whether a specific UTXO it already knows about is currently still unspent. For day-to-day operation as a "voting" network participant and for your own wallet, that's entirely sufficient, the three indexes below only solve additional needs that go beyond this core.

Why a Node Doesn't Simply Store "Everything"

This might seem surprising at first: wouldn't it be simpler if a node just indexed everything it sees, by default? The reason against it is simple: storage space and processing time. Every additional index means additional database entries that need updating with every new block, and additional disk space, which genuinely matters on a blockchain that's now over 700 gigabytes in size. Bitcoin Core therefore leaves the choice entirely up to each operator: whoever needs the extra functionality switches on the relevant index, everyone else saves themselves the overhead.

The Transaction Index: Making the Entire History Book Searchable

Without a special setting, a node can only look up transactions that either involve its own wallet or are still sitting in the current mempool. The optional transaction index (txindex, off by default, see src/index/txindex.h) changes that: once enabled, the node remembers, for every single transaction ever confirmed across the entire chain history, exactly where on disk it can be found, stored in a separate, highly efficient database (LevelDB). Services like block explorers (see Part 7 of this series) practically depend on this, since they need to look up arbitrary, unrelated transactions, not just their own.

Compact Filters for Lightweight Clients (BIP157/158)

Not everyone who wants to use Bitcoin can or wants to keep 700 gigabytes of blockchain data on their own device, think of a smartphone. For such "light" clients, there used to be an approach called Bloom filters (BIP37): the light client built a compact, deliberately somewhat imprecise filter (a space-saving bit array) from its own addresses and sent it to a full node, which then returned every block that might potentially match. That built-in imprecision was genuinely intentional: a hit in the filter only means "possibly relevant" (real matches included, but also false positives), while a non-hit means, with complete certainty, "definitely not relevant," this deliberate noise was meant to build in some fuzziness in favor of privacy. In practice, though, this turned out to be too weak: an observer who sees the same filter from the same wallet repeatedly over time can, through repeated observation, narrow down the actually targeted addresses with growing confidence, a privacy trade-off that gets worse over time instead of staying stable.

The more modern compact block filter index (BIP157/158, src/index/blockfilterindex.h) flips the principle around: the full node itself creates a compact, mathematically clever filter for every single block (a so-called Golomb-coded set, GCSFilter in src/blockfilter.h) and publishes it. A light client downloads these (fairly small) filters itself and checks purely locally, on its own device, whether a given block might contain potentially relevant transactions for it. Only if a filter indicates a possible match does the client specifically request the full block. The decisive difference: the full node never learns what the client is even searching for, the entire "search" happens exclusively on the client's side.

CoinStatsIndex: A Checksum Over Millions of Balances That Doesn't Need a Full Recompute

The third optional index solves a fairly subtle problem: how do you efficiently maintain a cryptographic "checksum" over the complete, current set of all existing, unspent bitcoin balances worldwide (the so-called UTXO set), without recalculating everything from scratch on every new transaction? The solution is called MuHash (src/crypto/muhash.h): a special hash function over sets that lets you simply add a single new element to an existing checksum, or remove a spent element from it, without having to reprocess the entire, enormous set all over again. Enable the CoinStatsIndex, and the node keeps this constantly up-to-date checksum ready at all times, useful, for example, to quickly verify that two independent nodes genuinely see exactly the same UTXO set, without triggering a very computationally expensive full check each time.

A Practical Trade-Off: Pruning as the Counterpart to Indexing

Interestingly, Bitcoin Core also offers an option in exactly the opposite direction: so-called pruned mode. Instead of enabling additional indexes and thereby using MORE disk space, a node can also be configured to delete older, already fully validated block data from disk after validation, keeping only the information strictly necessary for ongoing consensus checking. A node "pruned" this way can still fully, independently verify every new transaction and every new block against the same rules described in Part 2 of this series; it just can no longer answer very old, historical queries, because the corresponding raw data simply isn't there anymore. For someone who just wants to run a full, sovereign node for their own wallet, without also serving as a block explorer backend, this is a perfectly legitimate, resource-saving trade-off, a nice example of how "full rule verification" and "full data storage" are two independent things you can configure separately.

A Practical Example: Why a Lightning Node Can Depend on txindex

A concrete example makes the value of the transaction index tangible: a Lightning node (see Part 3 of this series for the technical basics of payment channels) occasionally needs to verify that a specific, possibly long-past channel-opening transaction was indeed anchored in the blockchain as expected, even if that transaction has nothing to do with the node operator's own wallet, because the channel partner originally submitted it. Without the transaction index enabled, the underlying Bitcoin node might, in the worst case, have to search the entire chain history for this; with txindex enabled, the answer instead comes back in a fraction of a second. That's one of the reasons guides for running your own Lightning node almost always recommend running the underlying Bitcoin node with the transaction index enabled from the start.

Conclusion of the Series: A System That Shows Its Own Work

With this final building block, the circle closes on this eight-part series. We've seen how Bitcoin's consensus rules are incorruptibly anchored in the code, how the script system evolved through Taproot toward more privacy, what rules govern the mempool, how nodes find each other with no central authority at all, how a wallet intelligently selects funds, how software talks to a node from the outside, and now, how optional indexes make certain questions practically answerable in the first place.

The actual point of this entire series was never for you to memorize every single line of code. It was to show you: every claim made here can be checked against a specific, publicly viewable spot in the code, none of it requires you to simply take anyone's word for it. That's exactly what separates a system you're supposed to trust from one you can verify yourself. And that, technically speaking, is where Bitcoin's real value lies.

This series refers to Bitcoin Core version 31.1 (commit 9be056a8…, as of September 2026). You can find all eight parts at a glance in Part 1.