]> Git Repo - VerusCoin.git/blob - src/wallet/rpcwallet.cpp
Auto merge of #2342 - bitcartel:1081__mempoolpatch, r=str4d
[VerusCoin.git] / src / wallet / rpcwallet.cpp
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.
5
6 #include "amount.h"
7 #include "base58.h"
8 #include "core_io.h"
9 #include "init.h"
10 #include "main.h"
11 #include "net.h"
12 #include "netbase.h"
13 #include "rpcserver.h"
14 #include "timedata.h"
15 #include "util.h"
16 #include "utilmoneystr.h"
17 #include "wallet.h"
18 #include "walletdb.h"
19 #include "primitives/transaction.h"
20 #include "zcbenchmarks.h"
21 #include "script/interpreter.h"
22
23 #include "utiltime.h"
24 #include "asyncrpcoperation.h"
25 #include "asyncrpcqueue.h"
26 #include "wallet/asyncrpcoperation_sendmany.h"
27
28 #include "sodium.h"
29
30 #include <stdint.h>
31
32 #include <boost/assign/list_of.hpp>
33
34 #include <univalue.h>
35
36 #include <numeric>
37
38 using namespace std;
39
40 using namespace libzcash;
41
42 extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
43
44 int64_t nWalletUnlockTime;
45 static CCriticalSection cs_nWalletUnlockTime;
46
47 // Private method:
48 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
49
50 std::string HelpRequiringPassphrase()
51 {
52     return pwalletMain && pwalletMain->IsCrypted()
53         ? "\nRequires wallet passphrase to be set with walletpassphrase call."
54         : "";
55 }
56
57 bool EnsureWalletIsAvailable(bool avoidException)
58 {
59     if (!pwalletMain)
60     {
61         if (!avoidException)
62             throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
63         else
64             return false;
65     }
66     return true;
67 }
68
69 void EnsureWalletIsUnlocked()
70 {
71     if (pwalletMain->IsLocked())
72         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
73 }
74
75 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
76 {
77     int confirms = wtx.GetDepthInMainChain();
78     entry.push_back(Pair("confirmations", confirms));
79     if (wtx.IsCoinBase())
80         entry.push_back(Pair("generated", true));
81     if (confirms > 0)
82     {
83         entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
84         entry.push_back(Pair("blockindex", wtx.nIndex));
85         entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
86     }
87     uint256 hash = wtx.GetHash();
88     entry.push_back(Pair("txid", hash.GetHex()));
89     UniValue conflicts(UniValue::VARR);
90     BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
91         conflicts.push_back(conflict.GetHex());
92     entry.push_back(Pair("walletconflicts", conflicts));
93     entry.push_back(Pair("time", wtx.GetTxTime()));
94     entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
95     BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
96         entry.push_back(Pair(item.first, item.second));
97
98     entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
99 }
100
101 string AccountFromValue(const UniValue& value)
102 {
103     string strAccount = value.get_str();
104     if (strAccount != "")
105         throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
106     return strAccount;
107 }
108
109 UniValue getnewaddress(const UniValue& params, bool fHelp)
110 {
111     if (!EnsureWalletIsAvailable(fHelp))
112         return NullUniValue;
113
114     if (fHelp || params.size() > 1)
115         throw runtime_error(
116             "getnewaddress ( \"account\" )\n"
117             "\nReturns a new Zcash address for receiving payments.\n"
118             "\nArguments:\n"
119             "1. \"account\"        (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
120             "\nResult:\n"
121             "\"zcashaddress\"    (string) The new zcash address\n"
122             "\nExamples:\n"
123             + HelpExampleCli("getnewaddress", "")
124             + HelpExampleRpc("getnewaddress", "")
125         );
126
127     LOCK2(cs_main, pwalletMain->cs_wallet);
128
129     // Parse the account first so we don't generate a key if there's an error
130     string strAccount;
131     if (params.size() > 0)
132         strAccount = AccountFromValue(params[0]);
133
134     if (!pwalletMain->IsLocked())
135         pwalletMain->TopUpKeyPool();
136
137     // Generate a new key that is added to wallet
138     CPubKey newKey;
139     if (!pwalletMain->GetKeyFromPool(newKey))
140         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
141     CKeyID keyID = newKey.GetID();
142
143     pwalletMain->SetAddressBook(keyID, strAccount, "receive");
144
145     return CBitcoinAddress(keyID).ToString();
146 }
147
148
149 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
150 {
151     CWalletDB walletdb(pwalletMain->strWalletFile);
152
153     CAccount account;
154     walletdb.ReadAccount(strAccount, account);
155
156     bool bKeyUsed = false;
157
158     // Check if the current key has been used
159     if (account.vchPubKey.IsValid())
160     {
161         CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
162         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
163              it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
164              ++it)
165         {
166             const CWalletTx& wtx = (*it).second;
167             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
168                 if (txout.scriptPubKey == scriptPubKey)
169                     bKeyUsed = true;
170         }
171     }
172
173     // Generate a new key
174     if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
175     {
176         if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
177             throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
178
179         pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
180         walletdb.WriteAccount(strAccount, account);
181     }
182
183     return CBitcoinAddress(account.vchPubKey.GetID());
184 }
185
186 UniValue getaccountaddress(const UniValue& params, bool fHelp)
187 {
188     if (!EnsureWalletIsAvailable(fHelp))
189         return NullUniValue;
190
191     if (fHelp || params.size() != 1)
192         throw runtime_error(
193             "getaccountaddress \"account\"\n"
194             "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
195             "\nArguments:\n"
196             "1. \"account\"       (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
197             "\nResult:\n"
198             "\"zcashaddress\"   (string) The account zcash address\n"
199             "\nExamples:\n"
200             + HelpExampleCli("getaccountaddress", "")
201             + HelpExampleCli("getaccountaddress", "\"\"")
202             + HelpExampleCli("getaccountaddress", "\"myaccount\"")
203             + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
204         );
205
206     LOCK2(cs_main, pwalletMain->cs_wallet);
207
208     // Parse the account first so we don't generate a key if there's an error
209     string strAccount = AccountFromValue(params[0]);
210
211     UniValue ret(UniValue::VSTR);
212
213     ret = GetAccountAddress(strAccount).ToString();
214     return ret;
215 }
216
217
218 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
219 {
220     if (!EnsureWalletIsAvailable(fHelp))
221         return NullUniValue;
222
223     if (fHelp || params.size() > 1)
224         throw runtime_error(
225             "getrawchangeaddress\n"
226             "\nReturns a new Zcash address, for receiving change.\n"
227             "This is for use with raw transactions, NOT normal use.\n"
228             "\nResult:\n"
229             "\"address\"    (string) The address\n"
230             "\nExamples:\n"
231             + HelpExampleCli("getrawchangeaddress", "")
232             + HelpExampleRpc("getrawchangeaddress", "")
233        );
234
235     LOCK2(cs_main, pwalletMain->cs_wallet);
236
237     if (!pwalletMain->IsLocked())
238         pwalletMain->TopUpKeyPool();
239
240     CReserveKey reservekey(pwalletMain);
241     CPubKey vchPubKey;
242     if (!reservekey.GetReservedKey(vchPubKey))
243         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
244
245     reservekey.KeepKey();
246
247     CKeyID keyID = vchPubKey.GetID();
248
249     return CBitcoinAddress(keyID).ToString();
250 }
251
252
253 UniValue setaccount(const UniValue& params, bool fHelp)
254 {
255     if (!EnsureWalletIsAvailable(fHelp))
256         return NullUniValue;
257
258     if (fHelp || params.size() < 1 || params.size() > 2)
259         throw runtime_error(
260             "setaccount \"zcashaddress\" \"account\"\n"
261             "\nDEPRECATED. Sets the account associated with the given address.\n"
262             "\nArguments:\n"
263             "1. \"zcashaddress\"  (string, required) The zcash address to be associated with an account.\n"
264             "2. \"account\"         (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
265             "\nExamples:\n"
266             + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
267             + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
268         );
269
270     LOCK2(cs_main, pwalletMain->cs_wallet);
271
272     CBitcoinAddress address(params[0].get_str());
273     if (!address.IsValid())
274         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
275
276     string strAccount;
277     if (params.size() > 1)
278         strAccount = AccountFromValue(params[1]);
279
280     // Only add the account if the address is yours.
281     if (IsMine(*pwalletMain, address.Get()))
282     {
283         // Detect when changing the account of an address that is the 'unused current key' of another account:
284         if (pwalletMain->mapAddressBook.count(address.Get()))
285         {
286             string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
287             if (address == GetAccountAddress(strOldAccount))
288                 GetAccountAddress(strOldAccount, true);
289         }
290         pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
291     }
292     else
293         throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
294
295     return NullUniValue;
296 }
297
298
299 UniValue getaccount(const UniValue& params, bool fHelp)
300 {
301     if (!EnsureWalletIsAvailable(fHelp))
302         return NullUniValue;
303
304     if (fHelp || params.size() != 1)
305         throw runtime_error(
306             "getaccount \"zcashaddress\"\n"
307             "\nDEPRECATED. Returns the account associated with the given address.\n"
308             "\nArguments:\n"
309             "1. \"zcashaddress\"  (string, required) The zcash address for account lookup.\n"
310             "\nResult:\n"
311             "\"accountname\"        (string) the account address\n"
312             "\nExamples:\n"
313             + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
314             + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
315         );
316
317     LOCK2(cs_main, pwalletMain->cs_wallet);
318
319     CBitcoinAddress address(params[0].get_str());
320     if (!address.IsValid())
321         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
322
323     string strAccount;
324     map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
325     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
326         strAccount = (*mi).second.name;
327     return strAccount;
328 }
329
330
331 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
332 {
333     if (!EnsureWalletIsAvailable(fHelp))
334         return NullUniValue;
335
336     if (fHelp || params.size() != 1)
337         throw runtime_error(
338             "getaddressesbyaccount \"account\"\n"
339             "\nDEPRECATED. Returns the list of addresses for the given account.\n"
340             "\nArguments:\n"
341             "1. \"account\"  (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
342             "\nResult:\n"
343             "[                     (json array of string)\n"
344             "  \"zcashaddress\"  (string) a zcash address associated with the given account\n"
345             "  ,...\n"
346             "]\n"
347             "\nExamples:\n"
348             + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
349             + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
350         );
351
352     LOCK2(cs_main, pwalletMain->cs_wallet);
353
354     string strAccount = AccountFromValue(params[0]);
355
356     // Find all addresses that have the given account
357     UniValue ret(UniValue::VARR);
358     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
359     {
360         const CBitcoinAddress& address = item.first;
361         const string& strName = item.second.name;
362         if (strName == strAccount)
363             ret.push_back(address.ToString());
364     }
365     return ret;
366 }
367
368 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
369 {
370     CAmount curBalance = pwalletMain->GetBalance();
371
372     // Check amount
373     if (nValue <= 0)
374         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
375
376     if (nValue > curBalance)
377         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
378
379     // Parse Zcash address
380     CScript scriptPubKey = GetScriptForDestination(address);
381
382     // Create and send the transaction
383     CReserveKey reservekey(pwalletMain);
384     CAmount nFeeRequired;
385     std::string strError;
386     vector<CRecipient> vecSend;
387     int nChangePosRet = -1;
388     CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
389     vecSend.push_back(recipient);
390     if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
391         if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
392             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));
393         throw JSONRPCError(RPC_WALLET_ERROR, strError);
394     }
395     if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
396         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 }
398
399 UniValue sendtoaddress(const UniValue& params, bool fHelp)
400 {
401     if (!EnsureWalletIsAvailable(fHelp))
402         return NullUniValue;
403
404     if (fHelp || params.size() < 2 || params.size() > 5)
405         throw runtime_error(
406             "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
407             "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
408             + HelpRequiringPassphrase() +
409             "\nArguments:\n"
410             "1. \"zcashaddress\"  (string, required) The zcash address to send to.\n"
411             "2. \"amount\"      (numeric, required) The amount in btc to send. eg 0.1\n"
412             "3. \"comment\"     (string, optional) A comment used to store what the transaction is for. \n"
413             "                             This is not part of the transaction, just kept in your wallet.\n"
414             "4. \"comment-to\"  (string, optional) A comment to store the name of the person or organization \n"
415             "                             to which you're sending the transaction. This is not part of the \n"
416             "                             transaction, just kept in your wallet.\n"
417             "5. subtractfeefromamount  (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
418             "                             The recipient will receive less zcash than you enter in the amount field.\n"
419             "\nResult:\n"
420             "\"transactionid\"  (string) The transaction id.\n"
421             "\nExamples:\n"
422             + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
423             + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
424             + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
425             + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
426         );
427
428     LOCK2(cs_main, pwalletMain->cs_wallet);
429
430     CBitcoinAddress address(params[0].get_str());
431     if (!address.IsValid())
432         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
433
434     // Amount
435     CAmount nAmount = AmountFromValue(params[1]);
436     if (nAmount <= 0)
437         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
438
439     // Wallet comments
440     CWalletTx wtx;
441     if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
442         wtx.mapValue["comment"] = params[2].get_str();
443     if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
444         wtx.mapValue["to"]      = params[3].get_str();
445
446     bool fSubtractFeeFromAmount = false;
447     if (params.size() > 4)
448         fSubtractFeeFromAmount = params[4].get_bool();
449
450     EnsureWalletIsUnlocked();
451
452     SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
453
454     return wtx.GetHash().GetHex();
455 }
456
457 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
458 {
459     if (!EnsureWalletIsAvailable(fHelp))
460         return NullUniValue;
461
462     if (fHelp)
463         throw runtime_error(
464             "listaddressgroupings\n"
465             "\nLists groups of addresses which have had their common ownership\n"
466             "made public by common use as inputs or as the resulting change\n"
467             "in past transactions\n"
468             "\nResult:\n"
469             "[\n"
470             "  [\n"
471             "    [\n"
472             "      \"zcashaddress\",     (string) The zcash address\n"
473             "      amount,                 (numeric) The amount in btc\n"
474             "      \"account\"             (string, optional) The account (DEPRECATED)\n"
475             "    ]\n"
476             "    ,...\n"
477             "  ]\n"
478             "  ,...\n"
479             "]\n"
480             "\nExamples:\n"
481             + HelpExampleCli("listaddressgroupings", "")
482             + HelpExampleRpc("listaddressgroupings", "")
483         );
484
485     LOCK2(cs_main, pwalletMain->cs_wallet);
486
487     UniValue jsonGroupings(UniValue::VARR);
488     map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
489     BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
490     {
491         UniValue jsonGrouping(UniValue::VARR);
492         BOOST_FOREACH(CTxDestination address, grouping)
493         {
494             UniValue addressInfo(UniValue::VARR);
495             addressInfo.push_back(CBitcoinAddress(address).ToString());
496             addressInfo.push_back(ValueFromAmount(balances[address]));
497             {
498                 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
499                     addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
500             }
501             jsonGrouping.push_back(addressInfo);
502         }
503         jsonGroupings.push_back(jsonGrouping);
504     }
505     return jsonGroupings;
506 }
507
508 UniValue signmessage(const UniValue& params, bool fHelp)
509 {
510     if (!EnsureWalletIsAvailable(fHelp))
511         return NullUniValue;
512
513     if (fHelp || params.size() != 2)
514         throw runtime_error(
515             "signmessage \"zcashaddress\" \"message\"\n"
516             "\nSign a message with the private key of an address"
517             + HelpRequiringPassphrase() + "\n"
518             "\nArguments:\n"
519             "1. \"zcashaddress\"  (string, required) The zcash address to use for the private key.\n"
520             "2. \"message\"         (string, required) The message to create a signature of.\n"
521             "\nResult:\n"
522             "\"signature\"          (string) The signature of the message encoded in base 64\n"
523             "\nExamples:\n"
524             "\nUnlock the wallet for 30 seconds\n"
525             + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
526             "\nCreate the signature\n"
527             + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
528             "\nVerify the signature\n"
529             + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
530             "\nAs json rpc\n"
531             + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
532         );
533
534     LOCK2(cs_main, pwalletMain->cs_wallet);
535
536     EnsureWalletIsUnlocked();
537
538     string strAddress = params[0].get_str();
539     string strMessage = params[1].get_str();
540
541     CBitcoinAddress addr(strAddress);
542     if (!addr.IsValid())
543         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
544
545     CKeyID keyID;
546     if (!addr.GetKeyID(keyID))
547         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
548
549     CKey key;
550     if (!pwalletMain->GetKey(keyID, key))
551         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
552
553     CHashWriter ss(SER_GETHASH, 0);
554     ss << strMessageMagic;
555     ss << strMessage;
556
557     vector<unsigned char> vchSig;
558     if (!key.SignCompact(ss.GetHash(), vchSig))
559         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
560
561     return EncodeBase64(&vchSig[0], vchSig.size());
562 }
563
564 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
565 {
566     if (!EnsureWalletIsAvailable(fHelp))
567         return NullUniValue;
568
569     if (fHelp || params.size() < 1 || params.size() > 2)
570         throw runtime_error(
571             "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
572             "\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n"
573             "\nArguments:\n"
574             "1. \"zcashaddress\"  (string, required) The zcash address for transactions.\n"
575             "2. minconf             (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
576             "\nResult:\n"
577             "amount   (numeric) The total amount in btc received at this address.\n"
578             "\nExamples:\n"
579             "\nThe amount from transactions with at least 1 confirmation\n"
580             + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
581             "\nThe amount including unconfirmed transactions, zero confirmations\n"
582             + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
583             "\nThe amount with at least 6 confirmation, very safe\n"
584             + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
585             "\nAs a json rpc call\n"
586             + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
587        );
588
589     LOCK2(cs_main, pwalletMain->cs_wallet);
590
591     // Bitcoin address
592     CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
593     if (!address.IsValid())
594         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
595     CScript scriptPubKey = GetScriptForDestination(address.Get());
596     if (!IsMine(*pwalletMain,scriptPubKey))
597         return (double)0.0;
598
599     // Minimum confirmations
600     int nMinDepth = 1;
601     if (params.size() > 1)
602         nMinDepth = params[1].get_int();
603
604     // Tally
605     CAmount nAmount = 0;
606     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
607     {
608         const CWalletTx& wtx = (*it).second;
609         if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
610             continue;
611
612         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
613             if (txout.scriptPubKey == scriptPubKey)
614                 if (wtx.GetDepthInMainChain() >= nMinDepth)
615                     nAmount += txout.nValue;
616     }
617
618     return  ValueFromAmount(nAmount);
619 }
620
621
622 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
623 {
624     if (!EnsureWalletIsAvailable(fHelp))
625         return NullUniValue;
626
627     if (fHelp || params.size() < 1 || params.size() > 2)
628         throw runtime_error(
629             "getreceivedbyaccount \"account\" ( minconf )\n"
630             "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
631             "\nArguments:\n"
632             "1. \"account\"      (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
633             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
634             "\nResult:\n"
635             "amount              (numeric) The total amount in btc received for this account.\n"
636             "\nExamples:\n"
637             "\nAmount received by the default account with at least 1 confirmation\n"
638             + HelpExampleCli("getreceivedbyaccount", "\"\"") +
639             "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
640             + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
641             "\nThe amount with at least 6 confirmation, very safe\n"
642             + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
643             "\nAs a json rpc call\n"
644             + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
645         );
646
647     LOCK2(cs_main, pwalletMain->cs_wallet);
648
649     // Minimum confirmations
650     int nMinDepth = 1;
651     if (params.size() > 1)
652         nMinDepth = params[1].get_int();
653
654     // Get the set of pub keys assigned to account
655     string strAccount = AccountFromValue(params[0]);
656     set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
657
658     // Tally
659     CAmount nAmount = 0;
660     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
661     {
662         const CWalletTx& wtx = (*it).second;
663         if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
664             continue;
665
666         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
667         {
668             CTxDestination address;
669             if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
670                 if (wtx.GetDepthInMainChain() >= nMinDepth)
671                     nAmount += txout.nValue;
672         }
673     }
674
675     return (double)nAmount / (double)COIN;
676 }
677
678
679 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
680 {
681     CAmount nBalance = 0;
682
683     // Tally wallet transactions
684     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
685     {
686         const CWalletTx& wtx = (*it).second;
687         if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
688             continue;
689
690         CAmount nReceived, nSent, nFee;
691         wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
692
693         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
694             nBalance += nReceived;
695         nBalance -= nSent + nFee;
696     }
697
698     // Tally internal accounting entries
699     nBalance += walletdb.GetAccountCreditDebit(strAccount);
700
701     return nBalance;
702 }
703
704 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
705 {
706     CWalletDB walletdb(pwalletMain->strWalletFile);
707     return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
708 }
709
710
711 UniValue getbalance(const UniValue& params, bool fHelp)
712 {
713     if (!EnsureWalletIsAvailable(fHelp))
714         return NullUniValue;
715
716     if (fHelp || params.size() > 3)
717         throw runtime_error(
718             "getbalance ( \"account\" minconf includeWatchonly )\n"
719             "\nReturns the server's total available balance.\n"
720             "\nArguments:\n"
721             "1. \"account\"      (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
722             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
723             "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
724             "\nResult:\n"
725             "amount              (numeric) The total amount in btc received for this account.\n"
726             "\nExamples:\n"
727             "\nThe total amount in the wallet\n"
728             + HelpExampleCli("getbalance", "") +
729             "\nThe total amount in the wallet at least 5 blocks confirmed\n"
730             + HelpExampleCli("getbalance", "\"*\" 6") +
731             "\nAs a json rpc call\n"
732             + HelpExampleRpc("getbalance", "\"*\", 6")
733         );
734
735     LOCK2(cs_main, pwalletMain->cs_wallet);
736
737     if (params.size() == 0)
738         return  ValueFromAmount(pwalletMain->GetBalance());
739
740     int nMinDepth = 1;
741     if (params.size() > 1)
742         nMinDepth = params[1].get_int();
743     isminefilter filter = ISMINE_SPENDABLE;
744     if(params.size() > 2)
745         if(params[2].get_bool())
746             filter = filter | ISMINE_WATCH_ONLY;
747
748     if (params[0].get_str() == "*") {
749         // Calculate total balance a different way from GetBalance()
750         // (GetBalance() sums up all unspent TxOuts)
751         // getbalance and "getbalance * 1 true" should return the same number
752         CAmount nBalance = 0;
753         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
754         {
755             const CWalletTx& wtx = (*it).second;
756             if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
757                 continue;
758
759             CAmount allFee;
760             string strSentAccount;
761             list<COutputEntry> listReceived;
762             list<COutputEntry> listSent;
763             wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
764             if (wtx.GetDepthInMainChain() >= nMinDepth)
765             {
766                 BOOST_FOREACH(const COutputEntry& r, listReceived)
767                     nBalance += r.amount;
768             }
769             BOOST_FOREACH(const COutputEntry& s, listSent)
770                 nBalance -= s.amount;
771             nBalance -= allFee;
772         }
773         return  ValueFromAmount(nBalance);
774     }
775
776     string strAccount = AccountFromValue(params[0]);
777
778     CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
779
780     return ValueFromAmount(nBalance);
781 }
782
783 UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
784 {
785     if (!EnsureWalletIsAvailable(fHelp))
786         return NullUniValue;
787
788     if (fHelp || params.size() > 0)
789         throw runtime_error(
790                 "getunconfirmedbalance\n"
791                 "Returns the server's total unconfirmed balance\n");
792
793     LOCK2(cs_main, pwalletMain->cs_wallet);
794
795     return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
796 }
797
798
799 UniValue movecmd(const UniValue& params, bool fHelp)
800 {
801     if (!EnsureWalletIsAvailable(fHelp))
802         return NullUniValue;
803
804     if (fHelp || params.size() < 3 || params.size() > 5)
805         throw runtime_error(
806             "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
807             "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
808             "\nArguments:\n"
809             "1. \"fromaccount\"   (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
810             "2. \"toaccount\"     (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
811             "3. minconf           (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
812             "4. \"comment\"       (string, optional) An optional comment, stored in the wallet only.\n"
813             "\nResult:\n"
814             "true|false           (boolean) true if successful.\n"
815             "\nExamples:\n"
816             "\nMove 0.01 btc from the default account to the account named tabby\n"
817             + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
818             "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
819             + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
820             "\nAs a json rpc call\n"
821             + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
822         );
823
824     LOCK2(cs_main, pwalletMain->cs_wallet);
825
826     string strFrom = AccountFromValue(params[0]);
827     string strTo = AccountFromValue(params[1]);
828     CAmount nAmount = AmountFromValue(params[2]);
829     if (nAmount <= 0)
830         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
831     if (params.size() > 3)
832         // unused parameter, used to be nMinDepth, keep type-checking it though
833         (void)params[3].get_int();
834     string strComment;
835     if (params.size() > 4)
836         strComment = params[4].get_str();
837
838     CWalletDB walletdb(pwalletMain->strWalletFile);
839     if (!walletdb.TxnBegin())
840         throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
841
842     int64_t nNow = GetAdjustedTime();
843
844     // Debit
845     CAccountingEntry debit;
846     debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
847     debit.strAccount = strFrom;
848     debit.nCreditDebit = -nAmount;
849     debit.nTime = nNow;
850     debit.strOtherAccount = strTo;
851     debit.strComment = strComment;
852     walletdb.WriteAccountingEntry(debit);
853
854     // Credit
855     CAccountingEntry credit;
856     credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
857     credit.strAccount = strTo;
858     credit.nCreditDebit = nAmount;
859     credit.nTime = nNow;
860     credit.strOtherAccount = strFrom;
861     credit.strComment = strComment;
862     walletdb.WriteAccountingEntry(credit);
863
864     if (!walletdb.TxnCommit())
865         throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
866
867     return true;
868 }
869
870
871 UniValue sendfrom(const UniValue& params, bool fHelp)
872 {
873     if (!EnsureWalletIsAvailable(fHelp))
874         return NullUniValue;
875
876     if (fHelp || params.size() < 3 || params.size() > 6)
877         throw runtime_error(
878             "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
879             "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a zcash address.\n"
880             "The amount is a real and is rounded to the nearest 0.00000001."
881             + HelpRequiringPassphrase() + "\n"
882             "\nArguments:\n"
883             "1. \"fromaccount\"       (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
884             "2. \"tozcashaddress\"  (string, required) The zcash address to send funds to.\n"
885             "3. amount                (numeric, required) The amount in btc. (transaction fee is added on top).\n"
886             "4. minconf               (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
887             "5. \"comment\"           (string, optional) A comment used to store what the transaction is for. \n"
888             "                                     This is not part of the transaction, just kept in your wallet.\n"
889             "6. \"comment-to\"        (string, optional) An optional comment to store the name of the person or organization \n"
890             "                                     to which you're sending the transaction. This is not part of the transaction, \n"
891             "                                     it is just kept in your wallet.\n"
892             "\nResult:\n"
893             "\"transactionid\"        (string) The transaction id.\n"
894             "\nExamples:\n"
895             "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
896             + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
897             "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
898             + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
899             "\nAs a json rpc call\n"
900             + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
901         );
902
903     LOCK2(cs_main, pwalletMain->cs_wallet);
904
905     string strAccount = AccountFromValue(params[0]);
906     CBitcoinAddress address(params[1].get_str());
907     if (!address.IsValid())
908         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
909     CAmount nAmount = AmountFromValue(params[2]);
910     if (nAmount <= 0)
911         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
912     int nMinDepth = 1;
913     if (params.size() > 3)
914         nMinDepth = params[3].get_int();
915
916     CWalletTx wtx;
917     wtx.strFromAccount = strAccount;
918     if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
919         wtx.mapValue["comment"] = params[4].get_str();
920     if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
921         wtx.mapValue["to"]      = params[5].get_str();
922
923     EnsureWalletIsUnlocked();
924
925     // Check funds
926     CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
927     if (nAmount > nBalance)
928         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
929
930     SendMoney(address.Get(), nAmount, false, wtx);
931
932     return wtx.GetHash().GetHex();
933 }
934
935
936 UniValue sendmany(const UniValue& params, bool fHelp)
937 {
938     if (!EnsureWalletIsAvailable(fHelp))
939         return NullUniValue;
940
941     if (fHelp || params.size() < 2 || params.size() > 5)
942         throw runtime_error(
943             "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
944             "\nSend multiple times. Amounts are double-precision floating point numbers."
945             + HelpRequiringPassphrase() + "\n"
946             "\nArguments:\n"
947             "1. \"fromaccount\"         (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
948             "2. \"amounts\"             (string, required) A json object with addresses and amounts\n"
949             "    {\n"
950             "      \"address\":amount   (numeric) The zcash address is the key, the numeric amount in btc is the value\n"
951             "      ,...\n"
952             "    }\n"
953             "3. minconf                 (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
954             "4. \"comment\"             (string, optional) A comment\n"
955             "5. subtractfeefromamount   (string, optional) A json array with addresses.\n"
956             "                           The fee will be equally deducted from the amount of each selected address.\n"
957             "                           Those recipients will receive less zcashs than you enter in their corresponding amount field.\n"
958             "                           If no addresses are specified here, the sender pays the fee.\n"
959             "    [\n"
960             "      \"address\"            (string) Subtract fee from this address\n"
961             "      ,...\n"
962             "    ]\n"
963             "\nResult:\n"
964             "\"transactionid\"          (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
965             "                                    the number of addresses.\n"
966             "\nExamples:\n"
967             "\nSend two amounts to two different addresses:\n"
968             + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
969             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
970             + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
971             "\nSend two amounts to two different addresses, subtract fee from amount:\n"
972             + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
973             "\nAs a json rpc call\n"
974             + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
975         );
976
977     LOCK2(cs_main, pwalletMain->cs_wallet);
978
979     string strAccount = AccountFromValue(params[0]);
980     UniValue sendTo = params[1].get_obj();
981     int nMinDepth = 1;
982     if (params.size() > 2)
983         nMinDepth = params[2].get_int();
984
985     CWalletTx wtx;
986     wtx.strFromAccount = strAccount;
987     if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
988         wtx.mapValue["comment"] = params[3].get_str();
989
990     UniValue subtractFeeFromAmount(UniValue::VARR);
991     if (params.size() > 4)
992         subtractFeeFromAmount = params[4].get_array();
993
994     set<CBitcoinAddress> setAddress;
995     vector<CRecipient> vecSend;
996
997     CAmount totalAmount = 0;
998     vector<string> keys = sendTo.getKeys();
999     BOOST_FOREACH(const string& name_, keys)
1000     {
1001         CBitcoinAddress address(name_);
1002         if (!address.IsValid())
1003             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_);
1004
1005         if (setAddress.count(address))
1006             throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1007         setAddress.insert(address);
1008
1009         CScript scriptPubKey = GetScriptForDestination(address.Get());
1010         CAmount nAmount = AmountFromValue(sendTo[name_]);
1011         if (nAmount <= 0)
1012             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1013         totalAmount += nAmount;
1014
1015         bool fSubtractFeeFromAmount = false;
1016         for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1017             const UniValue& addr = subtractFeeFromAmount[idx];
1018             if (addr.get_str() == name_)
1019                 fSubtractFeeFromAmount = true;
1020         }
1021
1022         CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1023         vecSend.push_back(recipient);
1024     }
1025
1026     EnsureWalletIsUnlocked();
1027
1028     // Check funds
1029     CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1030     if (totalAmount > nBalance)
1031         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1032
1033     // Send
1034     CReserveKey keyChange(pwalletMain);
1035     CAmount nFeeRequired = 0;
1036     int nChangePosRet = -1;
1037     string strFailReason;
1038     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1039     if (!fCreated)
1040         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1041     if (!pwalletMain->CommitTransaction(wtx, keyChange))
1042         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1043
1044     return wtx.GetHash().GetHex();
1045 }
1046
1047 // Defined in rpcmisc.cpp
1048 extern CScript _createmultisig_redeemScript(const UniValue& params);
1049
1050 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1051 {
1052     if (!EnsureWalletIsAvailable(fHelp))
1053         return NullUniValue;
1054
1055     if (fHelp || params.size() < 2 || params.size() > 3)
1056     {
1057         string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1058             "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1059             "Each key is a Zcash address or hex-encoded public key.\n"
1060             "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1061
1062             "\nArguments:\n"
1063             "1. nrequired        (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1064             "2. \"keysobject\"   (string, required) A json array of zcash addresses or hex-encoded public keys\n"
1065             "     [\n"
1066             "       \"address\"  (string) zcash address or hex-encoded public key\n"
1067             "       ...,\n"
1068             "     ]\n"
1069             "3. \"account\"      (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1070
1071             "\nResult:\n"
1072             "\"zcashaddress\"  (string) A zcash address associated with the keys.\n"
1073
1074             "\nExamples:\n"
1075             "\nAdd a multisig address from 2 addresses\n"
1076             + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1077             "\nAs json rpc call\n"
1078             + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1079         ;
1080         throw runtime_error(msg);
1081     }
1082
1083     LOCK2(cs_main, pwalletMain->cs_wallet);
1084
1085     string strAccount;
1086     if (params.size() > 2)
1087         strAccount = AccountFromValue(params[2]);
1088
1089     // Construct using pay-to-script-hash:
1090     CScript inner = _createmultisig_redeemScript(params);
1091     CScriptID innerID(inner);
1092     pwalletMain->AddCScript(inner);
1093
1094     pwalletMain->SetAddressBook(innerID, strAccount, "send");
1095     return CBitcoinAddress(innerID).ToString();
1096 }
1097
1098
1099 struct tallyitem
1100 {
1101     CAmount nAmount;
1102     int nConf;
1103     vector<uint256> txids;
1104     bool fIsWatchonly;
1105     tallyitem()
1106     {
1107         nAmount = 0;
1108         nConf = std::numeric_limits<int>::max();
1109         fIsWatchonly = false;
1110     }
1111 };
1112
1113 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1114 {
1115     // Minimum confirmations
1116     int nMinDepth = 1;
1117     if (params.size() > 0)
1118         nMinDepth = params[0].get_int();
1119
1120     // Whether to include empty accounts
1121     bool fIncludeEmpty = false;
1122     if (params.size() > 1)
1123         fIncludeEmpty = params[1].get_bool();
1124
1125     isminefilter filter = ISMINE_SPENDABLE;
1126     if(params.size() > 2)
1127         if(params[2].get_bool())
1128             filter = filter | ISMINE_WATCH_ONLY;
1129
1130     // Tally
1131     map<CBitcoinAddress, tallyitem> mapTally;
1132     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1133     {
1134         const CWalletTx& wtx = (*it).second;
1135
1136         if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1137             continue;
1138
1139         int nDepth = wtx.GetDepthInMainChain();
1140         if (nDepth < nMinDepth)
1141             continue;
1142
1143         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1144         {
1145             CTxDestination address;
1146             if (!ExtractDestination(txout.scriptPubKey, address))
1147                 continue;
1148
1149             isminefilter mine = IsMine(*pwalletMain, address);
1150             if(!(mine & filter))
1151                 continue;
1152
1153             tallyitem& item = mapTally[address];
1154             item.nAmount += txout.nValue;
1155             item.nConf = min(item.nConf, nDepth);
1156             item.txids.push_back(wtx.GetHash());
1157             if (mine & ISMINE_WATCH_ONLY)
1158                 item.fIsWatchonly = true;
1159         }
1160     }
1161
1162     // Reply
1163     UniValue ret(UniValue::VARR);
1164     map<string, tallyitem> mapAccountTally;
1165     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1166     {
1167         const CBitcoinAddress& address = item.first;
1168         const string& strAccount = item.second.name;
1169         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1170         if (it == mapTally.end() && !fIncludeEmpty)
1171             continue;
1172
1173         CAmount nAmount = 0;
1174         int nConf = std::numeric_limits<int>::max();
1175         bool fIsWatchonly = false;
1176         if (it != mapTally.end())
1177         {
1178             nAmount = (*it).second.nAmount;
1179             nConf = (*it).second.nConf;
1180             fIsWatchonly = (*it).second.fIsWatchonly;
1181         }
1182
1183         if (fByAccounts)
1184         {
1185             tallyitem& item = mapAccountTally[strAccount];
1186             item.nAmount += nAmount;
1187             item.nConf = min(item.nConf, nConf);
1188             item.fIsWatchonly = fIsWatchonly;
1189         }
1190         else
1191         {
1192             UniValue obj(UniValue::VOBJ);
1193             if(fIsWatchonly)
1194                 obj.push_back(Pair("involvesWatchonly", true));
1195             obj.push_back(Pair("address",       address.ToString()));
1196             obj.push_back(Pair("account",       strAccount));
1197             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1198             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1199             UniValue transactions(UniValue::VARR);
1200             if (it != mapTally.end())
1201             {
1202                 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1203                 {
1204                     transactions.push_back(item.GetHex());
1205                 }
1206             }
1207             obj.push_back(Pair("txids", transactions));
1208             ret.push_back(obj);
1209         }
1210     }
1211
1212     if (fByAccounts)
1213     {
1214         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1215         {
1216             CAmount nAmount = (*it).second.nAmount;
1217             int nConf = (*it).second.nConf;
1218             UniValue obj(UniValue::VOBJ);
1219             if((*it).second.fIsWatchonly)
1220                 obj.push_back(Pair("involvesWatchonly", true));
1221             obj.push_back(Pair("account",       (*it).first));
1222             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1223             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1224             ret.push_back(obj);
1225         }
1226     }
1227
1228     return ret;
1229 }
1230
1231 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1232 {
1233     if (!EnsureWalletIsAvailable(fHelp))
1234         return NullUniValue;
1235
1236     if (fHelp || params.size() > 3)
1237         throw runtime_error(
1238             "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1239             "\nList balances by receiving address.\n"
1240             "\nArguments:\n"
1241             "1. minconf       (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1242             "2. includeempty  (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1243             "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1244
1245             "\nResult:\n"
1246             "[\n"
1247             "  {\n"
1248             "    \"involvesWatchonly\" : true,        (bool) Only returned if imported addresses were involved in transaction\n"
1249             "    \"address\" : \"receivingaddress\",  (string) The receiving address\n"
1250             "    \"account\" : \"accountname\",       (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1251             "    \"amount\" : x.xxx,                  (numeric) The total amount in btc received by the address\n"
1252             "    \"confirmations\" : n                (numeric) The number of confirmations of the most recent transaction included\n"
1253             "  }\n"
1254             "  ,...\n"
1255             "]\n"
1256
1257             "\nExamples:\n"
1258             + HelpExampleCli("listreceivedbyaddress", "")
1259             + HelpExampleCli("listreceivedbyaddress", "6 true")
1260             + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1261         );
1262
1263     LOCK2(cs_main, pwalletMain->cs_wallet);
1264
1265     return ListReceived(params, false);
1266 }
1267
1268 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1269 {
1270     if (!EnsureWalletIsAvailable(fHelp))
1271         return NullUniValue;
1272
1273     if (fHelp || params.size() > 3)
1274         throw runtime_error(
1275             "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1276             "\nDEPRECATED. List balances by account.\n"
1277             "\nArguments:\n"
1278             "1. minconf      (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1279             "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1280             "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1281
1282             "\nResult:\n"
1283             "[\n"
1284             "  {\n"
1285             "    \"involvesWatchonly\" : true,   (bool) Only returned if imported addresses were involved in transaction\n"
1286             "    \"account\" : \"accountname\",  (string) The account name of the receiving account\n"
1287             "    \"amount\" : x.xxx,             (numeric) The total amount received by addresses with this account\n"
1288             "    \"confirmations\" : n           (numeric) The number of confirmations of the most recent transaction included\n"
1289             "  }\n"
1290             "  ,...\n"
1291             "]\n"
1292
1293             "\nExamples:\n"
1294             + HelpExampleCli("listreceivedbyaccount", "")
1295             + HelpExampleCli("listreceivedbyaccount", "6 true")
1296             + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1297         );
1298
1299     LOCK2(cs_main, pwalletMain->cs_wallet);
1300
1301     return ListReceived(params, true);
1302 }
1303
1304 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1305 {
1306     CBitcoinAddress addr;
1307     if (addr.Set(dest))
1308         entry.push_back(Pair("address", addr.ToString()));
1309 }
1310
1311 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1312 {
1313     CAmount nFee;
1314     string strSentAccount;
1315     list<COutputEntry> listReceived;
1316     list<COutputEntry> listSent;
1317
1318     wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1319
1320     bool fAllAccounts = (strAccount == string("*"));
1321     bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1322
1323     // Sent
1324     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1325     {
1326         BOOST_FOREACH(const COutputEntry& s, listSent)
1327         {
1328             UniValue entry(UniValue::VOBJ);
1329             if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1330                 entry.push_back(Pair("involvesWatchonly", true));
1331             entry.push_back(Pair("account", strSentAccount));
1332             MaybePushAddress(entry, s.destination);
1333             entry.push_back(Pair("category", "send"));
1334             entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1335             entry.push_back(Pair("vout", s.vout));
1336             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1337             if (fLong)
1338                 WalletTxToJSON(wtx, entry);
1339             entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1340             ret.push_back(entry);
1341         }
1342     }
1343
1344     // Received
1345     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1346     {
1347         BOOST_FOREACH(const COutputEntry& r, listReceived)
1348         {
1349             string account;
1350             if (pwalletMain->mapAddressBook.count(r.destination))
1351                 account = pwalletMain->mapAddressBook[r.destination].name;
1352             if (fAllAccounts || (account == strAccount))
1353             {
1354                 UniValue entry(UniValue::VOBJ);
1355                 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1356                     entry.push_back(Pair("involvesWatchonly", true));
1357                 entry.push_back(Pair("account", account));
1358                 MaybePushAddress(entry, r.destination);
1359                 if (wtx.IsCoinBase())
1360                 {
1361                     if (wtx.GetDepthInMainChain() < 1)
1362                         entry.push_back(Pair("category", "orphan"));
1363                     else if (wtx.GetBlocksToMaturity() > 0)
1364                         entry.push_back(Pair("category", "immature"));
1365                     else
1366                         entry.push_back(Pair("category", "generate"));
1367                 }
1368                 else
1369                 {
1370                     entry.push_back(Pair("category", "receive"));
1371                 }
1372                 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1373                 entry.push_back(Pair("vout", r.vout));
1374                 if (fLong)
1375                     WalletTxToJSON(wtx, entry);
1376                 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1377                 ret.push_back(entry);
1378             }
1379         }
1380     }
1381 }
1382
1383 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1384 {
1385     bool fAllAccounts = (strAccount == string("*"));
1386
1387     if (fAllAccounts || acentry.strAccount == strAccount)
1388     {
1389         UniValue entry(UniValue::VOBJ);
1390         entry.push_back(Pair("account", acentry.strAccount));
1391         entry.push_back(Pair("category", "move"));
1392         entry.push_back(Pair("time", acentry.nTime));
1393         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1394         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1395         entry.push_back(Pair("comment", acentry.strComment));
1396         ret.push_back(entry);
1397     }
1398 }
1399
1400 UniValue listtransactions(const UniValue& params, bool fHelp)
1401 {
1402     if (!EnsureWalletIsAvailable(fHelp))
1403         return NullUniValue;
1404
1405     if (fHelp || params.size() > 4)
1406         throw runtime_error(
1407             "listtransactions ( \"account\" count from includeWatchonly)\n"
1408             "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1409             "\nArguments:\n"
1410             "1. \"account\"    (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1411             "2. count          (numeric, optional, default=10) The number of transactions to return\n"
1412             "3. from           (numeric, optional, default=0) The number of transactions to skip\n"
1413             "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1414             "\nResult:\n"
1415             "[\n"
1416             "  {\n"
1417             "    \"account\":\"accountname\",       (string) DEPRECATED. The account name associated with the transaction. \n"
1418             "                                                It will be \"\" for the default account.\n"
1419             "    \"address\":\"zcashaddress\",    (string) The zcash address of the transaction. Not present for \n"
1420             "                                                move transactions (category = move).\n"
1421             "    \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1422             "                                                transaction between accounts, and not associated with an address,\n"
1423             "                                                transaction id or block. 'send' and 'receive' transactions are \n"
1424             "                                                associated with an address, transaction id and block details\n"
1425             "    \"amount\": x.xxx,          (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1426             "                                         'move' category for moves outbound. It is positive for the 'receive' category,\n"
1427             "                                         and for the 'move' category for inbound funds.\n"
1428             "    \"vout\" : n,               (numeric) the vout value\n"
1429             "    \"fee\": x.xxx,             (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1430             "                                         'send' category of transactions.\n"
1431             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1432             "                                         'receive' category of transactions.\n"
1433             "    \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1434             "                                          category of transactions.\n"
1435             "    \"blockindex\": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1436             "                                          category of transactions.\n"
1437             "    \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1438             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1439             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1440             "                                          for 'send' and 'receive' category of transactions.\n"
1441             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
1442             "    \"otheraccount\": \"accountname\",  (string) For the 'move' category of transactions, the account the funds came \n"
1443             "                                          from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1444             "                                          negative amounts).\n"
1445             "    \"size\": n,                (numeric) Transaction size in bytes\n"
1446             "  }\n"
1447             "]\n"
1448
1449             "\nExamples:\n"
1450             "\nList the most recent 10 transactions in the systems\n"
1451             + HelpExampleCli("listtransactions", "") +
1452             "\nList transactions 100 to 120\n"
1453             + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1454             "\nAs a json rpc call\n"
1455             + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1456         );
1457
1458     LOCK2(cs_main, pwalletMain->cs_wallet);
1459
1460     string strAccount = "*";
1461     if (params.size() > 0)
1462         strAccount = params[0].get_str();
1463     int nCount = 10;
1464     if (params.size() > 1)
1465         nCount = params[1].get_int();
1466     int nFrom = 0;
1467     if (params.size() > 2)
1468         nFrom = params[2].get_int();
1469     isminefilter filter = ISMINE_SPENDABLE;
1470     if(params.size() > 3)
1471         if(params[3].get_bool())
1472             filter = filter | ISMINE_WATCH_ONLY;
1473
1474     if (nCount < 0)
1475         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1476     if (nFrom < 0)
1477         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1478
1479     UniValue ret(UniValue::VARR);
1480
1481     std::list<CAccountingEntry> acentries;
1482     CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1483
1484     // iterate backwards until we have nCount items to return:
1485     for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1486     {
1487         CWalletTx *const pwtx = (*it).second.first;
1488         if (pwtx != 0)
1489             ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1490         CAccountingEntry *const pacentry = (*it).second.second;
1491         if (pacentry != 0)
1492             AcentryToJSON(*pacentry, strAccount, ret);
1493
1494         if ((int)ret.size() >= (nCount+nFrom)) break;
1495     }
1496     // ret is newest to oldest
1497
1498     if (nFrom > (int)ret.size())
1499         nFrom = ret.size();
1500     if ((nFrom + nCount) > (int)ret.size())
1501         nCount = ret.size() - nFrom;
1502
1503     vector<UniValue> arrTmp = ret.getValues();
1504
1505     vector<UniValue>::iterator first = arrTmp.begin();
1506     std::advance(first, nFrom);
1507     vector<UniValue>::iterator last = arrTmp.begin();
1508     std::advance(last, nFrom+nCount);
1509
1510     if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1511     if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1512
1513     std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1514
1515     ret.clear();
1516     ret.setArray();
1517     ret.push_backV(arrTmp);
1518
1519     return ret;
1520 }
1521
1522 UniValue listaccounts(const UniValue& params, bool fHelp)
1523 {
1524     if (!EnsureWalletIsAvailable(fHelp))
1525         return NullUniValue;
1526
1527     if (fHelp || params.size() > 2)
1528         throw runtime_error(
1529             "listaccounts ( minconf includeWatchonly)\n"
1530             "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1531             "\nArguments:\n"
1532             "1. minconf          (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1533             "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1534             "\nResult:\n"
1535             "{                      (json object where keys are account names, and values are numeric balances\n"
1536             "  \"account\": x.xxx,  (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1537             "  ...\n"
1538             "}\n"
1539             "\nExamples:\n"
1540             "\nList account balances where there at least 1 confirmation\n"
1541             + HelpExampleCli("listaccounts", "") +
1542             "\nList account balances including zero confirmation transactions\n"
1543             + HelpExampleCli("listaccounts", "0") +
1544             "\nList account balances for 6 or more confirmations\n"
1545             + HelpExampleCli("listaccounts", "6") +
1546             "\nAs json rpc call\n"
1547             + HelpExampleRpc("listaccounts", "6")
1548         );
1549
1550     LOCK2(cs_main, pwalletMain->cs_wallet);
1551
1552     int nMinDepth = 1;
1553     if (params.size() > 0)
1554         nMinDepth = params[0].get_int();
1555     isminefilter includeWatchonly = ISMINE_SPENDABLE;
1556     if(params.size() > 1)
1557         if(params[1].get_bool())
1558             includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1559
1560     map<string, CAmount> mapAccountBalances;
1561     BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1562         if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1563             mapAccountBalances[entry.second.name] = 0;
1564     }
1565
1566     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1567     {
1568         const CWalletTx& wtx = (*it).second;
1569         CAmount nFee;
1570         string strSentAccount;
1571         list<COutputEntry> listReceived;
1572         list<COutputEntry> listSent;
1573         int nDepth = wtx.GetDepthInMainChain();
1574         if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1575             continue;
1576         wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1577         mapAccountBalances[strSentAccount] -= nFee;
1578         BOOST_FOREACH(const COutputEntry& s, listSent)
1579             mapAccountBalances[strSentAccount] -= s.amount;
1580         if (nDepth >= nMinDepth)
1581         {
1582             BOOST_FOREACH(const COutputEntry& r, listReceived)
1583                 if (pwalletMain->mapAddressBook.count(r.destination))
1584                     mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1585                 else
1586                     mapAccountBalances[""] += r.amount;
1587         }
1588     }
1589
1590     list<CAccountingEntry> acentries;
1591     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1592     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1593         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1594
1595     UniValue ret(UniValue::VOBJ);
1596     BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1597         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1598     }
1599     return ret;
1600 }
1601
1602 UniValue listsinceblock(const UniValue& params, bool fHelp)
1603 {
1604     if (!EnsureWalletIsAvailable(fHelp))
1605         return NullUniValue;
1606
1607     if (fHelp)
1608         throw runtime_error(
1609             "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1610             "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1611             "\nArguments:\n"
1612             "1. \"blockhash\"   (string, optional) The block hash to list transactions since\n"
1613             "2. target-confirmations:    (numeric, optional) The confirmations required, must be 1 or more\n"
1614             "3. includeWatchonly:        (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1615             "\nResult:\n"
1616             "{\n"
1617             "  \"transactions\": [\n"
1618             "    \"account\":\"accountname\",       (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1619             "    \"address\":\"zcashaddress\",    (string) The zcash address of the transaction. Not present for move transactions (category = move).\n"
1620             "    \"category\":\"send|receive\",     (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1621             "    \"amount\": x.xxx,          (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1622             "                                          outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1623             "    \"vout\" : n,               (numeric) the vout value\n"
1624             "    \"fee\": x.xxx,             (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1625             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1626             "    \"blockhash\": \"hashvalue\",     (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1627             "    \"blockindex\": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1628             "    \"blocktime\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1629             "    \"txid\": \"transactionid\",  (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1630             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1631             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1632             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
1633             "    \"to\": \"...\",            (string) If a comment to is associated with the transaction.\n"
1634              "  ],\n"
1635             "  \"lastblock\": \"lastblockhash\"     (string) The hash of the last block\n"
1636             "}\n"
1637             "\nExamples:\n"
1638             + HelpExampleCli("listsinceblock", "")
1639             + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1640             + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1641         );
1642
1643     LOCK2(cs_main, pwalletMain->cs_wallet);
1644
1645     CBlockIndex *pindex = NULL;
1646     int target_confirms = 1;
1647     isminefilter filter = ISMINE_SPENDABLE;
1648
1649     if (params.size() > 0)
1650     {
1651         uint256 blockId;
1652
1653         blockId.SetHex(params[0].get_str());
1654         BlockMap::iterator it = mapBlockIndex.find(blockId);
1655         if (it != mapBlockIndex.end())
1656             pindex = it->second;
1657     }
1658
1659     if (params.size() > 1)
1660     {
1661         target_confirms = params[1].get_int();
1662
1663         if (target_confirms < 1)
1664             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1665     }
1666
1667     if(params.size() > 2)
1668         if(params[2].get_bool())
1669             filter = filter | ISMINE_WATCH_ONLY;
1670
1671     int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1672
1673     UniValue transactions(UniValue::VARR);
1674
1675     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1676     {
1677         CWalletTx tx = (*it).second;
1678
1679         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1680             ListTransactions(tx, "*", 0, true, transactions, filter);
1681     }
1682
1683     CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1684     uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1685
1686     UniValue ret(UniValue::VOBJ);
1687     ret.push_back(Pair("transactions", transactions));
1688     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1689
1690     return ret;
1691 }
1692
1693 UniValue gettransaction(const UniValue& params, bool fHelp)
1694 {
1695     if (!EnsureWalletIsAvailable(fHelp))
1696         return NullUniValue;
1697
1698     if (fHelp || params.size() < 1 || params.size() > 2)
1699         throw runtime_error(
1700             "gettransaction \"txid\" ( includeWatchonly )\n"
1701             "\nGet detailed information about in-wallet transaction <txid>\n"
1702             "\nArguments:\n"
1703             "1. \"txid\"    (string, required) The transaction id\n"
1704             "2. \"includeWatchonly\"    (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1705             "\nResult:\n"
1706             "{\n"
1707             "  \"amount\" : x.xxx,        (numeric) The transaction amount in btc\n"
1708             "  \"confirmations\" : n,     (numeric) The number of confirmations\n"
1709             "  \"blockhash\" : \"hash\",  (string) The block hash\n"
1710             "  \"blockindex\" : xx,       (numeric) The block index\n"
1711             "  \"blocktime\" : ttt,       (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1712             "  \"txid\" : \"transactionid\",   (string) The transaction id.\n"
1713             "  \"time\" : ttt,            (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1714             "  \"timereceived\" : ttt,    (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1715             "  \"details\" : [\n"
1716             "    {\n"
1717             "      \"account\" : \"accountname\",  (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1718             "      \"address\" : \"zcashaddress\",   (string) The zcash address involved in the transaction\n"
1719             "      \"category\" : \"send|receive\",    (string) The category, either 'send' or 'receive'\n"
1720             "      \"amount\" : x.xxx                  (numeric) The amount in btc\n"
1721             "      \"vout\" : n,                       (numeric) the vout value\n"
1722             "    }\n"
1723             "    ,...\n"
1724             "  ],\n"
1725             "  \"vjoinsplit\" : [\n"
1726             "    {\n"
1727             "      \"anchor\" : \"treestateref\",          (string) Merkle root of note commitment tree\n"
1728             "      \"nullifiers\" : [ string, ... ]      (string) Nullifiers of input notes\n"
1729             "      \"commitments\" : [ string, ... ]     (string) Note commitments for note outputs\n"
1730             "      \"macs\" : [ string, ... ]            (string) Message authentication tags\n"
1731             "      \"vpub_old\" : x.xxx                  (numeric) The amount removed from the transparent value pool\n"
1732             "      \"vpub_new\" : x.xxx,                 (numeric) The amount added to the transparent value pool\n"
1733             "    }\n"
1734             "    ,...\n"
1735             "  ],\n"
1736             "  \"hex\" : \"data\"         (string) Raw data for transaction\n"
1737             "}\n"
1738
1739             "\nExamples:\n"
1740             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1741             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1742             + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1743         );
1744
1745     LOCK2(cs_main, pwalletMain->cs_wallet);
1746
1747     uint256 hash;
1748     hash.SetHex(params[0].get_str());
1749
1750     isminefilter filter = ISMINE_SPENDABLE;
1751     if(params.size() > 1)
1752         if(params[1].get_bool())
1753             filter = filter | ISMINE_WATCH_ONLY;
1754
1755     UniValue entry(UniValue::VOBJ);
1756     if (!pwalletMain->mapWallet.count(hash))
1757         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1758     const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1759
1760     CAmount nCredit = wtx.GetCredit(filter);
1761     CAmount nDebit = wtx.GetDebit(filter);
1762     CAmount nNet = nCredit - nDebit;
1763     CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1764
1765     entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1766     if (wtx.IsFromMe(filter))
1767         entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1768
1769     WalletTxToJSON(wtx, entry);
1770
1771     UniValue details(UniValue::VARR);
1772     ListTransactions(wtx, "*", 0, false, details, filter);
1773     entry.push_back(Pair("details", details));
1774
1775     string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
1776     entry.push_back(Pair("hex", strHex));
1777
1778     return entry;
1779 }
1780
1781
1782 UniValue backupwallet(const UniValue& params, bool fHelp)
1783 {
1784     if (!EnsureWalletIsAvailable(fHelp))
1785         return NullUniValue;
1786
1787     if (fHelp || params.size() != 1)
1788         throw runtime_error(
1789             "backupwallet \"destination\"\n"
1790             "\nSafely copies wallet.dat to destination filename\n"
1791             "\nArguments:\n"
1792             "1. \"destination\"   (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
1793             "\nResult:\n"
1794             "\"path\"             (string) The full path of the destination file\n"
1795             "\nExamples:\n"
1796             + HelpExampleCli("backupwallet", "\"backupdata\"")
1797             + HelpExampleRpc("backupwallet", "\"backupdata\"")
1798         );
1799
1800     LOCK2(cs_main, pwalletMain->cs_wallet);
1801
1802     boost::filesystem::path exportdir;
1803     try {
1804         exportdir = GetExportDir();
1805     } catch (const std::runtime_error& e) {
1806         throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
1807     }
1808     if (exportdir.empty()) {
1809         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
1810     }
1811     std::string unclean = params[0].get_str();
1812     std::string clean = SanitizeFilename(unclean);
1813     if (clean.compare(unclean) != 0) {
1814         throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed.  Try '%s' instead.", clean));
1815     }
1816     boost::filesystem::path exportfilepath = exportdir / clean;
1817
1818     if (!BackupWallet(*pwalletMain, exportfilepath.string()))
1819         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1820
1821     return exportfilepath.string();
1822 }
1823
1824
1825 UniValue keypoolrefill(const UniValue& params, bool fHelp)
1826 {
1827     if (!EnsureWalletIsAvailable(fHelp))
1828         return NullUniValue;
1829
1830     if (fHelp || params.size() > 1)
1831         throw runtime_error(
1832             "keypoolrefill ( newsize )\n"
1833             "\nFills the keypool."
1834             + HelpRequiringPassphrase() + "\n"
1835             "\nArguments\n"
1836             "1. newsize     (numeric, optional, default=100) The new keypool size\n"
1837             "\nExamples:\n"
1838             + HelpExampleCli("keypoolrefill", "")
1839             + HelpExampleRpc("keypoolrefill", "")
1840         );
1841
1842     LOCK2(cs_main, pwalletMain->cs_wallet);
1843
1844     // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1845     unsigned int kpSize = 0;
1846     if (params.size() > 0) {
1847         if (params[0].get_int() < 0)
1848             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1849         kpSize = (unsigned int)params[0].get_int();
1850     }
1851
1852     EnsureWalletIsUnlocked();
1853     pwalletMain->TopUpKeyPool(kpSize);
1854
1855     if (pwalletMain->GetKeyPoolSize() < kpSize)
1856         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1857
1858     return NullUniValue;
1859 }
1860
1861
1862 static void LockWallet(CWallet* pWallet)
1863 {
1864     LOCK(cs_nWalletUnlockTime);
1865     nWalletUnlockTime = 0;
1866     pWallet->Lock();
1867 }
1868
1869 UniValue walletpassphrase(const UniValue& params, bool fHelp)
1870 {
1871     if (!EnsureWalletIsAvailable(fHelp))
1872         return NullUniValue;
1873
1874     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1875         throw runtime_error(
1876             "walletpassphrase \"passphrase\" timeout\n"
1877             "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1878             "This is needed prior to performing transactions related to private keys such as sending zcash\n"
1879             "\nArguments:\n"
1880             "1. \"passphrase\"     (string, required) The wallet passphrase\n"
1881             "2. timeout            (numeric, required) The time to keep the decryption key in seconds.\n"
1882             "\nNote:\n"
1883             "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1884             "time that overrides the old one.\n"
1885             "\nExamples:\n"
1886             "\nunlock the wallet for 60 seconds\n"
1887             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1888             "\nLock the wallet again (before 60 seconds)\n"
1889             + HelpExampleCli("walletlock", "") +
1890             "\nAs json rpc call\n"
1891             + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1892         );
1893
1894     LOCK2(cs_main, pwalletMain->cs_wallet);
1895
1896     if (fHelp)
1897         return true;
1898     if (!pwalletMain->IsCrypted())
1899         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1900
1901     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1902     SecureString strWalletPass;
1903     strWalletPass.reserve(100);
1904     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1905     // Alternately, find a way to make params[0] mlock()'d to begin with.
1906     strWalletPass = params[0].get_str().c_str();
1907
1908     if (strWalletPass.length() > 0)
1909     {
1910         if (!pwalletMain->Unlock(strWalletPass))
1911             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1912     }
1913     else
1914         throw runtime_error(
1915             "walletpassphrase <passphrase> <timeout>\n"
1916             "Stores the wallet decryption key in memory for <timeout> seconds.");
1917
1918     // No need to check return values, because the wallet was unlocked above
1919     pwalletMain->UpdateNullifierNoteMap();
1920     pwalletMain->TopUpKeyPool();
1921
1922     int64_t nSleepTime = params[1].get_int64();
1923     LOCK(cs_nWalletUnlockTime);
1924     nWalletUnlockTime = GetTime() + nSleepTime;
1925     RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
1926
1927     return NullUniValue;
1928 }
1929
1930
1931 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
1932 {
1933     if (!EnsureWalletIsAvailable(fHelp))
1934         return NullUniValue;
1935
1936     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1937         throw runtime_error(
1938             "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1939             "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1940             "\nArguments:\n"
1941             "1. \"oldpassphrase\"      (string) The current passphrase\n"
1942             "2. \"newpassphrase\"      (string) The new passphrase\n"
1943             "\nExamples:\n"
1944             + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1945             + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1946         );
1947
1948     LOCK2(cs_main, pwalletMain->cs_wallet);
1949
1950     if (fHelp)
1951         return true;
1952     if (!pwalletMain->IsCrypted())
1953         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1954
1955     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1956     // Alternately, find a way to make params[0] mlock()'d to begin with.
1957     SecureString strOldWalletPass;
1958     strOldWalletPass.reserve(100);
1959     strOldWalletPass = params[0].get_str().c_str();
1960
1961     SecureString strNewWalletPass;
1962     strNewWalletPass.reserve(100);
1963     strNewWalletPass = params[1].get_str().c_str();
1964
1965     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1966         throw runtime_error(
1967             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1968             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1969
1970     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1971         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1972
1973     return NullUniValue;
1974 }
1975
1976
1977 UniValue walletlock(const UniValue& params, bool fHelp)
1978 {
1979     if (!EnsureWalletIsAvailable(fHelp))
1980         return NullUniValue;
1981
1982     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1983         throw runtime_error(
1984             "walletlock\n"
1985             "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
1986             "After calling this method, you will need to call walletpassphrase again\n"
1987             "before being able to call any methods which require the wallet to be unlocked.\n"
1988             "\nExamples:\n"
1989             "\nSet the passphrase for 2 minutes to perform a transaction\n"
1990             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1991             "\nPerform a send (requires passphrase set)\n"
1992             + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1993             "\nClear the passphrase since we are done before 2 minutes is up\n"
1994             + HelpExampleCli("walletlock", "") +
1995             "\nAs json rpc call\n"
1996             + HelpExampleRpc("walletlock", "")
1997         );
1998
1999     LOCK2(cs_main, pwalletMain->cs_wallet);
2000
2001     if (fHelp)
2002         return true;
2003     if (!pwalletMain->IsCrypted())
2004         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2005
2006     {
2007         LOCK(cs_nWalletUnlockTime);
2008         pwalletMain->Lock();
2009         nWalletUnlockTime = 0;
2010     }
2011
2012     return NullUniValue;
2013 }
2014
2015
2016 UniValue encryptwallet(const UniValue& params, bool fHelp)
2017 {
2018     if (!EnsureWalletIsAvailable(fHelp))
2019         return NullUniValue;
2020
2021     auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2022
2023     std::string strWalletEncryptionDisabledMsg = "";
2024     if (!fEnableWalletEncryption) {
2025         strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2026     }
2027
2028     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2029         throw runtime_error(
2030             "encryptwallet \"passphrase\"\n"
2031             + strWalletEncryptionDisabledMsg +
2032             "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2033             "After this, any calls that interact with private keys such as sending or signing \n"
2034             "will require the passphrase to be set prior the making these calls.\n"
2035             "Use the walletpassphrase call for this, and then walletlock call.\n"
2036             "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2037             "Note that this will shutdown the server.\n"
2038             "\nArguments:\n"
2039             "1. \"passphrase\"    (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2040             "\nExamples:\n"
2041             "\nEncrypt you wallet\n"
2042             + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2043             "\nNow set the passphrase to use the wallet, such as for signing or sending zcash\n"
2044             + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2045             "\nNow we can so something like sign\n"
2046             + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
2047             "\nNow lock the wallet again by removing the passphrase\n"
2048             + HelpExampleCli("walletlock", "") +
2049             "\nAs a json rpc call\n"
2050             + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2051         );
2052
2053     LOCK2(cs_main, pwalletMain->cs_wallet);
2054
2055     if (fHelp)
2056         return true;
2057     if (!fEnableWalletEncryption) {
2058         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2059     }
2060     if (pwalletMain->IsCrypted())
2061         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2062
2063     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2064     // Alternately, find a way to make params[0] mlock()'d to begin with.
2065     SecureString strWalletPass;
2066     strWalletPass.reserve(100);
2067     strWalletPass = params[0].get_str().c_str();
2068
2069     if (strWalletPass.length() < 1)
2070         throw runtime_error(
2071             "encryptwallet <passphrase>\n"
2072             "Encrypts the wallet with <passphrase>.");
2073
2074     if (!pwalletMain->EncryptWallet(strWalletPass))
2075         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2076
2077     // BDB seems to have a bad habit of writing old data into
2078     // slack space in .dat files; that is bad if the old data is
2079     // unencrypted private keys. So:
2080     StartShutdown();
2081     return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2082 }
2083
2084 UniValue lockunspent(const UniValue& params, bool fHelp)
2085 {
2086     if (!EnsureWalletIsAvailable(fHelp))
2087         return NullUniValue;
2088
2089     if (fHelp || params.size() < 1 || params.size() > 2)
2090         throw runtime_error(
2091             "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2092             "\nUpdates list of temporarily unspendable outputs.\n"
2093             "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2094             "A locked transaction output will not be chosen by automatic coin selection, when spending zcash.\n"
2095             "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2096             "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2097             "Also see the listunspent call\n"
2098             "\nArguments:\n"
2099             "1. unlock            (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2100             "2. \"transactions\"  (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2101             "     [           (json array of json objects)\n"
2102             "       {\n"
2103             "         \"txid\":\"id\",    (string) The transaction id\n"
2104             "         \"vout\": n         (numeric) The output number\n"
2105             "       }\n"
2106             "       ,...\n"
2107             "     ]\n"
2108
2109             "\nResult:\n"
2110             "true|false    (boolean) Whether the command was successful or not\n"
2111
2112             "\nExamples:\n"
2113             "\nList the unspent transactions\n"
2114             + HelpExampleCli("listunspent", "") +
2115             "\nLock an unspent transaction\n"
2116             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2117             "\nList the locked transactions\n"
2118             + HelpExampleCli("listlockunspent", "") +
2119             "\nUnlock the transaction again\n"
2120             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2121             "\nAs a json rpc call\n"
2122             + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2123         );
2124
2125     LOCK2(cs_main, pwalletMain->cs_wallet);
2126
2127     if (params.size() == 1)
2128         RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2129     else
2130         RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2131
2132     bool fUnlock = params[0].get_bool();
2133
2134     if (params.size() == 1) {
2135         if (fUnlock)
2136             pwalletMain->UnlockAllCoins();
2137         return true;
2138     }
2139
2140     UniValue outputs = params[1].get_array();
2141     for (size_t idx = 0; idx < outputs.size(); idx++) {
2142         const UniValue& output = outputs[idx];
2143         if (!output.isObject())
2144             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2145         const UniValue& o = output.get_obj();
2146
2147         RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2148
2149         string txid = find_value(o, "txid").get_str();
2150         if (!IsHex(txid))
2151             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2152
2153         int nOutput = find_value(o, "vout").get_int();
2154         if (nOutput < 0)
2155             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2156
2157         COutPoint outpt(uint256S(txid), nOutput);
2158
2159         if (fUnlock)
2160             pwalletMain->UnlockCoin(outpt);
2161         else
2162             pwalletMain->LockCoin(outpt);
2163     }
2164
2165     return true;
2166 }
2167
2168 UniValue listlockunspent(const UniValue& params, bool fHelp)
2169 {
2170     if (!EnsureWalletIsAvailable(fHelp))
2171         return NullUniValue;
2172
2173     if (fHelp || params.size() > 0)
2174         throw runtime_error(
2175             "listlockunspent\n"
2176             "\nReturns list of temporarily unspendable outputs.\n"
2177             "See the lockunspent call to lock and unlock transactions for spending.\n"
2178             "\nResult:\n"
2179             "[\n"
2180             "  {\n"
2181             "    \"txid\" : \"transactionid\",     (string) The transaction id locked\n"
2182             "    \"vout\" : n                      (numeric) The vout value\n"
2183             "  }\n"
2184             "  ,...\n"
2185             "]\n"
2186             "\nExamples:\n"
2187             "\nList the unspent transactions\n"
2188             + HelpExampleCli("listunspent", "") +
2189             "\nLock an unspent transaction\n"
2190             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2191             "\nList the locked transactions\n"
2192             + HelpExampleCli("listlockunspent", "") +
2193             "\nUnlock the transaction again\n"
2194             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2195             "\nAs a json rpc call\n"
2196             + HelpExampleRpc("listlockunspent", "")
2197         );
2198
2199     LOCK2(cs_main, pwalletMain->cs_wallet);
2200
2201     vector<COutPoint> vOutpts;
2202     pwalletMain->ListLockedCoins(vOutpts);
2203
2204     UniValue ret(UniValue::VARR);
2205
2206     BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2207         UniValue o(UniValue::VOBJ);
2208
2209         o.push_back(Pair("txid", outpt.hash.GetHex()));
2210         o.push_back(Pair("vout", (int)outpt.n));
2211         ret.push_back(o);
2212     }
2213
2214     return ret;
2215 }
2216
2217 UniValue settxfee(const UniValue& params, bool fHelp)
2218 {
2219     if (!EnsureWalletIsAvailable(fHelp))
2220         return NullUniValue;
2221
2222     if (fHelp || params.size() < 1 || params.size() > 1)
2223         throw runtime_error(
2224             "settxfee amount\n"
2225             "\nSet the transaction fee per kB.\n"
2226             "\nArguments:\n"
2227             "1. amount         (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
2228             "\nResult\n"
2229             "true|false        (boolean) Returns true if successful\n"
2230             "\nExamples:\n"
2231             + HelpExampleCli("settxfee", "0.00001")
2232             + HelpExampleRpc("settxfee", "0.00001")
2233         );
2234
2235     LOCK2(cs_main, pwalletMain->cs_wallet);
2236
2237     // Amount
2238     CAmount nAmount = AmountFromValue(params[0]);
2239
2240     payTxFee = CFeeRate(nAmount, 1000);
2241     return true;
2242 }
2243
2244 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2245 {
2246     if (!EnsureWalletIsAvailable(fHelp))
2247         return NullUniValue;
2248
2249     if (fHelp || params.size() != 0)
2250         throw runtime_error(
2251             "getwalletinfo\n"
2252             "Returns an object containing various wallet state info.\n"
2253             "\nResult:\n"
2254             "{\n"
2255             "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
2256             "  \"balance\": xxxxxxx,         (numeric) the total confirmed zcash balance of the wallet\n"
2257             "  \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed zcash balance of the wallet\n"
2258             "  \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
2259             "  \"txcount\": xxxxxxx,         (numeric) the total number of transactions in the wallet\n"
2260             "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2261             "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
2262             "  \"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"
2263             "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee configuration, set in ZEC/KB\n"
2264             "}\n"
2265             "\nExamples:\n"
2266             + HelpExampleCli("getwalletinfo", "")
2267             + HelpExampleRpc("getwalletinfo", "")
2268         );
2269
2270     LOCK2(cs_main, pwalletMain->cs_wallet);
2271
2272     UniValue obj(UniValue::VOBJ);
2273     obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2274     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
2275     obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2276     obj.push_back(Pair("immature_balance",    ValueFromAmount(pwalletMain->GetImmatureBalance())));
2277     obj.push_back(Pair("txcount",       (int)pwalletMain->mapWallet.size()));
2278     obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2279     obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
2280     if (pwalletMain->IsCrypted())
2281         obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2282     obj.push_back(Pair("paytxfee",      ValueFromAmount(payTxFee.GetFeePerK())));
2283     return obj;
2284 }
2285
2286 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2287 {
2288     if (!EnsureWalletIsAvailable(fHelp))
2289         return NullUniValue;
2290
2291     if (fHelp || params.size() != 0)
2292         throw runtime_error(
2293             "resendwallettransactions\n"
2294             "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2295             "Intended only for testing; the wallet code periodically re-broadcasts\n"
2296             "automatically.\n"
2297             "Returns array of transaction ids that were re-broadcast.\n"
2298             );
2299
2300     LOCK2(cs_main, pwalletMain->cs_wallet);
2301
2302     std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2303     UniValue result(UniValue::VARR);
2304     BOOST_FOREACH(const uint256& txid, txids)
2305     {
2306         result.push_back(txid.ToString());
2307     }
2308     return result;
2309 }
2310
2311 UniValue listunspent(const UniValue& params, bool fHelp)
2312 {
2313     if (!EnsureWalletIsAvailable(fHelp))
2314         return NullUniValue;
2315
2316     if (fHelp || params.size() > 3)
2317         throw runtime_error(
2318             "listunspent ( minconf maxconf  [\"address\",...] )\n"
2319             "\nReturns array of unspent transaction outputs\n"
2320             "with between minconf and maxconf (inclusive) confirmations.\n"
2321             "Optionally filter to only include txouts paid to specified addresses.\n"
2322             "Results are an array of Objects, each of which has:\n"
2323             "{txid, vout, scriptPubKey, amount, confirmations}\n"
2324             "\nArguments:\n"
2325             "1. minconf          (numeric, optional, default=1) The minimum confirmations to filter\n"
2326             "2. maxconf          (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2327             "3. \"addresses\"    (string) A json array of zcash addresses to filter\n"
2328             "    [\n"
2329             "      \"address\"   (string) zcash address\n"
2330             "      ,...\n"
2331             "    ]\n"
2332             "\nResult\n"
2333             "[                   (array of json object)\n"
2334             "  {\n"
2335             "    \"txid\" : \"txid\",        (string) the transaction id \n"
2336             "    \"vout\" : n,               (numeric) the vout value\n"
2337             "    \"address\" : \"address\",  (string) the zcash address\n"
2338             "    \"account\" : \"account\",  (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2339             "    \"scriptPubKey\" : \"key\", (string) the script key\n"
2340             "    \"amount\" : x.xxx,         (numeric) the transaction amount in btc\n"
2341             "    \"confirmations\" : n       (numeric) The number of confirmations\n"
2342             "  }\n"
2343             "  ,...\n"
2344             "]\n"
2345
2346             "\nExamples\n"
2347             + HelpExampleCli("listunspent", "")
2348             + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2349             + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2350         );
2351
2352     RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2353
2354     int nMinDepth = 1;
2355     if (params.size() > 0)
2356         nMinDepth = params[0].get_int();
2357
2358     int nMaxDepth = 9999999;
2359     if (params.size() > 1)
2360         nMaxDepth = params[1].get_int();
2361
2362     set<CBitcoinAddress> setAddress;
2363     if (params.size() > 2) {
2364         UniValue inputs = params[2].get_array();
2365         for (size_t idx = 0; idx < inputs.size(); idx++) {
2366             const UniValue& input = inputs[idx];
2367             CBitcoinAddress address(input.get_str());
2368             if (!address.IsValid())
2369                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
2370             if (setAddress.count(address))
2371                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2372            setAddress.insert(address);
2373         }
2374     }
2375
2376     UniValue results(UniValue::VARR);
2377     vector<COutput> vecOutputs;
2378     assert(pwalletMain != NULL);
2379     LOCK2(cs_main, pwalletMain->cs_wallet);
2380     pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2381     BOOST_FOREACH(const COutput& out, vecOutputs) {
2382         if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2383             continue;
2384
2385         if (setAddress.size()) {
2386             CTxDestination address;
2387             if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2388                 continue;
2389
2390             if (!setAddress.count(address))
2391                 continue;
2392         }
2393
2394         CAmount nValue = out.tx->vout[out.i].nValue;
2395         const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2396         UniValue entry(UniValue::VOBJ);
2397         entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2398         entry.push_back(Pair("vout", out.i));
2399         CTxDestination address;
2400         if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2401             entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2402             if (pwalletMain->mapAddressBook.count(address))
2403                 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2404         }
2405         entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2406         if (pk.IsPayToScriptHash()) {
2407             CTxDestination address;
2408             if (ExtractDestination(pk, address)) {
2409                 const CScriptID& hash = boost::get<CScriptID>(address);
2410                 CScript redeemScript;
2411                 if (pwalletMain->GetCScript(hash, redeemScript))
2412                     entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2413             }
2414         }
2415         entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2416         entry.push_back(Pair("confirmations",out.nDepth));
2417         entry.push_back(Pair("spendable", out.fSpendable));
2418         results.push_back(entry);
2419     }
2420
2421     return results;
2422 }
2423
2424 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2425 {
2426     if (!EnsureWalletIsAvailable(fHelp))
2427         return NullUniValue;
2428
2429     if (fHelp || params.size() != 1)
2430         throw runtime_error(
2431                             "fundrawtransaction \"hexstring\"\n"
2432                             "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2433                             "This will not modify existing inputs, and will add one change output to the outputs.\n"
2434                             "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2435                             "The inputs added will not be signed, use signrawtransaction for that.\n"
2436                             "\nArguments:\n"
2437                             "1. \"hexstring\"    (string, required) The hex string of the raw transaction\n"
2438                             "\nResult:\n"
2439                             "{\n"
2440                             "  \"hex\":       \"value\", (string)  The resulting raw transaction (hex-encoded string)\n"
2441                             "  \"fee\":       n,         (numeric) The fee added to the transaction\n"
2442                             "  \"changepos\": n          (numeric) The position of the added change output, or -1\n"
2443                             "}\n"
2444                             "\"hex\"             \n"
2445                             "\nExamples:\n"
2446                             "\nCreate a transaction with no inputs\n"
2447                             + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2448                             "\nAdd sufficient unsigned inputs to meet the output value\n"
2449                             + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2450                             "\nSign the transaction\n"
2451                             + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2452                             "\nSend the transaction\n"
2453                             + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2454                             );
2455
2456     RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2457
2458     // parse hex string from parameter
2459     CTransaction origTx;
2460     if (!DecodeHexTx(origTx, params[0].get_str()))
2461         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2462
2463     CMutableTransaction tx(origTx);
2464     CAmount nFee;
2465     string strFailReason;
2466     int nChangePos = -1;
2467     if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2468         throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2469
2470     UniValue result(UniValue::VOBJ);
2471     result.push_back(Pair("hex", EncodeHexTx(tx)));
2472     result.push_back(Pair("changepos", nChangePos));
2473     result.push_back(Pair("fee", ValueFromAmount(nFee)));
2474
2475     return result;
2476 }
2477
2478 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2479 {
2480     if (fHelp) {
2481         throw runtime_error(
2482             "zcsamplejoinsplit\n"
2483             "\n"
2484             "Perform a joinsplit and return the JSDescription.\n"
2485             );
2486     }
2487
2488     LOCK(cs_main);
2489
2490     uint256 pubKeyHash;
2491     uint256 anchor = ZCIncrementalMerkleTree().root();
2492     JSDescription samplejoinsplit(*pzcashParams,
2493                                   pubKeyHash,
2494                                   anchor,
2495                                   {JSInput(), JSInput()},
2496                                   {JSOutput(), JSOutput()},
2497                                   0,
2498                                   0);
2499
2500     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2501     ss << samplejoinsplit;
2502
2503     return HexStr(ss.begin(), ss.end());
2504 }
2505
2506 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2507 {
2508     if (!EnsureWalletIsAvailable(fHelp)) {
2509         return NullUniValue;
2510     }
2511
2512     if (fHelp || params.size() < 2) {
2513         throw runtime_error(
2514             "zcbenchmark benchmarktype samplecount\n"
2515             "\n"
2516             "Runs a benchmark of the selected type samplecount times,\n"
2517             "returning the running times of each sample.\n"
2518             "\n"
2519             "Output: [\n"
2520             "  {\n"
2521             "    \"runningtime\": runningtime\n"
2522             "  },\n"
2523             "  {\n"
2524             "    \"runningtime\": runningtime\n"
2525             "  }\n"
2526             "  ...\n"
2527             "]\n"
2528             );
2529     }
2530
2531     LOCK(cs_main);
2532
2533     std::string benchmarktype = params[0].get_str();
2534     int samplecount = params[1].get_int();
2535
2536     if (samplecount <= 0) {
2537         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2538     }
2539
2540     std::vector<double> sample_times;
2541
2542     if (benchmarktype == "createjoinsplit") {
2543         /* Load the proving now key so that it doesn't happen as part of the
2544          * first joinsplit. */
2545         pzcashParams->loadProvingKey();
2546     }
2547
2548     JSDescription samplejoinsplit;
2549
2550     if (benchmarktype == "verifyjoinsplit") {
2551         CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2552         ss >> samplejoinsplit;
2553     }
2554
2555     for (int i = 0; i < samplecount; i++) {
2556         if (benchmarktype == "sleep") {
2557             sample_times.push_back(benchmark_sleep());
2558         } else if (benchmarktype == "parameterloading") {
2559             sample_times.push_back(benchmark_parameter_loading());
2560         } else if (benchmarktype == "createjoinsplit") {
2561             if (params.size() < 3) {
2562                 sample_times.push_back(benchmark_create_joinsplit());
2563             } else {
2564                 int nThreads = params[2].get_int();
2565                 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2566                 // Divide by nThreads^2 to get average seconds per JoinSplit because
2567                 // we are running one JoinSplit per thread.
2568                 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2569             }
2570         } else if (benchmarktype == "verifyjoinsplit") {
2571             sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2572 #ifdef ENABLE_MINING
2573         } else if (benchmarktype == "solveequihash") {
2574             if (params.size() < 3) {
2575                 sample_times.push_back(benchmark_solve_equihash());
2576             } else {
2577                 int nThreads = params[2].get_int();
2578                 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2579                 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2580             }
2581 #endif
2582         } else if (benchmarktype == "verifyequihash") {
2583             sample_times.push_back(benchmark_verify_equihash());
2584         } else if (benchmarktype == "validatelargetx") {
2585             sample_times.push_back(benchmark_large_tx());
2586         } else if (benchmarktype == "trydecryptnotes") {
2587             int nAddrs = params[2].get_int();
2588             sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2589         } else if (benchmarktype == "incnotewitnesses") {
2590             int nTxs = params[2].get_int();
2591             sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2592         } else if (benchmarktype == "connectblockslow") {
2593             if (Params().NetworkIDString() != "regtest") {
2594                 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2595             }
2596             sample_times.push_back(benchmark_connectblock_slow());
2597         } else {
2598             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2599         }
2600     }
2601
2602     UniValue results(UniValue::VARR);
2603     for (auto time : sample_times) {
2604         UniValue result(UniValue::VOBJ);
2605         result.push_back(Pair("runningtime", time));
2606         results.push_back(result);
2607     }
2608
2609     return results;
2610 }
2611
2612 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2613 {
2614     if (!EnsureWalletIsAvailable(fHelp)) {
2615         return NullUniValue;
2616     }
2617
2618     if (fHelp || params.size() != 2) {
2619         throw runtime_error(
2620             "zcrawreceive zcsecretkey encryptednote\n"
2621             "\n"
2622             "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2623             "are in the blockchain as indicated by the \"exists\" result.\n"
2624             "\n"
2625             "Output: {\n"
2626             "  \"amount\": value,\n"
2627             "  \"note\": noteplaintext,\n"
2628             "  \"exists\": exists\n"
2629             "}\n"
2630             );
2631     }
2632
2633     RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2634
2635     LOCK(cs_main);
2636
2637     CZCSpendingKey spendingkey(params[0].get_str());
2638     SpendingKey k = spendingkey.Get();
2639
2640     uint256 epk;
2641     unsigned char nonce;
2642     ZCNoteEncryption::Ciphertext ct;
2643     uint256 h_sig;
2644
2645     {
2646         CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2647         try {
2648             ssData >> nonce;
2649             ssData >> epk;
2650             ssData >> ct;
2651             ssData >> h_sig;
2652         } catch(const std::exception &) {
2653             throw runtime_error(
2654                 "encrypted_note could not be decoded"
2655             );
2656         }
2657     }
2658
2659     ZCNoteDecryption decryptor(k.viewing_key());
2660
2661     NotePlaintext npt = NotePlaintext::decrypt(
2662         decryptor,
2663         ct,
2664         epk,
2665         h_sig,
2666         nonce
2667     );
2668     PaymentAddress payment_addr = k.address();
2669     Note decrypted_note = npt.note(payment_addr);
2670
2671     assert(pwalletMain != NULL);
2672     std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2673     uint256 anchor;
2674     uint256 commitment = decrypted_note.cm();
2675     pwalletMain->WitnessNoteCommitment(
2676         {commitment},
2677         witnesses,
2678         anchor
2679     );
2680
2681     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2682     ss << npt;
2683
2684     UniValue result(UniValue::VOBJ);
2685     result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2686     result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2687     result.push_back(Pair("exists", (bool) witnesses[0]));
2688     return result;
2689 }
2690
2691
2692
2693 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
2694 {
2695     if (!EnsureWalletIsAvailable(fHelp)) {
2696         return NullUniValue;
2697     }
2698
2699     if (fHelp || params.size() != 5) {
2700         throw runtime_error(
2701             "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
2702             "  inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
2703             "  outputs: a JSON object mapping {zcaddr: value, ...}\n"
2704             "\n"
2705             "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
2706             "Outputs are confidential between sender/receiver. The vpub_old and\n"
2707             "vpub_new values are globally public and move transparent value into\n"
2708             "or out of the confidential value store, respectively.\n"
2709             "\n"
2710             "Note: The caller is responsible for delivering the output enc1 and\n"
2711             "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2712             "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2713             "payments in-band on the blockchain.)\n"
2714             "\n"
2715             "Output: {\n"
2716             "  \"encryptednote1\": enc1,\n"
2717             "  \"encryptednote2\": enc2,\n"
2718             "  \"rawtxn\": rawtxout\n"
2719             "}\n"
2720             );
2721     }
2722
2723     LOCK(cs_main);
2724
2725     CTransaction tx;
2726     if (!DecodeHexTx(tx, params[0].get_str()))
2727         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2728
2729     UniValue inputs = params[1].get_obj();
2730     UniValue outputs = params[2].get_obj();
2731
2732     CAmount vpub_old(0);
2733     CAmount vpub_new(0);
2734
2735     if (params[3].get_real() != 0.0)
2736         vpub_old = AmountFromValue(params[3]);
2737
2738     if (params[4].get_real() != 0.0)
2739         vpub_new = AmountFromValue(params[4]);
2740
2741     std::vector<JSInput> vjsin;
2742     std::vector<JSOutput> vjsout;
2743     std::vector<Note> notes;
2744     std::vector<SpendingKey> keys;
2745     std::vector<uint256> commitments;
2746
2747     for (const string& name_ : inputs.getKeys()) {
2748         CZCSpendingKey spendingkey(inputs[name_].get_str());
2749         SpendingKey k = spendingkey.Get();
2750
2751         keys.push_back(k);
2752
2753         NotePlaintext npt;
2754
2755         {
2756             CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2757             ssData >> npt;
2758         }
2759
2760         PaymentAddress addr = k.address();
2761         Note note = npt.note(addr);
2762         notes.push_back(note);
2763         commitments.push_back(note.cm());
2764     }
2765
2766     uint256 anchor;
2767     std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2768     pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2769
2770     assert(witnesses.size() == notes.size());
2771     assert(notes.size() == keys.size());
2772
2773     {
2774         for (size_t i = 0; i < witnesses.size(); i++) {
2775             if (!witnesses[i]) {
2776                 throw runtime_error(
2777                     "joinsplit input could not be found in tree"
2778                 );
2779             }
2780
2781             vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2782         }
2783     }
2784
2785     while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2786         vjsin.push_back(JSInput());
2787     }
2788
2789     for (const string& name_ : outputs.getKeys()) {
2790         CZCPaymentAddress pubaddr(name_);
2791         PaymentAddress addrTo = pubaddr.Get();
2792         CAmount nAmount = AmountFromValue(outputs[name_]);
2793
2794         vjsout.push_back(JSOutput(addrTo, nAmount));
2795     }
2796
2797     while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2798         vjsout.push_back(JSOutput());
2799     }
2800
2801     // TODO
2802     if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2803         throw runtime_error("unsupported joinsplit input/output counts");
2804     }
2805
2806     uint256 joinSplitPubKey;
2807     unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2808     crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
2809
2810     CMutableTransaction mtx(tx);
2811     mtx.nVersion = 2;
2812     mtx.joinSplitPubKey = joinSplitPubKey;
2813
2814     JSDescription jsdesc(*pzcashParams,
2815                          joinSplitPubKey,
2816                          anchor,
2817                          {vjsin[0], vjsin[1]},
2818                          {vjsout[0], vjsout[1]},
2819                          vpub_old,
2820                          vpub_new);
2821
2822     {
2823         auto verifier = libzcash::ProofVerifier::Strict();
2824         assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
2825     }
2826
2827     mtx.vjoinsplit.push_back(jsdesc);
2828
2829     // Empty output script.
2830     CScript scriptCode;
2831     CTransaction signTx(mtx);
2832     uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
2833
2834     // Add the signature
2835     assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2836                          dataToBeSigned.begin(), 32,
2837                          joinSplitPrivKey
2838                         ) == 0);
2839
2840     // Sanity check
2841     assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2842                                        dataToBeSigned.begin(), 32,
2843                                        mtx.joinSplitPubKey.begin()
2844                                       ) == 0);
2845
2846     CTransaction rawTx(mtx);
2847
2848     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2849     ss << rawTx;
2850
2851     std::string encryptedNote1;
2852     std::string encryptedNote2;
2853     {
2854         CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2855         ss2 << ((unsigned char) 0x00);
2856         ss2 << jsdesc.ephemeralKey;
2857         ss2 << jsdesc.ciphertexts[0];
2858         ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2859
2860         encryptedNote1 = HexStr(ss2.begin(), ss2.end());
2861     }
2862     {
2863         CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2864         ss2 << ((unsigned char) 0x01);
2865         ss2 << jsdesc.ephemeralKey;
2866         ss2 << jsdesc.ciphertexts[1];
2867         ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2868
2869         encryptedNote2 = HexStr(ss2.begin(), ss2.end());
2870     }
2871
2872     UniValue result(UniValue::VOBJ);
2873     result.push_back(Pair("encryptednote1", encryptedNote1));
2874     result.push_back(Pair("encryptednote2", encryptedNote2));
2875     result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2876     return result;
2877 }
2878
2879 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
2880 {
2881     if (!EnsureWalletIsAvailable(fHelp)) {
2882         return NullUniValue;
2883     }
2884
2885     if (fHelp || params.size() != 0) {
2886         throw runtime_error(
2887             "zcrawkeygen\n"
2888             "\n"
2889             "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
2890             "\n"
2891             "Output: {\n"
2892             "  \"zcaddress\": zcaddr,\n"
2893             "  \"zcsecretkey\": zcsecretkey,\n"
2894             "}\n"
2895             );
2896     }
2897
2898     auto k = SpendingKey::random();
2899     auto addr = k.address();
2900     auto viewing_key = k.viewing_key();
2901
2902     CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
2903
2904     viewing << viewing_key;
2905
2906     CZCPaymentAddress pubaddr(addr);
2907     CZCSpendingKey spendingkey(k);
2908     std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
2909
2910     UniValue result(UniValue::VOBJ);
2911     result.push_back(Pair("zcaddress", pubaddr.ToString()));
2912     result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2913     result.push_back(Pair("zcviewingkey", viewing_hex));
2914     return result;
2915 }
2916
2917
2918 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
2919 {
2920     if (!EnsureWalletIsAvailable(fHelp))
2921         return NullUniValue;
2922
2923     if (fHelp || params.size() > 0)
2924         throw runtime_error(
2925             "z_getnewaddress\n"
2926             "\nReturns a new zaddr for receiving payments.\n"
2927             "\nArguments:\n"
2928             "\nResult:\n"
2929             "\"zcashaddress\"    (string) The new zaddr\n"
2930             "\nExamples:\n"
2931             + HelpExampleCli("z_getnewaddress", "")
2932             + HelpExampleRpc("z_getnewaddress", "")
2933         );
2934
2935     LOCK2(cs_main, pwalletMain->cs_wallet);
2936
2937     EnsureWalletIsUnlocked();
2938
2939     CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2940     std::string result = pubaddr.ToString();
2941     return result;
2942 }
2943
2944
2945 UniValue z_listaddresses(const UniValue& params, bool fHelp)
2946 {
2947     if (!EnsureWalletIsAvailable(fHelp))
2948         return NullUniValue;
2949
2950     if (fHelp || params.size() > 1)
2951         throw runtime_error(
2952             "z_listaddresses\n"
2953             "\nReturns the list of zaddr belonging to the wallet.\n"
2954             "\nArguments:\n"
2955             "\nResult:\n"
2956             "[                     (json array of string)\n"
2957             "  \"zaddr\"           (string) a zaddr belonging to the wallet\n"
2958             "  ,...\n"
2959             "]\n"
2960             "\nExamples:\n"
2961             + HelpExampleCli("z_listaddresses", "")
2962             + HelpExampleRpc("z_listaddresses", "")
2963         );
2964
2965     LOCK2(cs_main, pwalletMain->cs_wallet);
2966
2967     UniValue ret(UniValue::VARR);
2968     std::set<libzcash::PaymentAddress> addresses;
2969     pwalletMain->GetPaymentAddresses(addresses);
2970     for (auto addr : addresses ) {
2971         ret.push_back(CZCPaymentAddress(addr).ToString());
2972     }
2973     return ret;
2974 }
2975
2976 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
2977     set<CBitcoinAddress> setAddress;
2978     vector<COutput> vecOutputs;
2979     CAmount balance = 0;
2980
2981     if (transparentAddress.length() > 0) {
2982         CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
2983         if (!taddr.IsValid()) {
2984             throw std::runtime_error("invalid transparent address");
2985         }
2986         setAddress.insert(taddr);
2987     }
2988
2989     LOCK2(cs_main, pwalletMain->cs_wallet);
2990
2991     pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2992
2993     BOOST_FOREACH(const COutput& out, vecOutputs) {
2994         if (out.nDepth < minDepth) {
2995             continue;
2996         }
2997
2998         if (setAddress.size()) {
2999             CTxDestination address;
3000             if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3001                 continue;
3002             }
3003
3004             if (!setAddress.count(address)) {
3005                 continue;
3006             }
3007         }
3008
3009         CAmount nValue = out.tx->vout[out.i].nValue;
3010         balance += nValue;
3011     }
3012     return balance;
3013 }
3014
3015 CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
3016     CAmount balance = 0;
3017     std::vector<CNotePlaintextEntry> entries;
3018     LOCK2(cs_main, pwalletMain->cs_wallet);
3019     pwalletMain->GetFilteredNotes(entries, address, minDepth);
3020     for (auto & entry : entries) {
3021         balance += CAmount(entry.plaintext.value);
3022     }
3023     return balance;
3024 }
3025
3026
3027 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3028 {
3029     if (!EnsureWalletIsAvailable(fHelp))
3030         return NullUniValue;
3031
3032     if (fHelp || params.size()==0 || params.size() >2)
3033         throw runtime_error(
3034             "z_listreceivedbyaddress \"address\" ( minconf )\n"
3035             "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3036             "\nArguments:\n"
3037             "1. \"address\"      (string) The private address.\n"
3038             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3039             "\nResult:\n"
3040             "{\n"
3041             "  \"txid\": xxxxx,     (string) the transaction id\n"
3042             "  \"amount\": xxxxx,   (numeric) the amount of value in the note\n"
3043             "  \"memo\": xxxxx,     (string) hexademical string representation of memo field\n"
3044             "}\n"
3045         );
3046
3047     LOCK2(cs_main, pwalletMain->cs_wallet);
3048
3049     int nMinDepth = 1;
3050     if (params.size() > 1) {
3051         nMinDepth = params[1].get_int();
3052     }
3053     if (nMinDepth < 0) {
3054         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3055     }
3056
3057     // Check that the from address is valid.
3058     auto fromaddress = params[0].get_str();
3059
3060     libzcash::PaymentAddress zaddr;
3061     CZCPaymentAddress address(fromaddress);
3062     try {
3063         zaddr = address.Get();
3064     } catch (const std::runtime_error&) {
3065         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3066     }
3067
3068     if (!pwalletMain->HaveSpendingKey(zaddr)) {
3069         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3070     }
3071
3072
3073     UniValue result(UniValue::VARR);
3074     std::vector<CNotePlaintextEntry> entries;
3075     pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false);
3076     for (CNotePlaintextEntry & entry : entries) {
3077         UniValue obj(UniValue::VOBJ);
3078         obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3079         obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3080         std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3081         obj.push_back(Pair("memo", HexStr(data)));
3082         result.push_back(obj);
3083     }
3084     return result;
3085 }
3086
3087
3088 UniValue z_getbalance(const UniValue& params, bool fHelp)
3089 {
3090     if (!EnsureWalletIsAvailable(fHelp))
3091         return NullUniValue;
3092
3093     if (fHelp || params.size()==0 || params.size() >2)
3094         throw runtime_error(
3095             "z_getbalance \"address\" ( minconf )\n"
3096             "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3097             "\nArguments:\n"
3098             "1. \"address\"      (string) The selected address. It may be a transparent or private address.\n"
3099             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3100             "\nResult:\n"
3101             "amount              (numeric) The total amount in ZEC received for this address.\n"
3102             "\nExamples:\n"
3103             "\nThe total amount received by address \"myaddress\"\n"
3104             + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3105             "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3106             + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3107             "\nAs a json rpc call\n"
3108             + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3109         );
3110
3111     LOCK2(cs_main, pwalletMain->cs_wallet);
3112
3113     int nMinDepth = 1;
3114     if (params.size() > 1) {
3115         nMinDepth = params[1].get_int();
3116     }
3117     if (nMinDepth < 0) {
3118         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3119     }
3120
3121     // Check that the from address is valid.
3122     auto fromaddress = params[0].get_str();
3123     bool fromTaddr = false;
3124     CBitcoinAddress taddr(fromaddress);
3125     fromTaddr = taddr.IsValid();
3126     libzcash::PaymentAddress zaddr;
3127     if (!fromTaddr) {
3128         CZCPaymentAddress address(fromaddress);
3129         try {
3130             zaddr = address.Get();
3131         } catch (const std::runtime_error&) {
3132             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3133         }
3134         if (!pwalletMain->HaveSpendingKey(zaddr)) {
3135              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3136         }
3137     }
3138
3139     CAmount nBalance = 0;
3140     if (fromTaddr) {
3141         nBalance = getBalanceTaddr(fromaddress, nMinDepth);
3142     } else {
3143         nBalance = getBalanceZaddr(fromaddress, nMinDepth);
3144     }
3145
3146     return ValueFromAmount(nBalance);
3147 }
3148
3149
3150 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3151 {
3152     if (!EnsureWalletIsAvailable(fHelp))
3153         return NullUniValue;
3154
3155     if (fHelp || params.size() > 1)
3156         throw runtime_error(
3157             "z_gettotalbalance ( minconf )\n"
3158             "\nReturn the total value of funds stored in the node’s wallet.\n"
3159             "\nArguments:\n"
3160             "1. minconf          (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3161             "\nResult:\n"
3162             "{\n"
3163             "  \"transparent\": xxxxx,     (numeric) the total balance of transparent funds\n"
3164             "  \"private\": xxxxx,         (numeric) the total balance of private funds\n"
3165             "  \"total\": xxxxx,           (numeric) the total balance of both transparent and private funds\n"
3166             "}\n"
3167             "\nExamples:\n"
3168             "\nThe total amount in the wallet\n"
3169             + HelpExampleCli("z_gettotalbalance", "") +
3170             "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3171             + HelpExampleCli("z_gettotalbalance", "5") +
3172             "\nAs a json rpc call\n"
3173             + HelpExampleRpc("z_gettotalbalance", "5")
3174         );
3175
3176     LOCK2(cs_main, pwalletMain->cs_wallet);
3177
3178     int nMinDepth = 1;
3179     if (params.size() == 1) {
3180         nMinDepth = params[0].get_int();
3181     }
3182     if (nMinDepth < 0) {
3183         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3184     }
3185
3186     // getbalance and "getbalance * 1 true" should return the same number
3187     // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3188     // pwalletMain->GetBalance() does not accept min depth parameter
3189     // so we use our own method to get balance of utxos.
3190     CAmount nBalance = getBalanceTaddr("", nMinDepth);
3191     CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
3192     CAmount nTotalBalance = nBalance + nPrivateBalance;
3193     UniValue result(UniValue::VOBJ);
3194     result.push_back(Pair("transparent", FormatMoney(nBalance)));
3195     result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3196     result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3197     return result;
3198 }
3199
3200 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3201 {
3202     if (!EnsureWalletIsAvailable(fHelp))
3203         return NullUniValue;
3204
3205     if (fHelp || params.size() > 1)
3206         throw runtime_error(
3207             "z_getoperationresult ([\"operationid\", ... ]) \n"
3208             "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3209             + HelpRequiringPassphrase() + "\n"
3210             "\nArguments:\n"
3211             "1. \"operationid\"         (array, optional) A list of operation ids we are interested in.  If not provided, examine all operations known to the node.\n"
3212             "\nResult:\n"
3213             "\"    [object, ...]\"      (array) A list of JSON objects\n"
3214         );
3215
3216     // This call will remove finished operations
3217     return z_getoperationstatus_IMPL(params, true);
3218 }
3219
3220 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3221 {
3222    if (!EnsureWalletIsAvailable(fHelp))
3223         return NullUniValue;
3224
3225     if (fHelp || params.size() > 1)
3226         throw runtime_error(
3227             "z_getoperationstatus ([\"operationid\", ... ]) \n"
3228             "\nGet operation status and any associated result or error data.  The operation will remain in memory."
3229             + HelpRequiringPassphrase() + "\n"
3230             "\nArguments:\n"
3231             "1. \"operationid\"         (array, optional) A list of operation ids we are interested in.  If not provided, examine all operations known to the node.\n"
3232             "\nResult:\n"
3233             "\"    [object, ...]\"      (array) A list of JSON objects\n"
3234         );
3235
3236    // This call is idempotent so we don't want to remove finished operations
3237    return z_getoperationstatus_IMPL(params, false);
3238 }
3239
3240 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3241 {
3242     LOCK2(cs_main, pwalletMain->cs_wallet);
3243
3244     std::set<AsyncRPCOperationId> filter;
3245     if (params.size()==1) {
3246         UniValue ids = params[0].get_array();
3247         for (const UniValue & v : ids.getValues()) {
3248             filter.insert(v.get_str());
3249         }
3250     }
3251     bool useFilter = (filter.size()>0);
3252
3253     UniValue ret(UniValue::VARR);
3254     std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3255     std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3256
3257     for (auto id : ids) {
3258         if (useFilter && !filter.count(id))
3259             continue;
3260
3261         std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3262         if (!operation) {
3263             continue;
3264             // It's possible that the operation was removed from the internal queue and map during this loop
3265             // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3266         }
3267
3268         UniValue obj = operation->getStatus();
3269         std::string s = obj["status"].get_str();
3270         if (fRemoveFinishedOperations) {
3271             // Caller is only interested in retrieving finished results
3272             if ("success"==s || "failed"==s || "cancelled"==s) {
3273                 ret.push_back(obj);
3274                 q->popOperationForId(id);
3275             }
3276         } else {
3277             ret.push_back(obj);
3278         }
3279     }
3280
3281     std::vector<UniValue> arrTmp = ret.getValues();
3282
3283     // sort results chronologically by creation_time
3284     std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3285         const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3286         const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3287         return t1 < t2;
3288     });
3289
3290     ret.clear();
3291     ret.setArray();
3292     ret.push_backV(arrTmp);
3293
3294     return ret;
3295 }
3296
3297
3298 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3299 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3300 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3301 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3302 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS    ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3303
3304 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3305 #define CTXIN_SPEND_DUST_SIZE   148
3306 #define CTXOUT_REGULAR_SIZE     34
3307
3308 UniValue z_sendmany(const UniValue& params, bool fHelp)
3309 {
3310     if (!EnsureWalletIsAvailable(fHelp))
3311         return NullUniValue;
3312
3313     if (fHelp || params.size() < 2 || params.size() > 4)
3314         throw runtime_error(
3315             "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3316             "\nSend multiple times. Amounts are double-precision floating point numbers."
3317             "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3318             "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3319             + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3320             + HelpRequiringPassphrase() + "\n"
3321             "\nArguments:\n"
3322             "1. \"fromaddress\"         (string, required) The taddr or zaddr to send the funds from.\n"
3323             "2. \"amounts\"             (array, required) An array of json objects representing the amounts to send.\n"
3324             "    [{\n"
3325             "      \"address\":address  (string, required) The address is a taddr or zaddr\n"
3326             "      \"amount\":amount    (numeric, required) The numeric amount in ZEC is the value\n"
3327             "      \"memo\":memo        (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3328             "    }, ... ]\n"
3329             "3. minconf               (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3330             "4. fee                   (numeric, optional, default="
3331             + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3332             "\nResult:\n"
3333             "\"operationid\"          (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3334         );
3335
3336     LOCK2(cs_main, pwalletMain->cs_wallet);
3337
3338     // Check that the from address is valid.
3339     auto fromaddress = params[0].get_str();
3340     bool fromTaddr = false;
3341     CBitcoinAddress taddr(fromaddress);
3342     fromTaddr = taddr.IsValid();
3343     libzcash::PaymentAddress zaddr;
3344     if (!fromTaddr) {
3345         CZCPaymentAddress address(fromaddress);
3346         try {
3347             zaddr = address.Get();
3348         } catch (const std::runtime_error&) {
3349             // invalid
3350             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3351         }
3352     }
3353
3354     // Check that we have the spending key
3355     if (!fromTaddr) {
3356         if (!pwalletMain->HaveSpendingKey(zaddr)) {
3357              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3358         }
3359     }
3360
3361     UniValue outputs = params[1].get_array();
3362
3363     if (outputs.size()==0)
3364         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3365
3366     // Keep track of addresses to spot duplicates
3367     set<std::string> setAddress;
3368
3369     // Recipients
3370     std::vector<SendManyRecipient> taddrRecipients;
3371     std::vector<SendManyRecipient> zaddrRecipients;
3372     CAmount nTotalOut = 0;
3373
3374     for (const UniValue& o : outputs.getValues()) {
3375         if (!o.isObject())
3376             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3377
3378         // sanity check, report error if unknown key-value pairs
3379         for (const string& name_ : o.getKeys()) {
3380             std::string s = name_;
3381             if (s != "address" && s != "amount" && s!="memo")
3382                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3383         }
3384
3385         string address = find_value(o, "address").get_str();
3386         bool isZaddr = false;
3387         CBitcoinAddress taddr(address);
3388         if (!taddr.IsValid()) {
3389             try {
3390                 CZCPaymentAddress zaddr(address);
3391                 zaddr.Get();
3392                 isZaddr = true;
3393             } catch (const std::runtime_error&) {
3394                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3395             }
3396         }
3397
3398         if (setAddress.count(address))
3399             throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3400         setAddress.insert(address);
3401
3402         UniValue memoValue = find_value(o, "memo");
3403         string memo;
3404         if (!memoValue.isNull()) {
3405             memo = memoValue.get_str();
3406             if (!isZaddr) {
3407                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr.  It can only be used with a zaddr.");
3408             } else if (!IsHex(memo)) {
3409                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3410             }
3411             if (memo.length() > ZC_MEMO_SIZE*2) {
3412                 throw JSONRPCError(RPC_INVALID_PARAMETER,  strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3413             }
3414         }
3415
3416         UniValue av = find_value(o, "amount");
3417         CAmount nAmount = AmountFromValue( av );
3418         if (nAmount < 0)
3419             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3420
3421         if (isZaddr) {
3422             zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3423         } else {
3424             taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3425         }
3426
3427         nTotalOut += nAmount;
3428     }
3429
3430     // Check the number of zaddr outputs does not exceed the limit.
3431     if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS)  {
3432         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3433     }
3434
3435     // As a sanity check, estimate and verify that the size of the transaction will be valid.
3436     // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3437     size_t txsize = 0;
3438     CMutableTransaction mtx;
3439     mtx.nVersion = 2;
3440     for (int i = 0; i < zaddrRecipients.size(); i++) {
3441         mtx.vjoinsplit.push_back(JSDescription());
3442     }
3443     CTransaction tx(mtx);
3444     txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3445     if (fromTaddr) {
3446         txsize += CTXIN_SPEND_DUST_SIZE;
3447         txsize += CTXOUT_REGULAR_SIZE;      // There will probably be taddr change
3448     }
3449     txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3450     if (txsize > MAX_TX_SIZE) {
3451         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3452     }
3453
3454     // Minimum confirmations
3455     int nMinDepth = 1;
3456     if (params.size() > 2) {
3457         nMinDepth = params[2].get_int();
3458     }
3459     if (nMinDepth < 0) {
3460         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3461     }
3462
3463     // Fee in Zatoshis, not currency format)
3464     CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3465     if (params.size() > 3) {
3466         if (params[3].get_real() == 0.0) {
3467             nFee = 0;
3468         } else {
3469             nFee = AmountFromValue( params[3] );
3470         }
3471
3472         // Check that the user specified fee is sane.
3473         if (nFee > nTotalOut) {
3474             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3475         }
3476     }
3477
3478     // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3479     UniValue o(UniValue::VOBJ);
3480     o.push_back(Pair("fromaddress", params[0]));
3481     o.push_back(Pair("amounts", params[1]));
3482     o.push_back(Pair("minconf", nMinDepth));
3483     o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3484     UniValue contextInfo = o;
3485
3486     // Create operation and add to global queue
3487     std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3488     std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3489     q->addOperation(operation);
3490     AsyncRPCOperationId operationId = operation->getId();
3491     return operationId;
3492 }
3493
3494
3495 UniValue z_listoperationids(const UniValue& params, bool fHelp)
3496 {
3497     if (!EnsureWalletIsAvailable(fHelp))
3498         return NullUniValue;
3499
3500     if (fHelp || params.size() > 1)
3501         throw runtime_error(
3502             "z_listoperationids\n"
3503             "\nReturns the list of operation ids currently known to the wallet.\n"
3504             "\nArguments:\n"
3505             "1. \"status\"         (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
3506             "\nResult:\n"
3507             "[                     (json array of string)\n"
3508             "  \"operationid\"       (string) an operation id belonging to the wallet\n"
3509             "  ,...\n"
3510             "]\n"
3511             "\nExamples:\n"
3512             + HelpExampleCli("z_listoperationids", "")
3513             + HelpExampleRpc("z_listoperationids", "")
3514         );
3515
3516     LOCK2(cs_main, pwalletMain->cs_wallet);
3517
3518     std::string filter;
3519     bool useFilter = false;
3520     if (params.size()==1) {
3521         filter = params[0].get_str();
3522         useFilter = true;
3523     }
3524
3525     UniValue ret(UniValue::VARR);
3526     std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3527     std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3528     for (auto id : ids) {
3529         std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3530         if (!operation) {
3531             continue;
3532         }
3533         std::string state = operation->getStateAsString();
3534         if (useFilter && filter.compare(state)!=0)
3535             continue;
3536         ret.push_back(id);
3537     }
3538
3539     return ret;
3540 }
This page took 0.224058 seconds and 4 git commands to generate.