100 Commits
Author SHA1 Message Date
l0rinc ce2a984ee3 test: cleanup, use HasReason in threadpool_tests.cpp 2026-02-26 11:28:55 -03:00
l0rinc 9ff1e82e7d test: cleanup, block threads via semaphore instead of shared_future
No-behavior change.
2026-02-24 19:18:31 -03:00
Lőrinc 3281824ecf fuzz: prevent invalid FRESH entries and surface BatchWrite errors
Modify fuzzer logic to avoid setting `FRESH` for an outpoint that already exists unspent in the parent view, and ensure `FRESH` implies `DIRTY`.
This keeps cursor invariants realistic and lets `BatchWrite` failures expose real bugs without resetting state.
2026-02-23 15:58:24 +01:00
Lőrinc 780f460635 fuzz: avoid invalid AddCoin overwrites
The coins view fuzzer can call `AddCoin` with `possible_overwrite=false` for an outpoint that already exists unspent in the view, which violates the `AddCoin` caller contract.
Derive `possible_overwrite` from `PeekCoin` so `possible_overwrite=false` is only used when the outpoint is absent.
This matches the approach used by the `coinscache_sim` fuzzer, which derives the overwrite flag from simulated state.
2026-02-23 15:58:23 +01:00
Lőrinc d7e0d510f2 fuzz: make AddCoins query view for overwrites
In validation, `AddCoins(check_for_overwrite=false)` is only used after BIP30 has already ensured the transaction does not overwrite any unspent outputs in the UTXO view.
The coins view fuzz target can call `AddCoins` with arbitrary txids, so using the `check_for_overwrite=false` fast path on non-coinbase transactions may violate the `AddCoin` caller contract and trigger logic errors.
Only use `check_for_overwrite=false` when we have first confirmed that none of the outputs are currently unspent.
Otherwise, fall back to `check_for_overwrite=true` so `AddCoins` determines overwrites via the view.
2026-02-23 15:58:07 +01:00
b8fa6f0f70 util: introduce TrySub to prevent unsigned underflow
Introduce `TrySub(T&, U)` which subtracts an unsigned integral `U` from an unsigned integral `T`, returning `false` on underflow.
Use with `Assume(TrySub(...))` at coins cache accounting decrement sites so invariant violations fail immediately rather than silently wrapping.

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
Co-authored-by: Pieter Wuille <pieter@wuille.net>
2026-02-23 15:56:25 +01:00
Lőrinc 45133c589a doc: clarify git range-diff add/delete output
When `git range-diff` cannot match a commit between two versions of a branch, it shows the old commit as removed (`<`) and the new commit as added (`>`), and it does not show the patch contents.
This output is easy to misread as "no code changes" because the diff for that commit is effectively empty.
It really means the commits were considered unrelated and the new commit should be reviewed from scratch.
This is analogous to rename detection in `git diff`: if similarity is too low, a rename shows up as delete+add.

Example (exact SHAs from PR #34320):
    B=ff338fdb53a66ab40a36e1277e7371941fc89840; A=dd76338a57b9b1169ac27f7b783d6d0d4c6e38ab; git fetch upstream $B $A
    git range-diff 0ca4295f2e5f4443a1f8b3bae7cba0f6c054276f..$B 139aa4b27e4839291c83a04dcd1649c5595814ca..$A

This produced output like:
    1:  4b32181dbb < -:  ---------- test: add `HaveInputs` call-path unit tests
    -:  ---------- > 1:  277c57f0c5 test: add `HaveInputs` call-path unit tests

Even though the subject matches, the first commit had no matching diff shown.
That should be treated as "unmatched" rather than "unchanged".

If you expected a match, try increasing the creation factor so `git range-diff` searches harder:
    git range-diff --creation-factor=95 <old_range> <new_range>
2026-02-23 13:36:27 +01:00
Lőrincandsedited ce8b692897 Add functional test exercising tx downloadman recently confirmed filter
This documents existing behaviour before the change in the following
commit: The bloom filter maintained by the txdownload manager tracks
recently confirmed transasctions even during ibd. If a peer sends an INV
once IBD is over it does not re-request them.

Co-authored-by: sedited <seb.kung@gmail.com>
2026-02-22 13:03:52 +01:00
LőrincandAndrew Toth 7e52b1b945 fuzz: call EmplaceCoinInternalDANGER as well in SimulationTest
Adds test coverage by randomly calling `EmplaceCoinInternalDANGER` in `SimulationTest` to verify it remains correct as we modify it in a future commit.

Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
2026-02-08 07:56:28 +01:00
LőrincandMarcoFalke eb510f8678 ci: fail fast in test-each-commit script
Pass `--failfast` to the functional test runner in `.github/ci-test-each-commit-exec.py`.
Stop after the first failure to surface the root cause sooner and keep logs readable when testing ancestor commits.

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2026-02-04 20:11:02 +01:00
LőrincandMarcoFalke 04c4d71008 ci: remove commit count limit from test-each-commit
Extend `test-each-commit` to run on every non-head pull request commit.
The PR tip is excluded because it is already covered by other CI jobs.
Runner was changed to a performant cirrus runner.

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2026-02-04 20:11:02 +01:00
LőrincandAntoine Poinsot 8c03318387 consensus/doc: explain GetValueOut() precondition
`Consensus::CheckTxInputs` calls `tx.GetValueOut()` and assumes output-range checks already ran.
Document the mempool and block validation call paths where this is guaranteed.

Co-authored-by: Antoine Poinsot <darosior@protonmail.com>
2026-02-02 19:32:14 +01:00
Lőrinc 82ef92c8d0 consensus/doc: explain unreachable bad-txns-fee-outofrange check
After the previous conditions were validated, document why `bad-txns-fee-outofrange` is unreachable once `nValueIn` and `value_out` are `MoneyRange` and `nValueIn >= value_out`.

Although unreachable, keep the check itself in place (instead of removing) as it's part of consensus-critical code; the comment serves as a proof for future refactors.

Inspired by b-c-cov coverage reports:
* "bad-txns-fee-outofrange" - https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/consensus/tx_verify.cpp.gcov.html#L200
2026-02-02 19:32:13 +01:00
Lőrinc 232a2bce90 consensus/test: add out-of-range output unit tests for CTransaction::GetValueOut
Inspired by b-c-cov coverage reports:
* "GetValueOut: value out of range" - https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/primitives/transaction.cpp.gcov.html#L103
2026-01-31 21:10:36 +01:00
Lőrinc aa87aae14f consensus/test: add MoneyRange unit tests for CheckTxInputs
Add minimal unit tests exercising `Consensus::CheckTxInputs` reject reasons for coinbase maturity (`bad-txns-premature-spend-of-coinbase`), input value range failures (`bad-txns-inputvalues-outofrange`), and for `nValueIn < value_out` (`bad-txns-in-belowout`).

Inspired by b-c-cov coverage reports:
* "bad-txns-premature-spend-of-coinbase" - https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/consensus/tx_verify.cpp.gcov.html#L180
* "bad-txns-inputvalues-outofrange" - https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/consensus/tx_verify.cpp.gcov.html#L187
* "bad-txns-in-belowout" - https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/consensus/tx_verify.cpp.gcov.html#L193
2026-01-31 21:10:33 +01:00
LőrincandCarlo Antinarella e67a676df9 fix: uptime RPC returns 0 on first call
The monotonic uptime fix (#34328) used a function-local static for `g_startup_time`, which was initialized on first `GetUptime()` call instead of app startup time.
This caused the first `uptime()` call to always return 0.

Move `g_startup_time` to namespace scope so it initializes at program start, ensuring the first call returns actual elapsed time. Note that we don't need to make it `static` anymore because it is just used in this single translation unit.

Test was updated to simulate some work before the first call.

Co-authored-by: Carlo Antinarella <carloantinarella@users.noreply.github.com>
2026-01-29 19:53:48 +01:00
LőrincandMartin Zumsande eeb4d28148 validation: follow-up nits for lock-free IsInitialBlockDownload()
Add `AssertLockHeld(cs_main)` to `ChainstateManager::UpdateIBDStatus()` given `EXCLUSIVE_LOCKS_REQUIRED(cs_main)`.
Fix outdated comment about constness of `ChainstateManager::IsInitialBlockDownload()` (build passes without it).
And since we're touching it, we might as well mark `ChainstateManager::IsInitialBlockDownload()` as `noexcept` now.

Follow-up to #34253.

Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
2026-01-29 12:29:37 +01:00
Lőrinc a73a3ec553 doc: fix invalid arg name hints for bugprone validation
The extra leading `=` or missing trailing `=` prevented clang-tidy's `bugprone-argument-comment` check from validating the parameter name, as it only matches comments formatted strictly as `/*arg=*/` (see https://clang.llvm.org/extra/clang-tidy/checks/bugprone/argument-comment.html).
2026-01-24 00:44:22 +01:00
Lőrincandw0xlt 8b9d30e3fa bench/test: clarify merkle bench and witness test intent
Follow-up to bitcoin/bitcoin#32497.

Clarify why the witness merkle test uses an odd leaf count (it exercises leaf duplication in `ComputeMerkleRoot()`), and make the coinbase witness hash initialization explicit.

Also simplify the leaf-copy loop in the MerkleRoot benchmark for readability.

No production code is changed in this follow-up, for simplicity and safety.

Co-authored-by: w0xlt <94266259+w0xlt@users.noreply.github.com>
2026-01-21 23:29:46 +01:00
LőrincandMarcoFalke 477c5504e0 coins: replace std::distance with unambiguous pointer subtraction
Avoid calling `std::distance` on null pointers in `PoolResource::AllocateChunk`.
 Compute remaining bytes with `m_available_memory_end - m_available_memory_it` instead, which is well-defined to be `0` when both are `nullptr`.

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2026-01-20 15:35:19 +01:00
Lőrinc 969c840db5 log,blocks: avoid ComputeTotalSize and GetHash work when logging is disabled
`PartiallyDownloadedBlock::FillBlock()` computed the block header hash and summed missing transaction sizes for debug logging unconditionally, including when cmpctblock debug logging is disabled.

Guard the debug-only hash and size computations with `LogAcceptCategory`.
Since `txn_available` is invalidated after the first loop (needed for efficient moving), we compute `tx_missing_size` by iterating `vtx_missing` directly. This is safe because the later `tx_missing_offset` check guarantees `vtx_missing` was fully consumed during reconstruction.

Use `block.GetHash()` instead of `header.GetHash()`, since header is cleared before logging.

No behavior change when debug logging is enabled: the reported counts, hashes, and byte totals remain the same.
2026-01-19 20:20:13 +01:00
Lőrinc babfda332b log,net: avoid ComputeTotalSize when logging is disabled
`PeerManagerImpl::SendBlockTransactions()` computed the total byte size of requested transactions for a debug log line by calling `ComputeTotalSize()` in a tight loop, triggering serialization even when debug logging is off.

Guard the size accumulation with `LogAcceptCategory` so the serialization work only happens when the log line can be emitted.

No behavior change when debug logging is enabled: the reported block hash, transaction count, and byte totals are the same.
The bounds checks still run unconditionally; the debug-only loop iterates the already-validated response contents.

Separating debug-only work from the critical path reduces risk and favors the performance-critical non-debug case.
This also narrows the racy scope of when logging is toggled from another thread.
2026-01-19 20:20:13 +01:00
Lőrincandmaflcko 1658b8f82b refactor: rename CTransaction::GetTotalSize to signal that it's not cached
Transaction hashes are cached, it may not be intuitive that their sizes are actually recalculated every time.
This is done before the other refactors to clarify why we want to avoid calling this method;

Co-authored-by: maflcko <6399679+maflcko@users.noreply.github.com>
2026-01-19 20:20:13 +01:00
LőrincandMarcoFalke 14f99cfe53 rpc: make uptime monotonic across NTP jumps
Compute `uptime` from `SteadyClock` so it is unaffected by system time changes after startup.

Derive GUI startup time by subtracting the monotonic uptime from the wall clock time.

Add a functional test covering a large `setmocktime` jump.

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2026-01-19 17:08:08 +01:00
Lőrinc a9440b1595 util: add TicksSeconds
Add a helper to convert durations to integer seconds.
2026-01-19 12:37:01 +01:00
LőrincandVasil Dimov b39291f4cd doc: fix -logips description to clarify that non-debug logs can also contain IP addresses
IP addresses controlled by `-logips` are also logged in non-debug outputs:
* LogInfo "outbound peer headers chain has insufficient work" -> src/net_processing.cpp:2909
* LogInfo "Outbound peer has old chain" -> src/net_processing.cpp:5301
* LogInfo "Peer is stalling block download" -> src/net_processing.cpp:6057
* LogInfo "Timeout downloading block" -> src/net_processing.cpp:6076
* LogInfo "Timeout downloading headers" -> src/net_processing.cpp:6092
* LogInfo "Timeout downloading headers from noban peer, not …" -> src/net_processing.cpp:6096
* LogError "Cannot load block from disk" -> src/net_processing.cpp:2386 and src/net_processing.cpp:2399

Co-authored-by: Vasil Dimov <vd@freebsd.org>
2026-01-14 12:18:12 +01:00
c7028d3368 init: log that additional logs may contain privacy-sensitive information
Log an info message when any `-debug` categories are enabled, noting they may contain privacy-sensitive information (e.g. transaction IDs) and should not be shared publicly.

Co-authored-by: Vasil Dimov <vd@FreeBSD.org>
Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2026-01-14 12:18:11 +01:00
LőrincandVasil Dimov 31b771a942 net: move privatebroadcast logs to debug category
Private broadcast is a privacy feature, and users may share `debug.log` with support.
Unconditional log messages that mention private broadcast and/or include (w)txids can leak which transactions a user originated.

Move private broadcast event logging from `LogInfo()` to `LogDebug(BCLog::PRIVBROADCAST, ...)` so it is only emitted when debug logging is enabled, and drop the hardcoded "[privatebroadcast]" prefixes.
Keep warnings at the default log level without (w)txids, detailed context remains available under `-debug=privatebroadcast`.

Co-authored-by: Vasil Dimov <vd@FreeBSD.org>
2026-01-14 10:34:01 +01:00
Lőrinc 2f5b1c5f80 psbt: Fix PSBTInputSignedAndVerified bounds assert
The previous `assert` used `>=`, allowing `input_index == psbt.inputs.size()` and out-of-bounds access in `psbt.inputs[input_index]`.

Found during review: https://github.com/bitcoin/bitcoin/pull/31650#discussion_r2685892867
2026-01-13 12:58:53 +01:00
557b41a38c validation: make IsInitialBlockDownload() lock-free
`ChainstateManager::IsInitialBlockDownload()` is queried on hot paths and previously acquired `cs_main` internally, contributing to lock contention.

Cache the IBD status in `m_cached_is_ibd`, and introduce `ChainstateManager::UpdateIBDStatus()` to latch it once block loading has finished and the current chain tip has enough work and is recent.
Call the updater after tip updates and after `ImportBlocks()` completes.

Since `IsInitialBlockDownload()` no longer updates the cache, drop `mutable` from `m_cached_is_ibd` and only update it from `UpdateIBDStatus()` under `cs_main`.

Update the new unit test to showcase the new `UpdateIBDStatus()`.

Co-authored-by: Patrick Strateman <patrick.strateman@gmail.com>
Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
2026-01-12 16:57:20 +01:00
b9c0ab3b75 chain: add CChain::IsTipRecent helper
Factor the chain tip work/recency check out of `ChainstateManager::IsInitialBlockDownload()` into a reusable `CChain::IsTipRecent()` helper, and annotate it as requiring `cs_main` since it's reading mutable state.

Also introduce a local `chainman_ref` in the kernel import-blocks wrapper to reduce repetition and keep follow-up diffs small.

`IsInitialBlockDownload` returns were also unified to make the followup move clean.

Co-authored-by: Patrick Strateman <patrick.strateman@gmail.com>
Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
2026-01-12 16:56:01 +01:00
Lőrinc 8d531c6210 validation: invert m_cached_finished_ibd to m_cached_is_ibd
Rename and invert the internal IBD latch so the cached value directly matches `IsInitialBlockDownload()` (true while in IBD, then latched to false).

This is a behavior-preserving refactor to avoid double negatives.
2026-01-12 16:54:11 +01:00
Lőrinc 8be54e3b19 test: cover IBD exit conditions
Add a unit test that exercises the `IsInitialBlockDownload()` decision matrix by varying the cached latch, `BlockManager::LoadingBlocks()`, and tip work/recency inputs.

This documents the current latching behavior and provides a baseline for later refactors.
2026-01-12 16:48:09 +01:00
Lőrinc ee1e40f580 txdb: assert CCoinsViewDB::GetCoin only returns unspent coins
The chainstate UTXO database only stores unspent outputs; spent entries are removed.

Assert after reading a `Coin` so corruption or misuse cannot propagate a spent coin through the `GetCoin()` interface.
2026-01-06 12:16:45 +01:00
7099e93d0a refactor: rename FlushStateMode::ALWAYS to FORCE_FLUSH
This prepares the addition of `FORCE_SYNC`.

`empty_cache` in `FlushStateToDisk` was moved up to be reusable and `FlushStateMode::FORCE_FLUSH` was used as a placeholder before we properly split the two new states.
`log_utxocache_flush.py` was regenerated and the alignment adjusted for the wider `FlushStateMode` values.

Co-authored-by: Pieter Wuille <pieter@wuille.net>
Co-authored-by: optout <13562139+optout21@users.noreply.github.com>
2026-01-03 12:43:57 +01:00
Lőrinc 658d38106a policy: remove constant parameter from IsWellFormedPackage
`IsWellFormedPackage()` already claims: "parents must appear before children."
In practice the `require_sorted` argument was always passed as `true`, making the false-path dead code.
It was introduced that way from the beginning in https://github.com/bitcoin/bitcoin/pull/28758/files#diff-f30090b30c9489972ee3f1181c302cf3a484bb890bade0fd7c9ca92ea8d347f6R79.

Remove the unused parameter, updating callers/tests.
2025-12-29 21:26:35 +01:00
3dd815f048 validation: pre-reserve leaves to prevent reallocs with odd vtx count
`ComputeMerkleRoot` duplicates the last hash when the input size is odd. If the caller provides a `std::vector` whose capacity equals its size, that extra `push_back` forces a reallocation, doubling its capacity (allocating 3x the necessary memory).

This affects roughly half of the created blocks (those with odd transaction counts), causing unnecessary memory fragmentation during every block validation.

Fix this by pre-reserving the vector capacity to account for the odd-count duplication. The expression `(size + 1) & ~1ULL` adds 1 to the size and clears the last bit, effectively rounding up to the next even number. This syntax produces optimal assembly across x86/ARM and 32/64-bit platforms for gcc/clang, see https://godbolt.org/z/xzscoq7nv.

Also switch from `resize` to `reserve` + `push_back` to eliminate the default construction of `uint256` objects that are immediately overwritten.

> ./build/bin/bench_bitcoin -filter='MerkleRoot.*' -min-time=1000

|             ns/leaf |              leaf/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|               43.73 |       22,867,350.51 |    0.0% |      1.10 | `MerkleRoot`
|               44.17 |       22,640,349.14 |    0.0% |      1.10 | `MerkleRootWithMutation`

Massif memory measurements after show 0.8 MB peak memory usage

    KB
801.4^ #
     | #
     | #
     | #
     | #
     | #
     | #
     | #                                                         :::::@:::::@:
     | #:::@@@::@:::::::::::::::@::@:@:::@@:::::::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
     | #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
   0 +----------------------------------------------------------------------->s
     0                                                                   227.5

and the stacks don't show reallocs anymore:
96.37% (790,809B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->35.10% (288,064B) 0x2234AF: allocate (new_allocator.h:151)
| ->35.10% (288,064B) 0x2234AF: allocate (allocator.h:203)
|   ->35.10% (288,064B) 0x2234AF: allocate (alloc_traits.h:614)
|     ->35.10% (288,064B) 0x2234AF: _M_allocate (stl_vector.h:387)
|       ->35.10% (288,064B) 0x2234AF: reserve (vector.tcc:79)
|         ->35.10% (288,064B) 0x2234AF: ToMerkleLeaves<std::vector<uint256>, MerkleRoot(ankerl::nanobench::Bench&)::<lambda()>::<lambda(bool, const auto:46&)> > (merkle.h:19)
|           ->35.10% (288,064B) 0x2234AF: operator() (merkle_root.cpp:25)
|             ->35.10% (288,064B) 0x2234AF: ankerl::nanobench::Bench& ankerl::nanobench::Bench::run<MerkleRoot(ankerl::nanobench::Bench&)::{lambda()

Co-authored-by: optout21 <13562139+optout21@users.noreply.github.com>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
2025-12-23 09:44:59 +02:00
LőrincandHodlinator 7fd47e0e56 bench: make MerkleRoot benchmark more representative
Two versions are run now, one with the mutation calculations, the other without.
To avoid unwanted compiler optimizations, we assert the expected hash, which should inhibit aggressive optimization.

To make the benchmark more similar to production `ComputeMerkleRoot` call sites, the input leaves-copying is made explicit before each run.

> ./build/bin/bench_bitcoin -filter='MerkleRoot.*' -min-time=1000

|             ns/leaf |              leaf/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|               44.18 |       22,634,858.70 |    0.0% |      1.10 | `MerkleRoot`
|               44.66 |       22,390,601.03 |    0.0% |      1.10 | `MerkleRootWithMutation`

Massif memory measurements show the excessive memory reservations:

    MB
1.332^        :
     | #      :
     | #      :
     | #      :
     | #      :
     | #    @ :
     | #    @ :
     | #    @ :
     | #    @ :
     | #    @ :
     | #    @ :
     | #    @ :
     | #    @ :
     | #::::@::::::::::::::::::::::::::::::::::::::::::::::::::::::@:::::@::::
     | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@::::
     | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@::::
     | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@::::
     | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@::::
     | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@::::
     | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@::::
   0 +----------------------------------------------------------------------->s
     0                                                                   226.2

showing the reallocations clearly in the stacks:
97.87% (1,366,841B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->41.25% (576,064B) 0x969717: allocate (new_allocator.h:151)
| ->41.25% (576,064B) 0x969717: allocate (allocator.h:203)
|   ->41.25% (576,064B) 0x969717: allocate (alloc_traits.h:614)
|     ->41.25% (576,064B) 0x969717: _M_allocate (stl_vector.h:387)
|       ->41.25% (576,064B) 0x969717: _M_realloc_append<const uint256&> (vector.tcc:572)
|         ->41.25% (576,064B) 0x969717: push_back (stl_vector.h:1427)
|           ->41.25% (576,064B) 0x969717: ComputeMerkleRoot(std::vector<uint256, std::allocator<uint256> >, bool*) (merkle.cpp:55)
|             ->41.25% (576,064B) 0x2235A7: operator() (merkle_root.cpp:31)
|               ->41.25% (576,064B) 0x2235A7: ankerl::nanobench::Bench& ankerl::nanobench::Bench::run<MerkleRoot(ankerl::nanobench::Bench&)::{lambda()

Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
2025-12-23 09:44:57 +02:00
Lőrinc 1e94e562f7 refactor: enable readability-container-contains clang-tidy rule
Replace the last few instances of `.count() != 0` and `.count() == 0` and `.count()` patterns with the more expressive C++20 `.contains()` method:

* `std::set<std::string>` in `getblocktemplate` RPC;
* `std::map<std::string, ...>` in `transaction_tests`;
* other bare `std::unordered_set` and `std::map` count calls.

With no remaining violations, enable the `readability-container-contains`
clang-tidy check to prevent future regressions.
2025-12-18 22:38:02 +01:00
Lőrinc fd9f1accbd Fix compilation for old Boost versions
Fixes https://github.com/bitcoin/bitcoin/issues/34101 by reverting `boost::multi_index::contains` calls only available in Boost 1.78.0
2025-12-18 22:38:02 +01:00
Lőrinc 85314dc0bf kernel: revert accidentally removed copyright header
See:
https://github.com/bitcoin/bitcoin/commit/7990463b1059ba5fc4ebe37fd1105a9e168ae20d?diff=split#diff-04e685224f1ac5bfd91d47d8d7528a2e44f94fab5535d4b6b5af79b5a13aeb93L1-L12
2025-12-18 16:07:31 +01:00
Lőrinc f0a2183108 test: adjust ComputeMerkleRoot tests
Update the integer fuzz test to move the vector into `ComputeMerkleRoot`, matching production usage patterns and avoiding unnecessary copies.

Update `merkle_test_BlockWitness` to use an odd number of transactions to ensure the test covers the scenario where leaf duplication occurs. Also switch to `GetWitnessHash` to match `BlockWitnessMerkleRoot` semantics.
The manual vector setup retains the exact-size `resize` to explicitly verify the behavior against the calculated root.
2025-12-11 14:47:48 +01:00
Lőrincandsedited 7e9de20c0c fuzz: exercise ComputeMerkleRoot without mutated parameter
Co-authored-by: sedited <seb.kung@gmail.com>
2025-12-11 12:47:18 +01:00
LőrincandRyan Ofsky 6eb5ba5691 refactor: extract shared SipHash state into SipHashState
Split the repeated `SipHash` v[0..3] initialization into a small `SipHashState` helper that is used by both `CSipHasher` and `PresaltedSipHasher`.

Added explanatory comments to clarify behavior, documenting the equivalence of `PresaltedSipHasher` `operator()` overloads to `CSipHasher` usage.

Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
2025-12-09 17:17:47 +01:00
Lőrinc 118d22ddb4 optimization: cache PresaltedSipHasher in CBlockHeaderAndShortTxIDs
Replaces separate `shorttxidk0`/`shorttxidk1` members with a cached `PresaltedSipHasher`, so `GetShortID()` reuses the precomputed `SipHash` state instead of rebuilding it on every call.

`CBlockHeaderAndShortTxIDs` was never intended to be used before `FillShortTxIDSelector()` runs; doing so already relied on indeterminate salt values.
The new `Assert(m_hasher)` just makes this invariant explicit and fails fast if the object is used in an uninitialized state.
2025-12-09 17:16:17 +01:00
Lőrinc 9ca52a4cbe optimization: migrate SipHashUint256 to PresaltedSipHasher
Replaces standalone `SipHashUint256` with an `operator()` overload in `PresaltedSipHasher`.
Updates all hasher classes (`SaltedUint256Hasher`, `SaltedTxidHasher`, `SaltedWtxidHasher`) to use `PresaltedSipHasher` internally, enabling the same constant-state caching optimization while keeping behavior unchanged.

Benchmark was also adjusted to cache the salting part.
2025-12-09 17:16:15 +01:00
Lőrincandsipa ec11b9fede optimization: introduce PresaltedSipHasher for repeated hashing
Replaces the `SipHashUint256Extra` function with the `PresaltedSipHasher` class that caches the constant-salted state (v[0-3] after XORing with keys).
This avoids redundant XOR operations when hashing multiple values with the same keys, benefiting use cases like `SaltedOutpointHasher`.

This essentially brings the precalculations in the `CSipHasher` constructor to the `uint256`-specialized SipHash implementation.

> cmake -B build -DBUILD_BENCH=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) && build/src/bench/bench_bitcoin -filter='SaltedOutpointHasherBench.*' -min-time=10000

> C++ compiler .......................... AppleClang 16.0.0.16000026

|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|               57.27 |       17,462,299.19 |    0.1% |     11.02 | `SaltedOutpointHasherBench_create_set`
|               11.24 |       88,997,888.48 |    0.3% |     11.04 | `SaltedOutpointHasherBench_hash`
|               13.91 |       71,902,014.20 |    0.2% |     11.01 | `SaltedOutpointHasherBench_match`
|               13.29 |       75,230,390.31 |    0.1% |     11.00 | `SaltedOutpointHasherBench_mismatch`

compared to master:
create_set - 17,462,299.19/17,065,922.04 - 2.3% faster
hash       - 88,997,888.48/83,576,684.83 - 6.4% faster
match      - 71,902,014.20/68,985,850.12 - 4.2% faster
mismatch   - 75,230,390.31/71,942,033.47 - 4.5% faster

> C++ compiler .......................... GNU 13.3.0

|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|              135.38 |        7,386,349.49 |    0.0% |        1,078.19 |          486.16 |  2.218 |         119.56 |    1.1% |     11.00 | `SaltedOutpointHasherBench_create_set`
|               23.67 |       42,254,558.08 |    0.0% |          247.01 |           85.01 |  2.906 |           4.00 |    0.0% |     11.00 | `SaltedOutpointHasherBench_hash`
|               58.95 |       16,962,220.14 |    0.1% |          446.55 |          211.74 |  2.109 |          20.86 |    1.4% |     11.01 | `SaltedOutpointHasherBench_match`
|               76.98 |       12,991,047.69 |    0.1% |          548.93 |          276.50 |  1.985 |          20.25 |    2.3% |     10.72 | `SaltedOutpointHasherBench_mismatch`

compared to master:
create_set -  7,386,349.49/7,312,133.16  - 1% faster
hash       - 42,254,558.08/41,978,882.62 - 0.6% faster
match      - 16,962,220.14/16,549,695.42 - 2.4% faster
mismatch   - 12,991,047.69/12,713,595.35 - 2% faster

Co-authored-by: sipa <pieter@wuille.net>
2025-12-09 17:13:44 +01:00
Lőrinc 20330548cf refactor: extract SipHash C0-C3 constants to class scope
Moves the `SipHash` initialization constants (C0-C3) from magic numbers to named static constexpr members of `CSipHasher`.
2025-12-09 17:03:18 +01:00
Lőrinc 9f9eb7fbc0 test: rename k1/k2 to k0/k1 in SipHash consistency tests
Aligns test variable naming with the `k0`/`k1` convention used consistently throughout the codebase for `SipHash` keys.
Also splits the single-param `SipHash` test from the one with extra, for clarity.
2025-12-09 17:03:18 +01:00
d9319b06cf refactor: unify container presence checks - non-trivial counts
The changes made here were:

| From              | To               |
|-------------------|------------------|
| `m.count(k) == 1` | `m.contains(k)`  |
| `m.count(k) == 0` | `!m.contains(k)` |
| `m.count(k) != 1` | `!m.contains(k)` |
| `m.count(k) < 1`  | `!m.contains(k)` |

* `mapInfo` is instance of `std::unordered_map` and can only contain 0 or 1 value for a given key;
* similarly, `g_enabled_filter_types` and `setClientRules` are both `std::set` instances;
* lastly, while `mapTxSpends` is `std::unordered_multimap` that could potentially hold multiple values, having a size less than 1 means that the value is missing.

`QMap<WalletModel*, WalletView*> mapWalletViews` values were also migrated manually.

Co-authored-by: pablomartin4btc <pablomartin4btc@gmail.com>
Co-authored-by: fanquake <fanquake@gmail.com>
2025-12-03 13:37:17 +01:00
LőrincandJan B 039307554e refactor: unify container presence checks - trivial counts
The changes made here were:

| From              | To               |
|-------------------|------------------|
| `m.count(k)`      | `m.contains(k)`  |
| `!m.count(k)`     | `!m.contains(k)` |
| `m.count(k) == 0` | `!m.contains(k)` |
| `m.count(k) != 0` | `m.contains(k)`  |
| `m.count(k) > 0`  | `m.contains(k)`  |

The commit contains the trivial, mechanical refactors where it doesn't matter if the container can have multiple elements or not

Co-authored-by: Jan B <608446+janb84@users.noreply.github.com>
2025-12-03 13:36:58 +01:00
Lőrinc 8bb9219b63 refactor: unify container presence checks - find
The changes made here were:

| From                   | To               |
|------------------------|------------------|
| `m.find(k) == m.end()` | `!m.contains(k)` |
| `m.find(k) != m.end()` | `m.contains(k)`  |
2025-12-03 13:31:11 +01:00
Lőrinc 24ed820d4f merkle: remove unused mutated arg from BlockWitnessMerkleRoot
The `mutated` parameter is never used at any call site - all callers pass `nullptr`.
The explicit comment in `validation.cpp` explains the reason:
// The malleation check is ignored; as the transaction tree itself
// already does not permit it, it is impossible to trigger in the
// witness tree.
2025-11-06 11:26:17 +01:00
Lőrinc 63d640fa6a merkle: remove unused proot and pmutated args from MerkleComputation
There's a single call to the methods from `ComputeMerklePath` where these were always set to `nullptr`.
2025-11-06 10:21:51 +01:00
Lőrinc be270551df merkle: migrate path arg of MerkleComputation to a reference
There's a single call to the methods from `ComputeMerklePath` where the last parameter is always provided.
This simplifies the implementation by not having to check for missing parameter.
2025-11-06 10:20:50 +01:00
Lőrinc 24bcad3d4d refactor: remove dead code in CountWitnessSigOps
Found while reviewing #32840

The `nullptr` witness path was dead in normal code paths: removing it deletes unreachable logic.

Code coverage proof:
https://maflcko.github.io/b-c-cov/total.coverage/src/script/interpreter.cpp.gcov.html#L2135
2025-11-04 22:51:25 +01:00
Lőrinc 2d23820ee1 refactor: remove dead branches in SingletonClusterImpl
`SplitAll()` always calls `ApplyRemovals()` first, for a singleton, it empties the cluster, therefore any `SingletonClusterImpl` passed to `Split()` must be empty.

`TxGraphImpl::ApplyDependencies()` first merges each dependency group and asserts the group has at least one dependency.
Since `parent` != `child`, `TxGraphImpl::Merge()` upgrades the merge target to `GenericClusterImpl`, therefore the `ApplyDependencies()` is never dispatched to `SingletonClusterImpl`.

Found during review: https://github.com/bitcoin/bitcoin/pull/33157#discussion_r2423058928
Coverage evidence:
* https://maflcko.github.io/b-c-cov/fuzz.coverage/src/txgraph.cpp.gcov.html#L1446
* https://storage.googleapis.com/oss-fuzz-coverage/bitcoin-core/reports/20251103/linux/src/bitcoin-core/src/txgraph.cpp.html#L1446
2025-11-03 12:19:05 +01:00
LőrincandMartin Ankerl 0ac969cddf validation: don't reallocate cache for short-lived CCoinsViewCache
A few temporary `CCoinsViewCache`'s are destructed right after the `Flush()`, therefore it is not necessary to call `ReallocateCache` to recreate them right before they're killed anyway.

* `Flush()` - retains existing functionality;
* `Flush(/*will_reuse_cache=*/false)` - skips destruction and reallocation of the parent cache since it will soon go out of scope anyway;

For the `will_reuse_cache` parameter we want to see exactly which ones will reallocate memory and which won't - since both can be valid usages.

This change was based on a subset of https://github.com/bitcoin/bitcoin/pull/28945.

Co-authored-by: Martin Ankerl <martin.ankerl@gmail.com>
2025-11-02 21:40:16 +01:00
c8f5e446dc coins: reduce lookups in dbcache layer propagation
Previously, when the parent coins cache had no entry and the child did, `BatchWrite` performed a find followed by `try_emplace`, which resulted in multiple `SipHash` computations and bucket traversals on the common insert path.

This change uses a single leading `try_emplace` and branches on the returned `inserted` flag.
In the `FRESH && SPENT` case (only exercised by tests), we erase the just-inserted placeholder (which is constant time with no rehash anyway).
Semantics are unchanged for all valid parent/child state combinations.

This change is a minimal version of https://github.com/bitcoin/bitcoin/pull/32128/commits/723c49b63bb10da843fbb6efc6928dca415cc47f and draws simplification ideas https://github.com/bitcoin/bitcoin/pull/30673/commits/ae76ec7bcff0a08a61f294882a71e46d177b009f.

Added TODO versions for related pre-existing issues that should be fixed in follow-ups.

Co-authored-by: Martin Ankerl <martin.ankerl@gmail.com>
Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
Co-authored-by: optout <13562139+optout21@users.noreply.github.com>
2025-11-01 22:29:42 +01:00
LőrincandHennadii Stepanov 9610b0d1e2 randomenv: Fix MinGW dllimport warning for environ
Extends 7703884 to guard environ declaration on all Windows builds, not just MSVC.
In the mingw-w64 headers (used by llvm-mingw), environ is defined as a macro which expands through _environ to (* __p__environ()), a call to a dllimport function, causing the same inconsistent linkage warning as MSVC.

Use WIN32 instead of _MSC_VER to match the platform-specific guards already used throughout the file.

The warning occurs with llvm-mingw (both UCRT and MSVCRT variants as tested by Hebasto), but not with the mingw-w64 toolchain currently used in CI (as mentioned by fanquake).

Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
2025-10-14 10:24:08 -04:00
24d861da78 coins: only adjust cachedCoinsUsage on EmplaceCoinInternalDANGER insert
`EmplaceCoinInternalDANGER()` incremented `cachedCoinsUsage` even when `try_emplace` did not insert (duplicate key), inflating the counter.
This is mostly reachable in tests today since `AssumeUTXO` does not overwrite.

Increment only on successful insert, and capture `coin.DynamicMemoryUsage()` before the move so accounting uses the correct value.

Fuzz: add an `EmplaceCoinInternalDANGER` path to exercise insert-only accounting.
Unit test: emplace two different coins at the same outpoint (with different `DynamicMemoryUsage()`), verify `SelfTest()` passes and `AccessCoin(outpoint)` returns the first coin.

Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
Co-authored-by: w0xlt <woltx@protonmail.com>
2025-10-12 12:37:45 -04:00
d7c9d6c291 coins: fix cachedCoinsUsage accounting to prevent underflow
Move the `cachedCoinsUsage` subtract in `AddCoin()` to after the `possible_overwrite` check.
Previously a throw before assignment decremented the counter without changing the entry, which corrupted accounting and later underflowed.

In `Flush()`, reset `cachedCoinsUsage` to `0` only when `BatchWrite()` succeeds and `cacheCoins` is actually cleared. In production `BatchWrite()` returns `true`, so this mostly affects tests. On failure, leave the counter unchanged to keep it in sync with the cache.

The existing `Flush()` workaround in fuzzing was also removed now that the source of the problem was fixed, so the fuzzer no longer needs `coins_view_cache.Flush()` to realign `cachedCoinsUsage` after an exception.
Replace the prior `expected_code_path` tracking with direct assertions. The role of the variable was to verify that code execution follows only expected paths, either successful addition, or if it's an exception, the message is verified and checked that overwrite was disallowed.

With these changes the counter stays consistent across success and exception paths, so we can finally remove the `UBSan` suppressions for `CCoinsViewCache` that were masking the issue.

Included a unit test as well, attempting to add a different coin to the same outpoint without allowing overwrites and make sure it throws.
We use `SelfTest()` to validates accounting, and check that the cache remains usable.

Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
Co-authored-by: w0xlt <woltx@protonmail.com>
2025-10-11 22:05:22 -04:00
Lőrinc 39cf8bb3d0 refactor: remove redundant usage tracking from CoinsViewCacheCursor
When a coin is spent via `SpendCoin()`, `cachedCoinsUsage` is already decremented and the coin's `scriptPubKey` is cleared, so `DynamicMemoryUsage()` is `0`.

`CoinsViewCacheCursor::NextAndMaybeErase()` was subtracting usage again when erasing spent entries.
Replace it with an assert that documents spent coins have zero dynamic memory usage by the time the cursor encounters them.

Remove the now-unnecessary `usage` reference from the cursor's constructor and member variables.
2025-10-11 21:48:04 -04:00
LőrincandAndrew Toth 67cff8bec9 refactor: assert newly-created parent cache entry has zero memory usage
During `BatchWrite`, the parent entry is created under a guard that guarantees insertion, so the new `Coin` is default-constructed and empty.
Assert this invariant to document why there is no `cachedCoinsUsage` decrement before the assignment at this site.

Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
2025-10-11 21:48:04 -04:00
LőrincandHodlinator 45bd891465 log: split assumevalid ancestry-failure-reason message
When the assumevalid ancestry check fails, log a precise reason:
- "block height above assumevalid height" if the block is above the assumevalid block (the default reason)
- "block not in of assumevalid chain" otherwise

The new split was added under the existing condition to simplify conceptually that the two cases are related.
It could still be useful to know when the block is just above the assumevalid block or when it's not even on the same chain.

Update the functional test to assert the new reason strings. No behavior change.

Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
2025-10-01 23:34:23 -04:00
6c13a38ab5 log: separate script verification reasons
Replace `fScriptChecks` with `script_check_reason` and log the precise reason when checks are enabled; log a plain "Disabling" when they are skipped.
Adjust the functional test to assert the new reason strings.

Co-authored-by: w0xlt <woltx@protonmail.com>
Co-authored-by: Eunovo <eunovo9@gmail.com>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
Co-authored-by: TheCharlatan <seb.kung@gmail.com>
Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
2025-10-01 23:34:23 -04:00
Lőrinc f2ea6f04e7 refactor: untangle assumevalid decision branches
Flatten nested conditionals into a linear gating sequence for readability and precise logging. No functional change, TODOs are addressed in next commit
2025-10-01 23:34:23 -04:00
9bc298556c validation: log initial script verification state
Replaced `atomic<bool>` with `std::optional<bool>` (logged once on first observation). Safe because `ConnectBlock` holds `cs_main`.\
After this change, the state is logged before the very first `UpdateTip` line.

Co-authored-by: Eunovo <eunovo9@gmail.com>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
Co-authored-by: w0xlt <woltx@protonmail.com>
2025-10-01 23:34:23 -04:00
LőrincandHodlinator 4fad4e992c test: add assumevalid scenarios scaffold
Increase the test to 6 nodes and add flows for baseline, deep anchor, and too-recent cases, plus scaffolding for off-best-header, not-in-assumevalid,
and reindex gates.
Assertions are minimal here; follow-ups add reason checks.

Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
2025-10-01 23:32:53 -04:00
1fc7a81f1f log: reduce excessive messages during block replay
After an incomplete reindex the blocks will need to be replayed.
This results in excessive `Rolling back` and `Rolling forward` messages which quickly triggers the recently introduced log rate limiter.

Change the logging strategy to:
- Add single `LogInfo` messages showing the full range being replayed for both rollback and roll forward;
- Log progress at `LogInfo` level only every 10,000 blocks to track the long operations.

Reproducer:
* Start a normal IBD, stop after some progress
* Do a reindex, stop before it finishes
* Restart the node normally without specifying the reindex parameter
It should start rolling the blocks forward.

Before this change the excessive logging would show:
```
[*] Rolling forward 000000002f4f55aecfccc911076dc3f73ac0288c83dc1d79db0a026441031d40 (46245)
[*] Rolling forward 0000000017ffcf34c8eac010c529670ba6745ea59cf1edf7b820928e3b40acf6 (46246)
```

After the change it shows:
```
Replaying blocks
Rolling forward to 00000000000000001034012d7e4facaf16ca747ea94b8ea66743086cfe298ef8 (326223 to 340991)
Rolling forward 00000000000000000faabab19f17c0178c754dbed023e6c871dcaf74159c5f02 (330000)
Rolling forward 00000000000000000d9b2508615d569e18f00c034d71474fc44a43af8d4a5003 (340000)
...
Rolled forward to 00000000000000001034012d7e4facaf16ca747ea94b8ea66743086cfe298ef8
```

(similarly to rolling back)

Co-authored-by: Anthony Towns <aj@erisian.com.au>
Co-authored-by: Vasil Dimov <vd@freebsd.org>
2025-09-24 20:25:23 -07:00
Lőrinc 56791b5829 test: split out system_ram_tests to signal when total ram cannot be determined
when `GetTotalRAM` returns an `std::nullopt` now we're getting:
```
The following tests did not run:
        106 - system_ram_tests (Skipped)
```
2025-09-22 12:25:45 +02:00
Lőrinc 91ac64b0a6 log: reword signature validations to script verification in assumevalid log
Even though not all script verification is turned off currently (e.g. we're still doing the cheaper sigop counts), this naming is more consistent with other usages.
2025-09-18 15:52:01 -07:00
168360f4ae coins: warn on oversized -dbcache
Oversized allocations can cause out-of-memory errors or [heavy swapping](https://github.com/getumbrel/umbrel-os/issues/64#issuecomment-663637321), [grinding the system to a halt](https://x.com/murchandamus/status/1964432335849607224).

`LogOversizedDbCache()` now emits a startup warning if the configured `-dbcache` exceeds a cap derived from system RAM, using the same parsing/clamping as cache sizing via CalculateDbCacheBytes(). This isn't meant as a recommended setting, rather a likely upper limit.

Note that we're not modifying the set value, just issuing a warning.
Also note that the 75% calculation is rounded for the last two numbers since we have to divide first before multiplying, otherwise we wouldn't stay inside size_t on 32-bit systems - and this was simpler than casting back and forth.

We could have chosen the remaining free memory for the warning (e.g. warn if free memory is less than 1 GiB), but this is just a heuristic, we assumed that on systems with a lot of memory, other processes are also running, while memory constrained ones run only Core.

If total RAM < 2 GiB, cap is `DEFAULT_DB_CACHE` (`450 MiB`), otherwise it's 75% of total RAM.
The threshold is chosen to be close to values commonly used in [raspiblitz](https://github.com/raspiblitz/raspiblitz/blob/dev/home.admin/_provision.setup.sh#L98-L115) for common setups:

| Total RAM | `dbcache` (MiB) | raspiblitz % | proposed cap (MiB) |
|----------:|----------------:|-------------:|-------------------:|
|     1 GiB |             512 |        50.0% |               450* |
|     2 GiB |            1536 |        75.0% |               1536 |
|     4 GiB |            2560 |        62.5% |               3072 |
|     8 GiB |            4096 |        50.0% |               6144 |
|    16 GiB |            4096 |        25.0% |              12288 |
|    32 GiB |            4096 |        12.5% |              24576 |

[Umbrel issues](https://github.com/getumbrel/umbrel-os/issues/64#issuecomment-663816367) also mention 75% being the upper limit.

Starting `bitcoind` on an 8 GiB rpi4b with a dbcache of 7 GiB:
> ./build/bin/bitcoind -dbcache=7000

warns now as follows:
```
2025-09-07T17:24:29Z [warning] A 7000 MiB dbcache may be too large for a system memory of only 7800 MiB.
2025-09-07T17:24:29Z Cache configuration:
2025-09-07T17:24:29Z * Using 2.0 MiB for block index database
2025-09-07T17:24:29Z * Using 8.0 MiB for chain state database
2025-09-07T17:24:29Z * Using 6990.0 MiB for in-memory UTXO set (plus up to 286.1 MiB of unused mempool space)
```

Besides the [godbolt](https://godbolt.org/z/EPsaE3xTj) reproducers for the new total memory method, we also tested the warnings manually on:
- [x] Apple M4 Max, macOS 15.6.1
- [x] Intel Core i9-9900K, Ubuntu 24.04.2 LTS
- [x] Raspberry Pi 4 Model B, Armbian Linux 6.12.22-current-bcm2711
- [x] Intel Xeon x64, Windows 11 Home Version 24H2, OS Build 26100.4351

Co-authored-by: stickies-v <stickies-v@protonmail.com>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
Co-authored-by: w0xlt <woltx@protonmail.com>
2025-09-17 11:36:21 -07:00
Lőrinc 6c720459be system: add helper for fetching total system memory
Added a minimal system helper to query total physical RAM on [Linux/macOS/Windows](https://stackoverflow.com/a/2513561) (on other platforms we just return an empty optional).

The added test checks if the value is roughly correct by checking if the CI platforms are returning any value and if the value is at least 1 GiB and not more than 10 TiB.

The max value is only validated on 64 bits, since it's not unreasonable for 32 bits to have max memory, but on 64 bits it's likely an error.

https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
> ullTotalPhys The amount of actual physical memory, in bytes.

https://man7.org/linux/man-pages/man3/sysconf.3.html:
> _SC_PHYS_PAGES The number of pages of physical memory. Note that it is possible for the product of this value and the value of _SC_PAGESIZE to overflow.
> _SC_PAGESIZE Size of a page in bytes. Must not be less than 1.

See https://godbolt.org/z/ec81Tjvrj for further details
2025-09-17 11:36:21 -07:00
Lőrincandmaflcko 75e6984ec8 test/refactor: use test deque to avoid quadratic iteration
Extracted from https://github.com/bitcoin/bitcoin/pull/33141#discussion_r2323012972.
In Python, list `pop(0)` is linear, so consuming all items is quadratic.
Switched to `collections.deque` with `popleft()` to express FIFO intent and avoid the O(n^2) path.
Behavior is unchanged; for a few hundred items the perf impact is likely negligible.

Ref: https://docs.python.org/3/tutorial/datastructures.html#using-lists-as-queues
> While appends and pops from the end of list are fast, doing inserts or pops
> from the beginning of a list is slow (because all of the other elements have
> to be shifted by one).

Co-authored-by: maflcko <6399679+maflcko@users.noreply.github.com>
2025-09-11 13:09:23 -07:00
Lőrinc d7de5b109f logs: show reindex progress in ImportBlocks
### Summary

When triggering a reindex, users had no indication of how many files remained or how far along the process was.

### Fix

This patch prefetches the target file block file count to be able to show progress information.
Instead of just displaying which block file is being processed, it now indicates how many files remain.

### Reproducer + expected results

Running
```bash
cmake -B build && make -C build -DCMAKE_BUILD_TYPE=Release && ./build/bin/bitcoind -datadir=demo -reindex
```
Shows the block files one-by-one currently, there's no way to see how much work is left:
```
Reindexing block file blk00000.dat...
Loaded 119920 blocks from external file in 1228ms
Reindexing block file blk00001.dat...
Loaded 10671 blocks from external file in 284ms
Reindexing block file blk00002.dat...
Loaded 5459 blocks from external file in 263ms
Reindexing block file blk00003.dat...
Loaded 5595 blocks from external file in 267ms
```

After the change:
```
Reindexing block file blk00000.dat (0% complete)...
Loaded 119920 blocks from external file in 1255ms
Reindexing block file blk00001.dat (1% complete)...
Loaded 10671 blocks from external file in 303ms
Reindexing block file blk00002.dat (2% complete)...
Loaded 5459 blocks from external file in 278ms
Reindexing block file blk00003.dat (3% complete)...
Loaded 5595 blocks from external file in 285ms
```
2025-09-09 15:31:55 -07:00
13f36c020f clang-format: regenerate configs
Regenerated `.clang-format` from current configs to replace deprecated keys with up-to-date equivalents.
Also added all current formatter default values to guard against version differences.

The configs were updated with the following command (using v16 for maximal compatibility):
   $(brew --prefix llvm@16)/bin/clang-format -dump-config -style=file:src/.clang-format

The new config was tested with:
   $(brew --prefix llvm@16)/bin/clang-format -i src/deploymentinfo.h

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
2025-09-01 15:10:24 -07:00
Lőrinc b6f8c48946 coins: increase default dbbatchsize to 32 MiB
The default database write batch size is increased from 16 MiB to 32 MiB to improve I/O efficiency and performance during UTXO flushes, particularly during Initial Block Download and `assumeutxo` loads.

On systems with slower I/O, a larger batch size reduces overhead from numerous small writes. Measurements show this change provides a modest performance improvement on most hardware during a critical section, with a minimal peak memory increase (approx. 75 MiB on default settings).
2025-08-28 10:09:32 -07:00
Lőrinc 8bbb7b8bf8 refactor: Extract default batch size into kernel
The constant for the default batch size is moved to `kernel/caches.h` to consolidate kernel-related cache constants.
2025-08-28 10:09:32 -07:00
Lőrinc 2885bd0e1c doc: unify datacarriersize warning with release notes
Unified the deprecation warning for the recently deprecated datacarrier[size] options to match the phrasing of release-notes-32406.md.
2025-08-19 20:34:07 -07:00
Lőrinc 743abbcbde refactor: inline constant return value of BlockTreeDB::WriteBatchSync and BlockManager::WriteBlockIndexDB and BlockTreeDB::WriteFlag 2025-08-13 15:47:48 -07:00
Lőrinc e030240e90 refactor: inline constant return value of CDBWrapper::Erase and BlockTreeDB::WriteReindexing
Did both in this commit, since the return value of `WriteReindexing` was ignored anyway - which existed only because of the constant `Erase` being called
2025-08-13 15:47:48 -07:00
Lőrinc cdab9480e9 refactor: inline constant return value of CDBWrapper::Write 2025-08-13 15:47:48 -07:00
Lőrinc d1847cf5b5 refactor: inline constant return value of TxIndex::DB::WriteTxs 2025-08-13 15:47:44 -07:00
Lőrinc 50b63a5698 refactor: inline constant return value of CDBWrapper::WriteBatch
`WriteBatch` can only ever return `true` - its errors are handled by throwing a `throw dbwrapper_error` instead.
The boolean return value is quite confusing, especially since it's symmetric with `CDBWrapper::Read`, which catches the exceptions and returns a boolean instead.
We're removing the constant return value and inlining `true` for its usages.
2025-08-13 15:47:39 -07:00
Lőrincandstickies-v cb173b8e93 test: use local CBlockIndex in block read hash mismatch test to avoid data race
Co-authored-by: stickies-v <stickies-v@protonmail.com>
2025-08-12 11:34:58 -07:00
Lőrinc fab2980bdc assumevalid: log every script validation state change
The `-assumevalid` option skips script verification for a specified block and all its ancestors during Initial Block Download.
Many new users are surprised when this suddenly slows their node to a halt.
This commit adds a log message to clearly indicate when this optimization ends and full validation begins (and vice versa).

When using `-assumeutxo`, logging is suppressed for the active assumed-valid chainstate and for the background validation chainstate to avoid the confusing toggles.

-------

> cmake -B build && cmake --build build && mkdir -p demo && build/bin/bitcoind -datadir=demo -stopatheight=500 | grep 'signature validation'

```
2025-08-08T20:59:21Z Disabling signature validations at block #1 (00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048).
2025-08-08T20:59:21Z Enabling signature validations at block #100 (000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a).
2025-08-08T20:59:21Z Disabling signature validations at block #200 (000000008f1a7008320c16b8402b7f11e82951f44ca2663caf6860ab2eeef320).
2025-08-08T20:59:21Z Enabling signature validations at block #300 (0000000062b69e4a2c3312a5782d7798b0711e9ebac065cd5d19f946439f8609).
```
2025-08-08 16:47:34 -07:00
l0rincandJon Atack 721a051320 test: add coverage for -netinfo header and local services
Co-authored-by: Jon Atack <jon@atack.com>
2025-08-04 15:33:25 -06:00
Lőrinc 0431a690c3 cleanup: remove unused ser_writedata16be and ser_readdata16be 2025-07-29 16:25:47 -07:00
LőrincandLarry Ruane 554befd873 test: revive getcoinscachesizestate
After the changes in https://github.com/bitcoin/bitcoin/pull/25325 `getcoinscachesizestate` always end the test early, see:
https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/test/validation_flush_tests.cpp.gcov.html

The test revival was extracted from a related PR where it was discovered, see: https://github.com/bitcoin/bitcoin/pull/28531#discussion_r2109417797

Co-authored-by: Larry Ruane <larryruane@gmail.com>
2025-07-28 13:17:30 -07:00
Lőrinc 64ed0fa6b7 refactor: modernize LargeCoinsCacheThreshold
* parameter name uses underscores
* commit message typo fixed and compacted
* used `10_MiB` to avoid having to comment
* swapped order of operands in (9 * x / 10) to make it obvious that we're calculating 90%
* inlined return value
2025-07-28 13:17:17 -07:00
Lőrinc 1b40dc02a6 refactor: extract LargeCoinsCacheThreshold from GetCoinsCacheSizeState
Move-only commit, enabled reusing the large cache size calculation logic later. The only difference is the removal of the `static` keyword  (since in a constexpr function it's a C++23 extension)
2025-07-28 13:17:17 -07:00
d5104cfbae prevector: store P2WSH/P2TR/P2PK scripts inline
The current `prevector` size of 28 bytes (chosen to fill the `sizeof(CScript)` aligned size) was introduced in 2015 (https://github.com/bitcoin/bitcoin/pull/6914) before SegWit and TapRoot.
However, the increasingly common `P2WSH` and `P2TR` scripts are both 34 bytes, and are forced to use heap (re)allocation rather than efficient inline storage.

The core trade-off of this change is to eliminate heap allocations for common 34-36 byte scripts at the cost of increasing the base memory footprint of all `CScript` objects by 8 bytes (while still respecting peak memory usage defined by `-dbcache`).

Increasing the `prevector` size allows these scripts to be stored inline, avoiding extra heap allocations, reducing potential memory fragmentation, and improving performance during cache flushes. Massif analysis confirms a lower stable memory usage after flushing, suggesting the elimination of heap allocations outweighs the larger base size for common workloads.

Due to memory alignment, increasing the `prevector` size to 36 bytes doesn't change the overall `sizeof(CScript)` compared to an increase to 34 bytes, allowing us to include `P2PK` scripts as well at no additional memory cost.

Performance benchmarks for AssumeUTXO load and flush show:
* Small dbcache (450MB): ~1-3% performance improvement (despite more frequent flushes)
* Large dbcache (4500MB): ~6-8% performance improvement due to fewer heap allocations (and basically the number of flushes)
* Very large dbcache (4500MB): ~5-6% performance improvement due to fewer heap allocations (and memory limit not being reached, so there's no memory penalty)

Full IBD and reindex-chainstate with larger `dbcache` values also show an overall ~3-4% speedup.

Co-authored-by: Ava Chow <github@achow101.com>
Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
Co-authored-by: maflcko <6399679+maflcko@users.noreply.github.com>
2025-07-25 22:33:50 -07:00
Lőrinc 52121506b2 test: assert CScript allocation characteristics
Verifies that script types are correctly allocated using prevector's direct or indirect storage based on their size:

Direct allocated script types (size ≤ 28 bytes):
* OP_RETURN (small)
* P2WPKH
* P2SH
* P2PKH

Indirect allocated script types (size > 28 bytes):
* P2WSH
* P2TR
* P2PK
* MULTISIG (small)

This test provides a baseline for verifying changes to prevector's inline capacity.

The `CHECK_SCRIPT_STATIC_SIZE` and `CHECK_SCRIPT_DYNAMIC_SIZE` macros were added to differentiate the two cases - while preserving the correct source code line in case of failure.
2025-07-25 22:33:13 -07:00
Lőrinc 65ac7f6d4d refactor: modernize CScriptBase definition 2025-07-25 16:23:38 -07:00
LőrincandAnthony Towns 756da2a994 refactor: extract STATIC_SIZE constant to prevector
Co-authored-by: Anthony Towns <aj@erisian.com.au>
2025-07-25 16:23:37 -07:00
Lőrinc ca38cf701d doc: fix a few obvious typos in the affected files 2025-07-23 22:00:40 -07:00
Lőrinc ddab466e0d doc: remove manual TOCs 2025-07-23 21:31:35 -07:00
Lőrinc 26a3730711 doc: unify developer-notes and productivity header styles 2025-07-23 21:31:06 -07:00
LőrincandRussell Yanofsky 86e3a0a8cb refactor: standardize obfuscation memory alignment
See:
* https://github.com/bitcoin/bitcoin/pull/31144#discussion_r2216962117
* https://github.com/bitcoin/bitcoin/pull/31144#discussion_r2220277161
* https://github.com/bitcoin/bitcoin/pull/31144#discussion_r2210851772

Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
2025-07-23 12:56:48 -07:00