diff options
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 414 |
1 files changed, 212 insertions, 202 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7ca097f8cf..41f3ac6b4a 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -9,10 +9,9 @@ #include <consensus/validation.h> #include <core_io.h> #include <index/txindex.h> -#include <keystore.h> -#include <validation.h> -#include <validationinterface.h> +#include <init.h> #include <key_io.h> +#include <keystore.h> #include <merkleblock.h> #include <net.h> #include <policy/policy.h> @@ -20,16 +19,16 @@ #include <primitives/transaction.h> #include <rpc/rawtransaction.h> #include <rpc/server.h> +#include <rpc/util.h> #include <script/script.h> #include <script/script_error.h> #include <script/sign.h> #include <script/standard.h> #include <txmempool.h> #include <uint256.h> -#include <utilstrencodings.h> -#ifdef ENABLE_WALLET -#include <wallet/rpcwallet.h> -#endif +#include <util/strencodings.h> +#include <validation.h> +#include <validationinterface.h> #include <future> #include <stdint.h> @@ -67,13 +66,18 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n" - - "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" - "enabled, it also works for blockchain transactions. If the block which contains the transaction\n" - "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n" - "provided, only that block will be searched and if the transaction is in the mempool or other\n" - "blocks, or if this node does not have the given block available, the transaction will not be found.\n" + RPCHelpMan{"getrawtransaction", + "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" + "enabled, it also works for blockchain transactions. If the block which contains the transaction\n" + "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n" + "provided, only that block will be searched and if the transaction is in the mempool or other\n" + "blocks, or if this node does not have the given block available, the transaction will not be found.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"verbose", RPCArg::Type::BOOL, true}, + {"blockhash", RPCArg::Type::STR_HEX, true}, + }} + .ToString() + "DEPRECATED: for now, it also works for transactions with unspent outputs.\n" "\nReturn the raw transaction data.\n" @@ -207,12 +211,21 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) { if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2)) throw std::runtime_error( - "gettxoutproof [\"txid\",...] ( blockhash )\n" - "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" - "\nNOTE: By default this function only works sometimes. This is when there is an\n" - "unspent output in the utxo for this transaction. To make it always work,\n" - "you need to maintain a transaction index, using the -txindex command line option or\n" - "specify the block in which the transaction is included manually (by blockhash).\n" + RPCHelpMan{"gettxoutproof", + "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" + "\nNOTE: By default this function only works sometimes. This is when there is an\n" + "unspent output in the utxo for this transaction. To make it always work,\n" + "you need to maintain a transaction index, using the -txindex command line option or\n" + "specify the block in which the transaction is included manually (by blockhash).\n", + { + {"txids", RPCArg::Type::ARR, + { + {"txid", RPCArg::Type::STR_HEX, false}, + }, + false}, + {"blockhash", RPCArg::Type::STR_HEX, true}, + }} + .ToString() + "\nArguments:\n" "1. \"txids\" (string) A json array of txids to filter\n" " [\n" @@ -229,9 +242,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) UniValue txids = request.params[0].get_array(); for (unsigned int idx = 0; idx < txids.size(); idx++) { const UniValue& txid = txids[idx]; - if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str()); - uint256 hash(uint256S(txid.get_str())); + uint256 hash(ParseHashV(txid, "txid")); if (setTxids.count(hash)) throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str()); setTxids.insert(hash); @@ -242,7 +253,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) uint256 hashBlock; if (!request.params[1].isNull()) { LOCK(cs_main); - hashBlock = uint256S(request.params[1].get_str()); + hashBlock = ParseHashV(request.params[1], "blockhash"); pblockindex = LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -301,9 +312,13 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "verifytxoutproof \"proof\"\n" - "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" - "and throwing an RPC error if the block is not in our best chain\n" + RPCHelpMan{"verifytxoutproof", + "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" + "and throwing an RPC error if the block is not in our best chain\n", + { + {"proof", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n" "\nResult:\n" @@ -351,7 +366,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal if (!locktime.isNull()) { int64_t nLockTime = locktime.get_int64(); - if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max()) + if (nLockTime < 0 || nLockTime > LOCKTIME_MAX) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range"); rawTx.nLockTime = nLockTime; } @@ -373,18 +388,18 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal uint32_t nSequence; if (rbfOptIn) { - nSequence = MAX_BIP125_RBF_SEQUENCE; + nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */ } else if (rawTx.nLockTime) { - nSequence = std::numeric_limits<uint32_t>::max() - 1; + nSequence = CTxIn::SEQUENCE_FINAL - 1; } else { - nSequence = std::numeric_limits<uint32_t>::max(); + nSequence = CTxIn::SEQUENCE_FINAL; } // set the sequence number if passed in the parameters object const UniValue& sequenceObj = find_value(o, "sequence"); if (sequenceObj.isNum()) { int64_t seqNr64 = sequenceObj.get_int64(); - if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max()) { + if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range"); } else { nSequence = (uint32_t)seqNr64; @@ -471,13 +486,13 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) " \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n" " },\n" " {\n" - " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n" + " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex-encoded data\n" " }\n" " ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" " accepted as second parameter.\n" " ]\n" "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" - "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n" + "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125-replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" @@ -508,9 +523,13 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "decoderawtransaction \"hexstring\" ( iswitness )\n" - "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" - + RPCHelpMan{"decoderawtransaction", + "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"iswitness", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The transaction hex string\n" "2. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction\n" @@ -583,14 +602,18 @@ static UniValue decodescript(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "decodescript \"hexstring\"\n" - "\nDecode a hex-encoded script.\n" + RPCHelpMan{"decodescript", + "\nDecode a hex-encoded script.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" - "1. \"hexstring\" (string) the hex encoded script\n" + "1. \"hexstring\" (string) the hex-encoded script\n" "\nResult:\n" "{\n" " \"asm\":\"asm\", (string) Script public key\n" - " \"hex\":\"hex\", (string) hex encoded public key\n" + " \"hex\":\"hex\", (string) hex-encoded public key\n" " \"type\":\"type\", (string) The output type\n" " \"reqSigs\": n, (numeric) The required signatures\n" " \"addresses\": [ (json array of string)\n" @@ -676,14 +699,20 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: static UniValue combinerawtransaction(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "combinerawtransaction [\"hexstring\",...]\n" - "\nCombine multiple partially signed transactions into one transaction.\n" - "The combined transaction may be another partially signed transaction or a \n" - "fully signed transaction." - + RPCHelpMan{"combinerawtransaction", + "\nCombine multiple partially signed transactions into one transaction.\n" + "The combined transaction may be another partially signed transaction or a \n" + "fully signed transaction.", + { + {"txs", RPCArg::Type::ARR, + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + }, + false}, + }} + .ToString() + "\nArguments:\n" "1. \"txs\" (string) A json array of hex strings of partially signed transactions\n" " [\n" @@ -759,7 +788,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) return EncodeHexTx(mergedTx); } -UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType) +UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType) { // Fetch previous transactions (inputs): CCoinsView viewDummy; @@ -824,8 +853,7 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival view.AddCoin(out, std::move(newcoin), true); } - // if redeemScript given and not using the local wallet (private keys - // given), add redeemScript to the keystore so it can be signed: + // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed if (is_temp_keystore && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash())) { RPCTypeCheckObj(prevOut, { @@ -903,13 +931,35 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) 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" - + RPCHelpMan{"signrawtransactionwithkey", + "\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", + { + {"hexstring", RPCArg::Type::STR, false}, + {"privkeys", RPCArg::Type::ARR, + { + {"privatekey", RPCArg::Type::STR_HEX, false}, + }, + false}, + {"prevtxs", RPCArg::Type::ARR, + { + {"", RPCArg::Type::OBJ, + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"vout", RPCArg::Type::NUM, false}, + {"scriptPubKey", RPCArg::Type::STR_HEX, false}, + {"redeemScript", RPCArg::Type::STR_HEX, false}, + {"amount", RPCArg::Type::AMOUNT, false}, + }, + true}, + }, + true}, + {"sighashtype", RPCArg::Type::STR, true}, + }} + .ToString() + "\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" @@ -928,7 +978,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) " }\n" " ,...\n" " ]\n" - "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n" + "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of:\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" @@ -975,116 +1025,29 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) keystore.AddKey(key); } - return SignTransaction(mtx, request.params[2], &keystore, true, request.params[3]); + return SignTransaction(*g_rpc_interfaces->chain, mtx, request.params[2], &keystore, true, request.params[3]); } UniValue signrawtransaction(const JSONRPCRequest& request) { -#ifdef ENABLE_WALLET - std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); -#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" - "\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 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" - - "\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("signrawtransaction")) { - throw JSONRPCError(RPC_METHOD_DEPRECATED, "signrawtransaction is deprecated and will be fully removed in v0.18. " - "To use signrawtransaction in v0.17, restart bitcoind with -deprecatedrpc=signrawtransaction.\n" - "Projects should transition to using signrawtransactionwithkey and signrawtransactionwithwallet before upgrading to v0.18"); - } - - 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(new_request); - } else { -#ifdef ENABLE_WALLET - // Otherwise sign with the wallet which does not take a privkeys parameter - 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(new_request); -#else - // 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."); -#endif - } + // This method should be removed entirely in V0.19, along with the entries in the + // CRPCCommand table and rpc/client.cpp. + throw JSONRPCError(RPC_METHOD_DEPRECATED, "signrawtransaction was removed in v0.18.\n" + "Clients should transition to using signrawtransactionwithkey and signrawtransactionwithwallet"); } static UniValue sendrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "sendrawtransaction \"hexstring\" ( allowhighfees )\n" - "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" - "\nAlso see createrawtransaction and signrawtransaction calls.\n" + RPCHelpMan{"sendrawtransaction", + "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" + "\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"allowhighfees", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" @@ -1094,10 +1057,10 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransaction", "\"myhex\"") + + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + - "\nAs a json rpc call\n" + "\nAs a JSON-RPC call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") ); @@ -1179,7 +1142,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) throw std::runtime_error( // clang-format off "testmempoolaccept [\"rawtxs\"] ( allowhighfees )\n" - "\nReturns if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" + "\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" "\nThis checks if the transaction violates the consensus or policy rules.\n" "\nSee sendrawtransaction call.\n" "\nArguments:\n" @@ -1199,10 +1162,10 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransaction", "\"myhex\"") + + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + "\nTest acceptance of the transaction (signed hex)\n" + HelpExampleCli("testmempoolaccept", "\"signedhex\"") + - "\nAs a json rpc call\n" + "\nAs a JSON-RPC call\n" + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") // clang-format on ); @@ -1275,9 +1238,12 @@ UniValue decodepsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "decodepsbt \"psbt\"\n" - "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n" - + RPCHelpMan{"decodepsbt", + "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n", + { + {"psbt", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"psbt\" (string, required) The PSBT base64 string\n" @@ -1458,11 +1424,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) UniValue keypath(UniValue::VOBJ); keypath.pushKV("pubkey", HexStr(entry.first)); - uint32_t fingerprint = entry.second.at(0); - keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint))); - - entry.second.erase(entry.second.begin()); - keypath.pushKV("path", WriteHDKeypath(entry.second)); + keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint))); + keypath.pushKV("path", WriteHDKeypath(entry.second.path)); keypaths.push_back(keypath); } in.pushKV("bip32_derivs", keypaths); @@ -1520,12 +1483,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) for (auto entry : output.hd_keypaths) { UniValue keypath(UniValue::VOBJ); keypath.pushKV("pubkey", HexStr(entry.first)); - - uint32_t fingerprint = entry.second.at(0); - keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint))); - - entry.second.erase(entry.second.begin()); - keypath.pushKV("path", WriteHDKeypath(entry.second)); + keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint))); + keypath.pushKV("path", WriteHDKeypath(entry.second.path)); keypaths.push_back(keypath); } out.pushKV("bip32_derivs", keypaths); @@ -1557,9 +1516,17 @@ UniValue combinepsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "combinepsbt [\"psbt\",...]\n" - "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n" - "Implements the Combiner role.\n" + RPCHelpMan{"combinepsbt", + "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n" + "Implements the Combiner role.\n", + { + {"txs", RPCArg::Type::ARR, + { + {"psbt", RPCArg::Type::STR_HEX, false}, + }, + false}, + }} + .ToString() + "\nArguments:\n" "1. \"txs\" (string) A json array of base64 strings of partially signed transactions\n" " [\n" @@ -1610,11 +1577,16 @@ UniValue finalizepsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "finalizepsbt \"psbt\" ( extract )\n" - "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" - "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" - "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" - "Implements the Finalizer and Extractor roles.\n" + RPCHelpMan{"finalizepsbt", + "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" + "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" + "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" + "Implements the Finalizer and Extractor roles.\n", + { + {"psbt", RPCArg::Type::STR, false}, + {"extract", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"psbt\" (string) A base64 string of a PSBT\n" "2. \"extract\" (boolean, optional, default=true) If true and the transaction is complete, \n" @@ -1641,13 +1613,13 @@ UniValue finalizepsbt(const JSONRPCRequest& request) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); } - // Get all of the previous transactions + // Finalize input signatures -- in case we have partial signatures that add up to a complete + // signature, but have not combined them yet (e.g. because the combiner that created this + // PartiallySignedTransaction did not understand them), this will combine them into a final + // script. bool complete = true; for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { - PSBTInput& input = psbtx.inputs.at(i); - - SignatureData sigdata; - complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, sigdata, i, 1); + complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SIGHASH_ALL); } UniValue result(UniValue::VOBJ); @@ -1660,10 +1632,10 @@ UniValue finalizepsbt(const JSONRPCRequest& request) mtx.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness; } ssTx << mtx; - result.pushKV("hex", HexStr(ssTx.begin(), ssTx.end())); + result.pushKV("hex", HexStr(ssTx.str())); } else { ssTx << psbtx; - result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size())); + result.pushKV("psbt", EncodeBase64(ssTx.str())); } result.pushKV("complete", complete); @@ -1674,9 +1646,39 @@ UniValue createpsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) throw std::runtime_error( - "createpsbt [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n" - "\nCreates a transaction in the Partially Signed Transaction format.\n" - "Implements the Creator role.\n" + RPCHelpMan{"createpsbt", + "\nCreates a transaction in the Partially Signed Transaction format.\n" + "Implements the Creator role.\n", + { + {"inputs", RPCArg::Type::ARR, + { + {"", RPCArg::Type::OBJ, + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"vout", RPCArg::Type::NUM, false}, + {"sequence", RPCArg::Type::NUM, true}, + }, + false}, + }, + false}, + {"outputs", RPCArg::Type::ARR, + { + {"", RPCArg::Type::OBJ, + { + {"address", RPCArg::Type::AMOUNT, false}, + }, + true}, + {"", RPCArg::Type::OBJ, + { + {"data", RPCArg::Type::STR_HEX, false}, + }, + true}, + }, + false}, + {"locktime", RPCArg::Type::NUM, true}, + {"replaceable", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"inputs\" (array, required) A json array of json objects\n" " [\n" @@ -1693,7 +1695,7 @@ UniValue createpsbt(const JSONRPCRequest& request) " \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n" " },\n" " {\n" - " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n" + " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex-encoded data\n" " }\n" " ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" " accepted as second parameter.\n" @@ -1739,16 +1741,22 @@ UniValue converttopsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "converttopsbt \"hexstring\" ( permitsigdata iswitness )\n" - "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" - "createpsbt and walletcreatefundedpsbt should be used for new applications.\n" + RPCHelpMan{"converttopsbt", + "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" + "createpsbt and walletcreatefundedpsbt should be used for new applications.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"permitsigdata", RPCArg::Type::BOOL, true}, + {"iswitness", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of a raw transaction\n" "2. permitsigdata (boolean, optional, default=false) If true, any signatures in the input will be discarded and conversion.\n" " will continue. If false, RPC will fail if any signatures are present.\n" "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n" " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n" - " will be tried. If false, only non-witness deserialization wil be tried. Only has an effect if\n" + " will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n" " permitsigdata is true.\n" "\nResult:\n" " \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n" @@ -1775,7 +1783,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) // Remove all scriptSigs and scriptWitnesses from inputs for (CTxIn& input : tx.vin) { - if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && (request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool()))) { + if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && !permitsigdata) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Inputs must not have scriptSigs and scriptWitnesses"); } input.scriptSig.clear(); @@ -1799,6 +1807,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -1808,7 +1817,7 @@ static const CRPCCommand commands[] = { "rawtransactions", "decodescript", &decodescript, {"hexstring"} }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} }, { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ + { "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, { "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} }, { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} }, { "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} }, @@ -1820,6 +1829,7 @@ static const CRPCCommand commands[] = { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, }; +// clang-format on void RegisterRawTransactionRPCCommands(CRPCTable &t) { |