Inside Bitcoin
Opening the selected file…
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.
1// Copyright (c) 2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <rpc/register.h> // IWYU pragma: associated8#include <addresstype.h>9#include <crypto/hex_base.h>10#include <key.h>11#include <key_io.h>12#include <outputtype.h>13#include <pubkey.h>14#include <rpc/protocol.h>15#include <rpc/request.h>16#include <rpc/server.h>17#include <rpc/util.h>18#include <script/descriptor.h>19#include <script/script.h>20#include <script/signingprovider.h>21#include <tinyformat.h>22#include <univalue.h>23#include <util/check.h>25#include <cstddef>26#include <cstdint>27#include <map>28#include <memory>29#include <optional>30#include <span>31#include <string>32#include <string_view>33#include <tuple>34#include <utility>35#include <variant>36#include <vector>38static RPCMethod validateaddress()39{40return RPCMethod{41"validateaddress",42"Return information about the given bitcoin address.\n",43{44{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},45},46RPCResult{47RPCResult::Type::OBJ, "", "",48{49{RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},50{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address validated"},51{RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded output script generated by the address"},52{RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script"},53{RPCResult::Type::BOOL, "iswitness", /*optional=*/true, "If the address is a witness address"},54{RPCResult::Type::NUM, "witness_version", /*optional=*/true, "The version number of the witness program"},55{RPCResult::Type::STR_HEX, "witness_program", /*optional=*/true, "The hex value of the witness program"},56{RPCResult::Type::STR, "error", /*optional=*/true, "Error message, if any"},57{RPCResult::Type::ARR, "error_locations", /*optional=*/true, "Indices of likely error locations in address, if known (e.g. Bech32 errors)",58{59{RPCResult::Type::NUM, "index", "index of a potential error"},60}},61}62},63RPCExamples{64HelpExampleCli("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +65HelpExampleRpc("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"")66},67[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue68{69std::string error_msg;70std::vector<int> error_locations;71CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg, &error_locations);72const bool isValid = IsValidDestination(dest);73CHECK_NONFATAL(isValid == error_msg.empty());75UniValue ret(UniValue::VOBJ);76ret.pushKV("isvalid", isValid);77if (isValid) {78std::string currentAddress = EncodeDestination(dest);79ret.pushKV("address", currentAddress);81CScript scriptPubKey = GetScriptForDestination(dest);82ret.pushKV("scriptPubKey", HexStr(scriptPubKey));84UniValue detail = DescribeAddress(dest);85ret.pushKVs(std::move(detail));86} else {87UniValue error_indices(UniValue::VARR);88for (int i : error_locations) error_indices.push_back(i);89ret.pushKV("error_locations", std::move(error_indices));90ret.pushKV("error", error_msg);91}93return ret;94},95};96}98static RPCMethod createmultisig()99{100return RPCMethod{101"createmultisig",102"Creates a multi-signature address with n signatures of m keys required.\n"103"It returns a json object with the address and redeemScript.\n",104{105{"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the m keys."},106{"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex-encoded public keys.",107{108{"key", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded public key"},109}},110{"address_type", RPCArg::Type::STR, RPCArg::Default{"legacy"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},111},112RPCResult{113RPCResult::Type::OBJ, "", "",114{115{RPCResult::Type::STR, "address", "The value of the new multisig address."},116{RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script."},117{RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},118{RPCResult::Type::ARR, "warnings", /*optional=*/true, "Any warnings resulting from the creation of this multisig",119{120{RPCResult::Type::STR, "", ""},121}},122}123},124RPCExamples{125"\nCreate a multisig address from 2 public keys\n"126+ HelpExampleCli("createmultisig", "2 \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") +127"\nAs a JSON-RPC call\n"128+ HelpExampleRpc("createmultisig", "2, [\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\",\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\"]")129},130[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue131{132int required = request.params[0].getInt<int>();134// Get the public keys135const UniValue& keys = request.params[1].get_array();136std::vector<CPubKey> pubkeys;137pubkeys.reserve(keys.size());138for (unsigned int i = 0; i < keys.size(); ++i) {139pubkeys.push_back(HexToPubKey(keys[i].get_str()));140}142// Get the output type143auto address_type{self.Arg<std::string_view>("address_type")};144auto output_type{ParseOutputType(address_type)};145if (!output_type) {146throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, tfm::format("Unknown address type '%s'", address_type));147} else if (output_type.value() == OutputType::BECH32M) {148throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "createmultisig cannot create bech32m multisig addresses");149}151FlatSigningProvider keystore;152CScript inner;153const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type.value(), keystore, inner);155// Make the descriptor156std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), keystore);158UniValue result(UniValue::VOBJ);159result.pushKV("address", EncodeDestination(dest));160result.pushKV("redeemScript", HexStr(inner));161result.pushKV("descriptor", descriptor->ToString());163UniValue warnings(UniValue::VARR);164if (descriptor->GetOutputType() != output_type.value()) {165// Only warns if the user has explicitly chosen an address type we cannot generate166warnings.push_back("Unable to make chosen address type, please ensure no uncompressed public keys are present.");167}168PushWarnings(warnings, result);170return result;171},172};173}175static RPCMethod getdescriptorinfo()176{177const std::string EXAMPLE_DESCRIPTOR = "wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)";179return RPCMethod{180"getdescriptorinfo",181"Analyses a descriptor.\n",182{183{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},184},185RPCResult{186RPCResult::Type::OBJ, "", "",187{188{RPCResult::Type::STR, "descriptor", "The descriptor, without private keys. For a multipath descriptor, only the first will be returned."},189{RPCResult::Type::ARR, "multipath_expansion", /*optional=*/true, "All descriptors produced by expanding multipath derivation elements. Only if the provided descriptor specifies multipath derivation elements.",190{191{RPCResult::Type::STR, "", ""},192}},193{RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"},194{RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"},195{RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"},196{RPCResult::Type::BOOL, "hasprivatekeys", "Whether the input descriptor contained at least one private key"},197}198},199RPCExamples{200"Analyse a descriptor\n" +201HelpExampleCli("getdescriptorinfo", "\"" + EXAMPLE_DESCRIPTOR + "\"") +202HelpExampleRpc("getdescriptorinfo", "\"" + EXAMPLE_DESCRIPTOR + "\"")203},204[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue205{206FlatSigningProvider provider;207std::string error;208auto descs = Parse(self.Arg<std::string_view>("descriptor"), provider, error);209if (descs.empty()) {210throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);211}213UniValue result(UniValue::VOBJ);214result.pushKV("descriptor", descs.at(0)->ToString());216if (descs.size() > 1) {217UniValue multipath_descs(UniValue::VARR);218for (const auto& d : descs) {219multipath_descs.push_back(d->ToString());220}221result.pushKV("multipath_expansion", multipath_descs);222}224result.pushKV("checksum", GetDescriptorChecksum(request.params[0].get_str()));225result.pushKV("isrange", descs.at(0)->IsRange());226result.pushKV("issolvable", descs.at(0)->IsSolvable());227result.pushKV("hasprivatekeys", provider.keys.size() > 0);228return result;229},230};231}233static UniValue DeriveAddresses(const Descriptor* desc, int64_t range_begin, int64_t range_end, FlatSigningProvider& key_provider)234{235UniValue addresses(UniValue::VARR);237for (int64_t i = range_begin; i <= range_end; ++i) {238FlatSigningProvider provider;239std::vector<CScript> scripts;240if (!desc->Expand(i, key_provider, scripts, provider)) {241throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");242}244for (const CScript& script : scripts) {245CTxDestination dest;246if (!ExtractDestination(script, dest)) {247// ExtractDestination no longer returns true for P2PK since it doesn't have a corresponding address248// However combo will output P2PK and should just ignore that script249if (scripts.size() > 1 && std::get_if<PubKeyDestination>(&dest)) {250continue;