Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
501BOOST_CHECK_EQUAL(result2[4], 9);503// Same test as above, but one of the percentile-overlapping pairs is split in 2.504total_weight = 100;505CAmount result3[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };506feerates.clear();508feerates.emplace_back(1, 9);509feerates.emplace_back(2 , 11); // 10th percentile510feerates.emplace_back(2 , 5); // 25th percentile511feerates.emplace_back(4 ,50); //50th + 75th percentile512feerates.emplace_back(5 ,10);513feerates.emplace_back(9 ,15); // 90th percentile515CalculatePercentilesByWeight(result3, feerates, total_weight);517BOOST_CHECK_EQUAL(result3[0], 2);518BOOST_CHECK_EQUAL(result3[1], 2);519BOOST_CHECK_EQUAL(result3[2], 4);520BOOST_CHECK_EQUAL(result3[3], 4);521BOOST_CHECK_EQUAL(result3[4], 9);523// Test with one transaction spanning all percentiles.524total_weight = 104;525CAmount result4[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };526feerates.clear();528feerates.emplace_back(1, 100);529feerates.emplace_back(2, 1);530feerates.emplace_back(3, 1);531feerates.emplace_back(3, 1);532feerates.emplace_back(999999, 1);534CalculatePercentilesByWeight(result4, feerates, total_weight);536for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {537BOOST_CHECK_EQUAL(result4[i], 1);538}539}541// Make sure errors are triggered appropriately if parameters have the same names.542BOOST_AUTO_TEST_CASE(check_dup_param_names)543{544enum ParamType { POSITIONAL, NAMED, NAMED_ONLY };545auto make_rpc = [](std::vector<std::tuple<std::string, ParamType>> param_names) {546std::vector<RPCArg> params;547std::vector<RPCArg> options;548auto push_options = [&] { if (!options.empty()) params.emplace_back(strprintf("options%i", params.size()), RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", std::move(options)); };549for (auto& [param_name, param_type] : param_names) {550if (param_type == POSITIONAL) {551push_options();552params.emplace_back(std::move(param_name), RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "description");553} else {554options.emplace_back(std::move(param_name), RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "description", RPCArgOptions{.also_positional = param_type == NAMED});555}556}557push_options();558return RPCMethod{"method_name", "description", params, RPCResults{}, RPCExamples{""}};559};561// No errors if parameter names are unique.562make_rpc({{"p1", POSITIONAL}, {"p2", POSITIONAL}});563make_rpc({{"p1", POSITIONAL}, {"p2", NAMED}});564make_rpc({{"p1", POSITIONAL}, {"p2", NAMED_ONLY}});565make_rpc({{"p1", NAMED}, {"p2", POSITIONAL}});566make_rpc({{"p1", NAMED}, {"p2", NAMED}});567make_rpc({{"p1", NAMED}, {"p2", NAMED_ONLY}});568make_rpc({{"p1", NAMED_ONLY}, {"p2", POSITIONAL}});569make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED}});570make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED_ONLY}});572{573test_only_CheckFailuresAreExceptionsNotAborts mock_checks{};574// Error if parameter names are duplicates, unless one parameter is575// positional and the other is named and .also_positional is true.576BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", POSITIONAL}}), NonFatalCheckError);577make_rpc({{"p1", POSITIONAL}, {"p1", NAMED}});578BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", NAMED_ONLY}}), NonFatalCheckError);579make_rpc({{"p1", NAMED}, {"p1", POSITIONAL}});580BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED}}), NonFatalCheckError);581BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED_ONLY}}), NonFatalCheckError);582BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", POSITIONAL}}), NonFatalCheckError);583BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED}}), NonFatalCheckError);584BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED_ONLY}}), NonFatalCheckError);586// Make sure duplicate aliases are detected too.587BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p2|p1", NAMED_ONLY}}), NonFatalCheckError);588}589}591BOOST_AUTO_TEST_CASE(help_example)592{593// test different argument types594const RPCArgList& args = {{"foo", "bar"}, {"b", true}, {"n", 1}};595BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", args), "> bitcoin-cli -named test foo=bar b=true n=1\n");596BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", args), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"foo\":\"bar\",\"b\":true,\"n\":1}}' -H 'content-type: application/json' http://127.0.0.1:8332/\n");598// test shell escape599BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b'ar"}}), "> bitcoin-cli -named test foo='b'''ar'\n");600BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b\"ar"}}), "> bitcoin-cli -named test foo='b\"ar'\n");601BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b ar"}}), "> bitcoin-cli -named test foo='b ar'\n");603// test object params604UniValue obj_value(UniValue::VOBJ);605obj_value.pushKV("foo", "bar");606obj_value.pushKV("b", false);607obj_value.pushKV("n", 1);608BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", obj_value}}), "> bitcoin-cli -named test name='{\"foo\":\"bar\",\"b\":false,\"n\":1}'\n");609BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", obj_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":{\"foo\":\"bar\",\"b\":false,\"n\":1}}}' -H 'content-type: application/json' http://127.0.0.1:8332/\n");611// test array params612UniValue arr_value(UniValue::VARR);613arr_value.push_back("bar");614arr_value.push_back(false);615arr_value.push_back(1);616BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", arr_value}}), "> bitcoin-cli -named test name='[\"bar\",false,1]'\n");617BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", arr_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":[\"bar\",false,1]}}' -H 'content-type: application/json' http://127.0.0.1:8332/\n");619// test types don't matter for shell620BOOST_CHECK_EQUAL(HelpExampleCliNamed("foo", {{"arg", true}}), HelpExampleCliNamed("foo", {{"arg", "true"}}));622// test types matter for Rpc623BOOST_CHECK_NE(HelpExampleRpcNamed("foo", {{"arg", true}}), HelpExampleRpcNamed("foo", {{"arg", "true"}}));624}626static void CheckRpc(const std::vector<RPCArg>& params, const UniValue& args, RPCMethod::RPCMethodImpl test_impl)627{628auto null_result{RPCResult{RPCResult::Type::NONE, "", "None"}};629const RPCMethod rpc{"dummy", "dummy description", params, null_result, RPCExamples{""}, test_impl};630JSONRPCRequest req;631req.params = args;633rpc.HandleRequest(req);634}636BOOST_AUTO_TEST_CASE(rpc_arg_helper)637{638constexpr bool DEFAULT_BOOL = true;639constexpr auto DEFAULT_STRING = "default";640constexpr uint64_t DEFAULT_UINT64_T = 3;642//! Parameters with which the RPCMethod is instantiated643const std::vector<RPCArg> params{644// Required arg645{"req_int", RPCArg::Type::NUM, RPCArg::Optional::NO, ""},646{"req_str", RPCArg::Type::STR, RPCArg::Optional::NO, ""},647// Default arg648{"def_uint64_t", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_UINT64_T}, ""},649{"def_string", RPCArg::Type::STR, RPCArg::Default{DEFAULT_STRING}, ""},650{"def_bool", RPCArg::Type::BOOL, RPCArg::Default{DEFAULT_BOOL}, ""},651// Optional arg without default652{"opt_double", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, ""},653{"opt_string", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}654};656//! Check that `self.Arg` returns the same value as the `request.params` accessors657RPCMethod::RPCMethodImpl check_positional = [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {658BOOST_CHECK_EQUAL(self.Arg<int>("req_int"), request.params[0].getInt<int>());659BOOST_CHECK_EQUAL(self.Arg<std::string_view>("req_str"), request.params[1].get_str());660BOOST_CHECK_EQUAL(self.Arg<uint64_t>("def_uint64_t"), request.params[2].isNull() ? DEFAULT_UINT64_T : request.params[2].getInt<uint64_t>());661BOOST_CHECK_EQUAL(self.Arg<std::string_view>("def_string"), request.params[3].isNull() ? DEFAULT_STRING : request.params[3].get_str());662BOOST_CHECK_EQUAL(self.Arg<bool>("def_bool"), request.params[4].isNull() ? DEFAULT_BOOL : request.params[4].get_bool());663if (!request.params[5].isNull()) {664BOOST_CHECK_EQUAL(self.MaybeArg<double>("opt_double").value(), request.params[5].get_real());665} else {666BOOST_CHECK(!self.MaybeArg<double>("opt_double"));667}668if (!request.params[6].isNull()) {669BOOST_CHECK_EQUAL(self.MaybeArg<std::string_view>("opt_string"), request.params[6].get_str());670} else {671BOOST_CHECK(!self.MaybeArg<std::string_view>("opt_string"));672}673return UniValue{};674};675CheckRpc(params, UniValue{JSON(R"([5, "hello", null, null, null, null, null])")}, check_positional);676CheckRpc(params, UniValue{JSON(R"([5, "hello", 4, "test", true, 1.23, "world"])")}, check_positional);677}679BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.