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