1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
13 #include "rpcserver.h"
16 #include "utilmoneystr.h"
19 #include "primitives/transaction.h"
20 #include "zcbenchmarks.h"
21 #include "script/interpreter.h"
24 #include "asyncrpcoperation.h"
25 #include "wallet/asyncrpcoperation_sendmany.h"
31 #include <boost/assign/list_of.hpp>
33 #include "json/json_spirit_utils.h"
34 #include "json/json_spirit_value.h"
35 #include "asyncrpcqueue.h"
38 using namespace json_spirit;
40 using namespace libzcash;
42 int64_t nWalletUnlockTime;
43 static CCriticalSection cs_nWalletUnlockTime;
46 Value z_getoperationstatus_IMPL(const Array&, bool);
48 std::string HelpRequiringPassphrase()
50 return pwalletMain && pwalletMain->IsCrypted()
51 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
55 bool EnsureWalletIsAvailable(bool avoidException)
60 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
67 void EnsureWalletIsUnlocked()
69 if (pwalletMain->IsLocked())
70 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
73 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
75 int confirms = wtx.GetDepthInMainChain();
76 entry.push_back(Pair("confirmations", confirms));
78 entry.push_back(Pair("generated", true));
81 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
82 entry.push_back(Pair("blockindex", wtx.nIndex));
83 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
85 uint256 hash = wtx.GetHash();
86 entry.push_back(Pair("txid", hash.GetHex()));
88 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
89 conflicts.push_back(conflict.GetHex());
90 entry.push_back(Pair("walletconflicts", conflicts));
91 entry.push_back(Pair("time", wtx.GetTxTime()));
92 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
93 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
94 entry.push_back(Pair(item.first, item.second));
97 string AccountFromValue(const Value& value)
99 string strAccount = value.get_str();
100 if (strAccount == "*")
101 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
105 Value getnewaddress(const Array& params, bool fHelp)
107 if (!EnsureWalletIsAvailable(fHelp))
110 if (fHelp || params.size() > 1)
112 "getnewaddress ( \"account\" )\n"
113 "\nReturns a new Bitcoin address for receiving payments.\n"
114 "If 'account' is specified (DEPRECATED), it is added to the address book \n"
115 "so payments received with the address will be credited to 'account'.\n"
117 "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
119 "\"bitcoinaddress\" (string) The new bitcoin address\n"
121 + HelpExampleCli("getnewaddress", "")
122 + HelpExampleRpc("getnewaddress", "")
125 LOCK2(cs_main, pwalletMain->cs_wallet);
127 // Parse the account first so we don't generate a key if there's an error
129 if (params.size() > 0)
130 strAccount = AccountFromValue(params[0]);
132 if (!pwalletMain->IsLocked())
133 pwalletMain->TopUpKeyPool();
135 // Generate a new key that is added to wallet
137 if (!pwalletMain->GetKeyFromPool(newKey))
138 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
139 CKeyID keyID = newKey.GetID();
141 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
143 return CBitcoinAddress(keyID).ToString();
147 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
149 CWalletDB walletdb(pwalletMain->strWalletFile);
152 walletdb.ReadAccount(strAccount, account);
154 bool bKeyUsed = false;
156 // Check if the current key has been used
157 if (account.vchPubKey.IsValid())
159 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
160 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
161 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
164 const CWalletTx& wtx = (*it).second;
165 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
166 if (txout.scriptPubKey == scriptPubKey)
171 // Generate a new key
172 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
174 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
175 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
177 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
178 walletdb.WriteAccount(strAccount, account);
181 return CBitcoinAddress(account.vchPubKey.GetID());
184 Value getaccountaddress(const Array& params, bool fHelp)
186 if (!EnsureWalletIsAvailable(fHelp))
189 if (fHelp || params.size() != 1)
191 "getaccountaddress \"account\"\n"
192 "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
194 "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
196 "\"bitcoinaddress\" (string) The account bitcoin address\n"
198 + HelpExampleCli("getaccountaddress", "")
199 + HelpExampleCli("getaccountaddress", "\"\"")
200 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
201 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
204 LOCK2(cs_main, pwalletMain->cs_wallet);
206 // Parse the account first so we don't generate a key if there's an error
207 string strAccount = AccountFromValue(params[0]);
211 ret = GetAccountAddress(strAccount).ToString();
216 Value getrawchangeaddress(const Array& params, bool fHelp)
218 if (!EnsureWalletIsAvailable(fHelp))
221 if (fHelp || params.size() > 1)
223 "getrawchangeaddress\n"
224 "\nReturns a new Bitcoin address, for receiving change.\n"
225 "This is for use with raw transactions, NOT normal use.\n"
227 "\"address\" (string) The address\n"
229 + HelpExampleCli("getrawchangeaddress", "")
230 + HelpExampleRpc("getrawchangeaddress", "")
233 LOCK2(cs_main, pwalletMain->cs_wallet);
235 if (!pwalletMain->IsLocked())
236 pwalletMain->TopUpKeyPool();
238 CReserveKey reservekey(pwalletMain);
240 if (!reservekey.GetReservedKey(vchPubKey))
241 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
243 reservekey.KeepKey();
245 CKeyID keyID = vchPubKey.GetID();
247 return CBitcoinAddress(keyID).ToString();
251 Value setaccount(const Array& params, bool fHelp)
253 if (!EnsureWalletIsAvailable(fHelp))
256 if (fHelp || params.size() < 1 || params.size() > 2)
258 "setaccount \"bitcoinaddress\" \"account\"\n"
259 "\nDEPRECATED. Sets the account associated with the given address.\n"
261 "1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\n"
262 "2. \"account\" (string, required) The account to assign the address to.\n"
264 + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
265 + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
268 LOCK2(cs_main, pwalletMain->cs_wallet);
270 CBitcoinAddress address(params[0].get_str());
271 if (!address.IsValid())
272 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
275 if (params.size() > 1)
276 strAccount = AccountFromValue(params[1]);
278 // Only add the account if the address is yours.
279 if (IsMine(*pwalletMain, address.Get()))
281 // Detect when changing the account of an address that is the 'unused current key' of another account:
282 if (pwalletMain->mapAddressBook.count(address.Get()))
284 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
285 if (address == GetAccountAddress(strOldAccount))
286 GetAccountAddress(strOldAccount, true);
288 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
291 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
297 Value getaccount(const Array& params, bool fHelp)
299 if (!EnsureWalletIsAvailable(fHelp))
302 if (fHelp || params.size() != 1)
304 "getaccount \"bitcoinaddress\"\n"
305 "\nDEPRECATED. Returns the account associated with the given address.\n"
307 "1. \"bitcoinaddress\" (string, required) The bitcoin address for account lookup.\n"
309 "\"accountname\" (string) the account address\n"
311 + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
312 + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
315 LOCK2(cs_main, pwalletMain->cs_wallet);
317 CBitcoinAddress address(params[0].get_str());
318 if (!address.IsValid())
319 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
322 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
323 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
324 strAccount = (*mi).second.name;
329 Value getaddressesbyaccount(const Array& params, bool fHelp)
331 if (!EnsureWalletIsAvailable(fHelp))
334 if (fHelp || params.size() != 1)
336 "getaddressesbyaccount \"account\"\n"
337 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
339 "1. \"account\" (string, required) The account name.\n"
341 "[ (json array of string)\n"
342 " \"bitcoinaddress\" (string) a bitcoin address associated with the given account\n"
346 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
347 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
350 LOCK2(cs_main, pwalletMain->cs_wallet);
352 string strAccount = AccountFromValue(params[0]);
354 // Find all addresses that have the given account
356 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
358 const CBitcoinAddress& address = item.first;
359 const string& strName = item.second.name;
360 if (strName == strAccount)
361 ret.push_back(address.ToString());
366 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
368 CAmount curBalance = pwalletMain->GetBalance();
372 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
374 if (nValue > curBalance)
375 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
377 // Parse Bitcoin address
378 CScript scriptPubKey = GetScriptForDestination(address);
380 // Create and send the transaction
381 CReserveKey reservekey(pwalletMain);
382 CAmount nFeeRequired;
383 std::string strError;
384 vector<CRecipient> vecSend;
385 int nChangePosRet = -1;
386 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
387 vecSend.push_back(recipient);
388 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
389 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
390 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
391 throw JSONRPCError(RPC_WALLET_ERROR, strError);
393 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
394 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
397 Value sendtoaddress(const Array& params, bool fHelp)
399 if (!EnsureWalletIsAvailable(fHelp))
402 if (fHelp || params.size() < 2 || params.size() > 5)
404 "sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
405 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
406 + HelpRequiringPassphrase() +
408 "1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
409 "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
410 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
411 " This is not part of the transaction, just kept in your wallet.\n"
412 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
413 " to which you're sending the transaction. This is not part of the \n"
414 " transaction, just kept in your wallet.\n"
415 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
416 " The recipient will receive less bitcoins than you enter in the amount field.\n"
418 "\"transactionid\" (string) The transaction id.\n"
420 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
421 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
422 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
423 + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
426 LOCK2(cs_main, pwalletMain->cs_wallet);
428 CBitcoinAddress address(params[0].get_str());
429 if (!address.IsValid())
430 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
433 CAmount nAmount = AmountFromValue(params[1]);
437 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
438 wtx.mapValue["comment"] = params[2].get_str();
439 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
440 wtx.mapValue["to"] = params[3].get_str();
442 bool fSubtractFeeFromAmount = false;
443 if (params.size() > 4)
444 fSubtractFeeFromAmount = params[4].get_bool();
446 EnsureWalletIsUnlocked();
448 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
450 return wtx.GetHash().GetHex();
453 Value listaddressgroupings(const Array& params, bool fHelp)
455 if (!EnsureWalletIsAvailable(fHelp))
460 "listaddressgroupings\n"
461 "\nLists groups of addresses which have had their common ownership\n"
462 "made public by common use as inputs or as the resulting change\n"
463 "in past transactions\n"
468 " \"bitcoinaddress\", (string) The bitcoin address\n"
469 " amount, (numeric) The amount in btc\n"
470 " \"account\" (string, optional) The account (DEPRECATED)\n"
477 + HelpExampleCli("listaddressgroupings", "")
478 + HelpExampleRpc("listaddressgroupings", "")
481 LOCK2(cs_main, pwalletMain->cs_wallet);
484 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
485 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
488 BOOST_FOREACH(CTxDestination address, grouping)
491 addressInfo.push_back(CBitcoinAddress(address).ToString());
492 addressInfo.push_back(ValueFromAmount(balances[address]));
494 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
495 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
497 jsonGrouping.push_back(addressInfo);
499 jsonGroupings.push_back(jsonGrouping);
501 return jsonGroupings;
504 Value signmessage(const Array& params, bool fHelp)
506 if (!EnsureWalletIsAvailable(fHelp))
509 if (fHelp || params.size() != 2)
511 "signmessage \"bitcoinaddress\" \"message\"\n"
512 "\nSign a message with the private key of an address"
513 + HelpRequiringPassphrase() + "\n"
515 "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the private key.\n"
516 "2. \"message\" (string, required) The message to create a signature of.\n"
518 "\"signature\" (string) The signature of the message encoded in base 64\n"
520 "\nUnlock the wallet for 30 seconds\n"
521 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
522 "\nCreate the signature\n"
523 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
524 "\nVerify the signature\n"
525 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
527 + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
530 LOCK2(cs_main, pwalletMain->cs_wallet);
532 EnsureWalletIsUnlocked();
534 string strAddress = params[0].get_str();
535 string strMessage = params[1].get_str();
537 CBitcoinAddress addr(strAddress);
539 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
542 if (!addr.GetKeyID(keyID))
543 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
546 if (!pwalletMain->GetKey(keyID, key))
547 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
549 CHashWriter ss(SER_GETHASH, 0);
550 ss << strMessageMagic;
553 vector<unsigned char> vchSig;
554 if (!key.SignCompact(ss.GetHash(), vchSig))
555 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
557 return EncodeBase64(&vchSig[0], vchSig.size());
560 Value getreceivedbyaddress(const Array& params, bool fHelp)
562 if (!EnsureWalletIsAvailable(fHelp))
565 if (fHelp || params.size() < 1 || params.size() > 2)
567 "getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
568 "\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
570 "1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
571 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
573 "amount (numeric) The total amount in btc received at this address.\n"
575 "\nThe amount from transactions with at least 1 confirmation\n"
576 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
577 "\nThe amount including unconfirmed transactions, zero confirmations\n"
578 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
579 "\nThe amount with at least 6 confirmation, very safe\n"
580 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
581 "\nAs a json rpc call\n"
582 + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
585 LOCK2(cs_main, pwalletMain->cs_wallet);
588 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
589 if (!address.IsValid())
590 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
591 CScript scriptPubKey = GetScriptForDestination(address.Get());
592 if (!IsMine(*pwalletMain,scriptPubKey))
595 // Minimum confirmations
597 if (params.size() > 1)
598 nMinDepth = params[1].get_int();
602 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
604 const CWalletTx& wtx = (*it).second;
605 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
608 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
609 if (txout.scriptPubKey == scriptPubKey)
610 if (wtx.GetDepthInMainChain() >= nMinDepth)
611 nAmount += txout.nValue;
614 return ValueFromAmount(nAmount);
618 Value getreceivedbyaccount(const Array& params, bool fHelp)
620 if (!EnsureWalletIsAvailable(fHelp))
623 if (fHelp || params.size() < 1 || params.size() > 2)
625 "getreceivedbyaccount \"account\" ( minconf )\n"
626 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
628 "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n"
629 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
631 "amount (numeric) The total amount in btc received for this account.\n"
633 "\nAmount received by the default account with at least 1 confirmation\n"
634 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
635 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
636 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
637 "\nThe amount with at least 6 confirmation, very safe\n"
638 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
639 "\nAs a json rpc call\n"
640 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
643 LOCK2(cs_main, pwalletMain->cs_wallet);
645 // Minimum confirmations
647 if (params.size() > 1)
648 nMinDepth = params[1].get_int();
650 // Get the set of pub keys assigned to account
651 string strAccount = AccountFromValue(params[0]);
652 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
656 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
658 const CWalletTx& wtx = (*it).second;
659 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
662 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
664 CTxDestination address;
665 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
666 if (wtx.GetDepthInMainChain() >= nMinDepth)
667 nAmount += txout.nValue;
671 return (double)nAmount / (double)COIN;
675 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
677 CAmount nBalance = 0;
679 // Tally wallet transactions
680 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
682 const CWalletTx& wtx = (*it).second;
683 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
686 CAmount nReceived, nSent, nFee;
687 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
689 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
690 nBalance += nReceived;
691 nBalance -= nSent + nFee;
694 // Tally internal accounting entries
695 nBalance += walletdb.GetAccountCreditDebit(strAccount);
700 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
702 CWalletDB walletdb(pwalletMain->strWalletFile);
703 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
707 Value getbalance(const Array& params, bool fHelp)
709 if (!EnsureWalletIsAvailable(fHelp))
712 if (fHelp || params.size() > 3)
714 "getbalance ( \"account\" minconf includeWatchonly )\n"
715 "\nIf account is not specified, returns the server's total available balance.\n"
716 "If account is specified (DEPRECATED), returns the balance in the account.\n"
717 "Note that the account \"\" is not the same as leaving the parameter out.\n"
718 "The server total may be different to the balance in the default \"\" account.\n"
720 "1. \"account\" (string, optional) DEPRECATED. The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
721 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
722 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
724 "amount (numeric) The total amount in btc received for this account.\n"
726 "\nThe total amount in the wallet\n"
727 + HelpExampleCli("getbalance", "") +
728 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
729 + HelpExampleCli("getbalance", "\"*\" 6") +
730 "\nAs a json rpc call\n"
731 + HelpExampleRpc("getbalance", "\"*\", 6")
734 LOCK2(cs_main, pwalletMain->cs_wallet);
736 if (params.size() == 0)
737 return ValueFromAmount(pwalletMain->GetBalance());
740 if (params.size() > 1)
741 nMinDepth = params[1].get_int();
742 isminefilter filter = ISMINE_SPENDABLE;
743 if(params.size() > 2)
744 if(params[2].get_bool())
745 filter = filter | ISMINE_WATCH_ONLY;
747 if (params[0].get_str() == "*") {
748 // Calculate total balance a different way from GetBalance()
749 // (GetBalance() sums up all unspent TxOuts)
750 // getbalance and "getbalance * 1 true" should return the same number
751 CAmount nBalance = 0;
752 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
754 const CWalletTx& wtx = (*it).second;
755 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
759 string strSentAccount;
760 list<COutputEntry> listReceived;
761 list<COutputEntry> listSent;
762 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
763 if (wtx.GetDepthInMainChain() >= nMinDepth)
765 BOOST_FOREACH(const COutputEntry& r, listReceived)
766 nBalance += r.amount;
768 BOOST_FOREACH(const COutputEntry& s, listSent)
769 nBalance -= s.amount;
772 return ValueFromAmount(nBalance);
775 string strAccount = AccountFromValue(params[0]);
777 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
779 return ValueFromAmount(nBalance);
782 Value getunconfirmedbalance(const Array ¶ms, bool fHelp)
784 if (!EnsureWalletIsAvailable(fHelp))
787 if (fHelp || params.size() > 0)
789 "getunconfirmedbalance\n"
790 "Returns the server's total unconfirmed balance\n");
792 LOCK2(cs_main, pwalletMain->cs_wallet);
794 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
798 Value movecmd(const Array& params, bool fHelp)
800 if (!EnsureWalletIsAvailable(fHelp))
803 if (fHelp || params.size() < 3 || params.size() > 5)
805 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
806 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
808 "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
809 "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
810 "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
811 "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
813 "true|false (boolean) true if successful.\n"
815 "\nMove 0.01 btc from the default account to the account named tabby\n"
816 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
817 "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
818 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
819 "\nAs a json rpc call\n"
820 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
823 LOCK2(cs_main, pwalletMain->cs_wallet);
825 string strFrom = AccountFromValue(params[0]);
826 string strTo = AccountFromValue(params[1]);
827 CAmount nAmount = AmountFromValue(params[2]);
828 if (params.size() > 3)
829 // unused parameter, used to be nMinDepth, keep type-checking it though
830 (void)params[3].get_int();
832 if (params.size() > 4)
833 strComment = params[4].get_str();
835 CWalletDB walletdb(pwalletMain->strWalletFile);
836 if (!walletdb.TxnBegin())
837 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
839 int64_t nNow = GetAdjustedTime();
842 CAccountingEntry debit;
843 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
844 debit.strAccount = strFrom;
845 debit.nCreditDebit = -nAmount;
847 debit.strOtherAccount = strTo;
848 debit.strComment = strComment;
849 walletdb.WriteAccountingEntry(debit);
852 CAccountingEntry credit;
853 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
854 credit.strAccount = strTo;
855 credit.nCreditDebit = nAmount;
857 credit.strOtherAccount = strFrom;
858 credit.strComment = strComment;
859 walletdb.WriteAccountingEntry(credit);
861 if (!walletdb.TxnCommit())
862 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
868 Value sendfrom(const Array& params, bool fHelp)
870 if (!EnsureWalletIsAvailable(fHelp))
873 if (fHelp || params.size() < 3 || params.size() > 6)
875 "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
876 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address.\n"
877 "The amount is a real and is rounded to the nearest 0.00000001."
878 + HelpRequiringPassphrase() + "\n"
880 "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
881 "2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
882 "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
883 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
884 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
885 " This is not part of the transaction, just kept in your wallet.\n"
886 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
887 " to which you're sending the transaction. This is not part of the transaction, \n"
888 " it is just kept in your wallet.\n"
890 "\"transactionid\" (string) The transaction id.\n"
892 "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
893 + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
894 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
895 + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
896 "\nAs a json rpc call\n"
897 + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
900 LOCK2(cs_main, pwalletMain->cs_wallet);
902 string strAccount = AccountFromValue(params[0]);
903 CBitcoinAddress address(params[1].get_str());
904 if (!address.IsValid())
905 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
906 CAmount nAmount = AmountFromValue(params[2]);
908 if (params.size() > 3)
909 nMinDepth = params[3].get_int();
912 wtx.strFromAccount = strAccount;
913 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
914 wtx.mapValue["comment"] = params[4].get_str();
915 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
916 wtx.mapValue["to"] = params[5].get_str();
918 EnsureWalletIsUnlocked();
921 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
922 if (nAmount > nBalance)
923 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
925 SendMoney(address.Get(), nAmount, false, wtx);
927 return wtx.GetHash().GetHex();
931 Value sendmany(const Array& params, bool fHelp)
933 if (!EnsureWalletIsAvailable(fHelp))
936 if (fHelp || params.size() < 2 || params.size() > 5)
938 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
939 "\nSend multiple times. Amounts are double-precision floating point numbers."
940 + HelpRequiringPassphrase() + "\n"
942 "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n"
943 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
945 " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
948 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
949 "4. \"comment\" (string, optional) A comment\n"
950 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
951 " The fee will be equally deducted from the amount of each selected address.\n"
952 " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
953 " If no addresses are specified here, the sender pays the fee.\n"
955 " \"address\" (string) Subtract fee from this address\n"
959 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
960 " the number of addresses.\n"
962 "\nSend two amounts to two different addresses:\n"
963 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
964 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
965 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
966 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
967 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
968 "\nAs a json rpc call\n"
969 + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
972 LOCK2(cs_main, pwalletMain->cs_wallet);
974 string strAccount = AccountFromValue(params[0]);
975 Object sendTo = params[1].get_obj();
977 if (params.size() > 2)
978 nMinDepth = params[2].get_int();
981 wtx.strFromAccount = strAccount;
982 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
983 wtx.mapValue["comment"] = params[3].get_str();
985 Array subtractFeeFromAmount;
986 if (params.size() > 4)
987 subtractFeeFromAmount = params[4].get_array();
989 set<CBitcoinAddress> setAddress;
990 vector<CRecipient> vecSend;
992 CAmount totalAmount = 0;
993 BOOST_FOREACH(const Pair& s, sendTo)
995 CBitcoinAddress address(s.name_);
996 if (!address.IsValid())
997 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
999 if (setAddress.count(address))
1000 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
1001 setAddress.insert(address);
1003 CScript scriptPubKey = GetScriptForDestination(address.Get());
1004 CAmount nAmount = AmountFromValue(s.value_);
1005 totalAmount += nAmount;
1007 bool fSubtractFeeFromAmount = false;
1008 BOOST_FOREACH(const Value& addr, subtractFeeFromAmount)
1009 if (addr.get_str() == s.name_)
1010 fSubtractFeeFromAmount = true;
1012 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1013 vecSend.push_back(recipient);
1016 EnsureWalletIsUnlocked();
1019 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1020 if (totalAmount > nBalance)
1021 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1024 CReserveKey keyChange(pwalletMain);
1025 CAmount nFeeRequired = 0;
1026 int nChangePosRet = -1;
1027 string strFailReason;
1028 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1030 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1031 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1032 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1034 return wtx.GetHash().GetHex();
1037 // Defined in rpcmisc.cpp
1038 extern CScript _createmultisig_redeemScript(const Array& params);
1040 Value addmultisigaddress(const Array& params, bool fHelp)
1042 if (!EnsureWalletIsAvailable(fHelp))
1045 if (fHelp || params.size() < 2 || params.size() > 3)
1047 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1048 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1049 "Each key is a Bitcoin address or hex-encoded public key.\n"
1050 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1053 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1054 "2. \"keysobject\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
1056 " \"address\" (string) bitcoin address or hex-encoded public key\n"
1059 "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n"
1062 "\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
1065 "\nAdd a multisig address from 2 addresses\n"
1066 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1067 "\nAs json rpc call\n"
1068 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1070 throw runtime_error(msg);
1073 LOCK2(cs_main, pwalletMain->cs_wallet);
1076 if (params.size() > 2)
1077 strAccount = AccountFromValue(params[2]);
1079 // Construct using pay-to-script-hash:
1080 CScript inner = _createmultisig_redeemScript(params);
1081 CScriptID innerID(inner);
1082 pwalletMain->AddCScript(inner);
1084 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1085 return CBitcoinAddress(innerID).ToString();
1093 vector<uint256> txids;
1098 nConf = std::numeric_limits<int>::max();
1099 fIsWatchonly = false;
1103 Value ListReceived(const Array& params, bool fByAccounts)
1105 // Minimum confirmations
1107 if (params.size() > 0)
1108 nMinDepth = params[0].get_int();
1110 // Whether to include empty accounts
1111 bool fIncludeEmpty = false;
1112 if (params.size() > 1)
1113 fIncludeEmpty = params[1].get_bool();
1115 isminefilter filter = ISMINE_SPENDABLE;
1116 if(params.size() > 2)
1117 if(params[2].get_bool())
1118 filter = filter | ISMINE_WATCH_ONLY;
1121 map<CBitcoinAddress, tallyitem> mapTally;
1122 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1124 const CWalletTx& wtx = (*it).second;
1126 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1129 int nDepth = wtx.GetDepthInMainChain();
1130 if (nDepth < nMinDepth)
1133 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1135 CTxDestination address;
1136 if (!ExtractDestination(txout.scriptPubKey, address))
1139 isminefilter mine = IsMine(*pwalletMain, address);
1140 if(!(mine & filter))
1143 tallyitem& item = mapTally[address];
1144 item.nAmount += txout.nValue;
1145 item.nConf = min(item.nConf, nDepth);
1146 item.txids.push_back(wtx.GetHash());
1147 if (mine & ISMINE_WATCH_ONLY)
1148 item.fIsWatchonly = true;
1154 map<string, tallyitem> mapAccountTally;
1155 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1157 const CBitcoinAddress& address = item.first;
1158 const string& strAccount = item.second.name;
1159 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1160 if (it == mapTally.end() && !fIncludeEmpty)
1163 CAmount nAmount = 0;
1164 int nConf = std::numeric_limits<int>::max();
1165 bool fIsWatchonly = false;
1166 if (it != mapTally.end())
1168 nAmount = (*it).second.nAmount;
1169 nConf = (*it).second.nConf;
1170 fIsWatchonly = (*it).second.fIsWatchonly;
1175 tallyitem& item = mapAccountTally[strAccount];
1176 item.nAmount += nAmount;
1177 item.nConf = min(item.nConf, nConf);
1178 item.fIsWatchonly = fIsWatchonly;
1184 obj.push_back(Pair("involvesWatchonly", true));
1185 obj.push_back(Pair("address", address.ToString()));
1186 obj.push_back(Pair("account", strAccount));
1187 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1188 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1190 if (it != mapTally.end())
1192 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1194 transactions.push_back(item.GetHex());
1197 obj.push_back(Pair("txids", transactions));
1204 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1206 CAmount nAmount = (*it).second.nAmount;
1207 int nConf = (*it).second.nConf;
1209 if((*it).second.fIsWatchonly)
1210 obj.push_back(Pair("involvesWatchonly", true));
1211 obj.push_back(Pair("account", (*it).first));
1212 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1213 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1221 Value listreceivedbyaddress(const Array& params, bool fHelp)
1223 if (!EnsureWalletIsAvailable(fHelp))
1226 if (fHelp || params.size() > 3)
1227 throw runtime_error(
1228 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1229 "\nList balances by receiving address.\n"
1231 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1232 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1233 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1238 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1239 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1240 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1241 " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
1242 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1248 + HelpExampleCli("listreceivedbyaddress", "")
1249 + HelpExampleCli("listreceivedbyaddress", "6 true")
1250 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1253 LOCK2(cs_main, pwalletMain->cs_wallet);
1255 return ListReceived(params, false);
1258 Value listreceivedbyaccount(const Array& params, bool fHelp)
1260 if (!EnsureWalletIsAvailable(fHelp))
1263 if (fHelp || params.size() > 3)
1264 throw runtime_error(
1265 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1266 "\nDEPRECATED. List balances by account.\n"
1268 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1269 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1270 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1275 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1276 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1277 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1278 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1284 + HelpExampleCli("listreceivedbyaccount", "")
1285 + HelpExampleCli("listreceivedbyaccount", "6 true")
1286 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1289 LOCK2(cs_main, pwalletMain->cs_wallet);
1291 return ListReceived(params, true);
1294 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1296 CBitcoinAddress addr;
1298 entry.push_back(Pair("address", addr.ToString()));
1301 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1304 string strSentAccount;
1305 list<COutputEntry> listReceived;
1306 list<COutputEntry> listSent;
1308 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1310 bool fAllAccounts = (strAccount == string("*"));
1311 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1314 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1316 BOOST_FOREACH(const COutputEntry& s, listSent)
1319 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1320 entry.push_back(Pair("involvesWatchonly", true));
1321 entry.push_back(Pair("account", strSentAccount));
1322 MaybePushAddress(entry, s.destination);
1323 entry.push_back(Pair("category", "send"));
1324 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1325 entry.push_back(Pair("vout", s.vout));
1326 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1328 WalletTxToJSON(wtx, entry);
1329 ret.push_back(entry);
1334 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1336 BOOST_FOREACH(const COutputEntry& r, listReceived)
1339 if (pwalletMain->mapAddressBook.count(r.destination))
1340 account = pwalletMain->mapAddressBook[r.destination].name;
1341 if (fAllAccounts || (account == strAccount))
1344 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1345 entry.push_back(Pair("involvesWatchonly", true));
1346 entry.push_back(Pair("account", account));
1347 MaybePushAddress(entry, r.destination);
1348 if (wtx.IsCoinBase())
1350 if (wtx.GetDepthInMainChain() < 1)
1351 entry.push_back(Pair("category", "orphan"));
1352 else if (wtx.GetBlocksToMaturity() > 0)
1353 entry.push_back(Pair("category", "immature"));
1355 entry.push_back(Pair("category", "generate"));
1359 entry.push_back(Pair("category", "receive"));
1361 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1362 entry.push_back(Pair("vout", r.vout));
1364 WalletTxToJSON(wtx, entry);
1365 ret.push_back(entry);
1371 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1373 bool fAllAccounts = (strAccount == string("*"));
1375 if (fAllAccounts || acentry.strAccount == strAccount)
1378 entry.push_back(Pair("account", acentry.strAccount));
1379 entry.push_back(Pair("category", "move"));
1380 entry.push_back(Pair("time", acentry.nTime));
1381 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1382 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1383 entry.push_back(Pair("comment", acentry.strComment));
1384 ret.push_back(entry);
1388 Value listtransactions(const Array& params, bool fHelp)
1390 if (!EnsureWalletIsAvailable(fHelp))
1393 if (fHelp || params.size() > 4)
1394 throw runtime_error(
1395 "listtransactions ( \"account\" count from includeWatchonly)\n"
1396 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1398 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1399 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1400 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1401 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1405 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1406 " It will be \"\" for the default account.\n"
1407 " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n"
1408 " move transactions (category = move).\n"
1409 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1410 " transaction between accounts, and not associated with an address,\n"
1411 " transaction id or block. 'send' and 'receive' transactions are \n"
1412 " associated with an address, transaction id and block details\n"
1413 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1414 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1415 " and for the 'move' category for inbound funds.\n"
1416 " \"vout\" : n, (numeric) the vout value\n"
1417 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1418 " 'send' category of transactions.\n"
1419 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1420 " 'receive' category of transactions.\n"
1421 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1422 " category of transactions.\n"
1423 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1424 " category of transactions.\n"
1425 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1426 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1427 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1428 " for 'send' and 'receive' category of transactions.\n"
1429 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1430 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1431 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1432 " negative amounts).\n"
1437 "\nList the most recent 10 transactions in the systems\n"
1438 + HelpExampleCli("listtransactions", "") +
1439 "\nList transactions 100 to 120\n"
1440 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1441 "\nAs a json rpc call\n"
1442 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1445 LOCK2(cs_main, pwalletMain->cs_wallet);
1447 string strAccount = "*";
1448 if (params.size() > 0)
1449 strAccount = params[0].get_str();
1451 if (params.size() > 1)
1452 nCount = params[1].get_int();
1454 if (params.size() > 2)
1455 nFrom = params[2].get_int();
1456 isminefilter filter = ISMINE_SPENDABLE;
1457 if(params.size() > 3)
1458 if(params[3].get_bool())
1459 filter = filter | ISMINE_WATCH_ONLY;
1462 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1464 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1468 std::list<CAccountingEntry> acentries;
1469 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1471 // iterate backwards until we have nCount items to return:
1472 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1474 CWalletTx *const pwtx = (*it).second.first;
1476 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1477 CAccountingEntry *const pacentry = (*it).second.second;
1479 AcentryToJSON(*pacentry, strAccount, ret);
1481 if ((int)ret.size() >= (nCount+nFrom)) break;
1483 // ret is newest to oldest
1485 if (nFrom > (int)ret.size())
1487 if ((nFrom + nCount) > (int)ret.size())
1488 nCount = ret.size() - nFrom;
1489 Array::iterator first = ret.begin();
1490 std::advance(first, nFrom);
1491 Array::iterator last = ret.begin();
1492 std::advance(last, nFrom+nCount);
1494 if (last != ret.end()) ret.erase(last, ret.end());
1495 if (first != ret.begin()) ret.erase(ret.begin(), first);
1497 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1502 Value listaccounts(const Array& params, bool fHelp)
1504 if (!EnsureWalletIsAvailable(fHelp))
1507 if (fHelp || params.size() > 2)
1508 throw runtime_error(
1509 "listaccounts ( minconf includeWatchonly)\n"
1510 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1512 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1513 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1515 "{ (json object where keys are account names, and values are numeric balances\n"
1516 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1520 "\nList account balances where there at least 1 confirmation\n"
1521 + HelpExampleCli("listaccounts", "") +
1522 "\nList account balances including zero confirmation transactions\n"
1523 + HelpExampleCli("listaccounts", "0") +
1524 "\nList account balances for 6 or more confirmations\n"
1525 + HelpExampleCli("listaccounts", "6") +
1526 "\nAs json rpc call\n"
1527 + HelpExampleRpc("listaccounts", "6")
1530 LOCK2(cs_main, pwalletMain->cs_wallet);
1533 if (params.size() > 0)
1534 nMinDepth = params[0].get_int();
1535 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1536 if(params.size() > 1)
1537 if(params[1].get_bool())
1538 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1540 map<string, CAmount> mapAccountBalances;
1541 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1542 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1543 mapAccountBalances[entry.second.name] = 0;
1546 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1548 const CWalletTx& wtx = (*it).second;
1550 string strSentAccount;
1551 list<COutputEntry> listReceived;
1552 list<COutputEntry> listSent;
1553 int nDepth = wtx.GetDepthInMainChain();
1554 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1556 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1557 mapAccountBalances[strSentAccount] -= nFee;
1558 BOOST_FOREACH(const COutputEntry& s, listSent)
1559 mapAccountBalances[strSentAccount] -= s.amount;
1560 if (nDepth >= nMinDepth)
1562 BOOST_FOREACH(const COutputEntry& r, listReceived)
1563 if (pwalletMain->mapAddressBook.count(r.destination))
1564 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1566 mapAccountBalances[""] += r.amount;
1570 list<CAccountingEntry> acentries;
1571 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1572 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1573 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1576 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1577 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1582 Value listsinceblock(const Array& params, bool fHelp)
1584 if (!EnsureWalletIsAvailable(fHelp))
1588 throw runtime_error(
1589 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1590 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1592 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1593 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1594 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1597 " \"transactions\": [\n"
1598 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1599 " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
1600 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1601 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1602 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1603 " \"vout\" : n, (numeric) the vout value\n"
1604 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1605 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1606 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1607 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1608 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1609 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1610 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1611 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1612 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1613 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1615 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1618 + HelpExampleCli("listsinceblock", "")
1619 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1620 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1623 LOCK2(cs_main, pwalletMain->cs_wallet);
1625 CBlockIndex *pindex = NULL;
1626 int target_confirms = 1;
1627 isminefilter filter = ISMINE_SPENDABLE;
1629 if (params.size() > 0)
1633 blockId.SetHex(params[0].get_str());
1634 BlockMap::iterator it = mapBlockIndex.find(blockId);
1635 if (it != mapBlockIndex.end())
1636 pindex = it->second;
1639 if (params.size() > 1)
1641 target_confirms = params[1].get_int();
1643 if (target_confirms < 1)
1644 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1647 if(params.size() > 2)
1648 if(params[2].get_bool())
1649 filter = filter | ISMINE_WATCH_ONLY;
1651 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1655 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1657 CWalletTx tx = (*it).second;
1659 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1660 ListTransactions(tx, "*", 0, true, transactions, filter);
1663 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1664 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1667 ret.push_back(Pair("transactions", transactions));
1668 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1673 Value gettransaction(const Array& params, bool fHelp)
1675 if (!EnsureWalletIsAvailable(fHelp))
1678 if (fHelp || params.size() < 1 || params.size() > 2)
1679 throw runtime_error(
1680 "gettransaction \"txid\" ( includeWatchonly )\n"
1681 "\nGet detailed information about in-wallet transaction <txid>\n"
1683 "1. \"txid\" (string, required) The transaction id\n"
1684 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1687 " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
1688 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1689 " \"blockhash\" : \"hash\", (string) The block hash\n"
1690 " \"blockindex\" : xx, (numeric) The block index\n"
1691 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1692 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1693 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1694 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1695 " \"details\" : [\n"
1697 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1698 " \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
1699 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1700 " \"amount\" : x.xxx (numeric) The amount in btc\n"
1701 " \"vout\" : n, (numeric) the vout value\n"
1705 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1709 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1710 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1711 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1714 LOCK2(cs_main, pwalletMain->cs_wallet);
1717 hash.SetHex(params[0].get_str());
1719 isminefilter filter = ISMINE_SPENDABLE;
1720 if(params.size() > 1)
1721 if(params[1].get_bool())
1722 filter = filter | ISMINE_WATCH_ONLY;
1725 if (!pwalletMain->mapWallet.count(hash))
1726 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1727 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1729 CAmount nCredit = wtx.GetCredit(filter);
1730 CAmount nDebit = wtx.GetDebit(filter);
1731 CAmount nNet = nCredit - nDebit;
1732 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1734 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1735 if (wtx.IsFromMe(filter))
1736 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1738 WalletTxToJSON(wtx, entry);
1741 ListTransactions(wtx, "*", 0, false, details, filter);
1742 entry.push_back(Pair("details", details));
1744 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
1745 entry.push_back(Pair("hex", strHex));
1751 Value backupwallet(const Array& params, bool fHelp)
1753 if (!EnsureWalletIsAvailable(fHelp))
1756 if (fHelp || params.size() != 1)
1757 throw runtime_error(
1758 "backupwallet \"destination\"\n"
1759 "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
1761 "1. \"destination\" (string) The destination directory or file\n"
1763 + HelpExampleCli("backupwallet", "\"backup.dat\"")
1764 + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1767 LOCK2(cs_main, pwalletMain->cs_wallet);
1769 string strDest = params[0].get_str();
1770 if (!BackupWallet(*pwalletMain, strDest))
1771 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1777 Value keypoolrefill(const Array& params, bool fHelp)
1779 if (!EnsureWalletIsAvailable(fHelp))
1782 if (fHelp || params.size() > 1)
1783 throw runtime_error(
1784 "keypoolrefill ( newsize )\n"
1785 "\nFills the keypool."
1786 + HelpRequiringPassphrase() + "\n"
1788 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1790 + HelpExampleCli("keypoolrefill", "")
1791 + HelpExampleRpc("keypoolrefill", "")
1794 LOCK2(cs_main, pwalletMain->cs_wallet);
1796 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1797 unsigned int kpSize = 0;
1798 if (params.size() > 0) {
1799 if (params[0].get_int() < 0)
1800 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1801 kpSize = (unsigned int)params[0].get_int();
1804 EnsureWalletIsUnlocked();
1805 pwalletMain->TopUpKeyPool(kpSize);
1807 if (pwalletMain->GetKeyPoolSize() < kpSize)
1808 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1814 static void LockWallet(CWallet* pWallet)
1816 LOCK(cs_nWalletUnlockTime);
1817 nWalletUnlockTime = 0;
1821 Value walletpassphrase(const Array& params, bool fHelp)
1823 if (!EnsureWalletIsAvailable(fHelp))
1826 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1827 throw runtime_error(
1828 "walletpassphrase \"passphrase\" timeout\n"
1829 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1830 "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
1832 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1833 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
1835 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1836 "time that overrides the old one.\n"
1838 "\nunlock the wallet for 60 seconds\n"
1839 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1840 "\nLock the wallet again (before 60 seconds)\n"
1841 + HelpExampleCli("walletlock", "") +
1842 "\nAs json rpc call\n"
1843 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1846 LOCK2(cs_main, pwalletMain->cs_wallet);
1850 if (!pwalletMain->IsCrypted())
1851 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1853 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1854 SecureString strWalletPass;
1855 strWalletPass.reserve(100);
1856 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1857 // Alternately, find a way to make params[0] mlock()'d to begin with.
1858 strWalletPass = params[0].get_str().c_str();
1860 if (strWalletPass.length() > 0)
1862 if (!pwalletMain->Unlock(strWalletPass))
1863 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1866 throw runtime_error(
1867 "walletpassphrase <passphrase> <timeout>\n"
1868 "Stores the wallet decryption key in memory for <timeout> seconds.");
1870 pwalletMain->TopUpKeyPool();
1872 int64_t nSleepTime = params[1].get_int64();
1873 LOCK(cs_nWalletUnlockTime);
1874 nWalletUnlockTime = GetTime() + nSleepTime;
1875 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
1881 Value walletpassphrasechange(const Array& params, bool fHelp)
1883 if (!EnsureWalletIsAvailable(fHelp))
1886 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1887 throw runtime_error(
1888 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1889 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1891 "1. \"oldpassphrase\" (string) The current passphrase\n"
1892 "2. \"newpassphrase\" (string) The new passphrase\n"
1894 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1895 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1898 LOCK2(cs_main, pwalletMain->cs_wallet);
1902 if (!pwalletMain->IsCrypted())
1903 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1905 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1906 // Alternately, find a way to make params[0] mlock()'d to begin with.
1907 SecureString strOldWalletPass;
1908 strOldWalletPass.reserve(100);
1909 strOldWalletPass = params[0].get_str().c_str();
1911 SecureString strNewWalletPass;
1912 strNewWalletPass.reserve(100);
1913 strNewWalletPass = params[1].get_str().c_str();
1915 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1916 throw runtime_error(
1917 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1918 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1920 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1921 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1927 Value walletlock(const Array& params, bool fHelp)
1929 if (!EnsureWalletIsAvailable(fHelp))
1932 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1933 throw runtime_error(
1935 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
1936 "After calling this method, you will need to call walletpassphrase again\n"
1937 "before being able to call any methods which require the wallet to be unlocked.\n"
1939 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1940 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1941 "\nPerform a send (requires passphrase set)\n"
1942 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1943 "\nClear the passphrase since we are done before 2 minutes is up\n"
1944 + HelpExampleCli("walletlock", "") +
1945 "\nAs json rpc call\n"
1946 + HelpExampleRpc("walletlock", "")
1949 LOCK2(cs_main, pwalletMain->cs_wallet);
1953 if (!pwalletMain->IsCrypted())
1954 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1957 LOCK(cs_nWalletUnlockTime);
1958 pwalletMain->Lock();
1959 nWalletUnlockTime = 0;
1966 Value encryptwallet(const Array& params, bool fHelp)
1968 if (!EnsureWalletIsAvailable(fHelp))
1971 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1972 throw runtime_error(
1973 "encryptwallet \"passphrase\"\n"
1974 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
1975 "After this, any calls that interact with private keys such as sending or signing \n"
1976 "will require the passphrase to be set prior the making these calls.\n"
1977 "Use the walletpassphrase call for this, and then walletlock call.\n"
1978 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
1979 "Note that this will shutdown the server.\n"
1981 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
1983 "\nEncrypt you wallet\n"
1984 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
1985 "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
1986 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
1987 "\nNow we can so something like sign\n"
1988 + HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
1989 "\nNow lock the wallet again by removing the passphrase\n"
1990 + HelpExampleCli("walletlock", "") +
1991 "\nAs a json rpc call\n"
1992 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
1995 LOCK2(cs_main, pwalletMain->cs_wallet);
1999 if (pwalletMain->IsCrypted())
2000 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2002 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2003 // Alternately, find a way to make params[0] mlock()'d to begin with.
2004 SecureString strWalletPass;
2005 strWalletPass.reserve(100);
2006 strWalletPass = params[0].get_str().c_str();
2008 if (strWalletPass.length() < 1)
2009 throw runtime_error(
2010 "encryptwallet <passphrase>\n"
2011 "Encrypts the wallet with <passphrase>.");
2013 if (!pwalletMain->EncryptWallet(strWalletPass))
2014 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2016 // BDB seems to have a bad habit of writing old data into
2017 // slack space in .dat files; that is bad if the old data is
2018 // unencrypted private keys. So:
2020 return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2023 Value lockunspent(const Array& params, bool fHelp)
2025 if (!EnsureWalletIsAvailable(fHelp))
2028 if (fHelp || params.size() < 1 || params.size() > 2)
2029 throw runtime_error(
2030 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2031 "\nUpdates list of temporarily unspendable outputs.\n"
2032 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2033 "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
2034 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2035 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2036 "Also see the listunspent call\n"
2038 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2039 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2040 " [ (json array of json objects)\n"
2042 " \"txid\":\"id\", (string) The transaction id\n"
2043 " \"vout\": n (numeric) The output number\n"
2049 "true|false (boolean) Whether the command was successful or not\n"
2052 "\nList the unspent transactions\n"
2053 + HelpExampleCli("listunspent", "") +
2054 "\nLock an unspent transaction\n"
2055 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2056 "\nList the locked transactions\n"
2057 + HelpExampleCli("listlockunspent", "") +
2058 "\nUnlock the transaction again\n"
2059 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2060 "\nAs a json rpc call\n"
2061 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2064 LOCK2(cs_main, pwalletMain->cs_wallet);
2066 if (params.size() == 1)
2067 RPCTypeCheck(params, boost::assign::list_of(bool_type));
2069 RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type));
2071 bool fUnlock = params[0].get_bool();
2073 if (params.size() == 1) {
2075 pwalletMain->UnlockAllCoins();
2079 Array outputs = params[1].get_array();
2080 BOOST_FOREACH(Value& output, outputs)
2082 if (output.type() != obj_type)
2083 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2084 const Object& o = output.get_obj();
2086 RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type));
2088 string txid = find_value(o, "txid").get_str();
2090 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2092 int nOutput = find_value(o, "vout").get_int();
2094 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2096 COutPoint outpt(uint256S(txid), nOutput);
2099 pwalletMain->UnlockCoin(outpt);
2101 pwalletMain->LockCoin(outpt);
2107 Value listlockunspent(const Array& params, bool fHelp)
2109 if (!EnsureWalletIsAvailable(fHelp))
2112 if (fHelp || params.size() > 0)
2113 throw runtime_error(
2115 "\nReturns list of temporarily unspendable outputs.\n"
2116 "See the lockunspent call to lock and unlock transactions for spending.\n"
2120 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2121 " \"vout\" : n (numeric) The vout value\n"
2126 "\nList the unspent transactions\n"
2127 + HelpExampleCli("listunspent", "") +
2128 "\nLock an unspent transaction\n"
2129 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2130 "\nList the locked transactions\n"
2131 + HelpExampleCli("listlockunspent", "") +
2132 "\nUnlock the transaction again\n"
2133 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2134 "\nAs a json rpc call\n"
2135 + HelpExampleRpc("listlockunspent", "")
2138 LOCK2(cs_main, pwalletMain->cs_wallet);
2140 vector<COutPoint> vOutpts;
2141 pwalletMain->ListLockedCoins(vOutpts);
2145 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2148 o.push_back(Pair("txid", outpt.hash.GetHex()));
2149 o.push_back(Pair("vout", (int)outpt.n));
2156 Value settxfee(const Array& params, bool fHelp)
2158 if (!EnsureWalletIsAvailable(fHelp))
2161 if (fHelp || params.size() < 1 || params.size() > 1)
2162 throw runtime_error(
2164 "\nSet the transaction fee per kB.\n"
2166 "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
2168 "true|false (boolean) Returns true if successful\n"
2170 + HelpExampleCli("settxfee", "0.00001")
2171 + HelpExampleRpc("settxfee", "0.00001")
2174 LOCK2(cs_main, pwalletMain->cs_wallet);
2177 CAmount nAmount = 0;
2178 if (params[0].get_real() != 0.0)
2179 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
2181 payTxFee = CFeeRate(nAmount, 1000);
2185 Value getwalletinfo(const Array& params, bool fHelp)
2187 if (!EnsureWalletIsAvailable(fHelp))
2190 if (fHelp || params.size() != 0)
2191 throw runtime_error(
2193 "Returns an object containing various wallet state info.\n"
2196 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2197 " \"balance\": xxxxxxx, (numeric) the total confirmed bitcoin balance of the wallet\n"
2198 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed bitcoin balance of the wallet\n"
2199 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
2200 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2201 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2202 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2203 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
2206 + HelpExampleCli("getwalletinfo", "")
2207 + HelpExampleRpc("getwalletinfo", "")
2210 LOCK2(cs_main, pwalletMain->cs_wallet);
2213 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2214 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2215 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2216 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2217 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2218 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2219 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2220 if (pwalletMain->IsCrypted())
2221 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2225 Value resendwallettransactions(const Array& params, bool fHelp)
2227 if (!EnsureWalletIsAvailable(fHelp))
2230 if (fHelp || params.size() != 0)
2231 throw runtime_error(
2232 "resendwallettransactions\n"
2233 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2234 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2236 "Returns array of transaction ids that were re-broadcast.\n"
2239 LOCK2(cs_main, pwalletMain->cs_wallet);
2241 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2243 BOOST_FOREACH(const uint256& txid, txids)
2245 result.push_back(txid.ToString());
2250 Value listunspent(const Array& params, bool fHelp)
2252 if (!EnsureWalletIsAvailable(fHelp))
2255 if (fHelp || params.size() > 3)
2256 throw runtime_error(
2257 "listunspent ( minconf maxconf [\"address\",...] )\n"
2258 "\nReturns array of unspent transaction outputs\n"
2259 "with between minconf and maxconf (inclusive) confirmations.\n"
2260 "Optionally filter to only include txouts paid to specified addresses.\n"
2261 "Results are an array of Objects, each of which has:\n"
2262 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2264 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2265 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2266 "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
2268 " \"address\" (string) bitcoin address\n"
2272 "[ (array of json object)\n"
2274 " \"txid\" : \"txid\", (string) the transaction id \n"
2275 " \"vout\" : n, (numeric) the vout value\n"
2276 " \"address\" : \"address\", (string) the bitcoin address\n"
2277 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2278 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2279 " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
2280 " \"confirmations\" : n (numeric) The number of confirmations\n"
2286 + HelpExampleCli("listunspent", "")
2287 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2288 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2291 RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type));
2294 if (params.size() > 0)
2295 nMinDepth = params[0].get_int();
2297 int nMaxDepth = 9999999;
2298 if (params.size() > 1)
2299 nMaxDepth = params[1].get_int();
2301 set<CBitcoinAddress> setAddress;
2302 if (params.size() > 2) {
2303 Array inputs = params[2].get_array();
2304 BOOST_FOREACH(Value& input, inputs) {
2305 CBitcoinAddress address(input.get_str());
2306 if (!address.IsValid())
2307 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
2308 if (setAddress.count(address))
2309 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2310 setAddress.insert(address);
2315 vector<COutput> vecOutputs;
2316 assert(pwalletMain != NULL);
2317 LOCK2(cs_main, pwalletMain->cs_wallet);
2318 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2319 BOOST_FOREACH(const COutput& out, vecOutputs) {
2320 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2323 if (setAddress.size()) {
2324 CTxDestination address;
2325 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2328 if (!setAddress.count(address))
2332 CAmount nValue = out.tx->vout[out.i].nValue;
2333 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2335 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2336 entry.push_back(Pair("vout", out.i));
2337 CTxDestination address;
2338 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2339 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2340 if (pwalletMain->mapAddressBook.count(address))
2341 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2343 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2344 if (pk.IsPayToScriptHash()) {
2345 CTxDestination address;
2346 if (ExtractDestination(pk, address)) {
2347 const CScriptID& hash = boost::get<CScriptID>(address);
2348 CScript redeemScript;
2349 if (pwalletMain->GetCScript(hash, redeemScript))
2350 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2353 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2354 entry.push_back(Pair("confirmations",out.nDepth));
2355 entry.push_back(Pair("spendable", out.fSpendable));
2356 results.push_back(entry);
2362 Value zc_sample_joinsplit(const json_spirit::Array& params, bool fHelp)
2365 throw runtime_error(
2366 "zcsamplejoinsplit\n"
2368 "Perform a joinsplit and return the JSDescription.\n"
2375 uint256 anchor = ZCIncrementalMerkleTree().root();
2376 JSDescription samplejoinsplit(*pzcashParams,
2379 {JSInput(), JSInput()},
2380 {JSOutput(), JSOutput()},
2384 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2385 ss << samplejoinsplit;
2387 return HexStr(ss.begin(), ss.end());
2390 Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
2392 if (!EnsureWalletIsAvailable(fHelp)) {
2396 if (fHelp || params.size() < 2) {
2397 throw runtime_error(
2398 "zcbenchmark benchmarktype samplecount\n"
2400 "Runs a benchmark of the selected type samplecount times,\n"
2401 "returning the running times of each sample.\n"
2405 " \"runningtime\": runningtime\n"
2408 " \"runningtime\": runningtime\n"
2417 std::string benchmarktype = params[0].get_str();
2418 int samplecount = params[1].get_int();
2420 if (samplecount <= 0) {
2421 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2424 std::vector<double> sample_times;
2426 if (benchmarktype == "createjoinsplit") {
2427 /* Load the proving now key so that it doesn't happen as part of the
2428 * first joinsplit. */
2429 pzcashParams->loadProvingKey();
2432 JSDescription samplejoinsplit;
2434 if (benchmarktype == "verifyjoinsplit") {
2435 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2436 ss >> samplejoinsplit;
2439 for (int i = 0; i < samplecount; i++) {
2440 if (benchmarktype == "sleep") {
2441 sample_times.push_back(benchmark_sleep());
2442 } else if (benchmarktype == "parameterloading") {
2443 sample_times.push_back(benchmark_parameter_loading());
2444 } else if (benchmarktype == "createjoinsplit") {
2445 sample_times.push_back(benchmark_create_joinsplit());
2446 } else if (benchmarktype == "verifyjoinsplit") {
2447 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2448 } else if (benchmarktype == "solveequihash") {
2449 if (params.size() < 3) {
2450 sample_times.push_back(benchmark_solve_equihash(true));
2452 int nThreads = params[2].get_int();
2453 sample_times.push_back(benchmark_solve_equihash_threaded(nThreads));
2455 } else if (benchmarktype == "verifyequihash") {
2456 sample_times.push_back(benchmark_verify_equihash());
2457 } else if (benchmarktype == "validatelargetx") {
2458 sample_times.push_back(benchmark_large_tx());
2460 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2465 for (int i = 0; i < samplecount; i++) {
2467 result.push_back(Pair("runningtime", sample_times.at(i)));
2468 results.push_back(result);
2474 Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
2476 if (!EnsureWalletIsAvailable(fHelp)) {
2480 if (fHelp || params.size() != 2) {
2481 throw runtime_error(
2482 "zcrawreceive zcsecretkey encryptednote\n"
2484 "Scheduled for deprecation. This call will be removed in 1.0.\n"
2485 "Decrypts encryptednote and checks if the coin commitments\n"
2486 "are in the blockchain as indicated by the \"exists\" result.\n"
2489 " \"amount\": value,\n"
2490 " \"note\": noteplaintext,\n"
2491 " \"exists\": exists\n"
2496 RPCTypeCheck(params, boost::assign::list_of(str_type)(str_type));
2500 CZCSpendingKey spendingkey(params[0].get_str());
2501 SpendingKey k = spendingkey.Get();
2504 unsigned char nonce;
2505 ZCNoteEncryption::Ciphertext ct;
2509 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2515 } catch(const std::exception &) {
2516 throw runtime_error(
2517 "encrypted_note could not be decoded"
2522 ZCNoteDecryption decryptor(k.viewing_key());
2524 NotePlaintext npt = NotePlaintext::decrypt(
2531 PaymentAddress payment_addr = k.address();
2532 Note decrypted_note = npt.note(payment_addr);
2534 assert(pwalletMain != NULL);
2535 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2537 uint256 commitment = decrypted_note.cm();
2538 pwalletMain->WitnessNoteCommitment(
2544 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2548 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2549 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2550 result.push_back(Pair("exists", (bool) witnesses[0]));
2556 Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp)
2558 if (!EnsureWalletIsAvailable(fHelp)) {
2562 if (fHelp || params.size() != 5) {
2563 throw runtime_error(
2564 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
2565 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
2566 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2568 "Scheduled for deprecation. This call will be removed in 1.0.\n"
2569 "Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
2570 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2571 "vpub_new values are globally public and move transparent value into\n"
2572 "or out of the confidential value store, respectively.\n"
2574 "Note: The caller is responsible for delivering the output enc1 and\n"
2575 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2576 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2577 "payments in-band on the blockchain.)\n"
2580 " \"encryptednote1\": enc1,\n"
2581 " \"encryptednote2\": enc2,\n"
2582 " \"rawtxn\": rawtxout\n"
2590 if (!DecodeHexTx(tx, params[0].get_str()))
2591 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2593 Object inputs = params[1].get_obj();
2594 Object outputs = params[2].get_obj();
2596 CAmount vpub_old(0);
2597 CAmount vpub_new(0);
2599 if (params[3].get_real() != 0.0)
2600 vpub_old = AmountFromValue(params[3]);
2602 if (params[4].get_real() != 0.0)
2603 vpub_new = AmountFromValue(params[4]);
2605 std::vector<JSInput> vjsin;
2606 std::vector<JSOutput> vjsout;
2607 std::vector<Note> notes;
2608 std::vector<SpendingKey> keys;
2609 std::vector<uint256> commitments;
2611 BOOST_FOREACH(const Pair& s, inputs)
2613 CZCSpendingKey spendingkey(s.value_.get_str());
2614 SpendingKey k = spendingkey.Get();
2621 CDataStream ssData(ParseHexV(s.name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2625 PaymentAddress addr = k.address();
2626 Note note = npt.note(addr);
2627 notes.push_back(note);
2628 commitments.push_back(note.cm());
2632 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2633 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2635 assert(witnesses.size() == notes.size());
2636 assert(notes.size() == keys.size());
2639 for (size_t i = 0; i < witnesses.size(); i++) {
2640 if (!witnesses[i]) {
2641 throw runtime_error(
2642 "joinsplit input could not be found in tree"
2646 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2650 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2651 vjsin.push_back(JSInput());
2654 BOOST_FOREACH(const Pair& s, outputs)
2656 CZCPaymentAddress pubaddr(s.name_);
2657 PaymentAddress addrTo = pubaddr.Get();
2658 CAmount nAmount = AmountFromValue(s.value_);
2660 vjsout.push_back(JSOutput(addrTo, nAmount));
2663 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2664 vjsout.push_back(JSOutput());
2668 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2669 throw runtime_error("unsupported joinsplit input/output counts");
2672 uint256 joinSplitPubKey;
2673 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2674 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
2676 CMutableTransaction mtx(tx);
2678 mtx.joinSplitPubKey = joinSplitPubKey;
2680 JSDescription jsdesc(*pzcashParams,
2683 {vjsin[0], vjsin[1]},
2684 {vjsout[0], vjsout[1]},
2688 assert(jsdesc.Verify(*pzcashParams, joinSplitPubKey));
2690 mtx.vjoinsplit.push_back(jsdesc);
2692 // Empty output script.
2694 CTransaction signTx(mtx);
2695 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
2697 // Add the signature
2698 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2699 dataToBeSigned.begin(), 32,
2704 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2705 dataToBeSigned.begin(), 32,
2706 mtx.joinSplitPubKey.begin()
2709 CTransaction rawTx(mtx);
2711 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2714 std::string encryptedNote1;
2715 std::string encryptedNote2;
2717 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2718 ss2 << ((unsigned char) 0x00);
2719 ss2 << jsdesc.ephemeralKey;
2720 ss2 << jsdesc.ciphertexts[0];
2721 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2723 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
2726 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2727 ss2 << ((unsigned char) 0x01);
2728 ss2 << jsdesc.ephemeralKey;
2729 ss2 << jsdesc.ciphertexts[1];
2730 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2732 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
2736 result.push_back(Pair("encryptednote1", encryptedNote1));
2737 result.push_back(Pair("encryptednote2", encryptedNote2));
2738 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2742 Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp)
2744 if (!EnsureWalletIsAvailable(fHelp)) {
2748 if (fHelp || params.size() != 0) {
2749 throw runtime_error(
2752 "Scheduled for deprecation. This call will be removed in 1.0.\n"
2753 "Generate a zcaddr which can send and receive confidential values.\n"
2756 " \"zcaddress\": zcaddr,\n"
2757 " \"zcsecretkey\": zcsecretkey,\n"
2762 auto k = SpendingKey::random();
2763 auto addr = k.address();
2764 auto viewing_key = k.viewing_key();
2766 CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
2768 viewing << viewing_key;
2770 CZCPaymentAddress pubaddr(addr);
2771 CZCSpendingKey spendingkey(k);
2772 std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
2775 result.push_back(Pair("zcaddress", pubaddr.ToString()));
2776 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2777 result.push_back(Pair("zcviewingkey", viewing_hex));
2782 Value z_getnewaddress(const Array& params, bool fHelp)
2784 if (!EnsureWalletIsAvailable(fHelp))
2787 if (fHelp || params.size() > 1)
2788 throw runtime_error(
2790 "\nReturns a new zaddr for receiving payments.\n"
2793 "\"zcashaddress\" (string) The new zaddr\n"
2795 + HelpExampleCli("z_getnewaddress", "")
2796 + HelpExampleRpc("z_getnewaddress", "")
2799 LOCK2(cs_main, pwalletMain->cs_wallet);
2801 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2802 std::string result = pubaddr.ToString();
2807 Value z_listaddresses(const Array& params, bool fHelp)
2809 if (!EnsureWalletIsAvailable(fHelp))
2812 if (fHelp || params.size() > 1)
2813 throw runtime_error(
2815 "\nReturns the list of zaddr belonging to the wallet.\n"
2818 "[ (json array of string)\n"
2819 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2823 + HelpExampleCli("z_listaddresses", "")
2824 + HelpExampleRpc("z_listaddresses", "")
2827 LOCK2(cs_main, pwalletMain->cs_wallet);
2830 std::set<libzcash::PaymentAddress> addresses;
2831 pwalletMain->GetPaymentAddresses(addresses);
2832 for (auto addr : addresses ) {
2833 ret.push_back(CZCPaymentAddress(addr).ToString());
2838 CAmount getBalanceTaddr(std::string transparentAddress, size_t minDepth=1) {
2839 set<CBitcoinAddress> setAddress;
2840 vector<COutput> vecOutputs;
2841 CAmount balance = 0;
2843 if (transparentAddress.length() > 0) {
2844 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
2845 if (!taddr.IsValid()) {
2846 throw std::runtime_error("invalid transparent address");
2848 setAddress.insert(taddr);
2851 LOCK2(cs_main, pwalletMain->cs_wallet);
2853 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2855 BOOST_FOREACH(const COutput& out, vecOutputs) {
2856 if (out.nDepth < minDepth) {
2860 if (setAddress.size()) {
2861 CTxDestination address;
2862 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2866 if (!setAddress.count(address)) {
2871 CAmount nValue = out.tx->vout[out.i].nValue;
2877 CAmount getBalanceZaddr(std::string address, size_t minDepth=1)
2879 CAmount balance = 0;
2880 bool fFilterAddress = false;
2881 PaymentAddress filterPaymentAddress;
2882 if (address.length()>0) {
2883 filterPaymentAddress = CZCPaymentAddress(address).Get();
2884 fFilterAddress = true;
2887 LOCK2(cs_main, pwalletMain->cs_wallet);
2889 for (auto & p : pwalletMain->mapWallet) {
2890 CWalletTx wtx = p.second;
2892 // Filter the transactions before checking for notes
2893 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth) {
2897 mapNoteData_t mapNoteData = pwalletMain->FindMyNotes(wtx);
2899 if (mapNoteData.size() == 0) {
2903 for (auto & pair : mapNoteData) {
2904 JSOutPoint jsop = pair.first;
2905 CNoteData nd = pair.second;
2906 PaymentAddress pa = nd.address;
2908 // skip notes which belong to a different payment address in the wallet
2909 if (fFilterAddress && !(pa == filterPaymentAddress)) {
2913 // skip note which has been spent
2914 if (pwalletMain->IsSpent(nd.nullifier)) {
2918 int i = jsop.js; // Index into CTransaction.vjoinsplit
2919 int j = jsop.n; // Index into JSDescription.ciphertexts
2921 // Get cached decryptor
2922 ZCNoteDecryption decryptor;
2923 if (!pwalletMain->GetNoteDecryptor(pa, decryptor)) {
2924 // Note decryptors are created when the wallet is loaded, so it should always exist
2925 throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", CZCPaymentAddress(pa).ToString()));
2928 // determine amount of funds in the note
2929 auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey);
2931 NotePlaintext plaintext = NotePlaintext::decrypt(
2933 wtx.vjoinsplit[i].ciphertexts[j],
2934 wtx.vjoinsplit[i].ephemeralKey,
2938 balance += CAmount(plaintext.value);
2940 } catch (const std::exception &) {
2941 // Couldn't decrypt with this spending key
2942 throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", CZCPaymentAddress(pa).ToString()));
2951 Value z_getbalance(const Array& params, bool fHelp)
2953 if (!EnsureWalletIsAvailable(fHelp))
2956 if (fHelp || params.size()==0 || params.size() >2)
2957 throw runtime_error(
2958 "z_getbalance \"address\" ( minconf )\n"
2959 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
2961 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
2962 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
2964 "amount (numeric) The total amount in ZEC received for this address.\n"
2966 "\nThe total amount received by address \"myaddress\"\n"
2967 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
2968 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
2969 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
2970 "\nAs a json rpc call\n"
2971 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
2974 LOCK2(cs_main, pwalletMain->cs_wallet);
2977 if (params.size() > 1) {
2978 nMinDepth = params[1].get_int();
2981 // Check that the from address is valid.
2982 auto fromaddress = params[0].get_str();
2983 bool fromTaddr = false;
2984 CBitcoinAddress taddr(fromaddress);
2985 fromTaddr = taddr.IsValid();
2986 libzcash::PaymentAddress zaddr;
2988 CZCPaymentAddress address(fromaddress);
2990 zaddr = address.Get();
2991 } catch (std::runtime_error) {
2992 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
2996 CAmount nBalance = 0;
2998 nBalance = getBalanceTaddr(fromaddress, nMinDepth);
3000 nBalance = getBalanceZaddr(fromaddress, nMinDepth);
3003 return ValueFromAmount(nBalance);
3007 Value z_gettotalbalance(const Array& params, bool fHelp)
3009 if (!EnsureWalletIsAvailable(fHelp))
3012 if (fHelp || params.size() > 1)
3013 throw runtime_error(
3014 "z_gettotalbalance ( minconf )\n"
3015 "\nReturn the total value of funds stored in the node’s wallet.\n"
3017 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3020 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3021 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3022 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3025 "\nThe total amount in the wallet\n"
3026 + HelpExampleCli("z_gettotalbalance", "") +
3027 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3028 + HelpExampleCli("z_gettotalbalance", "5") +
3029 "\nAs a json rpc call\n"
3030 + HelpExampleRpc("z_gettotalbalance", "5")
3033 LOCK2(cs_main, pwalletMain->cs_wallet);
3036 if (params.size() == 1) {
3037 nMinDepth = params[0].get_int();
3040 // getbalance and "getbalance * 1 true" should return the same number
3041 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3042 // pwalletMain->GetBalance() does not accept min depth parameter
3043 // so we use our own method to get balance of utxos.
3044 CAmount nBalance = getBalanceTaddr("", nMinDepth);
3045 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
3046 CAmount nTotalBalance = nBalance + nPrivateBalance;
3048 result.push_back(Pair("transparent", FormatMoney(nBalance, false)));
3049 result.push_back(Pair("private", FormatMoney(nPrivateBalance, false)));
3050 result.push_back(Pair("total", FormatMoney(nTotalBalance, false)));
3054 Value z_getoperationresult(const Array& params, bool fHelp)
3056 if (!EnsureWalletIsAvailable(fHelp))
3059 if (fHelp || params.size() > 1)
3060 throw runtime_error(
3061 "z_getoperationresult ([\"operationid\", ... ]) \n"
3062 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3063 + HelpRequiringPassphrase() + "\n"
3065 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3067 "\" [object, ...]\" (array) A list of JSON objects\n"
3070 // This call will remove finished operations
3071 return z_getoperationstatus_IMPL(params, true);
3074 Value z_getoperationstatus(const Array& params, bool fHelp)
3076 if (!EnsureWalletIsAvailable(fHelp))
3079 if (fHelp || params.size() > 1)
3080 throw runtime_error(
3081 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3082 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3083 + HelpRequiringPassphrase() + "\n"
3085 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3087 "\" [object, ...]\" (array) A list of JSON objects\n"
3090 // This call is idempotent so we don't want to remove finished operations
3091 return z_getoperationstatus_IMPL(params, false);
3094 Value z_getoperationstatus_IMPL(const Array& params, bool fRemoveFinishedOperations=false)
3096 LOCK2(cs_main, pwalletMain->cs_wallet);
3098 std::set<AsyncRPCOperationId> filter;
3099 if (params.size()==1) {
3100 Array ids = params[0].get_array();
3101 for (Value & v : ids) {
3102 filter.insert(v.get_str());
3105 bool useFilter = (filter.size()>0);
3108 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3109 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3111 for (auto id : ids) {
3112 if (useFilter && !filter.count(id))
3115 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3118 // It's possible that the operation was removed from the internal queue and map during this loop
3119 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3122 Value status = operation->getStatus();
3124 if (fRemoveFinishedOperations) {
3125 // Caller is only interested in retrieving finished results
3126 if (operation->isSuccess() || operation->isFailed() || operation->isCancelled()) {
3127 ret.push_back(status);
3128 q->popOperationForId(id);
3131 ret.push_back(status);
3138 Value z_sendmany(const Array& params, bool fHelp)
3140 if (!EnsureWalletIsAvailable(fHelp))
3143 if (fHelp || params.size() < 2 || params.size() > 3)
3144 throw runtime_error(
3145 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf )\n"
3146 "\nSend multiple times. Amounts are double-precision floating point numbers."
3147 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3148 + HelpRequiringPassphrase() + "\n"
3150 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3151 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3153 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3154 " \"amount\":amount (numeric, required) The numeric amount in ZEC is the value\n"
3155 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3157 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3159 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3162 LOCK2(cs_main, pwalletMain->cs_wallet);
3164 // Check that the from address is valid.
3165 auto fromaddress = params[0].get_str();
3166 bool fromTaddr = false;
3167 CBitcoinAddress taddr(fromaddress);
3168 fromTaddr = taddr.IsValid();
3169 libzcash::PaymentAddress zaddr;
3171 CZCPaymentAddress address(fromaddress);
3173 zaddr = address.Get();
3174 } catch (std::runtime_error) {
3176 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3180 // Check that we have the spending key
3182 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3183 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3187 Array outputs = params[1].get_array();
3189 if (outputs.size()==0)
3190 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3192 // Keep track of addresses to spot duplicates
3193 set<std::string> setAddress;
3196 std::vector<SendManyRecipient> taddrRecipients;
3197 std::vector<SendManyRecipient> zaddrRecipients;
3199 BOOST_FOREACH(Value& output, outputs)
3201 if (output.type() != obj_type)
3202 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3203 const Object& o = output.get_obj();
3205 RPCTypeCheck(o, boost::assign::map_list_of("address", str_type)("amount", real_type));
3207 // sanity check, report error if unknown key-value pairs
3208 for (const Pair& p : o) {
3209 std::string s = p.name_;
3210 if (s != "address" && s != "amount" && s!="memo")
3211 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3214 string address = find_value(o, "address").get_str();
3215 bool isZaddr = false;
3216 CBitcoinAddress taddr(address);
3217 if (!taddr.IsValid()) {
3219 CZCPaymentAddress zaddr(address);
3222 } catch (std::runtime_error) {
3223 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3227 if (setAddress.count(address))
3228 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3229 setAddress.insert(address);
3231 Value memoValue = find_value(o, "memo");
3233 if (!memoValue.is_null()) {
3234 memo = memoValue.get_str();
3236 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3237 } else if (!IsHex(memo)) {
3238 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3240 std::vector<unsigned char> vMemo = ParseHex(memo);
3241 if (vMemo.size() > ZC_MEMO_SIZE) {
3242 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3246 Value av = find_value(o, "amount");
3247 CAmount nAmount = AmountFromValue( av );
3249 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3252 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3254 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3258 // Minimum confirmations
3260 if (params.size() > 2)
3261 nMinDepth = params[2].get_int();
3263 // Create operation and add to global queue
3264 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3265 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth) );
3266 q->addOperation(operation);
3267 AsyncRPCOperationId operationId = operation->getId();
3272 Value z_listoperationids(const Array& params, bool fHelp)
3274 if (!EnsureWalletIsAvailable(fHelp))
3277 if (fHelp || params.size() > 1)
3278 throw runtime_error(
3279 "z_listoperationids\n"
3280 "\nReturns the list of operation ids currently known to the wallet.\n"
3282 "1. \"status\" (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
3284 "[ (json array of string)\n"
3285 " \"operationid\" (string) an operation id belonging to the wallet\n"
3289 + HelpExampleCli("z_listoperationids", "")
3290 + HelpExampleRpc("z_listoperationids", "")
3293 LOCK2(cs_main, pwalletMain->cs_wallet);
3296 bool useFilter = false;
3297 if (params.size()==1) {
3298 filter = params[0].get_str();
3303 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3304 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3305 for (auto id : ids) {
3306 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3310 std::string state = operation->getStateAsString();
3311 if (useFilter && filter.compare(state)!=0)