Skip to content

validation: write chainstate to disk every hour#30611

Merged
achow101 merged 5 commits into
bitcoin:masterfrom
andrewtoth:write-chainstate-every-hour
May 1, 2025
Merged

validation: write chainstate to disk every hour#30611
achow101 merged 5 commits into
bitcoin:masterfrom
andrewtoth:write-chainstate-every-hour

Conversation

@andrewtoth

@andrewtoth andrewtoth commented Aug 8, 2024

Copy link
Copy Markdown
Contributor

Since #28233, periodically writing the chainstate to disk every 24 hours does not clear the dbcache. Since #28280, periodically writing the chainstate to disk is proportional only to the amount of dirty entries in the cache. Due to these changes, it is no longer beneficial to only write the chainstate to disk every 24 hours. The periodic flush interval was necessary because every write of the chainstate would clear the dbcache. Now, we can get rid of the periodic flush interval and simply write the chainstate along with blocks and block index at least every hour.

Three benefits of doing this:

  1. For IBD or reindex-chainstate with a combination of large dbcache setting, slow CPU, slow internet speed/unreliable peers, it could be up to 24 hours until the chainstate is persisted to disk. A power outage or crash could potentially lose up to 24 hours of progress. If there is a very large amount of dirty cache entries, writing to disk when a flush finally does occur will take a very long time. Crashing during this window of writing can cause "Rolling forward" at startup can take a long time, and is not interruptible (after unclean shutdown) #11600. By syncing every hour in unison with the block index we avoid this problem. Only a maximum of one hour of progress can be lost, and the window for crashing during writing is much smaller. For IBD with lower dbcache settings, faster CPU, or better internet speed/reliable peers, chainstate writes are already triggered more often than every hour so this change will have no effect on IBD.
  2. Based on discussion in Don't empty dbcache on prune flushes: >30% faster IBD #28280, writing only once every 24 hours during long running operation of a node causes IO spikes. Writing smaller chainstate changes every hour like we do with blocks and block index will reduce IO spikes.
  3. Faster shutdown speeds. All dirty chainstate entries must be persisted to disk on shutdown. If we have a lot of dirty entries, such as when close to 24 hours or if we sync with a large dbcache, it can take a long time to shutdown. By keeping the chainstate clean we avoid this problem.

Inspired by this comment.

Resolves #11600

@DrahtBot

DrahtBot commented Aug 8, 2024

Copy link
Copy Markdown
Contributor

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/30611.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK achow101, davidgumberg, l0rinc, sipa

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #31703 (Use number of dirty cache entries in flush warnings/logs by sipa)
  • #30610 (validation: do not wipe utxo cache for stats/scans/snapshots by sipa)
  • #29365 (Extend signetchallenge to set target block spacing by starius)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@gmaxwell

gmaxwell commented Aug 8, 2024

Copy link
Copy Markdown
Contributor

Before someone suggests that it should do this every block, a reason to not do this too much is that delaying writes prevents many writes from ever happening at all because many outputs are quickly spent.

I don't see a particular problem for this, there will be some write traffic increase but I don't expect it will be enough to meaningfully reduce the life time of flash on cheap devices (and if that were a concern the default level of logging is probably more of an issue). It's the sort of thing someone could test, however.

Someone might also want to test the latency impact (e.g. on block template creation) of the traversal.

Though long term it would be preferable to introduce a data structure to track pending writes and keep a constantly flushing going which always lags the tip by N blocks, both avoiding the latency spikes and preventing unnecessary writes of entries that are just going to be spent in the next couple blocks.

@mzumsande mzumsande left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you check if this would slow down IBD noticeably when running with a large dbcache?
If i understand it right, coins that are created and destroyed more than 1 hour of syncing apart would not have been written to disk before, but will be written and deleted after this PR - though presumably this is not a frequent event, so there wouldn't be much of an impact?!

@andrewtoth

Copy link
Copy Markdown
Contributor Author

Before someone suggests that it should do this every block, a reason to not do this too much is that delaying writes prevents many writes from ever happening at all because many outputs are quickly spent.

If i understand it right, coins that are created and destroyed more than 1 hour of syncing apart would not have been written to disk before, but will be written and deleted after this PR

Correct, there will be significantly less utxo cut through with this PR.

I don't see a particular problem for this, there will be some write traffic increase but I don't expect it will be enough to meaningfully reduce the life time of flash on cheap devices (and if that were a concern the default level of logging is probably more of an issue). It's the sort of thing someone could test, however.

though presumably this is not a frequent event, so there wouldn't be much of an impact?!

For normal operation, this would mean writing 10s of MB every hour, vs 100s of MB every 24 hours. I don't think that we should be concerned about that increase in disk IO? Seems negligible to me.

Did you check if this would slow down IBD noticeably when running with a large dbcache?

Not yet. I will run a reindex-chainstate benchmark with max dbcache and see what the impact is.

@sipa

sipa commented Aug 9, 2024

Copy link
Copy Markdown
Member

It would be good to know what impact it has on IBD, as it's necessarily going to make things slower (more syncs means more disk writes, and more memory/cpu to remember UTXOs which must be marked spent on disk), for the benefit of reducing losses in case of crashes. The question is how much time & I/O it adds.

Regarding doing it for every block (during steady state), the trade-off there is different but still exists. On the pro side there is a reduction of latency spikes instead of reducing crash losses (as these are inherently less relevant in steady state). On the con side there is an increase in frequency of writes (and the latency spikes they bring, albeit smaller ones) instead of a sync speed slowdown.

We don't necessarily need to use the same sync frequency during IBD and during steady state, but the effects during steady state seem harder to measure, so it's hard to say what is acceptable there.

One related idea: maybe we should randomize the sync event times a bit (say, uniformly random intervals between 50 and 70 minutes) to prevent a situation where the network over time settles into a few cohorts of synchronized syncers (think like communicating metronomes: they start randomly, but have synchronized events (blocks arriving) that slightly delay sync events if they were to coincide).

@andrewtoth

Copy link
Copy Markdown
Contributor Author

It would be good to know what impact it has on IBD, as it's necessarily going to make things slower

Note that it is only necessarily slower when running with very high dbcache settings. For default settings the cache fills up and is flushed far more often than every hour, so this will have no effect.

@andrewtoth

Copy link
Copy Markdown
Contributor Author

This change didn't appear to have any speed impact for a reindex-chainstate using max dbcache. Ran the following benchmark:

nohup hyperfine \
--export-markdown ~/bench.md \
--show-output \
--parameter-list commit 81508954f1f89f95b6fdca10c3c471cdb6566c80,27a770b34b8f1dbb84760f442edb3e23a0c2420b \
--prepare 'git checkout {commit} && \
make -j$(nproc) src/bitcoind; \
sync; sudo /sbin/sysctl vm.drop_caches=3;' \
-M 2 \
'echo '{commit}' && \
./src/bitcoind -datadir=/home/user/.bitcoin \
-reindex-chainstate \
-dbcache=16384 \
-printtoconsole=0 \
-connect=0 \
-stopatheight=820000' &

Results are the same:

Benchmark 1: echo 81508954f1f89f95b6fdca10c3c471cdb6566c80 && \
./src/bitcoind -datadir=/home/user/.bitcoin \
-reindex-chainstate \
-dbcache=16384 \
-printtoconsole=0 \
-connect=0 \
-stopatheight=820000

81508954f1f89f95b6fdca10c3c471cdb6566c80
  Time (mean ± σ):     12239.620 s ±  3.156 s    [User: 12366.988 s, System: 562.121 s]
  Range (min … max):   12237.388 s … 12241.851 s    2 runs
 
Benchmark 2: echo 27a770b34b8f1dbb84760f442edb3e23a0c2420b && \
./src/bitcoind -datadir=/home/user/.bitcoin \
-reindex-chainstate \
-dbcache=16384 \
-printtoconsole=0 \
-connect=0 \
-stopatheight=820000

27a770b34b8f1dbb84760f442edb3e23a0c2420b
  Time (mean ± σ):     12243.072 s ±  6.588 s    [User: 12382.386 s, System: 559.349 s]
  Range (min … max):   12238.413 s … 12247.730 s    2 runs
 
Summary
  'echo 81508954f1f89f95b6fdca10c3c471cdb6566c80 && \
./src/bitcoind -datadir=/home/user/.bitcoin \
-reindex-chainstate \
-dbcache=16384 \
-printtoconsole=0 \
-connect=0 \
-stopatheight=820000' ran
    1.00 ± 0.00 times faster than 'echo 27a770b34b8f1dbb84760f442edb3e23a0c2420b && \
./src/bitcoind -datadir=/home/user/.bitcoin \
-reindex-chainstate \
-dbcache=16384 \
-printtoconsole=0 \
-connect=0 \
-stopatheight=820000'

So, I would say this PR is strictly beneficial for IBD/reindex-chainstate. It is the same speed, but protects against data loss.

@gmaxwell

Copy link
Copy Markdown
Contributor

I didn't comment on IBD because I figured a hit per hour isn't that significant in the context of IBD and likely pays for itself in improving crash robustness. I'm a little surprised that the effect is quite so small, but it does probably improve performance too by making writes a little more concurrent.

Sipa: good point on the injection locking, I've previously wondered if the the 24 hour behavior could sync up.

@andrewtoth

andrewtoth commented Aug 15, 2024

Copy link
Copy Markdown
Contributor Author

I'm a little surprised that the effect is quite so small

@gmaxwell I was as well, so I ran the same benchmark with -reindex as well and it gave me similar results:

Command Mean [s] Min [s] Max [s] Relative
echo 81508954f1f89f95b6fdca10c3c471cdb6566c80 && ./src/bitcoind -datadir=/home/user/.bitcoin -reindex -dbcache=16384 -printtoconsole=0 -connect=0 -stopatheight=820000 40765.075 ± 132.452 40671.417 40858.733 1.01 ± 0.00
echo 27a770b34b8f1dbb84760f442edb3e23a0c2420b && ./src/bitcoind -datadir=/home/user/.bitcoin -reindex -dbcache=16384 -printtoconsole=0 -connect=0 -stopatheight=820000 40536.484 ± 46.379 40503.689 40569.279 1.00

Will get some measurements for total chainstate bytes written and total time writing chainstate before and after this change during steady state. But, this will take a few weeks to get meaningful data. Even then there will be a lot of variance depending on how many utxos are being eagerly spent within 24 hours vs 1 hour at the time I am measuring.

Someone might also want to test the latency impact (e.g. on block template creation) of the traversal.

I'm not sure I understand what you are suggesting to measure here, or what you mean by traversal. We can measure the total time writing chainstate to disk with -debug=bench, which would be the latency impact if that's what you mean.

Though long term it would be preferable to introduce a data structure to track pending writes and keep a constantly flushing going which always lags the tip by N blocks, both avoiding the latency spikes and preventing unnecessary writes of entries that are just going to be spent in the next couple blocks.

You mentioned a similar idea a while ago here. I agree with you there that it is a much bigger project. If this change is accepted and merged, would there really be a benefit anymore of adding something like that?

@l0rinc

l0rinc commented Aug 19, 2024

Copy link
Copy Markdown
Contributor

I'll review this in more detail later, but I have a question first:
Whenever a production change is made without corresponding test changes (yet the build passes), it suggests to me that there might be a gap in our coverage.
Do you think it would make sense to add a test that reproduces some aspect of the old behavior before making the change—one that would need to be updated in the commit that introduces the change?

@andrewtoth

Copy link
Copy Markdown
Contributor Author

it would make sense to add a test that reproduces some aspect of the old behavior before making the change—one that would need to be updated in the commit that introduces the change?

Good point, I can add a test that that expects flush every 24 hours, then reduce it to 1 hour after this change.

Comment thread src/validation.cpp Outdated
@andrewtoth
andrewtoth force-pushed the write-chainstate-every-hour branch 3 times, most recently from 66499fb to 1c1b63a Compare August 31, 2024 17:58
@DrahtBot

Copy link
Copy Markdown
Contributor

🚧 At least one of the CI tasks failed.
Debug: https://github.com/bitcoin/bitcoin/runs/29514781087

Hints

Make sure to run all tests locally, according to the documentation.

The failure may happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

Comment thread src/validation.cpp Outdated
@andrewtoth

andrewtoth commented Sep 2, 2024

Copy link
Copy Markdown
Contributor Author

I got some stats for running in steady state for this branch and master.
I ran 4 nodes for 11 days and 18 hours using identical aws t2-small instances backed by 20GB EBS volumes all connected to another node in the same VPC.

Branch Total time writing chainstate Total bytes written
master 1 26372ms 497 MiB
master 2 28188ms 497 MiB
branch 1 32496ms 760 MiB
branch 2 32566ms 760 MiB

By writing every hour, we write about 50% more data, but we are only spending 20% more time writing.
On master we write about 42 MiB every 24 hours which locks the main thread for 2.3 seconds.
On this branch we write about 2.7 MiB every hour which locks the main thread for 115 milliseconds.
So it's about 0.9 MiB more data written every hour, which I think is a negligible amount. Note that this extra data is ephemeral and will be erased as these extra utxos are spent. It will not cause nodes to have to store more data.

Here are the write operations charts for the time period. You can see the write operations are more evenly spaced out by writing every hour.
Master 1
Master 2
Branch 2
Branch 1

@andrewtoth
andrewtoth force-pushed the write-chainstate-every-hour branch from 1c1b63a to ff9c90b Compare September 2, 2024 02:23
@andrewtoth

Copy link
Copy Markdown
Contributor Author

@gmaxwell @l0rinc @mzumsande @sipa thank you all for your reviews! I've updated the PR to have a random window for periodic flushes of between 50 and 70 minutes. I've also added a unit test that checks for a flush in this window. That unit test can be cherry-picked to master and verified that it does not pass.

@andrewtoth
andrewtoth force-pushed the write-chainstate-every-hour branch from ff9c90b to 5cad9d1 Compare September 2, 2024 04:12
@l0rinc

l0rinc commented Sep 2, 2024

Copy link
Copy Markdown
Contributor

The test runs unreliably for some reason, we need to fix that first.

NACK 5cad9d16dd07859a76c6637789695bf1b4f36e1c

On this branch [...] main thread for 115 milliseconds.

This sounds awesome!

Good point, I can add a test that that expects flush every 24 hours, then reduce it to 1 hour after this change.

Do you think we could still do something like this, i.e. add a test as a very first commit, which reproduces the old behavior first?

Comment thread src/validation.cpp Outdated
Comment thread src/test/chainstate_write_tests.cpp Outdated
Comment thread src/test/chainstate_write_tests.cpp Outdated
Comment thread src/validation.cpp Outdated
Comment thread src/validation.cpp Outdated
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 17, 2025
Summary:
This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@0ad7d7a
Depends on D18638

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18639
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 17, 2025
Summary:
Remove the 24 hour periodic flush interval and write the chainstate along with blocks and block index every hour.

From the PR description:
> Since #28233, periodically writing the chainstate to disk every 24 hours does not clear the dbcache. Since #28280, periodically writing the chainstate to disk is proportional only to the amount of dirty entries in the cache. Due to these changes, it is no longer beneficial to only write the chainstate to disk every 24 hours. The periodic flush interval was necessary because every write of the chainstate would clear the dbcache. Now, we can get rid of the periodic flush interval and simply write the chainstate along with blocks and block index at least every hour.
>
> Three benefits of doing this:
> - For IBD or reindex-chainstate with a combination of large dbcache setting, slow CPU, slow internet speed/unreliable peers, it could be up to 24 hours until the chainstate is persisted to disk. A power outage or crash could potentially lose up to 24 hours of progress. If there is a very large amount of dirty cache entries, writing to disk when a flush finally does occur will take a very long time. Crashing during this window of writing can cause  "Rolling forward" at startup can take a long time, and is not interruptible (after unclean shutdown) #11600. By syncing every hour in unison with the block index we avoid this problem. Only a maximum of one hour of progress can be lost, and the window for crashing during writing is much smaller. For IBD with lower dbcache settings, faster CPU, or better internet speed/reliable peers, chainstate writes are already triggered more often than every hour so this change will have no effect on IBD.
> - Based on discussion in "Don't empty dbcache on prune flushes: >30% faster IBD #28280", writing only once every 24 hours during long running operation of a node causes IO spikes. Writing smaller chainstate changes every hour like we do with blocks and block index will reduce IO spikes.
> - Faster shutdown speeds. All dirty chainstate entries must be persisted to disk on shutdown. If we have a lot of dirty entries, such as when close to 24 hours or if we sync with a large dbcache, it can take a long time to shutdown. By keeping the chainstate clean we avoid this problem.

A tradeoff is that now we write slightly more data to the disk that will be deleted again an hour later, as utxos are often short-lived.

> By writing every hour, we write about 50% more data, but we are only spending 20% more time writing.
> On master we write about 42 MiB every 24 hours which locks the main thread for 2.3 seconds.
> On this branch we write about 2.7 MiB every hour which locks the main thread for 115 milliseconds.
> So it's about 0.9 MiB more data written every hour, which I think is a negligible amount. Note that this extra data is ephemeral and will be erased as these extra utxos are spent. It will not cause nodes to have to store more data.

This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@d73bd9f
Depends on D18639

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18640
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 17, 2025
Summary:
This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@b557fa7
Depends on D18640

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18641
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 17, 2025
Summary:
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@2e2f410

Depends on D18641

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18642
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 17, 2025
Summary:
From the PR discussion:

> One related idea: maybe we should randomize the sync event times a bit (say, uniformly random intervals between 50 and 70 minutes) to prevent a situation where the network over time settles into a few cohorts of synchronized syncers (think like communicating metronomes: they start randomly, but have synchronized events (blocks arriving) that slightly delay sync events if they were to coincide).

Co-Authored-By: Pieter Wuille <pieter@wuille.net>
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>

This concludes backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@e976bd3
Depends on D18642

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18643
bug-castercv502 added a commit to bug-castercv502/rust-bitcoinkernel that referenced this pull request Sep 28, 2025
…417e0b3b1b0

1417e0b3b1b0 kernel: Fix bitcoin-chainstate for windows
4f07590a8bd6 kernel: Add Purpose section to header documentation
58c01a82c163 kernel: Add pure kernel bitcoin-chainstate
0416a292f545 kernel: Add functions to get the block hash from a block
8d25dfd1b2a2 kernel: Add block index utility functions to C header
eacf99dd3c28 kernel: Add function to read block undo data from disk to C header
3c012048c2f1 kernel: Add functions to read block from disk to C header
85f5264462e0 kernel: Add function for copying block data to C header
f136ca589153 kernel: Add functions for the block validation state to C header
9d7e19ee522d kernel: Add validation interface to C header
51555301a882 kernel: Add interrupt function to C header
61c4ac9c8e1f kernel: Add import blocks function to C header
4153ab77084e kernel: Add chainstate load options for in-memory dbs in C header
cb128288a0d9 kernel: Add options for reindexing in C header
7ead2a92be50 kernel: Add block validation to C header
9262ce715448 kernel: Add chainstate loading when instantiating a ChainstateManager
594b060da476 kernel: Add chainstate manager option for setting worker threads
7384b7325d5f kernel: Add chainstate manager object to C header
7920e23c22b8 kernel: Add notifications context option to C header
c0a86769e784 kernel: Add chain params context option to C header
3769d12882f9 kernel: Add kernel library context object
f7b435493bd7 kernel: Add logging to kernel library C header
62d0122c7ed0 kernel: Introduce initial kernel C header API
88b22acc3d6f Merge bitcoin/bitcoin#32528: rpc: Round verificationprogress to 1 for a recent tip
aee7cec0db8f Merge bitcoin/bitcoin#32364: refactor: validation: mark CheckBlockIndex as const
ce4600071243 Merge bitcoin/bitcoin#32509: qa: feature_framework_startup_failures.py fixes & improvements (#30660 follow-up)
d21612fc4b77 Merge bitcoin/bitcoin#32404: log: print reason when writing chainstate
9bd9aee5a656 Merge bitcoin/bitcoin#32487: blocks: avoid recomputing block header hash in `ReadBlock`
4173805a15c1 Merge bitcoin/bitcoin#32623: test: Add missing ipc subtree to lint
012f347685b8 Merge bitcoin/bitcoin#31375: multiprocess: Add bitcoin wrapper executable
38ad8027a26f Merge bitcoin/bitcoin#32439: guix: accomodate migration to codeberg
fa4b8b16c378 test: Add missing ipc subtree to lint
f7cc7f6468af Merge bitcoin/bitcoin#32591: test: fix and augment block tests of invalid_txs
87860143be79 Merge bitcoin/bitcoin#32270: test: fix pushdata scripts
c8d9baae942c guix: accomodate migration to codeberg
09ee8b7f2786 node: avoid recomputing block hash in `ReadBlock`
2bf173210fa1 test: exercise `ReadBlock` hash‑mismatch path
fab1e02086ce refactor: Pass verification_progress into block tip notifications
638a4c0bd8b5 Merge bitcoin/bitcoin#32596: wallet, rpc, doc: various legacy wallet removal cleanups in RPCs
53e9b71b2fd5 log: print reason for why should_write was triggered in `FlushStateToDisk`
e5cbea416b2f rpc: doc: remove redundant "descriptors" parameter in `createwallet` examples
7a05f941bb2c rpc: doc: drop descriptor wallet mentions in fast wallet rescan related RPCs
db465a50e23d wallet, rpc: remove obsolete "keypoololdest" result field/code
2df824f4e62b Merge bitcoin/bitcoin#32586: ci: Downgrade DEBUG=1 to -D_GLIBCXX_ASSERTIONS in centos task
0a8ab559514f Merge bitcoin/bitcoin#32467: checkqueue: make the queue non-optional for CCheckQueueControl and drop legacy locking macro usage
8fcd68450523 test: ensure reason is checked for invalid blocks rejection
1a689a2c8871 test: fix block tests of invalid_txs
d2c9fc84e171 Merge bitcoin/bitcoin#32533: test: properly check for per-tx sigops limit
fa079538e32d ci: Downgrade DEBUG=1 to -D_GLIBCXX_ASSERTIONS in centos task
35bf3f88398d Merge bitcoin/bitcoin#32400: random: Use modern Windows randomness functions
a42faa25d8f7 Merge bitcoin/bitcoin#32551: cmake: Remove `ENABLE_{SSE41,AVX2,X86_SHANI,ARM_SHANI}` from `bitcoin-build-config.h`
87ec923d3a7a Merge bitcoin/bitcoin#32475: wallet: Use `util::Error` throughout `AddWalletDescriptor` instead of returning `nullptr` for some errors
7763e86afa04 Merge bitcoin/bitcoin#32573: ci: Avoid && dropping errors
0a56ed1ac868 Merge bitcoin/bitcoin#32567: subprocess: Backport upstream changes
54e406a3055a Merge bitcoin/bitcoin#32459: qt: drop unused watch-only functionality
ec8120469430 Merge bitcoin/bitcoin#31622: psbt: add non-default sighash types to PSBTs and unify sighash type match checking
fab97f583f11 ci: Avoid && dropping errors
9a887baadebc Merge bitcoin/bitcoin#32344: Wallet:  Fix Non-Ranged Descriptors with Range [0,0] Trigger Unexpected Wallet Errors in AddWalletDescriptor
26fba39bda47 Merge bitcoin/bitcoin#32466: threading: drop CSemaphore in favor of c++20 std::counting_semaphore
878556947b0d Merge bitcoin/bitcoin#32333: doc: Add missing top-level description to pruneblockchain RPC
fd290730f530 validation: clean up and clarify CheckInputScripts logic
fad009af49c4 Merge bitcoin/bitcoin#32520: Remove legacy `Parse(U)Int*`
f66b14d2ecb0 test: fix pushdata scripts
0f9baba0fb6e Merge bitcoin/bitcoin#29868: Reintroduce external signer support for Windows
cf2cbfac6599 Merge bitcoin/bitcoin#32553: wallet: Fix logging of wallet version
bc4b04c5bfb4 Merge bitcoin/bitcoin#31864: doc: add missing copyright headers
e63a7034f038 subprocess: Don't add an extra whitespace at end of Windows command line
800b7cc42ca6 cmake: Add missed `SSE41_CXXFLAGS`
028476e71fdc cmake: Remove `ENABLE_ARM_SHANI` from `bitcoin-build-config.h`
1e900528d245 cmake: Remove `ENABLE_X86_SHANI` from `bitcoin-build-config.h`
8689628e2e36 cmake: Remove `ENABLE_AVX2` from `bitcoin-build-config.h`
a8e2342dca5e cmake: Remove `ENABLE_SSE41` from `bitcoin-build-config.h`
fa76b378e4b2 rpc: Round verificationprogress to exactly 1 for a recent tip
faf6304bdfdf test: Use mockable time in GuessVerificationProgress
c7c3bfadfc6e doc: add & amend copyright headers
f667000c83e7 contrib: remove outdated entries from copyright_header.py
0817f2d6cf52 doc: update MIT license URL
6854497b47ce contrib: remove GPL-3+ from debian/copyright
af65fd1a3330 Merge bitcoin/bitcoin#32560: ci: Move DEBUG=1 to centos task
548f6b8cdef5 Merge bitcoin/bitcoin#32562: doc: remove // for ... comments
7c87a0e3fb1b Merge bitcoin/bitcoin#32477: lint: Check for missing trailing newline
faf55fc80b11 doc: Remove ParseInt mentions in documentation
785e1407b0a3 wallet: Use util::Error throughout AddWalletDescriptor
1a3750789540 validation: use a lock for CCheckQueueControl
c3b0e6c7f482 validation: make CCheckQueueControl's CCheckQueue non-optional
4c8c90b5567a validation: only create a CCheckQueueControl if it's actually going to be used
11fed833b3ed threading: add LOCK_ARGS macro
33f8f8ae4ced Merge bitcoin/bitcoin#30221: wallet: Ensure best block matches wallet scan state
7054d24f119a Merge bitcoin-core/gui#875: Use WitnessV0KeyHash in TestAddAddressesToSendBook
4272966d0234 Merge bitcoin/bitcoin#32423: rpc: Undeprecate rpcuser/rpcpassword, store all credentials hashed in memory
7193245cd667 doc: remove For ... comments
33332829333b refactor: Remove unused Parse(U)Int*
1b9cdc933f6c net: drop win32 ifdef
19ba499b1f38 init: cerrno is used on all platforms
fa982f142544 Use WitnessV0KeyHash in TestAddAddressesToSendBook
fa58d6cdab00 ci: Move DEBUG=1 to centos task
ff1ee102c4ba Merge bitcoin/bitcoin#32561: doc: Adjust stale MSVC bug url
fa330a5e38a8 doc: Adjust stale MSVC bug url
88791fb97bc3 Merge bitcoin/bitcoin#32544: scripted-diff: test: remove 'descriptors=True' argument for `createwallet` calls
e8661aac752e wallet: drop watch-only things from interface
e99188e7daa1 qt: drop unused watch-only functionality
4b2cd0b41ff4 test: check that creating a wallet does not log version info
39a483c8e9dc test: Check that the correct versions are logged on wallet load
359ecd370499 walletdb: Log the wallet version after it has been read from disk
86de8c166800 scripted-diff: test: remove 'descriptors=True' argument for `createwallet` calls
7710a31f0cb6 Merge bitcoin/bitcoin#32452: test: Remove legacy wallet RPC overloads
b81e5076aa56 Merge bitcoin/bitcoin#32514: scripted-diff: Remove unused leading newline in RPC docs
3023d7e6ad52 Merge bitcoin/bitcoin#32534: Update leveldb subtree to latest upstream
fa84e6c36cb0 bitcoin-tx: Reject + sign in MutateTxDel*
face2519fac9 bitcoin-tx: Reject + sign in vout parsing
fa8acaf0b993 bitcoin-tx: Reject + sign in replaceable parsing
faff25a558ab bitcoin-tx: Reject + sign in locktime
dddd9e5fe38b bitcoin-tx: Reject + sign in nversion parsing
fab06ac03788 rest: Use SAFE_CHARS_URI in SanitizeString error msg
c461d1528758 Merge bitcoin/bitcoin#32511: refactor: bdb removals
b15c386933eb Merge bitcoin/bitcoin#32519: ci: Enable feature_init and wallet_reorgsrestore in valgrind task
7015052eba23 build: remove Wsuggest-override suppression from leveldb build
7bc64a8859c3 test: properly check for per-tx sigops limit
3f83c744ac28 Merge bitcoin/bitcoin#32526: fuzz: Delete wallet_notifications
fa1f10a49e7c doc: Fix minor typos in rpc help
0769c8fc999f Update leveldb subtree to latest upstream
e2c84b896fad Squashed 'src/leveldb/' changes from 4188247086..113db4962b
04c6c961b657 Merge bitcoin/bitcoin#32527: test: Remove unused verify_flags suppression
742b30549fc9 Merge bitcoin/bitcoin#32491: build: document why we check for `std::system`
fab5a3c803c7 test: Remove unused verify_flags suppression
c521192d8b9e Merge bitcoin/bitcoin#32485: Update minisketch subtree
3afde679c3b2 Merge bitcoin/bitcoin#32296: refactor: reenable `implicit-integer-sign-change` check for `serialize.h`
5af757bb7841 Merge bitcoin/bitcoin#32505: depends: bump to latest config.guess and config.sub
c60455a6458c Merge bitcoin/bitcoin#32500: init: drop `-upnp`
e230affaa321 Merge bitcoin/bitcoin#32396: cmake: Add application manifests when cross-compiling for Windows
51be79c42b7e Merge bitcoin/bitcoin#32238: qt, wallet: Convert uint256 to Txid
f96ae941a1db Merge bitcoin/bitcoin#32525: build: Revert "Temporarily disable compiling `fuzz/utxo_snapshot.cpp` with MSVC
fad2faf6c5d8 fuzz: Delete wallet_notifications
bf950c4544d3 qa: Improve suppressed errors output
075352ec8e57 qa: assert_raises_message() - search in str(e)
bd8ebbc4ab6a qa: Make --timeout-factor=0 result in a smaller factor
fa2c66236267 build: Revert "Temporarily disable compiling `fuzz/utxo_snapshot.cpp` with MSVC"
8888bb499dec rest: Reject + sign in /blockhashbyheight/
fafd43c69192 test: Reject + sign when parsing regtest deployment params
fa123afa0ef7 Reject + sign when checking -ipcfd
fa479857ed23 Reject + sign in SplitHostPort
fab4c2967d55 net: Reject + sign when parsing subnet mask
fa89652e68fc init: Reject + sign in -*port parsing
fa9c45577dfb cli: Reject + sign in -netinfo level parsing
fa980413257e refactor: Use ToIntegral in CreateFromDump
fa23ed7fc242 refactor: Use ToIntegral in ParseHDKeypath
fa2be605fee4 ci: Enable feature_init and wallet_reorgsrestore in valgrind task
725c9f7780e0 Merge bitcoin/bitcoin#31895: doc: Improve `dependencies.md`
bdc1cef1de84 Merge bitcoin/bitcoin#32507: ci: Exclude failing wallet_reorgsrestore.py from valgrind task for now
fae840e94b79 rpc: Reject beginning newline in RPC docs
e62423d6f151 doc: Improve dependencies.md documentation
a3520f9d561e doc: Add dependency self-compilation info
d1fdc84c5493 doc: Remove Linux Kernel from dep. table
135a0f0aa711 doc: Add missing top-level description to pruneblockchain RPC
fa414eda0834 scripted-diff: Remove unused leading newline in RPC docs
fafee8535839 remove unused GetDestinationForKey
fac72fef27de remove unused GetAllDestinationsForKey
fa91d57de36d remove unused AddrToPubKey
8f4fed7ec700 symbol-check: Add check for application manifest in Windows binaries
2bb6ab8f1baa ci: Add "Get bitcoind manifest" steps to Windows CI jobs
282b4913c7e4 cmake: Add application manifests when cross-compiling for Windows
faecf158d997 remove unused Import* function signatures
d8f05e7bf3ec qa: Fix dormant bug caused by multiple --tmpdir
fa981b90f531 ci: Exclude failing wallet_reorgsrestore.py from valgrind task for now
c779ee3a4044 Merge bitcoin/bitcoin#32492: test: add skip_if_running_under_valgrind()
89c7b6b97ab4 Merge bitcoin/bitcoin#32498: doc: remove Carls substitute server from Guix docs
6b4bcc162345 random: Use modern Windows randomness functions
31d3eebfb92a Merge bitcoin/bitcoin#32343: common: Close non-std fds before exec in RunCommandJSON
486bc9179072 depends: bump to latest config.sub
6880383427b4 depends: bump to latest config.guess
4b26ca0e2f1e Merge bitcoin/bitcoin#32502: wallet: Drop unused fFromMe from CWalletTx
d5786bc19a9f Merge bitcoin/bitcoin#32490: refactor: Remove UB in prevector reverse iterators
ee045b61efc1 rpc, psbt: Require sighashes match for descriptorprocesspsbt
2b7682c3729d psbt: use sighash type field to determine whether to remove non-witness utxos
28781b5f0670 psbt: Add sighash types to PSBT when not DEFAULT or ALL
15ce1bd73f80 psbt: Enforce sighash type of signatures matches psbt
1f71cd337ad7 wallet: Remove sighash type enforcement from FillPSBT
4c7d767e49b2 psbt: Check sighash types in SignPSBTInput and take sighash as optional
a11825694856 script: Add IsPayToTaproot()
d6001dcd4ada wallet: change FillPSBT to take sighash as optional
e58b680923b1 psbt: Return PSBTError from SignPSBTInput
2adfd8153257 tests: Test PSBT sighash type mismatch
5a5d26d6123e psbt: Require ECDSA signatures to be validly encoded
53eb5593f0a1 Merge bitcoin/bitcoin#32305: test: add test for decoding PSBT with MuSig2 PSBT key types (BIP 373)
e7a937237686 Merge bitcoin/bitcoin#32378: interfaces: refactor: move `Mining` and `BlockTemplate`  implementation to miner
5bf91ba8800d wallet: Drop unused fFromMe from CWalletTx
30a94b1ab9ae test, wallet: Remove concurrent writes test
b44b7c03fef0 wallet: Write best block record on unload
876a2585a8b6 wallet: Remove unnecessary database Close step on shutdown
98a1a5275c8c wallet: Remove chainStateFlushed
7fd3e1cf0c88 wallet, bench: Write a bestblock record in WalletMigration
6d3a8b195a82 wallet: Replace chainStateFlushed in loading with SetLastBlockProcessed
7bacabb204b6 wallet: Update best block record after block dis/connect
301993ebf7f8 init: drop -upnp
3b824169c776 doc: remove Carls substitute server from Guix docs
f1d78a3087fb Merge bitcoin/bitcoin#31624: doc: warn that CheckBlock() underestimates sigops
516f0689b511 refactor: re-enable UBSan implicit-sign-change in serialize.h
5827e9350779 refactor: use consistent size type for serialization template parameters
62fc42d475df interfaces: refactor: move `waitTipChanged` implementation to miner
c39ca9d4f7bc interfaces: move getTip implementation to miner
33dfbbdff69d Merge bitcoin/bitcoin#32483: test: fix two intermittent failures in wallet_basic.py
8a65f0389464 Merge bitcoin/bitcoin#32488: fuzz: Properly setup wallet in wallet_fees target
75a185ea3db3 test: add skip_if_running_under_valgrind()
8f4ba90b8ff4 build: document why we check for std::system
faf9082a5f68 test: Fix whitespace in prevector_tests.cpp
fa7f04c8a7b7 refactor: Remove UB in prevector reverse iterators
fa427ffceeef fuzz: Properly setup wallet in wallet_fees target
f9d8910539a2 Merge bitcoin/bitcoin#31080: fees: document non-monotonic estimation edge case
31650b458b6c Merge bitcoin/bitcoin#32386: mining: rename gbt_force and gbt_force_name
bac43b957e5f Merge bitcoin/bitcoin#32312: test: Fix feature_pruning test after nTime typo fix
c9ab10910cd7 Merge bitcoin/bitcoin#31444: cluster mempool: add txgraph diagrams/mining/eviction
e7ad86e1ca3b test: fix another intermittent failure in wallet_basic.py
07350e204ded test: Fix intermittent failure in wallet_basic.py
46b533dfe6fc Update minisketch subtree to latest upstream
bf25a0918f94 Squashed 'src/minisketch/' changes from d1e6bb8bbf..ea8f66b1ea
8309a9747a8d Merge bitcoin/bitcoin#32028: Update `secp256k1` subtree to latest master
720f201e6528 interfaces: refactor: move `waitNext` implementation to miner
e6c2f4ce7a84 interfaces: refactor: move `submitSolution` implementation to miner
02d4bc776bbe interfaces: remove redundant coinbase fee check in `waitNext`
fa9198af55df lint: Check for missing trailing newline
fa2b2aa27c29 lint: Add archived notes to default excludes
cbd8e3d51148 Merge bitcoin/bitcoin#32476: refactor: Remove unused HaveKey and HaveWatchOnly
915c1fa72c07 Update secp256k1 subtree to latest master
c31fcaaad38b Squashed 'src/secp256k1/' changes from 0cdc758a56..4187a46649
fabdc5ad06bc Remove unused LegacyDataSPKM::HaveWatchOnly()
fa7b7f796ac8 Remove HaveKey helper, unused after sethdseed removal
8673e8f01917 txgraph: Special-case singletons in chunk index (optimization)
abdd9d35a34d txgraph: Skipping end of cluster has no impact (optimization)
604acc2c289f txgraph: Reuse discarded chunkindex entries (optimization)
c734081454d7 txgraph: Introduce TxGraph::GetWorstMainChunk (feature)
394dbe21427e txgraph: Introduce BlockBuilder interface (feature)
883df3648ee9 txgraph: Generalize GetClusterRefs to support subsections (preparation)
c28a602e007f txgraph: Introduce TxGraphImpl observer tracking (preparation)
9095d8ac1c31 txgraph: Maintain chunk index (preparation)
87e74e1242ec txgraph: abstract out transaction ordering (refactor)
2614fea17fe3 txgraph: Add GetMainStagingDiagrams function (feature)
a5ac43d98d1a doc: Add release notes describing bitcoin wrapper executable
663a9cabf811 Merge bitcoin/bitcoin#32458: guix: move `*-check.py` scripts under contrib/guix/
258bda80c009 doc: Mention bitcoin wrapper executable in documentation
d2739d75c911 build: add bitcoin.exe to windows installer
ba649c00063a ci: Run multiprocess tests through wrapper executable
29bdd743bb84 test: Support BITCOIN_CMD environment variable
9c8c68891b43 multiprocess: Add bitcoin wrapper executable
5076d20fdb70 util: Add cross-platform ExecVp and GetExePath functions
05765b8818cf Merge bitcoin/bitcoin#32472: doc: Fix typo
d847e17c9656 doc: Fix typo
3edf400b1020 Merge bitcoin/bitcoin#32469: cmake: Allow `WITH_DBUS` on all Unix-like systems
59e09e0fb7b4 Merge bitcoin-core/gui#871: qt, docs: Unify term "clipboard"
46f79dde67e4 Merge bitcoin-core/gui#841: Decouple WalletModel from RPCExecutor
5b7ed460c7c1 cmake: Allow `WITH_DBUS` on all Unix-like systems
746ab19d5a13 Merge bitcoin/bitcoin#32446: build: simplify *ifaddr handling
6f7052a7b96f threading: semaphore: move CountingSemaphoreGrant to its own header
fd1546989293 threading: semaphore: remove temporary convenience types
1f89e2a49a21 scripted-diff: threading: semaphore: use direct types rather than the temporary convenience ones
f21365c4fc7f threading: replace CountingSemaphore with std::counting_semaphore
1acacfbad780 threading: make CountingSemaphore/CountingSemaphoreGrant template types
e6ce5f9e7874 scripted-diff: rename CSemaphore and CSemaphoreGrant
793166d3810e wallet: change the write semaphore to a BinarySemaphore
6790ad27f157 scripted-diff: rename CSemaphoreGrant and CSemaphore for net
d870bc94519a threading: add temporary semaphore aliases
19b1e177d673 Merge bitcoin/bitcoin#32155: miner: timelock the coinbase to the mined block's height
6c6ef58b0b22 Merge bitcoin/bitcoin#32436: test: refactor: negate signature-s using libsecp256k1
b104d4422770 test: Remove RPCOverloadWrapper
4d32c19516fd test: Replace importpubkey
fe838dd391be test: Replace usage of addmultisigaddress
d3142077794f test: Replace usage of importaddress
fcc457573f9b test: Replace importprivkey with wallet_importprivkey
94c87bbbd06e test: Remove unnecessary importprivkey from wallet_createwallet
9a05b45da60d Merge bitcoin/bitcoin#32438: refactor: Removals after bdb removal
e49a7274a214 rpc: Avoid join-split roundtrip for user:pass for auth credentials
98ff38a6f1a8 rpc: Perform HTTP user:pass split once in `RPCAuthorized`
879a17bcb1a5 rpc: Store all credentials hashed in memory
4ab9bedee9d8 rpc: Undeprecate rpcuser/rpcpassword, change message to security warning
fa061bfcdb0c Remove create options from wallet tool
fa2125e7b8e3 Remove unused IsSingleKey
fab5e2a0948a doc: Remove note about bdb wallets
eeeef88d46fe doc: fix typo in abortrescan rpc
fa7e5c15a795 Remove unused LegacyDataSPKM::DeleteRecords()
b070ce16966f Merge bitcoin/bitcoin#31360: depends: Avoid using helper variables in toolchain file
ffff94947298 remove NotifyWatchonlyChanged
fa62a013a558 remove dead flush()
fa5f3e62c880 vcpkg: Remove bdb
415650cea94f guix: move *-check.py scripts under contrib/guix
5b8752198e97 Merge bitcoin/bitcoin#32454: tracing: fix invalid argument in mempool_monitor
31c5ebc40078 tracing: fix invalid argument in mempool_monitor
ad5cd129f3cc Merge bitcoin/bitcoin#30660: qa: Verify clean shutdown on startup failure
7b816c4e00e2 threading: rename CSemaphore methods to match std::semaphore
1656f6dbba86 Merge bitcoin/bitcoin#32448: contrib: remove bdb exception from FORTIFY check
a04f17a18824 doc: warn that CheckBlock() underestimates sigops
ab878a7e7410 build: simplify *ifaddr handling
1b4ddb0c2d10 Merge bitcoin/bitcoin#32356: cmake: Respect user-provided configuration-specific flags
1ee698fde2e8 test: refactor: negate signature-s using libsecp256k1
f9dfe8d5e0d3 contrib: remove bdb exception from FORTIFY check
66c968b4b4a9 Merge bitcoin/bitcoin#32444: doc: swap "Docker image" for "container image"
646975295237 Merge bitcoin/bitcoin#32434: lint: Remove string exclusion from locale check
1372eb09c5d0 doc: swap "Docker image" for "container image"
03ebdd079302 Merge bitcoin/bitcoin#32437: crypto: disable ASan for sha256_sse4 with Clang
95bb305b96a8 Merge bitcoin/bitcoin#32429: docs: Improve `keypoolrefill` RPC docs
1b1b9f32cfdb Merge bitcoin/bitcoin#32440: test: remove bdb assert in tool_wallet.py
e08e6567f2e7 test: remove assert_dump since it is not used anymore
ff35a4b021e1 docs: Improve `keypoolrefill` RPC docs
4b2418675672 test: add test for decoding PSBT with MuSig2 PSBT key types (BIP 373)
8ba245cb8318 test: add constants for MuSig2 PSBT key types (BIP 373)
4b6dd9790b66 test: remove bdb assert in tool_wallet.py
97d383af6d54 Test updating non-ranged descriptor with [0,0] range succeeds
7343a1846ceb depends: Avoid using helper variables in toolchain file
0671d66a8ee0 wallet, refactor: Convert uint256 to Txid in wallet
c8ed51e62be9 wallet, refactor: Convert uint256 to Txid in wallet interfaces
b3214cefe6d8 qt, refactor: Convert uint256 to Txid in the GUI
efac285a0d70 Merge bitcoin/bitcoin#28710: Remove the legacy wallet and BDB dependency
fa24fdcb7f47 lint: Remove string exclusion from locale check
4e8ab5e00fa7 crypto: disable ASan for sha256_sse4 with Clang
6d5edfcc585b Merge bitcoin/bitcoin#32388: fuzz: Remove unused TimeoutExpired catch in fuzz runner
de054df6dc32 contrib: Remove legacy wallet RPCs from bash completions
5dff04a1bba8 legacy spkm: Make IsMine() and CanProvide() private and migration only
c0f3f3264ff7 wallet: Remove unused db functions
83af1a3cca7e wallet: Delete LegacySPKM
59d3e4ed34eb Merge bitcoin/bitcoin#32415: scripted-diff: adapt script error constant names in feature_taproot.py
fffb272c2587 Merge bitcoin/bitcoin#29532: Refactor BnB tests
3bbdbc0a5e1b qt, docs: Unify term "clipboard"
8ede6dea0c55 wallet, rpc: Remove legacy wallet only RPCs
4de3cec28dfb test: rpcs disabled for descriptor wallets will be removed
84f671b01df4 test: Run multisig script limit test
810476f31e42 test: Remove unused options and variables, correct comments
04a7a7a28cdc build, wallet, doc: Remove BDB
44057fe38ccc Merge bitcoin/bitcoin#32287: build: Fix `macdeployqtplus` after switching to Qt 6
229943b51368 Merge bitcoin/bitcoin#32086: Shuffle depends instructions and recommend modern make for macOS
3e6ac5bf7727 refactor: validation: mark CheckBlockIndex as const
61a51eccbba1 validation: don't use GetAll() in CheckBlockIndex()
edde96376a29 cmake: Respect user-provided configuration-specific flags
22cff32319de doc: recommend gmake for FreeBSD
b645c520714c doc: recommend modern make for macOS depends
99e6490dc51a doc: shuffle depends instructions
1e0de7a6ba92 fees: document non-monotonic estimation edge case
baa848b8d381 Merge bitcoin/bitcoin#32405: build: replace header checks with `__has_include`
3a18075aedd7 ci: Drop `-DENABLE_EXTERNAL_SIGNER=ON` configure option
719fa9f4ef68 build: Re-enable external signer support for Windows
6e5fc2bf9b18 test: Reintroduce Windows support in `system_tests/run_command` test
53ccb75f0c47 Merge bitcoin/bitcoin#32358: subprocess: Backport upstream changes
fa2c5484296f Merge bitcoin/bitcoin#32417: doc: Explain that .gitignore is not for IDE-specific excludes
fada115cbeaa doc: Explain that .gitignore is not for IDE-specific excludes
b5f580c58025 scripted-diff: adapt script error constant names in feature_taproot.py
eba5f9c4b63f Merge bitcoin/bitcoin#32403: test: remove Boost SIGCHLD workaround.
e1f543823b30 build: replace header checks with __has_include
3add6ab9adcd test: remove Boost SIGCHLD workaround.
cd95c9d6a7ec subprocess: check and handle fcntl(F_GETFD) failure
b7288decdf53 subprocess: Proper implementation of wait() on Windows
7423214d8dee subprocess: Do not escape double quotes for command line arguments on Windows
bb9ffea53fb0 subprocess: Explicitly define move constructor of Streams class
174bd43f2e46 subprocess: Avoid leaking POSIX name aliases beyond `subprocess.h`
7997b7656f99 subprocess: Fix cross-compiling with mingw toolchain
647630462f10 subprocess: Get Windows return code in wait()
d3f511b4583b subprocess: Fix string_arg when used with rref
2fd3f2fec67a subprocess: Fix memory leaks
5b8046a6e893 Merge bitcoin/bitcoin#30611: validation: write chainstate to disk every hour
fc6346dbc8dc Merge bitcoin/bitcoin#32389: doc: Fix test_bitcoin path
a0eed55398f8 run_command: Enable close_fds option to avoid lingering fds
c7c356a44865 cpp-subprocess: Iterate through /proc/self/fd for close_fds option on Linux
4f5e04da1350 Revert "remove unneeded close_fds option from cpp-subprocess"
6cbc28b8dd62 doc: Fix test_bitcoin path
85368aafa0d1 test: Run simple tests at various feerates
d610951c1546 test: Recreate BnB iteration exhaustion test
2a1b2754f14a test: Remove redundant repeated test
4781f5c8be55 test: Recreate simple BnB failure tests
a94030ae985b test: Recreate BnB clone skipping test
7db6f012c08c test: Move BnB feerate sensitivity tests
2bafc462610c test: Recreate simple BnB success tests
e976bd304501 validation: add randomness to periodic write interval
2e2f41068128 refactor: replace m_last_write with m_next_write
b557fa7a175f refactor: rename fDoFullFlush to should_write
d73bd9fbe483 validation: write chainstate to disk every hour
68ac9f116c02 Merge bitcoin/bitcoin#32383: util: Remove `fsbridge::get_filesystem_error_message()`
fa4804009ceb fuzz: Remove unused TimeoutExpired catch in fuzz runner
0750249289c0 mining: document gbt_rule_value helper
5e87c3ec094d scripted-diff: rename gbt_force and gbt_force_name
97eaadc3bf9f util: Remove `fsbridge::get_filesystem_error_message()`
14b8dfb2bd5e Merge bitcoin/bitcoin#31398: wallet: refactor: various master key encryption cleanups
a60445cd04c8 Merge bitcoin/bitcoin#32355: Bugfix: Miner: Don't reuse block_reserved_weight for "block is full enough to give up" weight delta
2d5b4244147b Merge bitcoin/bitcoin#32351: test: avoid stack overflow in `FindChallenges` via manual iteration
0ed5f37afef1 Merge bitcoin/bitcoin#31014: net: Use GetAdaptersAddresses to get local addresses on Windows
7a4a2a38ea37 Merge bitcoin/bitcoin#27826: validation: log which peer sent us a header
4694732bc4c3 Merge bitcoin/bitcoin#32338: net: remove unnecessary check from AlreadyConnectedToAddress()
7db096121d37 Merge bitcoin/bitcoin#29039: versionbits refactoring
51d76634fb57 Merge bitcoin/bitcoin#32365: descriptors: Reject + sign while parsing unsigned
c5e44a043563 Merge bitcoin/bitcoin#32369: test: Use the correct node for doubled keypath test
32d55e28af69 test: Use the correct node for doubled keypath test
65714c162c16 Merge bitcoin/bitcoin#32327: test: Add missing check for empty stderr in util tester
a4eee6d50be0 Merge bitcoin/bitcoin#29124: test: Test that migration automatically repairs corrupted metadata with doubled derivation path
af6cffa36d12 Merge bitcoin/bitcoin#32350: test: Slim down previous releases bdb check
33e6538b3076 Merge bitcoin/bitcoin#32360: test: Force named args for RPCOverloadWrapper optional args
3a29ba33dca6 Merge bitcoin/bitcoin#32357: depends: Fix cross-compiling `qt` package from macOS to Windows
fa655da15987 test: [refactor] Use ToIntegral in CheckInferDescriptor
fa55dd01df83 descriptors: Reject + sign when parsing multi threshold
fa6f77ed3c15 descriptors: Reject + sign in ParseKeyPathNum
7e8ef959d063 refactor: Fix Sonar rule `cpp:S4998` - avoid unique_ptr const& as parameter
e400ac53524d refactor: simplify repeated comparisons in `FindChallenges`
f670836112c0 test: remove old recursive `FindChallenges_recursive` implementation
b80d0bdee460 test: avoid stack overflow in `FindChallenges` via manual iteration
fa48be3ba443 test: Force named args for RPCOverloadWrapper optional args
aaaa45399ca3 test: Remove unused createwallet_passthrough
d05481df644c refactor: validation: mark SnapshotBase as const
f409444d0243 Merge bitcoin/bitcoin#32071: build: Drop option to disable hardening.
cccc1f4e9190 test: Remove unused RPCOverloadWrapper is_cli field
d62c2d82e14d Merge bitcoin/bitcoin#32353: doc: Fix fuzz test_runner.py path
10845cd7cc89 qa: Add feature_framework_startup_failures.py
35e57fbe336c depends: Fix cross-compiling `qt` package from macOS to Windows
d2ac748e9e7a Merge bitcoin-core/gui#864: Crash fix, disconnect numBlocksChanged() signal during shutdown
524f981bb873 Bugfix: Miner: Don't reuse block_reserved_weight for "block is full enough to give up" weight delta
84de8c93e7d4 ci: Add `deploy` target for native macOS CI job
fad57e9e0fe2 build: Fix `macdeployqtplus` after switching to Qt 6
de90b47ea098 Merge bitcoin-core/gui#868: Replace stray tfm::format to cerr with qWarning
a58cb3b1c12c qa: sanity check mined block have their coinbase timelocked to height
8f2078af6a55 miner: timelock coinbase transactions
788aeebf3435 qa: use prev height as nLockTime for coinbase txs created in unit tests
c76dbe9b8b6f qa: timelock coinbase transactions created in fuzz targets
9c94069d8b6c contrib: timelock coinbase transactions in signet miner
a5f52cfcc400 qa: timelock coinbase transactions created in functional tests
61f238e84ac6 doc: Fix fuzz test_runner.py path
c7e2b9e26444 tests: Test migration cleans up bad inactive chain derivation path
fa58f40b898b test: Slim down previous releases bdb check
f1b142856a4e test: Same addr, diff port is already connected
94e85a82a753 net: remove unnecessary check from AlreadyConnectedToAddress()
28e282ef9ae9 qa: assert_raises_message() - Stop assuming certain structure for exceptions
80e6ad9e3023 Merge bitcoin/bitcoin#31250: wallet: Disable creating and loading legacy wallets
971952588dae Merge bitcoin/bitcoin#32242: guix: Remove unused `file` package
ff69046e664f Merge bitcoin/bitcoin#32215: depends: Fix cross-compiling on macOS
2ae1788dd46a Skip range verification for non-ranged desc
4eee328a9820 Merge bitcoin/bitcoin#32318: Fix failing util_time_GetTime test on Windows
71656bdfaa6b gui: crash fix, disconnect numBlocksChanged() signal during shutdown
3dbd50a576be Fix failing util_time_GetTime test on Windows
edd46566bd66 qt: Replace stray tfm::format to cerr with qWarning
458720e5e98c Merge bitcoin/bitcoin#32336: test: Suppress upstream `-Wduplicate-decl-specifier` in bpfcc
facb9b327b9d scripted-diff: Use bpf_cflags
fa0c1baaf898 test: Add imports for util bpf_cflags
9efe54668858 Merge bitcoin/bitcoin#31835: validation: set BLOCK_FAILED_CHILD correctly
bd158ab4e35c Merge bitcoin/bitcoin#32023: wallet: removed duplicate call to GetDescriptorScriptPubKeyMan
17bb63f9f9b0 wallet: Disallow loading legacy wallets
9f04e02ffaee wallet: Disallow creating legacy wallets
6b247279b72d wallet: Disallow legacy wallet creation from the wallet tool
5e93b1fd6c1e bench: Remove WalletLoadingLegacy benchmark
56f959d829e9 wallet: Remove wallettool salvage
7a41c939f05f wallet: Remove -format and bdb from wallet tool's createfromdump
c847dee1488a test: remove legacy wallet functional tests
20a9173717b1 test: Remove legacy wallet tests from wallet_reindex.py
446d480cb22c test: Remove legacy wallet tests from wallet_backwards_compatibility.py
aff80298d05c test: wallet_signer.py bdb will be removed
f94f9399ac47 test: Remove legacy wallet unit tests
d9ac9dbd8ef5 tests, gui: Use descriptors watchonly wallet for watchonly test
9a4c92eb9ac2 Merge bitcoin/bitcoin#32226: ci: switch to LLVM 20 in tidy job
82d1e94838ee Merge bitcoin/bitcoin#32310: test: Run all benchmarks in the sanity check
dda2d4e17662 Merge bitcoin/bitcoin#32113: fuzz: enable running fuzz test cases in Debug mode
faca46b0421b test: Run all benchmarks in the sanity check
fadf12a56c29 test: Add missing check for empty stderr in util tester
08aa7fe23263 ci: clang-tidy 20
2b85d31bcc2f refactor: starts/ends_with changes for clang-tidy 20
3669ecd4ccd8 doc: Document fuzz build options
c1d01f59acc2 fuzz: enable running fuzz test cases in Debug mode
1f639efca5e7 qa: Work around Python socket timeout issue
2aa63d511aff test: Use uninvolved pruned node in feature_pruning undo test
772ba7f9ce09 test: Fix nTimes typo in feature_pruning test
9b24a403fae4 qa: Only allow calling TestNode.stop() after connecting
6ad21b4c0114 qa: Include ignored errors in RPC connection timeout
879243e81fd5 qa refactor: wait_for_rpc_connection - Treat OSErrors the same
513e2020a9ac guix: Remove unused `file` package
938208d91a27 build: Resolve `@rpath` in `macdeployqtplus`
abe43dfadd63 doc: release note for #27826
f9fa28788e63 Use LogBlockHeader for compact blocks
bad7c9147931 Log which peer sent us a header
9d3e39c29c31 Log block header in net_processing
d0cce4172c04 depends: Fix `mv` command compatibility with macOS
690f5da15a1e depends: Specify Objective C/C++ compilers for `native_qt` package
3c3548a70eed validation: clarify final |= BLOCK_FAILED_VALID in InvalidateBlock
aac5488909f7 validation: correctly update BlockStatus for invalid block descendants
9e29653b424b test: check BlockStatus when InvalidateBlock is used
c99667583dd9 validation: fix traversal condition to mark BLOCK_FAILED_CHILD
77e553ab6a0a build: refactor: hardening flags -> core_interface
00ba3ba30341 build: Drop option for disabling hardening
f57db75e91de build: Use `-z noseparate-code` on NetBSD < 11.0
55b931934a34 removed duplicate calling of GetDescriptorScriptPubKeyMan
e3014017bacf test: add IsActiveAfter tests for versionbits
60950f77c35e versionbits: docstrings for BIP9Info
b9d4d5f66a5a net: Use GetAdaptersAddresses to get local addresses on Windows
a8333fc9ff9a scripted-diff: wallet: rename plain and encrypted master key variables
5a92077fd531 wallet: refactor: dedup master key decryption
846545947cd3 wallet: refactor: dedup master key encryption / derivation rounds setting
a6d9b415aa3a wallet: refactor: introduce `CMasterKey::DEFAULT_DERIVE_ITERATIONS` constant
62c209f50d9c wallet: doc: remove mentions of unavailable scrypt derivation method
7565563bc7a5 tests: refactor versionbits fuzz test
2e4e9b9608c7 tests: refactor versionbits unit test
525c00f91bb2 versionbits: Expose VersionBitsConditionChecker via impl header
e74a7049b477 versionbits: Expose StateName function
d00d1ed52c8e versionbits: Split out internal details into impl header
37b9b67a3955 versionbits: Simplify VersionBitsCache API
1198e7d2fd66 versionbits: Move BIP9 status logic for getblocktemplate to versionbits
b1e967c3ec92 versionbits: Move getdeploymentinfo logic to versionbits
3bd32c20550e versionbits: Move WarningBits logic from validation to versionbits
5da119e5d0e6 versionbits: Change BIP9Stats to uint32_t types
a679040ec19e consensus/params: Move version bits period/threshold to bip9 param
0ad7d7abdbcf test: chainstate write test for periodic chainstate flush
e9d617095d4c versionbits: Remove params from AbstractThresholdConditionChecker
9bc41f1b48b2 versionbits: Use std::array instead of C-style arrays
002b792b9a85 gui: decouple WalletModel from RPCExecutor
REVERT: 4a4eeb94339b kernel: Fix bitcoin-chainstate for windows
REVERT: 9eb5d74b2d03 kernel: Add Purpose section to header documentation
REVERT: 7cf01306523b kernel: Add pure kernel bitcoin-chainstate
REVERT: 51aad49acdfe kernel: Add functions to get the block hash from a block
REVERT: a6ed3dec4d1d kernel: Add block index utility functions to C header
REVERT: 7aaefbbb3937 kernel: Add function to read block undo data from disk to C header
REVERT: 9535ffadba5c kernel: Add functions to read block from disk to C header
REVERT: 321ce88607fd kernel: Add function for copying block data to C header
REVERT: a15d107250f8 kernel: Add functions for the block validation state to C header
REVERT: f9f9a86402b1 kernel: Add validation interface to C header
REVERT: bac152a4fbe5 kernel: Add interrupt function to C header
REVERT: e1f204cb0de0 kernel: Add import blocks function to C header
REVERT: 75f25fa1b0b4 kernel: Add chainstate load options for in-memory dbs in C header
REVERT: 68acd5e0e904 kernel: Add options for reindexing in C header
REVERT: 04be23481105 kernel: Add block validation to C header
REVERT: 3cdc538d77d0 kernel: Add chainstate loading when instantiating a ChainstateManager
REVERT: a5a47d95e597 kernel: Add chainstate manager option for setting worker threads
REVERT: 5052b9bd823b kernel: Add chainstate manager object to C header
REVERT: 82f4769656b1 kernel: Add notifications context option to C header
REVERT: 7e32f6a9e897 kernel: Add chain params context option to C header
REVERT: af442d0d6cb1 kernel: Add kernel library context object
REVERT: e1a6c1b5b928 kernel: Add logging to kernel library C header
REVERT: 3339e6ca6a5f kernel: Introduce initial kernel C header API

git-subtree-dir: libbitcoinkernel-sys/bitcoin
git-subtree-split: 1417e0b3b1b03dd014a3459c10a5ae7ab0c3687f
glozow added a commit that referenced this pull request Oct 31, 2025
…32 MiB

b6f8c48 coins: increase default `dbbatchsize` to 32 MiB (Lőrinc)
8bbb7b8 refactor: Extract default batch size into kernel (Lőrinc)

Pull request description:

  This change is part of [[IBD] - Tracking PR for speeding up Initial Block Download](#32043)

  ### Summary

  When the in-memory UTXO set is flushed to LevelDB (after IBD or AssumeUTXO load), it does so in batches to manage memory usage during the flush.
  A hidden `-dbbatchsize` config option exists to modify this value. This PR only changes the default from `16` MiB to `32` MiB.
  Using a larger default reduces the overhead of many small writes and improves I/O efficiency (especially on HDDs). It may also help LevelDB optimize writes more effectively (e.g., via internal ordering).
  The change is meant to speed up a critical part of IBD: dumping the accumulated work to disk.

  ### Context

  The UTXO set has grown significantly since [2017](https://github.com/bitcoin/bitcoin/pull/10148/files#diff-d102b6032635ce90158c1e6e614f03b50e4449aa46ce23370da5387a658342fdR26-R27), when the original fixed 16 MiB batch size was chosen.

  With the current multi-gigabyte UTXO set and the common practice of using larger `-dbcache` values, the fixed 16 MiB batch size leads to several inefficiencies:

  * Flushing the entire UTXO set often requires thousands of separate 16 MiB write operations.
  * Particularly on HDDs, the cumulative disk seek time and per-operation overhead from numerous small writes significantly slow down the flushing process.
  * Each `WriteBatch` call incurs internal LevelDB overhead (e.g., MemTable handling, compaction triggering logic). More frequent, smaller batches amplify this cumulative overhead.

  Flush times of 20-30 minutes are not uncommon, even on capable hardware.

  ### Considerations

  As [noted by sipa](#31645 (comment)), flushing involves a temporary memory usage increase as the batch is prepared. A larger batch size naturally leads to a larger peak during this phase. Crashing due to OOM during a flush is highly undesirable, but now that [#30611](#30611) is merged, the most we'd lose is the first hour of IBD.

  Increasing the LevelDB write batch size from 16 to 32 MiB raised the measured peaks by ~70 MiB in my tests during UTXO dump. The option remains hidden, and users can always override it.

  The increased peak memory usage (detailed below) is primarily attributed to LevelDB's `leveldb::Arena` (backing MemTables) and the temporary storage of serialized batch data (e.g., `std::string` in `CDBBatch::WriteImpl`).

  Performance gains are most pronounced on systems with slower I/O (HDDs), but some SSDs also show measurable improvements.

  ### Measurements:

  AssumeUTXO proxy, multiple runs with error bars (flushing time is faster that the measured loading + flushing):
  * Raspberry Pi, dbcache=500: ~30% faster with 32 MiB vs 16 MiB, peak +~75 MiB and still < 1 GiB.
  * i7 + HDD: results vary by dbcache, but 32 MiB usually beats 16 MiB and tracks close to 64 MiB without the larger peak.
  * i9 + fast NVMe: roughly flat across 16/32/64 MiB. The goal here is to avoid regressions, which holds.

  ### Reproducer:

  ```bash
  # Set up a clean demo environment
  rm -rfd demo && mkdir -p demo

  # Build Bitcoin Core
  cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc)

  # Start bitcoind with minimal settings without mempool and internet connection
  build/bin/bitcoind -datadir=demo -stopatheight=1
  build/bin/bitcoind -datadir=demo -blocksonly=1 -connect=0 -dbcache=3000 -daemon

  # Load the AssumeUTXO snapshot, making sure the path is correct
  # Expected output includes `"coins_loaded": 184821030`
  build/bin/bitcoin-cli -datadir=demo -rpcclienttimeout=0 loadtxoutset ~/utxo-880000.dat

  # Stop the daemon and verify snapshot flushes in the logs
  build/bin/bitcoin-cli -datadir=demo stop
  grep "FlushSnapshotToDisk: completed" demo/debug.log
  ```

  ---

  This PR originally proposed 64 MiB, then a dynamic size, but both were dropped: 64 MiB increased peaks more than desired on low-RAM systems, and the dynamic variant underperformed across mixed hardware. 32 MiB is a simpler default that captures most of the gains with a modest peak increase.

  For more details see: #31645 (comment)
  ---

  While the PR isn't about IBD in general, rather about a critical section of it, I have measured a reindex-chainstate until 900k blocks, showing a 1% overall speedup:

  <details>
  <summary>Details</summary>

  ```python
  COMMITS="e6bfd95d5012fa1d91f83bf4122cb292afd6277f af653f321b135a59e38794b537737ed2f4a0040b"; \
  STOP=900000; DBCACHE=10000; \
  CC=gcc; CXX=g++; \
  BASE_DIR="/mnt/my_storage"; DATA_DIR="$BASE_DIR/BitcoinData"; LOG_DIR="$BASE_DIR/logs"; \
  (echo ""; for c in $COMMITS; do git fetch -q origin $c && git log -1 --pretty='%h %s' $c || exit 1; done; echo "") && \
  hyperfine \
    --sort command \
    --runs 1 \
    --export-json "$BASE_DIR/rdx-$(sed -E 's/(\w{8})\w+ ?/\1-/g;s/-$//'<<<"$COMMITS")-$STOP-$DBCACHE-$CC.json" \
    --parameter-list COMMIT ${COMMITS// /,} \
    --prepare "killall bitcoind 2>/dev/null; rm -f $DATA_DIR/debug.log; git checkout {COMMIT}; git clean -fxd; git reset --hard && \
      cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release && ninja -C build bitcoind && \
      ./build/bin/bitcoind -datadir=$DATA_DIR -stopatheight=$STOP -dbcache=1000 -printtoconsole=0; sleep 10" \
    --cleanup "cp $DATA_DIR/debug.log $LOG_DIR/debug-{COMMIT}-$(date +%s).log" \
    "COMPILER=$CC ./build/bin/bitcoind -datadir=$DATA_DIR -stopatheight=$STOP -dbcache=$DBCACHE -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0"

  e6bfd95 Merge bitcoin-core/gui#881: Move `FreespaceChecker` class into its own module
  af653f321b coins: derive `batch_write_bytes` from `-dbcache` when unspecified

  Benchmark 1: COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = e6bfd95)
    Time (abs ≡):        25016.346 s               [User: 30333.911 s, System: 826.463 s]

  Benchmark 2: COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = af653f321b135a59e38794b537737ed2f4a0040b)
    Time (abs ≡):        24801.283 s               [User: 30328.665 s, System: 834.110 s]

  Relative speed comparison
          1.01          COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = e6bfd95)
          1.00          COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = af653f321b135a59e38794b537737ed2f4a0040b)
  ```

  </details>

ACKs for top commit:
  laanwj:
    Concept and code review ACK b6f8c48
  TheCharlatan:
    ACK b6f8c48
  andrewtoth:
    ACK b6f8c48

Tree-SHA512: a72008feca866e658f0cb4ebabbeee740f9fb13680e517b9d95eaa136e627a9dd5ee328456a2bf040401f4a1977ffa7446ad13f66b286b3419ff0c35095a3521
achow101 added a commit that referenced this pull request Dec 11, 2025
…hainstate

c1e554d refactor: consolidate 3 separate locks into one block (Andrew Toth)
41479ed test: add test for periodic flush inside ActivateBestChain (Andrew Toth)
8482056 validation: periodically flush dbcache during reindex-chainstate (Andrew Toth)

Pull request description:

  After #30611 we periodically do a non-erasing flush of the dbcache to disk roughly every hour during IBD.
  The intention was to also do this periodic flush during reindex-chainstate, so we would not risk losing progress during a system failure when reindexing with a high dbcache value.

  It was discovered that reindex-chainstate does not perform a PERIODIC flush until it has already reached the tip. Since reindexing to tip usually happens within 24 hours, this behaviour was unnoticed with the previous periodic flush interval. Note that reindex-chainstate still does IF_NEEDED flushes during `ConnectBlock`, so this also would not be noticed when running with a lower dbcache value.

  This patch moves the PERIODIC flush from after the outer loop in `ActivateBestChain` to inside the outer loop after we release `cs_main`. This will periodically flush during IBD, reindex-chainstate, and steady state.

ACKs for top commit:
  l0rinc:
    ACK c1e554d
  achow101:
    ACK c1e554d
  sipa:
    utACK c1e554d

Tree-SHA512: c447ad03e16c9978b8ed2c285b38e1b4c56e7778ab93b6f64435116f47b8931017f5f56ab53eb61656693146aaced776f666af573a41ab28e8f2b6d8657fa756
@l0rinc l0rinc mentioned this pull request Jan 14, 2026
13 tasks
roqqit pushed a commit to doged-io/doged that referenced this pull request Jun 3, 2026
Summary:
This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@0ad7d7a
Depends on D18638

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18639
roqqit pushed a commit to doged-io/doged that referenced this pull request Jun 3, 2026
Summary:
Remove the 24 hour periodic flush interval and write the chainstate along with blocks and block index every hour.

From the PR description:
> Since #28233, periodically writing the chainstate to disk every 24 hours does not clear the dbcache. Since #28280, periodically writing the chainstate to disk is proportional only to the amount of dirty entries in the cache. Due to these changes, it is no longer beneficial to only write the chainstate to disk every 24 hours. The periodic flush interval was necessary because every write of the chainstate would clear the dbcache. Now, we can get rid of the periodic flush interval and simply write the chainstate along with blocks and block index at least every hour.
>
> Three benefits of doing this:
> - For IBD or reindex-chainstate with a combination of large dbcache setting, slow CPU, slow internet speed/unreliable peers, it could be up to 24 hours until the chainstate is persisted to disk. A power outage or crash could potentially lose up to 24 hours of progress. If there is a very large amount of dirty cache entries, writing to disk when a flush finally does occur will take a very long time. Crashing during this window of writing can cause  "Rolling forward" at startup can take a long time, and is not interruptible (after unclean shutdown) #11600. By syncing every hour in unison with the block index we avoid this problem. Only a maximum of one hour of progress can be lost, and the window for crashing during writing is much smaller. For IBD with lower dbcache settings, faster CPU, or better internet speed/reliable peers, chainstate writes are already triggered more often than every hour so this change will have no effect on IBD.
> - Based on discussion in "Don't empty dbcache on prune flushes: >30% faster IBD #28280", writing only once every 24 hours during long running operation of a node causes IO spikes. Writing smaller chainstate changes every hour like we do with blocks and block index will reduce IO spikes.
> - Faster shutdown speeds. All dirty chainstate entries must be persisted to disk on shutdown. If we have a lot of dirty entries, such as when close to 24 hours or if we sync with a large dbcache, it can take a long time to shutdown. By keeping the chainstate clean we avoid this problem.

A tradeoff is that now we write slightly more data to the disk that will be deleted again an hour later, as utxos are often short-lived.

> By writing every hour, we write about 50% more data, but we are only spending 20% more time writing.
> On master we write about 42 MiB every 24 hours which locks the main thread for 2.3 seconds.
> On this branch we write about 2.7 MiB every hour which locks the main thread for 115 milliseconds.
> So it's about 0.9 MiB more data written every hour, which I think is a negligible amount. Note that this extra data is ephemeral and will be erased as these extra utxos are spent. It will not cause nodes to have to store more data.

This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@d73bd9f
Depends on D18639

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18640
roqqit pushed a commit to doged-io/doged that referenced this pull request Jun 3, 2026
Summary:
This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@b557fa7
Depends on D18640

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18641
roqqit pushed a commit to doged-io/doged that referenced this pull request Jun 3, 2026
Summary:
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
This is a partial backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@2e2f410

Depends on D18641

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18642
roqqit pushed a commit to doged-io/doged that referenced this pull request Jun 3, 2026
Summary:
From the PR discussion:

> One related idea: maybe we should randomize the sync event times a bit (say, uniformly random intervals between 50 and 70 minutes) to prevent a situation where the network over time settles into a few cohorts of synchronized syncers (think like communicating metronomes: they start randomly, but have synchronized events (blocks arriving) that slightly delay sync events if they were to coincide).

Co-Authored-By: Pieter Wuille <pieter@wuille.net>
Co-Authored-By: l0rinc <pap.lorinc@gmail.com>

This concludes backport of [[bitcoin/bitcoin#30611 | core#30611]]
bitcoin/bitcoin@e976bd3
Depends on D18642

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D18643
l0rinc added a commit to l0rinc/bitcoin that referenced this pull request Jun 25, 2026
The randomized periodic chainstate write interval was tuned around one hour in bitcoin#30611 and made more visible during long activation loops in bitcoin#32414.

In bitcoin#32414, the max-dbcache HDD `-reindex-chainstate` benchmark showed the hourly cadence made the best-case memory-hoarding path 11% slower, while a 100-minute experiment reduced that slowdown to 7%.

Recent measurements show why the exact cadence matters on slower storage too.

Force-compacting a pruned chainstate took 13m31s on an rpi4 SSD and 1h38m on an rpi5 SD card.

Those force-compaction numbers are not typical periodic-flush durations, but they show that chainstate maintenance can be extremely expensive on target hardware.

A rpi5-8 pruned IBD benchmark of this change showed an almost 10% speedup.

Increase the periodic write window from 50-70 minutes to 90-110 minutes.

This keeps the average close to 100 minutes, about 10 blocks in steady state, while reducing forced full-cache writes on the best-case max-dbcache path.

PR bitcoin#35465 tied randomized post-flush compaction to the hourly flush cadence.

Retune the full-flush compaction chance from 1/320 to 1/200 so it still averages roughly every two weeks at a 100-minute flush interval, and document that missing compaction for roughly 200 days is a one-in-a-million event.
Kino1994 pushed a commit to Kino1994/bitcoin-full-history that referenced this pull request Jun 28, 2026
… flushes

b1b4582 coins: warn on shutdown for big UTXO set flushes (Lőrinc)

Pull request description:

  Split out of bitcoin/bitcoin#30611 (comment)

  Setting a large `-dbcache` size postpones the index writes until the coins cache size exceeds the specified limit. This causes the final flush after manual termination to seemingly hang forever (e.g. tens of minutes for 20 GiB); Now that the `dbcache` upper cap has been lifted, this will become even more apparent, so a warning will be shown when large UTXO sets are flushed (currently >1 GiB), such as:
  > 2024-12-18T18:25:03Z Flushed fee estimates to fee_estimates.dat.
  > 2024-12-18T18:25:03Z [warning] Flushing large (1 GiB) UTXO set to disk, it may take several minutes
  > 2024-12-18T18:25:09Z Shutdown: done

  ---

  You can reproduce it by starting `bitcoind` with a large `-dbcache`:
  > mkdir demo  && cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) && build/src/bitcoind -datadir=demo **-dbcache=10000**

  Waiting until the used memory is over 1 GiB
  > 2024-12-18T18:25:02Z UpdateTip: [...] progress=0.069009 cache=**1181.1MiB**(8827981txo)

  And cancelling the process from the terminal:
  > ^C2024-12-18T18:25:03Z tor: Thread interrupt
  > [...]
  > 2024-12-18T18:25:03Z **[warning] Flushing large (1 GiB) UTXO set to disk, it may take several minutes*

ACKs for top commit:
  sipa:
    utACK b1b4582
  tdb3:
    re ACK b1b4582
  1440000bytes:
    ACK bitcoin/bitcoin@b1b4582
  danielabrozzoni:
    tACK b1b4582

Tree-SHA512: 608cf797de788501ccb2986508c155f5660c5f6f7a414524bfcc2820cfa9ebe3da558d13f2317d1f121a82d49ffe1e711a1152c743c22dab9f9807363f4ed8d5
Kino1994 pushed a commit to Kino1994/bitcoin-full-history that referenced this pull request Jun 28, 2026
…ry hour

4c95a7d validation: add randomness to periodic write interval (Andrew Toth)
954ca36 refactor: replace m_last_write with m_next_write (Andrew Toth)
369e572 refactor: rename fDoFullFlush to should_write (Andrew Toth)
73a588d validation: write chainstate to disk every hour (Andrew Toth)
e48bd56 test: chainstate write test for periodic chainstate flush (Andrew Toth)

Pull request description:

  Since #28233, periodically writing the chainstate to disk every 24 hours does not clear the dbcache. Since #28280, periodically writing the chainstate to disk is proportional only to the amount of dirty entries in the cache. Due to these changes, it is no longer beneficial to only write the chainstate to disk every 24 hours. The periodic flush interval was necessary because every write of the chainstate would clear the dbcache. Now, we can get rid of the periodic flush interval and simply write the chainstate along with blocks and block index at least every hour.

  Three benefits of doing this:
  1. For IBD or reindex-chainstate with a combination of large dbcache setting, slow CPU, slow internet speed/unreliable peers, it could be up to 24 hours until the chainstate is persisted to disk. A power outage or crash could potentially lose up to 24 hours of progress. If there is a very large amount of dirty cache entries, writing to disk when a flush finally does occur will take a very long time. Crashing during this window of writing can cause bitcoin/bitcoin#11600. By syncing every hour in unison with the block index we avoid this problem. Only a maximum of one hour of progress can be lost, and the window for crashing during writing is much smaller. For IBD with lower dbcache settings, faster CPU, or better internet speed/reliable peers, chainstate writes are already triggered more often than every hour so this change will have no effect on IBD.
  2. Based on discussion in #28280, writing only once every 24 hours during long running operation of a node causes IO spikes. Writing smaller chainstate changes every hour like we do with blocks and block index will reduce IO spikes.
  3. Faster shutdown speeds. All dirty chainstate entries must be persisted to disk on shutdown. If we have a lot of dirty entries, such as when close to 24 hours or if we sync with a large dbcache, it can take a long time to shutdown. By keeping the chainstate clean we avoid this problem.

  Inspired by [this comment](bitcoin/bitcoin#28280 (comment)).

  Resolves bitcoin/bitcoin#11600

ACKs for top commit:
  achow101:
    ACK 4c95a7d
  davidgumberg:
    utACK bitcoin/bitcoin@4c95a7d
  sipa:
    utACK 4c95a7d
  l0rinc:
    ACK  4c95a7d

Tree-SHA512: 5bccd8f1dea47f9820a3fd32fe3bb6841c0167b3d6870cc8f3f7e2368f124af1a914bca6acb06889cd7183638a8dbdbace54d3237c3683f2b567eb7355e015ee
Kino1994 pushed a commit to Kino1994/bitcoin-full-history that referenced this pull request Jun 28, 2026
5b4c4dc log: print reason for why should_write was triggered in `FlushStateToDisk` (Lőrinc)

Pull request description:

  This PR addresses a leftover logging nit found while reviewing bitcoin/bitcoin#30611 (review).
  This was also needed to validate its behavior properly, because currently there's no way to visualize how often (and why) we're flushing/syncing.

  Starting with `-debug=coindb` will now add log lines such as
  ```
  2025-05-03T08:34:57Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T09:26:52Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T10:27:58Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T11:39:20Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T12:41:48Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T13:40:08Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T14:49:16Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T15:14:37Z [coindb] Writing chainstate to disk: flush mode=ALWAYS, prune=0, large=0, critical=0, periodic=0
  2025-05-03T15:17:28Z [coindb] Writing chainstate to disk: flush mode=ALWAYS, prune=0, large=0, critical=0, periodic=0
  ```

ACKs for top commit:
  davidgumberg:
    ACK bitcoin/bitcoin@5b4c4dc
  jonatack:
    diff-only review ACK 5b4c4dc per `git range-diff 2df824 cfc8056 5b4c4dc`
  achow101:
    ACK 5b4c4dc
  andrewtoth:
    utACK 5b4c4dc

Tree-SHA512: 09f3a38cf3ecaa32cf3aba350a9e9dff9345c5468a05070c8b20987f0fdb23a8b1dc59370829c64ea356d2fc0ce99a66cc7240de7fa8c19ef3133da06db6bf3d
Kino1994 pushed a commit to Kino1994/bitcoin-full-history that referenced this pull request Jun 28, 2026
… batch size to 32 MiB

4235728 coins: increase default `dbbatchsize` to 32 MiB (Lőrinc)
875ba15 refactor: Extract default batch size into kernel (Lőrinc)

Pull request description:

  This change is part of [[IBD] - Tracking PR for speeding up Initial Block Download](bitcoin/bitcoin#32043)

  ### Summary

  When the in-memory UTXO set is flushed to LevelDB (after IBD or AssumeUTXO load), it does so in batches to manage memory usage during the flush.
  A hidden `-dbbatchsize` config option exists to modify this value. This PR only changes the default from `16` MiB to `32` MiB.
  Using a larger default reduces the overhead of many small writes and improves I/O efficiency (especially on HDDs). It may also help LevelDB optimize writes more effectively (e.g., via internal ordering).
  The change is meant to speed up a critical part of IBD: dumping the accumulated work to disk.

  ### Context

  The UTXO set has grown significantly since [2017](https://github.com/bitcoin/bitcoin/pull/10148/files#diff-d102b6032635ce90158c1e6e614f03b50e4449aa46ce23370da5387a658342fdR26-R27), when the original fixed 16 MiB batch size was chosen.

  With the current multi-gigabyte UTXO set and the common practice of using larger `-dbcache` values, the fixed 16 MiB batch size leads to several inefficiencies:

  * Flushing the entire UTXO set often requires thousands of separate 16 MiB write operations.
  * Particularly on HDDs, the cumulative disk seek time and per-operation overhead from numerous small writes significantly slow down the flushing process.
  * Each `WriteBatch` call incurs internal LevelDB overhead (e.g., MemTable handling, compaction triggering logic). More frequent, smaller batches amplify this cumulative overhead.

  Flush times of 20-30 minutes are not uncommon, even on capable hardware.

  ### Considerations

  As [noted by sipa](bitcoin/bitcoin#31645 (comment)), flushing involves a temporary memory usage increase as the batch is prepared. A larger batch size naturally leads to a larger peak during this phase. Crashing due to OOM during a flush is highly undesirable, but now that [#30611](bitcoin/bitcoin#30611) is merged, the most we'd lose is the first hour of IBD.

  Increasing the LevelDB write batch size from 16 to 32 MiB raised the measured peaks by ~70 MiB in my tests during UTXO dump. The option remains hidden, and users can always override it.

  The increased peak memory usage (detailed below) is primarily attributed to LevelDB's `leveldb::Arena` (backing MemTables) and the temporary storage of serialized batch data (e.g., `std::string` in `CDBBatch::WriteImpl`).

  Performance gains are most pronounced on systems with slower I/O (HDDs), but some SSDs also show measurable improvements.

  ### Measurements:

  AssumeUTXO proxy, multiple runs with error bars (flushing time is faster that the measured loading + flushing):
  * Raspberry Pi, dbcache=500: ~30% faster with 32 MiB vs 16 MiB, peak +~75 MiB and still < 1 GiB.
  * i7 + HDD: results vary by dbcache, but 32 MiB usually beats 16 MiB and tracks close to 64 MiB without the larger peak.
  * i9 + fast NVMe: roughly flat across 16/32/64 MiB. The goal here is to avoid regressions, which holds.

  ### Reproducer:

  ```bash
  # Set up a clean demo environment
  rm -rfd demo && mkdir -p demo

  # Build Bitcoin Core
  cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc)

  # Start bitcoind with minimal settings without mempool and internet connection
  build/bin/bitcoind -datadir=demo -stopatheight=1
  build/bin/bitcoind -datadir=demo -blocksonly=1 -connect=0 -dbcache=3000 -daemon

  # Load the AssumeUTXO snapshot, making sure the path is correct
  # Expected output includes `"coins_loaded": 184821030`
  build/bin/bitcoin-cli -datadir=demo -rpcclienttimeout=0 loadtxoutset ~/utxo-880000.dat

  # Stop the daemon and verify snapshot flushes in the logs
  build/bin/bitcoin-cli -datadir=demo stop
  grep "FlushSnapshotToDisk: completed" demo/debug.log
  ```

  ---

  This PR originally proposed 64 MiB, then a dynamic size, but both were dropped: 64 MiB increased peaks more than desired on low-RAM systems, and the dynamic variant underperformed across mixed hardware. 32 MiB is a simpler default that captures most of the gains with a modest peak increase.

  For more details see: bitcoin/bitcoin#31645 (comment)
  ---

  While the PR isn't about IBD in general, rather about a critical section of it, I have measured a reindex-chainstate until 900k blocks, showing a 1% overall speedup:

  <details>
  <summary>Details</summary>

  ```python
  COMMITS="b22d6eb42b1ef3c29f8057c72045105dffbcc21d af653f321b135a59e38794b537737ed2f4a0040b"; \
  STOP=900000; DBCACHE=10000; \
  CC=gcc; CXX=g++; \
  BASE_DIR="/mnt/my_storage"; DATA_DIR="$BASE_DIR/BitcoinData"; LOG_DIR="$BASE_DIR/logs"; \
  (echo ""; for c in $COMMITS; do git fetch -q origin $c && git log -1 --pretty='%h %s' $c || exit 1; done; echo "") && \
  hyperfine \
    --sort command \
    --runs 1 \
    --export-json "$BASE_DIR/rdx-$(sed -E 's/(\w{8})\w+ ?/\1-/g;s/-$//'<<<"$COMMITS")-$STOP-$DBCACHE-$CC.json" \
    --parameter-list COMMIT ${COMMITS// /,} \
    --prepare "killall bitcoind 2>/dev/null; rm -f $DATA_DIR/debug.log; git checkout {COMMIT}; git clean -fxd; git reset --hard && \
      cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release && ninja -C build bitcoind && \
      ./build/bin/bitcoind -datadir=$DATA_DIR -stopatheight=$STOP -dbcache=1000 -printtoconsole=0; sleep 10" \
    --cleanup "cp $DATA_DIR/debug.log $LOG_DIR/debug-{COMMIT}-$(date +%s).log" \
    "COMPILER=$CC ./build/bin/bitcoind -datadir=$DATA_DIR -stopatheight=$STOP -dbcache=$DBCACHE -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0"

  b22d6eb Merge bitcoin-core/gui#881: Move `FreespaceChecker` class into its own module
  af653f321b coins: derive `batch_write_bytes` from `-dbcache` when unspecified

  Benchmark 1: COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = b22d6eb)
    Time (abs ≡):        25016.346 s               [User: 30333.911 s, System: 826.463 s]

  Benchmark 2: COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = af653f321b135a59e38794b537737ed2f4a0040b)
    Time (abs ≡):        24801.283 s               [User: 30328.665 s, System: 834.110 s]

  Relative speed comparison
          1.01          COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = b22d6eb)
          1.00          COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = af653f321b135a59e38794b537737ed2f4a0040b)
  ```

  </details>

ACKs for top commit:
  laanwj:
    Concept and code review ACK 4235728
  TheCharlatan:
    ACK 4235728
  andrewtoth:
    ACK 4235728

Tree-SHA512: a72008feca866e658f0cb4ebabbeee740f9fb13680e517b9d95eaa136e627a9dd5ee328456a2bf040401f4a1977ffa7446ad13f66b286b3419ff0c35095a3521
BigcoinBGC pushed a commit to BigcoinBGC/bigcoin that referenced this pull request Jun 30, 2026
… flushes

0a895bc coins: warn on shutdown for big UTXO set flushes (Lőrinc)

Pull request description:

  Split out of bitcoin/bitcoin#30611 (comment)

  Setting a large `-dbcache` size postpones the index writes until the coins cache size exceeds the specified limit. This causes the final flush after manual termination to seemingly hang forever (e.g. tens of minutes for 20 GiB); Now that the `dbcache` upper cap has been lifted, this will become even more apparent, so a warning will be shown when large UTXO sets are flushed (currently >1 GiB), such as:
  > 2024-12-18T18:25:03Z Flushed fee estimates to fee_estimates.dat.
  > 2024-12-18T18:25:03Z [warning] Flushing large (1 GiB) UTXO set to disk, it may take several minutes
  > 2024-12-18T18:25:09Z Shutdown: done

  ---

  You can reproduce it by starting `bitcoind` with a large `-dbcache`:
  > mkdir demo  && cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) && build/src/bitcoind -datadir=demo **-dbcache=10000**

  Waiting until the used memory is over 1 GiB
  > 2024-12-18T18:25:02Z UpdateTip: [...] progress=0.069009 cache=**1181.1MiB**(8827981txo)

  And cancelling the process from the terminal:
  > ^C2024-12-18T18:25:03Z tor: Thread interrupt
  > [...]
  > 2024-12-18T18:25:03Z **[warning] Flushing large (1 GiB) UTXO set to disk, it may take several minutes*

ACKs for top commit:
  sipa:
    utACK 0a895bc
  tdb3:
    re ACK 0a895bc
  1440000bytes:
    ACK bitcoin/bitcoin@0a895bc
  danielabrozzoni:
    tACK 0a895bc

Tree-SHA512: 608cf797de788501ccb2986508c155f5660c5f6f7a414524bfcc2820cfa9ebe3da558d13f2317d1f121a82d49ffe1e711a1152c743c22dab9f9807363f4ed8d5
BigcoinBGC pushed a commit to BigcoinBGC/bigcoin that referenced this pull request Jun 30, 2026
…ry hour

0e38866 validation: add randomness to periodic write interval (Andrew Toth)
6fa9cd9 refactor: replace m_last_write with m_next_write (Andrew Toth)
950f7fa refactor: rename fDoFullFlush to should_write (Andrew Toth)
ea06f1d validation: write chainstate to disk every hour (Andrew Toth)
daf4f91 test: chainstate write test for periodic chainstate flush (Andrew Toth)

Pull request description:

  Since #28233, periodically writing the chainstate to disk every 24 hours does not clear the dbcache. Since #28280, periodically writing the chainstate to disk is proportional only to the amount of dirty entries in the cache. Due to these changes, it is no longer beneficial to only write the chainstate to disk every 24 hours. The periodic flush interval was necessary because every write of the chainstate would clear the dbcache. Now, we can get rid of the periodic flush interval and simply write the chainstate along with blocks and block index at least every hour.

  Three benefits of doing this:
  1. For IBD or reindex-chainstate with a combination of large dbcache setting, slow CPU, slow internet speed/unreliable peers, it could be up to 24 hours until the chainstate is persisted to disk. A power outage or crash could potentially lose up to 24 hours of progress. If there is a very large amount of dirty cache entries, writing to disk when a flush finally does occur will take a very long time. Crashing during this window of writing can cause bitcoin/bitcoin#11600. By syncing every hour in unison with the block index we avoid this problem. Only a maximum of one hour of progress can be lost, and the window for crashing during writing is much smaller. For IBD with lower dbcache settings, faster CPU, or better internet speed/reliable peers, chainstate writes are already triggered more often than every hour so this change will have no effect on IBD.
  2. Based on discussion in #28280, writing only once every 24 hours during long running operation of a node causes IO spikes. Writing smaller chainstate changes every hour like we do with blocks and block index will reduce IO spikes.
  3. Faster shutdown speeds. All dirty chainstate entries must be persisted to disk on shutdown. If we have a lot of dirty entries, such as when close to 24 hours or if we sync with a large dbcache, it can take a long time to shutdown. By keeping the chainstate clean we avoid this problem.

  Inspired by [this comment](bitcoin/bitcoin#28280 (comment)).

  Resolves bitcoin/bitcoin#11600

ACKs for top commit:
  achow101:
    ACK 0e38866
  davidgumberg:
    utACK bitcoin/bitcoin@0e38866
  sipa:
    utACK 0e38866
  l0rinc:
    ACK  0e38866

Tree-SHA512: 5bccd8f1dea47f9820a3fd32fe3bb6841c0167b3d6870cc8f3f7e2368f124af1a914bca6acb06889cd7183638a8dbdbace54d3237c3683f2b567eb7355e015ee
BigcoinBGC pushed a commit to BigcoinBGC/bigcoin that referenced this pull request Jun 30, 2026
3a2afb9 log: print reason for why should_write was triggered in `FlushStateToDisk` (Lőrinc)

Pull request description:

  This PR addresses a leftover logging nit found while reviewing bitcoin/bitcoin#30611 (review).
  This was also needed to validate its behavior properly, because currently there's no way to visualize how often (and why) we're flushing/syncing.

  Starting with `-debug=coindb` will now add log lines such as
  ```
  2025-05-03T08:34:57Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T09:26:52Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T10:27:58Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T11:39:20Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T12:41:48Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T13:40:08Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T14:49:16Z [coindb] Writing chainstate to disk: flush mode=PERIODIC, prune=0, large=0, critical=0, periodic=1
  2025-05-03T15:14:37Z [coindb] Writing chainstate to disk: flush mode=ALWAYS, prune=0, large=0, critical=0, periodic=0
  2025-05-03T15:17:28Z [coindb] Writing chainstate to disk: flush mode=ALWAYS, prune=0, large=0, critical=0, periodic=0
  ```

ACKs for top commit:
  davidgumberg:
    ACK bitcoin/bitcoin@3a2afb9
  jonatack:
    diff-only review ACK 3a2afb9 per `git range-diff 2df824 cfc8056 3a2afb9`
  achow101:
    ACK 3a2afb9
  andrewtoth:
    utACK 3a2afb9

Tree-SHA512: 09f3a38cf3ecaa32cf3aba350a9e9dff9345c5468a05070c8b20987f0fdb23a8b1dc59370829c64ea356d2fc0ce99a66cc7240de7fa8c19ef3133da06db6bf3d
BigcoinBGC pushed a commit to BigcoinBGC/bigcoin that referenced this pull request Jun 30, 2026
… batch size to 32 MiB

3a6acea coins: increase default `dbbatchsize` to 32 MiB (Lőrinc)
2d5c938 refactor: Extract default batch size into kernel (Lőrinc)

Pull request description:

  This change is part of [[IBD] - Tracking PR for speeding up Initial Block Download](bitcoin/bitcoin#32043)

  ### Summary

  When the in-memory UTXO set is flushed to LevelDB (after IBD or AssumeUTXO load), it does so in batches to manage memory usage during the flush.
  A hidden `-dbbatchsize` config option exists to modify this value. This PR only changes the default from `16` MiB to `32` MiB.
  Using a larger default reduces the overhead of many small writes and improves I/O efficiency (especially on HDDs). It may also help LevelDB optimize writes more effectively (e.g., via internal ordering).
  The change is meant to speed up a critical part of IBD: dumping the accumulated work to disk.

  ### Context

  The UTXO set has grown significantly since [2017](https://github.com/bitcoin/bitcoin/pull/10148/files#diff-d102b6032635ce90158c1e6e614f03b50e4449aa46ce23370da5387a658342fdR26-R27), when the original fixed 16 MiB batch size was chosen.

  With the current multi-gigabyte UTXO set and the common practice of using larger `-dbcache` values, the fixed 16 MiB batch size leads to several inefficiencies:

  * Flushing the entire UTXO set often requires thousands of separate 16 MiB write operations.
  * Particularly on HDDs, the cumulative disk seek time and per-operation overhead from numerous small writes significantly slow down the flushing process.
  * Each `WriteBatch` call incurs internal LevelDB overhead (e.g., MemTable handling, compaction triggering logic). More frequent, smaller batches amplify this cumulative overhead.

  Flush times of 20-30 minutes are not uncommon, even on capable hardware.

  ### Considerations

  As [noted by sipa](bitcoin/bitcoin#31645 (comment)), flushing involves a temporary memory usage increase as the batch is prepared. A larger batch size naturally leads to a larger peak during this phase. Crashing due to OOM during a flush is highly undesirable, but now that [#30611](bitcoin/bitcoin#30611) is merged, the most we'd lose is the first hour of IBD.

  Increasing the LevelDB write batch size from 16 to 32 MiB raised the measured peaks by ~70 MiB in my tests during UTXO dump. The option remains hidden, and users can always override it.

  The increased peak memory usage (detailed below) is primarily attributed to LevelDB's `leveldb::Arena` (backing MemTables) and the temporary storage of serialized batch data (e.g., `std::string` in `CDBBatch::WriteImpl`).

  Performance gains are most pronounced on systems with slower I/O (HDDs), but some SSDs also show measurable improvements.

  ### Measurements:

  AssumeUTXO proxy, multiple runs with error bars (flushing time is faster that the measured loading + flushing):
  * Raspberry Pi, dbcache=500: ~30% faster with 32 MiB vs 16 MiB, peak +~75 MiB and still < 1 GiB.
  * i7 + HDD: results vary by dbcache, but 32 MiB usually beats 16 MiB and tracks close to 64 MiB without the larger peak.
  * i9 + fast NVMe: roughly flat across 16/32/64 MiB. The goal here is to avoid regressions, which holds.

  ### Reproducer:

  ```bash
  # Set up a clean demo environment
  rm -rfd demo && mkdir -p demo

  # Build Bitcoin Core
  cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc)

  # Start bitcoind with minimal settings without mempool and internet connection
  build/bin/bitcoind -datadir=demo -stopatheight=1
  build/bin/bitcoind -datadir=demo -blocksonly=1 -connect=0 -dbcache=3000 -daemon

  # Load the AssumeUTXO snapshot, making sure the path is correct
  # Expected output includes `"coins_loaded": 184821030`
  build/bin/bitcoin-cli -datadir=demo -rpcclienttimeout=0 loadtxoutset ~/utxo-880000.dat

  # Stop the daemon and verify snapshot flushes in the logs
  build/bin/bitcoin-cli -datadir=demo stop
  grep "FlushSnapshotToDisk: completed" demo/debug.log
  ```

  ---

  This PR originally proposed 64 MiB, then a dynamic size, but both were dropped: 64 MiB increased peaks more than desired on low-RAM systems, and the dynamic variant underperformed across mixed hardware. 32 MiB is a simpler default that captures most of the gains with a modest peak increase.

  For more details see: bitcoin/bitcoin#31645 (comment)
  ---

  While the PR isn't about IBD in general, rather about a critical section of it, I have measured a reindex-chainstate until 900k blocks, showing a 1% overall speedup:

  <details>
  <summary>Details</summary>

  ```python
  COMMITS="ca07be91689d6f18ce5b8833482622f6554775e2 af653f321b135a59e38794b537737ed2f4a0040b"; \
  STOP=900000; DBCACHE=10000; \
  CC=gcc; CXX=g++; \
  BASE_DIR="/mnt/my_storage"; DATA_DIR="$BASE_DIR/BitcoinData"; LOG_DIR="$BASE_DIR/logs"; \
  (echo ""; for c in $COMMITS; do git fetch -q origin $c && git log -1 --pretty='%h %s' $c || exit 1; done; echo "") && \
  hyperfine \
    --sort command \
    --runs 1 \
    --export-json "$BASE_DIR/rdx-$(sed -E 's/(\w{8})\w+ ?/\1-/g;s/-$//'<<<"$COMMITS")-$STOP-$DBCACHE-$CC.json" \
    --parameter-list COMMIT ${COMMITS// /,} \
    --prepare "killall bitcoind 2>/dev/null; rm -f $DATA_DIR/debug.log; git checkout {COMMIT}; git clean -fxd; git reset --hard && \
      cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release && ninja -C build bitcoind && \
      ./build/bin/bitcoind -datadir=$DATA_DIR -stopatheight=$STOP -dbcache=1000 -printtoconsole=0; sleep 10" \
    --cleanup "cp $DATA_DIR/debug.log $LOG_DIR/debug-{COMMIT}-$(date +%s).log" \
    "COMPILER=$CC ./build/bin/bitcoind -datadir=$DATA_DIR -stopatheight=$STOP -dbcache=$DBCACHE -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0"

  ca07be9 Merge bitcoin-core/gui#881: Move `FreespaceChecker` class into its own module
  af653f321b coins: derive `batch_write_bytes` from `-dbcache` when unspecified

  Benchmark 1: COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = ca07be9)
    Time (abs ≡):        25016.346 s               [User: 30333.911 s, System: 826.463 s]

  Benchmark 2: COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = af653f321b135a59e38794b537737ed2f4a0040b)
    Time (abs ≡):        24801.283 s               [User: 30328.665 s, System: 834.110 s]

  Relative speed comparison
          1.01          COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = ca07be9)
          1.00          COMPILER=gcc ./build/bin/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=900000 -dbcache=10000 -reindex-chainstate -blocksonly -connect=0 -printtoconsole=0 (COMMIT = af653f321b135a59e38794b537737ed2f4a0040b)
  ```

  </details>

ACKs for top commit:
  laanwj:
    Concept and code review ACK 3a6acea
  TheCharlatan:
    ACK 3a6acea
  andrewtoth:
    ACK 3a6acea

Tree-SHA512: a72008feca866e658f0cb4ebabbeee740f9fb13680e517b9d95eaa136e627a9dd5ee328456a2bf040401f4a1977ffa7446ad13f66b286b3419ff0c35095a3521
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Rolling forward" at startup can take a long time, and is not interruptible (after unclean shutdown)

10 participants