Both are fine and this refactor doesn't change any behavior.
However, inline constexpr from C++17 will ensure each symbol has a single address
across all TU, making the release binary minimally smaller. (For me it is smaller by about 1kB)
Both are fine and this refactor doesn't change any behavior.
However, inline constexpr from C++17 will ensure each symbol has a single address
across all TU, making the release binary minimally smaller. (For me it is smaller by about 1kB)
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--006a51241073e994b41acfe9ec718e94-->
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35852.
<!--021abf342d371248e50ceaed478a90ca-->
See the guideline and AI policy for information on the review process.
| Type | Reviewers |
|---|---|
| ACK | l0rinc, rustaceanrob, hebasto |
| Stale ACK | fanquake |
If your review is incorrectly listed, please copy-paste <code><!--meta-tag:bot-skip--></code> into the comment that the bot should ignore.
<!--174a7506f384e20aa4161008e828411d-->
Reviewers, this pull request conflicts with the following ones:
maxfeerate wallet startup option by ismaelsadeeq)If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
<!--5faf32d7da4f0f540f40219e4f7537a3-->
Concept ACK - Could change static const here too? Not sure it's worth adding to the dev notes that inline constexpr is generally preferred (over static constexpr, static const etc)?
22 | @@ -23,7 +23,7 @@ 23 | namespace util { 24 | namespace detail { 25 | template <unsigned num_params> 26 | -constexpr static void CheckNumFormatSpecifiers(const char* str)
fac31e6 refactor: Manually use inline constexpr over constexpr static:
This is already implicitly inline, if we're changing it in a separate commit, we might as well remove the modifier, preferably as a first commit, which would allow us to fix the other case here in the scripted diff.
And maybe cover https://github.com/bitcoin/bitcoin/blob/fa5f29774872d18febc0df38831a6e45f3de69cc/src/net_permissions.h#L49 as well, similarly removing both qualifiers.
Sure, done both.
17 | /* A delay between shutdown pollings */ 18 | -static constexpr auto SHUTDOWN_POLLING_DELAY{200ms}; 19 | +inline constexpr auto SHUTDOWN_POLLING_DELAY{200ms}; 20 | 21 | /* AskPassphraseDialog -- Maximum passphrase length */ 22 | static const int MAX_PASSPHRASE_SIZE = 1024;
fac31e6 refactor: Manually use inline constexpr over constexpr static:
Maybe we could extend the PR to cover these as well (edit: #35852 (comment))
Sure, seems few enough to just include here as well.
24 | @@ -25,7 +25,7 @@ typedef struct secp256k1_context_struct secp256k1_context; 25 | typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey; 26 | 27 | /** Size of ECDH shared secrets. */ 28 | -constexpr static size_t ECDH_SECRET_SIZE = CSHA256::OUTPUT_SIZE; 29 | +inline constexpr size_t ECDH_SECRET_SIZE{CSHA256::OUTPUT_SIZE};
fac31e6 refactor: Manually use inline constexpr over constexpr static:
Could we rather extend the scripted diff to cover this?
<details><summary>extended scripted diff</summary>
sed -E -i 's/^(static constexpr|constexpr static)\>/inline constexpr/g' $( \
git grep -El '^(static constexpr|constexpr static)' -- \
'*.h' \
':(exclude)src/crc32c' \
':(exclude)src/ipc/libmultiprocess' \
':(exclude)src/minisketch' \
)
</details>
thx, done
ACK fac8a3a4a68bc7edabaaab6bfb113199792babb4
9 | @@ -10,7 +10,7 @@ 10 | * 11 | * Each line contains a BIP155 serialized (networkID, addr, port) tuple. 12 | */ 13 | -static const uint8_t chainparams_seed_main[] = { 14 | +inline constexpr uint8_t chainparams_seed_main[] = {
fa41c7d scripted-diff: Use inline constexpr over static const:
Regenerating the seeds would restore static const - could we update the generator as well?
<details><summary>update the fixed-seed generator</summary>
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -22,9 +22,9 @@ These files must consist of lines in the format
The output will be several data structures with the peers in binary format:
- static const uint8_t chainparams_seed_{main,signet,test,testnet4}[]={
+ inline constexpr uint8_t chainparams_seed_{main,signet,test,testnet4}[]={
...
}
These should be pasted into `src/chainparamsseeds.h`.
'''
@@ -137,7 +137,7 @@ def bip155_serialize(spec):
return r
def process_nodes(g, f, structname):
- g.write('static const uint8_t %s[] = {\n' % structname)
+ g.write('inline constexpr uint8_t %s[] = {\n' % structname)
for line in f:
comment = line.find('#')
if comment != -1:
</details>
Ah, right. The header is included only once, so it shouldn't matter, but I've added a commit with you as co-author.
Sorry about this, the generated files still differ, my mistake:
diff -u src/chainparamsseeds.h <(python3 contrib/seeds/generate-seeds.py contrib/seeds) | egrep '[+-]'
--- src/chainparamsseeds.h 2026-08-04 10:43:25
+++ /dev/fd/11 2026-08-04 10:58:07
@@ -10,7 +10,7 @@
-inline constexpr uint8_t chainparams_seed_main[] = {
+inline constexpr uint8_t chainparams_seed_main[]{
@@ -2072,7 +2072,7 @@
-inline constexpr uint8_t chainparams_seed_signet[] = {
+inline constexpr uint8_t chainparams_seed_signet[]{
@@ -2245,7 +2245,7 @@
-inline constexpr uint8_t chainparams_seed_test[] = {
+inline constexpr uint8_t chainparams_seed_test[]{
@@ -2429,7 +2429,7 @@
-inline constexpr uint8_t chainparams_seed_testnet4[] = {
+inline constexpr uint8_t chainparams_seed_testnet4[]{
Though I'm find with leaving as is, the next generation will automatically fix these.
122 | * A value > 0 means to do partial spend avoidance if the fee difference against a regular coin selection instance is in the range [0..value]. 123 | */ 124 | -static const CAmount DEFAULT_MAX_AVOIDPARTIALSPEND_FEE = 0; 125 | +inline constexpr CAmount DEFAULT_MAX_AVOIDPARTIALSPEND_FEE = 0; 126 | //! discourage APS fee higher than this amount 127 | constexpr CAmount HIGH_APS_FEE{COIN / 10000};
fa8f820 scripted-diff: Use inline constexpr over static constexpr:
The current scripted diff only covers static constexpr values - could we cover non-static cases as well?
sed -i -E 's/^constexpr .+ [A-Z0-9_]+(\[\])? ?[={]/inline &/' $( \
git grep -l '^constexpr ' -- '*.h' ':(exclude)src/minisketch' \
)
Hmm, this was already fixed in C++17, which adds the inline here. But I guess it can't hurt to be explicit here:
static out of muscle memory (Hopefully static inline constexpr will look ugly enough for them to remove either inline or static.)constexpr )Added a commit with your scripted-diff as co-author.
31 | @@ -32,7 +32,7 @@ 32 | * The maximum size of a serialized object in bytes or number of elements 33 | * (for eg vectors) when the size is encoded as CompactSize. 34 | */ 35 | -static constexpr uint64_t MAX_SIZE = 0x02000000; 36 | +inline constexpr uint64_t MAX_SIZE = 0x02000000;
fa8f820 scripted-diff: Use inline constexpr over static constexpr:
Could we cover SocketError and deserialize as well?
diff --git a/src/ipc/util.h b/src/ipc/util.h
index 6352f98174..03ce153417 100644
--- a/src/ipc/util.h
+++ b/src/ipc/util.h
@@ -25,7 +25,7 @@ namespace mp {
class EventLoop;
using ProcessId = int;
using SocketId = int;
-constexpr SocketId SocketError{-1};
+inline constexpr SocketId SocketError{-1};
using Stream = SocketId;
inline Stream MakeStream(EventLoop&, SocketId socket)
diff --git a/src/serialize.h b/src/serialize.h
index 4dbfe819b3..e6926b3579 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -49,7 +49,7 @@ inline constexpr unsigned int MAX_VECTOR_ALLOCATE = 5000000;
* is likely the only way to do so.
*/
struct deserialize_type {};
-constexpr deserialize_type deserialize {};
+inline constexpr deserialize_type deserialize {};
/*
* Lowest-level serialization and conversion.
sure, done
137 | -static constexpr uint8_t PSBT_SEPARATOR = 0x00; 138 | +inline constexpr uint8_t PSBT_SEPARATOR = 0x00; 139 | 140 | // BIP 174 does not specify a maximum file size, but we set a limit anyway 141 | // to prevent reading a stream indefinitely and running out of memory. 142 | const std::streamsize MAX_FILE_SIZE_PSBT = 100000000; // 100 MB
fa41c7d scripted-diff: Use inline constexpr over static const:
The scripted diff only covers static const values - could we cover non-static cases as well?
type='auto|int|unsigned int|uint32_t|std::streamsize'
sed -i -E "s/^const ($type) /inline constexpr \1 /" $( \
git grep -lE "^const ($type) " -- '*.h' \
)
sure, done
30 | //! -dns default 31 | -static const int DEFAULT_NAME_LOOKUP = true; 32 | +inline constexpr int DEFAULT_NAME_LOOKUP = true; 33 | 34 | /** Prefix for unix domain socket addresses (which are local filesystem paths) */ 35 | const std::string ADDR_PREFIX_UNIX = "unix:";
fa41c7d scripted-diff: Use inline constexpr over static const:
The scripted diff still leaves non-static std::string and fs::path objects - could we cover those as well?
sed -i -E 's/^const (fs::path|std::string) /inline &/' $( \
git grep -lE '^const (fs::path|std::string) ' -- '*.h' \
)
sure, done, but in a different commit and with a different script.
25 | @@ -26,18 +26,18 @@ 26 | * Maximum amount of time that a block timestamp is allowed to exceed the 27 | * current time before the block will be accepted. 28 | */ 29 | -static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; 30 | +inline constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
fa8f820 scripted-diff: Use inline constexpr over static constexpr:
These conflict directly with https://github.com/bitcoin/bitcoin/commit/861d3345fdbbf2ec8990a07e596312cc821ad3fd - after merge I'd appreciate a re-review.
What pull id is that? In any case, happy to let this one sit. A rebase should be trivial either way, as this pull is mostly scripted-diffs.
11 | @@ -12,7 +12,7 @@ 12 | typedef int64_t CAmount; 13 | 14 | /** The amount of satoshis in one BTC. */ 15 | -static constexpr CAmount COIN = 100000000; 16 | +inline constexpr CAmount COIN = 100000000;
heh, I read those as 1'0000'0000
22 | @@ -23,7 +23,7 @@ static constexpr CAmount COIN = 100000000; 23 | * critical; in unusual circumstances like a(nother) overflow bug that allowed 24 | * for the creation of coins out of thin air modification could lead to a fork. 25 | * */ 26 | -static constexpr CAmount MAX_MONEY = 21000000 * COIN; 27 | +inline constexpr CAmount MAX_MONEY = 21000000 * COIN;
Sure, done here and for a few others.
Maybe my dream will come true https://github.com/bitcoin/bitcoin/pull/29444
I left a few follow-ups for header values that retain internal linkage.
Since generate-seeds.py still emits static const, the PR needs another push anyway, so perhaps the other cases could be folded into the existing scripted diffs or added as separate commits.
tested ACK fa423e08734d25110b41287bcab398bb41f40b46
Checked every line manually, rebased and tested locally.
Those functions have no need to be static in every TU. Also, static
somewhat contradicts and overwrites the inline keyword.
So remove the static, and just keep constexpr (which implies inline).
Both are fine and this refactor shouldn't change any behavior.
However, inline constexpr will ensure each symbol has a single address
across all TU, making the release binary smaller.
Review note: In theory the script may also cover functions, but they
were handled in the prior commit, to remove the redundant inline for
them.
-BEGIN VERIFY SCRIPT-
sed --regexp-extended -i 's/^(static constexpr|constexpr static)\>/inline constexpr/g' $( \
git grep --extended-regexp -l '^(static constexpr|constexpr static)' -- \
'*.h' \
':(exclude)src/crc32c' \
':(exclude)src/ipc/libmultiprocess' \
':(exclude)src/minisketch' \
)
-END VERIFY SCRIPT-
This is required for the next commit.
Also, in a test, use `inline constexpr` for an `auto` type, which is
also needed for the next commit, which hard-codes a list of types for
conversion.
Both are fine and this refactor shouldn't change any behavior.
However, inline constexpr will ensure each symbol has a single address
across all TU, making the release binary smaller.
Note, a follow-up commit will deal with string literals (const char*)
and other static const, which can not be constexpr (e.g. std::vector).
-BEGIN VERIFY SCRIPT-
# Limit to types that can be constexpr
type='bool|CAmount|size_t|((signed|unsigned) )?int|u?int[0-9]+_t|std::array|DatabaseFormat|CFeeRate|std::streamsize'
sed -i --regexp-extended "s/^(static )?const (${type})\>/inline constexpr \2/" $( \
git grep -l --extended-regexp "^(static )?const " -- \
'*.h' \
':(exclude)src/leveldb' \
':(exclude)src/secp256k1' \
)
-END VERIFY SCRIPT-
Otherwise, the changes in the previous commit will be reverted when this
script regenerates the header.
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
This is needed for the next scripted-diff commit, which would otherwise
turn the const from `static const char*` into `inline const char*`.
Both are fine and this refactor shouldn't change any behavior.
However, inline const will ensure each symbol has a single address
across all TU, making the release binary smaller.
-BEGIN VERIFY SCRIPT-
# Replace `static const`
sed -i "s/^static const /inline const /" $( \
git grep -l "^static const " -- \
'*.h' \
':(exclude)src/leveldb' \
':(exclude)src/secp256k1' \
)
# Replace plain `const`
sed -i --regexp-extended 's/^const (\S+ \w+(\[\])? ?[={])/inline &/' $( \
git grep -l '^const ' -- \
'*.h' \
':(exclude)src/leveldb' \
':(exclude)src/secp256k1' \
)
-END VERIFY SCRIPT-
Both are identical since C++17 and this refactor shouldn't change any
behavior. The benefits are consistency and to be explicit, to avoid
confusion with the C++11/14 constexpr.
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
-BEGIN VERIFY SCRIPT-
sed -i --regexp-extended 's/^constexpr \S+ \w+(\[\])? ?[={]/inline &/' $( \
git grep -l '^constexpr ' -- \
'*.h' \
':(exclude)src/minisketch' \
)
-END VERIFY SCRIPT-
Suggested by l0rinc.
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
reACK fab74a0e922c6eb6501c3852ae08a24aade3850d
ACK fab74a0e922c6eb6501c3852ae08a24aade3850d
ACK fab74a0e922c6eb6501c3852ae08a24aade3850d, I have reviewed the code and it looks OK.