{
 "number": 32229,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/32229",
 "title": "tests: Add unix timestamp tests for OP_CLTV and max mediantimepast tests",
 "author": "Christewart",
 "author_association": "CONTRIBUTOR",
 "created_at": "2025-04-07T16:44:37Z",
 "updated_at": "2026-09-16T15:37:23Z",
 "age_days": 527,
 "draft": false,
 "labels": [
  "Tests"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
 "head_ref": "2025-04-06-locktime-tests",
 "head_repo": "Christewart/bitcoin",
 "head_history": [
  {
   "t": "2025-04-07T16:45:55Z",
   "sha": "4d2e1089c4a6e07887e123abdd0a8d88c837efe9"
  },
  {
   "t": "2025-04-08T00:18:00Z",
   "sha": "69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8"
  },
  {
   "t": "2025-04-08T16:32:53Z",
   "sha": "062c31b72e1fab5ed2516ef7c5700ed9340dfe11"
  },
  {
   "t": "2025-08-02T18:57:16Z",
   "sha": "cbc1095adb8f729c2cb06574144187a16f45c68a"
  },
  {
   "t": "2026-07-05T19:17:25Z",
   "sha": "533d0c608312beaeb47bb5373169a17f9c756814"
  },
  {
   "t": "2026-07-29T19:07:11Z",
   "sha": "1f05d8e0364fa4b009e558c97e821be70313b8bc"
  }
 ],
 "additions": 107,
 "deletions": 7,
 "changed_files": 2,
 "commit_count": 1,
 "size_bucket": "M",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "sedited",
      "url": "https://github.com/bitcoin/bitcoin/pull/32229#issuecomment-4518177621"
     }
    ]
   },
   "conflicts": []
  }
 },
 "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": [
   "fanquake",
   "mabu44",
   "sedited"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-07-29T19:08:34Z",
  "last_reviewer_activity": "2026-09-16T15:37:08Z",
  "last_reviewer": "sedited",
  "author_silent_days": 49,
  "waiting_on_author_days": 1,
  "days_since_update": 1
 },
 "refs": {
  "mentioned": [
   35089
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 35089,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-04-19",
    "title": "test: Allow to set height in create_block"
   }
  ],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "test/functional/feature_cltv.py",
  "test/functional/feature_csv_activation.py"
 ],
 "body": "This PR adds a functional (p2p/block-validation) test for `OP_CHECKLOCKTIMEVERIFY` (BIP65) using unix-timestamp locktimes in test/functional/feature_cltv.py. It also adds tests around the maximum possible median-time-past (MTP) value, `UINT32_MAX`, and how that interacts with transaction finality.\n\nThe unix-timestamp portion of BIP65 already has unit-level coverage in `transaction_tests.cpp` (via `tx_valid.json`/`tx_invalid.json`), but those tests call `VerifyScript()` directly and never exercise median-time-past (MTP) or block connection. MTP-vs-nLockTime behavior itself is covered separately in `miner_tests.cpp` (lines 525-534) and `feature_csv_activation.py` (lines 340-355), but neither exercises `OP_CLTV` specifically. This test closes that gap: it builds and submits full blocks over p2p and checks that a block containing an `OP_CLTV`-locked output is only accepted once BIP113 MTP actually satisfies the requested locktime.\n\nThis PR also adds a BIP113 test to `feature_csv_activation.py` showing that MTP can never advance past `UINT32_MAX` - 1, so an output with a plain nLockTime of `UINT32_MAX` can never be confirmed. This is a general BIP113 property independent of `OP_CLTV`.\n\nThanks to @mabu44 and @sedited for the review so far.",
 "commits": [
  {
   "sha": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "date": "2026-07-29T18:56:35Z",
   "message": "test: add functional coverage for OP_CLTV unix-timestamp locktimes and BIP113 interaction\n\nAdd a functional (p2p/block-validation) test for OP_CHECKLOCKTIMEVERIFY\nusing unix-timestamp locktimes, including its interplay with BIP113\nmedian-time-past (MTP) rules: a block containing an OP_CLTV-locked\noutput is only accepted once MTP satisfies the requested locktime.\n\nAlso add a BIP113 test to feature_csv_activation.py showing that MTP\ncan never exceed UINT32_MAX, so an output with a plain nLockTime of\nUINT32_MAX can never be confirmed: BIP113 requires nLockTime to be\nstrictly less than MTP, and MTP itself can reach but never exceed\nUINT32_MAX (nTime is a uint32 field, and a block's timestamp must\nexceed the MTP of the blocks preceding it, so once MTP hits UINT32_MAX\nno further block -- and thus no further MTP advance -- is possible).\nThis is a general BIP113 property independent of OP_CLTV, so it lives\nalongside the other BIP113 tests rather than in feature_cltv.py."
  }
 ],
 "timeline": [
  {
   "t": "2025-04-07T16:45:55Z",
   "kind": "force_push",
   "who": "Christewart",
   "commit": "4d2e1089c4a6e07887e123abdd0a8d88c837efe9"
  },
  {
   "t": "2025-04-08T00:18:00Z",
   "kind": "force_push",
   "who": "Christewart",
   "commit": "69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8"
  },
  {
   "t": "2025-04-08T08:21:45Z",
   "kind": "review_comment",
   "who": "mabu44",
   "assoc": "NONE",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": null,
   "text": "nit: typo \"me**a**dian\""
  },
  {
   "t": "2025-04-08T08:27:37Z",
   "kind": "review_comment",
   "who": "mabu44",
   "assoc": "NONE",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": null,
   "text": "Do we need to create a new time-locked transaction? Cannot we use the one that is already in spendtx?"
  },
  {
   "t": "2025-04-08T08:43:14Z",
   "kind": "review_comment",
   "who": "mabu44",
   "assoc": "NONE",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": null,
   "text": "Here you are testing what will happen in the year 2106 if no changes are deployed in the meantime. Right?"
  },
  {
   "t": "2025-04-08T12:01:41Z",
   "kind": "review",
   "who": "mabu44",
   "assoc": "NONE",
   "state": "COMMENTED",
   "commit": "69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8",
   "text": "The Unix-timestamp portion of BIP65 is currently tested in the c++ unit tests in \"transactions_tests.cpp\". Test data includes transactions that have OP_CLTV with Unix timestamps (the files are /src/test/data/tx_valid.json and tx_invalid.json).\nDoes your test cover scenarios that are not covered in the existing tests?"
  },
  {
   "t": "2025-04-08T16:23:11Z",
   "kind": "comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "text": "Hi @mabu44 . Thanks for taking a look at this.\n\n[quoted text omitted]\nYes I believe so. I took a look at the values in `tx_valid.json` and `tx_invalid.json`. Here is a table\n\n| OP_CLTV parameter | Transaction locktime field | Valid |\n|-------------------|----------------------------|--------|\n| 0                 | 0                          | true   |\n| 499999999         | 499999999                  | true   |\n| 0                 | 499999999                  | true   |\n| 500000000         | 500000000                  | true   |\n| 4294967295        | 4294967295                 | true   |\n| 500000000         | 4294967295                 | true   |\n| 0                 | 0                          | true   |\n| -11               | 500000000                  | true   |\n| -19               | 4294967294                 | true   |\n| 0                 | 0                          | true   |\n| 1                 | 0                          | false  |\n| 499999999         | 499999998                  | false  |\n| 500000001         | 500000000                  | false  |\n| 4294967295        | 4294967294                 | false  |\n| -1                | 0                          | false  |\n| -1                | 500000000                  | false  |\n| 0                 | 0                          | false  |\n| 0                 | 0                          | false  |\n| 0                 | 500000000                  | false  |\n| 499999999         | 500000000                  | false  |\n| 500000000         | 0                          | false  |\n| 500000000         | 499999999                  | false  |\n| 4294967296        | 4294967295                 | false  |\n| 2147483648        | 2147483647                 | false  |\n| 0                 | 0                          | false  |\n\nThis test also directly tests the median-time-past logic. This is not tested in `tx_{valid,invalid}.json` as we just [directly call `VerifyScript()`](https://github.com/bitcoin/bitcoin/blob/cfe025ff0e1dcf984179a5a9b01dc8b865d95409/src/test/transaction_tests.cpp#L129) for individual transactions in the test files.\n\nInterestingly, i think there may be one test case overlap with `tx_valid.json`. While this transaction could be valid with relay policy I don't believe a transaction with these locktimes would be allowed to be included in a block? This is because median-time-past logic for a block with this transaction could be not be satisfied as per my last test case [here](https://github.com/Christewart/bitcoin/blob/69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8/test/functional/feature_cltv.py#L256).\n\n[quoted text omitted]\nSome more eyes on this could be good as I may be making a mistake."
  },
  {
   "t": "2025-04-08T16:26:06Z",
   "kind": "review_comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": 2032674574,
   "text": "I believe so because the previous one was mined in a valid block here: https://github.com/Christewart/bitcoin/blob/69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8/test/functional/feature_cltv.py#L213"
  },
  {
   "t": "2025-04-08T16:32:53Z",
   "kind": "force_push",
   "who": "Christewart",
   "commit": "062c31b72e1fab5ed2516ef7c5700ed9340dfe11"
  },
  {
   "t": "2025-04-10T11:44:32Z",
   "kind": "review_comment",
   "who": "mabu44",
   "assoc": "NONE",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": 2032674574,
   "text": "This tx was mined in [line 195](https://github.com/Christewart/bitcoin/blob/69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8/test/functional/feature_cltv.py#L195), not [213](https://github.com/Christewart/bitcoin/blob/69b6bb9438095f84ce90aecfc4e76b0ff21cc2b8/test/functional/feature_cltv.py#L213). I would move the creation of the transaction from line 230 to line 209. Otherwise, the check at line 218 could succeed not for the timelock (that is what we expect) but because of the duplicated transaction."
  },
  {
   "t": "2025-04-10T11:46:03Z",
   "kind": "review_comment",
   "who": "mabu44",
   "assoc": "NONE",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": null,
   "text": "This line can be removed"
  },
  {
   "t": "2025-04-10T11:47:13Z",
   "kind": "review_comment",
   "who": "mabu44",
   "assoc": "NONE",
   "path": "test/functional/feature_cltv.py",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a",
   "in_reply_to": null,
   "text": "This comment was not updated to reflect what the code is doing (same for the comments at line 256 and 258)."
  },
  {
   "t": "2025-04-10T12:03:43Z",
   "kind": "review",
   "who": "mabu44",
   "assoc": "NONE",
   "state": "COMMENTED",
   "commit": "01d2068fb66634bbb0851f042dc18d7fc89649dd",
   "text": "So this is an integration test of:\n- *Transaction validity based on input script and transaction locktime*: currently tested in [transactions_tests.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/test/transaction_tests.cpp);\n- *Transaction validity based on median block time*: currently tested in [miner_tests.cpp (lines 525-534)](https://github.com/bitcoin/bitcoin/blob/b8cefeb221490868d62b7a0695f8b5ea392d3654/src/test/miner_tests.cpp#L525-L534) and [feature_csv_activation.py (lines 340-355)](https://github.com/bitcoin/bitcoin/blob/b8cefeb221490868d62b7a0695f8b5ea392d3654/test/functional/feature_csv_activation.py#L340-L355)\n\nwith some more edge cases relative to the year 2106. Right?\n\n[quoted text omitted]\nI think that such a transaction will become relay-valid in 2106, but, unless consensus changes, it will never be mined because no blocks will be produced to mine it."
  },
  {
   "t": "2025-04-10T17:11:59Z",
   "kind": "comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "text": "Thank you again for the careful review. I've integrated your code review in 024c3bf\n\n[quoted text omitted]\nYes.\n\n[quoted text omitted]\nThat is my understanding as well :+1:"
  },
  {
   "t": "2025-08-02T18:57:16Z",
   "kind": "force_push",
   "who": "Christewart",
   "commit": "cbc1095adb8f729c2cb06574144187a16f45c68a"
  },
  {
   "t": "2025-12-03T11:02:51Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "cc @petertodd"
  },
  {
   "t": "2026-03-03T13:13:28Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "If I understand this change correctly, this adds test cases for the finality of a block's transactions and how they might interplay with CLTV. Can you re-formulate the PR description to make it clear what this actually tests? Contrary to your current description, it looks like we are already testing unix timestamp values in the locktime extensively. Are the finality tests better suited for `feature_csv_activation`?"
  },
  {
   "t": "2026-04-30T14:56:39Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "@Christewart any chance you want to follow up to the above?"
  },
  {
   "t": "2026-04-30T18:42:24Z",
   "kind": "comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "text": "Hi @sedited\n\n[quoted text omitted]\n`feature_csv_activation.py` tests relative lock times and the `OP_CHECKSEQUENCEVERIFY` opcode. This test case is testing `OP_CHECKLOCKTIMEVERIFY` and absolute wall clock locktimes (\"unix timestamps\"). Different fields on the transaction are used for verification (`sequence` vs `locktime`).\n\n[quoted text omitted]\nIn my opinion no so since this is testing absolute wall clock locktimes via a different opcode - `OP_CLTV`.\n\nThe real interesting part to me is the [setting the unix timestamp of the node to `UINT32_MAX`](https://github.com/Christewart/bitcoin/blob/cbc1095adb8f729c2cb06574144187a16f45c68a/test/functional/feature_cltv.py#L239), and then attempting to spend `OP_CLTV` locked utxos when we have reached the `UINT32_MAX` timestamp in the locktime field.\n\nSince we cannot satisfy the MTP requirement of BIP113 (i.e. we cannot create a block with timestamp `UINT32_MAX+1` so we are following BIP113 and monotonically increase the timestamp on the block) - the utxo can never be spent.\n\nFrom a quick glance through `feature_csv_activation.py` I don't see any references to `2**32` or `UINT32_MAX` - so I doubt this edge case is tested there - although if you could link to an exact line that it was tested on that would be helpful.\n\nIn general, I think @mabu44 's comment was good:\n\nhttps://github.com/bitcoin/bitcoin/pull/32229#pullrequestreview-2756380784\n\nEDIT:\n\nLooking closer at `feature_csv_activation.py` it does look like it tests BIP113 logic (its unfortunate the file is named after the opcode and is testing more than the opcode). The logic testing `UINT32_MAX` could be moved over to that file, however the `OP_CLTV` test logic should stay here and I still believe there is no integration tests for OP_CLTV and unix timestamps - please link if you find them"
  },
  {
   "t": "2026-05-22T11:18:03Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nYes, sorry for not being clearer on this before, but that is what I was suggesting.\n\n[quoted text omitted]\nThanks for linking mabu44's comment again, I was referring to the same tests too. Maybe mention them in the PR descritpion?\n\n[quoted text omitted]\nI guess once that MTP is reached, we'll have to change some part of the calculation anyway, but I'm fine with having a test for documenting this.\n\nConcept ACK"
  },
  {
   "t": "2026-07-05T19:17:25Z",
   "kind": "force_push",
   "who": "Christewart",
   "commit": "533d0c608312beaeb47bb5373169a17f9c756814"
  },
  {
   "t": "2026-07-05T19:17:39Z",
   "kind": "comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "text": "Hi @sedited , I pushed a new commit: 533d0c608312beaeb47bb5373169a17f9c756814\n\nHere are the things that i've changed since you've last reviewed\n\n   - Rewrote the PR description to clarify what this actually tests and to credit the existing coverage you and @mabu44 pointed to (see above).\n   - Split the `UINT32_MAX` / median-time-past edge case out of `feature_cltv.py` and into `feature_csv_activation.py`, since that behavior is a general BIP113 property and not specific to `OP_CLTV` (per our earlier discussion).\n   - Rebased onto latest master.\n   - The rebase pulled in #35089 (`create_block`'s `height=` kwarg replacing the old `create_coinbase(...)` calling convention), which broke a few call sites this PR touches. Fixed those up to match the new convention.\n\nLet me know if this addresses your concerns or if there's anything else you'd like changed."
  },
  {
   "t": "2026-07-23T13:56:51Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "533d0c608312beaeb47bb5373169a17f9c756814",
   "in_reply_to": null,
   "text": "Nit: Missing space (and for the other `cltv_validate` call too)."
  },
  {
   "t": "2026-07-23T14:59:47Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "533d0c608312beaeb47bb5373169a17f9c756814",
   "in_reply_to": null,
   "text": "If I remove this line, the test still passes. Is it required? Doesn't this also just append another scriptsig to the existing one?"
  },
  {
   "t": "2026-07-23T15:11:58Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "533d0c608312beaeb47bb5373169a17f9c756814",
   "in_reply_to": null,
   "text": "How about:\n```\n        # expect failure as we haven't satisfied wall clock time yet\n        with self.nodes[0].assert_debug_log(expected_msgs=['bad-txns-nonfinal']):\n            peer.send_and_ping(msg_block(block2))\n            assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), block2.hash_int)\n```\nAs done further above in the file to capture the rejection reason?"
  },
  {
   "t": "2026-07-23T16:19:40Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_csv_activation.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": null,
   "text": "Is this really exercising the edge case behaviour? It seems kind of obvious that for as long as the MTP isn't maxed out, the transaction will fail. From what I gather we want to show that a transaction with nLockTime will never be mined. Wouldn't it be better to mine to an MTP of UINT32_MAX, and then show that a) submitting a transaction to the mempool with nLockTime at UINT32_MAX fails, and that extending the chain further with a block containing the transaction will fail with \"time-too-old\"."
  },
  {
   "t": "2026-07-29T19:07:11Z",
   "kind": "force_push",
   "who": "Christewart",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc"
  },
  {
   "t": "2026-07-29T19:08:34Z",
   "kind": "comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "text": "@sedited I believe all your points are integrated into https://github.com/bitcoin/bitcoin/pull/32229/commits/1f05d8e0364fa4b009e558c97e821be70313b8bc"
  },
  {
   "t": "2026-09-16T14:32:35Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": null,
   "text": "Why is this line changed? Seems like it is not actually changing anything behaviour wise."
  },
  {
   "t": "2026-09-16T14:35:11Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": null,
   "text": "The test passes if this line is left the same, so maybe this should not be changed?"
  },
  {
   "t": "2026-09-16T14:52:51Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": null,
   "text": "Why twelve, doesn't this test only need eleven?"
  },
  {
   "t": "2026-09-16T15:06:18Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": null,
   "text": "Might it be better to derive this from the mediantime directly? Something like:\n```python\nlocktime = self.nodes[0].getblockheader(block.hash_hex)['mediantime'] + (60 * 60) # 1 hour\n```"
  },
  {
   "t": "2026-09-16T15:10:38Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_cltv.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": null,
   "text": "Nit: create_block has a txlist arg that this without having to do it manually."
  },
  {
   "t": "2026-09-16T15:37:08Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "test/functional/feature_csv_activation.py",
   "commit": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
   "in_reply_to": 3639682004,
   "text": "Looked at the latest version here and I think this is still not addressed, but my comment was not really helpful. The interesting case in my eyes is that on the final block, a UINT32_MAX - 1 timelocked transaction is considered standard and enters the mempool, but can't ever be mined. How about adding this:\n\n```diff\ndiff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py\nindex 410278f407b..943890d81bc 100755\n--- a/test/functional/feature_csv_activation.py\n+++ b/test/functional/feature_csv_activation.py\n@@ -61,7 +61,7 @@ from test_framework.wallet import (\n )\n\n TESTING_TX_COUNT = 83  # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above)\n-MTP_EDGE_CASE_INPUT_COUNT = 2  # Extra inputs for the \"median-time-past can never reach UINT32_MAX\" BIP113 test\n+MTP_EDGE_CASE_INPUT_COUNT = 3 # Extra inputs for the \"median-time-past can never reach UINT32_MAX\" BIP113 test\n COINBASE_BLOCK_COUNT = TESTING_TX_COUNT + MTP_EDGE_CASE_INPUT_COUNT  # Number of coinbase blocks we need to generate as inputs for our txs\n BASE_RELATIVE_LOCKTIME = 10\n SEQ_DISABLE_FLAG = 1 << 31\n@@ -520,6 +520,10 @@ class BIP68_112_113Test(BitcoinTestFramework):\n         block.solve()\n         self.send_blocks([block], success=False, reject_reason='bad-txns-nonfinal')\n\n+        # A transaction locked to UINT32_MAX - 1 is not final until the last block is mined\n+        max_locktime_standard_tx = mtp_edge_case_tx(mtp_edge_case_inputs[2], UINT32_MAX - 1)\n+        assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, max_locktime_standard_tx.serialize().hex())\n+\n         # max out MTP on the network to UINT32_MAX, so that the next block's nTime can't exceed it (and thus any block will be rejected for time-too-old)\n         while self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())['mediantime'] < UINT32_MAX:\n             block = create_block(self.tip, height=self.tipheight + 1, ntime=UINT32_MAX)\n@@ -530,6 +534,10 @@ class BIP68_112_113Test(BitcoinTestFramework):\n\n         assert_equal(self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())['mediantime'], UINT32_MAX)\n\n+        # The transaction locked to UINT32_MAX - 1 is now final and enters the mempool, but there can't be another block, so it won't be mined\n+        self.nodes[0].sendrawtransaction(max_locktime_standard_tx.serialize().hex())\n+        assert max_locktime_standard_tx.txid_hex in self.nodes[0].getrawmempool()\n+\n         # submitting a transaction to the mempool with nLockTime at UINT32_MAX fails\n         assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, never_final_tx.serialize().hex())\n```"
  }
 ],
 "labels_log": [
  {
   "t": "2025-04-07T16:44:43Z",
   "action": "labeled",
   "label": "Tests",
   "who": "DrahtBot"
  },
  {
   "t": "2025-04-07T18:50:16Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-04-08T01:18:27Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-04-29T02:01:40Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-05-02T08:48:02Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-06-14T17:00:00Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-06-16T08:29:44Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-23T08:44:35Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-08-02T19:52:31Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-29T19:07:37Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-29T20:06:41Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-07-05T19:22:10Z",
   "kind": "renamed",
   "who": "Christewart",
   "from": "tests: Add unix timestamp tests for OP_CLTV",
   "to": "tests: Add unix timestamp tests for OP_CLTV and max mediantimepast tests"
  }
 ],
 "text_chars": 15447,
 "text_tokens_estimate": 3861,
 "changed_paths": [
  "test/functional/feature_cltv.py",
  "test/functional/feature_csv_activation.py"
 ],
 "files": [
  {
   "path": "test/functional/feature_cltv.py",
   "add": 41,
   "del": 5
  },
  {
   "path": "test/functional/feature_csv_activation.py",
   "add": 66,
   "del": 2
  }
 ],
 "test_lines": 114,
 "git": {
  "head": "1f05d8e0364fa4b009e558c97e821be70313b8bc",
  "head_matches_backup": true,
  "base": "9b38d077f894d27ea76413b1db1cb040e25dc296",
  "commits": [
   {
    "sha": "1f05d8e036",
    "subject": "test: add functional coverage for OP_CLTV unix-timestamp locktimes and BIP113 interaction",
    "files": 2,
    "add": 107,
    "del": 7
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "6e88c06ff5bf3cff",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}