mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-12 05:32:22 +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 ```
238 lines
6.2 KiB
C++
238 lines
6.2 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_HASH_H
|
|
#define BITCOIN_HASH_H
|
|
|
|
#include <attributes.h>
|
|
#include <crypto/common.h>
|
|
#include <crypto/ripemd160.h>
|
|
#include <crypto/sha256.h>
|
|
#include <prevector.h>
|
|
#include <serialize.h>
|
|
#include <span.h>
|
|
#include <support/cleanse.h>
|
|
#include <uint256.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
/** A BIP32 chain code. Cleansed on destruction. */
|
|
class ChainCode : public base_blob<256> {
|
|
public:
|
|
constexpr ChainCode() = default;
|
|
constexpr explicit ChainCode(std::span<const unsigned char> vch) : base_blob<256>(vch) {}
|
|
constexpr explicit ChainCode(const base_blob<256>& b) : base_blob<256>(b) {}
|
|
~ChainCode() { memory_cleanse(data(), size()); }
|
|
};
|
|
|
|
/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */
|
|
class CHash256 {
|
|
private:
|
|
CSHA256 sha;
|
|
public:
|
|
static constexpr size_t OUTPUT_SIZE{CSHA256::OUTPUT_SIZE};
|
|
|
|
void Finalize(std::span<unsigned char> output) {
|
|
assert(output.size() == OUTPUT_SIZE);
|
|
unsigned char buf[CSHA256::OUTPUT_SIZE];
|
|
sha.Finalize(buf);
|
|
sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(output.data());
|
|
}
|
|
|
|
CHash256& Write(std::span<const unsigned char> input) {
|
|
sha.Write(input.data(), input.size());
|
|
return *this;
|
|
}
|
|
|
|
CHash256& Reset() {
|
|
sha.Reset();
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/** A hasher class for Bitcoin's 160-bit hash (SHA-256 + RIPEMD-160). */
|
|
class CHash160 {
|
|
private:
|
|
CSHA256 sha;
|
|
public:
|
|
static constexpr size_t OUTPUT_SIZE{CRIPEMD160::OUTPUT_SIZE};
|
|
|
|
void Finalize(std::span<unsigned char> output) {
|
|
assert(output.size() == OUTPUT_SIZE);
|
|
unsigned char buf[CSHA256::OUTPUT_SIZE];
|
|
sha.Finalize(buf);
|
|
CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(output.data());
|
|
}
|
|
|
|
CHash160& Write(std::span<const unsigned char> input) {
|
|
sha.Write(input.data(), input.size());
|
|
return *this;
|
|
}
|
|
|
|
CHash160& Reset() {
|
|
sha.Reset();
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/** Compute the 256-bit hash of an object. */
|
|
template<typename T>
|
|
inline uint256 Hash(const T& in1)
|
|
{
|
|
uint256 result;
|
|
CHash256().Write(MakeUCharSpan(in1)).Finalize(result);
|
|
return result;
|
|
}
|
|
|
|
/** Compute the 256-bit hash of the concatenation of two objects. */
|
|
template<typename T1, typename T2>
|
|
inline uint256 Hash(const T1& in1, const T2& in2) {
|
|
uint256 result;
|
|
CHash256().Write(MakeUCharSpan(in1)).Write(MakeUCharSpan(in2)).Finalize(result);
|
|
return result;
|
|
}
|
|
|
|
/** Compute the 160-bit hash an object. */
|
|
template<typename T1>
|
|
inline uint160 Hash160(const T1& in1)
|
|
{
|
|
uint160 result;
|
|
CHash160().Write(MakeUCharSpan(in1)).Finalize(result);
|
|
return result;
|
|
}
|
|
|
|
/** A writer stream (for serialization) that computes a 256-bit hash. */
|
|
class HashWriter
|
|
{
|
|
private:
|
|
CSHA256 ctx;
|
|
|
|
public:
|
|
void write(std::span<const std::byte> src)
|
|
{
|
|
ctx.Write(UCharCast(src.data()), src.size());
|
|
}
|
|
|
|
/** Compute the double-SHA256 hash of all data written to this object.
|
|
*
|
|
* Invalidates this object.
|
|
*/
|
|
uint256 GetHash() {
|
|
uint256 result;
|
|
ctx.Finalize(result.begin());
|
|
ctx.Reset().Write(result.begin(), CSHA256::OUTPUT_SIZE).Finalize(result.begin());
|
|
return result;
|
|
}
|
|
|
|
/** Compute the SHA256 hash of all data written to this object.
|
|
*
|
|
* Invalidates this object.
|
|
*/
|
|
uint256 GetSHA256() {
|
|
uint256 result;
|
|
ctx.Finalize(result.begin());
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns the first 64 bits from the resulting hash.
|
|
*/
|
|
inline uint64_t GetCheapHash() {
|
|
uint256 result = GetHash();
|
|
return ReadLE64(result.begin());
|
|
}
|
|
|
|
template <typename T>
|
|
HashWriter& operator<<(const T& obj)
|
|
{
|
|
::Serialize(*this, obj);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/** Reads data from an underlying stream, while hashing the read data. */
|
|
template <typename Source>
|
|
class HashVerifier : public HashWriter
|
|
{
|
|
private:
|
|
Source& m_source;
|
|
|
|
public:
|
|
explicit HashVerifier(Source& source LIFETIMEBOUND) : m_source{source} {}
|
|
|
|
void read(std::span<std::byte> dst)
|
|
{
|
|
m_source.read(dst);
|
|
this->write(dst);
|
|
}
|
|
|
|
void ignore(size_t num_bytes)
|
|
{
|
|
std::byte data[1024];
|
|
while (num_bytes > 0) {
|
|
size_t now = std::min<size_t>(num_bytes, 1024);
|
|
read({data, now});
|
|
num_bytes -= now;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
HashVerifier<Source>& operator>>(T&& obj)
|
|
{
|
|
::Unserialize(*this, obj);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/** Writes data to an underlying source stream, while hashing the written data. */
|
|
template <typename Source>
|
|
class HashedSourceWriter : public HashWriter
|
|
{
|
|
private:
|
|
Source& m_source;
|
|
|
|
public:
|
|
explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : HashWriter{}, m_source{source} {}
|
|
|
|
void write(std::span<const std::byte> src)
|
|
{
|
|
m_source.write(src);
|
|
HashWriter::write(src);
|
|
}
|
|
|
|
template <typename T>
|
|
HashedSourceWriter& operator<<(const T& obj)
|
|
{
|
|
::Serialize(*this, obj);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/** Single-SHA256 a 32-byte input (represented as uint256). */
|
|
[[nodiscard]] uint256 SHA256Uint256(const uint256& input);
|
|
|
|
unsigned int MurmurHash3(unsigned int nHashSeed, std::span<const unsigned char> vDataToHash);
|
|
|
|
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
|
|
|
|
/** Return a HashWriter primed for tagged hashes (as specified in BIP 340).
|
|
*
|
|
* The returned object will have SHA256(tag) written to it twice (= 64 bytes).
|
|
* A tagged hash can be computed by feeding the message into this object, and
|
|
* then calling HashWriter::GetSHA256().
|
|
*/
|
|
HashWriter TaggedHash(const std::string& tag);
|
|
|
|
/** Compute the 160-bit RIPEMD-160 hash of an array. */
|
|
inline uint160 RIPEMD160(std::span<const unsigned char> data)
|
|
{
|
|
uint160 result;
|
|
CRIPEMD160().Write(data.data(), data.size()).Finalize(result.begin());
|
|
return result;
|
|
}
|
|
|
|
#endif // BITCOIN_HASH_H
|