]> Git Repo - VerusCoin.git/blob - src/rpcwallet.cpp
Mention `*` value for account in documentation for `getbalance` RPC
[VerusCoin.git] / src / rpcwallet.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "base58.h"
7 #include "rpcserver.h"
8 #include "init.h"
9 #include "net.h"
10 #include "netbase.h"
11 #include "util.h"
12 #include "wallet.h"
13 #include "walletdb.h"
14
15 #include <stdint.h>
16
17 #include <boost/assign/list_of.hpp>
18 #include "json/json_spirit_utils.h"
19 #include "json/json_spirit_value.h"
20
21 using namespace std;
22 using namespace boost;
23 using namespace boost::assign;
24 using namespace json_spirit;
25
26 int64_t nWalletUnlockTime;
27 static CCriticalSection cs_nWalletUnlockTime;
28
29 std::string HelpRequiringPassphrase()
30 {
31     return pwalletMain && pwalletMain->IsCrypted()
32         ? "\nRequires wallet passphrase to be set with walletpassphrase call."
33         : "";
34 }
35
36 void EnsureWalletIsUnlocked()
37 {
38     if (pwalletMain->IsLocked())
39         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
40 }
41
42 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
43 {
44     int confirms = wtx.GetDepthInMainChain();
45     entry.push_back(Pair("confirmations", confirms));
46     if (wtx.IsCoinBase())
47         entry.push_back(Pair("generated", true));
48     if (confirms)
49     {
50         entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
51         entry.push_back(Pair("blockindex", wtx.nIndex));
52         entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
53     }
54     entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
55     entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
56     entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
57     BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
58         entry.push_back(Pair(item.first, item.second));
59 }
60
61 string AccountFromValue(const Value& value)
62 {
63     string strAccount = value.get_str();
64     if (strAccount == "*")
65         throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
66     return strAccount;
67 }
68
69 Value getnewaddress(const Array& params, bool fHelp)
70 {
71     if (fHelp || params.size() > 1)
72         throw runtime_error(
73             "getnewaddress ( \"account\" )\n"
74             "\nReturns a new Bitcoin address for receiving payments.\n"
75             "If 'account' is specified (recommended), it is added to the address book \n"
76             "so payments received with the address will be credited to 'account'.\n"
77             "\nArguments:\n"
78             "1. \"account\"        (string, optional) 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"
79             "\nResult:\n"
80             "\"bitcoinaddress\"    (string) The new bitcoin address\n"
81             "\nExamples:\n"
82             + HelpExampleCli("getnewaddress", "")
83             + HelpExampleCli("getnewaddress", "\"\"")
84             + HelpExampleCli("getnewaddress", "\"myaccount\"")
85             + HelpExampleRpc("getnewaddress", "\"myaccount\"")
86         );
87
88     // Parse the account first so we don't generate a key if there's an error
89     string strAccount;
90     if (params.size() > 0)
91         strAccount = AccountFromValue(params[0]);
92
93     if (!pwalletMain->IsLocked())
94         pwalletMain->TopUpKeyPool();
95
96     // Generate a new key that is added to wallet
97     CPubKey newKey;
98     if (!pwalletMain->GetKeyFromPool(newKey))
99         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
100     CKeyID keyID = newKey.GetID();
101
102     pwalletMain->SetAddressBook(keyID, strAccount, "receive");
103
104     return CBitcoinAddress(keyID).ToString();
105 }
106
107
108 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
109 {
110     CWalletDB walletdb(pwalletMain->strWalletFile);
111
112     CAccount account;
113     walletdb.ReadAccount(strAccount, account);
114
115     bool bKeyUsed = false;
116
117     // Check if the current key has been used
118     if (account.vchPubKey.IsValid())
119     {
120         CScript scriptPubKey;
121         scriptPubKey.SetDestination(account.vchPubKey.GetID());
122         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
123              it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
124              ++it)
125         {
126             const CWalletTx& wtx = (*it).second;
127             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
128                 if (txout.scriptPubKey == scriptPubKey)
129                     bKeyUsed = true;
130         }
131     }
132
133     // Generate a new key
134     if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
135     {
136         if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
137             throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
138
139         pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
140         walletdb.WriteAccount(strAccount, account);
141     }
142
143     return CBitcoinAddress(account.vchPubKey.GetID());
144 }
145
146 Value getaccountaddress(const Array& params, bool fHelp)
147 {
148     if (fHelp || params.size() != 1)
149         throw runtime_error(
150             "getaccountaddress \"account\"\n"
151             "\nReturns the current Bitcoin address for receiving payments to this account.\n"
152             "\nArguments:\n"
153             "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"
154             "\nResult:\n"
155             "\"bitcoinaddress\"   (string) The account bitcoin address\n"
156             "\nExamples:\n"
157             + HelpExampleCli("getaccountaddress", "")
158             + HelpExampleCli("getaccountaddress", "\"\"")
159             + HelpExampleCli("getaccountaddress", "\"myaccount\"")
160             + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
161         );
162
163     // Parse the account first so we don't generate a key if there's an error
164     string strAccount = AccountFromValue(params[0]);
165
166     Value ret;
167
168     ret = GetAccountAddress(strAccount).ToString();
169
170     return ret;
171 }
172
173
174 Value getrawchangeaddress(const Array& params, bool fHelp)
175 {
176     if (fHelp || params.size() > 1)
177         throw runtime_error(
178             "getrawchangeaddress\n"
179             "\nReturns a new Bitcoin address, for receiving change.\n"
180             "This is for use with raw transactions, NOT normal use.\n"
181             "\nResult:\n"
182             "\"address\"    (string) The address\n"
183             "\nExamples:\n"
184             + HelpExampleCli("getrawchangeaddress", "")
185             + HelpExampleRpc("getrawchangeaddress", "")
186        );
187
188     if (!pwalletMain->IsLocked())
189         pwalletMain->TopUpKeyPool();
190
191     CReserveKey reservekey(pwalletMain);
192     CPubKey vchPubKey;
193     if (!reservekey.GetReservedKey(vchPubKey))
194         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Unable to obtain key for change");
195
196     reservekey.KeepKey();
197
198     CKeyID keyID = vchPubKey.GetID();
199
200     return CBitcoinAddress(keyID).ToString();
201 }
202
203
204 Value setaccount(const Array& params, bool fHelp)
205 {
206     if (fHelp || params.size() < 1 || params.size() > 2)
207         throw runtime_error(
208             "setaccount \"bitcoinaddress\" \"account\"\n"
209             "\nSets the account associated with the given address.\n"
210             "\nArguments:\n"
211             "1. \"bitcoinaddress\"  (string, required) The bitcoin address to be associated with an account.\n"
212             "2. \"account\"         (string, required) The account to assign the address to.\n"
213             "\nExamples:\n"
214             + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
215             + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
216         );
217
218     CBitcoinAddress address(params[0].get_str());
219     if (!address.IsValid())
220         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
221
222
223     string strAccount;
224     if (params.size() > 1)
225         strAccount = AccountFromValue(params[1]);
226
227     // Detect when changing the account of an address that is the 'unused current key' of another account:
228     if (pwalletMain->mapAddressBook.count(address.Get()))
229     {
230         string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
231         if (address == GetAccountAddress(strOldAccount))
232             GetAccountAddress(strOldAccount, true);
233     }
234
235     pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
236
237     return Value::null;
238 }
239
240
241 Value getaccount(const Array& params, bool fHelp)
242 {
243     if (fHelp || params.size() != 1)
244         throw runtime_error(
245             "getaccount \"bitcoinaddress\"\n"
246             "\nReturns the account associated with the given address.\n"
247             "\nArguments:\n"
248             "1. \"bitcoinaddress\"  (string, required) The bitcoin address for account lookup.\n"
249             "\nResult:\n"
250             "\"accountname\"        (string) the account address\n"
251             "\nExamples:\n"
252             + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
253             + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
254         );
255
256     CBitcoinAddress address(params[0].get_str());
257     if (!address.IsValid())
258         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
259
260     string strAccount;
261     map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
262     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
263         strAccount = (*mi).second.name;
264     return strAccount;
265 }
266
267
268 Value getaddressesbyaccount(const Array& params, bool fHelp)
269 {
270     if (fHelp || params.size() != 1)
271         throw runtime_error(
272             "getaddressesbyaccount \"account\"\n"
273             "\nReturns the list of addresses for the given account.\n"
274             "\nArguments:\n"
275             "1. \"account\"  (string, required) The account name.\n"
276             "\nResult:\n"
277             "[                     (json array of string)\n"
278             "  \"bitcoinaddress\"  (string) a bitcoin address associated with the given account\n"
279             "  ,...\n"
280             "]\n"
281             "\nExamples:\n"
282             + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
283             + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
284         );
285
286     string strAccount = AccountFromValue(params[0]);
287
288     // Find all addresses that have the given account
289     Array ret;
290     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
291     {
292         const CBitcoinAddress& address = item.first;
293         const string& strName = item.second.name;
294         if (strName == strAccount)
295             ret.push_back(address.ToString());
296     }
297     return ret;
298 }
299
300 Value sendtoaddress(const Array& params, bool fHelp)
301 {
302     if (fHelp || params.size() < 2 || params.size() > 4)
303         throw runtime_error(
304             "sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" )\n"
305             "\nSent an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
306             + HelpRequiringPassphrase() +
307             "\nArguments:\n"
308             "1. \"bitcoinaddress\"  (string, required) The bitcoin address to send to.\n"
309             "2. \"amount\"      (numeric, required) The amount in btc to send. eg 0.1\n"
310             "3. \"comment\"     (string, optional) A comment used to store what the transaction is for. \n"
311             "                             This is not part of the transaction, just kept in your wallet.\n"
312             "4. \"comment-to\"  (string, optional) A comment to store the name of the person or organization \n"
313             "                             to which you're sending the transaction. This is not part of the \n"
314             "                             transaction, just kept in your wallet.\n"
315             "\nResult:\n"
316             "\"transactionid\"  (string) The transaction id. (view at https://blockchain.info/tx/[transactionid])\n"
317             "\nExamples:\n"
318             + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
319             + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
320             + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
321         );
322
323     CBitcoinAddress address(params[0].get_str());
324     if (!address.IsValid())
325         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
326
327     // Amount
328     int64_t nAmount = AmountFromValue(params[1]);
329
330     // Wallet comments
331     CWalletTx wtx;
332     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
333         wtx.mapValue["comment"] = params[2].get_str();
334     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
335         wtx.mapValue["to"]      = params[3].get_str();
336
337     EnsureWalletIsUnlocked();
338
339     string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
340     if (strError != "")
341         throw JSONRPCError(RPC_WALLET_ERROR, strError);
342
343     return wtx.GetHash().GetHex();
344 }
345
346 Value listaddressgroupings(const Array& params, bool fHelp)
347 {
348     if (fHelp)
349         throw runtime_error(
350             "listaddressgroupings\n"
351             "\nLists groups of addresses which have had their common ownership\n"
352             "made public by common use as inputs or as the resulting change\n"
353             "in past transactions\n"
354             "\nResult:\n"
355             "[\n"
356             "  [\n"
357             "    [\n"
358             "      \"bitcoinaddress\",     (string) The bitcoin address\n"
359             "      amount,                 (numeric) The amount in btc\n"
360             "      \"account\"             (string, optional) The account\n"
361             "    ]\n"
362             "    ,...\n"
363             "  ]\n"
364             "  ,...\n"
365             "]\n"
366             "\nExamples:\n"
367             + HelpExampleCli("listaddressgroupings", "")
368             + HelpExampleRpc("listaddressgroupings", "")
369         );
370
371     Array jsonGroupings;
372     map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
373     BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
374     {
375         Array jsonGrouping;
376         BOOST_FOREACH(CTxDestination address, grouping)
377         {
378             Array addressInfo;
379             addressInfo.push_back(CBitcoinAddress(address).ToString());
380             addressInfo.push_back(ValueFromAmount(balances[address]));
381             {
382                 LOCK(pwalletMain->cs_wallet);
383                 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
384                     addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
385             }
386             jsonGrouping.push_back(addressInfo);
387         }
388         jsonGroupings.push_back(jsonGrouping);
389     }
390     return jsonGroupings;
391 }
392
393 Value signmessage(const Array& params, bool fHelp)
394 {
395     if (fHelp || params.size() != 2)
396         throw runtime_error(
397             "signmessage \"bitcoinaddress\" \"message\"\n"
398             "\nSign a message with the private key of an address"
399             + HelpRequiringPassphrase() + "\n"
400             "\nArguments:\n"
401             "1. \"bitcoinaddress\"  (string, required) The bitcoin address to use for the private key.\n"
402             "2. \"message\"         (string, required) The message to create a signature of.\n"
403             "\nResult:\n"
404             "\"signature\"          (string) The signature of the message encoded in base 64\n"
405             "\nExamples:\n"
406             "\nUnlock the wallet for 30 seconds\n"
407             + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
408             "\nCreate the signature\n"
409             + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
410             "\nVerify the signature\n"
411             + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
412             "\nAs json rpc\n"
413             + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
414         );
415
416     EnsureWalletIsUnlocked();
417
418     string strAddress = params[0].get_str();
419     string strMessage = params[1].get_str();
420
421     CBitcoinAddress addr(strAddress);
422     if (!addr.IsValid())
423         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
424
425     CKeyID keyID;
426     if (!addr.GetKeyID(keyID))
427         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
428
429     CKey key;
430     if (!pwalletMain->GetKey(keyID, key))
431         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
432
433     CHashWriter ss(SER_GETHASH, 0);
434     ss << strMessageMagic;
435     ss << strMessage;
436
437     vector<unsigned char> vchSig;
438     if (!key.SignCompact(ss.GetHash(), vchSig))
439         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
440
441     return EncodeBase64(&vchSig[0], vchSig.size());
442 }
443
444 Value getreceivedbyaddress(const Array& params, bool fHelp)
445 {
446     if (fHelp || params.size() < 1 || params.size() > 2)
447         throw runtime_error(
448             "getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
449             "\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
450             "\nArguments:\n"
451             "1. \"bitcoinaddress\"  (string, required) The bitcoin address for transactions.\n"
452             "2. minconf             (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
453             "\nResult:\n"
454             "amount   (numeric) The total amount in btc received at this address.\n"
455             "\nExamples:\n"
456             "\nThe amount from transactions with at least 1 confirmation\n"
457             + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
458             "\nThe amount including unconfirmed transactions, zero confirmations\n"
459             + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
460             "\nThe amount with at least 6 confirmation, very safe\n"
461             + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
462             "\nAs a json rpc call\n"
463             + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
464        );
465
466     // Bitcoin address
467     CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
468     CScript scriptPubKey;
469     if (!address.IsValid())
470         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
471     scriptPubKey.SetDestination(address.Get());
472     if (!IsMine(*pwalletMain,scriptPubKey))
473         return (double)0.0;
474
475     // Minimum confirmations
476     int nMinDepth = 1;
477     if (params.size() > 1)
478         nMinDepth = params[1].get_int();
479
480     // Tally
481     int64_t nAmount = 0;
482     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
483     {
484         const CWalletTx& wtx = (*it).second;
485         if (wtx.IsCoinBase() || !IsFinalTx(wtx))
486             continue;
487
488         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
489             if (txout.scriptPubKey == scriptPubKey)
490                 if (wtx.GetDepthInMainChain() >= nMinDepth)
491                     nAmount += txout.nValue;
492     }
493
494     return  ValueFromAmount(nAmount);
495 }
496
497
498 Value getreceivedbyaccount(const Array& params, bool fHelp)
499 {
500     if (fHelp || params.size() < 1 || params.size() > 2)
501         throw runtime_error(
502             "getreceivedbyaccount \"account\" ( minconf )\n"
503             "\nReturns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
504             "\nArguments:\n"
505             "1. \"account\"      (string, required) The selected account, may be the default account using \"\".\n"
506             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
507             "\nResult:\n"
508             "amount              (numeric) The total amount in btc received for this account.\n"
509             "\nExamples:\n"
510             "\nAmount received by the default account with at least 1 confirmation\n"
511             + HelpExampleCli("getreceivedbyaccount", "\"\"") +
512             "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
513             + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
514             "\nThe amount with at least 6 confirmation, very safe\n"
515             + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
516             "\nAs a json rpc call\n"
517             + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
518         );
519
520     // Minimum confirmations
521     int nMinDepth = 1;
522     if (params.size() > 1)
523         nMinDepth = params[1].get_int();
524
525     // Get the set of pub keys assigned to account
526     string strAccount = AccountFromValue(params[0]);
527     set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
528
529     // Tally
530     int64_t nAmount = 0;
531     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
532     {
533         const CWalletTx& wtx = (*it).second;
534         if (wtx.IsCoinBase() || !IsFinalTx(wtx))
535             continue;
536
537         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
538         {
539             CTxDestination address;
540             if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
541                 if (wtx.GetDepthInMainChain() >= nMinDepth)
542                     nAmount += txout.nValue;
543         }
544     }
545
546     return (double)nAmount / (double)COIN;
547 }
548
549
550 int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
551 {
552     int64_t nBalance = 0;
553
554     // Tally wallet transactions
555     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
556     {
557         const CWalletTx& wtx = (*it).second;
558         if (!IsFinalTx(wtx))
559             continue;
560
561         int64_t nReceived, nSent, nFee;
562         wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee);
563
564         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
565             nBalance += nReceived;
566         nBalance -= nSent + nFee;
567     }
568
569     // Tally internal accounting entries
570     nBalance += walletdb.GetAccountCreditDebit(strAccount);
571
572     return nBalance;
573 }
574
575 int64_t GetAccountBalance(const string& strAccount, int nMinDepth)
576 {
577     CWalletDB walletdb(pwalletMain->strWalletFile);
578     return GetAccountBalance(walletdb, strAccount, nMinDepth);
579 }
580
581
582 Value getbalance(const Array& params, bool fHelp)
583 {
584     if (fHelp || params.size() > 2)
585         throw runtime_error(
586             "getbalance ( \"account\" minconf )\n"
587             "\nIf account is not specified, returns the server's total available balance.\n"
588             "If account is specified, returns the balance in the account.\n"
589             "Note that the account \"\" is not the same as leaving the parameter out.\n"
590             "The server total may be different to the balance in the default \"\" account.\n"
591             "\nArguments:\n"
592             "1. \"account\"      (string, optional) The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
593             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
594             "\nResult:\n"
595             "amount              (numeric) The total amount in btc received for this account.\n"
596             "\nExamples:\n"
597             "\nThe total amount in the server across all accounts\n"
598             + HelpExampleCli("getbalance", "") +
599             "\nThe total amount in the server across all accounts, with at least 5 confirmations\n"
600             + HelpExampleCli("getbalance", "\"*\" 6") +
601             "\nThe total amount in the default account with at least 1 confirmation\n"
602             + HelpExampleCli("getbalance", "\"\"") +
603             "\nThe total amount in the account named tabby with at least 6 confirmations\n"
604             + HelpExampleCli("getbalance", "\"tabby\" 6") +
605             "\nAs a json rpc call\n"
606             + HelpExampleRpc("getbalance", "\"tabby\", 6")
607         );
608
609     if (params.size() == 0)
610         return  ValueFromAmount(pwalletMain->GetBalance());
611
612     int nMinDepth = 1;
613     if (params.size() > 1)
614         nMinDepth = params[1].get_int();
615
616     if (params[0].get_str() == "*") {
617         // Calculate total balance a different way from GetBalance()
618         // (GetBalance() sums up all unspent TxOuts)
619         // getbalance and getbalance '*' 0 should return the same number
620         int64_t nBalance = 0;
621         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
622         {
623             const CWalletTx& wtx = (*it).second;
624             if (!wtx.IsConfirmed())
625                 continue;
626
627             int64_t allFee;
628             string strSentAccount;
629             list<pair<CTxDestination, int64_t> > listReceived;
630             list<pair<CTxDestination, int64_t> > listSent;
631             wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
632             if (wtx.GetDepthInMainChain() >= nMinDepth)
633             {
634                 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
635                     nBalance += r.second;
636             }
637             BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
638                 nBalance -= r.second;
639             nBalance -= allFee;
640         }
641         return  ValueFromAmount(nBalance);
642     }
643
644     string strAccount = AccountFromValue(params[0]);
645
646     int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
647
648     return ValueFromAmount(nBalance);
649 }
650
651 Value getunconfirmedbalance(const Array &params, bool fHelp)
652 {
653     if (fHelp || params.size() > 0)
654         throw runtime_error(
655                 "getunconfirmedbalance\n"
656                 "Returns the server's total unconfirmed balance\n");
657     return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
658 }
659
660
661 Value movecmd(const Array& params, bool fHelp)
662 {
663     if (fHelp || params.size() < 3 || params.size() > 5)
664         throw runtime_error(
665             "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
666             "\nMove a specified amount from one account in your wallet to another.\n"
667             "\nArguments:\n"
668             "1. \"fromaccount\"   (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
669             "2. \"toaccount\"     (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
670             "3. minconf           (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
671             "4. \"comment\"       (string, optional) An optional comment, stored in the wallet only.\n"
672             "\nResult:\n"
673             "true|false           (boolean) true if successfull.\n"
674             "\nExamples:\n"
675             "\nMove 0.01 btc from the default account to the account named tabby\n"
676             + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
677             "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
678             + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
679             "\nAs a json rpc call\n"
680             + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
681         );
682
683     string strFrom = AccountFromValue(params[0]);
684     string strTo = AccountFromValue(params[1]);
685     int64_t nAmount = AmountFromValue(params[2]);
686     if (params.size() > 3)
687         // unused parameter, used to be nMinDepth, keep type-checking it though
688         (void)params[3].get_int();
689     string strComment;
690     if (params.size() > 4)
691         strComment = params[4].get_str();
692
693     CWalletDB walletdb(pwalletMain->strWalletFile);
694     if (!walletdb.TxnBegin())
695         throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
696
697     int64_t nNow = GetAdjustedTime();
698
699     // Debit
700     CAccountingEntry debit;
701     debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
702     debit.strAccount = strFrom;
703     debit.nCreditDebit = -nAmount;
704     debit.nTime = nNow;
705     debit.strOtherAccount = strTo;
706     debit.strComment = strComment;
707     walletdb.WriteAccountingEntry(debit);
708
709     // Credit
710     CAccountingEntry credit;
711     credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
712     credit.strAccount = strTo;
713     credit.nCreditDebit = nAmount;
714     credit.nTime = nNow;
715     credit.strOtherAccount = strFrom;
716     credit.strComment = strComment;
717     walletdb.WriteAccountingEntry(credit);
718
719     if (!walletdb.TxnCommit())
720         throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
721
722     return true;
723 }
724
725
726 Value sendfrom(const Array& params, bool fHelp)
727 {
728     if (fHelp || params.size() < 3 || params.size() > 6)
729         throw runtime_error(
730             "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
731             "\nSent an amount from an account to a bitcoin address.\n"
732             "The amount is a real and is rounded to the nearest 0.00000001."
733             + HelpRequiringPassphrase() + "\n"
734             "\nArguments:\n"
735             "1. \"fromaccount\"       (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
736             "2. \"tobitcoinaddress\"  (string, required) The bitcoin address to send funds to.\n"
737             "3. amount                (numeric, required) The amount in btc. (transaction fee is added on top).\n"
738             "4. minconf               (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
739             "5. \"comment\"           (string, optional) A comment used to store what the transaction is for. \n"
740             "                                     This is not part of the transaction, just kept in your wallet.\n"
741             "6. \"comment-to\"        (string, optional) An optional comment to store the name of the person or organization \n"
742             "                                     to which you're sending the transaction. This is not part of the transaction, \n"
743             "                                     it is just kept in your wallet.\n"
744             "\nResult:\n"
745             "\"transactionid\"        (string) The transaction id. (view at https://blockchain.info/tx/[transactionid])\n"
746             "\nExamples:\n"
747             "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
748             + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
749             "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
750             + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
751             "\nAs a json rpc call\n"
752             + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
753         );
754
755     string strAccount = AccountFromValue(params[0]);
756     CBitcoinAddress address(params[1].get_str());
757     if (!address.IsValid())
758         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
759     int64_t nAmount = AmountFromValue(params[2]);
760     int nMinDepth = 1;
761     if (params.size() > 3)
762         nMinDepth = params[3].get_int();
763
764     CWalletTx wtx;
765     wtx.strFromAccount = strAccount;
766     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
767         wtx.mapValue["comment"] = params[4].get_str();
768     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
769         wtx.mapValue["to"]      = params[5].get_str();
770
771     EnsureWalletIsUnlocked();
772
773     // Check funds
774     int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
775     if (nAmount > nBalance)
776         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
777
778     // Send
779     string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
780     if (strError != "")
781         throw JSONRPCError(RPC_WALLET_ERROR, strError);
782
783     return wtx.GetHash().GetHex();
784 }
785
786
787 Value sendmany(const Array& params, bool fHelp)
788 {
789     if (fHelp || params.size() < 2 || params.size() > 4)
790         throw runtime_error(
791             "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" )\n"
792             "\nSend multiple times. Amounts are double-precision floating point numbers."
793             + HelpRequiringPassphrase() + "\n"
794             "\nArguments:\n"
795             "1. \"fromaccount\"         (string, required) The account to send the funds from, can be \"\" for the default account\n"
796             "2. \"amounts\"             (string, required) A json object with addresses and amounts\n"
797             "    {\n"
798             "      \"address\":amount   (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
799             "      ,...\n"
800             "    }\n"
801             "3. minconf                 (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
802             "4. \"comment\"             (string, optional) A comment\n"
803             "\nResult:\n"
804             "\"transactionid\"          (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
805             "                                    the number of addresses. See https://blockchain.info/tx/[transactionid]\n"
806             "\nExamples:\n"
807             "\nSend two amounts to two different addresses:\n"
808             + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
809             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
810             + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
811             "\nAs a json rpc call\n"
812             + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
813         );
814
815     string strAccount = AccountFromValue(params[0]);
816     Object sendTo = params[1].get_obj();
817     int nMinDepth = 1;
818     if (params.size() > 2)
819         nMinDepth = params[2].get_int();
820
821     CWalletTx wtx;
822     wtx.strFromAccount = strAccount;
823     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
824         wtx.mapValue["comment"] = params[3].get_str();
825
826     set<CBitcoinAddress> setAddress;
827     vector<pair<CScript, int64_t> > vecSend;
828
829     int64_t totalAmount = 0;
830     BOOST_FOREACH(const Pair& s, sendTo)
831     {
832         CBitcoinAddress address(s.name_);
833         if (!address.IsValid())
834             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
835
836         if (setAddress.count(address))
837             throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
838         setAddress.insert(address);
839
840         CScript scriptPubKey;
841         scriptPubKey.SetDestination(address.Get());
842         int64_t nAmount = AmountFromValue(s.value_);
843         totalAmount += nAmount;
844
845         vecSend.push_back(make_pair(scriptPubKey, nAmount));
846     }
847
848     EnsureWalletIsUnlocked();
849
850     // Check funds
851     int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
852     if (totalAmount > nBalance)
853         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
854
855     // Send
856     CReserveKey keyChange(pwalletMain);
857     int64_t nFeeRequired = 0;
858     string strFailReason;
859     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason);
860     if (!fCreated)
861         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
862     if (!pwalletMain->CommitTransaction(wtx, keyChange))
863         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
864
865     return wtx.GetHash().GetHex();
866 }
867
868 // Defined in rpcmisc.cpp
869 extern CScript _createmultisig(const Array& params);
870
871 Value addmultisigaddress(const Array& params, bool fHelp)
872 {
873     if (fHelp || params.size() < 2 || params.size() > 3)
874     {
875         string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
876             "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
877             "Each key is a Bitcoin address or hex-encoded public key.\n"
878             "If 'account' is specified, assign address to that account.\n"
879
880             "\nArguments:\n"
881             "1. nrequired        (numeric, required) The number of required signatures out of the n keys or addresses.\n"
882             "2. \"keysobject\"   (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
883             "     [\n"
884             "       \"address\"  (string) bitcoin address or hex-encoded public key\n"
885             "       ...,\n"
886             "     ]\n"
887             "3. \"account\"      (string, optional) An account to assign the addresses to.\n"
888
889             "\nResult:\n"
890             "\"bitcoinaddress\"  (string) A bitcoin address associated with the keys.\n"
891
892             "\nExamples:\n"
893             "\nAdd a multisig address from 2 addresses\n"
894             + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
895             "\nAs json rpc call\n"
896             + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
897         ;
898         throw runtime_error(msg);
899     }
900
901     string strAccount;
902     if (params.size() > 2)
903         strAccount = AccountFromValue(params[2]);
904
905     // Construct using pay-to-script-hash:
906     CScript inner = _createmultisig(params);
907     CScriptID innerID = inner.GetID();
908     pwalletMain->AddCScript(inner);
909
910     pwalletMain->SetAddressBook(innerID, strAccount, "send");
911     return CBitcoinAddress(innerID).ToString();
912 }
913
914
915 struct tallyitem
916 {
917     int64_t nAmount;
918     int nConf;
919     vector<uint256> txids;
920     tallyitem()
921     {
922         nAmount = 0;
923         nConf = std::numeric_limits<int>::max();
924     }
925 };
926
927 Value ListReceived(const Array& params, bool fByAccounts)
928 {
929     // Minimum confirmations
930     int nMinDepth = 1;
931     if (params.size() > 0)
932         nMinDepth = params[0].get_int();
933
934     // Whether to include empty accounts
935     bool fIncludeEmpty = false;
936     if (params.size() > 1)
937         fIncludeEmpty = params[1].get_bool();
938
939     // Tally
940     map<CBitcoinAddress, tallyitem> mapTally;
941     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
942     {
943         const CWalletTx& wtx = (*it).second;
944
945         if (wtx.IsCoinBase() || !IsFinalTx(wtx))
946             continue;
947
948         int nDepth = wtx.GetDepthInMainChain();
949         if (nDepth < nMinDepth)
950             continue;
951
952         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
953         {
954             CTxDestination address;
955             if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
956                 continue;
957
958             tallyitem& item = mapTally[address];
959             item.nAmount += txout.nValue;
960             item.nConf = min(item.nConf, nDepth);
961             item.txids.push_back(wtx.GetHash());
962         }
963     }
964
965     // Reply
966     Array ret;
967     map<string, tallyitem> mapAccountTally;
968     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
969     {
970         const CBitcoinAddress& address = item.first;
971         const string& strAccount = item.second.name;
972         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
973         if (it == mapTally.end() && !fIncludeEmpty)
974             continue;
975
976         int64_t nAmount = 0;
977         int nConf = std::numeric_limits<int>::max();
978         if (it != mapTally.end())
979         {
980             nAmount = (*it).second.nAmount;
981             nConf = (*it).second.nConf;
982         }
983
984         if (fByAccounts)
985         {
986             tallyitem& item = mapAccountTally[strAccount];
987             item.nAmount += nAmount;
988             item.nConf = min(item.nConf, nConf);
989         }
990         else
991         {
992             Object obj;
993             obj.push_back(Pair("address",       address.ToString()));
994             obj.push_back(Pair("account",       strAccount));
995             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
996             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
997             Array transactions;
998             if (it != mapTally.end())
999             {
1000                 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1001                 {
1002                     transactions.push_back(item.GetHex());
1003                 }
1004             }
1005             obj.push_back(Pair("txids", transactions));
1006             ret.push_back(obj);
1007         }
1008     }
1009
1010     if (fByAccounts)
1011     {
1012         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1013         {
1014             int64_t nAmount = (*it).second.nAmount;
1015             int nConf = (*it).second.nConf;
1016             Object obj;
1017             obj.push_back(Pair("account",       (*it).first));
1018             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1019             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1020             ret.push_back(obj);
1021         }
1022     }
1023
1024     return ret;
1025 }
1026
1027 Value listreceivedbyaddress(const Array& params, bool fHelp)
1028 {
1029     if (fHelp || params.size() > 2)
1030         throw runtime_error(
1031             "listreceivedbyaddress ( minconf includeempty )\n"
1032             "\nList balances by receiving address.\n"
1033             "\nArguments:\n"
1034             "1. minconf       (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1035             "2. includeempty  (numeric, optional, dafault=false) Whether to include addresses that haven't received any payments.\n"
1036
1037             "\nResult:\n"
1038             "[\n"
1039             "  {\n"
1040             "    \"address\" : \"receivingaddress\",  (string) The receiving address\n"
1041             "    \"account\" : \"accountname\",       (string) The account of the receiving address. The default account is \"\".\n"
1042             "    \"amount\" : x.xxx,                  (numeric) The total amount in btc received by the address\n"
1043             "    \"confirmations\" : n                (numeric) The number of confirmations of the most recent transaction included\n"
1044             "  }\n"
1045             "  ,...\n"
1046             "]\n"
1047
1048             "\nExamples:\n"
1049             + HelpExampleCli("listreceivedbyaddress", "")
1050             + HelpExampleCli("listreceivedbyaddress", "6 true")
1051             + HelpExampleRpc("listreceivedbyaddress", "6, true")
1052         );
1053
1054     return ListReceived(params, false);
1055 }
1056
1057 Value listreceivedbyaccount(const Array& params, bool fHelp)
1058 {
1059     if (fHelp || params.size() > 2)
1060         throw runtime_error(
1061             "listreceivedbyaccount ( minconf includeempty )\n"
1062             "\nList balances by account.\n"
1063             "\nArguments:\n"
1064             "1. minconf      (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1065             "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1066
1067             "\nResult:\n"
1068             "[\n"
1069             "  {\n"
1070             "    \"account\" : \"accountname\",  (string) The account name of the receiving account\n"
1071             "    \"amount\" : x.xxx,             (numeric) The total amount received by addresses with this account\n"
1072             "    \"confirmations\" : n           (numeric) The number of confirmations of the most recent transaction included\n"
1073             "  }\n"
1074             "  ,...\n"
1075             "]\n"
1076
1077             "\nExamples:\n"
1078             + HelpExampleCli("listreceivedbyaccount", "")
1079             + HelpExampleCli("listreceivedbyaccount", "6 true")
1080             + HelpExampleRpc("listreceivedbyaccount", "6, true")
1081         );
1082
1083     return ListReceived(params, true);
1084 }
1085
1086 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1087 {
1088     CBitcoinAddress addr;
1089     if (addr.Set(dest))
1090         entry.push_back(Pair("address", addr.ToString()));
1091 }
1092
1093 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1094 {
1095     int64_t nFee;
1096     string strSentAccount;
1097     list<pair<CTxDestination, int64_t> > listReceived;
1098     list<pair<CTxDestination, int64_t> > listSent;
1099
1100     wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
1101
1102     bool fAllAccounts = (strAccount == string("*"));
1103
1104     // Sent
1105     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1106     {
1107         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1108         {
1109             Object entry;
1110             entry.push_back(Pair("account", strSentAccount));
1111             MaybePushAddress(entry, s.first);
1112             entry.push_back(Pair("category", "send"));
1113             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1114             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1115             if (fLong)
1116                 WalletTxToJSON(wtx, entry);
1117             ret.push_back(entry);
1118         }
1119     }
1120
1121     // Received
1122     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1123     {
1124         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1125         {
1126             string account;
1127             if (pwalletMain->mapAddressBook.count(r.first))
1128                 account = pwalletMain->mapAddressBook[r.first].name;
1129             if (fAllAccounts || (account == strAccount))
1130             {
1131                 Object entry;
1132                 entry.push_back(Pair("account", account));
1133                 MaybePushAddress(entry, r.first);
1134                 if (wtx.IsCoinBase())
1135                 {
1136                     if (wtx.GetDepthInMainChain() < 1)
1137                         entry.push_back(Pair("category", "orphan"));
1138                     else if (wtx.GetBlocksToMaturity() > 0)
1139                         entry.push_back(Pair("category", "immature"));
1140                     else
1141                         entry.push_back(Pair("category", "generate"));
1142                 }
1143                 else
1144                     entry.push_back(Pair("category", "receive"));
1145                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1146                 if (fLong)
1147                     WalletTxToJSON(wtx, entry);
1148                 ret.push_back(entry);
1149             }
1150         }
1151     }
1152 }
1153
1154 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1155 {
1156     bool fAllAccounts = (strAccount == string("*"));
1157
1158     if (fAllAccounts || acentry.strAccount == strAccount)
1159     {
1160         Object entry;
1161         entry.push_back(Pair("account", acentry.strAccount));
1162         entry.push_back(Pair("category", "move"));
1163         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1164         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1165         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1166         entry.push_back(Pair("comment", acentry.strComment));
1167         ret.push_back(entry);
1168     }
1169 }
1170
1171 Value listtransactions(const Array& params, bool fHelp)
1172 {
1173     if (fHelp || params.size() > 3)
1174         throw runtime_error(
1175             "listtransactions ( \"account\" count from )\n"
1176             "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1177             "\nArguments:\n"
1178             "1. \"account\"    (string, optional) The account name. If not included, it will list all transactions for all accounts.\n"
1179             "                                     If \"\" is set, it will list transactions for the default account.\n"
1180             "2. count          (numeric, optional, default=10) The number of transactions to return\n"
1181             "3. from           (numeric, optional, default=0) The number of transactions to skip\n"
1182
1183             "\nResult:\n"
1184             "[\n"
1185             "  {\n"
1186             "    \"account\":\"accountname\",       (string) The account name associated with the transaction. \n"
1187             "                                                It will be \"\" for the default account.\n"
1188             "    \"address\":\"bitcoinaddress\",    (string) The bitcoin address of the transaction. Not present for \n"
1189             "                                                move transactions (category = move).\n"
1190             "    \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1191             "                                                transaction between accounts, and not associated with an address,\n"
1192             "                                                transaction id or block. 'send' and 'receive' transactions are \n"
1193             "                                                associated with an address, transaction id and block details\n"
1194             "    \"amount\": x.xxx,          (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1195             "                                         'move' category for moves outbound. It is positive for the 'receive' category,\n"
1196             "                                         and for the 'move' category for inbound funds.\n"
1197             "    \"fee\": x.xxx,             (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1198             "                                         'send' category of transactions.\n"
1199             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1200             "                                         'receive' category of transactions.\n"
1201             "    \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1202             "                                          category of transactions.\n"
1203             "    \"blockindex\": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1204             "                                          category of transactions.\n"
1205             "    \"txid\": \"transactionid\", (string) The transaction id (see https://blockchain.info/tx/[transactionid]. Available \n"
1206             "                                          for 'send' and 'receive' category of transactions.\n"
1207             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1208             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1209             "                                          for 'send' and 'receive' category of transactions.\n"
1210             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
1211             "    \"otheraccount\": \"accountname\",  (string) For the 'move' category of transactions, the account the funds came \n"
1212             "                                          from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1213             "                                          negative amounts).\n"
1214             "  }\n"
1215             "]\n"
1216
1217             "\nExamples:\n"
1218             "\nList the most recent 10 transactions in the systems\n"
1219             + HelpExampleCli("listtransactions", "") +
1220             "\nList the most recent 10 transactions for the tabby account\n"
1221             + HelpExampleCli("listtransactions", "\"tabby\"") +
1222             "\nList transactions 100 to 120 from the tabby account\n"
1223             + HelpExampleCli("listtransactions", "\"tabby\" 20 100") +
1224             "\nAs a json rpc call\n"
1225             + HelpExampleRpc("listtransactions", "\"tabby\", 20, 100")
1226         );
1227
1228     string strAccount = "*";
1229     if (params.size() > 0)
1230         strAccount = params[0].get_str();
1231     int nCount = 10;
1232     if (params.size() > 1)
1233         nCount = params[1].get_int();
1234     int nFrom = 0;
1235     if (params.size() > 2)
1236         nFrom = params[2].get_int();
1237
1238     if (nCount < 0)
1239         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1240     if (nFrom < 0)
1241         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1242
1243     Array ret;
1244
1245     std::list<CAccountingEntry> acentries;
1246     CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1247
1248     // iterate backwards until we have nCount items to return:
1249     for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1250     {
1251         CWalletTx *const pwtx = (*it).second.first;
1252         if (pwtx != 0)
1253             ListTransactions(*pwtx, strAccount, 0, true, ret);
1254         CAccountingEntry *const pacentry = (*it).second.second;
1255         if (pacentry != 0)
1256             AcentryToJSON(*pacentry, strAccount, ret);
1257
1258         if ((int)ret.size() >= (nCount+nFrom)) break;
1259     }
1260     // ret is newest to oldest
1261
1262     if (nFrom > (int)ret.size())
1263         nFrom = ret.size();
1264     if ((nFrom + nCount) > (int)ret.size())
1265         nCount = ret.size() - nFrom;
1266     Array::iterator first = ret.begin();
1267     std::advance(first, nFrom);
1268     Array::iterator last = ret.begin();
1269     std::advance(last, nFrom+nCount);
1270
1271     if (last != ret.end()) ret.erase(last, ret.end());
1272     if (first != ret.begin()) ret.erase(ret.begin(), first);
1273
1274     std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1275
1276     return ret;
1277 }
1278
1279 Value listaccounts(const Array& params, bool fHelp)
1280 {
1281     if (fHelp || params.size() > 1)
1282         throw runtime_error(
1283             "listaccounts ( minconf )\n"
1284             "\nReturns Object that has account names as keys, account balances as values.\n"
1285             "\nArguments:\n"
1286             "1. minconf     (numeric, optional, default=1) Only onclude transactions with at least this many confirmations\n"
1287             "\nResult:\n"
1288             "{                      (json object where keys are account names, and values are numeric balances\n"
1289             "  \"account\": x.xxx,  (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1290             "  ...\n"
1291             "}\n"
1292             "\nExamples:\n"
1293             "\nList account balances where there at least 1 confirmation\n"
1294             + HelpExampleCli("listaccounts", "") +
1295             "\nList account balances including zero confirmation transactions\n"
1296             + HelpExampleCli("listaccounts", "0") +
1297             "\nList account balances for 6 or more confirmations\n"
1298             + HelpExampleCli("listaccounts", "6") +
1299             "\nAs json rpc call\n"
1300             + HelpExampleRpc("listaccounts", "6")
1301         );
1302
1303     int nMinDepth = 1;
1304     if (params.size() > 0)
1305         nMinDepth = params[0].get_int();
1306
1307     map<string, int64_t> mapAccountBalances;
1308     BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1309         if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
1310             mapAccountBalances[entry.second.name] = 0;
1311     }
1312
1313     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1314     {
1315         const CWalletTx& wtx = (*it).second;
1316         int64_t nFee;
1317         string strSentAccount;
1318         list<pair<CTxDestination, int64_t> > listReceived;
1319         list<pair<CTxDestination, int64_t> > listSent;
1320         wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
1321         mapAccountBalances[strSentAccount] -= nFee;
1322         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
1323             mapAccountBalances[strSentAccount] -= s.second;
1324         if (wtx.GetDepthInMainChain() >= nMinDepth)
1325         {
1326             BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
1327                 if (pwalletMain->mapAddressBook.count(r.first))
1328                     mapAccountBalances[pwalletMain->mapAddressBook[r.first].name] += r.second;
1329                 else
1330                     mapAccountBalances[""] += r.second;
1331         }
1332     }
1333
1334     list<CAccountingEntry> acentries;
1335     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1336     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1337         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1338
1339     Object ret;
1340     BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
1341         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1342     }
1343     return ret;
1344 }
1345
1346 Value listsinceblock(const Array& params, bool fHelp)
1347 {
1348     if (fHelp)
1349         throw runtime_error(
1350             "listsinceblock ( \"blockhash\" target-confirmations )\n"
1351             "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1352             "\nArguments:\n"
1353             "1. \"blockhash\"   (string, optional) The block hash to list transactions since\n"
1354             "2. target-confirmations:    (numeric, optional) The confirmations required, must be 1 or more\n"
1355             "\nResult:\n"
1356             "{\n"
1357             "  \"transactions\": [\n"
1358             "    \"account\":\"accountname\",       (string) The account name associated with the transaction. Will be \"\" for the default account.\n"
1359             "    \"address\":\"bitcoinaddress\",    (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
1360             "    \"category\":\"send|receive\",     (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1361             "    \"amount\": x.xxx,          (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1362             "                                          outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1363             "    \"fee\": x.xxx,             (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1364             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1365             "    \"blockhash\": \"hashvalue\",     (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1366             "    \"blockindex\": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1367             "    \"blocktime\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1368             "    \"txid\": \"transactionid\",  (string) The transaction id (see https://blockchain.info/tx/[transactionid]. Available for 'send' and 'receive' category of transactions.\n"
1369             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1370             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1371             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
1372             "    \"to\": \"...\",            (string) If a comment to is associated with the transaction.\n"
1373              "  ],\n"
1374             "  \"lastblock\": \"lastblockhash\"     (string) The hash of the last block\n"
1375             "}\n"
1376             "\nExamples:\n"
1377             + HelpExampleCli("listsinceblock", "")
1378             + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1379             + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1380         );
1381
1382     CBlockIndex *pindex = NULL;
1383     int target_confirms = 1;
1384
1385     if (params.size() > 0)
1386     {
1387         uint256 blockId = 0;
1388
1389         blockId.SetHex(params[0].get_str());
1390         std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(blockId);
1391         if (it != mapBlockIndex.end())
1392             pindex = it->second;
1393     }
1394
1395     if (params.size() > 1)
1396     {
1397         target_confirms = params[1].get_int();
1398
1399         if (target_confirms < 1)
1400             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1401     }
1402
1403     int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1404
1405     Array transactions;
1406
1407     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1408     {
1409         CWalletTx tx = (*it).second;
1410
1411         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1412             ListTransactions(tx, "*", 0, true, transactions);
1413     }
1414
1415     CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1416     uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0;
1417
1418     Object ret;
1419     ret.push_back(Pair("transactions", transactions));
1420     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1421
1422     return ret;
1423 }
1424
1425 Value gettransaction(const Array& params, bool fHelp)
1426 {
1427     if (fHelp || params.size() != 1)
1428         throw runtime_error(
1429             "gettransaction \"txid\"\n"
1430             "\nGet detailed information about in-wallet transaction <txid>\n"
1431             "\nArguments:\n"
1432             "1. \"txid\"    (string, required) The transaction id\n"
1433             "\nResult:\n"
1434             "{\n"
1435             "  \"amount\" : x.xxx,        (numeric) The transaction amount in btc\n"
1436             "  \"confirmations\" : n,     (numeric) The number of confirmations\n"
1437             "  \"blockhash\" : \"hash\",  (string) The block hash\n"
1438             "  \"blockindex\" : xx,       (numeric) The block index\n"
1439             "  \"blocktime\" : ttt,       (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1440             "  \"txid\" : \"transactionid\",   (string) The transaction id, see also https://blockchain.info/tx/[transactionid]\n"
1441             "  \"time\" : ttt,            (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1442             "  \"timereceived\" : ttt,    (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1443             "  \"details\" : [\n"
1444             "    {\n"
1445             "      \"account\" : \"accountname\",  (string) The account name involved in the transaction, can be \"\" for the default account.\n"
1446             "      \"address\" : \"bitcoinaddress\",   (string) The bitcoin address involved in the transaction\n"
1447             "      \"category\" : \"send|receive\",    (string) The category, either 'send' or 'receive'\n"
1448             "      \"amount\" : x.xxx                  (numeric) The amount in btc\n"
1449             "    }\n"
1450             "    ,...\n"
1451             "  ]\n"
1452             "}\n"
1453
1454             "\nbExamples\n"
1455             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1456             + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1457         );
1458
1459     uint256 hash;
1460     hash.SetHex(params[0].get_str());
1461
1462     Object entry;
1463     if (!pwalletMain->mapWallet.count(hash))
1464         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1465     const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1466
1467     int64_t nCredit = wtx.GetCredit();
1468     int64_t nDebit = wtx.GetDebit();
1469     int64_t nNet = nCredit - nDebit;
1470     int64_t nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1471
1472     entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1473     if (wtx.IsFromMe())
1474         entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1475
1476     WalletTxToJSON(wtx, entry);
1477
1478     Array details;
1479     ListTransactions(wtx, "*", 0, false, details);
1480     entry.push_back(Pair("details", details));
1481
1482     return entry;
1483 }
1484
1485
1486 Value backupwallet(const Array& params, bool fHelp)
1487 {
1488     if (fHelp || params.size() != 1)
1489         throw runtime_error(
1490             "backupwallet \"destination\"\n"
1491             "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
1492             "\nArguments:\n"
1493             "1. \"destination\"   (string) The destination directory or file\n"
1494             "\nExamples:\n"
1495             + HelpExampleCli("backupwallet", "\"backup.dat\"")
1496             + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1497         );
1498
1499     string strDest = params[0].get_str();
1500     if (!BackupWallet(*pwalletMain, strDest))
1501         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1502
1503     return Value::null;
1504 }
1505
1506
1507 Value keypoolrefill(const Array& params, bool fHelp)
1508 {
1509     if (fHelp || params.size() > 1)
1510         throw runtime_error(
1511             "keypoolrefill ( newsize )\n"
1512             "\nFills the keypool."
1513             + HelpRequiringPassphrase() + "\n"
1514             "\nArguments\n"
1515             "1. newsize     (numeric, optional, default=100) The new keypool size\n"
1516             "\nExamples:\n"
1517             + HelpExampleCli("keypoolrefill", "")
1518             + HelpExampleRpc("keypoolrefill", "")
1519         );
1520
1521     // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1522     unsigned int kpSize = 0;
1523     if (params.size() > 0) {
1524         if (params[0].get_int() < 0)
1525             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1526         kpSize = (unsigned int)params[0].get_int();
1527     }
1528
1529     EnsureWalletIsUnlocked();
1530     pwalletMain->TopUpKeyPool(kpSize);
1531
1532     if (pwalletMain->GetKeyPoolSize() < kpSize)
1533         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1534
1535     return Value::null;
1536 }
1537
1538
1539 static void LockWallet(CWallet* pWallet)
1540 {
1541     LOCK(cs_nWalletUnlockTime);
1542     nWalletUnlockTime = 0;
1543     pWallet->Lock();
1544 }
1545
1546 Value walletpassphrase(const Array& params, bool fHelp)
1547 {
1548     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1549         throw runtime_error(
1550             "walletpassphrase \"passphrase\" timeout\n"
1551             "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1552             "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
1553             "\nArguments:\n"
1554             "1. \"passphrase\"     (string, required) The wallet passphrase\n"
1555             "2. timeout            (numeric, required) The time to keep the decryption key in seconds.\n"
1556             "\nExamples:\n"
1557             "\nunlock the wallet for 60 seconds\n"
1558             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1559             "\nLock the wallet again (before 60 seconds)\n"
1560             + HelpExampleCli("walletlock", "") +
1561             "\nAs json rpc call\n"
1562             + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1563         );
1564
1565     if (fHelp)
1566         return true;
1567     if (!pwalletMain->IsCrypted())
1568         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1569
1570     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1571     SecureString strWalletPass;
1572     strWalletPass.reserve(100);
1573     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1574     // Alternately, find a way to make params[0] mlock()'d to begin with.
1575     strWalletPass = params[0].get_str().c_str();
1576
1577     if (strWalletPass.length() > 0)
1578     {
1579         if (!pwalletMain->Unlock(strWalletPass))
1580             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1581     }
1582     else
1583         throw runtime_error(
1584             "walletpassphrase <passphrase> <timeout>\n"
1585             "Stores the wallet decryption key in memory for <timeout> seconds.");
1586
1587     pwalletMain->TopUpKeyPool();
1588
1589     int64_t nSleepTime = params[1].get_int64();
1590     LOCK(cs_nWalletUnlockTime);
1591     nWalletUnlockTime = GetTime() + nSleepTime;
1592     RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
1593
1594     return Value::null;
1595 }
1596
1597
1598 Value walletpassphrasechange(const Array& params, bool fHelp)
1599 {
1600     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1601         throw runtime_error(
1602             "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1603             "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1604             "\nArguments:\n"
1605             "1. \"oldpassphrase\"      (string) The current passphrase\n"
1606             "2. \"newpassphrase\"      (string) The new passphrase\n"
1607             "\nExamples:\n"
1608             + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1609             + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1610         );
1611
1612     if (fHelp)
1613         return true;
1614     if (!pwalletMain->IsCrypted())
1615         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1616
1617     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1618     // Alternately, find a way to make params[0] mlock()'d to begin with.
1619     SecureString strOldWalletPass;
1620     strOldWalletPass.reserve(100);
1621     strOldWalletPass = params[0].get_str().c_str();
1622
1623     SecureString strNewWalletPass;
1624     strNewWalletPass.reserve(100);
1625     strNewWalletPass = params[1].get_str().c_str();
1626
1627     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1628         throw runtime_error(
1629             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1630             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1631
1632     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1633         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1634
1635     return Value::null;
1636 }
1637
1638
1639 Value walletlock(const Array& params, bool fHelp)
1640 {
1641     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1642         throw runtime_error(
1643             "walletlock\n"
1644             "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
1645             "After calling this method, you will need to call walletpassphrase again\n"
1646             "before being able to call any methods which require the wallet to be unlocked.\n"
1647             "\nExamples:\n"
1648             "\nSet the passphrase for 2 minutes to perform a transaction\n"
1649             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1650             "\nPerform a send (requires passphrase set)\n"
1651             + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1652             "\nClear the passphrase since we are done before 2 minutes is up\n"
1653             + HelpExampleCli("walletlock", "") +
1654             "\nAs json rpc call\n"
1655             + HelpExampleRpc("walletlock", "")
1656         );
1657
1658     if (fHelp)
1659         return true;
1660     if (!pwalletMain->IsCrypted())
1661         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
1662
1663     {
1664         LOCK(cs_nWalletUnlockTime);
1665         pwalletMain->Lock();
1666         nWalletUnlockTime = 0;
1667     }
1668
1669     return Value::null;
1670 }
1671
1672
1673 Value encryptwallet(const Array& params, bool fHelp)
1674 {
1675     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1676         throw runtime_error(
1677             "encryptwallet \"passphrase\"\n"
1678             "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
1679             "After this, any calls that interact with private keys such as sending or signing \n"
1680             "will require the passphrase to be set prior the making these calls.\n"
1681             "Use the walletpassphrase call for this, and then walletlock call.\n"
1682             "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
1683             "Note that this will shutdown the server.\n"
1684             "\nArguments:\n"
1685             "1. \"passphrase\"    (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
1686             "\nExamples:\n"
1687             "\nEncrypt you wallet\n"
1688             + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
1689             "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
1690             + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
1691             "\nNow we can so something like sign\n"
1692             + HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
1693             "\nNow lock the wallet again by removing the passphrase\n"
1694             + HelpExampleCli("walletlock", "") +
1695             "\nAs a json rpc call\n"
1696             + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
1697         );
1698
1699     if (fHelp)
1700         return true;
1701     if (pwalletMain->IsCrypted())
1702         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
1703
1704     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1705     // Alternately, find a way to make params[0] mlock()'d to begin with.
1706     SecureString strWalletPass;
1707     strWalletPass.reserve(100);
1708     strWalletPass = params[0].get_str().c_str();
1709
1710     if (strWalletPass.length() < 1)
1711         throw runtime_error(
1712             "encryptwallet <passphrase>\n"
1713             "Encrypts the wallet with <passphrase>.");
1714
1715     if (!pwalletMain->EncryptWallet(strWalletPass))
1716         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
1717
1718     // BDB seems to have a bad habit of writing old data into
1719     // slack space in .dat files; that is bad if the old data is
1720     // unencrypted private keys. So:
1721     StartShutdown();
1722     return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
1723 }
1724
1725 Value lockunspent(const Array& params, bool fHelp)
1726 {
1727     if (fHelp || params.size() < 1 || params.size() > 2)
1728         throw runtime_error(
1729             "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
1730             "\nUpdates list of temporarily unspendable outputs.\n"
1731             "Temporarily lock (lock=true) or unlock (lock=false) specified transaction outputs.\n"
1732             "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
1733             "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
1734             "is always cleared (by virtue of process exit) when a node stops or fails.\n"
1735             "Also see the listunspent call\n"
1736             "\nArguments:\n"
1737             "1. unlock            (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
1738             "2. \"transactions\"  (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
1739             "     [           (json array of json objects)\n"
1740             "       {\n"
1741             "         \"txid\":\"id\",    (string) The transaction id\n"
1742             "         \"vout\": n         (numeric) The output number\n"
1743             "       }\n"
1744             "       ,...\n"
1745             "     ]\n"
1746
1747             "\nResult:\n"
1748             "true|false    (boolean) Whether the command was successful or not\n"
1749
1750             "\nExamples:\n"
1751             "\nList the unspent transactions\n"
1752             + HelpExampleCli("listunspent", "") +
1753             "\nLock an unspent transaction\n"
1754             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1755             "\nList the locked transactions\n"
1756             + HelpExampleCli("listlockunspent", "") +
1757             "\nUnlock the transaction again\n"
1758             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1759             "\nAs a json rpc call\n"
1760             + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
1761         );
1762
1763     if (params.size() == 1)
1764         RPCTypeCheck(params, list_of(bool_type));
1765     else
1766         RPCTypeCheck(params, list_of(bool_type)(array_type));
1767
1768     bool fUnlock = params[0].get_bool();
1769
1770     if (params.size() == 1) {
1771         if (fUnlock)
1772             pwalletMain->UnlockAllCoins();
1773         return true;
1774     }
1775
1776     Array outputs = params[1].get_array();
1777     BOOST_FOREACH(Value& output, outputs)
1778     {
1779         if (output.type() != obj_type)
1780             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
1781         const Object& o = output.get_obj();
1782
1783         RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type));
1784
1785         string txid = find_value(o, "txid").get_str();
1786         if (!IsHex(txid))
1787             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
1788
1789         int nOutput = find_value(o, "vout").get_int();
1790         if (nOutput < 0)
1791             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
1792
1793         COutPoint outpt(uint256(txid), nOutput);
1794
1795         if (fUnlock)
1796             pwalletMain->UnlockCoin(outpt);
1797         else
1798             pwalletMain->LockCoin(outpt);
1799     }
1800
1801     return true;
1802 }
1803
1804 Value listlockunspent(const Array& params, bool fHelp)
1805 {
1806     if (fHelp || params.size() > 0)
1807         throw runtime_error(
1808             "listlockunspent\n"
1809             "\nReturns list of temporarily unspendable outputs.\n"
1810             "See the lockunspent call to lock and unlock transactions for spending.\n"
1811             "\nResult:\n"
1812             "[\n"
1813             "  {\n"
1814             "    \"txid\" : \"transactionid\",     (string) The transaction id locked\n"
1815             "    \"vout\" : n                      (numeric) The vout value\n"
1816             "  }\n"
1817             "  ,...\n"
1818             "]\n"
1819             "\nExamples:\n"
1820             "\nList the unspent transactions\n"
1821             + HelpExampleCli("listunspent", "") +
1822             "\nLock an unspent transaction\n"
1823             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1824             "\nList the locked transactions\n"
1825             + HelpExampleCli("listlockunspent", "") +
1826             "\nUnlock the transaction again\n"
1827             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1828             "\nAs a json rpc call\n"
1829             + HelpExampleRpc("listlockunspent", "")
1830         );
1831
1832     vector<COutPoint> vOutpts;
1833     pwalletMain->ListLockedCoins(vOutpts);
1834
1835     Array ret;
1836
1837     BOOST_FOREACH(COutPoint &outpt, vOutpts) {
1838         Object o;
1839
1840         o.push_back(Pair("txid", outpt.hash.GetHex()));
1841         o.push_back(Pair("vout", (int)outpt.n));
1842         ret.push_back(o);
1843     }
1844
1845     return ret;
1846 }
1847
1848 Value settxfee(const Array& params, bool fHelp)
1849 {
1850     if (fHelp || params.size() < 1 || params.size() > 1)
1851         throw runtime_error(
1852             "settxfee amount\n"
1853             "\nSet the transaction fee. 'amount' is a real and is rounded to the nearest 0.00000001\n"
1854             "\nArguments:\n"
1855             "1. amount         (numeric, required) The transaction fee in btc rounded to the nearest 0.00000001\n"
1856             "\nResult\n"
1857             "true|false        (boolean) Returns true if successful\n"
1858             "\nExamples:\n"
1859             + HelpExampleCli("settxfee", "0.00001")
1860             + HelpExampleRpc("settxfee", "0.00001")
1861         );
1862
1863     // Amount
1864     int64_t nAmount = 0;
1865     if (params[0].get_real() != 0.0)
1866         nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts
1867
1868     nTransactionFee = nAmount;
1869     return true;
1870 }
1871
1872
This page took 0.131384 seconds and 4 git commands to generate.