Skip to content

backport: bitcoin/bitcoin#23083: rpc: Fail to return undocumented or misdocumented JSON - #7502

Open
knst wants to merge 3 commits into
dashpay:developfrom
knst:bp-v24-23083
Open

backport: bitcoin/bitcoin#23083: rpc: Fail to return undocumented or misdocumented JSON #7502
knst wants to merge 3 commits into
dashpay:developfrom
knst:bp-v24-23083

Conversation

@knst

@knst knst commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Backport bitcoin#23083 discovered multiple issues in our help for RPC

What was done?

AI crafted fixes for RPC help + backport bitcoin#23083 + fixes from bitcoin#34683

How Has This Been Tested?

Run unit / functional tests, fix multiple failures such as:

[in regressions tests]
test/rpc_tests.cpp(141): error: in "rpc_tests/rpc_rawparams": unexpected exception thrown by r = CallRPC(std::string("decoderawtransaction ")+rawtx)
unknown location(0): fatal error: in "rpc_tests/rpc_rawparams": UniValue::type_error: JSON value of type null is not of expected type object

[in functional tests]
  File "/home/knst/projects/dash-v22/test/functional/feature_governance.py", line 189, in run_test
mn_list = self.nodes[0].protx("list", "registered", True)
...
test_framework.authproxy.JSONRPCException: Internal bug detected: std::any_of(m_results.m_results.begin(), m_results.m_results.end(), [&ret](const RPCResult& res) { return res.MatchesType(ret); })
rpc/util.cpp:533 (HandleRequest)
Dash Core v23.1.7-955-g8c2b1eb467fc-dirty
Please report this issue here: https://github.com/dashpay/dash/issues

Breaking Changes

Debug builds going to crash every time when RPC help is not matching with real RPC response.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@knst knst added this to the 24 milestone Jul 30, 2026
@knst
knst requested review from PastaPastaPasta and UdjinM6 July 30, 2026 18:08
@knst knst added the RPC Some notable changes to RPC params/behaviour/descriptions label Jul 30, 2026
@knst
knst requested a review from thephez July 30, 2026 18:08
@thepastaclaw

thepastaclaw commented Jul 30, 2026

Copy link
Copy Markdown

⛔ Blockers found — Opus deferred (commit b77fd4a)
Canonical validated blockers: 2

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fe96b4e5-0c36-454c-92b9-5fa69e4c3b55

📥 Commits

Reviewing files that changed from the base of the PR and between 9f22c9c and b77fd4a.

📒 Files selected for processing (2)
  • src/rpc/coinjoin.cpp
  • src/wallet/rpc/transactions.cpp
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/rpc/coinjoin.cpp
  • src/wallet/rpc/transactions.cpp

Walkthrough

This PR updates RPC help schemas across core, governance, quorum, masternode, transaction, networking, and wallet commands. It adds dynamic-object descriptions, marks conditional fields optional, corrects field names and types, and documents additional response fields. RPCResult::MatchesType now validates arrays and objects, supports dynamic keys, and can skip type checks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RPCCommand
  participant RPCResult
  participant UniValue
  RPCCommand->>RPCResult: provide documented result schema
  RPCResult->>UniValue: inspect returned response
  UniValue-->>RPCResult: return keys and values
  RPCResult-->>RPCCommand: validate documented response shape
Loading

Suggested reviewers: udjinm6

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the RPC backport and its purpose of addressing undocumented or misdocumented JSON responses.
Description check ✅ Passed The description directly explains the RPC help fixes, backport scope, test failures, and debug validation behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/rpc/evo.cpp (1)

1-1: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Keep production RPCResult schemas renderable in ToSections.

RPCResult::Type::ANY is only for test schemas, but adding it to real help paths such as protx list inserts an unreachable branch into the schema traversal used to emit -help documentation. Replace these production usages with renderable alternatives or make ToSections safely handle skip_type_check/dynamic shapes without relying on ANY.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/rpc/evo.cpp` at line 1, Replace production RPCResult::Type::ANY usages in
the evo RPC help schemas, including protx list, with concrete renderable types
or supported dynamic-shape definitions. Ensure the affected schemas remain
traversable by ToSections and do not introduce unreachable branches; reserve ANY
for test-only schemas.
🧹 Nitpick comments (1)
src/rpc/quorums.cpp (1)

117-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a descriptive placeholder instead of "xxxx" for the dynamic quorum-hash key.

This key name is rendered verbatim in generated help text ("xxxx" : {...}) since OBJ_DYN's inner entry is emitted with its m_key_name when nested under an OBJ context. Elsewhere in this same PR, dynamic-key placeholders use a descriptive form (<outpoint>, <sig_hex>, <protx_hash>); consider <quorumHash> here for consistency and clearer generated docs.

✏️ Proposed rename
-                        {RPCResult::Type::OBJ, "xxxx", "Quorum details",
+                        {RPCResult::Type::OBJ, "<quorumHash>", "Quorum details",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/rpc/quorums.cpp` around lines 117 - 127, Replace the dynamic quorum-hash
key placeholder "xxxx" in the RPC result schema with the descriptive placeholder
"<quorumHash>", preserving the existing OBJ_DYN structure and quorum detail
fields so generated help text clearly identifies the key.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/governance/core_write.cpp`:
- Around line 122-138: Replace the seven RPCResult::Type::ANY entries in the
data schema with appropriate concrete types so RPCResult::ToSections can render
help without reaching NONFATAL_UNREACHABLE(). Preserve skip_type_check=true on
the enclosing data object, which continues to allow mixed and extra proposal
fields during validation; do not modify unrelated fields such as plain or hex.

In `@src/llmq/core_write.cpp`:
- Around line 22-53: Replace the RPCResult::Type::ANY usage in the member_tally
helper with a schema-specific representation that accurately documents the
detail_level-dependent scalar and array variants without relying on ANY. Update
the six member tally fields in the surrounding DKG result schema to use this
representation while preserving their existing descriptions and runtime help
validation.

In `@src/rpc/evo.cpp`:
- Around line 1507-1515: Replace RPCResult::Type::ANY in the protx list result
declaration with typed result definitions: document the non-detailed array
elements as ProTx-hash strings and add a separate typed array shape for detailed
masternode objects, using the existing RPCResult field definitions where
available. Ensure ToSections() can recurse through both array shapes without
encountering ANY.

In `@src/rpc/rawtransaction.cpp`:
- Around line 576-578: Update the getislocks RPC summary text to state that it
returns the string "None" when no InstantSend lock is known, replacing the
inaccurate reference to Null. Keep the existing implementation and detailed
result documentation unchanged.

In `@src/wallet/rpc/transactions.cpp`:
- Around line 424-445: Update WalletTxToJSON() to filter out the internal
Dash-specific “DS” mapValue entry before serializing mapValue into the
transaction JSON. Preserve serialization of all documented entries and ensure
the RPC output conforms to its declared schema.

In `@src/wallet/rpc/wallet.cpp`:
- Line 126: Update the getwalletinfo RPC result definition for
keypoolsize_hd_internal to match its unconditional emission: remove the optional
flag and clarify that a value of zero indicates no internal keypool, or
alternatively update the producer to omit the field when the feature is inactive
while preserving the documented behavior.

---

Outside diff comments:
In `@src/rpc/evo.cpp`:
- Line 1: Replace production RPCResult::Type::ANY usages in the evo RPC help
schemas, including protx list, with concrete renderable types or supported
dynamic-shape definitions. Ensure the affected schemas remain traversable by
ToSections and do not introduce unreachable branches; reserve ANY for test-only
schemas.

---

Nitpick comments:
In `@src/rpc/quorums.cpp`:
- Around line 117-127: Replace the dynamic quorum-hash key placeholder "xxxx" in
the RPC result schema with the descriptive placeholder "<quorumHash>",
preserving the existing OBJ_DYN structure and quorum detail fields so generated
help text clearly identifies the key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 15abbeec-1c9c-4130-a5ac-badb191f7d73

📥 Commits

Reviewing files that changed from the base of the PR and between 2e52d33 and 6287883.

📒 Files selected for processing (19)
  • src/evo/core_write.cpp
  • src/governance/core_write.cpp
  • src/llmq/core_write.cpp
  • src/rpc/blockchain.cpp
  • src/rpc/coinjoin.cpp
  • src/rpc/evo.cpp
  • src/rpc/governance.cpp
  • src/rpc/masternode.cpp
  • src/rpc/mempool.cpp
  • src/rpc/mining.cpp
  • src/rpc/net.cpp
  • src/rpc/node.cpp
  • src/rpc/quorums.cpp
  • src/rpc/rawtransaction.cpp
  • src/rpc/util.cpp
  • src/rpc/util.h
  • src/wallet/rpc/backup.cpp
  • src/wallet/rpc/transactions.cpp
  • src/wallet/rpc/wallet.cpp

Comment thread src/governance/core_write.cpp
Comment thread src/llmq/core_write.cpp
Comment thread src/rpc/evo.cpp
Comment on lines +576 to +578
// An element is the plain string "None" when no InstantSend Lock is known for
// that txid, so the element type cannot be checked against this object.
/*skip_type_check=*/true},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the getislocks summary to document the string "None".

The implementation returns "None" at Line 619, and this change now explicitly documents that string. However, the RPC summary still says it returns Null, which describes the wrong JSON value type. Update the summary text accordingly.

Proposed documentation fix
-        "\nReturns the raw InstantSend lock data for each txids. Returns Null if there is no known IS yet.",
+        "\nReturns the raw InstantSend lock data for each txids. Returns the string \"None\" if there is no known IS yet.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// An element is the plain string "None" when no InstantSend Lock is known for
// that txid, so the element type cannot be checked against this object.
/*skip_type_check=*/true},
"\nReturns the raw InstantSend lock data for each txids. Returns the string \"None\" if there is no known IS yet.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/rpc/rawtransaction.cpp` around lines 576 - 578, Update the getislocks RPC
summary text to state that it returns the string "None" when no InstantSend lock
is known, replacing the inaccurate reference to Null. Keep the existing
implementation and detailed result documentation unchanged.

Comment thread src/wallet/rpc/transactions.cpp
Comment thread src/wallet/rpc/wallet.cpp
{RPCResult::Type::NUM_TIME, "timefirstkey", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest known key in the wallet. Legacy wallets only"},
{RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only"},
{RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
{RPCResult::Type::NUM, "keypoolsize_hd_internal", /*optional=*/ true, "how many new keys are pre-generated for internal use (used for change outputs and mobile coinjoin, only appears if the wallet is using this feature, otherwise external keys are used)"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not mark keypoolsize_hd_internal optional while always emitting it.

getwalletinfo() unconditionally adds this field, including when no internal keypool feature is active. Keep it required and clarify that zero means no internal pool, or change the producer to omit it under the documented condition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/rpc/wallet.cpp` at line 126, Update the getwalletinfo RPC result
definition for keypoolsize_hd_internal to match its unconditional emission:
remove the optional flag and clarify that a value of zero indicates no internal
keypool, or alternatively update the producer to omit the field when the feature
is inactive while preserving the documented behavior.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The upstream backport and most Dash-specific schema adaptations are coherent, but the newly introduced nested ANY entries violate the existing help-renderer contract and make several RPC help pages throw NonFatalCheckError. The revised mempool result documentation also omits the normal "false" value for instantlock, so changes are required before merge.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed), gpt-5.6-sol — backport-reviewer (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking | 💬 1 nitpick(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/llmq/core_write.cpp`:
- [BLOCKING] src/llmq/core_write.cpp:28-32: Nested ANY result types make RPC help throw
  `RPCResult::Type::ANY` is only skipped when it is the top-level result. Nested entries are passed to `RPCResult::ToSections()`, whose `Type::ANY` branch calls `NONFATAL_UNREACHABLE()` and throws `NonFatalCheckError`. Therefore, rendering `help quorum dkgstatus` traverses this member-tally entry and fails instead of returning help. The same PR-introduced problem affects the nested `ANY` entries in `src/governance/core_write.cpp:127-133`, `src/rpc/rawtransaction.cpp:474`, `src/rpc/evo.cpp:1514`, and `src/wallet/rpc/transactions.cpp:868`. The new `m_skip_type_check` flag only affects `MatchesType()` and does not prevent help rendering. Add a displayable representation for nested `ANY`, or use displayable result types with type checking skipped.

Comment thread src/llmq/core_write.cpp
Comment thread src/rpc/mempool.cpp
RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
{RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
RPCResult{RPCResult::Type::BOOL, "instantsend", "True if this transaction was locked via InstantSend"},
RPCResult{RPCResult::Type::STR, "instantlock", "\"true\" if this transaction was locked via InstantSend, \"unknown\" if InstantSend is unavailable"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Document the unlocked instantlock value

entryToJSON() serializes isman->IsLocked(...) through util::to_string(bool), which returns either "true" or "false"; it returns "unknown" only when the InstantSend manager is unavailable. The revised documentation omits the normal "false" response value, leaving this result incompletely documented in a PR specifically correcting RPC result schemas.

Suggested change
RPCResult{RPCResult::Type::STR, "instantlock", "\"true\" if this transaction was locked via InstantSend, \"unknown\" if InstantSend is unavailable"},
RPCResult{RPCResult::Type::STR, "instantlock", "\"true\" if this transaction was locked via InstantSend, \"false\" if it was not locked, and \"unknown\" if InstantSend is unavailable"},

source: ['codex']

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8647e75e0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/evo.cpp
// cannot be listed as alternatives here - the first entry would be applied
// to element 0 only and the second to every element after it.
// TODO: document fields of the detailed entry
{RPCResult::Type::ANY, "", "The ProTx hash when detailed=false, otherwise an object describing the masternode"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Render nested ANY results before using them in help

When users request help for protx list, this nested RPCResult::Type::ANY is still rendered by RPCResult::ToSections(), whose ANY case calls NONFATAL_UNREACHABLE(); RPCResults::ToDescriptionString() only skips top-level ANY results. This pattern is repeated by the other new nested ANY entries, so those command help paths return an internal-bug error instead of help text. Teach ToSections() how to print ANY, or avoid using it in public nested result docs.

Useful? React with 👍 / 👎.

Comment thread src/rpc/util.cpp
Comment on lines +909 to +910
if (doc_keys.find(result_entry.first) == doc_keys.end()) {
return false; // missing documentation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for CoinJoin metadata before rejecting extra result keys

When -rpcdoccheck is enabled, this new unknown-key rejection makes listtransactions fail for CoinJoin sends: SendMoney() stores map_value["DS"] = "1" when coin_control.IsUsingCoinJoin(), and WalletTxToJSON() pushes every wtx.mapValue key into the result object, but the listtransactions result docs in this commit still do not include DS. In that scenario the returned object contains an otherwise-valid Dash-specific field and MatchesType() returns false, turning the RPC into an internal bug during functional tests; either document/whitelist the wallet metadata keys or avoid strict checking for that map.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9f22c9ccc9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/coinjoin.cpp Outdated
Comment on lines 431 to 432
{RPCResult::Type::BOOL, "running", /*optional=*/true, "Whether mixing is currently running (not returned when no wallet is loaded)"},
{RPCResult::Type::NUM, "pending_inputs", "The number of successfully mixed inputs kept locked until the transaction spending them is observed"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mark pending_inputs optional for no-wallet CoinJoin info

When getcoinjoininfo runs on a regular node without a selected/loaded wallet, the handler returns at src/rpc/coinjoin.cpp:485-487 before CCoinJoinClientManager::getJsonInfo() adds pending_inputs, but this result entry is still required while the neighboring wallet-only fields were made optional. With -rpcdoccheck, that no-wallet/reduced-functionality path still fails the new result matcher instead of returning the CoinJoin options object; make pending_inputs optional or document a separate no-wallet result shape.

Useful? React with 👍 / 👎.

@thephez thephez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Language looks okay to me. Just one comment regarding this rename.

Comment thread src/wallet/rpc/transactions.cpp
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Potential PR merge conflicts

This is advisory only. It does not block CI, but it marks PRs that will likely need a rebase depending on merge order.

If these PRs merge first

This PR will likely need a rebase:

@PastaPastaPasta

Copy link
Copy Markdown
Member

2. listtransactions/gettransaction/listsinceblockDS not documented — confirmed blocker at tip

src/wallet/rpc/transactions.cpp:56 WalletTxToJSON (unchanged at 9f22c9) does for(item: wtx.mapValue) entry.pushKV(item.first,item.second). CoinJoin sends set mapValue["DS"]="1" in src/wallet/rpc/spend.cpp:154 / src/qt/walletmodel.cpp:318. TransactionDescriptionString() at 9f22c9:410-440 documents comment/to but not DS. New src/rpc/util.cpp:897-914 strict OBJ check requires every result key be in doc_keys — so any verbose list/get of a CoinJoin send fails std::any_of(MatchesType) at src/rpc/util.cpp:533 when rpcdoccheck=1. Other agent's 3 options (document DS optional, filter mapValue emission, or skip_type_check the object) all fix it; documenting DS as optional STR alongside comment/to is minimal.

Note: comment/to are now documented at 9f22c9, so the dump-as-doc'd pattern is intentional — DS is the sole leftover.

3. getcoinjoininfopending_inputs should be optional — confirmed blocker at tip

At 9f22c9:432 doc says required NUM pending_inputs. Runtime:

  • src/coinjoin/options.cpp:77 CCoinJoinClientOptions::GetJsonInfo never emits pending_inputs
  • src/coinjoin/client.cpp:1989 CCoinJoinClientManager::getJsonInfo emits pending_inputs + running + sessions — but src/rpc/coinjoin.cpp:477-490 only calls it when a wallet is present; no-wallet early-returns after GetJsonInfo + queue_size.

fa9 already fixed queue_size/running/sessions to /*optional=*/true — missed pending_inputs. One-line fix: {Type::NUM,"pending_inputs",/*optional=*/true,...}.

Agents had the above review

knst and others added 3 commits August 12, 2026 02:43
…d JSON

fc892c3 rpc: Fail to return undocumented or misdocumented JSON (MarcoFalke)
f4bc4a7 rpc: Add m_skip_type_check to RPCResult (MarcoFalke)

Pull request description:

  This avoids documentation shortcomings such as the ones fixed in commit e7b6272, 138d55e, 577bd51, f8c84e0, 0ee9a00, 13f4185, or faecb2e

ACKs for top commit:
  fanquake:
    ACK fc892c3 - tested that this catches issue, i.e bitcoin#24691:

Tree-SHA512: 9d0d7e6291bfc6f67541a4ff746d374ad8751fefcff6d103d8621c0298b190ab1d209ce96cfc3a0d4a6a5460a9f9bb790eb96027b16e5ff91f2512e40c92ca84

Co-authored-by: fanquake <fanquake@gmail.com>
… JSON-RPC interface

Includes 6a1a66c rpc: render Type::ANY in help text instead of aborting

RPCResult::Type::ANY triggers NONFATAL_UNREACHABLE() in ToSections(),
which crashes the help() RPC when a command uses Type::ANY in a
nested result field.

Previously this was never hit because Type::ANY was only used as a
top-level alternate result type, filtered out before ToSections() is
called.

getopenrpcinfo() will use this result type, so render it like other
types allowing it to be used in nested result definitions like schema.

Co-authored-by: will <will@256k1.dev>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b77fd4ac77

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/util.cpp
Comment on lines +923 to +924
if (!doc_entry.MatchesType(result_it->second)) {
return false; // wrong type

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep getpeerinfo mapped_as from tripping doccheck

When -rpcdoccheck is enabled and getpeerinfo reports a peer with a non-zero AS mapping, this new recursive object check now validates the existing mapped_as result doc and rejects it: src/rpc/net.cpp documents mapped_as as RPCResult::Type::STR, but the handler pushes uint64_t(stats.m_mapped_as) at src/rpc/net.cpp:230-231. In that asmap-enabled context the RPC returns an internal doccheck bug instead of peer info; update the result doc to NUM (or otherwise match the emitted type) before enabling strict nested checks.

Useful? React with 👍 / 👎.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The recursive RPC result checker still rejects two supported responses: wallet-disabled getcoinjoininfo returns an empty object that matches neither documented variant, and getpeerinfo documents numeric mapped_as values as strings. The current head also contains one non-buildable intermediate commit and three smaller documentation inconsistencies.
Source: reviewers gpt-5.6-sol (general), gpt-5.6-sol (dash-core-commit-history), and gpt-5.6-sol (backport-reviewer); final verifier gpt-5.6-sol. Orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (not reviewer evidence).

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed), gpt-5.6-sol — backport-reviewer (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking | 🟡 1 suggestion(s) | 💬 2 nitpick(s)

2 additional finding(s) omitted (not in diff).

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/rpc/coinjoin.cpp`:
- [BLOCKING] src/rpc/coinjoin.cpp:423-429: Mark pending_inputs optional for no-wallet CoinJoin info
  Making pending_inputs optional fixes the wallet-enabled path where no wallet is selected, but builds without ENABLE_WALLET still fail result checking. getcoinjoininfo remains registered in that configuration, while the entire regular-node producer at lines 476-502 is compiled out, so the handler returns {}. The regular-node schema still requires enabled through denoms_hardcap, and the masternode schema also requires fields absent from {}, so -rpcdoccheck turns this supported reduced response into an internal documentation-check error. Emit the base options outside the wallet guard, make these base fields optional, or add a distinct empty-object result variant.

In `src/rpc/net.cpp`:
- [BLOCKING] src/rpc/net.cpp:129: Missing prerequisite: bitcoin#17812
  The newly recursive checker validates each getpeerinfo entry, but mapped_as is still declared as STR even though the producer inserts uint64_t(stats.m_mapped_as). With AS mapping enabled and a nonzero mapping, the checker therefore replaces getpeerinfo's response with an internal documentation-check error. Upstream bitcoin#23083 already had mapped_as declared as NUM because bitcoin#17812 commit 5ba829e12e99f119df56cab422f827b9be03fe57 fixed it before this backport; carry that prerequisite fix into Dash.

In `src/governance/core_write.cpp`:
- [SUGGESTION] src/governance/core_write.cpp:138: Place the RPCResult API backport before its callers
  Commit 3344adbae81 uses the new RPCResult constructor argument ending in /*skip_type_check=*/true here and in rawtransaction.cpp, but that commit's parent only has constructors accepting the old argument shapes. The required m_skip_type_check API is introduced by the following commit f2e13f0f46a, so the first PR commit cannot compile independently even though the final head can. Reorder the API backport before its callers or squash the dependent changes so the permanent history remains buildable and bisectable.

In `src/rpc/rawtransaction.cpp`:
- [NITPICK] src/rpc/rawtransaction.cpp:548-550: Update the getislocks summary to document the string "None"
  The implementation appends the JSON string "None" when no InstantSend lock is known, and the detailed result declaration now accommodates that string. The command summary still says the RPC returns Null, which denotes a different JSON type and contradicts the implementation.

In `src/wallet/rpc/wallet.cpp`:
- [NITPICK] src/wallet/rpc/wallet.cpp:126: Do not mark `keypoolsize_hd_internal` optional while always emitting it
  getwalletinfo unconditionally inserts keypoolsize_hd_internal at line 193, including when its value is zero. Marking the field optional and saying it only appears when the feature is used therefore misdocuments the actual response. Keep the field required and explain the zero value instead.

In `src/rpc/mempool.cpp`:
- [NITPICK] src/rpc/mempool.cpp:276: Document the unlocked instantlock value
  (existing thread: https://github.com/dashpay/dash/pull/7502#discussion_r3685409612)
  entryToJSON() serializes isman->IsLocked(...) through util::to_string(bool), which returns either "true" or "false"; "unknown" is emitted only when the InstantSend manager is unavailable. The result description omits the normal unlocked value "false", leaving this Dash-specific schema adaptation incomplete.

Comment thread src/rpc/coinjoin.cpp
Comment on lines 427 to 429
{RPCResult::Type::NUM, "max_amount", "Target CoinJoin balance in " + CURRENCY_UNIT + ""},
{RPCResult::Type::NUM, "denoms_goal", "How many inputs of each denominated amount to target"},
{RPCResult::Type::NUM, "denoms_hardcap", "Maximum limit of how many inputs of each denominated amount to create"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Mark pending_inputs optional for no-wallet CoinJoin info

Making pending_inputs optional fixes the wallet-enabled path where no wallet is selected, but builds without ENABLE_WALLET still fail result checking. getcoinjoininfo remains registered in that configuration, while the entire regular-node producer at lines 476-502 is compiled out, so the handler returns {}. The regular-node schema still requires enabled through denoms_hardcap, and the masternode schema also requires fields absent from {}, so -rpcdoccheck turns this supported reduced response into an internal documentation-check error. Emit the base options outside the wallet guard, make these base fields optional, or add a distinct empty-object result variant.

Suggested change
{RPCResult::Type::NUM, "max_amount", "Target CoinJoin balance in " + CURRENCY_UNIT + ""},
{RPCResult::Type::NUM, "denoms_goal", "How many inputs of each denominated amount to target"},
{RPCResult::Type::NUM, "denoms_hardcap", "Maximum limit of how many inputs of each denominated amount to create"},
{RPCResult::Type::BOOL, "enabled", /*optional=*/true, "Whether mixing functionality is enabled"},
{RPCResult::Type::BOOL, "multisession", /*optional=*/true, "Whether CoinJoin Multisession option is enabled"},
{RPCResult::Type::NUM, "max_sessions", /*optional=*/true, "How many parallel mixing sessions can there be at once"},
{RPCResult::Type::NUM, "max_rounds", /*optional=*/true, "How many rounds to mix"},
{RPCResult::Type::NUM, "max_amount", /*optional=*/true, "Target CoinJoin balance in " + CURRENCY_UNIT + ""},
{RPCResult::Type::NUM, "denoms_goal", /*optional=*/true, "How many inputs of each denominated amount to target"},
{RPCResult::Type::NUM, "denoms_hardcap", /*optional=*/true, "Maximum limit of how many inputs of each denominated amount to create"},

source: ['codex']

// Always emitted by ToJson()
{RPCResult::Type::STR_HEX, "hex", "Governance object data as hex"},
}},
}, /*skip_type_check=*/true},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Place the RPCResult API backport before its callers

Commit 3344adb uses the new RPCResult constructor argument ending in /skip_type_check=/true here and in rawtransaction.cpp, but that commit's parent only has constructors accepting the old argument shapes. The required m_skip_type_check API is introduced by the following commit f2e13f0, so the first PR commit cannot compile independently even though the final head can. Reorder the API backport before its callers or squash the dependent changes so the permanent history remains buildable and bisectable.

source: ['codex']

Comment thread src/wallet/rpc/wallet.cpp
{RPCResult::Type::NUM_TIME, "timefirstkey", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest known key in the wallet. Legacy wallets only"},
{RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only"},
{RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
{RPCResult::Type::NUM, "keypoolsize_hd_internal", /*optional=*/ true, "how many new keys are pre-generated for internal use (used for change outputs and mobile coinjoin, only appears if the wallet is using this feature, otherwise external keys are used)"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Do not mark keypoolsize_hd_internal optional while always emitting it

getwalletinfo unconditionally inserts keypoolsize_hd_internal at line 193, including when its value is zero. Marking the field optional and saying it only appears when the feature is used therefore misdocuments the actual response. Keep the field required and explain the zero value instead.

Suggested change
{RPCResult::Type::NUM, "keypoolsize_hd_internal", /*optional=*/ true, "how many new keys are pre-generated for internal use (used for change outputs and mobile coinjoin, only appears if the wallet is using this feature, otherwise external keys are used)"},
{RPCResult::Type::NUM, "keypoolsize_hd_internal", "how many new keys are pre-generated for internal use (used for change outputs and mobile coinjoin; zero if no internal keypool is in use)"},

source: ['coderabbit']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RPC Some notable changes to RPC params/behaviour/descriptions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants