{
 "number": 34978,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/34978",
 "title": "init: reserve file descriptors for IPC connections",
 "author": "enirox001",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-04-01T08:34:56Z",
 "updated_at": "2026-09-16T08:19:56Z",
 "age_days": 169,
 "draft": true,
 "labels": [
  "Needs rebase"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "c29e28c7044f793cfea553dc64825604cc24d65a",
 "head_ref": "04-26-ipc-maxconnections",
 "head_repo": "enirox001/bitcoin",
 "head_history": [
  {
   "t": "2026-04-01T14:59:00Z",
   "sha": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5"
  },
  {
   "t": "2026-04-01T15:17:46Z",
   "sha": "bd4ef3ec5339d8825e77363a754dd2bdffbf880c"
  },
  {
   "t": "2026-04-02T18:07:24Z",
   "sha": "cb2561f26e0d98e1827f2fea6d724b3c34797970"
  },
  {
   "t": "2026-04-03T11:44:39Z",
   "sha": "37e195d99e04830f4a33679cebd2bc4577e2f642"
  },
  {
   "t": "2026-04-03T12:57:04Z",
   "sha": "ac1e51db8639e194967454ee0a4da0e8dd7949a0"
  },
  {
   "t": "2026-04-03T17:28:33Z",
   "sha": "bf037b74762220afab8d506c56f7d801b5e6da7e"
  },
  {
   "t": "2026-04-08T08:30:18Z",
   "sha": "3c9ff9bf5b83ff6c18fcbeb38b79f8bf30b88b7e"
  },
  {
   "t": "2026-04-08T08:36:13Z",
   "sha": "365be355a58ebfdbe7f9cb8acc9ee3221bad844b"
  },
  {
   "t": "2026-05-04T13:12:43Z",
   "sha": "e175b8a1c9c19ae7bfedb50f477907191a4c5ccd"
  },
  {
   "t": "2026-05-04T13:16:00Z",
   "sha": "c29e28c7044f793cfea553dc64825604cc24d65a"
  }
 ],
 "additions": 87,
 "deletions": 4,
 "changed_files": 3,
 "commit_count": 3,
 "size_bucket": "S",
 "mergeable_state": "dirty",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "Sjors",
      "url": "https://github.com/bitcoin/bitcoin/pull/34978#pullrequestreview-4042683109"
     },
     {
      "login": "kevkevinpal",
      "url": "https://github.com/bitcoin/bitcoin/pull/34978#pullrequestreview-4044893549"
     },
     {
      "login": "w0xlt",
      "url": "https://github.com/bitcoin/bitcoin/pull/34978#issuecomment-4173616048"
     },
     {
      "login": "sedited",
      "url": "https://github.com/bitcoin/bitcoin/pull/34978#pullrequestreview-4146944718"
     }
    ],
    "stale_ack": [
     {
      "login": "ryanofsky",
      "url": "https://github.com/bitcoin/bitcoin/pull/34978#pullrequestreview-4076049225"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35730,
     "title": "http: limit connected HTTPRemoteClients",
     "author": "pinheadmz"
    },
    {
     "number": 35037,
     "title": "ipc: support per-address max-connections options on -ipcbind",
     "author": "enirox001"
    },
    {
     "number": 17783,
     "title": "common: Disallow calling IsArgSet() on ALLOW_LIST options",
     "author": "ryanofsky"
    },
    {
     "number": 17581,
     "title": "refactor: Remove settings merge reverse precedence code",
     "author": "ryanofsky"
    },
    {
     "number": 17580,
     "title": "refactor: Add ALLOW_LIST flags and enforce usage in CheckArgFlags",
     "author": "ryanofsky"
    },
    {
     "number": 17493,
     "title": "util: Forbid ambiguous multiple assignments in config file",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "Sjors": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-04-01T08:54:10Z",
   "stale": false
  },
  "kevkevinpal": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-04-01T15:07:53Z",
   "stale": false
  },
  "w0xlt": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-04-01T23:45:00Z",
   "stale": false
  },
  "ryanofsky": {
   "kind": "ack",
   "hash": "bf037b74762220afab8d506c56f7d801b5e6da7e",
   "t": "2026-04-08T14:55:02Z",
   "stale": true
  },
  "sedited": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-05-02T20:44:52Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 1,
  "concept_ack": 4,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 4,
  "changes_requested": 0,
  "distinct_reviewers": [
   "Sjors",
   "ViniciusCestarii",
   "kevkevinpal",
   "ryanofsky",
   "sedited",
   "w0xlt"
  ]
 },
 "signals": {
  "needs_rebase": true,
  "ci_failed": false,
  "mergeable_state": "dirty",
  "last_author_activity": "2026-06-25T12:59:54Z",
  "last_reviewer_activity": "2026-06-25T12:49:45Z",
  "last_reviewer": "Sjors",
  "author_silent_days": 84,
  "waiting_on_author_days": 0,
  "days_since_update": 1
 },
 "refs": {
  "mentioned": [
   32297,
   35037
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 35037,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "ipc: support per-address max-connections options on -ipcbind"
   },
   {
    "number": 32297,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-03-30",
    "title": "bitcoin-cli: Add -ipcconnect option"
   }
  ],
  "conflicts": [
   35730,
   35037,
   17783,
   17581,
   17580,
   17493
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/init.cpp",
  "test/functional/interface_ipc_cli.py"
 ],
 "body": "When `-ipcbind` is used, the node opens one listening socket FD per bound address and accepts concurrent IPC connections. Neither was previously accounted for in `min_required_fds`, meaning IPC-heavy workloads could silently exhaust available file descriptors.\n\nThis PR adds `-ipcmaxconnections` (default: 16, mirroring `-rpcworkqueue`) so operators can control how many FDs are reserved for accepted IPC connections. It also adds `ipc_bind` to account for the listening socket FDs opened per `-ipcbind` address, which were previously unaccounted for. A warning is emitted when `-ipcmaxconnections` is set without `-ipcbind`.\n\nThis reserves file descriptors at startup. Upstream PR enforcing the connection limit https://github.com/bitcoin-core/libmultiprocess/pull/269\n\nNote: there is also a draft alternative downstream approach in bitcoin/bitcoin#35037, using the local per-listener limit API proposed in bitcoin-core/libmultiprocess#269 to support per-address `max-connections=` options on `-ipcbind`.\n\nSo the two concrete directions under discussion are:\n\n1. the global `-ipcmaxconnections` reservation approach in this PR\n2. the per-address `-ipcbind ... max-connections=`\n  approach in #35037\n\nSuggested by Sjors in #32297 (comment).",
 "commits": [
  {
   "sha": "f7e40ee98492f2b5e9de45a20d193d3cecee56dd",
   "date": "2026-04-08T08:35:40Z",
   "message": "test: assert file descriptors available is logged on -ipcbind startup\n\nBefore adding IPC FD reservation, verify that the existing \"file\ndescriptors available\" log line fires when the node starts with\n-ipcbind=unix. This establishes a baseline; the following commits\nrename this helper to test_ipcmaxconnections and extend it to assert\nthe new reservation log line."
  },
  {
   "sha": "2f731bdee79e711fa78409593aeb64aeb8b1759c",
   "date": "2026-05-04T13:15:46Z",
   "message": "init: Reserve file descriptors for IPC connections\n\nWhen -ipcbind is used, the node opens one listening socket FD per\nbound address and accepts concurrent IPC connections. Neither was\npreviously accounted for in min_required_fds, meaning IPC-heavy\nworkloads could silently exhaust available file descriptors at\nunpredictable moments.\n\nAdd -ipcmaxconnections (default: 16, mirroring -rpcworkqueue) so\noperators can control how many FDs are reserved for accepted IPC\nconnections. Add ipc_bind to account for the listening socket FDs\nopened per -ipcbind address, which were previously unaccounted for.\nEmit a warning when -ipcmaxconnections is set without -ipcbind. Log\nthe total IPC FD reservation at startup so operators can verify it.\n\nSuggested by Sjors in #32297 (comment)."
  },
  {
   "sha": "c29e28c7044f793cfea553dc64825604cc24d65a",
   "date": "2026-05-04T13:15:46Z",
   "message": "test: extend -ipcmaxconnections coverage to assert FD reservation logging\n\nAdd -ipcmaxconnections startup checks and assert the new IPC FD\nreservation log line fires with correct values. With -ipcmaxconnections=8,\nthe node logs \"Reserving 9 file descriptors for IPC (1 listening sockets,\n8 accepted connections)\", demonstrating that this PR increases the reserved\nFD count."
  }
 ],
 "timeline": [
  {
   "t": "2026-04-01T08:51:22Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "90ad4dc5e6be9c6e206706b08c3142c84e395889",
   "in_reply_to": null,
   "text": "Maybe make call this `-unixmaxconnections` so it's clear that this covers both the Capnp IPC and the RPC-via-IPC use case (and maybe Tor over unix?)."
  },
  {
   "t": "2026-04-01T08:51:54Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "90ad4dc5e6be9c6e206706b08c3142c84e395889",
   "in_reply_to": null,
   "text": "New code can use modern variable name style."
  },
  {
   "t": "2026-04-01T08:54:10Z",
   "kind": "review",
   "who": "Sjors",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "90ad4dc5e6be9c6e206706b08c3142c84e395889",
   "text": "Concept ACK\n\n[quoted text omitted]\nI think it should, because the error for running out file descriptors is presumably confusing, and it will happen at unpredictable moments depending on how many RPC, P2P and IPC connections are active.\n\nIt would also be good to cover the number of reserved file descriptors that's printed in the log. If you do that in a test commit _before_ the actual change, that nicely demonstrates that this PR actually increases it."
  },
  {
   "t": "2026-04-01T14:06:59Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nRegarding the hard connection limit at the accept loop, implementing that would require changes to mp::ListenConnections in libmultiprocess. Would you expect that to be done in this PR, or as a follow-up in libmultiprocess?"
  },
  {
   "t": "2026-04-01T14:23:22Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nGood question. libmultiprocess should probably give us a hook to (optionally) control the maximum number of connections. It might be good to draft a PR for that on [bitcoin-core/libmultiprocess](https://github.com/bitcoin-core/libmultiprocess/), or at least open an issue.\n\nIt doesn't have to a pre-requisite for this PR, it could indeed be a followup."
  },
  {
   "t": "2026-04-01T14:59:00Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5"
  },
  {
   "t": "2026-04-01T15:04:48Z",
   "kind": "review_comment",
   "who": "kevkevinpal",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5",
   "in_reply_to": null,
   "text": "I would update this to reflect the arg name `DEFAULT_UNIX_MAX_CONNECTIONS`"
  },
  {
   "t": "2026-04-01T15:05:20Z",
   "kind": "review_comment",
   "who": "kevkevinpal",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5",
   "in_reply_to": null,
   "text": "same here to update this to reflect the arg name `user_unix_max_connections`"
  },
  {
   "t": "2026-04-01T15:07:53Z",
   "kind": "review",
   "who": "kevkevinpal",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5",
   "text": "Concept ACK [b1abf1a](https://github.com/bitcoin/bitcoin/pull/34978/commits/b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5)\n\nI would also update the description to reflect the usage of `-unixmaxconnections`"
  },
  {
   "t": "2026-04-01T15:17:46Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "bd4ef3ec5339d8825e77363a754dd2bdffbf880c"
  },
  {
   "t": "2026-04-01T15:18:56Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "90ad4dc5e6be9c6e206706b08c3142c84e395889",
   "in_reply_to": 3020704436,
   "text": "Done, renamed to -unixmaxconnections."
  },
  {
   "t": "2026-04-01T15:19:14Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "90ad4dc5e6be9c6e206706b08c3142c84e395889",
   "in_reply_to": 3020707055,
   "text": "Done, renamed to ipc_bind."
  },
  {
   "t": "2026-04-01T15:19:33Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5",
   "in_reply_to": 3022717802,
   "text": "Done, thanks"
  },
  {
   "t": "2026-04-01T15:20:31Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "b1abf1a5e1cdb6e9edca6524d5a3d85d10d397a5",
   "in_reply_to": 3022721318,
   "text": "Done, made this update"
  },
  {
   "t": "2026-04-01T15:27:45Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "Thanks for the reviews @Sjors @kevkevinpal.\n\nI have addressed the comments in the recent push, also updated the PR description to match the changes made."
  },
  {
   "t": "2026-04-01T23:45:00Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK"
  },
  {
   "t": "2026-04-02T18:07:24Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "cb2561f26e0d98e1827f2fea6d724b3c34797970"
  },
  {
   "t": "2026-04-03T11:44:39Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "37e195d99e04830f4a33679cebd2bc4577e2f642"
  },
  {
   "t": "2026-04-03T12:20:08Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "C.I failure is unrelated"
  },
  {
   "t": "2026-04-03T12:35:11Z",
   "kind": "review_comment",
   "who": "kevkevinpal",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "ac1e51db8639e194967454ee0a4da0e8dd7949a0",
   "in_reply_to": null,
   "text": "Can we test this in the functional test?"
  },
  {
   "t": "2026-04-03T12:48:23Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "ac1e51db8639e194967454ee0a4da0e8dd7949a0",
   "in_reply_to": null,
   "text": "In commit \"init: Reserve file descriptors for IPC connections\" (fa57007dfde3a532f76709b8ff0f38e52f7412aa)\n\nThis line should be changed to `if (ipc_bind > 0)` so it will work correctly when `-noipcbind` is specified. (In general IsArgSet should be avoided because it works poorly with negation).\n\nThe other check on line 1055 will have similar problems. Would suggest something more like:\n\n```c++\nauto ipc_bind = args.GetArgs(\"-ipcbind\").size();\nauto unix_max_connections = args.GetIntArg(\"-unixmaxconnections\", 0);\n\nif (unix_max_connections < 0) {\n    return InitError(Untranslated(\"-unixmaxconnections must be greater than or equal to zero\"));\n} else if (ipc_bind > 0) {\n    if (!IsArgSet(\"-unixmaxconnections\")) unix_max_connections = DEFAULT_UNIX_MAX_CONNECTIONS;\n    LogInfo(\"Reserving %d file descriptors for IPC (%d listening sockets, %d accepted connections)\",\n                    ipc_bind + user_unix_max_connections , ipc_bind, user_unix_max_connections);\n} else if (unix_max_connections > 0) {\n    LogWarning(\"-unixmaxconnections is %s but -ipcbind is not enabled; option will have no effect.\\n\", unix_max_connections);\n    unix_max_connections = 0;\n}\n```"
  },
  {
   "t": "2026-04-03T12:57:04Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "ac1e51db8639e194967454ee0a4da0e8dd7949a0"
  },
  {
   "t": "2026-04-03T12:57:32Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "ac1e51db8639e194967454ee0a4da0e8dd7949a0",
   "in_reply_to": 3032697525,
   "text": "Good suggeestion, added this in the recent push. Thanks"
  },
  {
   "t": "2026-04-03T13:17:27Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "1c0a5e38dee85c5abd61e60741df07f35cf03cbe",
   "in_reply_to": null,
   "text": "In commit \"init: Reserve file descriptors for IPC connections\" (fa57007dfde3a532f76709b8ff0f38e52f7412aa)\n\nI think it would be better to call this `-ipcmaxconnections` to more clearly connect this to other IPC parameters like `-ipcbind` and `-ipcconnect`."
  },
  {
   "t": "2026-04-03T13:32:37Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "ac1e51db8639e194967454ee0a4da0e8dd7949a0",
   "text": "Code review ac1e51db8639e194967454ee0a4da0e8dd7949a0. This looks pretty good, but it looks like there is a problem with negation (see below), and also I made a suggestion about renaming the new option.\n\nIdeally, I think I would want to implement the max connection limit by extending the `-ipcbind` option instead of introducing a new option. I'd probably extend the `-ipcbind` syntax to support socat-style options like `-ipcbind=unix:/path/to/socket:max-connections=8` when listening on a custom path or `-ipcbind=unix::max-connections=10` when listening on the default path. This way different paths (or different transports if we add tcp support) could have different connection limits.\n\nBut I can see that a separate option is probably easiest to implement, and it might be useful to users to have an overall cap on the number of connections, so current approach makes sense and might be best for now."
  },
  {
   "t": "2026-04-03T17:28:33Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "bf037b74762220afab8d506c56f7d801b5e6da7e"
  },
  {
   "t": "2026-04-03T17:30:11Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "ac1e51db8639e194967454ee0a4da0e8dd7949a0",
   "in_reply_to": 3032738091,
   "text": "Good catch.\n\nUpdated to check ` ipc_bind > 0` instead of `IsArgSet(\"-ipcbind\")` so it handles `-noipcbind` correctly, and restructured the logic as suggested."
  },
  {
   "t": "2026-04-03T17:40:25Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "Thanks for the reviews so far @ryanofsky @kevkevinpal @Sjors\n\n[quoted text omitted]\nThe socat-style syntax for per-path limits is an interesting idea. Happy to follow up with that approach in a separate PR if there's appetite for it\n\nChanges made in this commit are:\n- Renamed to `-ipcmaxconnections` to keep it consistent with `-ipcbind` and `-ipcconnect`. @Sjors had suggested, `unixmaxconnections` to be more transport-specific, but `-ipcmaxconnections` seems clearer given the current codebase only has Unix socket IPC.\n- Fixed the `IsArgSet` negation bug by restructuring the logic to check `ipc_bind > 0` instead, so `-noipcbind` is handled correctly:\n- Also extended the functional test to assert that passing `-ipcmaxconnections=-1` raises the expected init error."
  },
  {
   "t": "2026-04-03T17:48:40Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "1c0a5e38dee85c5abd61e60741df07f35cf03cbe",
   "in_reply_to": 3032830798,
   "text": "Renamed to `-ipcmaxconnections` to keep it consistent with `-ipcbind` and `-ipcconnect`."
  },
  {
   "t": "2026-04-06T15:14:14Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "test/functional/interface_ipc_cli.py",
   "commit": "dc0583bb8b78ba11c824dc5cb628ab7835f88aee",
   "in_reply_to": null,
   "text": "In commit \"test: assert file descriptors available is logged on -ipcbind startup\" (dc0583bb8b78ba11c824dc5cb628ab7835f88aee)\n\nI think this file is probably not the right place for these checks, because this file is trying to test `bitcoin-cil`. Would suggest moving this to `interface_ipc.py` or adding a new test like `interface_ipc_init.py`"
  },
  {
   "t": "2026-04-06T15:18:16Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "test/functional/interface_ipc_cli.py",
   "commit": "bf037b74762220afab8d506c56f7d801b5e6da7e",
   "in_reply_to": null,
   "text": "In commit \"test: extend -ipcmaxconnections coverage to assert FD reservation logging\" (bf037b74762220afab8d506c56f7d801b5e6da7e)\n\nIs there a reason for deleting this test? Maybe it should just be extended to check for the new log string?"
  },
  {
   "t": "2026-04-06T15:22:13Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "test/functional/interface_ipc_cli.py",
   "commit": "bf037b74762220afab8d506c56f7d801b5e6da7e",
   "in_reply_to": null,
   "text": "In commit \"test: extend -ipcmaxconnections coverage to assert FD reservation logging\" (bf037b74762220afab8d506c56f7d801b5e6da7e)\n\nIt would seem good to just make this the first test and only start the node with `-ipcmaxconnections=8` one time, instead of twice."
  },
  {
   "t": "2026-04-06T16:29:21Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "bf037b74762220afab8d506c56f7d801b5e6da7e",
   "text": "Code review ACK bf037b74762220afab8d506c56f7d801b5e6da7e. Strictly speaking I think this PR is an improvement over the status quo, because right now no file descriptors are reserved for IPC and this does reserve some.\n\nBut I have the same concerns as Sjors https://github.com/bitcoin/bitcoin/pull/34978#pullrequestreview-4042683109 about how usable the new command line option will be because it only reserves file descriptors *for* IPC, without limiting how many descriptors IPC uses.\n\nI was also initially concerned that a global limit on number of incoming connections could be more awkward to implement than local limits per listening address, because implementing local limits would just seem to require adding a `max_connections` parameter to [`mp::ListenConnections`](https://github.com/bitcoin-core/libmultiprocess/blob/75c2a2764cae62798955c317f79b633fff472f49/include/mp/proxy-io.h#L866) and using a local counter to stop calling `ConnectionReceiver::accept` when the limit is reached, while a global limit would require adding more state to the `EventLoop` class. But probably overall complexity of both approaches is about the same.\n\nI'd still prefer local limits, and accepting socat-style `max-connections=<n>` options in `-ipcbind` over introducing a new command line option and global limit, but that's not a strong preference.\n\nIt would also be nice to see a draft PR with a some complete implementation of connection limiting because it would be a natural followup and could help compare the different approaches."
  },
  {
   "t": "2026-04-08T08:30:18Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "3c9ff9bf5b83ff6c18fcbeb38b79f8bf30b88b7e"
  },
  {
   "t": "2026-04-08T08:36:13Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "365be355a58ebfdbe7f9cb8acc9ee3221bad844b"
  },
  {
   "t": "2026-04-08T08:39:29Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "test/functional/interface_ipc_cli.py",
   "commit": "dc0583bb8b78ba11c824dc5cb628ab7835f88aee",
   "in_reply_to": 3040148712,
   "text": "Good point, this didn\u2019t really belong in `interface_ipc_cli.py`. I moved the startup logging coverage into a dedicated `interface_ipc_init.py` test so the tests are more focused on their intended use"
  },
  {
   "t": "2026-04-08T08:41:05Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "test/functional/interface_ipc_cli.py",
   "commit": "bf037b74762220afab8d506c56f7d801b5e6da7e",
   "in_reply_to": 3040165959,
   "text": "Agreed, I kept the original \"file descriptors available\" check and extended it in `interface_ipc_init.py` so the same startup also asserts the new IPC FD reservation log line."
  },
  {
   "t": "2026-04-08T08:41:46Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "test/functional/interface_ipc_cli.py",
   "commit": "bf037b74762220afab8d506c56f7d801b5e6da7e",
   "in_reply_to": 3040183214,
   "text": "Changed that so the first startup uses -ipcmaxconnections=8, and that single restart now checks both the existing startup log and the new reservation log."
  },
  {
   "t": "2026-04-08T10:05:44Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "Thanks everyone for the review so far.\n\nI addressed the test-related comments by moving the startup logging coverage out of interface_ipc_cli.py into a dedicated interface_ipc_init.py test. The original \"file descriptors available\" check is still there and is now extended to also assert the new IPC FD reservation log line, with the -ipcmaxconnections=8 case using a single restart for both checks.\n\nI also opened an [upstream draft PR](https://github.com/bitcoin-core/libmultiprocess/pull/269) to prototype local per-listener connection limiting, which would be the natural follow-up for enforcing a real IPC connection cap instead of only reserving FDs."
  },
  {
   "t": "2026-04-08T14:55:02Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "365be355a58ebfdbe7f9cb8acc9ee3221bad844b",
   "text": "Code review ACK bf037b74762220afab8d506c56f7d801b5e6da7e. Thanks for the test updates!\n\nOne caveat: after reviewing https://github.com/bitcoin-core/libmultiprocess/pull/269 I'm less sure that we will want to add a global `-ipcmaxconnections` option if we can add per-address limits instead (with `-ipcbind` `max-connections` options or something similar).\n\nEither approach should work but should probably pick one before merging any of these PRs."
  },
  {
   "t": "2026-04-09T13:51:23Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "I opened a separate draft PR here #35037 to make the per-address approach concrete downstream using the local listener limit API from bitcoin-core/libmultiprocess#269.\n\nThat draft uses `-ipcbind ... max-connections=<n>` instead of a global `-ipcmaxconnections` option so the two approaches can be compared more directly."
  },
  {
   "t": "2026-04-09T15:01:30Z",
   "kind": "review",
   "who": "ViniciusCestarii",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "365be355a58ebfdbe7f9cb8acc9ee3221bad844b",
   "text": "There doesn\u2019t seem to be a test covering the default behavior when -ipcmaxconnections is not set.\n\nIt might be useful to add a case asserting the expected default (16 connections) at test/functional/interface_ipc_init.py:\n\n```py\n        with node.assert_debug_log([\n            \"file descriptors available\",\n            \"Reserving 17 file descriptors for IPC (1 listening sockets, 16 accepted connections)\",\n        ]):\n            self.restart_node(0)\n        assert_equal(node.getblockcount(), 0)\n```"
  },
  {
   "t": "2026-04-21T10:28:00Z",
   "kind": "review_comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "c29e28c7044f793cfea553dc64825604cc24d65a",
   "in_reply_to": null,
   "text": "The comment for `nBind` says \"Number of bound interfaces\". I think `ipc_bind` arguably counts towards that too. How about moving that line above the definition of `max_private` and adding `ipc_bind` to it?\n\nClick to expand diff\n\n```diff\ndiff --git a/src/init.cpp b/src/init.cpp\nindex 962b6c9105..86f0efdf6d 100644\n--- a/src/init.cpp\n+++ b/src/init.cpp\n@@ -1032,3 +1031,0 @@ bool AppInitParameterInteraction(const ArgsManager& args)\n-    // Number of bound interfaces (we have at least one)\n-    int nBind = std::max(nUserBind, size_t(1));\n-\n@@ -1057,0 +1055,3 @@ bool AppInitParameterInteraction(const ArgsManager& args)\n+    // Number of bound interfaces (we have at least one)\n+    int binds = std::max(nUserBind + ipc_bind, size_t(1));\n+\n@@ -1062 +1062 @@ bool AppInitParameterInteraction(const ArgsManager& args)\n-    int min_required_fds = MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + nBind + ipc_bind + ipc_max_connections;\n+    int min_required_fds = MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + binds + ipc_max_connections;\n```"
  },
  {
   "t": "2026-05-02T20:44:52Z",
   "kind": "review",
   "who": "sedited",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "365be355a58ebfdbe7f9cb8acc9ee3221bad844b",
   "text": "Concept ACK\n\nThe per-bind accounting seems fine too, but isn't that a bit overkill? Are there really scenarios where different binds or transports would command a completely different number of descriptors?"
  },
  {
   "t": "2026-05-04T13:12:43Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "e175b8a1c9c19ae7bfedb50f477907191a4c5ccd"
  },
  {
   "t": "2026-05-04T13:16:00Z",
   "kind": "force_push",
   "who": "enirox001",
   "commit": "c29e28c7044f793cfea553dc64825604cc24d65a"
  },
  {
   "t": "2026-05-04T13:17:04Z",
   "kind": "review_comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "path": "src/init.cpp",
   "commit": "c29e28c7044f793cfea553dc64825604cc24d65a",
   "in_reply_to": 3116762272,
   "text": "Moving the calculation down and grouping the bound interfaces makes sense, and I applied that in the latest push.\n\nWhile doing that, I noticed the previous `nBind = std::max(nUserBind, size_t(1))` logic had a small pre-existing inaccuracy: it reserves one P2P listener FD even when the node is started with `-listen=0`.\n\nAlso, using `std::max(nUserBind + ipc_bind, size_t(1))` directly would undercount in the case where there are no `-bind` args and one `-ipcbind`, because the default P2P listener and the IPC listener would together open two listening sockets, but that expression would only reserve one.\n\nSo I split the accounting as such\n\n  ```cpp\n  int p2p_binds = args.GetBoolArg(\"-listen\",\n  DEFAULT_LISTEN) ? std::max(nUserBind, size_t(1)) :\n  0;\n  int binds = p2p_binds + ipc_bind;\n```\n\nThis keeps the grouping you suggested, fixes the old -listen=0 behavior, and accounts for IPC listener without under-reserving."
  },
  {
   "t": "2026-05-04T13:17:19Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nI don't think the strongest argument for per-address limits is that current transports need wildly different FD budgets. It's more that accepted connections are attached to individual listeners, so per-listener limits are a more natural fit if we later enforce limits in the accept path.\n\nFor this PR though, since the goal is only startup FD reservation, the global accounting is simpler and probably sufficient."
  },
  {
   "t": "2026-05-04T14:07:01Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "C.I failure is unrelated https://github.com/bitcoin/bitcoin/issues/35199"
  },
  {
   "t": "2026-05-18T15:26:31Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/init.cpp",
   "commit": "2f731bdee79e711fa78409593aeb64aeb8b1759c",
   "in_reply_to": null,
   "text": "In commit \"init: Reserve file descriptors for IPC connections\" (2f731bdee79e711fa78409593aeb64aeb8b1759c)\n\nIt seems like this is no longer adding `std::max(nUserBind, size_t(1))` to number of required fd's if `-listen=0` is used, which seems like a potentially good change, but not related to IPC, and it doesn't seem to be mentioned in the commit description.\n\nIf this change will be included I'd suggest making it in a separate commit, or maybe even a separate PR so reviewers more familiar with p2p can ensure it is correct."
  },
  {
   "t": "2026-05-18T16:13:49Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "c29e28c7044f793cfea553dc64825604cc24d65a",
   "text": "Code review c29e28c7044f793cfea553dc64825604cc24d65a. Would suggest changing this PR from ready to draft state, because while the accounting logic and test here seem useful, I don't think it would be good to add a new `-ipcmaxconnections` option that's global and independent from actual IPC interfaces and endpoints.\n\nThe related PRs https://github.com/bitcoin-core/libmultiprocess/pull/269 and https://github.com/bitcoin/bitcoin/pull/35037 seem promising and this PR could build on them using them to control `ipc_max_connections`. (I'm planning to review them soon.) This PR could also hardcode a small value for `ipc_max_connections` now and allow it to be configurable later. Then it could be merged independently of the other PRs.\n\nre: https://github.com/bitcoin/bitcoin/pull/34978#pullrequestreview-4146944718\n\n[quoted text omitted]\nIt's more straightforward to implement a per-address connnection limit than a global connection limit because each address requires a separate `ListenConnections` call and `ListenConnection` calls do not know about each other. A per-address limit also provides an easy-to-understand UX because it doesn't require any new command line options to be added or any command line interactions to be explained. It lets listening options be specified directly along with the listening address."
  },
  {
   "t": "2026-05-18T16:22:29Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "Marking this PR to draft in favor of https://github.com/bitcoin/bitcoin/pull/35037"
  },
  {
   "t": "2026-06-25T12:49:45Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I'm confused, that PR is also draft and says:\n\n[quoted text omitted]"
  },
  {
   "t": "2026-06-25T12:59:54Z",
   "kind": "comment",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nI had mentioned this in #35037 when I opened the PR because this PR was Open for Review at the time.\n\nI suppose I should move that PR to Ready for Review since this has been moved to draft."
  }
 ],
 "labels_log": [
  {
   "t": "2026-04-01T10:05:26Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-03T15:27:36Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-08T08:36:48Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-08T09:57:57Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-04T13:18:50Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-05T13:27:04Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T09:22:54Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-05-04T12:43:56Z",
   "kind": "renamed",
   "who": "enirox001",
   "from": "init: Reserve file descriptors for IPC connections",
   "to": "init: reserve file descriptors for IPC connections"
  },
  {
   "t": "2026-05-18T16:20:58Z",
   "kind": "convert_to_draft",
   "who": "enirox001"
  }
 ],
 "text_chars": 17904,
 "text_tokens_estimate": 4476,
 "changed_paths": [
  "src/init.cpp",
  "test/functional/interface_ipc_init.py",
  "test/functional/test_runner.py"
 ],
 "files": [
  {
   "path": "src/init.cpp",
   "add": 26,
   "del": 4
  },
  {
   "path": "test/functional/interface_ipc_init.py",
   "add": 60,
   "del": 0
  },
  {
   "path": "test/functional/test_runner.py",
   "add": 1,
   "del": 0
  }
 ],
 "test_lines": 61,
 "git": {
  "head": "c29e28c7044f793cfea553dc64825604cc24d65a",
  "head_matches_backup": true,
  "base": "0831173c0171de33f95b96324db4041c4799b163",
  "commits": [
   {
    "sha": "f7e40ee984",
    "subject": "test: assert file descriptors available is logged on -ipcbind startup",
    "files": 2,
    "add": 34,
    "del": 0
   },
   {
    "sha": "2f731bdee7",
    "subject": "init: Reserve file descriptors for IPC connections",
    "files": 1,
    "add": 26,
    "del": 4
   },
   {
    "sha": "c29e28c704",
    "subject": "test: extend -ipcmaxconnections coverage to assert FD reservation logging",
    "files": 1,
    "add": 31,
    "del": 4
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "f6625881ae0f4795",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}