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