Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented May 6, 2025

Currently mocktime is written to a global, which may leak between sub-tests (albeit some tests try to reset the mocktime on a best-effort basis). Also, when advancing it, one has to keep a counter variable around.

Fix both issues by a new ElapseTime helper, which resets the mocktime once it goes out of scope. Also, it has a method to advance the mocktime by a delta.

@DrahtBot
Copy link
Contributor

DrahtBot commented May 6, 2025

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/32430.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK l0rinc
Stale ACK w0xlt

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:

  • #33106 (policy: lower the default blockmintxfee, incrementalrelayfee, minrelaytxfee by glozow)
  • #32941 (p2p: TxOrphanage revamp cleanups by glozow)
  • #32414 (validation: periodically flush dbcache during reindex-chainstate by andrewtoth)
  • #29700 (kernel, refactor: return error status on all fatal errors by ryanofsky)
  • #28676 (Cluster mempool implementation by sdaftuar)
  • #17783 (common: Disallow calling IsArgSet() on ALLOW_LIST options by ryanofsky)
  • #17580 (refactor: Add ALLOW_LIST flags and enforce usage in CheckArgFlags by ryanofsky)
  • #16545 (refactor: Implement missing error checking for ArgsManager flags by ryanofsky)

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.

@DrahtBot
Copy link
Contributor

DrahtBot commented May 6, 2025

🚧 At least one of the CI tasks failed.
Task lint: https://github.com/bitcoin/bitcoin/runs/41759458930
LLM reason (✨ experimental): (empty)

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
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.

@maflcko maflcko force-pushed the 2505-elapse-time branch 5 times, most recently from fa123d4 to fae29c5 Compare May 7, 2025 09:27
Copy link
Contributor

@l0rinc l0rinc 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 - was thinking of something similar when reviewing 41479ed (#32414)

@maflcko
Copy link
Member Author

maflcko commented May 7, 2025

Sorry for the force-pushes, but this uncovered pre-existing issues in the fuzz tests that were not using mocktime during init. So I went ahead and fixed those as well in a separate commit. Should be good now, hopefully 😅

Copy link
Contributor

@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

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

ACK fae29c5

@DrahtBot
Copy link
Contributor

DrahtBot commented Jul 8, 2025

🚧 At least one of the CI tasks failed.
Task previous releases, depends DEBUG: https://github.com/bitcoin/bitcoin/runs/45588216821
LLM reason (✨ experimental): The CI failure is caused by a compilation error in src/util/time.cpp due to incorrect usage of std::chrono::duration, which prevents building.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
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.

@maflcko
Copy link
Member Author

maflcko commented Jul 9, 2025

Sorry for the force-pushes, but this uncovered pre-existing issues in the fuzz tests that were not using mocktime during init. So I went ahead and fixed those as well in a separate commit. Should be good now, hopefully 😅

Went ahead and cherry-picked out the fuzz-fixes into #32927. Should be easy to (re-)review that one.

@maflcko maflcko force-pushed the 2505-elapse-time branch 2 times, most recently from fad3690 to fa1dde3 Compare July 11, 2025 13:35
@maflcko
Copy link
Member Author

maflcko commented Jul 11, 2025

rebased to drop merged commits and included some minimal fixups

Copy link
Contributor

@l0rinc l0rinc left a comment

Choose a reason for hiding this comment

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

Thanks for fixing these, left quite a few comments, hope you'll find them useful


CBlockHeader genesis_header{Params().GenesisBlock()};
CBlockIndex start_index(genesis_header);

if (mock_time < start_index.GetMedianTimePast()) return;
SetMockTime(mock_time);
SetMockTime(ConsumeTime(fuzzed_data_provider, /*min=*/start_index.GetMedianTimePast()));
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 for using the built-in min instead.

Could we add it to the commit message that this isn't just a simple refactor (and not just about the return value), but as @hodlinator stated in a different PR where he did the same:

That way we can always proceed instead of just exiting the fuzz target, wasting cycles. Also reduces code complexity.

Copy link
Member Author

Choose a reason for hiding this comment

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

thx, split up into a new commit

Copy link
Contributor

Choose a reason for hiding this comment

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

typo in commit message:

no state is leaked between test cases

Copy link
Member Author

Choose a reason for hiding this comment

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

thx, fixed

void operator()(std::chrono::milliseconds d)
{
Assert(d >= 0s); // Steady time can only move forward.
Copy link
Contributor

@l0rinc l0rinc Jul 27, 2025

Choose a reason for hiding this comment

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

nit: the code isn't in exact alignment with the comment - and since we are calling it with 0, maybe something like:

Suggested change
Assert(d >= 0s); // Steady time can only move forward.
Assert(d >= 0ms); // Steady time cannot move backward.

(nit2: I know it's the same, but to clarify that we don't just mean that time-jumps cannot be 0.5 seconds, we might want to use 0ms instead)

Copy link
Member Author

Choose a reason for hiding this comment

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

thx, reworded comment a bit

NodeSeconds m_t{std::chrono::seconds::max()};

public:
/** Initialize with initial time */
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I understand that it's meant to be symmetric with ElapseSteady, but I don't find the comment helpful as it is.

Copy link
Member Author

Choose a reason for hiding this comment

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

thx, reworded comment

@@ -167,7 +168,7 @@ BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
BOOST_CHECK(node->fDisconnect == false);
}

SetMockTime(time_later);
elapse_time(delta);
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason for defining the delta so far away from first usage?

Suggested change
elapse_time(delta);
const auto delta{3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
elapse_time(delta);

Copy link
Member Author

Choose a reason for hiding this comment

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

Just to make review easier, because you agree that the commit is already large in #32430 (comment). Will leave as-is for now.

@@ -44,7 +45,7 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize)

auto& connman = static_cast<ConnmanTestMsg&>(*g_setup->m_node.connman);
auto& chainman = static_cast<TestChainstateManager&>(*g_setup->m_node.chainman);
SetMockTime(1610000000); // any time to successfully reset ibd
ElapseTime elapse_time{1610000000s}; // any time to successfully reset ibd
Copy link
Contributor

Choose a reason for hiding this comment

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

do we still need to keep these constants or is there maybe a cleaner way now?

Copy link
Member Author

Choose a reason for hiding this comment

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

seems unrelated? But i am happy to review a pull request changing it


public:
/** Initialize with initial time */
ElapseTime(NodeSeconds init_time) { set(init_time); }
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we might as well make the constructors explicit

Copy link
Member Author

Choose a reason for hiding this comment

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

thx, done

Copy link
Contributor

@l0rinc l0rinc Jul 27, 2025

Choose a reason for hiding this comment

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

faaaaac is quite big...
And some of the changes are non-trivial, if you can, please consider doing it in multiple commits

Copy link
Member Author

Choose a reason for hiding this comment

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

It is just 50 lines, so it should be manageable. Anyone is free to review it file-by-file, if they want to split it up, but I am not sure about splitting it up too much?

MarcoFalke added 6 commits July 31, 2025 12:19
This is less code and also required for the next commit.
This is a bit more type-safe than a raw i64.
This makes it easier to use mock-time in tests. Also, it resets the
global mocktime, so that no state is leaked between test cases.

Also, it resets the global steady mock-time for the same reason.
This is required in the next commit.
@maflcko maflcko force-pushed the 2505-elapse-time branch from faaaaac to fa80e75 Compare July 31, 2025 10:22
@maflcko
Copy link
Member Author

maflcko commented Jul 31, 2025

Force pushed with some minor doc-changes and small refactoring in src/test/util/time.h

Copy link
Contributor

@l0rinc l0rinc 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 fa80e75

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 4, 2025

🐙 This pull request conflicts with the target branch and needs rebase.

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.

4 participants