Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: trivial 2024 10 23 pr10 #6353

5 changes: 4 additions & 1 deletion build-aux/m4/l_atomic.m4
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ m4_define([_CHECK_ATOMIC_testbody], [[

int main() {
std::atomic<bool> lock{true};
std::atomic_exchange(&lock, false);
lock.exchange(false);

std::atomic<std::chrono::seconds> t{0s};
t.store(2s);
Expand All @@ -34,6 +34,8 @@ m4_define([_CHECK_ATOMIC_testbody], [[
AC_DEFUN([CHECK_ATOMIC], [

AC_LANG_PUSH(C++)
TEMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"

AC_MSG_CHECKING([whether std::atomic can be used without link library])

Expand All @@ -51,5 +53,6 @@ AC_DEFUN([CHECK_ATOMIC], [
])
])

CXXFLAGS="$TEMP_CXXFLAGS"
AC_LANG_POP
])
6 changes: 3 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,6 @@ else
AX_CXX_COMPILE_STDCXX([20], [noext], [mandatory])
fi

dnl Check if -latomic is required for <std::atomic>
CHECK_ATOMIC

dnl check if additional link flags are required for std::filesystem
CHECK_FILESYSTEM

Expand Down Expand Up @@ -896,6 +893,9 @@ AC_C_BIGENDIAN
dnl Check for pthread compile/link requirements
AX_PTHREAD

dnl Check if -latomic is required for <std::atomic>
CHECK_ATOMIC

dnl The following macro will add the necessary defines to bitcoin-config.h, but
dnl they also need to be passed down to any subprojects. Pull the results out of
dnl the cache and add them to CPPFLAGS.
Expand Down
77 changes: 47 additions & 30 deletions doc/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,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)
Expand Down Expand Up @@ -95,7 +96,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.
Expand Down Expand Up @@ -160,6 +164,27 @@ 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)
------------------------------

Expand Down Expand Up @@ -681,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++
-------------

Expand All @@ -696,12 +717,6 @@ Common misconceptions are clarified in those sections:
- Passing (non-)fundamental types in the [C++ Core
Guideline](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-conventional).

- Assertions should not have side-effects.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

28304 -- yay! asserts everywhere! 🥳


- *Rationale*: Even though the source code is set to refuse to compile
with assertions disabled, having side-effects in assertions is unexpected and
makes the code harder to understand.

- If you use the `.h`, you must link the `.cpp`.

- *Rationale*: Include files define the interface for the code in implementation files. Including one but
Expand Down Expand Up @@ -894,12 +909,22 @@ 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
Expand Down Expand Up @@ -972,6 +997,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`.
Expand Down Expand Up @@ -1421,22 +1448,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.

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;
```
- Interface methods should not be overloaded.

- For friendliness to code generation tools, interface methods should not be
overloaded:
*Rationale*: consistency and friendliness to code generation tools.

Example:

Expand All @@ -1450,10 +1464,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++
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ class Chain
//! to be prepared to handle this by ignoring notifications about unknown
//! removed transactions and already added new transactions.
virtual void requestMempoolTransactions(Notifications& notifications) = 0;

//! Return true if an assumed-valid chain is in use.
virtual bool hasAssumedValidChain() = 0;
};

//! Interface to let node manage chain clients (wallets, or maybe tools for
Expand Down
11 changes: 6 additions & 5 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ class PeerManagerImpl final : public PeerManager


// All of the following cache a recent block, and are protected by m_most_recent_block_mutex
RecursiveMutex m_most_recent_block_mutex;
Mutex m_most_recent_block_mutex;
std::shared_ptr<const CBlock> m_most_recent_block GUARDED_BY(m_most_recent_block_mutex);
std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block GUARDED_BY(m_most_recent_block_mutex);
uint256 m_most_recent_block_hash GUARDED_BY(m_most_recent_block_mutex);
Expand Down Expand Up @@ -5676,15 +5676,16 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->GetId());

bool fGotBlockFromCache = false;
std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
{
LOCK(m_most_recent_block_mutex);
if (m_most_recent_block_hash == pBestIndex->GetBlockHash()) {
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::CMPCTBLOCK, *m_most_recent_compact_block));
fGotBlockFromCache = true;
cached_cmpctblock_msg = msgMaker.Make(NetMsgType::CMPCTBLOCK, *m_most_recent_compact_block);
}
}
if (!fGotBlockFromCache) {
if (cached_cmpctblock_msg.has_value()) {
m_connman.PushMessage(pto, std::move(cached_cmpctblock_msg.value()));
} else {
CBlock block;
bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
assert(ret);
Expand Down
5 changes: 5 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,11 @@ class ChainImpl : public Chain
notifications.transactionAddedToMempool(entry.GetSharedTx(), /* nAcceptTime = */ 0, /* mempool_sequence = */ 0);
}
}
bool hasAssumedValidChain() override
{
return Assert(m_node.chainman)->IsSnapshotActive();
}

NodeContext& m_node;
};
} // namespace
Expand Down
1 change: 0 additions & 1 deletion src/util/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ T&& inline_check_non_fatal(T&& val, const char* file, int line, const char* func
throw NonFatalCheckError(
format_internal_error(assertion, file, line, func, PACKAGE_BUGREPORT));
}

return std::forward<T>(val);
}

Expand Down
19 changes: 16 additions & 3 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5028,20 +5028,33 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf

if (tip_height && *tip_height != rescan_height)
{
if (chain.havePruned()) {
// Technically we could execute the code below in any case, but performing the
// `while` loop below can make startup very slow, so only check blocks on disk
// if necessary.
if (chain.havePruned() || chain.hasAssumedValidChain()) {
int block_height = *tip_height;
while (block_height > 0 && chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
--block_height;
}

if (rescan_height != block_height) {
// We can't rescan beyond non-pruned blocks, stop and throw an error.
// We can't rescan beyond blocks we don't have data for, stop and throw an error.
// This might happen if a user uses an old wallet within a pruned node
// or if they ran -disablewallet for a longer time, then decided to re-enable
// Exit early and print an error.
// It also may happen if an assumed-valid chain is in use and therefore not
// all block data is available.
// If a block is pruned after this check, we will load the wallet,
// but fail the rescan with a generic error.
error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");

error = chain.havePruned() ?
_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
strprintf(_(
"Error loading wallet. Wallet requires blocks to be downloaded, "
"and software does not currently support loading wallets while "
"blocks are being downloaded out of order when using assumeutxo "
"snapshots. Wallet should be able to load successfully after "
"node sync reaches height %s"), block_height);
return false;
}
}
Expand Down
3 changes: 1 addition & 2 deletions test/functional/interface_usdt_utxocache.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ def test_uncache(self):

# Create a transaction and invalidate it by changing the txid of the previous
# output to the coinbase txid of the block at height 1.
invalid_tx = self.wallet.create_self_transfer(
from_node=self.nodes[0])["tx"]
invalid_tx = self.wallet.create_self_transfer()["tx"]
invalid_tx.vin[0].prevout.hash = int(block_1_coinbase_txid, 16)

self.log.info("hooking into the utxocache:uncache tracepoint")
Expand Down
22 changes: 6 additions & 16 deletions test/lint/lint-assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,17 @@ def git_grep(params: [], error_msg: ""):


def main():
# PRE31-C (SEI CERT C Coding Standard):
# "Assertions should not contain assignments, increment, or decrement operators."
exit_code = git_grep([
"-E",
r"[^_]assert\(.*(\+\+|\-\-|[^=!<>]=[^=!<>]).*\);",
"--",
"*.cpp",
"*.h"
], "Assertions should not have side effects:")

# Macro CHECK_NONFATAL(condition) should be used instead of assert for RPC code, where it
# is undesirable to crash the whole program. See: src/util/check.h
# Aborting the whole process is undesirable for RPC code. So nonfatal
# checks should be used over assert. See: src/util/check.h
# src/rpc/server.cpp is excluded from this check since it's mostly meta-code.
exit_code |= git_grep([
exit_code = git_grep([
"-nE",
r"\<(A|a)ssert *\(.*\);",
r"\<(A|a)ss(ume|ert) *\(.*\);",
"--",
"src/rpc/",
"src/wallet/rpc*",
":(exclude)src/rpc/server.cpp"
], "CHECK_NONFATAL(condition) should be used instead of assert for RPC code.")
":(exclude)src/rpc/server.cpp",
], "CHECK_NONFATAL(condition) or NONFATAL_UNREACHABLE should be used instead of assert for RPC code.")

sys.exit(exit_code)

Expand Down
Loading