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