mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-12 21:52:53 +02:00
If a `static class` member is not inlined or `constexpr`, the linker will fail when attempting to ODR-use the constant (passing as `const T&`). These can be fixed by finding all member variables that are `const` qualified and inlining them with `constexpr`. There is a clang-tidy pull request that would lint these callsites: https://github.com/llvm/llvm-project/pull/162741 A script was used to modify these sites, however it cannot run as a scripted-diff because it uses clang-query and a build folder. The script only queries for integer and enumeration types, as other data members would have to be marked `constexpr` or `inline` from what I understand: https://en.cppreference.com/cpp/language/static#Constant_static_members Removing the ZMQ forward declaration was a clang-tidy lint. The script used to find these sites, LLM assisted: ``` set -uxo pipefail cd "$(git rev-parse --show-toplevel)" BUILD=${BUILD:-build} if [ ! -f "${BUILD}/compile_commands.json" ]; then echo "error: ${BUILD}/compile_commands.json not found. Run cmake -B ${BUILD} first." >&2 exit 1 fi if ! command -v clang-query >/dev/null; then echo "error: clang-query not on PATH. Install clang-tools." >&2 exit 1 fi if ! git diff --quiet || ! git diff --cached --quiet; then echo "error: working tree has uncommitted changes. Commit or stash first." >&2 exit 1 fi MATCHER='match varDecl(hasParent(cxxRecordDecl()), hasType(qualType(isConstQualified(), anyOf(hasCanonicalType(isInteger()), hasDeclaration(enumDecl())))), hasInitializer(expr()), unless(isConstexpr()), isExpansionInFileMatching("/src/"))' RAW=$(mktemp) trap 'rm -f "$RAW"' EXIT echo "Sweeping TUs (batched, may take a few minutes)..." >&2 find src -type d \( -name secp256k1 -o -name leveldb -o -name crc32c \ -o -name minisketch -o -name libmultiprocess -o -name ctaes \) -prune -o \ -name '*.cpp' -print0 \ | xargs -0 -n 50 clang-query -p "${BUILD}" \ -c 'set output diag' \ -c "${MATCHER}" \ >>"$RAW" || true ROOT=$(pwd) LOCS=$(grep -oE "${ROOT}/src/[^:]+:[0-9]+:[0-9]+:" "$RAW" \ | sed -E "s|^${ROOT}/||; s|:[0-9]+:$||" \ | sort -u) if [ -z "$LOCS" ]; then echo "no matches" >&2 exit 0 fi FILTERED="" while IFS=: read -r file line; do case "$file" in src/secp256k1/*|src/leveldb/*|src/crc32c/*|src/minisketch/*|src/ipc/libmultiprocess/*|src/crypto/ctaes/*) continue ;; src/tinyformat.h) continue ;; esac src=$(sed -n "${line}p" "$file") case "$src" in *inline*) continue ;; esac FILTERED+="${file}:${line}"$'\n' done <<<"$LOCS" FILTERED=$(printf '%s' "$FILTERED" | sed '/^$/d') if [ -z "$FILTERED" ]; then echo "no matches after filtering" >&2 exit 0 fi echo "Sites to rewrite ($(echo "$FILTERED" | wc -l)):" >&2 echo "$FILTERED" >&2 declare -A LINES while IFS=: read -r file line; do LINES[$file]+="${line} " done <<<"$FILTERED" for file in "${!LINES[@]}"; do args=() for line in ${LINES[$file]}; do args+=(-e "${line}s/static const /static constexpr /") done sed -i "${args[@]}" "$file" done echo >&2 echo "===== proposed diff =====" >&2 git --no-pager diff ```
119 lines
3.7 KiB
C++
119 lines
3.7 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-present The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_COMPRESSOR_H
|
|
#define BITCOIN_COMPRESSOR_H
|
|
|
|
#include <prevector.h>
|
|
#include <primitives/transaction.h>
|
|
#include <script/script.h>
|
|
#include <serialize.h>
|
|
#include <span.h>
|
|
|
|
/**
|
|
* This saves us from making many heap allocations when serializing
|
|
* and deserializing compressed scripts.
|
|
*
|
|
* This prevector size is determined by the largest .resize() in the
|
|
* CompressScript function. The largest compressed script format is a
|
|
* compressed public key, which is 33 bytes.
|
|
*/
|
|
using CompressedScript = prevector<33, unsigned char>;
|
|
|
|
|
|
bool CompressScript(const CScript& script, CompressedScript& out);
|
|
unsigned int GetSpecialScriptSize(unsigned int nSize);
|
|
bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in);
|
|
|
|
/**
|
|
* Compress amount.
|
|
*
|
|
* nAmount is of type uint64_t and thus cannot be negative. If you're passing in
|
|
* a CAmount (int64_t), make sure to properly handle the case where the amount
|
|
* is negative before calling CompressAmount(...).
|
|
*
|
|
* @pre Function defined only for 0 <= nAmount <= MAX_MONEY.
|
|
*/
|
|
uint64_t CompressAmount(uint64_t nAmount);
|
|
|
|
uint64_t DecompressAmount(uint64_t nAmount);
|
|
|
|
/** Compact serializer for scripts.
|
|
*
|
|
* It detects common cases and encodes them much more efficiently.
|
|
* 3 special cases are defined:
|
|
* * Pay to pubkey hash (encoded as 21 bytes)
|
|
* * Pay to script hash (encoded as 21 bytes)
|
|
* * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
|
|
*
|
|
* Other scripts up to 121 bytes require 1 byte + script length. Above
|
|
* that, scripts up to 16505 bytes require 2 bytes + script length.
|
|
*/
|
|
struct ScriptCompression
|
|
{
|
|
/**
|
|
* make this static for now (there are only 6 special scripts defined)
|
|
* this can potentially be extended together with a new version for
|
|
* transactions, in which case this value becomes dependent on version
|
|
* and nHeight of the enclosing transaction.
|
|
*/
|
|
static constexpr unsigned int nSpecialScripts{6};
|
|
|
|
template<typename Stream>
|
|
void Ser(Stream &s, const CScript& script) {
|
|
CompressedScript compr;
|
|
if (CompressScript(script, compr)) {
|
|
s << std::span{compr};
|
|
return;
|
|
}
|
|
unsigned int nSize = script.size() + nSpecialScripts;
|
|
s << VARINT(nSize);
|
|
s << std::span{script};
|
|
}
|
|
|
|
template<typename Stream>
|
|
void Unser(Stream &s, CScript& script) {
|
|
unsigned int nSize = 0;
|
|
s >> VARINT(nSize);
|
|
if (nSize < nSpecialScripts) {
|
|
CompressedScript vch(GetSpecialScriptSize(nSize), 0x00);
|
|
s >> std::span{vch};
|
|
DecompressScript(script, nSize, vch);
|
|
return;
|
|
}
|
|
nSize -= nSpecialScripts;
|
|
if (nSize > MAX_SCRIPT_SIZE) {
|
|
// Overly long script, replace with a short invalid one
|
|
script << OP_RETURN;
|
|
s.ignore(nSize);
|
|
} else {
|
|
script.resize(nSize);
|
|
s >> std::span{script};
|
|
}
|
|
}
|
|
};
|
|
|
|
struct AmountCompression
|
|
{
|
|
template<typename Stream, typename I> void Ser(Stream& s, I val)
|
|
{
|
|
s << VARINT(CompressAmount(val));
|
|
}
|
|
template<typename Stream, typename I> void Unser(Stream& s, I& val)
|
|
{
|
|
uint64_t v;
|
|
s >> VARINT(v);
|
|
val = DecompressAmount(v);
|
|
}
|
|
};
|
|
|
|
/** wrapper for CTxOut that provides a more compact serialization */
|
|
struct TxOutCompression
|
|
{
|
|
FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); }
|
|
};
|
|
|
|
#endif // BITCOIN_COMPRESSOR_H
|