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/privateor fornamespace - No extra spaces inside parentheses; don’t do
( this ) - No space after function names; one space after
if,for, andwhile - 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, orALL_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 insrc/test/foo_tests.cpp should be named foo_tests. Test suite names must be unique.
C++ Best Practices
Preferred Syntax
- Increment: Prefer
++ioveri++ - Null pointers: Use
nullptr(notNULLor(void*)0) - Compile-time checks: Use
static_assertoverassertwhere possible - Casts: Use named/functional casts, not C-style casts
- Between integer types:
int(x)orint{x}(not(int) x) - Between complex types:
static_cast,reinterpret_cast,const_cast
- Between integer types:
- Initialization: Prefer list initialization
int x{0};overint x = 0;orint 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:- Input parameters first
- In-out parameters next
- Output parameters last
Return Values
- Prefer returning values directly over using in-out/output parameters
- Use
std::optionalfor optional return values - Use
std::optionalfor 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)
Named Arguments
Use a format that clang-tidy understands:Running clang-tidy
Install dependencies (Ubuntu/Debian):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
argumentnames - 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.[] 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()andvch.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:Constructors
By default, declare constructorsexplicit:
Rationale: Prevents unintended conversions.
Character Types
Use explicitly signed or unsignedchars, 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
Usestd::span as a function argument when it can operate on any range-like container:
Enumerations
Preferenum 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
\0characters
Format Specifiers
Forstrprintf, 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- useQString::fromStdString() - When you do use it, consider checking for embedded
'\0'characters that could truncate the string
Threading and Synchronization
Mutex Preference
PreferMutex type to RecursiveMutex.
Thread Safety Analysis
Consistently use Clang Thread Safety Analysis annotations:Lock Scope
When usingLOCK/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
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.