{
 "number": 35557,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35557",
 "title": "kernel, validation: Add btck_chainstate_manager_set_clock_time",
 "author": "ryanofsky",
 "author_association": "MEMBER",
 "created_at": "2026-06-18T02:52:12Z",
 "updated_at": "2026-09-16T23:08:58Z",
 "age_days": 91,
 "draft": false,
 "labels": [
  "Validation",
  "Kernel"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "1d3a0270fcf3fcabd2249c4b06a071a32a7b364b",
 "head_ref": "pr/kclock",
 "head_repo": "ryanofsky/bitcoin",
 "head_history": [
  {
   "t": "2026-06-18T13:51:13Z",
   "sha": "94622b041571f73e8e5e661b9bce4213b957a561"
  },
  {
   "t": "2026-06-18T15:58:37Z",
   "sha": "27ea72916b71e40859d7d86348eb3d99c4211b34"
  },
  {
   "t": "2026-06-18T17:18:25Z",
   "sha": "8be500e6bec2e4e664f36dea22c6419237ba9ec2"
  },
  {
   "t": "2026-06-18T19:28:06Z",
   "sha": "37fb1b596e2006ffb1af82945f81a27c2bc1777a"
  },
  {
   "t": "2026-06-29T00:09:48Z",
   "sha": "1ae28a401368448cc6466aada72afe2101ae7d61"
  },
  {
   "t": "2026-06-29T01:06:40Z",
   "sha": "12a237f9d3570f96663dd84550f9fcc25ee53584"
  },
  {
   "t": "2026-08-15T01:16:51Z",
   "sha": "058d434f3c5b25aef65dd71576576b35dfc9ce27"
  },
  {
   "t": "2026-08-24T14:22:43Z",
   "sha": "d364d7e35c3c7b5b9bfc44c4f4cb58fad09aa645"
  },
  {
   "t": "2026-09-08T18:13:40Z",
   "sha": "1d3a0270fcf3fcabd2249c4b06a071a32a7b364b"
  }
 ],
 "additions": 258,
 "deletions": 99,
 "changed_files": 31,
 "commit_count": 6,
 "size_bucket": "M",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {},
   "conflicts": [
    {
     "number": 35906,
     "title": "First steps towards a stateless, side-effect free validation library",
     "author": "purpleKarrot"
    },
    {
     "number": 35570,
     "title": "refactor: Change some validation.cpp methods to return BlockValidationState",
     "author": "optout21"
    },
    {
     "number": 35511,
     "title": "RFC: consensus: Make `CAmount` a class",
     "author": "hodlinator"
    },
    {
     "number": 34844,
     "title": "util: Add util::NotNull<SmartPtrType>",
     "author": "maflcko"
    },
    {
     "number": 29700,
     "title": "kernel, refactor: return error status on all fatal errors",
     "author": "ryanofsky"
    },
    {
     "number": 26022,
     "title": "Add util::ResultPtr class",
     "author": "ryanofsky"
    },
    {
     "number": 25665,
     "title": "refactor: Add util::Result failure types and ability to merge result values",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "maflcko",
   "sedited",
   "seduless",
   "stickies-v"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-08T18:13:40Z",
  "last_reviewer_activity": "2026-08-17T08:16:51Z",
  "last_reviewer": "maflcko",
  "author_silent_days": 8,
  "waiting_on_author_days": 0,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [
   34075,
   35496,
   35792,
   36103
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 35496,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-11",
    "title": "kernel: add `btck_set_mock_time` for testing time-dependent paths"
   },
   {
    "number": 34075,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-21",
    "title": "fees: Introduce Mempool Based Fee Estimation to reduce overestimation"
   },
   {
    "number": 35792,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-07-24",
    "title": "refactor: Make all `const static` class members `constexpr`"
   },
   {
    "number": 36103,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-08-31",
    "title": "validation: remove unused code"
   }
  ],
  "conflicts": [
   35906,
   35570,
   35511,
   34844,
   29700,
   26022,
   25665
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/node/chainstate.cpp",
  "src/test/fuzz/tx_pool.cpp",
  "src/test/validation_chainstatemanager_tests.cpp",
  "src/util/time.h",
  "src/validation.h"
 ],
 "body": "The main commit in this PR is the second commit adding a `btck_chainstate_manager_set_clock_time` API which lets kernel applications run validation code deterministically without depending on the system clock. This is an alternative to #35496, and one of several alternatives discussed in that PR, with some tradeoffs described in https://github.com/bitcoin/bitcoin/pull/35496#issuecomment-4735710317.\n\nThe other commits are indirectly related and could be moved to separate PRs (or dropped):\n\nDetails\n\n- The first commit fixes a timing race in the `chainstatemanager_ibd_exit_after_loading_blocks` test that happened because test code and validation code (in `UpdateIBDStatus`) were both calling `NodeClock::now()` to get the current clock time, and test relied on the times being the same for `tip_recent=true` checks. The failure this fixes should be rare, but I noticed it when I experimented with making time comparison in `IsTipRecent` more precise.\n\n- The third commit refactors mempool code to use a consistent way of getting and representing clock times, allowing the fourth commit to enforce that no libbitcoinkernel code uses nondeterministic clock times unintentionally. The third and fourth commits do not need to be part of this PR, but I implemented them to be sure the main commit was complete and all call sites were using the right clock times.",
 "commits": [
  {
   "sha": "f398f9359307ee4e3bd159836d530709fdc68476",
   "date": "2026-09-03T11:32:49Z",
   "message": "test: Fix nondeterministic clock race in chainstatemanager_ibd_exit_after_loading_blocks\n\nThe test set up the tip time using Now<NodeSeconds>() and then called\nUpdateIBDStatus(), which calls IsTipRecent(), which also calls\nNow<NodeSeconds>(). If a second boundary was crossed between the two\ncalls, the tip_recent=true case would fail spuriously.\n\nFix by freezing the clock with FakeNodeClock before the test runs.\n\nCo-Authored-By: seduless <seduless@proton.me>\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
  },
  {
   "sha": "53a822ec77437515994cff3372df03b132613cfd",
   "date": "2026-09-03T11:32:49Z",
   "message": "kernel, validation: scope clock time to ChainstateManager\n\nAdd ChainstateManager::Now() as the single injection point for the\ncurrent time in all validation paths, replacing direct NodeClock::now()\ncalls. A new m_clock_now_seconds field (std::atomic<std::chrono::seconds>)\nlets callers override the time for a chainstate manager instance.\n\nAffected paths:\n- ContextualCheckBlockHeader: future-time check\n- UpdateIBDStatus -> IsTipRecent: IBD latch (IsTipRecent gains a now\n  parameter so callers control what time is used)\n- ProcessNewBlockHeaders / ReportHeadersPresync: IBD progress logging\n- GuessVerificationProgress: verification_progress in block tip callbacks\n- VerifyLoadedChainstate: future-tip sanity check on startup\n\nThe kernel C API gains btck_chainstate_manager_set_clock_time(chainman,\nnow_seconds), and the C++ wrapper gains a matching SetClockTime() method.\nTwo concurrent test instances using different chainman objects see\nindependent clocks; no cleanup of global state is required between tests.\n\nNote: this commit slightly changes behavior of the\nIsCurrentForFeeEstimation and GuessVerificationProgress functions\nbecause these function previously did time calculations with 1-second\nprecision, and use with system clock level precision (typicaly\nnanoseconds). No other behavior outside of these two functions is\nchanging.\n\nCo-Authored-By: stringintech <stringintech@gmail.com>\nCo-Authored-By: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
  },
  {
   "sha": "d5312e631670baa24497e4883e64428de2abdb89",
   "date": "2026-09-03T11:32:49Z",
   "message": "mempool: Use NodeClock::time_point to represent times\n\nUse NodeClock::time_point instead of integer ticks or std::chrono::seconds\ndurations to represent time points in mempool code.  Using points is safer and\nmore precise and tends to simplify time calculations.\n\nThis also adds MempoolTime and CTxMemPool::Now() definitions for convenience,\nand to make it easier to add more determinism or type-checking to mempool code\nin the future without changing it.\n\nAnother benefit of this commit is that it gets rid of all GetTime() calls in\nthe kernel, which have long been deprecated. The integer GetTime() function is\ndeprecated because it does not return type-safe values. And the template\nGetTime() function has been deprecated since the NodeClock struct was added\nbecause it provides a subset of NodeClock functionality and confusingly returns\na duration rather than a time.\n\nCo-Authored-By: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>"
  },
  {
   "sha": "547b7daab9029811a5b6fa7e339433b3b6f47e59",
   "date": "2026-09-03T11:32:49Z",
   "message": "util/time: Disallow calling now() methods in kernel code\n\nMove NodeClock::now() and NodeClock::now() symbol definitions to a\ntime_nondet.cpp file so they will not be linked into kernel code and\naccidentally called there.\n\nKernel code should generally try to be deterministic and not rely on\ntime variables outside of application control. As an escape hatch,\n_now_nondet() methods are added to provide nondeterminism in cases where\nit is ok.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
  },
  {
   "sha": "86799babf5ca152b3a1d7773f424c9d19ceb4d69",
   "date": "2026-09-03T11:32:49Z",
   "message": "test: Use chainman-scoped clock in chainstatemanager_ibd_exit_after_loading_blocks\n\nReplace SetMockTime() with chainman.m_clock_now_seconds so the clock\nfrozen for the race-prevention matches the same clock that\nUpdateIBDStatus/IsTipRecent() reads. This also avoids touching any\nglobal state and lets the test more directly exercise the new\nchainman-scoped clock path.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
  },
  {
   "sha": "1d3a0270fcf3fcabd2249c4b06a071a32a7b364b",
   "date": "2026-09-03T11:32:49Z",
   "message": "test: Use chainman-scoped clock in utxo_total_supply fuzz target\n\nReplace FakeNodeClock (global mock time) with chainman.m_clock_now_seconds\nso the fuzzed time is set directly on the chainstate manager instance\nrather than via a global. This exercises the IBD and tip-age checks\nthrough the new per-chainman clock path. Byte consumption order from\nfuzzed_data_provider is unchanged so existing corpus entries remain valid.\n\nIdea for using clock time in utxo fuzz test from sedited in:\nhttps://github.com/bitcoin/bitcoin/pull/35557#issuecomment-4763429282\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
  }
 ],
 "timeline": [
  {
   "t": "2026-06-18T05:02:52Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "9f67c9b269cbc0da459eafa1a5ba357e82f07212",
   "in_reply_to": null,
   "text": "9f67c9b269cbc0da459eafa1a5ba357e82f07212: You can use `tip->Time()`, to avoid the cast here.\n\nGenerally, it is better to use the chrono types and let the compiler do the type checks. After compilation, there won't be a difference anyway."
  },
  {
   "t": "2026-06-18T05:12:15Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/util/time.h",
   "commit": "7d656ac341140dc80f73abcc45adc19f0430eaae",
   "in_reply_to": null,
   "text": "Seems fine, but this may be promoting ugly code, such as `count_seconds(DurationSinceEpoch<std::chrono::seconds>(...`\n\nI think generally it is better to use the correct std chrono type and let the compiler do the type checks. Casting a time point to a duration (since epoch) seems like a violation that should be avoided, for the same reasons that `GetTime` is deprecated.\n\nAt call sites you can just replace block->GetBlockTime() with block->Time() to avoid any casts, and this helper."
  },
  {
   "t": "2026-06-18T05:17:38Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.h",
   "commit": "9f67c9b269cbc0da459eafa1a5ba357e82f07212",
   "in_reply_to": null,
   "text": "Do we really want the cast here? The answer is probably, \"doesn't matter\", because consensus time checks are seconds-based, and the double-precision rolling update mempool code doesn't care about sub-second precision. Though, I wanted to point it out, that this is intentional and not just something that was most likely to the LLM.\n\nAn alternative could be to remove the cast here and only add the cast in call sites that need it (implicilty \"upgrading\" the call-sites to sub-second precision)"
  },
  {
   "t": "2026-06-18T09:52:49Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Thanks @maflcko! I was very dissatisfied with all the casts in the second commit and your tips should be helpful for getting rid of them. I will also implement your suggestion to not cast away precision in ChainstateManager::Now(). (The LLM actually didn't write the cast, but called `::Now<NodeSeconds>()` instead and I manually added the cast to try to be more explicit.)"
  },
  {
   "t": "2026-06-18T13:51:13Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "94622b041571f73e8e5e661b9bce4213b957a561"
  },
  {
   "t": "2026-06-18T13:55:34Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/chainstate.cpp",
   "commit": "9f67c9b269cbc0da459eafa1a5ba357e82f07212",
   "in_reply_to": 3433180374,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/35557#discussion_r3433180374\n\n[quoted text omitted]\nThanks! That is so much better and I applied this many places"
  },
  {
   "t": "2026-06-18T13:56:27Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/util/time.h",
   "commit": "7d656ac341140dc80f73abcc45adc19f0430eaae",
   "in_reply_to": 3433217273,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/35557#discussion_r3433217273\n\n[quoted text omitted]\nYou're right, dropped this now"
  },
  {
   "t": "2026-06-18T14:03:55Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/validation.h",
   "commit": "9f67c9b269cbc0da459eafa1a5ba357e82f07212",
   "in_reply_to": 3433238010,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/35557#discussion_r3433238010\n\n[quoted text omitted]\nI don't think so. It's definitely simpler not to have this and it is dropped now.\n\n[quoted text omitted]\nI guess it's fair to blame the LLM for this. Technically I added this cast, but the LLM originally wrote `::Now<NodeSeconds>()` which was casting internally. Smarter to avoid it entirely."
  },
  {
   "t": "2026-06-18T14:10:18Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "94622b041571f73e8e5e661b9bce4213b957a561",
   "text": "Updated 7d656ac341140dc80f73abcc45adc19f0430eaae -> 94622b041571f73e8e5e661b9bce4213b957a561 ([`pr/kclock.1`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.1) -> [`pr/kclock.2`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.2), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.1..pr/kclock.2)) adding a new commit to use time points to represent times in mempool code\n\nUpdated 94622b041571f73e8e5e661b9bce4213b957a561 -> 27ea72916b71e40859d7d86348eb3d99c4211b34 ([`pr/kclock.2`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.2) -> [`pr/kclock.3`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.3), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.2..pr/kclock.3)) to fix CI: compile error (duration_cast on time_point in TRACEPOINT calls) and nondeterministic test (clock race in chainstatemanager_ibd_exit_after_loading_blocks); also prepends a standalone test fix commit using only pre-existing SetMockTime API https://github.com/bitcoin/bitcoin/actions/runs/27764264509/job/82146558123\n\nUpdated 27ea72916b71e40859d7d86348eb3d99c4211b34 -> 8be500e6bec2e4e664f36dea22c6419237ba9ec2 ([`pr/kclock.3`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.3) -> [`pr/kclock.4`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.4), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.3..pr/kclock.4)) to fix fuzz UBSan signed integer overflow converting seconds to nanoseconds in ConsumeTxMemPoolEntry https://github.com/bitcoin/bitcoin/actions/runs/15491561394/job/82175291056\n\nUpdated 8be500e6bec2e4e664f36dea22c6419237ba9ec2 -> 37fb1b596e2006ffb1af82945f81a27c2bc1777a ([`pr/kclock.4`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.4) -> [`pr/kclock.5`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.5), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.4..pr/kclock.5)) to fix UBSan signed-integer-overflow: throw in LoadMempool when nTime is out of MempoolTime range; also use ConsumeTime() in ConsumeTxMemPoolEntry https://github.com/bitcoin/bitcoin/actions/runs/27776901912/job/82191293065"
  },
  {
   "t": "2026-06-18T14:24:36Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/test/fuzz/tx_pool.cpp",
   "commit": "27ea72916b71e40859d7d86348eb3d99c4211b34",
   "in_reply_to": null,
   "text": "probably not a problem in reality, but the call to `GetMockTime` here looks wrong for several reasons:\n\n* It directly access the test-only global of the mock time, which may be `0`, and thus may lead to silent bugs if mocktime was not used here?\n* It side-steps the `g_used_system_time` runtime sanitizer.\n* It returns the wrong type (it should be a time point, not a duration)\n\nI guess it would be better to just call `Now()` or `tx_pool.Now()` to fix all issues and avoid the NodeSeconds{} cast."
  },
  {
   "t": "2026-06-18T15:58:37Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "27ea72916b71e40859d7d86348eb3d99c4211b34"
  },
  {
   "t": "2026-06-18T17:18:25Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "8be500e6bec2e4e664f36dea22c6419237ba9ec2"
  },
  {
   "t": "2026-06-18T19:28:06Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "37fb1b596e2006ffb1af82945f81a27c2bc1777a"
  },
  {
   "t": "2026-06-18T20:45:15Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/fuzz/tx_pool.cpp",
   "commit": "27ea72916b71e40859d7d86348eb3d99c4211b34",
   "in_reply_to": 3436545216,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/35557#discussion_r3436545216\n\nMakes sense, switched GetMockTime() -> Now()"
  },
  {
   "t": "2026-06-18T21:01:53Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "37fb1b596e2006ffb1af82945f81a27c2bc1777a",
   "text": "Marked ready for review now that CI is passing. Possible questions for reviewers:\n\n- Should this PR be split up? I am thinking of dropping everything except the main commit 8a93ea0f2904ec780a690d987a25e5fa113552c9 and moving other commits to a followup PR. But happy to do anything.\n- Is `btck_chainstate_manager_set_clock_time(chainman, now)` a good kernel API? I think it is, giving applications control over time in a pretty granular way that doesn't get in the way of adding more control later.\n- Are the changes to validtion code ok? There's a new `ChainstateManager::m_clock_now_seconds` field which adds new state, but not much changes otherwise and the changes make code more consistent."
  },
  {
   "t": "2026-06-21T22:05:26Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nMy preference is larger pull requests usually, so I would keep this in one piece, but I would go a bit further. Can we use this new clock in one of the tests (maybe one of the utxo* fuzz tests, haven't looked too closely yet).\n\n[quoted text omitted]\nIf we set it in the options instead, we can fake the time once per instance, if we set it like here, it can be moved any number of times. I think I prefer that, as it seems to overlap more closely with the current global mechanics. The only reservation I have with this is that there might be a case where the clock needs to be set during chainman construction. I don't think that is the case right now, but that might change in the future.\n\n[quoted text omitted]\nI would feel more confident if something (a test, a utility, etc.) was actually exercising the various instances where the chainman-scoped fake time is used now."
  },
  {
   "t": "2026-06-23T14:44:41Z",
   "kind": "comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThis could get a bit annoying and potentially dangerous when users need to start managing clocks across multiple places. Perhaps a more ergonomic alternative could be to add a `btck_Clock` type which basically is just a callback that returns the current time? The callback can then be anything, e.g. a fixed value, the user's system time, a mocked clock, ...\n\nThat way, a single clock can be passed multiple times, and updated in a single place. Of course, it comes with its costs of increased API surface and lifetime concerns that a simple seconds setter doesn't have."
  },
  {
   "t": "2026-06-25T03:47:25Z",
   "kind": "review_comment",
   "who": "seduless",
   "assoc": "CONTRIBUTOR",
   "path": "src/test/validation_chainstatemanager_tests.cpp",
   "commit": "37fb1b596e2006ffb1af82945f81a27c2bc1777a",
   "in_reply_to": null,
   "text": "In commit \"test: Fix nondeterministic clock race in chainstatemanager_ibd_exit_after_loading_blocks\" (f0fea79bdaabbea40f1177702ff2c169d82f62be)\n\nNice fix, thanks for cleaning this up.\n\nInstead of bare `SetMockTime` calls, this is a good candidate for the RAII `FakeNodeClock`.\n\n```diff\ndiff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp\nindex b0176f641c..3c357844cd 100644\n--- a/src/test/validation_chainstatemanager_tests.cpp\n+++ b/src/test/validation_chainstatemanager_tests.cpp\n@@ -18,2 +18,3 @@\n #include <test/util/setup_common.h>\n+#include <test/util/time.h>\n #include <test/util/validation.h>\n@@ -22,3 +23,2 @@\n #include <util/result.h>\n-#include <util/time.h>\n #include <util/vector.h>\n@@ -178,3 +178,3 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_ibd_exit_after_loading_blocks, ChainTe\n     // causing a spurious failure in the tip_recent=true case.\n-    SetMockTime(Now<NodeSeconds>());\n+    FakeNodeClock clock{};\n\n@@ -214,3 +214,2 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_ibd_exit_after_loading_blocks, ChainTe\n     }\n-    SetMockTime(0);\n }\n```"
  },
  {
   "t": "2026-06-29T00:09:48Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "1ae28a401368448cc6466aada72afe2101ae7d61"
  },
  {
   "t": "2026-06-29T00:11:39Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/test/validation_chainstatemanager_tests.cpp",
   "commit": "37fb1b596e2006ffb1af82945f81a27c2bc1777a",
   "in_reply_to": 3471733323,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/35557#discussion_r3471733323\n\n[quoted text omitted]\nThanks! Applied your patch and switched to FakeNodeClock"
  },
  {
   "t": "2026-06-29T01:06:40Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "12a237f9d3570f96663dd84550f9fcc25ee53584"
  },
  {
   "t": "2026-06-29T01:30:16Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "12a237f9d3570f96663dd84550f9fcc25ee53584",
   "text": "re: sedited https://github.com/bitcoin/bitcoin/pull/35557#issuecomment-4763429282\n\n[quoted text omitted]\nThanks, kept all commits for now and added new tests as suggested.\n\nre: stickies-v https://github.com/bitcoin/bitcoin/pull/35557#issuecomment-4780411600\n\n[quoted text omitted]\nThis is an interesting idea. Implemented in 3d513c5d03ceb8d33dc8e19c07149e3337c64ac6 to see what it would look like.\n\nThe implementation barely even affects validation code so I think the main question is does it seem safer or easier to use for kernel applications?\n\nMy instinct is that it doesn't because if you're creating multiple chainstate managers or other objects that accept times, and your application needs artificial times instead of the current clock time, I wouldn't assume that multiple objects would want to have the same time set. Or if they did, I wouldn't assume that setting the time once on a shared clock object would be much easier than setting the time directly on the relevant objects.\n\nBut I also think this alternate API is clean, and would have no problem switching to this approach. It also seems like it wouldn't be hard to switch approaches later (with compatibly even).\n\n---\n\nUpdated 37fb1b596e2006ffb1af82945f81a27c2bc1777a -> 1ae28a401368448cc6466aada72afe2101ae7d61 ([`pr/kclock.5`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.5) -> [`pr/kclock.6`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.6), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.5..pr/kclock.6)) adding suggested tests\n\nUpdated 1ae28a401368448cc6466aada72afe2101ae7d61 -> 12a237f9d3570f96663dd84550f9fcc25ee53584 ([`pr/kclock.6`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.6) -> [`pr/kclock.7`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.7), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.6..pr/kclock.7)) to fix utxo_total_supply fuzz g_used_system_time failure https://github.com/bitcoin/bitcoin/actions/runs/28340730799/job/83954616774\n\nRebased 12a237f9d3570f96663dd84550f9fcc25ee53584 -> 058d434f3c5b25aef65dd71576576b35dfc9ce27 ([`pr/kclock.7`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.7) -> [`pr/kclock.8`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.8), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.7-rebase..pr/kclock.8)) due to conflicts with #35496 and #35792\n\nRebased 058d434f3c5b25aef65dd71576576b35dfc9ce27 -> d364d7e35c3c7b5b9bfc44c4f4cb58fad09aa645 ([`pr/kclock.8`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.8) -> [`pr/kclock.9`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.9), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.8-rebase..pr/kclock.9)) due to conflicts with #34075\n\nRebased d364d7e35c3c7b5b9bfc44c4f4cb58fad09aa645 -> 1d3a0270fcf3fcabd2249c4b06a071a32a7b364b ([`pr/kclock.9`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.9) -> [`pr/kclock.10`](https://github.com/ryanofsky/bitcoin/commits/pr/kclock.10), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/kclock.9-rebase..pr/kclock.10)) due to conflict with #36103"
  },
  {
   "t": "2026-08-15T01:16:51Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "058d434f3c5b25aef65dd71576576b35dfc9ce27"
  },
  {
   "t": "2026-08-17T08:16:51Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThat one was merged, so is this here still relevant?\n\nAlso, this conflicts with https://github.com/bitcoin/bitcoin/pull/35906#discussion_r3726539086"
  },
  {
   "t": "2026-08-24T14:22:43Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "d364d7e35c3c7b5b9bfc44c4f4cb58fad09aa645"
  },
  {
   "t": "2026-09-08T18:13:40Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "1d3a0270fcf3fcabd2249c4b06a071a32a7b364b"
  }
 ],
 "labels_log": [
  {
   "t": "2026-06-18T04:07:44Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-18T20:42:21Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-29T01:08:21Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-29T02:12:44Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-09T13:43:20Z",
   "action": "labeled",
   "label": "Kernel",
   "who": "willcl-ark"
  },
  {
   "t": "2026-07-09T13:43:32Z",
   "action": "labeled",
   "label": "Validation",
   "who": "willcl-ark"
  },
  {
   "t": "2026-07-24T18:57:49Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-15T02:47:43Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-21T08:25:37Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T15:53:56Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-31T16:53:59Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-08T20:12:03Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-06-18T21:01:11Z",
   "kind": "ready_for_review",
   "who": "ryanofsky"
  }
 ],
 "text_chars": 17683,
 "text_tokens_estimate": 4420,
 "changed_paths": [
  "src/bench/blockencodings.cpp",
  "src/bench/mempool_ephemeral_spends.cpp",
  "src/bench/mempool_eviction.cpp",
  "src/bench/mempool_stress.cpp",
  "src/bench/rpc_mempool.cpp",
  "src/chain.h",
  "src/kernel/bitcoinkernel.cpp",
  "src/kernel/bitcoinkernel.h",
  "src/kernel/bitcoinkernel_wrapper.h",
  "src/kernel/mempool_entry.h",
  "src/node/chainstate.cpp",
  "src/node/mempool_persist.cpp",
  "src/rpc/mempool.cpp",
  "src/test/fuzz/package_eval.cpp",
  "src/test/fuzz/rbf.cpp",
  "src/test/fuzz/tx_pool.cpp",
  "src/test/fuzz/util/mempool.cpp",
  "src/test/fuzz/utxo_total_supply.cpp",
  "src/test/kernel/test_kernel.cpp",
  "src/test/rbf_tests.cpp",
  "src/test/util/setup_common.cpp",
  "src/test/util/txmempool.cpp",
  "src/test/validation_chainstatemanager_tests.cpp",
  "src/txmempool.cpp",
  "src/txmempool.h",
  "src/util/CMakeLists.txt",
  "src/util/time.cpp",
  "src/util/time.h",
  "src/util/time_nondet.cpp",
  "src/validation.cpp",
  "src/validation.h"
 ],
 "files": [
  {
   "path": "src/bench/blockencodings.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/bench/mempool_ephemeral_spends.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/bench/mempool_eviction.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/bench/mempool_stress.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/bench/rpc_mempool.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/chain.h",
   "add": 4,
   "del": 2
  },
  {
   "path": "src/kernel/bitcoinkernel.cpp",
   "add": 10,
   "del": 0
  },
  {
   "path": "src/kernel/bitcoinkernel.h",
   "add": 28,
   "del": 0
  },
  {
   "path": "src/kernel/bitcoinkernel_wrapper.h",
   "add": 7,
   "del": 0
  },
  {
   "path": "src/kernel/mempool_entry.h",
   "add": 5,
   "del": 3
  },
  {
   "path": "src/node/chainstate.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/node/mempool_persist.cpp",
   "add": 9,
   "del": 2
  },
  {
   "path": "src/rpc/mempool.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/test/fuzz/package_eval.cpp",
   "add": 3,
   "del": 3
  },
  {
   "path": "src/test/fuzz/rbf.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/test/fuzz/tx_pool.cpp",
   "add": 5,
   "del": 5
  },
  {
   "path": "src/test/fuzz/util/mempool.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/test/fuzz/utxo_total_supply.cpp",
   "add": 6,
   "del": 3
  },
  {
   "path": "src/test/kernel/test_kernel.cpp",
   "add": 35,
   "del": 0
  },
  {
   "path": "src/test/rbf_tests.cpp",
   "add": 17,
   "del": 17
  },
  {
   "path": "src/test/util/setup_common.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/test/util/txmempool.cpp",
   "add": 3,
   "del": 3
  },
  {
   "path": "src/test/validation_chainstatemanager_tests.cpp",
   "add": 9,
   "del": 1
  },
  {
   "path": "src/txmempool.cpp",
   "add": 8,
   "del": 8
  },
  {
   "path": "src/txmempool.h",
   "add": 19,
   "del": 5
  },
  {
   "path": "src/util/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/util/time.cpp",
   "add": 2,
   "del": 4
  },
  {
   "path": "src/util/time.h",
   "add": 13,
   "del": 3
  },
  {
   "path": "src/util/time_nondet.cpp",
   "add": 14,
   "del": 0
  },
  {
   "path": "src/validation.cpp",
   "add": 29,
   "del": 29
  },
  {
   "path": "src/validation.h",
   "add": 21,
   "del": 1
  }
 ],
 "test_lines": 126,
 "git": {
  "head": "1d3a0270fcf3fcabd2249c4b06a071a32a7b364b",
  "head_matches_backup": true,
  "base": "4ec6ff022a4b33fab46afa5656a983cda8ba3099",
  "commits": [
   {
    "sha": "f398f93593",
    "subject": "test: Fix nondeterministic clock race in chainstatemanager_ibd_exit_after_loading_blocks",
    "files": 1,
    "add": 6,
    "del": 0
   },
   {
    "sha": "53a822ec77",
    "subject": "kernel, validation: scope clock time to ChainstateManager",
    "files": 8,
    "add": 117,
    "del": 15
   },
   {
    "sha": "d5312e6316",
    "subject": "mempool: Use NodeClock::time_point to represent times",
    "files": 19,
    "add": 89,
    "del": 69
   },
   {
    "sha": "547b7daab9",
    "subject": "util/time: Disallow calling now() methods in kernel code",
    "files": 7,
    "add": 39,
    "del": 13
   },
   {
    "sha": "86799babf5",
    "subject": "test: Use chainman-scoped clock in chainstatemanager_ibd_exit_after_loading_blocks",
    "files": 1,
    "add": 9,
    "del": 7
   },
   {
    "sha": "1d3a0270fc",
    "subject": "test: Use chainman-scoped clock in utxo_total_supply fuzz target",
    "files": 1,
    "add": 6,
    "del": 3
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "2899c0a1372aee07",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}