Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validation: UpdateTip/CheckBlockIndex assumeutxo support #21526

Merged
merged 12 commits into from
Sep 23, 2021

Conversation

jamesob
Copy link
Contributor

@jamesob jamesob commented Mar 24, 2021

This is part of the assumeutxo project (parent PR: #15606)


Modify UpdateTip and CheckBlockIndex for use with multiple chainstates. Includes a new unittest verifying g_best_block behavior (previously untested at the unit level) and various changes necessary for running and testing ProcessNewBlock()-like behavior on the background validation chainstate.

This changeset introduces a new block index nStatus flag called BLOCK_ASSUMED_VALID, and it is applied to block index entries that are beneath the UTXO snapshot base block upon snapshot load. Once each block is validated (during async background validation), the flag is removed. This allows us to avoid (ab)using BLOCK_VALID_* flags for snapshot chain block entries, and preserves the original meaning of those flags.

Note: this PR previously incorporated changes to LoadBlockIndex() and RewindBlockIndex() as noted in Russ' comments below, but once I generated the changes necessary to test the UpdateTip change, I decided to split this changes out into another PR due to the size of this one.

@DrahtBot
Copy link
Contributor

DrahtBot commented Mar 24, 2021

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

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #22937 (refactor: Forbid calling unsafe fs::path(std::string) constructor and fs::path::string() method by ryanofsky)
  • #22932 (consensus: require CBlockIndex::GetBlockPos() to hold mutex cs_main by jonatack)
  • #22564 ([WIP] refactor: Move mutable globals cleared in ::UnloadBlockIndex to BlockManager by dongcarl)
  • #21603 (log: Mitigate disk filling attacks by rate limiting LogPrintf by dergoegge)
  • #19790 (Flag when blocks have had their scripts checked instead of skipped by luke-jr)

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.

@ryanofsky
Copy link
Contributor

ryanofsky commented Mar 29, 2021

re: #21526 (comment)

  • Don't run UpdateTip for background validation chainstates.

Does this prevent bugs in the future when there can be a background validation chainstate? It would help to say what would happen without this change. It could also be helpful to say more about the motivation for this set of changes, and maybe summarize the current state of things for forgetful people like me who somewhat lost the thread on assumeutxo 🐠

  • Modify LoadBlockIndex() to populate the "faked" nChainTx value when using a yet-unvalidated snapshot chainstate. This allows assumeutxo sync-to-tip to offer normal progress estimates on the basis of having nChainTx without the associated block data.

IIUC, the faking isn't new, and the value was faked before this change, but startup code is now fixed so things work if the node is restarted before the assumeutxo snapshot is validated? Again could help to say what bad things would happen without this.

  • In LoadBlockIndex(), ensure that assumed-valid CBlockIndex entries aren't added to the background validation chainstate's setBlockIndexCandidates (since we want that chainstate to actually validate those entries at some point).

Wondering also what bad things happen without this change, and why it's in the same commit as the last change. Is it just that both changes affect the LoadBlockIndex() function?

  • Prevent RewindBlockIndex() from rewinding past the assumeutxo base on the snapshot chainstate.

I'm a little confused by this code (also the existing pruning code here). It says the purpose of the break is to prevent the DisconnectTip call immediately below from failing. But don't we want to fail in these cases? It seems like now if rewind isn't possible, this just flushes some things and returns true. I'm also wondering if there's a reason this change is in the same commit as the other changes, which seem tangentially related.

Also, there's no test coverage here. Maybe is the best we can do when adding dead code to older functions that weren't really designed to be unit-tested. But are there at least future tests in #15606 that would fail without these different fixes?

Thanks for any clarifications, and great to see assumeutxo work moving along again!

@jamesob
Copy link
Contributor Author

jamesob commented Mar 30, 2021

@ryanofsky thanks for the thorough look! I agree that I should take a look at writing unittests for these changes and do so if practical. Also appreciate your questions on the logic - I'll get together some responses for those and either adjust the code (especially since RewindBlockIndex() is probably going away in #21009) or add some motivating documentation.

@ryanofsky ryanofsky mentioned this pull request Apr 1, 2021
18 tasks
@jamesob jamesob force-pushed the 2021-03-multi-chainstates branch 2 times, most recently from d7bb92c to c1b1d66 Compare April 8, 2021 14:38
@jamesob jamesob changed the title validation: misc. multi-chainstate preparation validation: UpdateTip/CheckBlockIndex assumeutxo support Apr 8, 2021
@jamesob jamesob force-pushed the 2021-03-multi-chainstates branch from c1b1d66 to e07edda Compare April 8, 2021 14:52
@jamesob
Copy link
Contributor Author

jamesob commented Apr 8, 2021

Okay, after taking @ryanofsky's advice, I sat down to write some unittests for the chainstate-dependent UpdateTip() behavior. It turns out that in the process, trying to get those tests to work uncovered a number of changes that needed to be made to other test-related stuff, including slightly modifying CheckBlockIndex() to account for the specific nature of the background validation chainstate. Additionally I've added some unittesting utils that help with testing multiple chainstates.

Because that's dragged in so much new code, I've narrowed the scope of this PR to the above and I'll deal with the other BlockIndex-related changes in a follow-up PR.

So all the logic changes in this are now tested (and this actually adds unit-level coverage of the UpdateTip() behvaior that we didn't have previously). So hopefully that entices people to review, because testing future assumeutxo-related changes will probably depend on some of the unittest utils added here.

Also worth mentioning is that I had to remove some of the active chainstate assertions that @dongcarl added for the sake of his work in #20158. This should all be okay because those assertions are actually made obsolete by assumeutxo functionality.

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

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

Started review (will update list below with progress). Thanks for splitting this up!

  • b9f805b validation: change UpdateTip for multiple chainstates (1/6)
  • d3cec2a validation: fix CheckBlockIndex for multiple chainstates (2/6)
  • 0fd884d move-only: unittest: add test/util/chainstate.h (3/6)
  • 6e5871c test: refactor: separate CreateBlock in TestChain100Setup (4/6)
  • d7fc5c3 refactor: remove assertions preventing multiple chainstates (5/6)
  • 3f1346a test: validation: add unittest for UpdateTip behavior (6/6)

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

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

Code review ACK 3f1346a. This is great! Changes are small and easy to understand and new test is surprisingly straightforward, not requiring too much setup.

src/validation.cpp Outdated Show resolved Hide resolved
src/test/util/setup_common.h Outdated Show resolved Hide resolved
pblock, state, chainparams, &pindex, true, nullptr, &newblock);
BOOST_CHECK(accepted);
}
bool block_added = background_cs.ActivateBestChain(state, chainparams, pblock);
Copy link
Contributor

Choose a reason for hiding this comment

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

In commit "test: validation: add unittest for UpdateTip behavior" (3f1346a)

Since this test is designed to check UpdateTip background behavior, but the test doesn't call UpdateTip directly, it may be good to add a comment saying this line is what calls UpdateTip.

Also could maybe a simple check could be added here to verify the new background tip hash?

Also curious if there's an existing test (or a planned one) to cover the background chain catching up to the activated snapshot.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Also curious if there's an existing test (or a planned one) to cover the background chain catching up to the activated snapshot.

Yes; I'll look at writing a test for this sometime today in addition to some chainstate-concurrency torture tests.

@jamesob
Copy link
Contributor Author

jamesob commented Apr 23, 2021

Thanks for the great feedback, @ryanofsky!

@DrahtBot
Copy link
Contributor

DrahtBot commented May 3, 2021

🕵️ @sipa has been requested to review this pull request as specified in the REVIEWERS file.

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

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

Code review ACK eb9623d. Since last review just rebase and various suggestions applied, biggest one updating CheckBlockIndex in a different way where I think it does some more checks than the previous change and some fewer, but is now a simpler change. Overall this looks good and please ignore my new suggestion unless something needs to be updated for another reason.

Recommend this PR for any reviewer looking for a simple review of some critical code. The first commit's the only code commit that's even a little complicated and the other commits are either test updates or trivial code changes.

CBlock TestChain100Setup::CreateBlock(
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
CChainState* chainstate)
Copy link
Contributor

Choose a reason for hiding this comment

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

In commit "test: refactor: separate CreateBlock in TestChain100Setup" (6d5d096)

Would be nice to make the last argument a CChainState& reference instead of a pointer since it isn't allowed to be null (and it's a new method so there's no backward compatility concern)

Copy link
Contributor

Choose a reason for hiding this comment

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

In commit "test: refactor: separate CreateBlock in TestChain100Setup" (e061837)

Would be nice to make the last argument a CChainState& reference instead of a pointer since it isn't allowed to be null (and it's a new method so there's no backward compatility concern)

(This is still applicable, in case the PR gets another update)

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

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

Mostly happy with eb9623d, but I'm a bit confused about some code paths that I thought shouldn't be possible on the background chainstate.

I'd like to do some testing with the parent PR, if you don't mind rebasing that.

@@ -2321,8 +2355,7 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
}

bilingual_str warning_messages;
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
Copy link
Member

Choose a reason for hiding this comment

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

23c2d26: given the above return, you don't have to drop this assert

EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
auto& func_name = __func__;
auto& coins_view = chainstate.CoinsTip();
auto log_progress = [pindexNew, &func_name, &coins_view, &chainParams](
Copy link
Member

Choose a reason for hiding this comment

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

validation.cpp:2321:38: warning: lambda capture 'func_name' is not required to be captured for this use [-Wunused-lambda-capture]
    auto log_progress = [pindexNew, &func_name, &coins_view, &chainParams](
                                  ~~~^~~~~~~~~
1 warning generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fails CI when addressing this warning.

src/miner.cpp Outdated
@@ -116,7 +116,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end

LOCK2(cs_main, m_mempool.cs);
assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*m_chainstate.m_chain.Tip()));
Copy link
Member

Choose a reason for hiding this comment

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

23b5ebd why would CreateNewBlock ever be called on the background chainstate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gets called during unittests.

Copy link
Member

Choose a reason for hiding this comment

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

But why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because (unlike in actual snapshot usage) we don't have pre-prepared snapshots to use from within unittests, we have to use the same chainstate objects that we ultimately test on to generate snapshots for use during the test. As a result, the background validation chainstate is already at the snapshot base block, so in order to test appending to the bg chainstate, we have to call CreateNewBlock with it.

While I agree this usage isn't realistic, we don't have great alternatives within tests. I guess another option would involve using a temporary chainstate to generate the snapshot and then loading it into a new chainstatemanager object, but that sounds even hairier than what we're doing here, and much more code.

@@ -635,7 +635,6 @@ void CTxMemPool::check(CChainState& active_chainstate) const
uint64_t innerUsage = 0;

CCoinsViewCache& active_coins_tip = active_chainstate.CoinsTip();
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(active_coins_tip)); // TODO: REVIEW-ONLY, REMOVE IN FUTURE COMMIT
Copy link
Member

Choose a reason for hiding this comment

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

23b5ebd: I thought the background chain didn't have a mempool? Or it had a dummy mempool. I guess it's fine to remove this assert though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above; called during unittests.

@jamesob jamesob force-pushed the 2021-03-multi-chainstates branch from a07e850 to 673a5bd Compare September 15, 2021 19:47
@achow101
Copy link
Member

ACK 673a5bd

@jamesob
Copy link
Contributor Author

jamesob commented Sep 16, 2021

Okay, thanks everyone for bearing with the build issues. I think I've addressed all feedback here; in the latest change I've

  • made the auto -> const auto change (thanks again @ryanofsky), and
  • moved the g_best_block documentation change into its own commit (thanks @JeremyRubin).

I think this is in good shape pending some reACKs.

@jonatack
Copy link
Member

jonatack commented Sep 16, 2021

@jamesob in case it's accidental, just noticed one commit (b217020) has a different email for you than the others.

Code-review re-ACK 673a5bd reviewed diff, rebased to master/debug build/ran unit+functional tests

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

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

Code review ACK 673a5bd. Just linker fix and split commit changes mentioned #21526 (comment) since last review

@naumenkogs
Copy link
Member

ACK 673a5bd

Copy link
Contributor

@benthecarman benthecarman left a comment

Choose a reason for hiding this comment

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

ACK 673a5bd

@fjahr
Copy link
Contributor

fjahr commented Sep 19, 2021

Code review ACK 673a5bd

@ariard
Copy link
Contributor

ariard commented Sep 19, 2021

utACK 673a5bd

@ryanofsky
Copy link
Contributor

Anything holding this up for merge at this point?

@laanwj laanwj merged commit b7e3600 into bitcoin:master Sep 23, 2021
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Sep 24, 2021
fanquake pushed a commit to fanquake/bitcoin that referenced this pull request Sep 24, 2021
To avoid linker error on some platforms:
    bitcoin#21526 (comment)

Co-authored-by: Russ Yanofsky <russ@yanofsky.org>
* If set, this indicates that the block index entry is assumed-valid.
* Certain diagnostics will be skipped in e.g. CheckBlockIndex().
* It almost certainly means that the block's full validation is pending
* on a background chainstate. See `doc/assumeutxo.md`.
Copy link
Member

Choose a reason for hiding this comment

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

There is no such document. Also, it would be good to explain how the unlikely case where this is not pending on background validation might happen. Even more so when this comment contradicts the very next comment (IsAssumedValid).

rebroad pushed a commit to rebroad/bitcoin that referenced this pull request Oct 13, 2021
To avoid linker error on some platforms:
    bitcoin#21526 (comment)

Co-authored-by: Russ Yanofsky <russ@yanofsky.org>
maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Nov 3, 2021
9ab4401 doc: add assumeutxo notes (James O'Beirne)

Pull request description:

  This is part of the [assumeutxo project](https://github.com/bitcoin/bitcoin/projects/11) (parent PR: #15606)

  ---

  Adds some notes on assumeutxo design.

  Related: bitcoin/bitcoin#21526 (comment)

ACKs for top commit:
  ariard:
    ACK 9ab4401
  naumenkogs:
    ACK 9ab4401
  michaelfolkson:
    ACK 9ab4401
  fjahr:
    ACK 9ab4401

Tree-SHA512: 2fca8373b78701754957d12bc43ce18aa6928507965448741cb4e8c56589ad61d261f8542e348094fc9631d46ee6a7afee75c965c0db993fc816758569137b74
janus pushed a commit to BitgesellOfficial/bitgesell that referenced this pull request Nov 11, 2021
To avoid linker error on some platforms:
    bitcoin/bitcoin#21526 (comment)

Co-authored-by: Russ Yanofsky <russ@yanofsky.org>
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 17, 2022
Summary:
After feedback from Russ, I realized that there are some extraneous assumeutxo methods
that are not necessary and probably just overly confusing. These include

- `Validated*()`
- `IsBackgroundIBD()`

and they can be removed.

Also add comment for g_best_block

This is a backport of [[bitcoin/bitcoin#21526 | core#21526]] [2 & 3/12]
bitcoin/bitcoin@ac4051d
bitcoin/bitcoin@665072a

Backported out of order (unrelated refactorings first)

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D12267
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 17, 2022
Summary:
> move-only: unittest: add test/util/chainstate.h
>
> and move `CreateAndActivateUTXOSnapshot()` into it for reuse
> in future test modules.

> test: refactor: declare NoMalleation const auto
>
> To avoid linker error on some platforms:
>     bitcoin/bitcoin#21526 (comment)
>
> Co-authored-by: Russ Yanofsky <russ@yanofsky.org>

This is a backport of [[bitcoin/bitcoin#21526 | core#21526]] [9 & 10/12]
bitcoin/bitcoin@0712009
bitcoin/bitcoin@298bf5d

Backported out of order (refactoring commits first)

Test Plan: `ninja check`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D12268
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 17, 2022
Summary:
This is so we can create blocks within unittests and have them
be processed by specific chainstates (instead of the just the
active one).

This is a backport of [[bitcoin/bitcoin#21526 | core#21526]] [11/12]
bitcoin/bitcoin@2705570

Test Plan: `ninja check`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D12269
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 19, 2022
Summary:
Add an upwards reference to chainstate instances to the owning
ChainstateManager. This is necessary because there are a number
of `this_chainstate == chainman.ActiveChainstate()` checks that
will happen (as a result of assumeutxo) in functions that otherwise
don't have an easily-accessible reference to the chainstate's
ChainManager.

This is a backport of [[bitcoin/bitcoin#21526 | core#21526]] [1/12]
bitcoin/bitcoin@9f6bb53

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D12277
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 19, 2022
Summary:
Only perform certain behavior (namely that related to servicing
the getblocktemplate RPC call) for the active chainstate when
calling UpdateTip.

Co-authored-by: Jon Atack <jon@atack.com>

This is a backport of [[bitcoin/bitcoin#21526 | core#21526]] [3/12]
bitcoin/bitcoin@b217020
Depends on D12277

Notes:
 - the main difference from the source material is that we do not have the code handling BIP9 deployments in `UpdateTip`. As a result, there is no need for the `warning_messages` arguments in `UpdateTipLog`
 - the  `const` qualifier for the  `CblockIndex *pindexNew` argument in `UpdateTip` was missed in D1972

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D12278
@bitcoin bitcoin locked and limited conversation to collaborators Oct 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.