Skip to content

Commit 8332457

Browse files
committed
Merge pull request #7003
b8c06ef doc: Add non-style-related development guidelines (Wladimir J. van der Laan)
2 parents 8284feb + b8c06ef commit 8332457

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

doc/developer-notes.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,172 @@ If a set of tools is used by the build system or scripts the repository (for
204204
example, lcov) it is perfectly acceptable to add its files to `.gitignore`
205205
and commit them.
206206

207+
Development guidelines
208+
============================
209+
210+
A few non-style-related recommendations for developers, as well as points to
211+
pay attention to for reviewers of Bitcoin Core code.
212+
213+
General Bitcoin Core
214+
----------------------
215+
216+
- New features should be exposed on RPC first, then can be made available in the GUI
217+
218+
- *Rationale*: RPC allows for better automatic testing. The test suite for
219+
the GUI is very limited
220+
221+
- Make sure pulls pass Travis CI before merging
222+
223+
- *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing
224+
on the master branch. Otherwise all new pull requests will start failing the tests, resulting in
225+
confusion and mayhem
226+
227+
- *Explanation*: If the test suite is to be updated for a change, this has to
228+
be done first
229+
230+
Wallet
231+
-------
232+
233+
- Make sure that that no crashes happen with run-time option `-disablewallet`.
234+
235+
- *Rationale*: In RPC code that conditionally use the wallet (such as
236+
`validateaddress`) it is easy to forget that global pointer `pwalletMain`
237+
can be NULL. See `qa/rpc-tests/disablewallet.py` for functional tests
238+
exercising the API with `-disablewallet`
239+
240+
- Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set
241+
242+
- *Rationale*: Otherwise compilation of the disable-wallet build will fail in environments without BerkeleyDB
243+
244+
General C++
245+
-------------
246+
247+
- Assertions should not have side-effects
248+
249+
- *Rationale*: Even though the source code is set to to refuse to compile
250+
with assertions disabled, having side-effects in assertions is unexpected and
251+
makes the code harder to understand
252+
253+
- If you use the .h, you must link the .cpp
254+
255+
- *Rationale*: Include files are the interface for the implementation file. Including one but
256+
not linking the other is confusing. Please avoid that. Moving functions from
257+
the `.h` to the `.cpp` should not result in build errors
258+
259+
- Use the RAII (Resource Acquisition Is Initialization) paradigm where possible. For example by using
260+
`scoped_pointer` for allocations in a function.
261+
262+
- *Rationale*: This avoids memory and resource leaks, and ensures exception safety
263+
264+
C++ data structures
265+
--------------------
266+
267+
- Never use the std::map [] syntax when reading from a map, but instead use .find()
268+
269+
- *Rationale*: [] does an insert (of the default element) if the item doesn't
270+
exist in the map yet. This has resulted in memory leaks in the past, as well as
271+
race conditions (expecting read-read behavior). Using [] is fine for *writing* to a map
272+
273+
- Do not compare an iterator from one data structure with an iterator of
274+
another data structure (even if of the same type)
275+
276+
- *Rationale*: Behavior is undefined. In C++ parlor this means "may reformat
277+
the universe", in practice this has resulted in at least one hard-to-debug crash bug
278+
279+
- Watch out for vector out-of-bounds exceptions. `&vch[0]` is illegal for an
280+
empty vector, `&vch[vch.size()]` is always illegal. Use `begin_ptr(vch)` and
281+
`end_ptr(vch)` to get the begin and end pointer instead (defined in
282+
`serialize.h`)
283+
284+
- Vector bounds checking is only enabled in debug mode. Do not rely on it
285+
286+
- Make sure that constructors initialize all fields. If this is skipped for a
287+
good reason (i.e., optimization on the critical path), add an explicit
288+
comment about this
289+
290+
- *Rationale*: Ensure determinism by avoiding accidental use of uninitialized
291+
values. Also, static analyzers balk about this.
292+
293+
- Use explicitly signed or unsigned `char`s, or even better `uint8_t` and
294+
`int8_t`. Do not use bare `char` unless it is to pass to a third-party API.
295+
This type can be signed or unsigned depending on the architecture, which can
296+
lead to interoperability problems or dangerous conditions such as
297+
out-of-bounds array accesses
298+
299+
- Prefer explicit constructions over implicit ones that rely on 'magical' C++ behavior
300+
301+
- *Rationale*: Easier to understand what is happening, thus easier to spot mistakes, even for those
302+
that are not language lawyers
303+
304+
Strings and formatting
305+
------------------------
306+
307+
- Be careful of LogPrint versus LogPrintf. LogPrint takes a 'category' argument, LogPrintf does not.
308+
309+
- *Rationale*: Confusion of these can result in runtime exceptions due to
310+
formatting mismatch, and it is easy to get wrong because of subtly similar naming
311+
312+
- Use std::string, avoid C string manipulation functions
313+
314+
- *Rationale*: C++ string handling is marginally safer, less scope for
315+
buffer overflows and surprises with \0 characters. Also some C string manipulations
316+
tend to act differently depending on platform, or even the user locale
317+
318+
- Use ParseInt32, ParseInt64, ParseDouble from `utilstrencodings.h` for number parsing
319+
320+
- *Rationale*: These functions do overflow checking, and avoid pesky locale issues
321+
322+
- For `strprintf`, `LogPrint`, `LogPrintf` formatting characters don't need size specifiers
323+
324+
- *Rationale*: Bitcoin Core uses tinyformat, which is type safe. Leave them out to avoid confusion
325+
326+
Threads and synchronization
327+
----------------------------
328+
329+
- Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential
330+
deadlocks are introduced. As of 0.12, this is defined by default when
331+
configuring with `--enable-debug`
332+
333+
- When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of
334+
the current scope, so surround the statement and the code that needs the lock
335+
with braces
336+
337+
OK:
338+
339+
```c++
340+
{
341+
TRY_LOCK(cs_vNodes, lockNodes);
342+
...
343+
}
344+
```
345+
346+
Wrong:
347+
348+
```c++
349+
TRY_LOCK(cs_vNodes, lockNodes);
350+
{
351+
...
352+
}
353+
```
354+
355+
Source code organization
356+
--------------------------
357+
358+
- Implementation code should go into the `.cpp` file and not the `.h`, unless necessary due to template usage or
359+
when performance due to inlining is critical
360+
361+
- *Rationale*: Shorter and simpler header files are easier to read, and reduce compile time
362+
363+
- Don't import anything into the global namespace (`using namespace ...`). Use
364+
fully specified types such as `std::string`.
365+
366+
- *Rationale*: Avoids symbol conflicts
367+
368+
GUI
369+
-----
370+
371+
- Do not display or manipulate dialogs in model code (classes `*Model`)
372+
373+
- *Rationale*: Model classes pass through events and data from the core, they
374+
should not interact with the user. That's where View classes come in. The converse also
375+
holds: try to not directly access core data structures from Views.

0 commit comments

Comments
 (0)