Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/rawtransaction.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 "rpc/rawtransaction.h" | |||||
#include "base58.h" | #include "base58.h" | ||||
#include "chain.h" | #include "chain.h" | ||||
#include "coins.h" | #include "coins.h" | ||||
#include "config.h" | #include "config.h" | ||||
#include "consensus/validation.h" | #include "consensus/validation.h" | ||||
#include "core_io.h" | #include "core_io.h" | ||||
#include "dstencode.h" | #include "dstencode.h" | ||||
#include "init.h" | #include "init.h" | ||||
#include "keystore.h" | #include "keystore.h" | ||||
#include "merkleblock.h" | #include "merkleblock.h" | ||||
#include "net.h" | #include "net.h" | ||||
#include "policy/policy.h" | #include "policy/policy.h" | ||||
#include "primitives/transaction.h" | #include "primitives/transaction.h" | ||||
#include "rpc/safemode.h" | #include "rpc/safemode.h" | ||||
#include "rpc/server.h" | #include "rpc/server.h" | ||||
#include "rpc/tojson.h" | #include "rpc/tojson.h" | ||||
#include "script/script.h" | #include "script/script.h" | ||||
#include "script/script_error.h" | #include "script/script_error.h" | ||||
#include "script/sign.h" | #include "script/sign.h" | ||||
#include "script/standard.h" | #include "script/standard.h" | ||||
#include "txmempool.h" | #include "txmempool.h" | ||||
#include "uint256.h" | #include "uint256.h" | ||||
#include "util.h" | |||||
deadalnix: Remove | |||||
#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" | |||||
#endif | #endif | ||||
#include <cstdint> | #include <cstdint> | ||||
#include <univalue.h> | #include <univalue.h> | ||||
void ScriptPubKeyToJSON(const Config &config, const CScript &scriptPubKey, | void ScriptPubKeyToJSON(const Config &config, const CScript &scriptPubKey, | ||||
UniValue &out, bool fIncludeHex) { | UniValue &out, bool fIncludeHex) { | ||||
▲ Show 20 Lines • Show All 676 Lines • ▼ Show 20 Lines | static void TxInErrorToJSON(const CTxIn &txin, UniValue &vErrorsRet, | ||||
entry.pushKV("vout", uint64_t(txin.prevout.GetN())); | entry.pushKV("vout", uint64_t(txin.prevout.GetN())); | ||||
entry.pushKV("scriptSig", | entry.pushKV("scriptSig", | ||||
HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); | HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); | ||||
entry.pushKV("sequence", uint64_t(txin.nSequence)); | entry.pushKV("sequence", uint64_t(txin.nSequence)); | ||||
entry.pushKV("error", strMessage); | entry.pushKV("error", strMessage); | ||||
vErrorsRet.push_back(entry); | vErrorsRet.push_back(entry); | ||||
} | } | ||||
UniValue combinerawtransaction(const Config &config, | static UniValue combinerawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | if (request.fHelp || request.params.size() != 1) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"combinerawtransaction [\"hexstring\",...]\n" | "combinerawtransaction [\"hexstring\",...]\n" | ||||
"\nCombine multiple partially signed transactions into one " | "\nCombine multiple partially signed transactions into one " | ||||
"transaction.\n" | "transaction.\n" | ||||
"The combined transaction may be another partially signed " | "The combined transaction may be another partially signed " | ||||
"transaction or a \n" | "transaction or a \n" | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < mergedTx.vin.size(); i++) { | ||||
} | } | ||||
UpdateTransaction(mergedTx, i, sigdata); | UpdateTransaction(mergedTx, i, sigdata); | ||||
} | } | ||||
return EncodeHexTx(CTransaction(mergedTx)); | return EncodeHexTx(CTransaction(mergedTx)); | ||||
} | } | ||||
static UniValue signrawtransaction(const Config &config, | UniValue SignTransaction(CMutableTransaction &mtx, | ||||
const JSONRPCRequest &request) { | const UniValue &prevTxsUnival, | ||||
#ifdef ENABLE_WALLET | CBasicKeyStore *keystore, bool is_temp_keystore, | ||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | const UniValue &hashType) { | ||||
#endif | |||||
if (request.fHelp || request.params.size() < 1 || | |||||
request.params.size() > 4) { | |||||
throw std::runtime_error( | |||||
"signrawtransaction \"hexstring\" ( " | |||||
"[{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\"," | |||||
"\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype " | |||||
")\n" | |||||
"\nSign inputs for raw transaction (serialized, hex-encoded).\n" | |||||
"The second optional argument (may be null) is an array of " | |||||
"previous transaction outputs that\n" | |||||
"this transaction depends on but may not yet be in the block " | |||||
"chain.\n" | |||||
"The third optional argument (may be null) is an array of " | |||||
"base58-encoded private\n" | |||||
"keys that, if given, will be the only keys used to sign the " | |||||
"transaction.\n" | |||||
#ifdef ENABLE_WALLET | |||||
+ HelpRequiringPassphrase(pwallet) + | |||||
"\n" | |||||
#endif | |||||
"\nArguments:\n" | |||||
"1. \"hexstring\" (string, required) The transaction hex " | |||||
"string\n" | |||||
"2. \"prevtxs\" (string, optional) An json array of previous " | |||||
"dependent transaction outputs\n" | |||||
" [ (json array of json objects, or 'null' if " | |||||
"none provided)\n" | |||||
" {\n" | |||||
" \"txid\":\"id\", (string, required) The " | |||||
"transaction id\n" | |||||
" \"vout\":n, (numeric, required) The " | |||||
"output number\n" | |||||
" \"scriptPubKey\": \"hex\", (string, required) script " | |||||
"key\n" | |||||
" \"redeemScript\": \"hex\", (string, required for P2SH " | |||||
"or P2WSH) redeem script\n" | |||||
" \"amount\": value (numeric, required) The " | |||||
"amount spent\n" | |||||
" }\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"3. \"privkeys\" (string, optional) A json array of " | |||||
"base58-encoded private keys for signing\n" | |||||
" [ (json array of strings, or 'null' if none " | |||||
"provided)\n" | |||||
" \"privatekey\" (string) private key in base58-encoding\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"4. \"sighashtype\" (string, optional, default=ALL) The " | |||||
"signature hash type. Must be one of\n" | |||||
" \"ALL\"\n" | |||||
" \"NONE\"\n" | |||||
" \"SINGLE\"\n" | |||||
" \"ALL|ANYONECANPAY\"\n" | |||||
" \"NONE|ANYONECANPAY\"\n" | |||||
" \"SINGLE|ANYONECANPAY\"\n" | |||||
" \"ALL|FORKID\"\n" | |||||
" \"NONE|FORKID\"\n" | |||||
" \"SINGLE|FORKID\"\n" | |||||
" \"ALL|FORKID|ANYONECANPAY\"\n" | |||||
" \"NONE|FORKID|ANYONECANPAY\"\n" | |||||
" \"SINGLE|FORKID|ANYONECANPAY\"\n" | |||||
"\nResult:\n" | |||||
"{\n" | |||||
" \"hex\" : \"value\", (string) The hex-encoded raw " | |||||
"transaction with signature(s)\n" | |||||
" \"complete\" : true|false, (boolean) If the transaction has a " | |||||
"complete set of signatures\n" | |||||
" \"errors\" : [ (json array of objects) Script " | |||||
"verification errors (if there are any)\n" | |||||
" {\n" | |||||
" \"txid\" : \"hash\", (string) The hash of the " | |||||
"referenced, previous transaction\n" | |||||
" \"vout\" : n, (numeric) The index of the " | |||||
"output to spent and used as input\n" | |||||
" \"scriptSig\" : \"hex\", (string) The hex-encoded " | |||||
"signature script\n" | |||||
" \"sequence\" : n, (numeric) Script sequence " | |||||
"number\n" | |||||
" \"error\" : \"text\" (string) Verification or " | |||||
"signing error related to the input\n" | |||||
" }\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"}\n" | |||||
"\nExamples:\n" + | |||||
HelpExampleCli("signrawtransaction", "\"myhex\"") + | |||||
HelpExampleRpc("signrawtransaction", "\"myhex\"")); | |||||
} | |||||
ObserveSafeMode(); | |||||
#ifdef ENABLE_WALLET | |||||
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); | |||||
#else | |||||
LOCK(cs_main); | |||||
#endif | |||||
RPCTypeCheck( | |||||
request.params, | |||||
{UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); | |||||
CMutableTransaction mtx; | |||||
if (!DecodeHexTx(mtx, request.params[0].get_str())) { | |||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); | |||||
} | |||||
// Fetch previous transactions (inputs): | // Fetch previous transactions (inputs): | ||||
CCoinsView viewDummy; | CCoinsView viewDummy; | ||||
CCoinsViewCache view(&viewDummy); | CCoinsViewCache view(&viewDummy); | ||||
{ | { | ||||
LOCK(g_mempool.cs); | LOCK2(cs_main, g_mempool.cs); | ||||
CCoinsViewCache &viewChain = *pcoinsTip; | CCoinsViewCache &viewChain = *pcoinsTip; | ||||
CCoinsViewMemPool viewMempool(&viewChain, g_mempool); | CCoinsViewMemPool viewMempool(&viewChain, g_mempool); | ||||
// Temporarily switch cache backend to db+mempool view. | // Temporarily switch cache backend to db+mempool view. | ||||
view.SetBackend(viewMempool); | view.SetBackend(viewMempool); | ||||
for (const CTxIn &txin : mtx.vin) { | for (const CTxIn &txin : mtx.vin) { | ||||
// Load entries from viewChain into view; can fail. | // Load entries from viewChain into view; can fail. | ||||
view.AccessCoin(txin.prevout); | view.AccessCoin(txin.prevout); | ||||
} | } | ||||
// Switch back to avoid locking mempool for too long. | // Switch back to avoid locking mempool for too long. | ||||
view.SetBackend(viewDummy); | view.SetBackend(viewDummy); | ||||
} | } | ||||
bool fGivenKeys = false; | |||||
CBasicKeyStore tempKeystore; | |||||
if (request.params.size() > 2 && !request.params[2].isNull()) { | |||||
fGivenKeys = true; | |||||
UniValue keys = request.params[2].get_array(); | |||||
for (size_t idx = 0; idx < keys.size(); idx++) { | |||||
UniValue k = keys[idx]; | |||||
CBitcoinSecret vchSecret; | |||||
bool fGood = vchSecret.SetString(k.get_str()); | |||||
if (!fGood) { | |||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | |||||
"Invalid private key"); | |||||
} | |||||
CKey key = vchSecret.GetKey(); | |||||
if (!key.IsValid()) { | |||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | |||||
"Private key outside allowed range"); | |||||
} | |||||
tempKeystore.AddKey(key); | |||||
} | |||||
} | |||||
#ifdef ENABLE_WALLET | |||||
else if (pwallet) { | |||||
EnsureWalletIsUnlocked(pwallet); | |||||
} | |||||
#endif | |||||
// Add previous txouts given in the RPC call: | // Add previous txouts given in the RPC call: | ||||
if (request.params.size() > 1 && !request.params[1].isNull()) { | if (!prevTxsUnival.isNull()) { | ||||
UniValue prevTxs = request.params[1].get_array(); | UniValue prevTxs = prevTxsUnival.get_array(); | ||||
for (size_t idx = 0; idx < prevTxs.size(); idx++) { | for (size_t idx = 0; idx < prevTxs.size(); ++idx) { | ||||
const UniValue &p = prevTxs[idx]; | const UniValue &p = prevTxs[idx]; | ||||
if (!p.isObject()) { | if (!p.isObject()) { | ||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | ||||
"expected object with " | "expected object with " | ||||
"{\"txid'\",\"vout\",\"scriptPubKey\"}"); | "{\"txid'\",\"vout\",\"scriptPubKey\"}"); | ||||
} | } | ||||
UniValue prevOut = p.get_obj(); | UniValue prevOut = p.get_obj(); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (!prevTxsUnival.isNull()) { | ||||
// eg getbalance returns "3.14152" rather than 3.14152 | // eg getbalance returns "3.14152" rather than 3.14152 | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount"); | throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount"); | ||||
} | } | ||||
view.AddCoin(out, Coin(txout, 1, false), true); | view.AddCoin(out, Coin(txout, 1, false), true); | ||||
} | } | ||||
// If redeemScript given and not using the local wallet (private | // If redeemScript given and not using the local wallet (private | ||||
// keys given), add redeemScript to the tempKeystore so it can be | // keys given), add redeemScript to the keystore so it can be | ||||
// signed: | // signed: | ||||
if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { | if (is_temp_keystore && (scriptPubKey.IsPayToScriptHash())) { | ||||
RPCTypeCheckObj( | RPCTypeCheckObj( | ||||
prevOut, | prevOut, | ||||
{ | { | ||||
{"txid", UniValueType(UniValue::VSTR)}, | {"txid", UniValueType(UniValue::VSTR)}, | ||||
{"vout", UniValueType(UniValue::VNUM)}, | {"vout", UniValueType(UniValue::VNUM)}, | ||||
{"scriptPubKey", UniValueType(UniValue::VSTR)}, | {"scriptPubKey", UniValueType(UniValue::VSTR)}, | ||||
{"redeemScript", UniValueType(UniValue::VSTR)}, | {"redeemScript", UniValueType(UniValue::VSTR)}, | ||||
}); | }); | ||||
UniValue v = find_value(prevOut, "redeemScript"); | UniValue v = find_value(prevOut, "redeemScript"); | ||||
if (!v.isNull()) { | if (!v.isNull()) { | ||||
std::vector<uint8_t> rsData(ParseHexV(v, "redeemScript")); | std::vector<uint8_t> rsData(ParseHexV(v, "redeemScript")); | ||||
CScript redeemScript(rsData.begin(), rsData.end()); | CScript redeemScript(rsData.begin(), rsData.end()); | ||||
tempKeystore.AddCScript(redeemScript); | keystore->AddCScript(redeemScript); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#ifdef ENABLE_WALLET | |||||
const CKeyStore &keystore = | |||||
((fGivenKeys || !pwallet) ? tempKeystore : *pwallet); | |||||
#else | |||||
const CKeyStore &keystore = tempKeystore; | |||||
#endif | |||||
SigHashType sigHashType = SigHashType().withForkId(); | SigHashType sigHashType = SigHashType().withForkId(); | ||||
if (request.params.size() > 3 && !request.params[3].isNull()) { | if (!hashType.isNull()) { | ||||
static std::map<std::string, int> mapSigHashValues = { | static std::map<std::string, int> mapSigHashValues = { | ||||
{"ALL", SIGHASH_ALL}, | {"ALL", SIGHASH_ALL}, | ||||
{"ALL|ANYONECANPAY", SIGHASH_ALL | SIGHASH_ANYONECANPAY}, | {"ALL|ANYONECANPAY", SIGHASH_ALL | SIGHASH_ANYONECANPAY}, | ||||
{"ALL|FORKID", SIGHASH_ALL | SIGHASH_FORKID}, | {"ALL|FORKID", SIGHASH_ALL | SIGHASH_FORKID}, | ||||
{"ALL|FORKID|ANYONECANPAY", | {"ALL|FORKID|ANYONECANPAY", | ||||
SIGHASH_ALL | SIGHASH_FORKID | SIGHASH_ANYONECANPAY}, | SIGHASH_ALL | SIGHASH_FORKID | SIGHASH_ANYONECANPAY}, | ||||
{"NONE", SIGHASH_NONE}, | {"NONE", SIGHASH_NONE}, | ||||
{"NONE|ANYONECANPAY", SIGHASH_NONE | SIGHASH_ANYONECANPAY}, | {"NONE|ANYONECANPAY", SIGHASH_NONE | SIGHASH_ANYONECANPAY}, | ||||
{"NONE|FORKID", SIGHASH_NONE | SIGHASH_FORKID}, | {"NONE|FORKID", SIGHASH_NONE | SIGHASH_FORKID}, | ||||
{"NONE|FORKID|ANYONECANPAY", | {"NONE|FORKID|ANYONECANPAY", | ||||
SIGHASH_NONE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY}, | SIGHASH_NONE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY}, | ||||
{"SINGLE", SIGHASH_SINGLE}, | {"SINGLE", SIGHASH_SINGLE}, | ||||
{"SINGLE|ANYONECANPAY", SIGHASH_SINGLE | SIGHASH_ANYONECANPAY}, | {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE | SIGHASH_ANYONECANPAY}, | ||||
{"SINGLE|FORKID", SIGHASH_SINGLE | SIGHASH_FORKID}, | {"SINGLE|FORKID", SIGHASH_SINGLE | SIGHASH_FORKID}, | ||||
{"SINGLE|FORKID|ANYONECANPAY", | {"SINGLE|FORKID|ANYONECANPAY", | ||||
SIGHASH_SINGLE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY}, | SIGHASH_SINGLE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY}, | ||||
}; | }; | ||||
std::string strHashType = request.params[3].get_str(); | std::string strHashType = hashType.get_str(); | ||||
if (!mapSigHashValues.count(strHashType)) { | if (!mapSigHashValues.count(strHashType)) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); | ||||
} | } | ||||
sigHashType = SigHashType(mapSigHashValues[strHashType]); | sigHashType = SigHashType(mapSigHashValues[strHashType]); | ||||
if (!sigHashType.hasForkId()) { | if (!sigHashType.hasForkId()) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Signature must use SIGHASH_FORKID"); | "Signature must use SIGHASH_FORKID"); | ||||
Show All 11 Lines | for (size_t i = 0; i < mtx.vin.size(); i++) { | ||||
CTxIn &txin = mtx.vin[i]; | CTxIn &txin = mtx.vin[i]; | ||||
const Coin &coin = view.AccessCoin(txin.prevout); | const Coin &coin = view.AccessCoin(txin.prevout); | ||||
if (coin.IsSpent()) { | if (coin.IsSpent()) { | ||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); | TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); | ||||
continue; | continue; | ||||
} | } | ||||
const CScript &prevPubKey = coin.GetTxOut().scriptPubKey; | const CScript &prevPubKey = coin.GetTxOut().scriptPubKey; | ||||
const Amount amount = coin.GetTxOut().nValue; | const Amount &amount = coin.GetTxOut().nValue; | ||||
deadalnixUnsubmitted Not Done Inline Actionsremove deadalnix: remove | |||||
SignatureData sigdata; | SignatureData sigdata; | ||||
// Only sign SIGHASH_SINGLE if there's a corresponding output: | // Only sign SIGHASH_SINGLE if there's a corresponding output: | ||||
if ((sigHashType.getBaseType() != BaseSigHashType::SINGLE) || | if ((sigHashType.getBaseType() != BaseSigHashType::SINGLE) || | ||||
(i < mtx.vout.size())) { | (i < mtx.vout.size())) { | ||||
ProduceSignature(MutableTransactionSignatureCreator( | ProduceSignature(MutableTransactionSignatureCreator( | ||||
&keystore, &mtx, i, amount, sigHashType), | keystore, &mtx, i, amount, sigHashType), | ||||
prevPubKey, sigdata); | prevPubKey, sigdata); | ||||
} | } | ||||
sigdata = CombineSignatures( | sigdata = CombineSignatures( | ||||
prevPubKey, TransactionSignatureChecker(&txConst, i, amount), | prevPubKey, TransactionSignatureChecker(&txConst, i, amount), | ||||
sigdata, DataFromTransaction(mtx, i)); | sigdata, DataFromTransaction(mtx, i)); | ||||
UpdateTransaction(mtx, i, sigdata); | UpdateTransaction(mtx, i, sigdata); | ||||
ScriptError serror = SCRIPT_ERR_OK; | ScriptError serror = SCRIPT_ERR_OK; | ||||
if (!VerifyScript( | if (!VerifyScript( | ||||
txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, | txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, | ||||
TransactionSignatureChecker(&txConst, i, amount), &serror)) { | TransactionSignatureChecker(&txConst, i, amount), &serror)) { | ||||
if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) { | |||||
// Unable to sign input and verification failed (possible | |||||
// attempt to partially sign). | |||||
TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid " | |||||
"stack size (possibly missing " | |||||
"key)"); | |||||
} else { | |||||
deadalnixUnsubmitted Not Done Inline ActionsThis is not part of the original diff. Finding the origin of that code backporting it apropriately would be better than sticking it into this backport. deadalnix: This is not part of the original diff. Finding the origin of that code backporting it… | |||||
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); | TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); | ||||
} | } | ||||
} | } | ||||
} | |||||
bool fComplete = vErrors.empty(); | bool fComplete = vErrors.empty(); | ||||
UniValue result(UniValue::VOBJ); | UniValue result(UniValue::VOBJ); | ||||
result.pushKV("hex", EncodeHexTx(CTransaction(mtx))); | result.pushKV("hex", EncodeHexTx(CTransaction(mtx))); | ||||
result.pushKV("complete", fComplete); | result.pushKV("complete", fComplete); | ||||
if (!vErrors.empty()) { | if (!vErrors.empty()) { | ||||
result.pushKV("errors", vErrors); | result.pushKV("errors", vErrors); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
static UniValue signrawtransactionwithkey(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) | |||||
deadalnixUnsubmitted Not Done Inline Actionsbraces deadalnix: braces | |||||
throw std::runtime_error( | |||||
"signrawtransactionwithkey \"hexstring\" [\"privatekey1\",...] ( " | |||||
"[{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\"," | |||||
"\"redeemScript\":\"hex\"},...] sighashtype )\n" | |||||
"\nSign inputs for raw transaction (serialized, hex-encoded).\n" | |||||
"The second argument is an array of base58-encoded private\n" | |||||
"keys that will be the only keys used to sign the transaction.\n" | |||||
"The third optional argument (may be null) is an array of previous " | |||||
"transaction outputs that\n" | |||||
"this transaction depends on but may not yet be in the block " | |||||
"chain.\n" | |||||
"\nArguments:\n" | |||||
"1. \"hexstring\" (string, required) The " | |||||
"transaction hex string\n" | |||||
"2. \"privkeys\" (string, required) A json " | |||||
"array of base58-encoded private keys for signing\n" | |||||
" [ (json array of strings)\n" | |||||
" \"privatekey\" (string) private key in " | |||||
"base58-encoding\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"3. \"prevtxs\" (string, optional) An json " | |||||
"array of previous dependent transaction outputs\n" | |||||
" [ (json array of json objects, " | |||||
"or 'null' if none provided)\n" | |||||
" {\n" | |||||
" \"txid\":\"id\", (string, required) The " | |||||
"transaction id\n" | |||||
" \"vout\":n, (numeric, required) The " | |||||
"output number\n" | |||||
" \"scriptPubKey\": \"hex\", (string, required) script " | |||||
"key\n" | |||||
" \"redeemScript\": \"hex\", (string, required for " | |||||
"P2SH) redeem script\n" | |||||
" \"amount\": value (numeric, required) The " | |||||
"amount spent\n" | |||||
" }\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"4. \"sighashtype\" (string, optional, " | |||||
"default=ALL) The signature hash type. Must be one of\n" | |||||
" \"ALL\"\n" | |||||
" \"NONE\"\n" | |||||
" \"SINGLE\"\n" | |||||
" \"ALL|ANYONECANPAY\"\n" | |||||
" \"NONE|ANYONECANPAY\"\n" | |||||
" \"SINGLE|ANYONECANPAY\"\n" | |||||
" \"ALL|FORKID\"\n" | |||||
" \"NONE|FORKID\"\n" | |||||
" \"SINGLE|FORKID\"\n" | |||||
" \"ALL|FORKID|ANYONECANPAY\"\n" | |||||
" \"NONE|FORKID|ANYONECANPAY\"\n" | |||||
" \"SINGLE|FORKID|ANYONECANPAY\"\n" | |||||
"\nResult:\n" | |||||
"{\n" | |||||
" \"hex\" : \"value\", (string) The hex-encoded " | |||||
"raw transaction with signature(s)\n" | |||||
" \"complete\" : true|false, (boolean) If the " | |||||
"transaction has a complete set of signatures\n" | |||||
" \"errors\" : [ (json array of objects) " | |||||
"Script verification errors (if there are any)\n" | |||||
" {\n" | |||||
" \"txid\" : \"hash\", (string) The hash of the " | |||||
"referenced, previous transaction\n" | |||||
" \"vout\" : n, (numeric) The index of the " | |||||
"output to spent and used as input\n" | |||||
" \"scriptSig\" : \"hex\", (string) The hex-encoded " | |||||
"signature script\n" | |||||
" \"sequence\" : n, (numeric) Script sequence " | |||||
"number\n" | |||||
" \"error\" : \"text\" (string) Verification or " | |||||
"signing error related to the input\n" | |||||
" }\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"}\n" | |||||
"\nExamples:\n" + | |||||
HelpExampleCli("signrawtransactionwithkey", "\"myhex\"") + | |||||
HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"")); | |||||
RPCTypeCheck( | |||||
request.params, | |||||
{UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); | |||||
CMutableTransaction mtx; | |||||
if (!DecodeHexTx(mtx, request.params[0].get_str())) { | |||||
deadalnixUnsubmitted Not Done Inline ActionsThere is a parameter missing here. Why the difference ? deadalnix: There is a parameter missing here. Why the difference ? | |||||
FabienAuthorUnsubmitted Done Inline ActionsThis is a segwit related flag which tells whether witness data is serialized in the tx or not Fabien: This is a segwit related flag which tells whether witness data is serialized in the tx or not | |||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); | |||||
} | |||||
CBasicKeyStore keystore; | |||||
const UniValue &keys = request.params[1].get_array(); | |||||
for (size_t idx = 0; idx < keys.size(); ++idx) { | |||||
UniValue k = keys[idx]; | |||||
CBitcoinSecret vchSecret; | |||||
if (!vchSecret.SetString(k.get_str())) { | |||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | |||||
"Invalid private key"); | |||||
} | |||||
CKey key = vchSecret.GetKey(); | |||||
if (!key.IsValid()) { | |||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | |||||
"Private key outside allowed range"); | |||||
} | |||||
keystore.AddKey(key); | |||||
} | |||||
return SignTransaction(mtx, request.params[2], &keystore, true, | |||||
request.params[3]); | |||||
} | |||||
static UniValue signrawtransaction(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
#ifdef ENABLE_WALLET | |||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | |||||
#endif | |||||
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) | |||||
deadalnixUnsubmitted Not Done Inline Actionsbraces deadalnix: braces | |||||
throw std::runtime_error( | |||||
"signrawtransaction \"hexstring\" ( " | |||||
"[{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\"," | |||||
"\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype " | |||||
")\n" | |||||
"\nDEPRECATED. Sign inputs for raw transaction (serialized, " | |||||
"hex-encoded).\n" | |||||
"The second optional argument (may be null) is an array of " | |||||
"previous transaction outputs that\n" | |||||
"this transaction depends on but may not yet be in the block " | |||||
"chain.\n" | |||||
"The third optional argument (may be null) is an array of " | |||||
"base58-encoded private\n" | |||||
"keys that, if given, will be the only keys used to sign the " | |||||
"transaction.\n" | |||||
#ifdef ENABLE_WALLET | |||||
+ HelpRequiringPassphrase(pwallet) + | |||||
"\n" | |||||
#endif | |||||
"\nArguments:\n" | |||||
"1. \"hexstring\" (string, required) The transaction hex " | |||||
"string\n" | |||||
"2. \"prevtxs\" (string, optional) An json array of previous " | |||||
"dependent transaction outputs\n" | |||||
" [ (json array of json objects, or 'null' if " | |||||
"none provided)\n" | |||||
" {\n" | |||||
" \"txid\":\"id\", (string, required) The " | |||||
"transaction id\n" | |||||
" \"vout\":n, (numeric, required) The " | |||||
"output number\n" | |||||
" \"scriptPubKey\": \"hex\", (string, required) script " | |||||
"key\n" | |||||
" \"redeemScript\": \"hex\", (string, required for P2SH) " | |||||
"redeem script\n" | |||||
" \"amount\": value (numeric, required) The " | |||||
"amount spent\n" | |||||
" }\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"3. \"privkeys\" (string, optional) A json array of " | |||||
"base58-encoded private keys for signing\n" | |||||
" [ (json array of strings, or 'null' if none " | |||||
"provided)\n" | |||||
" \"privatekey\" (string) private key in base58-encoding\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"4. \"sighashtype\" (string, optional, default=ALL) The " | |||||
"signature hash type. Must be one of\n" | |||||
" \"ALL\"\n" | |||||
" \"NONE\"\n" | |||||
" \"SINGLE\"\n" | |||||
" \"ALL|ANYONECANPAY\"\n" | |||||
" \"NONE|ANYONECANPAY\"\n" | |||||
" \"SINGLE|ANYONECANPAY\"\n" | |||||
" \"ALL|FORKID\"\n" | |||||
" \"NONE|FORKID\"\n" | |||||
" \"SINGLE|FORKID\"\n" | |||||
" \"ALL|FORKID|ANYONECANPAY\"\n" | |||||
" \"NONE|FORKID|ANYONECANPAY\"\n" | |||||
" \"SINGLE|FORKID|ANYONECANPAY\"\n" | |||||
"\nResult:\n" | |||||
"{\n" | |||||
" \"hex\" : \"value\", (string) The hex-encoded raw " | |||||
"transaction with signature(s)\n" | |||||
" \"complete\" : true|false, (boolean) If the transaction has a " | |||||
"complete set of signatures\n" | |||||
" \"errors\" : [ (json array of objects) Script " | |||||
"verification errors (if there are any)\n" | |||||
" {\n" | |||||
" \"txid\" : \"hash\", (string) The hash of the " | |||||
"referenced, previous transaction\n" | |||||
" \"vout\" : n, (numeric) The index of the " | |||||
"output to spent and used as input\n" | |||||
" \"scriptSig\" : \"hex\", (string) The hex-encoded " | |||||
"signature script\n" | |||||
" \"sequence\" : n, (numeric) Script sequence " | |||||
"number\n" | |||||
" \"error\" : \"text\" (string) Verification or " | |||||
"signing error related to the input\n" | |||||
" }\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"}\n" | |||||
"\nExamples:\n" + | |||||
HelpExampleCli("signrawtransaction", "\"myhex\"") + | |||||
HelpExampleRpc("signrawtransaction", "\"myhex\"")); | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "signrawtransaction")) { | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"signrawtransaction is deprecated and will be fully removed in " | |||||
"v0.19. " | |||||
deadalnixUnsubmitted Not Done Inline ActionsIs that on our roadmap ? deadalnix: Is that on our roadmap ? | |||||
"To use signrawtransaction in v0.18, restart bitcoind with " | |||||
"-deprecatedrpc=signrawtransaction.\n" | |||||
"Projects should transition to using signrawtransactionwithkey and " | |||||
"signrawtransactionwithwallet before upgrading to v0.19"); | |||||
} | |||||
RPCTypeCheck( | |||||
request.params, | |||||
{UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); | |||||
// Make a JSONRPCRequest to pass on to the right signrawtransaction* command | |||||
JSONRPCRequest new_request; | |||||
new_request.id = request.id; | |||||
new_request.params.setArray(); | |||||
// For signing with private keys | |||||
if (!request.params[2].isNull()) { | |||||
new_request.params.push_back(request.params[0]); | |||||
// Note: the prevtxs and privkeys are reversed for | |||||
// signrawtransactionwithkey | |||||
new_request.params.push_back(request.params[2]); | |||||
new_request.params.push_back(request.params[1]); | |||||
new_request.params.push_back(request.params[3]); | |||||
return signrawtransactionwithkey(config, new_request); | |||||
} | |||||
// Otherwise sign with the wallet which does not take a privkeys parameter | |||||
#ifdef ENABLE_WALLET | |||||
else { | |||||
new_request.params.push_back(request.params[0]); | |||||
new_request.params.push_back(request.params[1]); | |||||
new_request.params.push_back(request.params[3]); | |||||
return signrawtransactionwithwallet(config, new_request); | |||||
} | |||||
#endif | |||||
// If we have made it this far, then wallet is disabled and no private keys | |||||
// were given, so fail here. | |||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "No private keys available."); | |||||
} | |||||
static UniValue sendrawtransaction(const Config &config, | static UniValue sendrawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 1 || | if (request.fHelp || request.params.size() < 1 || | ||||
request.params.size() > 2) { | request.params.size() > 2) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"sendrawtransaction \"hexstring\" ( allowhighfees )\n" | "sendrawtransaction \"hexstring\" ( allowhighfees )\n" | ||||
"\nSubmits raw transaction (serialized, hex-encoded) to local node " | "\nSubmits raw transaction (serialized, hex-encoded) to local node " | ||||
"and network.\n" | "and network.\n" | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | static UniValue sendrawtransaction(const Config &config, | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); | g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); | ||||
return txid.GetHex(); | return txid.GetHex(); | ||||
} | } | ||||
// clang-format off | // clang-format off | ||||
static const ContextFreeRPCCommand commands[] = { | static const ContextFreeRPCCommand commands[] = { | ||||
// category name actor (function) argNames | // category name actor (function) argNames | ||||
// ------------------- ------------------------ ---------------------- ---------- | // ------------------- ------------------------ ---------------------- ---------- | ||||
{ "rawtransactions", "getrawtransaction", getrawtransaction, {"txid","verbose"} }, | { "rawtransactions", "getrawtransaction", getrawtransaction, {"txid","verbose"} }, | ||||
{ "rawtransactions", "createrawtransaction", createrawtransaction, {"inputs","outputs","locktime"} }, | { "rawtransactions", "createrawtransaction", createrawtransaction, {"inputs","outputs","locktime"} }, | ||||
{ "rawtransactions", "decoderawtransaction", decoderawtransaction, {"hexstring"} }, | { "rawtransactions", "decoderawtransaction", decoderawtransaction, {"hexstring"} }, | ||||
{ "rawtransactions", "decodescript", decodescript, {"hexstring"} }, | { "rawtransactions", "decodescript", decodescript, {"hexstring"} }, | ||||
{ "rawtransactions", "sendrawtransaction", sendrawtransaction, {"hexstring","allowhighfees"} }, | { "rawtransactions", "sendrawtransaction", sendrawtransaction, {"hexstring","allowhighfees"} }, | ||||
{ "rawtransactions", "combinerawtransaction", combinerawtransaction, {"txs"} }, | { "rawtransactions", "combinerawtransaction", combinerawtransaction, {"txs"} }, | ||||
{ "rawtransactions", "signrawtransaction", signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ | { "rawtransactions", "signrawtransaction", signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ | ||||
{ "rawtransactions", "signrawtransactionwithkey", signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} }, | |||||
deadalnixUnsubmitted Not Done Inline ActionsCnsidering there are several spaces here, I fail to see why everythibg has to be shifted right by so many spaces. deadalnix: Cnsidering there are several spaces here, I fail to see why everythibg has to be shifted right… | |||||
{ "blockchain", "gettxoutproof", gettxoutproof, {"txids", "blockhash"} }, | { "blockchain", "gettxoutproof", gettxoutproof, {"txids", "blockhash"} }, | ||||
{ "blockchain", "verifytxoutproof", verifytxoutproof, {"proof"} }, | { "blockchain", "verifytxoutproof", verifytxoutproof, {"proof"} }, | ||||
}; | }; | ||||
// clang-format on | // clang-format on | ||||
void RegisterRawTransactionRPCCommands(CRPCTable &t) { | void RegisterRawTransactionRPCCommands(CRPCTable &t) { | ||||
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { | for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { | ||||
t.appendCommand(commands[vcidx].name, &commands[vcidx]); | t.appendCommand(commands[vcidx].name, &commands[vcidx]); | ||||
} | } | ||||
} | } |
Remove