Welcome back to Inside Bitcoin Code! Before starting, I wanted to thank every and each one of the 75 people following this newsletter. I really appreciate your support!
Today we are going to dive in the second part of the Bitcoin Core initialization, resuming from where we stopped last week in IBC#007.
Are you ready? Let’s go!
AppInitMain()
— Step-by-step
The last thing discussed in the last episode was the activation of the logging routine, in order to highlight any kind of problems to the user.
The first thing the code does is warning the user in case he decides to set a relative directory for the data. A directory is called relative if it is derived starting from the current working folder; on the contrary, an absolute path is one that does not depend on the particular folder in which the software is. As the warning suggests, putting the directory as a relative folder would make the system fragile, since, in case something is moved, it would not be possible to recover the previous data. Thus, the code controls if the directory set using the -datadir
command is absolute or not.
// Warn about relative -datadir path.
if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) {
LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
"current working directory '%s'. This is fragile, because if bitcoin is started in the future "
"from a different location, it will be unable to locate the current data files. There could "
"also be data loss if bitcoin is started while in a temporary directory.\n",
args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
}
After that, a ValidationCacheSizes
object is created; this structure contains limits in bytes for the signature cache and the script execution cache. The ApplyArgsManOptions()
checks if the -maxsigcachesize
input parameter was set and, if so, fills the ValidationCacheSizes
object.
ValidationCacheSizes validation_cache_sizes{};
ApplyArgsManOptions(args, validation_cache_sizes);
Then, signature and script execution caches are initialized; in case the initialization fails, an error is returned.
if (!InitSignatureCache(validation_cache_sizes.signature_cache_bytes)
|| !InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes))
{
return InitError(strprintf(_("Unable to allocate memory for -maxsigcachesize: '%s' MiB"), args.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_BYTES >> 20)));
}
Then the number of threads used for checking scripts is defined; a thread is basically a process which is executed as a subroutine, called directly from the main process. In this case the number of threads to be used is set through the input parameter -par
. This input is called as a number less than or equal to 0. Why? Because it identifies the number of threads that should be left free. The GetNumCores()
function automatically infers the number of cores available on the machine. Remember that one core can support one thread at a time.
int script_threads = args.GetIntArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (script_threads <= 0) {
// -par=0 means autodetect (number of cores - 1 script threads)
// -par=-n means "leave n cores free" (number of cores - n - 1 script threads)
script_threads += GetNumCores();
}
so, for example, if we wanted to leave 3 threads free we would have:
-par=-3
Thus:
script_threads = -3
In the hypothesis that GetNumCores()
returned 8 cores available:
script_threads += 8
So, the final number of threads usable would be
-3 += 8 => script_threads = 5
Then, the number of script checking threads is controlled to be inside the [0; MAX_SCRIPTCHECK_THREADS
] range. std::max
and std::min
respectively take the maximum and minimum value between the two inputs. Note that script_threads - 1
is taken instead of script_threads
, since the main thread is excluded from the ones available.
// Subtract 1 because the main thread counts towards the par threads
script_threads = std::max(script_threads - 1, 0);
// Number of script-checking threads <= MAX_SCRIPTCHECK_THREADS
script_threads = std::min(script_threads, MAX_SCRIPTCHECK_THREADS);
Finally, the program logs the number of additional threads used and, in case one or more threads are requested for script verification, the threads are launched.
LogPrintf("Script verification uses %d additional threads\n", script_threads);
if (script_threads >= 1) {
StartScriptCheckWorkerThreads(script_threads);
}
Enough for today!
This function is more than 800 lines long, it will take a while to complete it. Thus, see you next week with part 3 of the AppInitMain()
function
As usual, let me know what you think in the comment section and consider sharing Inside Bitcoin Code to anyone who might be interested. It means the world to me!
Usque in Finem
Tuma
Keep up the great work!