Repository: bitcoin/bitcoin
File: src/rpc/server.cpp (C++)

Code before:
        UniValue result = tableRPC.execute(jreq);
        rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
    }
    catch (const UniValue& objError)
    {
        rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
    }
    catch (const std::exception& e)
    {
        rpc_result = JSONRPCReplyObj(NullUniValue,
                                     JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
    }

    return rpc_result;
}

std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
{
    UniValue ret(UniValue::VARR);
    for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
        ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));

    return ret.write() + "\n";
}

/**
 * Process named arguments into a vector of positional arguments, based on the
 * passed-in specification for the RPC call's arguments.
 */
static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::pair<std::string, bool>>& argNames)
{
    JSONRPCRequest out = in;
    out.params = UniValue(UniValue::VARR);
    // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
    // there is an unknown one.
    const std::vector<std::string>& keys = in.params.getKeys();
    const std::vector<UniValue>& values = in.params.getValues();
    std::unordered_map<std::string, const UniValue*> argsIn;
    for (size_t i=0; i<keys.size(); ++i) {
        auto [_, inserted] = argsIn.emplace(keys[i], &values[i]);
        if (!inserted) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times");
        }
    }
    // Process expected parameters. If any parameters were left unspecified in
    // the request before a parameter that was specified, null values need to be
    // inserted at the unspecified parameter positions, and the "hole" variable
    // below tracks the number of null values that need to be inserted.
    // The "initial_hole_size" variable stores the size of the initial hole,
    // i.e. how many initial positional arguments were left unspecified. This is
    // used after the for-loop to add initial positional arguments from the

Review comment (suggestion):
In commit "rpc: JSON-RPC 2.0 should not respond to "notifications"" (28e4d9e7dd1604f1504f191d258a32f495c2fb4f)

Would suggest std::move(*maybe_result) here as well to avoid copying

Code after:
            return JSONRPCReplyObj(NullUniValue, JSONRPCError(RPC_MISC_ERROR, e.what()), jreq.id, jreq.m_json_version);
        }
    } else {
        result = tableRPC.execute(jreq);
    }

    return JSONRPCReplyObj(std::move(result), NullUniValue, jreq.id, jreq.m_json_version);
}

/**
 * Process named arguments into a vector of positional arguments, based on the
 * passed-in specification for the RPC call's arguments.
 */
static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::pair<std::string, bool>>& argNames)
{
    JSONRPCRequest out = in;
    out.params = UniValue(UniValue::VARR);
    // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
    // there is an unknown one.
    const std::vector<std::string>& keys = in.params.getKeys();
    const std::vector<UniValue>& values = in.params.getValues();
    std::unordered_map<std::string, const UniValue*> argsIn;
    for (size_t i=0; i<keys.size(); ++i) {
        auto [_, inserted] = argsIn.emplace(keys[i], &values[i]);
        if (!inserted) {
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times");
        }
    }
    // Process expected parameters. If any parameters were left unspecified in
    // the request before a parameter that was specified, null values need to be
    // inserted at the unspecified parameter positions, and the "hole" variable
    // below tracks the number of null values that need to be inserted.
    // The "initial_hole_size" variable stores the size of the initial hole,
    // i.e. how many initial positional arguments were left unspecified. This is
    // used after the for-loop to add initial positional arguments from the
    // "args" parameter, if present.
    int hole = 0;
    int initial_hole_size = 0;
    const std::string* initial_param = nullptr;
    UniValue options{UniValue::VOBJ};
    for (const auto& [argNamePattern, named_only]: argNames) {
        std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
        auto fr = argsIn.end();
        for (const std::string & argName : vargNames) {
            fr = argsIn.find(argName);
            if (fr != argsIn.end()) {
                break;
            }
        }

        // Handle named-only parameters by pushing them into a temporary options