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