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