diff options
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 230 |
1 files changed, 165 insertions, 65 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b504b84274..457abec1bc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4,18 +4,19 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <amount.h> -#include <base58.h> #include <chain.h> #include <consensus/validation.h> #include <core_io.h> #include <httpserver.h> #include <validation.h> +#include <key_io.h> #include <net.h> #include <policy/feerate.h> #include <policy/fees.h> #include <policy/policy.h> #include <policy/rbf.h> #include <rpc/mining.h> +#include <rpc/rawtransaction.h> #include <rpc/safemode.h> #include <rpc/server.h> #include <rpc/util.h> @@ -1402,6 +1403,16 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA if(params[2].get_bool()) filter = filter | ISMINE_WATCH_ONLY; + bool has_filtered_address = false; + CTxDestination filtered_address = CNoDestination(); + if (!fByAccounts && params.size() > 3) { + if (!IsValidDestinationString(params[3].get_str())) { + throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid"); + } + filtered_address = DecodeDestination(params[3].get_str()); + has_filtered_address = true; + } + // Tally std::map<CTxDestination, tallyitem> mapTally; for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { @@ -1420,6 +1431,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA if (!ExtractDestination(txout.scriptPubKey, address)) continue; + if (has_filtered_address && !(filtered_address == address)) { + continue; + } + isminefilter mine = IsMine(*pwallet, address); if(!(mine & filter)) continue; @@ -1436,10 +1451,24 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA // Reply UniValue ret(UniValue::VARR); std::map<std::string, tallyitem> mapAccountTally; - for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) { - const CTxDestination& dest = item.first; - const std::string& strAccount = item.second.name; - std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest); + + // Create mapAddressBook iterator + // If we aren't filtering, go from begin() to end() + auto start = pwallet->mapAddressBook.begin(); + auto end = pwallet->mapAddressBook.end(); + // If we are filtering, find() the applicable entry + if (has_filtered_address) { + start = pwallet->mapAddressBook.find(filtered_address); + if (start != end) { + end = std::next(start); + } + } + + for (auto item_it = start; item_it != end; ++item_it) + { + const CTxDestination& address = item_it->first; + const std::string& strAccount = item_it->second.name; + auto it = mapTally.find(address); if (it == mapTally.end() && !fIncludeEmpty) continue; @@ -1465,7 +1494,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA UniValue obj(UniValue::VOBJ); if(fIsWatchonly) obj.pushKV("involvesWatchonly", true); - obj.pushKV("address", EncodeDestination(dest)); + obj.pushKV("address", EncodeDestination(address)); obj.pushKV("account", strAccount); obj.pushKV("amount", ValueFromAmount(nAmount)); obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); @@ -1510,15 +1539,15 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 3) + if (request.fHelp || request.params.size() > 4) throw std::runtime_error( - "listreceivedbyaddress ( minconf include_empty include_watchonly)\n" + "listreceivedbyaddress ( minconf include_empty include_watchonly address_filter )\n" "\nList balances by receiving address.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" "2. include_empty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n" "3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n" - + "4. address_filter (string, optional) If present, only return information on this address.\n" "\nResult:\n" "[\n" " {\n" @@ -1540,6 +1569,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) + HelpExampleCli("listreceivedbyaddress", "") + HelpExampleCli("listreceivedbyaddress", "6 true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true") + + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"") ); ObserveSafeMode(); @@ -3236,6 +3266,75 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) return result; } +UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) +{ + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) + throw std::runtime_error( + "signrawtransactionwithwallet \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] 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" + + HelpRequiringPassphrase(pwallet) + "\n" + + "\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. \"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("signrawtransactionwithwallet", "\"myhex\"") + + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"") + ); + + RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); + + CMutableTransaction mtx; + if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + + // Sign the transaction + LOCK2(cs_main, pwallet->cs_wallet); + return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]); +} + UniValue bumpfee(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); @@ -3731,62 +3830,63 @@ extern UniValue importmulti(const JSONRPCRequest& request); extern UniValue rescanblockchain(const JSONRPCRequest& request); static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, - { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, - { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, - { "wallet", "abortrescan", &abortrescan, {} }, - { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account","address_type"} }, - { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, - { "wallet", "backupwallet", &backupwallet, {"destination"} }, - { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, - { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, - { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, - { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, - { "wallet", "getaccountaddress", &getaccountaddress, {"account"} }, - { "wallet", "getaccount", &getaccount, {"address"} }, - { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} }, - { "wallet", "getaddressinfo", &getaddressinfo, {"address"} }, - { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} }, - { "wallet", "getnewaddress", &getnewaddress, {"account","address_type"} }, - { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, - { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} }, - { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} }, - { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} }, - { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} }, - { "wallet", "getwalletinfo", &getwalletinfo, {} }, - { "wallet", "importmulti", &importmulti, {"requests","options"} }, - { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} }, - { "wallet", "importwallet", &importwallet, {"filename"} }, - { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} }, - { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} }, - { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} }, - { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} }, - { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} }, - { "wallet", "listaddressgroupings", &listaddressgroupings, {} }, - { "wallet", "listlockunspent", &listlockunspent, {} }, - { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} }, - { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} }, - { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, - { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} }, - { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, - { "wallet", "listwallets", &listwallets, {} }, - { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} }, - { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, - { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, - { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, - { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} }, - { "wallet", "setaccount", &setaccount, {"address","account"} }, - { "wallet", "settxfee", &settxfee, {"amount"} }, - { "wallet", "signmessage", &signmessage, {"address","message"} }, - { "wallet", "walletlock", &walletlock, {} }, - { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, - { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, - { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, - { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, - - { "generating", "generate", &generate, {"nblocks","maxtries"} }, +{ // category name actor (function) argNames + // --------------------- ------------------------ ----------------------- ---------- + { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, + { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, + { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, + { "wallet", "abortrescan", &abortrescan, {} }, + { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account","address_type"} }, + { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, + { "wallet", "backupwallet", &backupwallet, {"destination"} }, + { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, + { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, + { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, + { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, + { "wallet", "getaccountaddress", &getaccountaddress, {"account"} }, + { "wallet", "getaccount", &getaccount, {"address"} }, + { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} }, + { "wallet", "getaddressinfo", &getaddressinfo, {"address"} }, + { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} }, + { "wallet", "getnewaddress", &getnewaddress, {"account","address_type"} }, + { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, + { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} }, + { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} }, + { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} }, + { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} }, + { "wallet", "getwalletinfo", &getwalletinfo, {} }, + { "wallet", "importmulti", &importmulti, {"requests","options"} }, + { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} }, + { "wallet", "importwallet", &importwallet, {"filename"} }, + { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} }, + { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} }, + { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} }, + { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} }, + { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} }, + { "wallet", "listaddressgroupings", &listaddressgroupings, {} }, + { "wallet", "listlockunspent", &listlockunspent, {} }, + { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} }, + { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, + { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, + { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} }, + { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, + { "wallet", "listwallets", &listwallets, {} }, + { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} }, + { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, + { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, + { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, + { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} }, + { "wallet", "setaccount", &setaccount, {"address","account"} }, + { "wallet", "settxfee", &settxfee, {"amount"} }, + { "wallet", "signmessage", &signmessage, {"address","message"} }, + { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} }, + { "wallet", "walletlock", &walletlock, {} }, + { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, + { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, + { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, + { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, + + { "generating", "generate", &generate, {"nblocks","maxtries"} }, }; void RegisterWalletRPCCommands(CRPCTable &t) |