Commit Graph

675 Commits

Author SHA1 Message Date
Martin Zumsande
c011e3aa54 test: Wrap validation functions with TestChainstateManager
This allows to access them in the fuzz test in the next commit
without making them public.

Co-authored-by: TheCharlatan <seb.kung@gmail.com>
2025-12-16 11:25:46 -05:00
Ryan Ofsky
82be652e40 doc: Improve ChainstateManager documentation, use consistent terms 2025-12-12 06:49:59 -04:00
TheCharlatan
af455dcb39 refactor: Simplify pruning functions
Move GetPruneRange from ChainstateManager to Chainstate.
2025-12-12 11:49:59 +01:00
Ryan Ofsky
ae85c495f1 refactor: Delete ChainstateManager::GetAll() method
Just use m_chainstates array instead.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
6a572dbda9 refactor: Add ChainstateManager::ActivateBestChains() method
Deduplicate code looping over chainstate objects and calling
ActivateBestChain() and avoid need for code outside ChainstateManager to use
the GetAll() method.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
491d827d52 refactor: Add ChainstateManager::m_chainstates member
Use to replace m_active_chainstate, m_ibd_chainstate, and m_snapshot_chainstate
members. This has several benefits:

- Ensures ChainstateManager treats chainstates instances equally, making
  distinctions based on their attributes, not having special cases and making
  assumptions based on their identities.

- Normalizes ChainstateManager representation so states that should be
  impossible to reach and validation code has no handling for (like
  m_snapshot_chainstate being set and m_ibd_chainstate being unset, or both
  being set but m_active_chainstate pointing to the m_ibd_chainstate) can no
  longer be represented.

- Makes ChainstateManager more extensible so new chainstates can be added for
  different purposes, like indexing or generating and validating assumeutxo
  snapshots without interrupting regular node operations. With the
  m_chainstates member, new chainstates can be added and handled without needing
  to make changes all over validation code or to copy/paste/modify the existing
  code that's been already been written to handle m_ibd_chainstate and
  m_snapshot_chainstate.

- Avoids terms that are confusing and misleading:

  - The term "active chainstate" term is confusing because multiple chainstates
    will be active and in use at the same time. Before a snapshot is validated,
    wallet code will use the snapshot chainstate, while indexes will use the IBD
    chainstate, and netorking code will use both chainstates, downloading
    snapshot blocks at higher priority, but also IBD blocks simultaneously.

  - The term "snapshot chainstate" is ambiguous because it could refer either
    to the chainstate originally loaded from a snapshot, or to the chainstate
    being used to validate a snapshot that was loaded, or to a chainstate being
    used to produce a snapshot, but it is arbitrary used to refer the first
    thing. The terms "most-work chainstate" or "assumed-valid chainstate" should
    be less ambiguous ways to refer to chainstates loaded from snapshots.

  - The term "IBD chainstate" is not just ambiguous but actively confusing
    because technically IBD ends and the node is considered synced when the
    snapshot chainstate finishes syncing, so in practice the IBD chainstate
    will mostly by synced after IBD is complete. The term "fully-validated" is
    a better way of describing the characteristics and purpose of this
    chainstate.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
e514fe6116 refactor: Delete ChainstateManager::SnapshotBlockhash() method
SnapshotBlockhash() is only called two places outside of tests, and is used
redundantly in some tests, checking the same field as other checks. Simplify by
dropping the method and using the m_from_snapshot_blockhash field directly.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
ee35250683 refactor: Delete ChainstateManager::IsSnapshotValidated() method
IsSnapshotValidated() is only called one place outside of tests, and is use
redundantly in some tests, asserting that a snapshot is not validated when a
snapshot chainstate does not even exist. Simplify by dropping the method and
checking Chainstate m_assumeutxo field directly.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
d9e82299fc refactor: Delete ChainstateManager::IsSnapshotActive() method
IsSnapshotActive() method is only called one place outside of tests and
asserts, and is confusing because it returns true even after the snapshot is
fully validated.

The documentation which said this "implies that a background validation
chainstate is also in use" is also incorrect, because after the snapshot is
validated, the background chainstate gets disabled and IsUsable() would return
false.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
4dfe383912 refactor: Convert ChainstateRole enum to struct
Change ChainstateRole parameter passed to wallets and indexes. Wallets and
indexes need to know whether chainstate is historical and whether it is fully
validated. They should not be aware of the assumeutxo snapshot validation
process.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
352ad27fc1 refactor: Add ChainstateManager::ValidatedChainstate() method
ValidatedChainstate() accessor replaces GetChainstateForIndexing() with no
change in behavior.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
a229cb9477 refactor: Add ChainstateManager::CurrentChainstate() method
CurrentChainstate() is basically the same as ActiveChainstate() except it
requires cs_main to be locked when it is called, instead of locking cs_main
internally.

The name "current" should also be less confusing than "active" because multiple
chainstates can be active, and CurrentChainstate() returns the chainstate
targeting the current network tip, regardless of what chainstates are being
downloaded or how they are used.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
a9b7f5614c refactor: Add Chainstate::StoragePath() method
Use to simplify code determining the chainstate leveldb paths. New method is
the now the only code that needs to figure out the storage path, so the path
doesn't need to be constructed multiple places and backed out of leveldb.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
840bd2ef23 refactor: Pass chainstate parameters to MaybeCompleteSnapshotValidation
Remove hardcoded references to m_ibd_chainstate and m_snapshot_chainstate so
MaybeCompleteSnapshotValidation function can be simpler and focus on validating
the snapshot without dealing with internal ChainstateManager states.

This is a step towards being able to validate the snapshot outside of
ActivateBestChain loop so cs_main is not locked for minutes when the snapshot
block is connected.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
1598a15aed refactor: Deduplicate Chainstate activation code
Move duplicate code from ChainstateManager::ActivateSnapshot and
ChainstateManager::ActivateExistingSnapshot methods to a new
ChainstateManager::AddChainstate method.

The "AddChainstate" method name doesn't mention snapshots even though it is
only used to add snapshot chainstates now, because it becomes more generalized
in a later commit in this PR ("refactor: Add ChainstateManager::m_chainstates
member")
2025-12-12 06:49:59 -04:00
Ryan Ofsky
9fe927b6d6 refactor: Add Chainstate m_assumeutxo and m_target_utxohash members
Get rid of m_disabled/IsUsable members. Instead of marking chains disabled for
different reasons, store chainstate assumeutxo status explicitly and use that
information to determine how chains should be treated.
2025-12-12 06:49:59 -04:00
Ryan Ofsky
6082c84713 refactor: Add Chainstate::m_target_blockhash member
Make Chainstate objects aware of what block they are targeting. This makes
Chainstate objects more self contained, so it's possible for validation code to
look at one Chainstate object and know what blocks to connect to it without
needing to consider global validation state or look at other Chainstate
objects.

The motivation for this change is to make validation and networking code more
readable, so understanding it just requires knowing about chains and blocks,
not reasoning about assumeutxo download states. This change also enables
simplifications to the ChainstateManager interface in subsequent commits, and
could make it easier to implement new features like creating new Chainstate
objects to generate UTXO snapshots or index UTXO data.

Note that behavior of the MaybeCompleteSnapshotValidation function is not
changing here but some checks that were previously impossible to trigger like
the BASE_BLOCKHASH_MISMATCH case have been turned into asserts.
2025-12-12 06:49:59 -04:00
Sjors Provoost
00d1b6ef4b doc: clarify UpdateUncommittedBlockStructures 2025-10-31 11:47:28 +01:00
merge-script
56e9703968 Merge bitcoin/bitcoin#29640: Fix tiebreak when loading blocks from disk (and add tests for comparing chain ties)
0465574c12 test: Fixes send_blocks_and_test docs (Sergi Delgado Segura)
09c95f21e7 test: Adds block tiebreak over restarts tests (Sergi Delgado Segura)
18524b072e Make nSequenceId init value constants (Sergi Delgado Segura)
8b91883a23 Set the same best tip on restart if two candidates have the same work (Sergi Delgado Segura)
5370bed21e test: add functional test for complex reorgs (Pieter Wuille)
ab145cb3b4 Updates CBlockIndexWorkComparator outdated comment (Sergi Delgado Segura)

Pull request description:

  This PR grabs some interesting bits from https://github.com/bitcoin/bitcoin/pull/29284 and fixes some edge cases in how block tiebreaks are dealt with.

  ## Regarding #29284

  The main functionality from the PR was dropped given it was not an issue anymore, however, reviewers pointed out some comments were outdated https://github.com/bitcoin/bitcoin/pull/29284#discussion_r1522023578 (which to my understanding may have led to thinking that there was still an issue) it also added test coverage for the aforementioned case which was already passing on master and is useful to keep.

  ## New functionality

  While reviewing the superseded PR, it was noticed that blocks that are loaded from disk may face a similar issue (check https://github.com/bitcoin/bitcoin/pull/29284#issuecomment-1994317785 for more context).

  The issue comes from how tiebreaks for equal work blocks are handled: if two blocks have the same amount of work, the one that is activatable first wins, that is, the one for which we have all its data (and all of its ancestors'). The variable that keeps track of this, within `CBlockIndex` is `nSequenceId`, which is not persisted over restarts. This means that when a node is restarted, all blocks loaded from disk are defaulted the same `nSequenceId`: 0.
  Now, when trying to decide what chain is best on loading blocks from disk, the previous tiebreaker rule is not decisive anymore, so the `CBlockIndexWorkComparator` has to default to its last rule: whatever block is loaded first (has a smaller memory address).

  This means that if multiple same work tip candidates were available before restarting the node, it could be the case that the selected chain tip after restarting does not match the one before.

  Therefore, the way `nSequenceId` is initialized is changed to:

  - 0 for blocks that belong to the previously known best chain
  - 1 to all other blocks loaded from disk

ACKs for top commit:
  sipa:
    utACK 0465574c12
  TheCharlatan:
    ACK 0465574c12
  furszy:
    Tested ACK 0465574c12.

Tree-SHA512: 161da814da03ce10c34d27d79a315460a9c98d019b85ee35bc5daa991ed3b6a2e69a829e421fc70d093a83cf7a2e403763041e594df39ed1991445e54c16532a
2025-10-27 12:17:37 -04:00
Ava Chow
0eb554728c Merge bitcoin/bitcoin#33336: log: print every script verification state change
45bd891465 log: split assumevalid ancestry-failure-reason message (Lőrinc)
6c13a38ab5 log: separate script verification reasons (Lőrinc)
f2ea6f04e7 refactor: untangle assumevalid decision branches (Lőrinc)
9bc298556c validation: log initial script verification state (Lőrinc)
4fad4e992c test: add assumevalid scenarios scaffold (Lőrinc)
91ac64b0a6 log: reword `signature validations` to `script verification` in `assumevalid` log (Lőrinc)

Pull request description:

  ### Summary

  Users can encounter cases where script checks are unexpectedly enabled (e.g. after reindex, or when `assumevalid`/`minimumchainwork` gates fail). Without an explicit line, they must infer state from the absence of a message, which is incomplete and error-prone.
  The existing "Assuming ancestors of block …" line does not reliably indicate whether script checks are actually enabled, which makes debugging/benchmarking confusing.

  ### What this changes

  We make the initial **script-verification** state explicit and log **why** checks are enabled to avoid confusion.
  * Always log the first script-verification state on startup, **before** the first `UpdateTip`.
  * Flatten the nested `assumevalid` conditionals into a linear gating sequence for readability.
  * Extend the functional test to assert the old behavior with the new reason strings.

  This is a **logging-only** test change it shouldn't change any other behavior.

  ### Example output

  The state (with reason) is logged at startup and whenever the reason changes, e.g.:

  * `Disabling script verification at block #904336 (000000000000000000014106b2082b1a18aaf3091e8b337c6fed110db8c56620).`
  * `Enabling script verification at block #912527 (000000000000000000010bb6aa3ecabd7d41738463b6c6621776c2e40dbe738a): block too recent relative to best header.`
  * `Enabling script verification at block #912684 (00000000000000000001375cf7b90b2b86e559d05ed92ca764d376702ead3858): block height above assumevalid height.`

  ------

  Follow-up to https://github.com/bitcoin/bitcoin/pull/32975#discussion_r2329269037

ACKs for top commit:
  Eunovo:
    re-ACK 45bd891465
  achow101:
    ACK 45bd891465
  hodlinator:
    re-ACK 45bd891465
  yuvicc:
    ACK 45bd891465
  andrewtoth:
    ACK 45bd891465
  ajtowns:
    ACK 45bd891465

Tree-SHA512: 58328d7c418a6fe18f1c7fe1dd31955bb6fce8b928b0df693f6200807932eb5933146300af886a80a1d922228d93faf531145186dae55ad4ad1f691970732eca
2025-10-24 11:00:35 -07:00
Ava Chow
d735e2e9b3 Merge bitcoin/bitcoin#32998: Bump SCRIPT_VERIFY flags to 64 bit
652424ad16 test: additional test coverage for script_verify_flags (Anthony Towns)
417437eb01 script/verify_flags: extend script_verify_flags to 64 bits (Anthony Towns)
3cbbcb66ef script/interpreter: make script_verify_flag_name an ordinary enum (Anthony Towns)
bddcadee82 script/verify_flags: make script_verify_flags type safe (Anthony Towns)
a5ead122fe script/interpreter: introduce script_verify_flags typename (Anthony Towns)
4577fb2b1e rpc: have getdeploymentinfo report script verify flags (Anthony Towns)
a3986935f0 validation: export GetBlockScriptFlags() (Anthony Towns)
5db8cd2d37 Move mapFlagNames and FormatScriptFlags logic to script/interpreter.h (Anthony Towns)

Pull request description:

  We currently use 21 of 32 possible bits for `SCRIPT_VERIFY_*` flags, with open PRs that may use 8 more (#29247, #31989, #32247, #32453). The mutinynet fork that has included many experimental soft fork features is [already reusing bits here](d4a86277ed/src/script/interpreter.h (L175-L195)). Therefore, bump this to 64 bits.

  In order to make it easier to update this logic in future, this PR also introduces a dedicated type for the script flags, and disables implicit conversion between that type and the underlying integer type. To make verifying that this change doesn't cause flags to disappear, this PR also resurrects the changes from #28806 so that the script flags that are consensus enforced on each block can be queried via getdeploymentinfo.

ACKs for top commit:
  instagibbs:
    reACK 652424ad16
  achow101:
    ACK 652424ad16
  darosior:
    ACK 652424ad16
  theStack:
    Code-review ACK 652424ad16 🎏

Tree-SHA512: 7b30152196cdfdef8b9700b571b7d7d4e94d28fbc5c26ea7532788037efc02e4b1d8de392b0b20507badfdc26f5c125f8356a479604a9149b8aae23a7cf5549f
2025-10-07 14:51:22 -07:00
Lőrinc
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
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
Ava Chow
04c115dfde Merge bitcoin/bitcoin#33078: kernel: improve BlockChecked ownership semantics
1d9f1cb4bd kernel: improve BlockChecked ownership semantics (stickies-v)
9ba1fff29e kernel: refactor: ConnectTip to pass block pointer by value (stickies-v)

Pull request description:

  Subscribers to the BlockChecked validation interface event may need access to the block outside of the callback scope. Currently, this is only possible by copying the block, which makes exposing this validation interface event publicly either cumbersome or with significant copy overhead.

  By using shared_ptr, we make the shared ownership explicit and allow users to safely use the block outside of the callback scope. By using a const-ref shared_ptr, no atomic reference count cost is incurred if a subscriber does not require block ownership.

  For example: in  #30595, this would allow us to drop the `kernel_BlockPointer` handle entirely, and generalize everything into `kernel_Block`. This PoC is implemented in https://github.com/stickies-v/bitcoin/commits/kernel/remove-blockpointer/.

  ---

  ### Performance

  I have added a benchmark in a [separate branch](https://github.com/stickies-v/bitcoin/commits/2025-07/validation-interface-ownership-benched/), to ensure this change does not lead to a problematic performance regression. Since most of the overhead comes from the subscribers, I have added scenarios for `One`, `Two`, and `Ten` subscribers. From these results, it appears there is no meaningful performance difference on my machine.

  When `BlockChecked()` takes a `const CBlock&` reference _(master)_:
  |               ns/op |                op/s |    err% |     total | benchmark
  |--------------------:|--------------------:|--------:|----------:|:----------
  |              170.09 |        5,879,308.26 |    0.3% |      0.01 | `BlockCheckedOne`
  |            1,603.95 |          623,460.10 |    0.5% |      0.01 | `BlockCheckedTen`
  |              336.00 |        2,976,173.37 |    1.1% |      0.01 | `BlockCheckedTwo`

  When `BlockChecked()` takes a `const std::shared_ptr<const CBlock>&` _(this PR)_:
  |               ns/op |                op/s |    err% |     total | benchmark
  |--------------------:|--------------------:|--------:|----------:|:----------
  |              172.20 |        5,807,155.33 |    0.1% |      0.01 | `BlockCheckedOne`
  |            1,596.79 |          626,254.52 |    0.0% |      0.01 | `BlockCheckedTen`
  |              333.38 |        2,999,603.17 |    0.3% |      0.01 | `BlockCheckedTwo`

ACKs for top commit:
  achow101:
    ACK 1d9f1cb4bd
  w0xlt:
    reACK 1d9f1cb4bd
  ryanofsky:
    Code review ACK 1d9f1cb4bd. These all seem like simple changes that make sense
  TheCharlatan:
    ACK 1d9f1cb4bd
  yuvicc:
    Code Review ACK 1d9f1cb4bd

Tree-SHA512: 7ed0cccb7883dbb1885917ef749ab7cae5d60ee803b7e3145b2954d885e81ba8c9d5ab1edb9694ce6b308235c621094c029024eaf99f1aab1b47311c40958095
2025-08-20 10:45:36 -07:00
Ava Chow
97593c1fd3 Merge bitcoin/bitcoin#32975: assumevalid: log every script validation state change
fab2980bdc assumevalid: log every script validation state change (Lőrinc)

Pull request description:

  The `-assumevalid` option skips script verification for a specified block and all its ancestors during Initial Block Download.
  Many new [users are surprised](https://github.com/bitcoin/bitcoin/issues/32832) 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).

  <details>
  <summary>Testing instructions</summary>

  The behavior can easily be tested by adding this before the new log:
  ```C++
      // TODO hack to enable/disable script checks based on block height for testing purposes
           if (pindex->nHeight < 100) fScriptChecks = false;
      else if (pindex->nHeight < 200) fScriptChecks = true;
      else if (pindex->nHeight < 300) fScriptChecks = false;
      else if (pindex->nHeight < 400) fScriptChecks = true;
  ```
  and exercise the new code with:
  ```bash
  cmake -B build && cmake --build build && mkdir -p demo && build/bin/bitcoind -datadir=demo -stopatheight=500 | grep 'signature validation'
  ```
  showing something like:
  * Disabling signature validations at block #1 (00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048).
  * Enabling signature validations at block #100 (000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a).
  * Disabling signature validations at block #200 (000000008f1a7008320c16b8402b7f11e82951f44ca2663caf6860ab2eeef320).
  * Enabling signature validations at block #300 (0000000062b69e4a2c3312a5782d7798b0711e9ebac065cd5d19f946439f8609).

  </details>

ACKs for top commit:
  achow101:
    ACK fab2980bdc
  ajtowns:
    crACK fab2980bdc
  davidgumberg:
    untested crACK fab2980bdc

Tree-SHA512: e90b66f7423b639356daace476942ce83e65e70466544394cbe2f15738bdbf716163eaf590c64c5448f9b41aeeaafe3342c48c6a7a478678a70b0310ca94e11d
2025-08-15 13:54:09 -07:00
Anthony Towns
a5ead122fe script/interpreter: introduce script_verify_flags typename
Previously the SCRIPT_VERIFY_* flags were specified as either uint32_t,
unsigned int, or unsigned. This converts them to a common type alias in
preparation for changing the underlying type.
2025-08-14 10:17:32 +10:00
Anthony Towns
a3986935f0 validation: export GetBlockScriptFlags() 2025-08-14 10:17:32 +10: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
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
Sergi Delgado Segura
18524b072e Make nSequenceId init value constants
Make it easier to follow what the values come without having to go
over the comments, plus easier to maintain
2025-07-28 10:15:17 -04:00
Sergi Delgado Segura
8b91883a23 Set the same best tip on restart if two candidates have the same work
Before this, if we had two (or more) same work tip candidates and restarted our node,
it could be the case that the block set as tip after bootstrap didn't match the one
before stopping. That's because the work and `nSequenceId` of both block will be the same
(the latter is only kept in memory), so the active chain after restart would have depended
on what tip candidate was loaded first.

This makes sure that we are consistent over reboots.
2025-07-28 10:15:14 -04:00
stickies-v
9ba1fff29e kernel: refactor: ConnectTip to pass block pointer by value
By passing by value, we can remove the need to allocate a new pointer if
the callsite uses move semantics. In the process, simplify naming.
2025-07-28 13:45:15 +01:00
MarcoFalke
fa9a3de09b fuzz: DisableNextWrite
This is required in the process_message(s) fuzz targets to avoid leaking
the next write time from one run to the next. Also, disable it
completely because it is not needed and due to leveldb-internal
non-determinism.
2025-07-18 14:02:59 +02:00
Ava Chow
a40e953658 Merge bitcoin/bitcoin#30479: validation: Add eligible ancestors of reconsidered block to setBlockIndexCandidates
8cc3ac6c23 validation: Don't use IsValid() to filter for invalid blocks (Martin Zumsande)
86d98b94e5 test: verify that ancestors of a reconsidered block can become the chain tip (stratospher)
3c39a55e64 validation: Add ancestors of reconsiderblock to setBlockIndexCandidates (Martin Zumsande)

Pull request description:

  When we call `reconsiderblock` for some block,  `Chainstate::ResetBlockFailureFlags` puts the descendants of that block into `setBlockIndexCandidates` (if they meet the criteria, i.e. have more work than the tip etc.), but never put any ancestors into the set even though we do clear their failure flags.

  I think that this is wrong, because `setBlockIndexCandidates` should always contain all eligible indexes that have at least as much work as the current tip, which can include ancestors of the reconsidered block. This is being checked by `CheckBlockIndex()`, which could fail if it was invoked after `ActivateBestChain` connects a block and releases `cs_main`:
  ``` diff
  diff --git a/src/validation.cpp b/src/validation.cpp
  index 7b04bd9a5b..ff0c3c9f58 100644
  --- a/src/validation.cpp
  +++ b/src/validation.cpp
  @@ -3551,6 +3551,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
               }
           }
           // When we reach this point, we switched to a new tip (stored in pindexNewTip).
  +        m_chainman.CheckBlockIndex();
   
           if (exited_ibd) {
               // If a background chainstate is in use, we may need to rebalance our
  ```
  makes `rpc_invalidateblock.py` fail on master.

  Even though we don't currently have a `CheckBlockIndex()` in that place, after `cs_main` is released other threads could invoke it, which is happening in the rare failures of #16444 where an invalid header received from another peer could trigger a `CheckBlockIndex()` call that would fail.

  Fix this by adding eligible ancestors to `setBlockIndexCandidates` in `Chainstate::ResetBlockFailureFlags` (also simplifying that function a bit).

  Fixes #16444

ACKs for top commit:
  achow101:
    ACK 8cc3ac6c23
  TheCharlatan:
    Re-ACK 8cc3ac6c23
  stratospher:
    reACK 8cc3ac6.

Tree-SHA512: 53f27591916246be4093d64b86a0494e55094abd8c586026b1247e4a36747bc3d6dbe46dc26ee4a22f47b8eb0d9699d13e577dee0e7198145f3c9b11ab2a30b7
2025-07-09 16:55:43 -07:00
Ava Chow
9a7eece5a4 Merge bitcoin/bitcoin#31981: Add checkBlock() to Mining interface
a18e572328 test: more template verification tests (Sjors Provoost)
10c908808f test: move gbt proposal mode tests to new file (Sjors Provoost)
94959b8dee Add checkBlock to Mining interface (Sjors Provoost)
6077157531 ipc: drop BlockValidationState special handling (Sjors Provoost)
74690f4ed8 validation: refactor TestBlockValidity (Sjors Provoost)

Pull request description:

  This PR adds the IPC equivalent of the `getblocktemplate` RPC in `proposal` mode.

  In order to do so it has `TestBlockValidity` return error reasons as a string instead of `BlockValidationState`. This avoids complexity in IPC code for handling the latter struct.

  The new Mining interface method is used in `miner_tests`.

  It's not used by the `getblocktemplate` and `generateblock` RPC calls, see https://github.com/bitcoin/bitcoin/pull/31981#discussion_r2096473337

  The `inconclusive-not-best-prevblk` check is moved from RPC
  code to `TestBlockValidity`.

  Test coverage is increased by `mining_template_verification.py`.

  Superseedes #31564

  ## Background

  ### Verifying block templates (no PoW)

  Stratum v2 allows miners to generate their own block template. Pools may wish (or need) to verify these templates. This typically involves comparing mempools, asking miners to providing missing transactions and then reconstructing the proposed block.[^0] This is not sufficient to ensure a proposed block is actually valid. In some schemes miners could take advantage of incomplete validation[^1].

  The Stratum Reference Implementation (SRI), currently the only Stratum v2 implementation, collects all missing mempool transactions, but does not yet fully verify the block.[^2]. It could use the `getblocktemplate` RPC in `proposal` mode, but using IPC is more performant, as it avoids serialising up to 4 MB of transaction data as JSON.

  (although SRI could use this PR, the Template Provider role doesn't need it, so this is _not_ part of #31098)

  [^0]: https://github.com/stratum-mining/sv2-spec/blob/main/06-Job-Declaration-Protocol.md
  [^1]: https://delvingbitcoin.org/t/pplns-with-job-declaration/1099/45?u=sjors
  [^2]: https://github.com/stratum-mining/stratum/blob/v1.1.0/roles/jd-server/src/lib/job_declarator/message_handler.rs#L196

ACKs for top commit:
  davidgumberg:
    reACK a18e572328
  achow101:
    ACK a18e572328
  TheCharlatan:
    ACK a18e572328
  ryanofsky:
    Code review ACK a18e572328 just adding another NONFATAL_UNREACHABLE since last review

Tree-SHA512: 1a6c29f45a1666114f10f55aed155980b90104db27761c78aada4727ce3129e6ae7a522d90a56314bd767bd7944dfa46e85fb9f714370fc83e6a585be7b044f1
2025-06-18 17:07:21 -07:00
Sjors Provoost
74690f4ed8 validation: refactor TestBlockValidity
Comments are expanded.

Return BlockValidationState instead of passing a reference.
Lock Chainman mutex instead of cs_main.
Remove redundant chainparams and pindexPrev arguments.
Drop defaults for checking proof-of-work and merkle root.

The ContextualCheckBlockHeader check is moved to after CheckBlock,
which is more similar to normal validation where context-free checks
are done first.

Validation failure reasons are no longer printed through LogError(),
since it depends on the caller whether this implies an actual bug
in the node, or an externally sourced block that happens to be invalid.
When called from getblocktemplate, via BlockAssembler::CreateNewBlock(),
this method already throws an std::runtime_error if validation fails.

Additionally it moves the inconclusive-not-best-prevblk check from RPC
code to TestBlockValidity.

There is no behavior change when callling getblocktemplate with proposal.
Previously this would return a BIP22ValidationResult which can throw for
state.IsError(). But CheckBlock() and the functions it calls only use
state.IsValid().

The final assert is changed into Assume, with a LogError.

Co-authored-by: <Ryan Ofsky <ryan@ofsky.org>
2025-06-14 14:32:45 +02:00
Ava Chow
19765dca19 Merge bitcoin/bitcoin#32694: index: move disk read lookups to base class
029ba1a21d index: remove CBlockIndex access from CustomAppend() (furszy)
91b7ab6c69 refactor: index, simplify CopyHeightIndexToHashIndex to process single block (furszy)
6f1392cc42 indexes, refactor: Remove remaining CBlockIndex* uses in index Rewind methods (Ryan Ofsky)
0a248708dc indexes, refactor: Stop requiring CBlockIndex type to call IsBIP30Unspendable (Ryan Ofsky)
331a25cb16 test: indexes, avoid creating threads when sync runs synchronously (furszy)

Pull request description:

  Combining common refactors from #24230 and #26966, aiming to move both efforts forward while reducing their size and review burden.

  Broadly, #24230 focuses on enabling indexes to run in a separate process, and #26966 aims to parallelize the indexes initial synchronization process. A shared prerequisite for both is ensuring that only the base index class interacts with the node’s chain internals - child index classes should instead operate solely through chain events.

  This PR moves disk read lookups from child index classes to the base index class. It also includes a few documentation improvements and a test-only code cleanup.

ACKs for top commit:
  maflcko:
    review ACK 029ba1a21d 👡
  achow101:
    ACK 029ba1a21d
  TheCharlatan:
    Re-ACK 029ba1a21d
  davidgumberg:
    ACK 029ba1a21d
  mzumsande:
    Code Review ACK 029ba1a21d

Tree-SHA512: f073af407fc86f228cb47a32c7bcf2241551cc89ff32059317eb81d5b86fd5fda35f228d2567e0aedbc9fd6826291f5fee05619db35ba44108421ae04d11e6fb
2025-06-12 16:01:04 -07:00
Martin Zumsande
3c39a55e64 validation: Add ancestors of reconsiderblock to setBlockIndexCandidates
When we call reconsiderblock for some block, ResetBlockFailureFlags puts the descendants of that block
into setBlockIndexCandidates (if they meet the criteria, i.e. have more work than the tip etc.)
We also clear the failure flags of the ancestors, but we never put any of those into setBlockIndexCandidates
this is wrong and could lead to failures in CheckBlockIndex().
2025-06-12 14:40:57 -04:00
Ava Chow
5757de4ddd Merge bitcoin/bitcoin#32673: clang-tidy: Apply modernize-deprecated-headers
fa9ca13f35 refactor: Sort includes of touched source files (MarcoFalke)
facb152697 scripted-diff: Bump copyright headers after include changes (MarcoFalke)
fae71d30f7 clang-tidy: Apply modernize-deprecated-headers (MarcoFalke)

Pull request description:

  Bitcoin Core is written in C++, so it is confusing to sometimes use the deprecated C headers (with the `.h` extension). For example, it is less clear whether `string.h` refers to the file in this repo or the cstring stdlib header (https://github.com/bitcoin/bitcoin/pull/31308#discussion_r2121492797).

  The check is currently disabled for headers, to exclude subtree headers.

ACKs for top commit:
  l0rinc:
    ACK fa9ca13f35
  achow101:
    ACK fa9ca13f35
  janb84:
    ACK fa9ca13f35
  stickies-v:
    ACK fa9ca13f35

Tree-SHA512: 6639608308c598d612e24435aa519afe92d71b955874b87e527245291fb874b67f3ab95d3a0a5125c6adce5eb41c0d62f6ca488fbbfd60a94f2063d734173f4d
2025-06-11 15:08:23 -07:00
Ryan Ofsky
7c0cfce20d Merge bitcoin/bitcoin#31405: validation: stricter internal handling of invalid blocks
f6b782f3aa doc: Improve m_best_header documentation (Martin Zumsande)
ee673b9aa0 validation: remove m_failed_blocks (Martin Zumsande)
ed764ea2b4 validation: Add more checks to CheckBlockIndex() (Martin Zumsande)
9a70883002 validation: in invalidateblock, calculate m_best_header right away (Martin Zumsande)
8e39f2d20d validation: in invalidateblock, mark children as invalid right away (Martin Zumsande)
4c29326183 validation: cache all headers with enough PoW in invalidateblock (Martin Zumsande)
15fa5b5a90 validation: call InvalidBlockFound also from AcceptBlock (Martin Zumsande)

Pull request description:

  Some fields in validation are set opportunistically by "best effort":
  - The `BLOCK_FAILED_CHILD` status (which means that the block index has an invalid predecessor)
  - `m_best_header` (the most-work header not known to be invalid).

  This means that there are known situations in which these fields are not set when they should be, or set to wrong values. This is tolerated because the fields are not used for anything consensus-critical and triggering these situations involved creating invalid blocks with valid PoW header, so would have a cost attached. Also, having stricter guarantees for these fields requires iterating over the entire block index, which has some DoS potential, especially with any header above the checkpoint being accepted int he past (see e.g. #11531).

  However, there are reasons to change this now:
  - RPCs use these fields and can report wrong results
  - There is the constant possibility that someone could add code that expects these fields to be correct, especially because it is not well documented that these fields cannot always be relied upon.
  - DoS concerns have become less of an issue after #25717 - now an attacker would need to invest much more work because they can't fork off the last checkpoint anymore

  This PR continues the work from #30666 to ensure that `BLOCK_FAILED_CHILD` status and `m_best_header` are always correct:
  - it adds a call to `InvalidChainFound()` in `AcceptBlock()`.
  - it adds checks for `BLOCK_FAILED_CHILD` and `m_best_header`  to `CheckBlockIndex()`. In order to be able to do this, the existing cache in the RPC-only `InvalidateBlock()` is adjusted to handle these as well. These are performance optimizations with the goal of avoiding having a call of `InvalidChainFound()` / looping over the block index after each disconnected block.
  I also wrote a fuzz test to find possible edge cases violating `CheckBlockIndex`, which I will PR separately soon.
  - it removes the `m_failed_blocks` set, which was a heuristic necessary when we couldn't be sure if a given block index had an invalid predecessor or not. Now that we have that guarantee, the set is no longer needed.

ACKs for top commit:
  stickies-v:
    re-ACK f6b782f3aa
  achow101:
    reACK f6b782f3aa
  ryanofsky:
    Code review ACK f6b782f3aa with only minor code & comment updates
  TheCharlatan:
    Re-ACK f6b782f3aa

Tree-SHA512: 1bee324216eeee6af401abdb683abd098b18212833f9600dbc0a46244e634cb0e6f2a320c937a5675a12af7ec4a7d10fabc1db9e9bc0d9d0712e6e6ca72d084f
2025-06-11 16:17:22 -04:00
Ryan Ofsky
0a248708dc indexes, refactor: Stop requiring CBlockIndex type to call IsBIP30Unspendable
This commit does not change behavior in any way.
2025-06-10 12:57:15 -04:00
Martin Zumsande
f6b782f3aa doc: Improve m_best_header documentation 2025-06-06 11:23:44 -04:00
Martin Zumsande
ee673b9aa0 validation: remove m_failed_blocks
After changes in previous commits, we now mark all blocks that descend from an invalid block
immediately as the block is found invalid. This happens both in the AcceptBlock
and ConnectBlock stages of block validation.
As a result, the pindexPrev->nStatus check in AcceptBlockHeader is now sufficient to detect
invalid blocks and checking m_failed_blocks there is no longer necessary.
2025-06-06 11:23:44 -04:00
MarcoFalke
fa9ca13f35 refactor: Sort includes of touched source files 2025-06-03 19:56:55 +02:00
MarcoFalke
fae71d30f7 clang-tidy: Apply modernize-deprecated-headers
This can be reproduced according to the developer notes with something
like

( cd ./src/ && ../contrib/devtools/run-clang-tidy.py -p ../bld-cmake -fix -j $(nproc) )

Also, the header related changes were done manually.
2025-06-03 15:13:54 +02:00
Ava Chow
88b22acc3d Merge bitcoin/bitcoin#32528: rpc: Round verificationprogress to 1 for a recent tip
fab1e02086 refactor: Pass verification_progress into block tip notifications (MarcoFalke)
fa76b378e4 rpc: Round verificationprogress to exactly 1 for a recent tip (MarcoFalke)
faf6304bdf test: Use mockable time in GuessVerificationProgress (MarcoFalke)

Pull request description:

  Some users really seem to care about this. While it shouldn't matter much, the diff is so trivial that it is probably worth doing.

  Fixes #31127

  One could also consider to split the field into two dedicated ones (https://github.com/bitcoin/bitcoin/issues/28847#issuecomment-1807115357), but this is left for a more involved follow-up and may also be controversial.

ACKs for top commit:
  achow101:
    ACK fab1e02086
  pinheadmz:
    ACK fab1e02086
  sipa:
    utACK fab1e02086

Tree-SHA512: a3c24e3c446d38fbad9399c1e7f1ffa7904490a3a7d12623b44e583b435cc8b5f1ba83b84d29c7ffaf22028bc909c7cec07202b825480449c6419d2a190938f5
2025-05-27 16:45:23 -07:00
Ava Chow
aee7cec0db Merge bitcoin/bitcoin#32364: refactor: validation: mark CheckBlockIndex as const
3e6ac5bf77 refactor: validation: mark CheckBlockIndex as const (stickies-v)
61a51eccbb validation: don't use GetAll() in CheckBlockIndex() (stickies-v)
d05481df64 refactor: validation: mark SnapshotBase as const (stickies-v)

Pull request description:

  While reviewing another PR, I [noticed](https://github.com/bitcoin/bitcoin/pull/31405#discussion_r2056509235) that `ChainstateManager::CheckBlockIndex()`  is not a `const` method. To try and assert that this method was not causing any side-effects, I modified the method to make it `const`. It did not surface any errors, but I think it would be good to merge this change regardless, even if `CheckBlockIndex` is only used in regtest.

  This PR removes `CheckBlockIndex()`'s calls to non-const `ChainstateManager` methods by marking `SnapshotBase` `const` and ~inlining the `GetAll()` calls (thereby also performing consistency checks on invalid or fully validated `m_disabled==true` chainstates, as slight behaviour change), and finally marks `CheckBlockIndex()` as `const`.

ACKs for top commit:
  achow101:
    ACK 3e6ac5bf77
  mzumsande:
    Code Review ACK 3e6ac5bf77
  TheCharlatan:
    ACK 3e6ac5bf77

Tree-SHA512: 3d3cd351f5af1fab9a9498218ec62dba6e397fc7b5f4868ae0a77dc2b7c813d12c4f53f253f209101a3f6523695014e20c82dfac27cf0035611d5dd29feb80b5
2025-05-27 15:33:09 -07:00
Lőrinc
53e9b71b2f log: print reason for why should_write was triggered in FlushStateToDisk
Co-authored-by: Jon Atack <jon@atack.com>
2025-05-23 21:18:00 +02:00
MarcoFalke
fa76b378e4 rpc: Round verificationprogress to exactly 1 for a recent tip
This requires a new lock annotation, but all relevant callers already
held the lock.
2025-05-20 11:17:29 +02:00