diff options
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 84 |
1 files changed, 45 insertions, 39 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index b967f2dbf8..d860dbc244 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -16,6 +16,7 @@ #include "policy/policy.h" #include "policy/rbf.h" #include "primitives/transaction.h" +#include "rpc/safemode.h" #include "rpc/server.h" #include "script/script.h" #include "script/script_error.h" @@ -41,7 +42,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) // Blockchain contextual information (confirmations and blocktime) is not // available to code in bitcoin-common, so we query them here and push the // data into the returned UniValue. - TxToUniv(tx, uint256(), entry); + TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags()); if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); @@ -160,13 +161,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request) : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") + ". Use gettransaction for wallet transactions."); - std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); - if (!fVerbose) - return strHex; + return EncodeHexTx(*tx, RPCSerializationFlags()); UniValue result(UniValue::VOBJ); - result.push_back(Pair("hex", strHex)); TxToJSON(*tx, hashBlock, result); return result; } @@ -208,7 +206,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request) LOCK(cs_main); - CBlockIndex* pblockindex = NULL; + CBlockIndex* pblockindex = nullptr; uint256 hashBlock; if (!request.params[1].isNull()) @@ -228,7 +226,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request) } } - if (pblockindex == NULL) + if (pblockindex == nullptr) { CTransactionRef tx; if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull()) @@ -339,14 +337,14 @@ UniValue createrawtransaction(const JSONRPCRequest& request) CMutableTransaction rawTx; - if (request.params.size() > 2 && !request.params[2].isNull()) { + if (!request.params[2].isNull()) { int64_t nLockTime = request.params[2].get_int64(); if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range"); rawTx.nLockTime = nLockTime; } - bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false; + bool rbfOptIn = request.params[3].isTrue(); for (unsigned int idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; @@ -386,7 +384,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) rawTx.vin.push_back(in); } - std::set<CBitcoinAddress> setAddress; + std::set<CTxDestination> destinations; std::vector<std::string> addrList = sendTo.getKeys(); for (const std::string& name_ : addrList) { @@ -396,15 +394,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request) CTxOut out(0, CScript() << OP_RETURN << data); rawTx.vout.push_back(out); } else { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_); + CTxDestination destination = DecodeDestination(name_); + if (!IsValidDestination(destination)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_); + } - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); + if (!destinations.insert(destination).second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_); + } - CScript scriptPubKey = GetScriptForDestination(address.Get()); + CScript scriptPubKey = GetScriptForDestination(destination); CAmount nAmount = AmountFromValue(sendTo[name_]); CTxOut out(nAmount, scriptPubKey); @@ -483,7 +482,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); UniValue result(UniValue::VOBJ); - TxToUniv(CTransaction(std::move(mtx)), uint256(), result); + TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false); return result; } @@ -531,7 +530,7 @@ UniValue decodescript(const JSONRPCRequest& request) if (type.isStr() && type.get_str() != "scripthash") { // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. - r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); + r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script)))); } return r; @@ -572,7 +571,7 @@ UniValue combinerawtransaction(const JSONRPCRequest& request) " ]\n" "\nResult:\n" - "\"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" + "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n" "\nExamples:\n" + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]") @@ -706,8 +705,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request) + HelpExampleRpc("signrawtransaction", "\"myhex\"") ); + ObserveSafeMode(); #ifdef ENABLE_WALLET - LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL); + LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); #else LOCK(cs_main); #endif @@ -735,7 +735,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) bool fGivenKeys = false; CBasicKeyStore tempKeystore; - if (request.params.size() > 2 && !request.params[2].isNull()) { + if (!request.params[2].isNull()) { fGivenKeys = true; UniValue keys = request.params[2].get_array(); for (unsigned int idx = 0; idx < keys.size(); idx++) { @@ -757,7 +757,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) #endif // Add previous txouts given in the RPC call: - if (request.params.size() > 1 && !request.params[1].isNull()) { + if (!request.params[1].isNull()) { UniValue prevTxs = request.params[1].get_array(); for (unsigned int idx = 0; idx < prevTxs.size(); idx++) { const UniValue& p = prevTxs[idx]; @@ -828,7 +828,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) #endif int nHashType = SIGHASH_ALL; - if (request.params.size() > 3 && !request.params[3].isNull()) { + if (!request.params[3].isNull()) { static std::map<std::string, int> mapSigHashValues = { {std::string("ALL"), int(SIGHASH_ALL)}, {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)}, @@ -873,7 +873,12 @@ UniValue signrawtransaction(const JSONRPCRequest& request) ScriptError serror = SCRIPT_ERR_OK; if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) { - TxInErrorToJSON(txin, vErrors, ScriptErrorString(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 { + TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); + } } } bool fComplete = vErrors.empty(); @@ -911,6 +916,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") ); + ObserveSafeMode(); LOCK(cs_main); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); @@ -922,7 +928,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) const uint256& hashTx = tx->GetHash(); CAmount nMaxRawTxFee = maxTxFee; - if (request.params.size() > 1 && request.params[1].get_bool()) + if (!request.params[1].isNull() && request.params[1].get_bool()) nMaxRawTxFee = 0; CCoinsViewCache &view = *pcoinsTip; @@ -936,8 +942,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) // push to local node and sync with wallets CValidationState state; bool fMissingInputs; - bool fLimitFree = true; - if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, NULL, false, nMaxRawTxFee)) { + if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs, + nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) { if (state.IsInvalid()) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); } else { @@ -962,18 +968,18 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode +{ // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable"} }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} }, - { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} }, - { "rawtransactions", "combinerawtransaction", &combinerawtransaction, true, {"txs"} }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ - - { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} }, - { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} }, + { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose"} }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} }, + { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} }, + { "rawtransactions", "decodescript", &decodescript, {"hexstring"} }, + { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} }, + { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} }, + { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ + + { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, + { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, }; void RegisterRawTransactionRPCCommands(CRPCTable &t) |