assumeutxo: snapshot initialization#25667
Conversation
38d511b to
0a482e9
Compare
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
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. |
0a482e9 to
15da925
Compare
There was a problem hiding this comment.
note for reviewers: for now is_snapshot is always true as there is a single usage. This is not the case anymore with the remaining commits of the #24232 patchset.
There was a problem hiding this comment.
note to reviewers: this method is used in the remaining #24232 patchset.
|
@dergoegge I think you could be interested to review the assumeutxo work. In case of future hypothetical integration of libutreexo in Core, I believe there would be intersecting code paths and data structure modified. It might also prepare for future synergies between utreexo and assumeutxo. |
|
Planning on diving deeply into this, thanks for splitting it up @jamesob! Questions from going over the commits: Q1: Is the intended layout:
Q2: The last 6 commits seem to be focused on unit tests, but it seems to me that the functionality being added here is better tested with functional tests. Is there something we need to test here that a functional test won't be able to do? |
There was a problem hiding this comment.
Note to other reviewers: the call to DestroyDB will actually remove the entire directory, including the blockhash file if it still existed since we place the blockhash file inside what leveldb considers to be its directory, but it's probably better (more polite?) to remove it ourselves just so we can print nice errors.
bitcoin/src/leveldb/db/db_impl.cc
Line 1550 in de3c46c
|
This PR needs rebase. |
15da925 to
2dcb2bd
Compare
|
Hi all, sorry for the delay. My spirit has been weak the last few months, and I took two weeks off to try and shake the burnout. I've addressed all feedback listed here and rebased. @dongcarl asks:
Yep, it is.
We can't have functional tests to exercise this behavior until we add |
2dcb2bd to
f73ca14
Compare
This CreateAndActivateUTXOSnapshot parameter is necessary once we perform snapshot completion within ABC, since the existing UpdateTip test will fail because the IBD chain that has generated the snapshot will exceed the base of the snapshot. Being able to test snapshots being loaded into a mostly-uninitialized datadir allows for more realistic unittest scenarios.
Used when testing cleanup of on-disk chainstate data for snapshot testcases. Also necessary for simulating node restart in .cpp tests.
in TestingSetup(). This is used in the following commit to test reinitializing chainstates after snapshot validation and cleanup. Best reviewed with `git diff --color-moved=dimmed-zebra`.
1430518 to
bf95976
Compare
|
Thanks for the feedback @MarcoFalke, all addressed. |
|
utACK bf95976 |
ariard
left a comment
There was a problem hiding this comment.
Code Review ACK bf95976
Changes since last ACK:
CChainState->Chainstate, after #24513- replacing
CAutoFileusage inutxo_snapshot.cppbyAutoFile - commenting
SNAPSHOT_BLOCKHASH_FILENAME - a new informative log L116 in
src/node/chainstate.cpp - replacing
InitializeChainstatebyActivateExistingSnapshotin tests - dropping the optional
snapshot_blockashargument fromInitializeChainstateand adding asserts - commenting
ActivateExistingSnapshot - comment, lock simplification and minor code changes in unit tests
There was a problem hiding this comment.
Code review ACK bf95976. Changes since last review: rebasing, switching from CAutoFile to AutoFile, adding comments, switching from BOOST_CHECK to Assert in test util, using chainman.GetMutex() in tests, destroying one ChainstateManager before creating a new one in tests
There was a problem hiding this comment.
nit: Can be swapped with sync.h above to have alphabetical order
| chainstate and a sync to tip begins. A new chainstate directory is created in the | ||
| datadir for the snapshot chainstate called | ||
| `chainstate_[SHA256 blockhash of snapshot base block]`. | ||
| datadir for the snapshot chainstate called `chainstate_snapshot`. When this directory |
There was a problem hiding this comment.
line 117 in this file still mentions chainstate_[hash]
|
I'm counting 4 ACKs here - what more is needed to merge? |
aureleoules
left a comment
There was a problem hiding this comment.
LGTM, I also verified that all commits compile and pass unit tests.
Left some minor/nit comments.
| //! @returns filesystem path to the on-disk data. | ||
| std::optional<fs::path> StoragePath() { | ||
| if (m_is_memory) { | ||
| return {}; |
There was a problem hiding this comment.
d14bebf
also missing #include <optional>
| return {}; | |
| return std::nullopt; |
| { | ||
| LOCK(cs_LastBlockFile); | ||
|
|
||
| if (m_blockfile_info.size() < 1) { |
There was a problem hiding this comment.
8153bd9
nit: easier to read and guaranteed constant time
| if (m_blockfile_info.size() < 1) { | |
| if (m_blockfile_info.empty()) { |
| return true; | ||
| } | ||
|
|
||
| std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir) |
There was a problem hiding this comment.
f9f1735
nit
| std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir) | |
| std::optional<uint256> ReadSnapshotBaseBlockhash(const fs::path& chaindir) |
| const std::vector<const char*>& extra_args, | ||
| const bool coins_db_in_memory, | ||
| const bool block_tree_db_in_memory) | ||
| : TestingSetup{CBaseChainParams::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory} |
There was a problem hiding this comment.
51fc924
I believe it should be like this?
| : TestingSetup{CBaseChainParams::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory} | |
| : TestingSetup{chain_name, extra_args, coins_db_in_memory, block_tree_db_in_memory} |
|
|
||
| // Background chainstate should be unaware of new blocks on the snapshot | ||
| // chainstate. | ||
| for (Chainstate* cs : chainman_restarted.GetAll()) { |
There was a problem hiding this comment.
e4d7995
nit
| for (Chainstate* cs : chainman_restarted.GetAll()) { | |
| for (const Chainstate* cs : chainman_restarted.GetAll()) { |
| return nullptr; | ||
| } | ||
|
|
||
| static bool DeleteCoinsDBFromDisk(const fs::path db_path, bool is_snapshot) |
There was a problem hiding this comment.
34d1590
nit
| static bool DeleteCoinsDBFromDisk(const fs::path db_path, bool is_snapshot) | |
| static bool DeleteCoinsDBFromDisk(const fs::path& db_path, bool is_snapshot) |
|
I'm going to leave the nits as-is to avoid ACK churn unless maints feel they are blocking merge. I'll be very quick to review any followups that @aureleoules or @fjahr would like to do towards addressing them. |
| if (fs::exists(base_blockhash_path)) { | ||
| bool removed = fs::remove(base_blockhash_path); | ||
| if (!removed) { | ||
| LogPrintf("[snapshot] failed to remove file %s\n", |
There was a problem hiding this comment.
I don't think this code is the intended behavior. This is redundant to the previous check 3 lines up. If fs::remove without a second parameter returns false it is only because the file does not exist. If it actually fails to remove an existing file it will throw an exception (see https://en.cppreference.com/w/cpp/filesystem/remove).
If intended behavior is to only log error and continue fs::remove should be wrapped in a try/catch block or passed a std::error_code.
See https://github.com/bitcoin/bitcoin/blob/master/src/init.cpp#L326-L332.
Summary: > db: add StoragePath to CDBWrapper/CCoinsViewDB > > This is used in subsequent commits. It allows us to clean up UTXO > snapshot chainstate after background validation completes. bitcoin/bitcoin@d14bebf > validation: rename snapshot chainstate dir > > This changes the snapshot's leveldb chainstate dir name from > `chainstate_[blockhash]` to `chainstate_snapshot`. This simplifies > later logic that loads snapshot data, and enforces the limitation > of a single snapshot at any given time. > > Since we still need to persist the blockhash of the base block, we > write that out to a file (`chainstate_snapshot/base_blockhash`) for > later use during initialization, so that we can reinitialize the > snapshot chainstate. > > Co-authored-by: Russell Yanofsky <russ@yanofsky.org> bitcoin/bitcoin@f9f1735 > test: allow on-disk coins and block tree dbs in tests > > Used when testing cleanup of on-disk chainstate data for snapshot > testcases. Also necessary for simulating node restart in .cpp tests. bitcoin/bitcoin@51fc924 Note: TestChain100Setup now inherits TestingSetup instead of RegTestingSetup. This would normally be done in [[bitcoin/bitcoin#22818 | core#22818]] which we didn't backport because the whole softfork machiney is not relevant to us. This is a partial backport of [[bitcoin/bitcoin#25667 | core#25667]] Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14650
… dbs in tests Summary: > init: add utxo snapshot detection > > Add functionality for activating a snapshot-based chainstate if one is > detected on-disk. > > Also cautiously initialize chainstate cache usages so that we don't > somehow blow past our cache allowances during initialization, then > rebalance at the end of init. > > Co-authored-by: Russell Yanofsky <russ@yanofsky.org> bitcoin/bitcoin@252abd1 > blockmanager: avoid undefined behavior during FlushBlockFile > > If we call FlushBlockFile() without having intitialized the block index > with LoadBlockIndexDB(), we may be indexing into an empty vector. > > Specifically this is an issue when we call MaybeRebalanceCaches() during > chainstate init before the block index has been loaded, which calls > FlushBlockFile(). > > Also add an assert to avoid undefined behavior. > > Co-authored-by: Russell Yanofsky <russ@yanofsky.org> bitcoin/bitcoin@8153bd9 This is a partial backport of [[bitcoin/bitcoin#25667 | core#25667]] Depends on D14650 Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D14651
Summary: For use in next commit. Most easily reviewed with `--color-moved=dimmed_zebra --color-moved-ws=allow-indentation-change`. This is a partial backport of [[bitcoin/bitcoin#25667 | core#25667]] bitcoin/bitcoin@3a29dfb Depends on D14651 Test Plan: `ninja check` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14652
Summary: > validation: add ResetChainstates() > > Necessary for the following test commit. bitcoin/bitcoin@00b357c > test: add reset_chainstate parameter for snapshot unittests > > This CreateAndActivateUTXOSnapshot parameter is necessary once we > perform snapshot completion within ABC, since the existing UpdateTip > test will fail because the IBD chain that has generated the snapshot > will exceed the base of the snapshot. > > Being able to test snapshots being loaded into a mostly-uninitialized > datadir allows for more realistic unittest scenarios. bitcoin/bitcoin@3c36139 Backport note: this process of resetting the chainstate without also resetting the block index would cause `CheckBlockIndex` to fail on `assert(setBlockIndexCandidates.count(pindex)));` after D4717 made `CheckBlockIndex` run on intermediate steps in `ActiveBestChain`. I disabled `CheckBlockIndex` until after the snapshot chain is activated. This is a partial backport of [[bitcoin/bitcoin#25667 | core#25667]] Depends on D14652 Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14653
Summary: > add utilities for deleting on-disk leveldb data > > Used in later commits to remove leveldb directories for > - invalid snapshot chainstates, and > - background-vaildation chainstates that have finished serving their > purpose. bitcoin/bitcoin@34d1590 > validation: remove snapshot datadirs upon validation failure > > If a UTXO snapshot fails to validate, don't leave the resulting datadir > on disk as this will confuse initialization on next startup and we'll > get an assertion error. bitcoin/bitcoin@ad67ff3 This is a partial backport of [[bitcoin/bitcoin#25667 | core#25667]] Depends on D14653 Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14654
Summary: This is a partial backport of [[bitcoin/bitcoin#25667 | core#25667]] bitcoin/bitcoin@e4d7995 Depends on D14654 Test Plan: `ninja check` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14655
Summary: This is a backport of [[bitcoin/bitcoin#23154 | core#23154]] with updates from [[bitcoin/bitcoin#25667 | core#25667]] and [[bitcoin/bitcoin#25740 | core#25740]] Depends on D14655 Test Plan: proof-reading Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14656
This is part of the assumeutxo project (parent PR: #15606)
Half of the replacement for #24232. The original PR grew larger than expected throughout the review process.
This change adds the ability to initialize a snapshot-based chainstate during init if one is detected on disk. This is of course unused as of now (aside from in unittests) given that we haven't yet enabled actually loading snapshots.
Don't be scared! There are some big move-only commits in here.
Accompanying changes include:
chainstate_[base blockhash]tochainstate_snapshot, since we only support one snapshot in use at a time. This simplifies some logic, but it necessitates writing that base blockhash out to a file within the coinsdb dir. See discussion here.FlushBlockFile()that avoids a crash when attemping to flush to disk beforeLoadBlockIndexDB()is called, which happens when callingMaybeRebalanceCaches()during multiple chainstate init.