rpc: tighten setmocktime upper bound to UINT32_MAX #35519

pull stringintech wants to merge 1 commits into bitcoin:master from stringintech:2026/06/rpc-setmocktime-upperbound changing 3 files +6 −6
  1. stringintech commented at 12:55 PM on June 12, 2026: contributor

    The previous upper bound for setmocktime was std::chrono::nanoseconds::max() converted to seconds (~year 2262). This was too permissive in two ways:

    1. Paths that add an offset to the mocked time can overflow int64_t (caught by UBSan). For example, ContextualCheckBlockHeader adds a constant to the current time for its future-time check. (see comment)

    2. Paths that assign the mocked time to a uint32_t field silently truncate it (caught by the integer sanitizer). For example, miner.cpp assigns NodeClock::now() directly to pblock->nTime. (see comment)

    UINT32_MAX is the natural ceiling since block header nTime is uint32_t, making mocked values beyond it meaningless for anything consensus-related.

  2. DrahtBot added the label RPC/REST/ZMQ on Jun 12, 2026
  3. DrahtBot commented at 12:55 PM on June 12, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35519.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK sedited, winterrdog
    Stale ACK maflcko

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):

    • assert_raises_rpc_error(-8, f"Mocktime must be in the range [0, {time_2106}], not -1.", self.nodes[0].setmocktime, -1) in test/functional/rpc_blockchain.py

    <sup>2026-06-13 09:48:41</sup>

  4. stringintech force-pushed on Jun 12, 2026
  5. DrahtBot added the label CI failed on Jun 12, 2026
  6. DrahtBot commented at 1:02 PM on June 12, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/27416995525/job/81032244191</sub> <sub>LLM reason (✨ experimental): CI failed because the lint test detected a file with a shebang (test/functional/rpc_mocktime.py) that lacks executable permission (644 instead of 755), causing lint-files.py to fail.</sub>

    <details><summary>Hints</summary>

    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.

    </details>

  7. in test/functional/rpc_mocktime.py:20 in e176de41e2 outdated
      15 | +
      16 | +    def run_test(self):
      17 | +        self._test_mocktime_bounds()
      18 | +
      19 | +    def _test_mocktime_bounds(self):
      20 | +        max_time = 2**32 - 1  # maximum representable block timestamp
    


    maflcko commented at 1:03 PM on June 12, 2026:

    style nit: All good, but seems a bit overkill to have a full test+node for a single test-only RPC call. Maybe just recycle the existing test case for this:

    test/functional/rpc_blockchain.py:        time_2106 = 2**32 - 1
    

    and add the two failing RPC calls there?


    stringintech commented at 1:22 PM on June 12, 2026:

    Done. Thanks!

  8. maflcko approved
  9. maflcko commented at 1:03 PM on June 12, 2026: member

    lgtm

  10. stringintech force-pushed on Jun 12, 2026
  11. stringintech force-pushed on Jun 12, 2026
  12. maflcko commented at 1:45 PM on June 12, 2026: member

    lgtm ACK bf2d7fc3615622f869eb0bafd9696329a16c9e1f

  13. sedited commented at 1:59 PM on June 12, 2026: contributor

    Concept ACK

  14. DrahtBot removed the label CI failed on Jun 12, 2026
  15. in test/functional/rpc_blockchain.py:294 in bf2d7fc361
     289 | @@ -290,6 +290,8 @@ def _test_y2106(self):
     290 |          self.log.info("Check that block timestamps work until year 2106")
     291 |          self.generate(self.nodes[0], 8)[-1]
     292 |          time_2106 = 2**32 - 1
     293 | +        assert_raises_rpc_error(-8, f"Mocktime must be in the range [0, {time_2106}], not -1.", self.nodes[0].setmocktime, -1)
     294 | +        assert_raises_rpc_error(-8, f"Mocktime must be in the range [0, {time_2106}], not {time_2106 + 1}", self.nodes[0].setmocktime, time_2106 + 1)
    


    winterrdog commented at 8:07 PM on June 12, 2026:

    nano nit: missing trailing . in the error string to match the strprintf output in node.cpp:

            assert_raises_rpc_error(-8, f"Mocktime must be in the range [0, {time_2106}], not {time_2106 + 1}.", self.nodes[0].setmocktime, time_2106 + 1)
    

    (will not affect test behaviour since assert_raises_rpc_error does substring matching, but keeps it consistent with the line above.)

  16. winterrdog commented at 8:07 PM on June 12, 2026: none

    crACK bf2d7fc3615622f869eb0bafd9696329a16c9e1f

  17. DrahtBot requested review from sedited on Jun 12, 2026
  18. rpc: tighten setmocktime upper bound to UINT32_MAX
    The previous bound (~year 2262) was too permissive: paths that add an offset to the mocked time (e.g. the future-time check in ContextualCheckBlockHeader) can overflow int64_t (caught by UBSan), and paths that assign it to a uint32_t field (e.g. pblock->nTime in miner.cpp) silently truncate it (caught by the integer sanitizer). UINT32_MAX is the natural ceiling since block header nTime is uint32_t, and mocking beyond it is meaningless for anything consensus-related.
    
    Add setmocktime bound checks to the existing _test_y2106 case in rpc_blockchain.py, and remove the negative bound check from rpc_uptime.py.
    406c2348dd
  19. stringintech force-pushed on Jun 13, 2026
  20. sedited approved
  21. sedited commented at 1:27 PM on June 14, 2026: contributor

    ACK 406c2348ddbf5ade903280e8dcda9cf62ea632a3

  22. DrahtBot requested review from maflcko on Jun 14, 2026
  23. DrahtBot requested review from winterrdog on Jun 14, 2026
  24. winterrdog commented at 1:38 PM on June 14, 2026: none

    ACK 406c2348ddbf5ade903280e8dcda9cf62ea632a3

  25. fanquake merged this on Jun 14, 2026
  26. fanquake closed this on Jun 14, 2026


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-06-20 23:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me