Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/misc.cpp
// Copyright (c) 2010 Satoshi Nakamoto | // Copyright (c) 2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <base58.h> | #include <base58.h> | ||||
#include <chain.h> | #include <chain.h> | ||||
#include <clientversion.h> | #include <clientversion.h> | ||||
#include <config.h> | #include <config.h> | ||||
#include <dstencode.h> | #include <dstencode.h> | ||||
#include <init.h> | #include <init.h> | ||||
#include <net.h> | #include <net.h> | ||||
#include <netbase.h> | #include <netbase.h> | ||||
#include <rpc/blockchain.h> | #include <rpc/blockchain.h> | ||||
#include <rpc/misc.h> | #include <rpc/misc.h> | ||||
#include <rpc/server.h> | #include <rpc/server.h> | ||||
#include <rpc/util.h> | |||||
#include <timedata.h> | #include <timedata.h> | ||||
#include <util.h> | #include <util.h> | ||||
#include <utilstrencodings.h> | #include <utilstrencodings.h> | ||||
#include <validation.h> | #include <validation.h> | ||||
#ifdef ENABLE_WALLET | #ifdef ENABLE_WALLET | ||||
#include <wallet/rpcwallet.h> | #include <wallet/rpcwallet.h> | ||||
#include <wallet/wallet.h> | #include <wallet/wallet.h> | ||||
#include <wallet/walletdb.h> | #include <wallet/walletdb.h> | ||||
▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around | // Needed even with !ENABLE_WALLET, to pass (ignored) pointers around | ||||
class CWallet; | class CWallet; | ||||
/** | |||||
* Used by addmultisigaddress / createmultisig: | |||||
*/ | |||||
CScript createmultisig_redeemScript(CWallet *const pwallet, | |||||
const UniValue ¶ms) { | |||||
int nRequired = params[0].get_int(); | |||||
const UniValue &keys = params[1].get_array(); | |||||
// Gather public keys | |||||
if (nRequired < 1) { | |||||
throw std::runtime_error( | |||||
"a multisignature address must require at least one key to redeem"); | |||||
} | |||||
if ((int)keys.size() < nRequired) { | |||||
throw std::runtime_error( | |||||
strprintf("not enough keys supplied " | |||||
"(got %u keys, but need at least %d to redeem)", | |||||
keys.size(), nRequired)); | |||||
} | |||||
if (keys.size() > 16) { | |||||
throw std::runtime_error( | |||||
"Number of addresses involved in the " | |||||
"multisignature address creation > 16\nReduce the " | |||||
"number"); | |||||
} | |||||
std::vector<CPubKey> pubkeys; | |||||
pubkeys.resize(keys.size()); | |||||
for (size_t i = 0; i < keys.size(); i++) { | |||||
const std::string &ks = keys[i].get_str(); | |||||
#ifdef ENABLE_WALLET | |||||
// Case 1: Bitcoin address and we have full public key: | |||||
if (pwallet) { | |||||
CTxDestination dest = DecodeDestination(ks, pwallet->chainParams); | |||||
if (IsValidDestination(dest)) { | |||||
const CKeyID *keyID = boost::get<CKeyID>(&dest); | |||||
if (!keyID) { | |||||
throw std::runtime_error( | |||||
strprintf("%s does not refer to a key", ks)); | |||||
} | |||||
CPubKey vchPubKey; | |||||
if (!pwallet->GetPubKey(*keyID, vchPubKey)) { | |||||
throw std::runtime_error( | |||||
strprintf("no full public key for address %s", ks)); | |||||
} | |||||
if (!vchPubKey.IsFullyValid()) { | |||||
throw std::runtime_error(" Invalid public key: " + ks); | |||||
} | |||||
pubkeys[i] = vchPubKey; | |||||
continue; | |||||
} | |||||
} | |||||
#endif | |||||
// Case 2: hex public key | |||||
if (IsHex(ks)) { | |||||
CPubKey vchPubKey(ParseHex(ks)); | |||||
if (!vchPubKey.IsFullyValid()) { | |||||
throw std::runtime_error(" Invalid public key: " + ks); | |||||
} | |||||
pubkeys[i] = vchPubKey; | |||||
} else { | |||||
throw std::runtime_error(" Invalid public key: " + ks); | |||||
} | |||||
} | |||||
CScript result = GetScriptForMultisig(nRequired, pubkeys); | |||||
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) { | |||||
throw std::runtime_error( | |||||
strprintf("redeemScript exceeds size limit: %d > %d", result.size(), | |||||
MAX_SCRIPT_ELEMENT_SIZE)); | |||||
} | |||||
return result; | |||||
} | |||||
static UniValue createmultisig(const Config &config, | static UniValue createmultisig(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
#ifdef ENABLE_WALLET | |||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | |||||
#else | |||||
CWallet *const pwallet = nullptr; | |||||
#endif | |||||
if (request.fHelp || request.params.size() < 2 || | if (request.fHelp || request.params.size() < 2 || | ||||
request.params.size() > 2) { | request.params.size() > 2) { | ||||
std::string msg = | std::string msg = | ||||
"createmultisig nrequired [\"key\",...]\n" | "createmultisig nrequired [\"key\",...]\n" | ||||
"\nCreates a multi-signature address with n signature of m keys " | "\nCreates a multi-signature address with n signature of m keys " | ||||
"required.\n" | "required.\n" | ||||
"It returns a json object with the address and redeemScript.\n" | "It returns a json object with the address and redeemScript.\n" | ||||
"DEPRECATION WARNING: Using addresses with createmultisig is " | |||||
"deprecated. Clients must\n" | |||||
"transition to using addmultisigaddress to create multisig " | |||||
"addresses with addresses known\n" | |||||
"to the wallet before upgrading to v0.20. To use the deprecated " | |||||
"functionality, start bitcoind with -deprecatedrpc=createmultisig\n" | |||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. nrequired (numeric, required) The number of required " | "1. nrequired (numeric, required) The number of required " | ||||
"signatures out of the n keys or addresses.\n" | "signatures out of the n keys or addresses.\n" | ||||
"2. \"keys\" (string, required) A json array of keys which " | "2. \"keys\" (string, required) A json array of hex-encoded " | ||||
"are bitcoin addresses or hex-encoded public keys\n" | "public keys\n" | ||||
" [\n" | " [\n" | ||||
" \"key\" (string) bitcoin address or hex-encoded public " | " \"key\" (string) The hex-encoded public key\n" | ||||
"key\n" | |||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"{\n" | "{\n" | ||||
" \"address\":\"multisigaddress\", (string) The value of the new " | " \"address\":\"multisigaddress\", (string) The value of the new " | ||||
"multisig address.\n" | "multisig address.\n" | ||||
" \"redeemScript\":\"script\" (string) The string value of " | " \"redeemScript\":\"script\" (string) The string value of " | ||||
"the hex-encoded redemption script.\n" | "the hex-encoded redemption script.\n" | ||||
"}\n" | "}\n" | ||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nCreate a multisig address from 2 addresses\n" + | "\nCreate a multisig address from 2 public keys\n" + | ||||
HelpExampleCli("createmultisig", | HelpExampleCli("createmultisig", | ||||
"2 " | "2 " | ||||
"\"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\"," | "\"[" | ||||
"\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + | "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" | ||||
"42cf11ae157a7ace5fd\\\"," | |||||
"\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" | |||||
"7e107ef3f6aa5a61626\\\"]\"") + | |||||
"\nAs a json rpc call\n" + | "\nAs a json rpc call\n" + | ||||
HelpExampleRpc("createmultisig", | HelpExampleRpc("createmultisig", | ||||
"2, " | "2, " | ||||
"\"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\"," | "\"[" | ||||
"\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\""); | "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" | ||||
"42cf11ae157a7ace5fd\\\"," | |||||
"\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" | |||||
"7e107ef3f6aa5a61626\\\"]\""); | |||||
throw std::runtime_error(msg); | throw std::runtime_error(msg); | ||||
} | } | ||||
int required = request.params[0].get_int(); | |||||
// Get the public keys | |||||
const UniValue &keys = request.params[1].get_array(); | |||||
std::vector<CPubKey> pubkeys; | |||||
for (size_t i = 0; i < keys.size(); ++i) { | |||||
if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 || | |||||
keys[i].get_str().length() == 130)) { | |||||
pubkeys.push_back(HexToPubKey(keys[i].get_str())); | |||||
} else { | |||||
#ifdef ENABLE_WALLET | |||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | |||||
if (IsDeprecatedRPCEnabled(gArgs, "createmultisig") && | |||||
EnsureWalletIsAvailable(pwallet, false)) { | |||||
pubkeys.push_back(AddrToPubKey(config.GetChainParams(), pwallet, | |||||
keys[i].get_str())); | |||||
} else | |||||
#endif | |||||
throw JSONRPCError( | |||||
RPC_INVALID_ADDRESS_OR_KEY, | |||||
strprintf("Invalid public key: %s\nNote that from v0.19.6, " | |||||
"createmultisig no longer accepts addresses." | |||||
" Clients must transition to using " | |||||
"addmultisigaddress to create multisig addresses " | |||||
"with addresses known to the wallet before " | |||||
"upgrading to v0.20." | |||||
" To use the deprecated functionality, start " | |||||
"bitcoind with -deprecatedrpc=createmultisig", | |||||
keys[i].get_str())); | |||||
} | |||||
} | |||||
// Construct using pay-to-script-hash: | // Construct using pay-to-script-hash: | ||||
CScript inner = createmultisig_redeemScript(pwallet, request.params); | CScript inner = CreateMultisigRedeemscript(required, pubkeys); | ||||
CScriptID innerID(inner); | CScriptID innerID(inner); | ||||
UniValue result(UniValue::VOBJ); | UniValue result(UniValue::VOBJ); | ||||
result.pushKV("address", EncodeDestination(innerID)); | result.pushKV("address", EncodeDestination(innerID)); | ||||
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); | result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); | ||||
return result; | return result; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 279 Lines • Show Last 20 Lines |