aboutsummaryrefslogtreecommitdiff
path: root/doc/developer-notes.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/developer-notes.md')
-rw-r--r--doc/developer-notes.md210
1 files changed, 166 insertions, 44 deletions
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 1888897856..23f975df34 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -17,6 +17,7 @@ Developer Notes
- [`debug.log`](#debuglog)
- [Signet, testnet, and regtest modes](#signet-testnet-and-regtest-modes)
- [DEBUG_LOCKORDER](#debug_lockorder)
+ - [DEBUG_LOCKCONTENTION](#debug_lockcontention)
- [Valgrind suppressions file](#valgrind-suppressions-file)
- [Compiling for test coverage](#compiling-for-test-coverage)
- [Performance profiling with perf](#performance-profiling-with-perf)
@@ -31,6 +32,7 @@ Developer Notes
- [C++ data structures](#c-data-structures)
- [Strings and formatting](#strings-and-formatting)
- [Shadowing](#shadowing)
+ - [Lifetimebound](#lifetimebound)
- [Threads and synchronization](#threads-and-synchronization)
- [Scripts](#scripts)
- [Shebang](#shebang)
@@ -95,7 +97,10 @@ code.
Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-caps),
which recommend using `snake_case`. Please use what seems appropriate.
- Class names, function names, and method names are UpperCamelCase
- (PascalCase). Do not prefix class names with `C`.
+ (PascalCase). Do not prefix class names with `C`. See [Internal interface
+ naming style](#internal-interface-naming-style) for an exception to this
+ convention.
+
- Test suite naming convention: The Boost test suite in file
`src/test/foo_tests.cpp` should be named `foo_tests`. Test suite names
must be unique.
@@ -105,6 +110,28 @@ code.
- `nullptr` is preferred over `NULL` or `(void*)0`.
- `static_assert` is preferred over `assert` where possible. Generally; compile-time checking is preferred over run-time checking.
+For function calls a namespace should be specified explicitly, unless such functions have been declared within it.
+Otherwise, [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl), also known as ADL, could be
+triggered that makes code harder to maintain and reason about:
+```c++
+#include <filesystem>
+
+namespace fs {
+class path : public std::filesystem::path
+{
+};
+// The intention is to disallow this function.
+bool exists(const fs::path& p) = delete;
+} // namespace fs
+
+int main()
+{
+ //fs::path p; // error
+ std::filesystem::path p; // compiled
+ exists(p); // ADL being used for unqualified name lookup
+}
+```
+
Block style example:
```c++
int g_count = 0;
@@ -137,11 +164,78 @@ public:
} // namespace foo
```
+Coding Style (C++ functions and methods)
+--------------------
+
+- When ordering function parameters, place input parameters first, then any
+ in-out parameters, followed by any output parameters.
+
+- *Rationale*: API consistency.
+
+- Prefer returning values directly to using in-out or output parameters. Use
+ `std::optional` where helpful for returning values.
+
+- *Rationale*: Less error-prone (no need for assumptions about what the output
+ is initialized to on failure), easier to read, and often the same or better
+ performance.
+
+- Generally, use `std::optional` to represent optional by-value inputs (and
+ instead of a magic default value, if there is no real default). Non-optional
+ input parameters should usually be values or const references, while
+ non-optional in-out and output parameters should usually be references, as
+ they cannot be null.
+
+Coding Style (C++ named arguments)
+------------------------------
+
+When passing named arguments, use a format that clang-tidy understands. The
+argument names can otherwise not be verified by clang-tidy.
+
+For example:
+
+```c++
+void function(Addrman& addrman, bool clear);
+
+int main()
+{
+ function(g_addrman, /*clear=*/false);
+}
+```
+
+### Running clang-tidy
+
+To run clang-tidy on Ubuntu/Debian, install the dependencies:
+
+```sh
+apt install clang-tidy bear clang
+```
+
+Then, pass clang as compiler to configure, and use bear to produce the `compile_commands.json`:
+
+```sh
+./autogen.sh && ./configure CC=clang CXX=clang++
+make clean && bear make -j $(nproc) # For bear 2.x
+make clean && bear -- make -j $(nproc) # For bear 3.x
+```
+
+To run clang-tidy on all source files:
+
+```sh
+( cd ./src/ && run-clang-tidy -j $(nproc) )
+```
+
+To run clang-tidy on the changed source lines:
+
+```sh
+git diff | ( cd ./src/ && clang-tidy-diff -p2 -j $(nproc) )
+```
+
Coding Style (Python)
---------------------
Refer to [/test/functional/README.md#style-guidelines](/test/functional/README.md#style-guidelines).
+
Coding Style (Doxygen-compatible comments)
------------------------------------------
@@ -316,6 +410,21 @@ configure option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts
run-time checks to keep track of which locks are held and adds warnings to the
`debug.log` file if inconsistencies are detected.
+### DEBUG_LOCKCONTENTION
+
+Defining `DEBUG_LOCKCONTENTION` adds a "lock" logging category to the logging
+RPC that, when enabled, logs the location and duration of each lock contention
+to the `debug.log` file.
+
+The `--enable-debug` configure option adds `-DDEBUG_LOCKCONTENTION` to the
+compiler flags. You may also enable it manually for a non-debug build by running
+configure with `-DDEBUG_LOCKCONTENTION` added to your CPPFLAGS,
+i.e. `CPPFLAGS="-DDEBUG_LOCKCONTENTION"`, then build and run bitcoind.
+
+You can then use the `-debug=lock` configuration option at bitcoind startup or
+`bitcoin-cli logging '["lock"]'` at runtime to turn on lock contention logging.
+It can be toggled off again with `bitcoin-cli logging [] '["lock"]'`.
+
### Assertions and Checks
The util file `src/util/check.h` offers helpers to protect against coding and
@@ -331,7 +440,7 @@ other input.
failure, it will throw an exception, which can be caught to recover from the
error.
- For example, a nullptr dereference or any other logic bug in RPC code
- means that the RPC code is faulty and can not be executed. However, the
+ means that the RPC code is faulty and cannot be executed. However, the
logic bug can be shown to the user and the program can continue to run.
* `Assume` should be used to document assumptions when program execution can
safely continue even if the assumption is violated. In debug builds it
@@ -597,10 +706,6 @@ Wallet
- Make sure that no crashes happen with run-time option `-disablewallet`.
-- Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set.
-
- - *Rationale*: Otherwise compilation of the disable-wallet build will fail in environments without BerkeleyDB.
-
General C++
-------------
@@ -726,11 +831,6 @@ int GetInt(Tabs tab)
Strings and formatting
------------------------
-- Be careful of `LogPrint` versus `LogPrintf`. `LogPrint` takes a `category` argument, `LogPrintf` does not.
-
- - *Rationale*: Confusion of these can result in runtime exceptions due to
- formatting mismatch, and it is easy to get wrong because of subtly similar naming.
-
- Use `std::string`, avoid C string manipulation functions.
- *Rationale*: C++ string handling is marginally safer, less scope for
@@ -803,22 +903,37 @@ from using a different variable with the same name),
please name variables so that their names do not shadow variables defined in the source code.
When using nested cycles, do not name the inner cycle variable the same as in
-the upper cycle, etc.
+the outer cycle, etc.
+
+Lifetimebound
+--------------
+
+The [Clang `lifetimebound`
+attribute](https://clang.llvm.org/docs/AttributeReference.html#lifetimebound)
+can be used to tell the compiler that a lifetime is bound to an object and
+potentially see a compile-time warning if the object has a shorter lifetime from
+the invalid use of a temporary. You can use the attribute by adding a `LIFETIMEBOUND`
+annotation defined in `src/attributes.h`; please grep the codebase for examples.
Threads and synchronization
----------------------------
-- Prefer `Mutex` type to `RecursiveMutex` one
+- Prefer `Mutex` type to `RecursiveMutex` one.
- Consistently use [Clang Thread Safety Analysis](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html) annotations to
- get compile-time warnings about potential race conditions in code. Combine annotations in function declarations with
- run-time asserts in function definitions:
+ get compile-time warnings about potential race conditions or deadlocks in code.
- In functions that are declared separately from where they are defined, the
thread safety annotations should be added exclusively to the function
declaration. Annotations on the definition could lead to false positives
(lack of compile failure) at call sites between the two.
+ - Prefer locks that are in a class rather than global, and that are
+ internal to a class (private or protected) rather than public.
+
+ - Combine annotations in function declarations with run-time asserts in
+ function definitions:
+
```C++
// txmempool.h
class CTxMemPool
@@ -842,21 +957,37 @@ void CTxMemPool::UpdateTransactionsFromBlock(...)
```C++
// validation.h
-class ChainstateManager
+class CChainState
{
+protected:
+ ...
+ Mutex m_chainstate_mutex;
+ ...
public:
...
- bool ProcessNewBlock(...) LOCKS_EXCLUDED(::cs_main);
+ bool ActivateBestChain(
+ BlockValidationState& state,
+ std::shared_ptr<const CBlock> pblock = nullptr)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex)
+ LOCKS_EXCLUDED(::cs_main);
+ ...
+ bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex)
+ LOCKS_EXCLUDED(::cs_main);
...
}
// validation.cpp
-bool ChainstateManager::ProcessNewBlock(...)
+bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
{
+ AssertLockNotHeld(m_chainstate_mutex);
AssertLockNotHeld(::cs_main);
- ...
- LOCK(::cs_main);
- ...
+ {
+ LOCK(cs_main);
+ ...
+ }
+
+ return ActivateBestChain(state, std::shared_ptr<const CBlock>());
}
```
@@ -887,6 +1018,8 @@ TRY_LOCK(cs_vNodes, lockNodes);
Scripts
--------------------------
+Write scripts in Python rather than bash, when possible.
+
### Shebang
- Use `#!/usr/bin/env bash` instead of obsolete `#!/bin/bash`.
@@ -1025,10 +1158,6 @@ Current subtrees include:
- src/crypto/ctaes
- Upstream at https://github.com/bitcoin-core/ctaes ; maintained by Core contributors.
-- src/univalue
- - Subtree at https://github.com/bitcoin-core/univalue-subtree ; maintained by Core contributors.
- - Deviates from upstream https://github.com/jgarzik/univalue.
-
- src/minisketch
- Upstream at https://github.com/sipa/minisketch ; maintained by Core contributors.
@@ -1160,7 +1289,10 @@ A few guidelines for introducing and reviewing new RPC interfaces:
- *Rationale*: Consistency with the existing interface.
-- Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`)
+- Argument and field naming: please consider whether there is already a naming
+ style or spelling convention in the API for the type of object in question
+ (`blockhash`, for example), and if so, try to use that. If not, use snake case
+ `fee_delta` (and not, e.g. `feedelta` or camel case `feeDelta`).
- *Rationale*: Consistency with the existing interface.
@@ -1199,7 +1331,7 @@ A few guidelines for introducing and reviewing new RPC interfaces:
- Don't forget to fill in the argument names correctly in the RPC command table.
- - *Rationale*: If not, the call can not be used with name-based arguments.
+ - *Rationale*: If not, the call cannot be used with name-based arguments.
- Add every non-string RPC argument `(method, idx, name)` to the table `vRPCConvertParams` in `rpc/client.cpp`.
@@ -1326,22 +1458,9 @@ communication:
virtual boost::signals2::scoped_connection connectTipChanged(TipChangedFn fn) = 0;
```
-- For consistency and friendliness to code generation tools, interface method
- input and inout parameters should be ordered first and output parameters
- should come last.
+- Interface methods should not be overloaded.
- Example:
-
- ```c++
- // Good: error output param is last
- virtual bool broadcastTransaction(const CTransactionRef& tx, CAmount max_fee, std::string& error) = 0;
-
- // Bad: error output param is between input params
- virtual bool broadcastTransaction(const CTransactionRef& tx, std::string& error, CAmount max_fee) = 0;
- ```
-
-- For friendliness to code generation tools, interface methods should not be
- overloaded:
+ *Rationale*: consistency and friendliness to code generation tools.
Example:
@@ -1355,10 +1474,13 @@ communication:
virtual bool disconnect(NodeId id) = 0;
```
-- For consistency and friendliness to code generation tools, interface method
- names should be `lowerCamelCase` and standalone function names should be
+### Internal interface naming style
+
+- Interface method names should be `lowerCamelCase` and standalone function names should be
`UpperCamelCase`.
+ *Rationale*: consistency and friendliness to code generation tools.
+
Examples:
```c++