diff options
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 161 |
1 files changed, 85 insertions, 76 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 276ebfda26..696f1bd781 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -24,6 +24,7 @@ #include "uint256.h" #include "utilstrencodings.h" #ifdef ENABLE_WALLET +#include "wallet/rpcwallet.h" #include "wallet/wallet.h" #endif @@ -33,12 +34,10 @@ #include <univalue.h> -using namespace std; - void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; - vector<CTxDestination> addresses; + std::vector<CTxDestination> addresses; int nRequired; out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey))); @@ -126,18 +125,20 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) UniValue getrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getrawtransaction \"txid\" ( verbose )\n" - "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n" - "or there is an 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.\n" + + "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" + "enabled, it also works for blockchain transactions.\n" + "DEPRECATED: for now, it also works for transactions with unspent outputs.\n" + "\nReturn the raw transaction data.\n" "\nIf verbose is 'true', returns an Object with information about 'txid'.\n" "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" - "2. verbose (bool, optional, default=false) If true, return a string, other return a json object\n" + "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n" "\nResult (if verbose is not set or set to false):\n" "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" @@ -174,7 +175,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"bitcoinaddress\" (string) bitcoin address\n" + " \"address\" (string) bitcoin address\n" " ,...\n" " ]\n" " }\n" @@ -212,15 +213,17 @@ UniValue getrawtransaction(const JSONRPCRequest& request) } else { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean."); - } + } } CTransactionRef tx; uint256 hashBlock; if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? "No such mempool or blockchain transaction" + : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") + + ". Use gettransaction for wallet transactions."); - string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); + std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); if (!fVerbose) return strHex; @@ -234,35 +237,34 @@ UniValue getrawtransaction(const JSONRPCRequest& request) UniValue gettxoutproof(const JSONRPCRequest& request) { if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2)) - throw runtime_error( + 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" - "\nReturn the raw transaction data.\n" "\nArguments:\n" "1. \"txids\" (string) A json array of txids to filter\n" " [\n" " \"txid\" (string) A transaction hash\n" " ,...\n" " ]\n" - "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n" + "2. \"blockhash\" (string, optional) If specified, looks for txid in the block with this hash\n" "\nResult:\n" "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" ); - set<uint256> setTxids; + std::set<uint256> setTxids; uint256 oneTxid; 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, string("Invalid txid ")+txid.get_str()); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str()); uint256 hash(uint256S(txid.get_str())); if (setTxids.count(hash)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str()); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str()); setTxids.insert(hash); oneTxid = hash; } @@ -315,7 +317,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request) UniValue verifytxoutproof(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + 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" @@ -331,8 +333,8 @@ UniValue verifytxoutproof(const JSONRPCRequest& request) UniValue res(UniValue::VARR); - vector<uint256> vMatch; - vector<unsigned int> vIndex; + std::vector<uint256> vMatch; + std::vector<unsigned int> vIndex; if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) return res; @@ -349,7 +351,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request) UniValue createrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n" "\nCreate a transaction spending the given inputs and creating new outputs.\n" "Outputs can be addresses or data.\n" @@ -358,24 +360,24 @@ UniValue createrawtransaction(const JSONRPCRequest& request) "it is not stored in the wallet or transmitted to the network.\n" "\nArguments:\n" - "1. \"transactions\" (string, required) A json array of json objects\n" + "1. \"inputs\" (string, required) A json array of json objects\n" " [\n" " {\n" " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n (numeric, required) The output number\n" - " \"sequence\":n (numeric, optional) The sequence number\n" - " }\n" + " \"vout\":n, (numeric, required) The output number\n" + " \"sequence\":n (numeric, optional) The sequence number\n" + " } \n" " ,...\n" " ]\n" - "2. \"outputs\" (string, required) a json object with outputs\n" + "2. \"outputs\" (string, required) a json object with outputs\n" " {\n" - " \"address\": x.xxx (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" - " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n" - " ...\n" + " \"address\": x.xxx, (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" + " \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n" + " ,...\n" " }\n" - "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" + "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" "\nResult:\n" - "\"transaction\" (string) hex string of the transaction\n" + "\"transaction\" (string) hex string of the transaction\n" "\nExamples:\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") @@ -430,9 +432,9 @@ UniValue createrawtransaction(const JSONRPCRequest& request) rawTx.vin.push_back(in); } - set<CBitcoinAddress> setAddress; - vector<string> addrList = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, addrList) { + std::set<CBitcoinAddress> setAddress; + std::vector<std::string> addrList = sendTo.getKeys(); + BOOST_FOREACH(const std::string& name_, addrList) { if (name_ == "data") { std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data"); @@ -442,10 +444,10 @@ UniValue createrawtransaction(const JSONRPCRequest& request) } else { CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); @@ -462,12 +464,12 @@ UniValue createrawtransaction(const JSONRPCRequest& request) UniValue decoderawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "decoderawtransaction \"hexstring\"\n" "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" "\nArguments:\n" - "1. \"hex\" (string, required) The transaction hex string\n" + "1. \"hexstring\" (string, required) The transaction hex string\n" "\nResult:\n" "{\n" @@ -531,11 +533,11 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) UniValue decodescript(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( - "decodescript \"hex\"\n" + throw std::runtime_error( + "decodescript \"hexstring\"\n" "\nDecode a hex-encoded script.\n" "\nArguments:\n" - "1. \"hex\" (string) the hex encoded script\n" + "1. \"hexstring\" (string) the hex encoded script\n" "\nResult:\n" "{\n" " \"asm\":\"asm\", (string) Script public key\n" @@ -558,7 +560,7 @@ UniValue decodescript(const JSONRPCRequest& request) UniValue r(UniValue::VOBJ); CScript script; if (request.params[0].get_str().size() > 0){ - vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument")); + std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument")); script = CScript(scriptData.begin(), scriptData.end()); } else { // Empty scripts are valid @@ -591,8 +593,12 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: UniValue signrawtransaction(const JSONRPCRequest& request) { +#ifdef ENABLE_WALLET + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); +#endif + if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw runtime_error( + 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" @@ -600,7 +606,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) "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() + "\n" + + HelpRequiringPassphrase(pwallet) + "\n" #endif "\nArguments:\n" @@ -616,7 +622,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) " }\n" " ,...\n" " ]\n" - "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\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" @@ -651,15 +657,15 @@ UniValue signrawtransaction(const JSONRPCRequest& request) ); #ifdef ENABLE_WALLET - LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); + LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL); #else LOCK(cs_main); #endif RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true); - vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1")); + std::vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); - vector<CMutableTransaction> txVariants; + std::vector<CMutableTransaction> txVariants; while (!ssData.empty()) { try { CMutableTransaction tx; @@ -714,8 +720,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request) } } #ifdef ENABLE_WALLET - else if (pwalletMain) - EnsureWalletIsUnlocked(); + else if (pwallet) { + EnsureWalletIsUnlocked(pwallet); + } #endif // Add previous txouts given in the RPC call: @@ -741,13 +748,13 @@ UniValue signrawtransaction(const JSONRPCRequest& request) if (nOut < 0) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); - vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); + std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); { CCoinsModifier coins = view.ModifyCoins(txid); if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { - string err("Previous output scriptPubKey mismatch:\n"); + std::string err("Previous output scriptPubKey mismatch:\n"); err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+ ScriptToAsmStr(scriptPubKey); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); @@ -773,7 +780,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) }); UniValue v = find_value(prevOut, "redeemScript"); if (!v.isNull()) { - vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); + std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); } @@ -782,23 +789,23 @@ UniValue signrawtransaction(const JSONRPCRequest& request) } #ifdef ENABLE_WALLET - const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); + const CKeyStore& keystore = ((fGivenKeys || !pwallet) ? tempKeystore : *pwallet); #else const CKeyStore& keystore = tempKeystore; #endif int nHashType = SIGHASH_ALL; if (request.params.size() > 3 && !request.params[3].isNull()) { - static map<string, int> mapSigHashValues = + static std::map<std::string, int> mapSigHashValues = boost::assign::map_list_of - (string("ALL"), int(SIGHASH_ALL)) - (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) - (string("NONE"), int(SIGHASH_NONE)) - (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) - (string("SINGLE"), int(SIGHASH_SINGLE)) - (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) + (std::string("ALL"), int(SIGHASH_ALL)) + (std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) + (std::string("NONE"), int(SIGHASH_NONE)) + (std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) + (std::string("SINGLE"), int(SIGHASH_SINGLE)) + (std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) ; - string strHashType = request.params[3].get_str(); + std::string strHashType = request.params[3].get_str(); if (mapSigHashValues.count(strHashType)) nHashType = mapSigHashValues[strHashType]; else @@ -831,7 +838,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request) // ... and merge in other signatures: BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { - sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i)); + if (txv.vin.size() > i) { + sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i)); + } } UpdateTransaction(mergedTx, i, sigdata); @@ -856,7 +865,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) UniValue sendrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + 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" @@ -886,7 +895,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) CTransactionRef tx(MakeTransactionRef(std::move(mtx))); const uint256& hashTx = tx->GetHash(); - bool fLimitFree = false; + bool fLimitFree = true; CAmount nMaxRawTxFee = maxTxFee; if (request.params.size() > 1 && request.params[1].get_bool()) nMaxRawTxFee = 0; @@ -899,7 +908,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) // push to local node and sync with wallets CValidationState state; bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) { + if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, NULL, false, nMaxRawTxFee)) { if (state.IsInvalid()) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); } else { @@ -926,15 +935,15 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true }, - { "rawtransactions", "decodescript", &decodescript, true }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ - - { "blockchain", "gettxoutproof", &gettxoutproof, true }, - { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, + { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"transactions","outputs","locktime"} }, + { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} }, + { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} }, + { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} }, + { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ + + { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} }, + { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} }, }; void RegisterRawTransactionRPCCommands(CRPCTable &t) |