perf(rpc): move the result subtree out of the parse tree
parseRpcResult copied the "result" node out of the parsed reply, because indexing the JSON object yields an lvalue reference. On large replies - full transaction lists, unspent-note sets - that duplicated the entire subtree for no reason, and it also meant a secret-bearing result then existed in two trees at once. - The result node is now moved out of the parse tree instead of copied, so the secret lives only in the returned value that the calling code already wipes. The leftover result slot is moved-from (null), so the existing secret-scrub of the discarded tree still runs harmlessly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -451,8 +451,8 @@ json RPCClient::parseRpcResult(long httpCode, const std::string& body, bool scru
|
||||
throw RpcError(errCode, "RPC error: " + err_msg, httpCode);
|
||||
}
|
||||
|
||||
json result = response["result"]; // a COPY of the subobject (operator[] yields an lvalue ref)
|
||||
if (scrubSource) scrubJsonSecrets(response); // zero the discarded tree's secret before it frees (B7)
|
||||
json result = std::move(response["result"]); // move the subtree out: the secret now lives only here
|
||||
if (scrubSource) scrubJsonSecrets(response); // response["result"] is now moved-from (null); harmless (B7)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -285,9 +285,9 @@ private:
|
||||
// hold curl_mutex_ and have verified impl_->curl.
|
||||
std::string performCall(const std::string& method, const json& params, long& httpCodeOut);
|
||||
// Centralizes the HTTP-code check and JSON error->RpcError extraction, returning
|
||||
// response["result"] on success. When scrubSource is true (secret-bearing calls), the intermediate
|
||||
// parse tree's string values are zeroed before it is discarded — parseRpcResult returns a COPY of
|
||||
// the result node, so its own tree would otherwise free the secret un-wiped (B7).
|
||||
// response["result"] on success. The result subtree is moved out of the parse tree, so a secret lives
|
||||
// only in the returned node (which callSecret/callSecretString callers wipe). When scrubSource is true
|
||||
// (secret-bearing calls), any remaining parse-tree string values are zeroed before it is discarded (B7).
|
||||
static json parseRpcResult(long httpCode, const std::string& body, bool scrubSource = false);
|
||||
// A non-200 reply: RpcError when the body carries a JSON-RPC error, else RpcTransportError classified
|
||||
// from the status and plain-text body. hideBody keeps the body out of the message (secret calls).
|
||||
|
||||
Reference in New Issue
Block a user