Skip to content

Conversation

TheCharlatan
Copy link
Contributor

The tests should run the same checks on the mempool options that the init code also applies. The downside to this patch is that the log line may now be printed more than once in the for loop.

This was originally noticed here #25290 (comment).

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 9, 2023

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

Code Coverage

For detailed information about the code coverage, see the test coverage report.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK stickies-v, ryanofsky, achow101
Stale ACK glozow

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:

  • #30058 (Encapsulate warnings in generalized node::Warnings and remove globals by stickies-v)
  • #29641 (scripted-diff: Use LogInfo/LogDebug over LogPrintf/LogPrint by maflcko)
  • #28687 (C++20 std::views::reverse by stickies-v)
  • #28676 ([WIP] Cluster mempool implementation by sdaftuar)

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.

@TheCharlatan TheCharlatan changed the title [refactor] Check CTxMemPool options in ctor [refactor] Improve CTxMemPool options handling Nov 9, 2023
@TheCharlatan TheCharlatan changed the title [refactor] Improve CTxMemPool options handling [refactor] Check CTxMemPool options in ctor Nov 9, 2023
@TheCharlatan TheCharlatan marked this pull request as ready for review November 10, 2023 06:52
Copy link
Contributor

@stickies-v stickies-v left a comment

Choose a reason for hiding this comment

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

Concept ACK

@TheCharlatan
Copy link
Contributor Author

Rebased 29818f5 -> 1d18cc6 (mempoolArgs_0 -> mempoolArgs_1, compare)

Updated 1d18cc6 -> 3aa41a3 (mempoolArgs_1 -> mempoolArgs_2, compare)

  • Addressed @stickies-v's comment, using the Result type and a factory method instead of error string parameters.

Copy link
Contributor

@stickies-v stickies-v left a comment

Choose a reason for hiding this comment

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

LGTM 3aa41a3 when fuzzer is fixed

@@ -125,7 +125,7 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();

// ...and construct a CTxMemPool from it
return CTxMemPool{mempool_opts};
return std::move(Assert(CTxMemPool::Make(mempool_opts)).value());
Copy link
Contributor

Choose a reason for hiding this comment

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

Wdyt about this approach to fix the fuzzer (this impl requires rebase to use c++20 for std::string::starts_with)? This should be efficient without relying too much (but still somewhat) on the implementation of CTxMemPool::Make?

After #25665 is merged, could have a Make return an enum failure value and avoid the errorstring checking.

git diff on 3aa41a3
diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp
index ec708a5c53..7f8aecb1ae 100644
--- a/src/test/fuzz/package_eval.cpp
+++ b/src/test/fuzz/package_eval.cpp
@@ -111,13 +111,15 @@ std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider
     // Take the default options for tests...
     CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
 
-
     // ...override specific options for this specific fuzz suite
     mempool_opts.limits.ancestor_count = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50);
     mempool_opts.limits.ancestor_size_vbytes = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202) * 1'000;
     mempool_opts.limits.descendant_count = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50);
-    mempool_opts.limits.descendant_size_vbytes = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202) * 1'000;
-    mempool_opts.max_size_bytes = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 200) * 1'000'000;
+    auto set_descendants_size = [&]() {
+        mempool_opts.limits.descendant_size_vbytes = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202) * 1'000;
+        mempool_opts.max_size_bytes = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 200) * 1'000'000;
+    };
+    set_descendants_size();
     mempool_opts.expiry = std::chrono::hours{fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)};
     nBytesPerSigOp = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(1, 999);
 
@@ -125,7 +127,15 @@ std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider
     mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
 
     // ...and construct a CTxMemPool from it
-    return std::move(Assert(CTxMemPool::Make(mempool_opts)).value());
+    while (true) {
+        if (auto res{CTxMemPool::Make(mempool_opts)}) {
+            return std::move(res.value());
+        } else {
+            // Ensure this harness is updated when additional mempool construction failure paths are introduced
+            assert(util::ErrorString(res).original.starts_with("-maxmempool must be at least"));
+            set_descendants_size();
+        }
+    }
 }
 
 FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)

@TheCharlatan
Copy link
Contributor Author

Rebased 3aa41a3 -> 571fa4f (mempoolArgs_2 -> mempoolArgs_3, compare)

Updated 571fa4f -> 364456f (mempoolArgs_3 -> mempoolArgs_4, compare)

I'm still not quite happy with the fuzz test, which is why I left it in a separate commit. Maybe a better approach would be to let the fuzzer do its job and just return early in the fuzz test if MakeUnique fails?

Comment on lines 204 to 212
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
while (true) {
if (tx_pool_) {
break;
} else {
// Ensure this harness is updated when additional mempool construction failure paths are introduced
assert(util::ErrorString(tx_pool_).original.starts_with("-maxmempool must be at least"));
SetMempoolConstraints(*node.args, fuzzed_data_provider);
tx_pool_ = MakeMempool(fuzzed_data_provider, node);
}
}

MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.value().get());
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we're resetting all constraints on every loop, is this not overly verbose? (+below)

git diff on 364456f
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 1400fadea0..7ddc45c4b4 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -200,17 +200,10 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
     // The sum of the values of all spendable outpoints
     constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
 
-    SetMempoolConstraints(*node.args, fuzzed_data_provider);
-    auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
-    while (true) {
-        if (tx_pool_) {
-            break;
-        } else {
-            // Ensure this harness is updated when additional mempool construction failure paths are introduced
-            assert(util::ErrorString(tx_pool_).original.starts_with("-maxmempool must be at least"));
-            SetMempoolConstraints(*node.args, fuzzed_data_provider);
-            tx_pool_ =  MakeMempool(fuzzed_data_provider, node);
-        }
+    util::Result<std::unique_ptr<CTxMemPool>> tx_pool_;
+    while (!tx_pool_) {
+        SetMempoolConstraints(*node.args, fuzzed_data_provider);
+        tx_pool_ = MakeMempool(fuzzed_data_provider, node);
     }
 
     MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.value().get());

@stickies-v
Copy link
Contributor

re-ACK 27af391

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 27af391

@TheCharlatan
Copy link
Contributor Author

Thanks for the reviews, going to take @ryanofsky's suggestion, hope it is not much work to review again

Updated 27af391 -> 33f2a70 (mempoolArgs_8 -> mempoolArgs_9, compare)

  • Addressed @ryanofsky's comment, slightly changing the mechanics of the mempool constructor for better clarity.

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 33f2a70. I actually didn't notice this push when I made my last two comments, so feel free to ignore the comments if you want to keep the current code.

@TheCharlatan
Copy link
Contributor Author

Sorry for the many pushes, but I think it's important to get this consistent.

Updated 33f2a70 -> 856c856 (mempoolArgs_9 -> mempoolArgs_10, compare)

  • Changed the constructor to be more like the ChainstateManager.

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 856c856, just tweaked since last review to be more consistent with validation.cpp Flatten code

Sorry for the many pushes, but I think it's important to get this consistent.

Thanks for the update! I agree it's much nicer to be consistent. And sorry for the detour I caused by not fully understanding the original approach.

Copy link
Contributor

@stickies-v stickies-v left a comment

Choose a reason for hiding this comment

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

ACK 856c856

@@ -395,8 +397,19 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee,
assert(int(nSigOpCostWithAncestors) >= 0);
}

CTxMemPool::CTxMemPool(const Options& opts)
: m_opts{opts}
//! Clamp option values and return error if options are not valid.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: slightly confusing docstring: the Options ref is always returned, error is non-empty if options are not valid. Since Flatten is internal, this is probably something that mostly should be documented in the CTxMemPool ctor anyway though (highlighting that callers should check that error.empty())

@achow101
Copy link
Member

ACK 856c856

@TheCharlatan
Copy link
Contributor Author

TheCharlatan commented May 17, 2024

856c856 -> 09ef322 (mempoolArgs_10 -> mempoolArgs_11, compare)

This ensures that the tests run the same checks on the mempool options
that the init code also applies.
@stickies-v
Copy link
Contributor

re-ACK 09ef322 . Fixed unreachable assert and updated docstring, and also added an exception for "-maxmempool must be at least " in the tx_pool fuzz test, which makes sense when looking at how the mempool options are constructed in SetMempoolConstraints.

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 09ef322. Just fuzz test error checking fix and updated comment since last review

@@ -107,7 +109,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains
SetMockTime(time);
}

CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
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 "[[refactor]] Check CTxMemPool options in constructor" (09ef322)

It's a shame this has to return a pointer now. It would have been nice to avoid the unreachable code with something like scope_exit, but I guess that is still experimental and hasn't been standardized.

    bilingual_str error;
    auto error_check{std::experimental::scope_exit([&] { Assert(error.empty()); })};
    return CTxMemPool{mempool_opts, error};

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.

[deleted comment accidentally posted to wrong pr]

@DrahtBot DrahtBot requested a review from ryanofsky June 10, 2024 13:15
@achow101
Copy link
Member

ACK 09ef322

@achow101 achow101 merged commit 2251460 into bitcoin:master Jun 11, 2024
@maflcko
Copy link
Member

maflcko commented Jul 5, 2024

pm-lgtm

achow101 added a commit that referenced this pull request Sep 30, 2024
e9d60af refactor: Replace init retry for loop with if statement (TheCharlatan)
c1d8870 refactor: Move most of init retry for loop to a function (TheCharlatan)
781c01f init: Check mempool arguments in AppInitParameterInteractions (TheCharlatan)

Pull request description:

  The for loop around the chain loading logic in `init.cpp` allows users of the GUI to retry once on failure with reindexing without having to manually set the reindex flag on startup. However this current mechanism has problems:

  * It is badly documented and has led to confusion among developers and bugs making it into master. Examples:
      * https://github.com/bitcoin/bitcoin/pull/28830/files#r1598392660
      * #30132 (comment)
  * It can only ever iterate once, making the choice of a for loop questionable.
  * With its large scope it is easy for re-entry bugs to sneak in. Example:
      * #28830 (comment)

  Attempt to fix this by moving the bulk of the logic into a separate function and replacing the for loop with a simpler `if` statement.

  The diff's in this pull request are best reviewed with `--color-moved-ws=ignore-all-space --color-moved=dimmed-zebra`. The error behaviour can be tested by either manually making `LoadChainstate` return a failure, or deleting some of the block index database files.

ACKs for top commit:
  maflcko:
    review ACK e9d60af 🚸
  josibake:
    crACK e9d60af
  achow101:
    ACK e9d60af
  ryanofsky:
    Code review ACK e9d60af. Nice change to make AppInitMain shorter and more understandable.

Tree-SHA512: 5e5c0a5fd1b32225346450f8482f0ae8792e1557cdab1518112c1a3ec3a4400b64f5796692245cc5bf2f9010bb97b3a9558f07626a285ccd6ae525dd671ead13
@bitcoin bitcoin locked and limited conversation to collaborators Jul 5, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
Status: Done or Closed or Rethinking
Development

Successfully merging this pull request may close these issues.

7 participants