IBC#020: Bitcoin Core Initialization, Step 7— Cache Allocation
Loading the Block Chain: Cache Allocation
Hello everyone and welcome to this new episode of Inside Bitcoin Code.
A special welcome to the new people that recently subscribed to this newsletter, I hope that you will enjoy what I write. A small suggestion for you: if you know nothing about coding, start reading the posts from Learn2Code to get some basic knowledge before diving in the real deal.
A huge thanks to each of the 145 subscribers of this newsletter and to those who decided to contribute with some sats to this project. It means the world to me!
Last episode was focused on Onion proxy configuration. Today we are going to continue our trip inside the initialization of Bitcoin Core with the allocation of cache memory for the loading of the block chain. [Code Link]
Let’s start!
Cache Allocation
We have finally reached the end of step 6, network initialization, and we are now ready to deep dive into the loading of the chain of blocks. The software starts by handling memory cache allocation for the different databases used by Bitcoin.
First of all, the code validates that the amount of memory set through the -dbcache
is reasonable with respect to the available RAM, through the LogOversizedDbCache()
function. If the amount chosen is too high, the program logs a warning.
// cache size calculations
node::LogOversizedDbCache(args);
Then, the size of the cache is calculated, based on the set -dbcache
argument, and stored in index_cache_sizes
and kernel_cache_sizes
. The former is used to store the transaction index — which allows fast lookup of any transaction by its hash, while the latter to store the block index — which contains information about block headers, chain difficulty and metadata.
const auto [index_cache_sizes, kernel_cache_sizes] = CalculateCacheSizes
(args, g_enabled_filter_types.size());
Moreover, the size()
of g_enabled_filter_types
is passed as an input to CalculateCacheSizes()
function. This allows to allocate some cache for block filters, a compact representation of blocks, following BIP1581, which allow wallets to determine whether a block contains any transactions involving a user’s keys in a more private manner.
These values are then logged. The code checks if -txindex
has been set, before logging any information. This input argument signals whether or not to keep the full transaction index.
LogInfo(”Cache configuration:”);
LogInfo(”* Using %.1f MiB for block index database”, kernel_cache_sizes.block_tree_db * (1.0 / 1024 / 1024));
if (args.GetBoolArg(”-txindex”, DEFAULT_TXINDEX)) {
LogInfo(”* Using %.1f MiB for transaction index database”, index_cache_sizes.tx_index * (1.0 / 1024 / 1024));
}
Then, the software also logs the cache dedicated to block filters, specifying the amount of memory allocated for each one of them.
for (BlockFilterType filter_type : g_enabled_filter_types) {
LogInfo(”* Using %.1f MiB for %s block filter index database”,
index_cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type));
}
Eventually, information about the chain state dedicated cache is logged. This database contains the UTXO set, which is required for transaction validation and wallet balance calculation.
LogInfo(”* Using %.1f MiB for chain state database”, kernel_cache_sizes.coins_db * (1.0 / 1024 / 1024));
There are two final checks, to make sure that the software is starting from a clean state: the mempool and the blockchain manager should not exist at this point in the code.
assert(!node.mempool);
assert(!node.chainman);
Let’s keep in touch:
Check out my writings on btc++ insider edition
Try my new app Sats Tracker, an expense tracker app for people living in the Bitcoin standard.
Zap me a coffee and leave me a message: tuma@wallet.yakihonne.com