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