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.
251}253script_out = GetScriptForMultisig(required, pubkeys);255// Check if any keys are uncompressed. If so, the type is legacy256for (const CPubKey& pk : pubkeys) {257if (!pk.IsCompressed()) {258type = OutputType::LEGACY;259break;260}261}263if (type == OutputType::LEGACY && script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) {264throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE)));265}267// Make the address268CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type);270return dest;271}273class DescribeAddressVisitor274{275public:276explicit DescribeAddressVisitor() = default;278UniValue operator()(const CNoDestination& dest) const279{280return UniValue(UniValue::VOBJ);281}283UniValue operator()(const PubKeyDestination& dest) const284{285return UniValue(UniValue::VOBJ);286}288UniValue operator()(const PKHash& keyID) const289{290UniValue obj(UniValue::VOBJ);291obj.pushKV("isscript", false);292obj.pushKV("iswitness", false);293return obj;294}296UniValue operator()(const ScriptHash& scriptID) const297{298UniValue obj(UniValue::VOBJ);299obj.pushKV("isscript", true);300obj.pushKV("iswitness", false);301return obj;302}304UniValue operator()(const WitnessV0KeyHash& id) const305{306UniValue obj(UniValue::VOBJ);307obj.pushKV("isscript", false);308obj.pushKV("iswitness", true);309obj.pushKV("witness_version", 0);310obj.pushKV("witness_program", HexStr(id));311return obj;312}314UniValue operator()(const WitnessV0ScriptHash& id) const315{316UniValue obj(UniValue::VOBJ);317obj.pushKV("isscript", true);318obj.pushKV("iswitness", true);319obj.pushKV("witness_version", 0);320obj.pushKV("witness_program", HexStr(id));321return obj;322}324UniValue operator()(const WitnessV1Taproot& tap) const325{326UniValue obj(UniValue::VOBJ);327obj.pushKV("isscript", true);328obj.pushKV("iswitness", true);329obj.pushKV("witness_version", 1);330obj.pushKV("witness_program", HexStr(tap));331return obj;332}334UniValue operator()(const PayToAnchor& anchor) const335{336UniValue obj(UniValue::VOBJ);337obj.pushKV("isscript", true);338obj.pushKV("iswitness", true);339return obj;340}342UniValue operator()(const WitnessUnknown& id) const343{344UniValue obj(UniValue::VOBJ);345obj.pushKV("iswitness", true);346obj.pushKV("witness_version", id.GetWitnessVersion());347obj.pushKV("witness_program", HexStr(id.GetWitnessProgram()));348return obj;349}350};352UniValue DescribeAddress(const CTxDestination& dest)353{354return std::visit(DescribeAddressVisitor(), dest);355}357/**358* Returns a sighash value corresponding to the passed in argument.359*360* @pre The sighash argument should be string or null.361*/362std::optional<int> ParseSighashString(const UniValue& sighash)363{364if (sighash.isNull()) {365return std::nullopt;366}367const auto result{SighashFromStr(sighash.get_str())};368if (!result) {369throw JSONRPCError(RPC_INVALID_PARAMETER, util::ErrorString(result).original);370}371return result.value();372}374unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)375{376const int target{value.getInt<int>()};377const unsigned int unsigned_target{static_cast<unsigned int>(target)};378if (target < 1 || unsigned_target > max_target) {379throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u and %u", 1, max_target));380}381return unsigned_target;382}384RPCErrorCode RPCErrorFromPSBTError(PSBTError err)385{386switch (err) {387case PSBTError::UNSUPPORTED:388return RPC_INVALID_PARAMETER;389case PSBTError::SIGHASH_MISMATCH:390return RPC_DESERIALIZATION_ERROR;391default: break;392}393return RPC_TRANSACTION_ERROR;394}396RPCErrorCode RPCErrorFromTransactionError(TransactionError terr)397{398switch (terr) {399case TransactionError::MEMPOOL_REJECTED:400return RPC_TRANSACTION_REJECTED;401case TransactionError::ALREADY_IN_UTXO_SET:402return RPC_VERIFY_ALREADY_IN_UTXO_SET;403case TransactionError::PRIVATE_BROADCAST_FULL:404return RPC_LIMIT_EXCEEDED;405default: break;406}407return RPC_TRANSACTION_ERROR;408}410UniValue JSONRPCPSBTError(PSBTError err)411{412return JSONRPCError(RPCErrorFromPSBTError(err), PSBTErrorString(err).original);413}415UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string)416{417if (err_string.length() > 0) {418return JSONRPCError(RPCErrorFromTransactionError(terr), err_string);419} else {420return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr).original);421}422}424/**425* A pair of strings that can be aligned (through padding) with other Sections426* later on427*/428struct Section {429Section(const std::string& left, const std::string& right)430: m_left{left}, m_right{right} {}431std::string m_left;432const std::string m_right;433};435/**436* Keeps track of RPCArgs by transforming them into sections for the purpose437* of serializing everything to a single string438*/439struct Sections {440std::vector<Section> m_sections;441size_t m_max_pad{0};443void PushSection(const Section& s)444{445m_max_pad = std::max(m_max_pad, s.m_left.size());446m_sections.push_back(s);447}449/**450* Recursive helper to translate an RPCArg into sections451*/452// NOLINTNEXTLINE(misc-no-recursion)453void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NONE)454{455const auto indent = std::string(current_indent, ' ');456const auto indent_next = std::string(current_indent + 2, ' ');457const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name458const bool is_top_level_arg{outer_type == OuterType::NONE}; // True on the first recursion460switch (arg.m_type) {461case RPCArg::Type::STR_HEX:462case RPCArg::Type::STR:463case RPCArg::Type::NUM:464case RPCArg::Type::AMOUNT:465case RPCArg::Type::RANGE:466case RPCArg::Type::BOOL:467case RPCArg::Type::OBJ_NAMED_PARAMS: {468if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion469auto left = indent;470if (arg.m_opts.type_str.size() != 0 && push_name) {471left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0);472} else {473left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false);474}475left += ",";476PushSection({left, arg.ToDescriptionString(/*is_named_arg=*/push_name)});477break;478}479case RPCArg::Type::OBJ:480case RPCArg::Type::OBJ_USER_KEYS: {481const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name);482PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right});483for (const auto& arg_inner : arg.m_inner) {484Push(arg_inner, current_indent + 2, OuterType::OBJ);485}486if (arg.m_type != RPCArg::Type::OBJ) {487PushSection({indent_next + "...", ""});488}489PushSection({indent + "}" + (is_top_level_arg ? "" : ","), ""});490break;491}492case RPCArg::Type::ARR: {493auto left = indent;494left += push_name ? "\"" + arg.GetName() + "\": " : "";495left += "[";496const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name);497PushSection({left, right});498for (const auto& arg_inner : arg.m_inner) {499Push(arg_inner, current_indent + 2, OuterType::ARR);500}