{
 "number": 34534,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/34534",
 "title": "rpc: Manual prune lock management (Take 2)",
 "author": "fjahr",
 "author_association": "MEMBER",
 "created_at": "2026-02-08T14:01:05Z",
 "updated_at": "2026-09-13T11:30:54Z",
 "age_days": 221,
 "draft": false,
 "labels": [
  "RPC/REST/ZMQ"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "67960317cda01b102c5cbec7efb8ab56611b21a7",
 "head_ref": "2026-02-prunelocks-rpc-v2",
 "head_repo": "fjahr/bitcoin",
 "head_history": [
  {
   "t": "2026-02-08T15:28:26Z",
   "sha": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a"
  },
  {
   "t": "2026-02-18T13:54:07Z",
   "sha": "0032cee2492c4a82054cbd374c67593039bf550d"
  },
  {
   "t": "2026-02-19T15:38:12Z",
   "sha": "b7fc779c01ed31d3a182a47ee3e98e0598a5847c"
  },
  {
   "t": "2026-03-22T13:40:44Z",
   "sha": "c7ac2d8692f75784780153b96b897304e293da3c"
  },
  {
   "t": "2026-03-31T21:55:38Z",
   "sha": "b4895d5222b5984245e7494a83c550bbcd2213ee"
  },
  {
   "t": "2026-04-19T15:31:28Z",
   "sha": "37880b32dc3cdb20212dd5eaf242c7e3a761d680"
  },
  {
   "t": "2026-04-23T09:39:14Z",
   "sha": "9465be6fd01138246337ec91745d08a65f7bea66"
  },
  {
   "t": "2026-07-15T21:47:40Z",
   "sha": "9fa4953f01cab3ab8669b316224b4eeb8433a8d8"
  },
  {
   "t": "2026-07-28T22:00:29Z",
   "sha": "67960317cda01b102c5cbec7efb8ab56611b21a7"
  }
 ],
 "additions": 404,
 "deletions": 1,
 "changed_files": 9,
 "commit_count": 6,
 "size_bucket": "L",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "stickies-v",
      "url": "https://github.com/bitcoin/bitcoin/pull/34534#issuecomment-4096999828"
     }
    ],
    "stale_ack": [
     {
      "login": "sedited",
      "url": "https://github.com/bitcoin/bitcoin/pull/34534#pullrequestreview-4768353421"
     }
    ]
   },
   "conflicts": [
    {
     "number": 34486,
     "title": "net: Reduce local network activity when networkactive=0",
     "author": "willcl-ark"
    }
   ]
  }
 },
 "acks_parsed": {
  "sedited": {
   "kind": "ack",
   "hash": "9fa4953f01cab3ab8669b316224b4eeb8433a8d8",
   "t": "2026-07-23T21:31:03Z",
   "stale": true
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 1,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 2,
  "changes_requested": 1,
  "distinct_reviewers": [
   "achow101",
   "andrewtoth",
   "bvbfan",
   "luke-jr",
   "maflcko",
   "rkrux",
   "sedited",
   "stickies-v"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-13T11:30:54Z",
  "last_reviewer_activity": "2026-09-09T17:02:26Z",
  "last_reviewer": "andrewtoth",
  "author_silent_days": 4,
  "waiting_on_author_days": 0,
  "days_since_update": 4
 },
 "refs": {
  "mentioned": [
   19463
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 19463,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "Prune locks"
   }
  ],
  "conflicts": [
   34486
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "doc/release-notes-34534.md",
  "src/init.cpp",
  "src/node/blockstorage.h",
  "src/rpc/blockchain.cpp",
  "test/functional/rpc_prunelock.py"
 ],
 "body": "This is a refreshed version of #19463, which was closed due to inactivity.\n\nMotivation: On pruned nodes, if a wallet is not loaded while the node is running, blocks necessary for rescanning when the wallet is loaded may be pruned. This PR allows users and external wallet software to manually manage prune locks via RPC, so they can protect blocks needed for future rescans and also clean up locks that are no longer relevant (e.g. after permanently unloading a wallet from a node). This is useful both for Bitcoin Core's own wallet and for external wallets that use Bitcoin Core as a backend. Usage of temporary prune locking may also be helpful in other functional test scenarios but I didn't spend time to check where might apply.\n\nThis PR leverages the existing prune locks system we already have. The interface of the RPCs of the old PR has been slightly updated, it now matches the pattern used by `setban`/`listbanned` exactly. The locks are prefixed to distinguish them from the systems locks and prevent naming colissions. They are not persisted across restarts.",
 "commits": [
  {
   "sha": "63cf16ede5216c8baff8cee2932cacdb656db248",
   "date": "2026-07-15T19:31:32Z",
   "message": "blockstorage: Add GetPruneLocks to BlockManager\n\nThis is needed in RPCs that manage prune locks manually."
  },
  {
   "sha": "6fe60f24906917df2af84a7109aff4aaef1eb523",
   "date": "2026-07-28T20:38:28Z",
   "message": "rpc: Add setprunelock and listprunelocks\n\nThese allow for manual management of prune locks by users and follow the UX pattern of setban/listbanned.\n\nCo-authored-by: Luke Dashjr <luke-jr+git@utopios.org>"
  },
  {
   "sha": "f71df2b387755ed4664b7393d8bb757108c260ba",
   "date": "2026-07-28T20:38:46Z",
   "message": "test: Add manual prune lock RPC coverage"
  },
  {
   "sha": "de844e7d103b39194deb718df796c2831a16e22d",
   "date": "2026-07-28T20:39:49Z",
   "message": "init: Add -prunelockheight init option\n\nThis allows to start a node with a prune lock already set in order to avoid racing with any unwanted pruning."
  },
  {
   "sha": "95c8e24ddec283fb25ab6824508a543ba3161a63",
   "date": "2026-07-28T21:59:39Z",
   "message": "doc: Add release note for prune lock RPCs and -prunelockheight"
  },
  {
   "sha": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "date": "2026-07-28T21:59:39Z",
   "message": "test: Add prune lock coverage for an unloaded wallet"
  }
 ],
 "timeline": [
  {
   "t": "2026-02-08T14:15:01Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-02-08T15:28:26Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a"
  },
  {
   "t": "2026-02-08T15:29:23Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Fixing CI failure: Forgot to set `RPC_COMMANDS_[NOT_]SAFE_FOR_FUZZING` for the new RPCs."
  },
  {
   "t": "2026-02-10T01:51:23Z",
   "kind": "review_comment",
   "who": "luke-jr",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": null,
   "text": "This was an Object for future extensibility. No reason to lose that."
  },
  {
   "t": "2026-02-10T01:51:33Z",
   "kind": "review_comment",
   "who": "luke-jr",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": null,
   "text": "```suggestion\n                    {RPCResult::Type::STR, \"id\", \"The identifier of the prune lock\"},\n```"
  },
  {
   "t": "2026-02-10T01:53:34Z",
   "kind": "review",
   "who": "luke-jr",
   "assoc": "CONTRIBUTOR",
   "state": "CHANGES_REQUESTED",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "text": "Incomplete review. Basically, the original PR interface was way better."
  },
  {
   "t": "2026-02-10T06:56:23Z",
   "kind": "review_comment",
   "who": "bvbfan",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": null,
   "text": "You could get it as copy and don't keep lock while iterating, performance wise.\n```\nconst auto prune_locks = WITH_LOCK(::cs_main, return chainman.m_blockman.GetPruneLocks());\n```"
  },
  {
   "t": "2026-02-18T13:54:07Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "0032cee2492c4a82054cbd374c67593039bf550d"
  },
  {
   "t": "2026-02-18T13:54:21Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": 2786137682,
   "text": "Done"
  },
  {
   "t": "2026-02-18T13:54:26Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": 2785381566,
   "text": "Done"
  },
  {
   "t": "2026-02-18T13:54:51Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": 2785381112,
   "text": "The RPC is called `listprunelocks`, I don't see how it could be extended to return anything else aside from a list of locks without that other thing feeling out of place. Can you give some specific ideas that you have? At least I would want to give the RPC a different name then (`getpruneinfo` or so) but potentially these ideas should rather be in a separate RPC. I prefer consistency and so I really like that we could be consistenty with the banning RPC."
  },
  {
   "t": "2026-02-18T13:55:02Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "@luke-jr\n\n[quoted text omitted]\nIs this just about https://github.com/bitcoin/bitcoin/pull/34534#discussion_r2785381112 or did you mean something else?"
  },
  {
   "t": "2026-02-18T13:55:23Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Addressed feedback from @luke-jr and @bvbfan , thanks for the review!"
  },
  {
   "t": "2026-02-18T14:28:32Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": 2785381112,
   "text": "`listprunelocks` could return a \"blockman epoch\" in the future, if there was need to further distinguish rpc results. (Yes, this is made up, but with an array, this is impossible, with an object, this is trivial and harmless)"
  },
  {
   "t": "2026-02-18T14:35:51Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": 2785381112,
   "text": "What is a \"blockman epoch\"? I don't think I have heard of that before."
  },
  {
   "t": "2026-02-19T15:38:12Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "b7fc779c01ed31d3a182a47ee3e98e0598a5847c"
  },
  {
   "t": "2026-02-19T15:40:00Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "f192b06a3bdfb6b6f27b0e0d7a676376989a3d1a",
   "in_reply_to": 2785381112,
   "text": "I guess TIL per [this comment](https://github.com/bitcoin/bitcoin/pull/33920#discussion_r2826613479) that the JSON object thing is in the dev notes, fair enough, I have changed it to return an object."
  },
  {
   "t": "2026-03-18T15:57:59Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nDo you remember at least who mentioned these users/use cases?"
  },
  {
   "t": "2026-03-19T17:30:15Z",
   "kind": "comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThis looks potentially interesting, but I don't think we should be implementing RPCs when we don't know anyone that would actually be using them? Since the previous PR has been open since 2020 already without users chiming in, it seems like there's no real demand for this?"
  },
  {
   "t": "2026-03-19T17:47:16Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "This is generally useful in the wallet and for any wallets that leverage Bitcoin Core. The fundamental issue is that if the wallet is not loaded while the node is running, blocks necessary for rescanning when the wallet is loaded may be pruned away. The wallet definitely should be using prune locks, but it's also necessary to have a way to for users to remove prune locks that are no longer relevant, e.g. if they unload a wallet that they don't plan to load on that node again. External wallets that use Bitcoin Core should also find this useful as they can then set prune locks that match the scan state of the external wallet."
  },
  {
   "t": "2026-03-20T10:10:18Z",
   "kind": "comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "text": "Thanks for the explanation @achow101 . Concept ACK. Enabling wallets to build on top of a pruned node via RPC seems enough of a use case to move this forward. @fjahr I think this might be useful to include in PR description to give it more motivation?"
  },
  {
   "t": "2026-03-20T11:54:19Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nDone, replace that vague part of the description with a better motivation paragraph."
  },
  {
   "t": "2026-03-21T11:41:59Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "1f9cfa1a88273533f591bbad5a5ac3cc5f2c4562",
   "in_reply_to": null,
   "text": "Don't we either have to hold this lock while iterating through the prune locks, or copy them? I think my preference would be to just take a copy here."
  },
  {
   "t": "2026-03-21T12:02:03Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/node/blockstorage.h",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": null,
   "text": "Is there a reason for introducing this helper? Existing validation code that iterates through the locks directly."
  },
  {
   "t": "2026-03-21T12:17:09Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "b7fc779c01ed31d3a182a47ee3e98e0598a5847c",
   "text": "One thing that is still not clear to me is how this is actually useful to external applications if the locks are not persisted. I could see how this might be interesting for our own wallets, by setting prune locks for wallets even though they are not loaded yet. But for outside users this seems like a limitation that is difficult to deal with. If you want to add a wallet on startup, wouldn't that require racing to set a lock again if you restart? What is the exact scenario here?"
  },
  {
   "t": "2026-03-22T13:40:44Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "c7ac2d8692f75784780153b96b897304e293da3c"
  },
  {
   "t": "2026-03-22T13:41:03Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "1f9cfa1a88273533f591bbad5a5ac3cc5f2c4562",
   "in_reply_to": 2969489551,
   "text": "Hm, it certainly seems like I addressed [this comment](https://github.com/bitcoin/bitcoin/pull/34534#discussion_r2786137682) without thinking about it enough because the surrounding parentesis were unnecessary as well. I am now using a explicit `unordered_map` constructor now to ensure the copy happens before the lock scope ends and I have added a comment and removed the parenthesis."
  },
  {
   "t": "2026-03-22T13:41:25Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Addressed latest @sedited feedback, thank you!\n\n[quoted text omitted]\nFirst, I think we can agree that it's useful for long-running nodes and the internal wallet, right? So for the following I am still unsure if it should be included here or part of follow-up PR.\n\nFor a node that is relaunched only every few weeks for usage of (cold-ish) wallet the persisted lock sounds useful. But I am not sure if just making the locks persistent is actually the best UI for this use-case. The pattern would probably be that the user, before shutdown, sets a prune lock to the last scan height (potentially the tip) and then shuts down. Then on restart the prune lock is respected. But then maybe it would actually be more convenient if there was a startup option `-prunelocked` or so where the node can be started with the current tip locked. It could get a height parameter too if an earlier height should be locked. I haven't spent much time thinking if this covers all the use-cases but so far I tend to think the startup option covers what I have in mind and comes with a few upsides: If the node crashes and the user couldn't set the lock before, with persistence they might be still screwed but with the startup option they are safe. And since we could avoid persistence this should be much easier to implement and have less code to maintain.\n\nEDIT: Also, for certain wallets that really need a lot of control, there is always the option to manually prune as well."
  },
  {
   "t": "2026-03-22T13:41:34Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/node/blockstorage.h",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": 2969506440,
   "text": "`m_prune_locks` is private and the direct access to it in `validation.cpp` is only possible because `ChainState` is a friend class of `BlockManager`. Of course we could also just make it public but a getter method seemed nicer to me."
  },
  {
   "t": "2026-03-25T10:28:47Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThe case is still not quite clear to me to be honest. Would the wallet start tracking prune locks for unloaded wallets? Afaict it doesn't currently hold a lock during rescan - that does indeed seem like something useful. I can also see how deleting / cleaning up existing locks could be useful, though it also feels like bit of a footgun. I'm having a hard time thinking of a scenario where you can robustly race a node pruning and important an existing wallet / descriptor. The startup option does seem better to me too."
  },
  {
   "t": "2026-03-25T13:34:03Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThanks, I have added a minimal implementation of the startup option because so far seems like a clearly useful feature to me if outside wallets want to use prune locks in any capacity. But conceptual feedback still very welcome!\n\n[quoted text omitted]\nI think so? I could see something like this become more common in the future when more users switch on pruning to avoid having to get a larger disk. I would expect there are wallet options that market themselves being compatible with (possibly aggressive) pruning on the node and that this option will become more common in the future. But of course it would be a stronger statement to hear from an implementer directly that they would use such a feature. I just looked at the sparrow docs as a start and they are rather \"hands-off\" so far and just warn about potential issues: https://sparrowwallet.com/docs/connect-node.html#pruned-nodes"
  },
  {
   "t": "2026-03-31T21:55:38Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "b4895d5222b5984245e7494a83c550bbcd2213ee"
  },
  {
   "t": "2026-03-31T21:55:53Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Rebased"
  },
  {
   "t": "2026-04-19T15:31:28Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "37880b32dc3cdb20212dd5eaf242c7e3a761d680"
  },
  {
   "t": "2026-04-19T15:48:28Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Rebased"
  },
  {
   "t": "2026-04-23T09:39:14Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66"
  },
  {
   "t": "2026-04-23T13:03:25Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": null,
   "text": "Nit: Why not duplicate the description from setprunelock to describe their mechanics? The description here feels a bit incomplete, since it does not just prevent pruning at a single height."
  },
  {
   "t": "2026-04-23T13:37:39Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "text": "ACK 9465be6fd01138246337ec91745d08a65f7bea66"
  },
  {
   "t": "2026-04-23T14:36:02Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": 3130965630,
   "text": "Fair, I will address it the next time I touch this."
  },
  {
   "t": "2026-05-25T14:56:22Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": null,
   "text": "Can't there be a case wherein this new argument causes the -prune=<n> option to not be respected? If this has already been discussed before, please point me to that conversation."
  },
  {
   "t": "2026-05-25T14:59:14Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "text": "Thanks for the review ping, I was not aware of this PR.\n\nI started looking and it looks interesting - also helpful if it can be leveraged by the wallet (or by external ones)."
  },
  {
   "t": "2026-05-25T19:53:09Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": 3298799922,
   "text": "Yes, unless I am misunderstanding your question that is the whole idea behind prune locks, to temporarily protect certain block ranges from pruning if there is some work left to do. I added that functionality [here](https://github.com/bitcoin/bitcoin/pull/21726) a few years ago with the initial goal to let indexes catch up without the necessary blocks disappearing suddenly if they are running on a pruned node. The basic discussion can be found there. This PR only allows to configure these prune locks via RPC which may be interesting for external wallets for example. Does that answer your question?"
  },
  {
   "t": "2026-06-08T13:55:32Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": 3298799922,
   "text": "Sorry for the delay in getting back here, I should be able to get to it this week."
  },
  {
   "t": "2026-06-12T11:31:42Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/rpc_prunelock.py",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": null,
   "text": "Is this correct? The following diff passes where this value is halved along with the corresponding heights in the pruneblockchain RPCs.\n\n```diff\ndiff --git a/test/functional/rpc_prunelock.py b/test/functional/rpc_prunelock.py\nindex a122a6164a..9a2dd5b6c2 100755\n--- a/test/functional/rpc_prunelock.py\n+++ b/test/functional/rpc_prunelock.py\n@@ -17,7 +17,7 @@ from test_framework.util import (\n\n # Blocks needed to generate at minimum to allow pruning to work on\n # regtest (with fastprune).\n-INITIAL_BLOCKS = 1500\n+INITIAL_BLOCKS = 750\n\n class PruneLockTest(BitcoinTestFramework):\n@@ -92,7 +92,7 @@ class PruneLockTest(BitcoinTestFramework):\n                             {\"id\": \"rpc:protect_early\"},\n                             {\"height\": 2})\n\n-        prune_height_locked = node.pruneblockchain(500)\n+        prune_height_locked = node.pruneblockchain(250)\n         assert self.has_block_file(node, 0), \"blk00000.dat should still exist with prune lock active\"\n\n         self.log.info(\"Test that removing the prune lock allows further pruning\")\n@@ -101,7 +101,7 @@ class PruneLockTest(BitcoinTestFramework):\n                             {\"id\": \"rpc:protect_early\"}, {},\n                             should_not_find=True)\n\n-        prune_height_unlocked = node.pruneblockchain(500)\n+        prune_height_unlocked = node.pruneblockchain(250)\n         assert_greater_than(prune_height_unlocked, prune_height_locked)\n         assert not self.has_block_file(node, 0), \"blk00000.dat should be pruned after lock removal\"\n\n@@ -142,15 +142,15 @@ class PruneLockTest(BitcoinTestFramework):\n         node = self.nodes[0]\n\n         self.log.info(\"Test -prunelockheight with explicit height\")\n-        self.restart_node(0, extra_args=[\"-prune=1\", \"-prunelockheight=500\"])\n+        self.restart_node(0, extra_args=[\"-prune=1\", \"-prunelockheight=250\"])\n         assert_array_result(node.listprunelocks()[\"prune_locks\"],\n                             {\"id\": \"init\"},\n-                            {\"height\": 500})\n+                            {\"height\": 250})\n\n         self.log.info(\"Test -prunelockheight can coexist with RPC locks\")\n         node.setprunelock(\"mylock\", \"add\", 100)\n         locks = node.listprunelocks()[\"prune_locks\"]\n-        assert_array_result(locks, {\"id\": \"init\"}, {\"height\": 500})\n+        assert_array_result(locks, {\"id\": \"init\"}, {\"height\": 250})\n         assert_array_result(locks, {\"id\": \"rpc:mylock\"}, {\"height\": 100})\n         node.setprunelock(\"mylock\", \"remove\")\n\n```\n\nBased it off of this conditional:\nhttps://github.com/bitcoin/bitcoin/blob/142e86a65c8a809911e37ead5ece63ad7854077e/src/kernel/chainparams.cpp#L603"
  },
  {
   "t": "2026-06-12T11:36:08Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "test/functional/rpc_prunelock.py",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": null,
   "text": "prune_height_locked is -1 because the lock prevents the pruning from happening.\nI don't see much point in asserting that prune_height_unlocked is greater than prune_height_locked."
  },
  {
   "t": "2026-06-12T11:37:41Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": null,
   "text": "The changes in this file require a release note because of new RPCs being added.\nAlong with the new startup option."
  },
  {
   "t": "2026-06-12T11:40:24Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": null,
   "text": "There isn't a check that forbids locking blocks that'd be generated in the future. Is it intentional?\nThe following test change passes:\n\n```diff\n-        node.setprunelock(\"testlock\", \"add\", 100)\n+        node.setprunelock(\"testlock\", \"add\", 1600)\n         assert_array_result(node.listprunelocks()[\"prune_locks\"],\n                             {\"id\": \"rpc:testlock\"},\n-                            {\"height\": 100})\n+                            {\"height\": 1600})\n```"
  },
  {
   "t": "2026-06-12T11:41:31Z",
   "kind": "review_comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": 3298799922,
   "text": "Ok, can add a sentence here that this option will cause the -prune option to not be respected - just to be explicit."
  },
  {
   "t": "2026-06-12T11:48:50Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "text": "Overall, I feel this PR needs to market itself a bit. Either in the release notes or maybe a new section in the docs/ directory. I worry that this feature would be underutilised or, worse, unused because of lack of awareness. The motivation in the PR description and the use cases discussed in the PR comments previously can be listed there.\n\nFrom https://github.com/bitcoin/bitcoin/pull/34534#issuecomment-4092098083:\n[quoted text omitted]\n\nAlso, a functional test for wallet exercising prune locks that solves the above scenario would be nice. Using prune locks temporarily instead of manually importing via importprunedfunds RPC (which requires the the proof via another RPC - gettxoutproof) seems like a more natural choice to me (can be a part of the motivation/marketing)."
  },
  {
   "t": "2026-07-15T21:47:40Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "9fa4953f01cab3ab8669b316224b4eeb8433a8d8"
  },
  {
   "t": "2026-07-15T21:48:31Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": 3298799922,
   "text": "Good idea, done!"
  },
  {
   "t": "2026-07-15T21:49:08Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "test/functional/rpc_prunelock.py",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": 3403010419,
   "text": "Hm, for me the proposed diff fails because the blocks are not enough to get actual pruning. I am not sure why it would pass for you and not for me, it's possible that there is some dependency on filesystems but I usually try to tweak these values to the minimum that works reliably locally."
  },
  {
   "t": "2026-07-15T21:49:13Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "test/functional/rpc_prunelock.py",
   "commit": "9465be6fd01138246337ec91745d08a65f7bea66",
   "in_reply_to": 3403031901,
   "text": "Changed this to check for -1 and >0 more explicitly now."
  },
  {
   "t": "2026-07-15T21:49:22Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": 3403038964,
   "text": "Right, added the necessary release notes!"
  },
  {
   "t": "2026-07-15T21:49:28Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/rpc/blockchain.cpp",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7",
   "in_reply_to": 3403052103,
   "text": "Right, that's a good observation, I didn't think about this explicitly so far but I don't see harm in allowing this and it may even be useful for some use-cases. So I tend to say I would keep allowing it and I have added a note in the docs on it. But if you (or other reviewers) strongly prefer these values to be rejected I can be convinced to do that as well."
  },
  {
   "t": "2026-07-15T21:52:26Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Addressed feedback by @rkrux , thanks a lot!\n\n[quoted text omitted]\nI added release notes per your inline comment\n\n[quoted text omitted]\nI added this in a separate commit. I folded it into the existing test file since generating all those blocks is pretty expensive and I didn't see this justifying a new functional test file. Let me know what you think."
  },
  {
   "t": "2026-07-23T21:30:12Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34534.md",
   "commit": "9fa4953f01cab3ab8669b316224b4eeb8433a8d8",
   "in_reply_to": null,
   "text": "Maybe mention here that the lock may be viewed by `listprunelock`and removed by `setprunelock`."
  },
  {
   "t": "2026-07-23T21:31:03Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "9fa4953f01cab3ab8669b316224b4eeb8433a8d8",
   "text": "Re-ACK 9fa4953f01cab3ab8669b316224b4eeb8433a8d8"
  },
  {
   "t": "2026-07-28T22:00:29Z",
   "kind": "force_push",
   "who": "fjahr",
   "commit": "67960317cda01b102c5cbec7efb8ab56611b21a7"
  },
  {
   "t": "2026-07-28T22:04:21Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34534.md",
   "commit": "9fa4953f01cab3ab8669b316224b4eeb8433a8d8",
   "in_reply_to": 3641509070,
   "text": "Well, now that you say it.... the `setprunelock` removal part wasn't actually possible because of the forced `rpc:` prefix which the init option didn't use. I changed this and renamed the prefix to `user:` since it's not strictly used by RPCs anymore. Otherwise, removing the lock would have required a restart."
  },
  {
   "t": "2026-09-09T17:02:26Z",
   "kind": "comment",
   "who": "andrewtoth",
   "assoc": "MEMBER",
   "text": "I'm not sure I find the motivation compelling. Would the same functionality be achieved via the `pruneblockchain` RPC and a `-prune=1` setting? This way a user can have all their wallets sync, and then call `pruneblockchain`. Keeping the node running would not prune on its own."
  },
  {
   "t": "2026-09-13T11:30:54Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nPartly yes, but I think it would be much more complex and difficult to implement managing that behavior on the side of an external wallet. With `-prune=1` nothing is pruned unless `pruneblockchain` is called and to achieve some kind of constant disk usage threshold it needs to be called regularly. In order to decide when to prune the wallet would need to monitor disk usage constantly and then decide with which height to call `pruneblockchain`. It basically means the wallet has the burden to reimplement our automatic pruning logic, just to get that extra bit of control that the pull here provides. It gets even trickier if there are multiple consumers of RPC that need that pruning control, like a wallet and an external index, with management RPCs they both can set their locks as they need and it should be simple to implement that."
  }
 ],
 "labels_log": [
  {
   "t": "2026-02-08T14:01:09Z",
   "action": "labeled",
   "label": "RPC/REST/ZMQ",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-08T15:18:57Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-08T16:44:34Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-03-31T17:33:49Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-03-31T22:15:47Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-19T10:02:58Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-19T16:51:46Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-23T06:09:59Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-23T10:28:17Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 17475,
 "text_tokens_estimate": 4368,
 "changed_paths": [],
 "files": [],
 "test_lines": null,
 "git": null,
 "input_hash": "c8d46f103d7abc3b",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}