Skip to main content

Indentation and Whitespace

Bitcoin Core follows the rules specified in src/.clang-format. Use the clang-format-diff script to automatically clean up patches.

Key Rules

  • Braces on new lines for classes, functions, methods
  • Braces on same line for everything else (including structs)
  • 4 space indentation (no tabs) for every block except namespaces
  • No indentation for public/protected/private or for namespace
  • No extra spaces inside parentheses; don’t do ( this )
  • No space after function names; one space after if, for, and while
  • Single-statement if: Can appear on same line without braces; otherwise braces required
  • Line width: No hard limit, but prefer less than 100 characters if it doesn’t decrease readability

Example

Naming Conventions

These are preferred in new code but not required when changes would affect significant existing code.

Variables and Namespaces

  • Variable names: All lowercase, may use _ to separate words (snake_case)
  • Function arguments: Same as variables
  • Class member variables: m_ prefix (e.g., m_name, m_count)
  • Global variables: g_ prefix (e.g., g_context)

Constants and Enums

  • Constant names: All uppercase, use _ to separate words (e.g., MAX_BLOCK_SIZE)
  • Enumerator constants: May be snake_case, PascalCase, or ALL_CAPS (use what seems appropriate)

Classes and Functions

  • Class names: UpperCamelCase (PascalCase), do NOT prefix with C
  • Function names: UpperCamelCase (PascalCase)
  • Method names: UpperCamelCase (PascalCase)

Test Suites

Boost test suite in src/test/foo_tests.cpp should be named foo_tests. Test suite names must be unique.

C++ Best Practices

Preferred Syntax

  • Increment: Prefer ++i over i++
  • Null pointers: Use nullptr (not NULL or (void*)0)
  • Compile-time checks: Use static_assert over assert where possible
  • Casts: Use named/functional casts, not C-style casts
    • Between integer types: int(x) or int{x} (not (int) x)
    • Between complex types: static_cast, reinterpret_cast, const_cast
  • Initialization: Prefer list initialization int x{0}; over int x = 0; or int x(0);
  • Recursion: Must be explicit with NOLINTNEXTLINE(misc-no-recursion) comment

Namespace Usage

For function calls, specify namespace explicitly to avoid argument-dependent lookup (ADL):

Functions and Methods

Parameter Ordering

When ordering function parameters:
  1. Input parameters first
  2. In-out parameters next
  3. Output parameters last
Rationale: API consistency

Return Values

  • Prefer returning values directly over using in-out/output parameters
  • Use std::optional for optional return values
  • Use std::optional for optional by-value inputs (instead of magic default values)
  • Non-optional input parameters: Usually values or const references
  • Non-optional in-out/output parameters: Usually references (cannot be null)
Returning values directly is less error-prone, easier to read, and often has the same or better performance.

Named Arguments

Use a format that clang-tidy understands:

Running clang-tidy

Install dependencies (Ubuntu/Debian):
Configure with clang:
Run on all files:
Run on changed lines only:

Doxygen Comments

Use Doxygen-compatible comments for functions, methods, and fields.

Function Documentation

Class Documentation

Member/Variable Documentation

Recommendations

  • Avoid duplicating type and input/output information in descriptions
  • Use backticks to refer to argument names
  • Doxygen automatically builds hyperlinks for known functions
  • Avoid linking to external documentation (links can break)
  • Use // or /* */ for comments you want preserved in code previews

Data Structures

std::map Usage

Never use std::map[] syntax when reading from a map. Use .find() instead. [] performs an insert if the key doesn’t exist, which has caused memory leaks and race conditions.
Using [] is fine for writing to a map.

Iterator Safety

Do not compare an iterator from one data structure with an iterator from another, even if they’re the same type. Rationale: Undefined behavior that has caused hard-to-debug crashes.

Vector Safety

  • Watch out for out-of-bounds access
  • &vch[vch.size()] is illegal, including &vch[0] for empty vectors
  • Use vch.data() and vch.data() + vch.size() instead
  • Vector bounds checking is only enabled in debug mode

Member Initialization

Initialize all non-static class members where they are defined:
Rationale: Ensures determinism, helps static analyzers, makes uninitialized members easy to spot.

Constructors

By default, declare constructors explicit: Rationale: Prevents unintended conversions.

Character Types

Use explicitly signed or unsigned chars, or better yet uint8_t and int8_t. Don’t use bare char unless passing to third-party API. Rationale: char signedness is architecture-dependent, which can lead to interoperability problems or dangerous conditions like out-of-bounds array access.

std::span

Use std::span as a function argument when it can operate on any range-like container:
Rationale: Avoids potentially expensive conversion to vector if caller has data in another container type.

Enumerations

Prefer enum class (scoped) over enum (traditional): Rationale: Avoids implicit conversions to int and name clashes from enumerators exported to surrounding scope.

Strings and Formatting

String Handling

  • Use std::string, avoid C string manipulation functions
  • Rationale: Safer, less scope for buffer overflows, no surprises with \0 characters

Format Specifiers

For strprintf, LogInfo, LogDebug, etc., don’t use size specifiers (hh, h, l, ll, j, z, t, L) for arithmetic types. Rationale: Bitcoin Core uses tinyformat, which is type safe.

Using .c_str()

Use .c_str() sparingly - only to pass C++ strings to C functions expecting NULL-terminated strings.
  • Don’t use with .size() - use .data() instead
  • Don’t use with tfm::format, strprintf, LogInfo, LogDebug - they handle strings
  • Don’t use to convert to QString - use QString::fromStdString()
  • When you do use it, consider checking for embedded '\0' characters that could truncate the string

Threading and Synchronization

Mutex Preference

Prefer Mutex type to RecursiveMutex.

Thread Safety Analysis

Consistently use Clang Thread Safety Analysis annotations:
Add annotations exclusively to function declarations, not definitions. Combine annotations in declarations with run-time asserts in definitions.

Lock Scope

When using LOCK/TRY_LOCK, surround the statement and code needing the lock with braces:

Source Code Organization

Implementation Location

Implementation code should go in .cpp files, not .h, unless:
  • Necessary due to template usage
  • Performance due to inlining is critical
Rationale: Shorter, simpler headers are easier to read and reduce compile time.

Header Includes

Every .cpp and .h file should #include every header it directly uses, even if already indirectly included. Rationale: Prevents compilation failures when indirect dependencies change; makes real dependencies clear.

Namespace Rules

  • Don’t import into global namespace (using namespace ...)
  • Use fully specified types like std::string
  • Terminate namespaces with a comment:

Shadowing

Although -Wshadow is not enabled by default, name variables so they don’t shadow variables defined elsewhere. When using nested loops, don’t reuse the inner loop variable name.

Python Style

Refer to /test/functional/README.md#style-guidelines for Python coding style.