Review report

bitcoin/bitcoin: PR #36753

Head: 8cfdc340b779 · Base: f103de70de06
Completed: 2026-11-04T13:26:09Z

Run archive · Previous runs

1 major finding · 2 minor findings · 2 suggestions

Findings

🔴 Major · IPC whitelist test fails with relocated sockets

When the framework relocates an overlong IPC socket path, the new whitelist checks fall back to HTTP with the deliberately wrong password and fail, including under the default CI scratch layout.

Location: test/functional/interface_ipc_cli.py:49 (head).

Details and suggested fix

Both calls in test_whitelist omit -ipcconnect, so bitcoin-cli uses auto and tries <datadir>/regtest/node.sock. When that path reaches the platform's Unix socket limit, TestNode binds a shorter temporary path instead. Auto mode catches the overlong-path error and falls back to HTTP, where test_cli supplies -rpcpassword=wrong. The first assertion therefore receives an authorization error instead of 0\n, and the denial assertion is never reached. The existing run_test checks handle relocation by guarding default-path calls and passing an explicit address for the unconditional IPC call, but test_whitelist runs unconditionally. Pass f"-ipcconnect=unix:{self.nodes[0].ipc_socket_path}" to both new calls. The framework retains that binding across node restarts.

🟠 Minor · CLI batch handlers hide later permission errors behind -39

With a partial whitelist that permits the first batch method but denies a later one, bitcoin-cli -getinfo or -netinfo prints the generic -39 error without naming the denied method.

Location: src/httprpc.cpp:162 (head).

Details and suggested fix

For a user permitted to call getnetworkinfo,getblockchaininfo but not getwalletinfo,getbalances, the refused -getinfo batch gives its first entry RPC_REQUEST_NOT_EXECUTED (-39). GetinfoRequestHandler::ProcessReply immediately returns that entry, so the CLI prints the fixed held-back message and exits with 39 instead of showing a later RPC_METHOD_NOT_PERMITTED (-38) error naming a denied method. -netinfo has the same problem when getpeerinfo is permitted but getnetworkinfo is denied. These batches were already refused in base; the limitation is in the new error reporting. Have both batch handlers prefer an available -38 error before returning -39, and add a partial-whitelist test. The current test denies getnetworkinfo itself, so its first entry already contains -38.

🟠 Minor · Malformed refused-batch members lose their invalid-request errors

An ID-bearing member with no method receives -39 when another member is denied, hiding the invalid-request error that the normal batch path would report.

Location: src/httprpc.cpp:162 (head).

Details and suggested fix

For a user denied getnetworkinfo, send [{"id":0},{"method":"getnetworkinfo","id":1}]. The authorization pass skips member 0 and refuses member 1. ParseRefusedRequest then reads ID 0 and catches the RPC_INVALID_REQUEST exception for “Missing method”, but discards it. Because denied[0] is empty, the reply instead says member 0 was not executed because another request was not permitted. Removing the denied member and retrying reveals the original -32600 error, requiring another round trip to diagnose the batch. Preserve caught parse errors and use them for malformed members, reserving -39 for well-formed members held back by the refusal. Keep the existing notification suppression: malformed 2.0 objects without an ID receive no reply on either path. Base returned no per-member errors here; this concerns the accuracy of the new replies.

Optional improvements

🔵 Suggestion · Whitelist response compatibility changes lack a release note

Clients relying on HTTP 403 for JSON-RPC 2.0 or batch whitelist refusals must adapt to new statuses and error bodies, but no release note describes the transition.

Location: src/rpc/protocol.h:79 (head).

Details and suggested fix

Add a PR-specific release note covering RPC_METHOD_NOT_PERMITTED (-38), RPC_REQUEST_NOT_EXECUTED (-39), and the changed HTTP responses. Refused 2.0 singleton calls now return 200 with an error, while notifications return 204 without a body. Refused batches of either version return 200 with per-request errors, or 204 for an all-notification batch. Legacy singleton denials retain 403 but gain an error body. Users denied by -rpcwhitelistdefault also now reach request parsing and can receive the usual malformed-request errors. Tell clients that branch on 403 to inspect JSON-RPC error codes instead. The PR description explains compatibility, but users need this in the release notes, as requested by doc/developer-notes.md for API and other visible changes.

🔵 Suggestion · Refused-batch test does not observe non-execution

The “runs none of them” test uses only read-only methods, so executing permitted members before constructing the same refusal array would leave every assertion passing.

Location: test/functional/rpc_whitelist.py:140 (head).

Details and suggested fix

Both permitted members are getblockcount, and the assertions check only IDs, error codes, and the absence of results. The current production code correctly returns before the execution loop, but this test does not independently protect the no-partial-effect behavior. Whitelist a non-wallet state-changing method such as setnetworkactive for a test user. Put a call with [false] before a denied method, then verify through the unrestricted connection that getnetworkinfo()["networkactive"] remains true. Extend rpcbatch to accept parameters and retain the existing reply-shape assertions.

Coverage details