index

Useful Commands for Bitcoin Core Development

This blog is subject to change, and may become out of date

LSP

First time build, so clangd can find a compile_commands.json:

cmake -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

Build

Prebuild:

cmake -B build

Build:

cmake --build build -j $(nproc)

Clear cache:

ccache -C

Tests

Unit tests:

ctest --test-dir build
# or
build/bin/test_bitcoin
# or, with full logging
build/bin/test_bitcoin --log_level=all

Run a single unit test:

build/bin/test_bitcoin --log_level=all --run_test=getarg_tests

Full regression test suite:

build/test/functional/test_runner.py

Run a single functional test:

build/test/functional/feature_rbf.py

Configure test_kernel:

cmake -B build -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON

Build it:

cmake --build build -j$(nproc) --target test_kernel

Run it:

ctest --test-dir build -R test_kernel -V

Git

Worktree checkout, from master:

git worktree add ../network

Cherry-pick a merge commit:

git cherry-pick -Xours -m 1 -x 00af5620f01dbd1d2e696487303fad0382b67591

Run a build and test suite on every commit in a range, useful for bisecting where something broke:

git rebase -i --exec "cmake --build build && ctest --test-dir build" "$(git merge-base master HEAD)"

Configure a fuzz build with GCC and sanitizers:

cmake -B build_fuzz_gcc \
  -DCMAKE_C_COMPILER=gcc \
  -DCMAKE_CXX_COMPILER=g++ \
  -DBUILD_FOR_FUZZING=ON \
  -DSANITIZERS=address,undefined

Combine a normal build, test, fuzz build, and lint into a single rebase exec:

git rebase -i --exec "cmake --build build -j 16 && ctest --test-dir build && cmake -B build_fuzz -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DBUILD_FOR_FUZZING=ON && cmake --build build_fuzz -j 16 && ./ci/lint.py" HEAD~8

IWYU

Restart Docker:

sudo systemctl restart docker

Run the native IWYU CI task locally:

env -i HOME="$HOME" PATH="$PATH" USER="$USER" MAKEJOBS="-j1" FILE_ENV="./ci/test/00_setup_env_native_iwyu.sh" ./ci/test_run_all.sh

CI

Run the native fuzz-with-valgrind CI task locally:

env -i HOME="$HOME" PATH="$PATH" USER="$USER" MAKEJOBS="-j16" FILE_ENV="./ci/test/00_setup_env_native_fuzz_with_valgrind.sh" ./ci/test_run_all.sh

Debug

To debug a test, build a debug binary:

cmake -B build_debug -DCMAKE_BUILD_TYPE=DEBUG && cmake --build build_debug -j $(nproc)

Then run it under gdb:

gdb --args build_debug/bin/test_bitcoin -t blockfilter_tests

Handy reference: gdb cheat sheet.

Bench

Benchmark the merge-base against the current branch, then walk through each commit on the branch running the same benchmark, checking out the current branch again at the end:

BASE=$(git merge-base master HEAD) && \
  git checkout --detach --quiet "$BASE" && \
  cmake --build build --target bench_bitcoin >/dev/null && \
  build/bin/bench_bitcoin -filter='.*MemPool.*' && \
  git checkout --quiet - && \
  git rebase -i --exec "cmake --build build && build/bin/bench_bitcoin -filter='.*MemPool.*'" "$BASE"

A simpler before/after comparison between the merge-base and the tip of the current branch:

BRANCH=$(git symbolic-ref --short HEAD) && \
  git checkout --detach --quiet "$(git merge-base master HEAD)" && \
  cmake --build build --target bench_bitcoin && \
  build/bin/bench_bitcoin -filter='.*MemPool.*' && \
  git checkout --quiet "$BRANCH" && \
  cmake --build build --target bench_bitcoin && \
  build/bin/bench_bitcoin -filter='.*MemPool.*'