]> Git Repo - VerusCoin.git/blame - src/rpcwallet.cpp
qt: GUI for conflicted transactions
[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));
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));
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"
3cf1f436 592 "1. \"account\" (string, optional) The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
a6099ef3 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", "") +
3cf1f436
WL
599 "\nThe total amount in the server across all accounts, with at least 5 confirmations\n"
600 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 601 "\nThe total amount in the default account with at least 1 confirmation\n"
602 + HelpExampleCli("getbalance", "\"\"") +
603 "\nThe total amount in the account named tabby with at least 6 confirmations\n"
604 + HelpExampleCli("getbalance", "\"tabby\" 6") +
605 "\nAs a json rpc call\n"
606 + HelpExampleRpc("getbalance", "\"tabby\", 6")
607 );
e3bc5698
JG
608
609 if (params.size() == 0)
610 return ValueFromAmount(pwalletMain->GetBalance());
611
612 int nMinDepth = 1;
613 if (params.size() > 1)
614 nMinDepth = params[1].get_int();
615
616 if (params[0].get_str() == "*") {
617 // Calculate total balance a different way from GetBalance()
618 // (GetBalance() sums up all unspent TxOuts)
d28bd8b7 619 // getbalance and getbalance '*' 0 should return the same number
51ed9ec9 620 int64_t nBalance = 0;
e3bc5698
JG
621 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
622 {
623 const CWalletTx& wtx = (*it).second;
0542619d 624 if (!wtx.IsTrusted())
e3bc5698
JG
625 continue;
626
51ed9ec9 627 int64_t allFee;
e3bc5698 628 string strSentAccount;
51ed9ec9
BD
629 list<pair<CTxDestination, int64_t> > listReceived;
630 list<pair<CTxDestination, int64_t> > listSent;
e07c8e91 631 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
e3bc5698
JG
632 if (wtx.GetDepthInMainChain() >= nMinDepth)
633 {
51ed9ec9 634 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
e3bc5698
JG
635 nBalance += r.second;
636 }
51ed9ec9 637 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
e3bc5698
JG
638 nBalance -= r.second;
639 nBalance -= allFee;
e3bc5698
JG
640 }
641 return ValueFromAmount(nBalance);
642 }
643
644 string strAccount = AccountFromValue(params[0]);
645
51ed9ec9 646 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
e3bc5698
JG
647
648 return ValueFromAmount(nBalance);
649}
650
6027b460
MB
651Value getunconfirmedbalance(const Array &params, bool fHelp)
652{
653 if (fHelp || params.size() > 0)
654 throw runtime_error(
655 "getunconfirmedbalance\n"
656 "Returns the server's total unconfirmed balance\n");
657 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
658}
659
e3bc5698
JG
660
661Value movecmd(const Array& params, bool fHelp)
662{
663 if (fHelp || params.size() < 3 || params.size() > 5)
664 throw runtime_error(
a6099ef3 665 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
666 "\nMove a specified amount from one account in your wallet to another.\n"
667 "\nArguments:\n"
668 "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
669 "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
670 "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
671 "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
672 "\nResult:\n"
673 "true|false (boolean) true if successfull.\n"
674 "\nExamples:\n"
675 "\nMove 0.01 btc from the default account to the account named tabby\n"
676 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
677 "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
678 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
679 "\nAs a json rpc call\n"
680 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
681 );
e3bc5698
JG
682
683 string strFrom = AccountFromValue(params[0]);
684 string strTo = AccountFromValue(params[1]);
51ed9ec9 685 int64_t nAmount = AmountFromValue(params[2]);
e3bc5698
JG
686 if (params.size() > 3)
687 // unused parameter, used to be nMinDepth, keep type-checking it though
688 (void)params[3].get_int();
689 string strComment;
690 if (params.size() > 4)
691 strComment = params[4].get_str();
692
693 CWalletDB walletdb(pwalletMain->strWalletFile);
694 if (!walletdb.TxnBegin())
738835d7 695 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 696
51ed9ec9 697 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
698
699 // Debit
700 CAccountingEntry debit;
4291e8fe 701 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
702 debit.strAccount = strFrom;
703 debit.nCreditDebit = -nAmount;
704 debit.nTime = nNow;
705 debit.strOtherAccount = strTo;
706 debit.strComment = strComment;
707 walletdb.WriteAccountingEntry(debit);
708
709 // Credit
710 CAccountingEntry credit;
4291e8fe 711 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
712 credit.strAccount = strTo;
713 credit.nCreditDebit = nAmount;
714 credit.nTime = nNow;
715 credit.strOtherAccount = strFrom;
716 credit.strComment = strComment;
717 walletdb.WriteAccountingEntry(credit);
718
719 if (!walletdb.TxnCommit())
738835d7 720 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
721
722 return true;
723}
724
725
726Value sendfrom(const Array& params, bool fHelp)
727{
728 if (fHelp || params.size() < 3 || params.size() > 6)
729 throw runtime_error(
a6099ef3 730 "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
731 "\nSent an amount from an account to a bitcoin address.\n"
732 "The amount is a real and is rounded to the nearest 0.00000001."
733 + HelpRequiringPassphrase() + "\n"
734 "\nArguments:\n"
735 "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
736 "2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
737 "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
738 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
739 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
740 " This is not part of the transaction, just kept in your wallet.\n"
741 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
742 " to which you're sending the transaction. This is not part of the transaction, \n"
743 " it is just kept in your wallet.\n"
744 "\nResult:\n"
745 "\"transactionid\" (string) The transaction id. (view at https://blockchain.info/tx/[transactionid])\n"
746 "\nExamples:\n"
747 "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
748 + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
749 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
750 + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
751 "\nAs a json rpc call\n"
752 + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
753 );
e3bc5698
JG
754
755 string strAccount = AccountFromValue(params[0]);
756 CBitcoinAddress address(params[1].get_str());
757 if (!address.IsValid())
738835d7 758 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
51ed9ec9 759 int64_t nAmount = AmountFromValue(params[2]);
e3bc5698
JG
760 int nMinDepth = 1;
761 if (params.size() > 3)
762 nMinDepth = params[3].get_int();
763
764 CWalletTx wtx;
765 wtx.strFromAccount = strAccount;
766 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
767 wtx.mapValue["comment"] = params[4].get_str();
768 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
769 wtx.mapValue["to"] = params[5].get_str();
770
771 EnsureWalletIsUnlocked();
772
773 // Check funds
51ed9ec9 774 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
e3bc5698 775 if (nAmount > nBalance)
738835d7 776 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
777
778 // Send
779 string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
780 if (strError != "")
738835d7 781 throw JSONRPCError(RPC_WALLET_ERROR, strError);
e3bc5698
JG
782
783 return wtx.GetHash().GetHex();
784}
785
786
787Value sendmany(const Array& params, bool fHelp)
788{
789 if (fHelp || params.size() < 2 || params.size() > 4)
790 throw runtime_error(
a6099ef3 791 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" )\n"
792 "\nSend multiple times. Amounts are double-precision floating point numbers."
793 + HelpRequiringPassphrase() + "\n"
794 "\nArguments:\n"
795 "1. \"fromaccount\" (string, required) The account to send the funds from, can be \"\" for the default account\n"
796 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
797 " {\n"
798 " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
799 " ,...\n"
800 " }\n"
801 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
802 "4. \"comment\" (string, optional) A comment\n"
803 "\nResult:\n"
804 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
805 " the number of addresses. See https://blockchain.info/tx/[transactionid]\n"
806 "\nExamples:\n"
807 "\nSend two amounts to two different addresses:\n"
808 + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
809 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
810 + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
811 "\nAs a json rpc call\n"
812 + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
813 );
e3bc5698
JG
814
815 string strAccount = AccountFromValue(params[0]);
816 Object sendTo = params[1].get_obj();
817 int nMinDepth = 1;
818 if (params.size() > 2)
819 nMinDepth = params[2].get_int();
820
821 CWalletTx wtx;
822 wtx.strFromAccount = strAccount;
823 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
824 wtx.mapValue["comment"] = params[3].get_str();
825
826 set<CBitcoinAddress> setAddress;
51ed9ec9 827 vector<pair<CScript, int64_t> > vecSend;
e3bc5698 828
51ed9ec9 829 int64_t totalAmount = 0;
e3bc5698
JG
830 BOOST_FOREACH(const Pair& s, sendTo)
831 {
832 CBitcoinAddress address(s.name_);
833 if (!address.IsValid())
738835d7 834 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
e3bc5698
JG
835
836 if (setAddress.count(address))
738835d7 837 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
e3bc5698
JG
838 setAddress.insert(address);
839
840 CScript scriptPubKey;
841 scriptPubKey.SetDestination(address.Get());
51ed9ec9 842 int64_t nAmount = AmountFromValue(s.value_);
e3bc5698
JG
843 totalAmount += nAmount;
844
845 vecSend.push_back(make_pair(scriptPubKey, nAmount));
846 }
847
848 EnsureWalletIsUnlocked();
849
850 // Check funds
51ed9ec9 851 int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
e3bc5698 852 if (totalAmount > nBalance)
738835d7 853 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
854
855 // Send
856 CReserveKey keyChange(pwalletMain);
51ed9ec9 857 int64_t nFeeRequired = 0;
1f00f4e9
GA
858 string strFailReason;
859 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason);
e3bc5698 860 if (!fCreated)
1f00f4e9 861 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 862 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 863 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698
JG
864
865 return wtx.GetHash().GetHex();
866}
867
723a03d2
WL
868// Defined in rpcmisc.cpp
869extern CScript _createmultisig(const Array& params);
34226be7
GA
870
871Value addmultisigaddress(const Array& params, bool fHelp)
872{
873 if (fHelp || params.size() < 2 || params.size() > 3)
874 {
a6099ef3 875 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
876 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
877 "Each key is a Bitcoin address or hex-encoded public key.\n"
878 "If 'account' is specified, assign address to that account.\n"
879
880 "\nArguments:\n"
881 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
882 "2. \"keysobject\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
883 " [\n"
884 " \"address\" (string) bitcoin address or hex-encoded public key\n"
885 " ...,\n"
886 " ]\n"
887 "3. \"account\" (string, optional) An account to assign the addresses to.\n"
888
889 "\nResult:\n"
890 "\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
891
892 "\nExamples:\n"
893 "\nAdd a multisig address from 2 addresses\n"
894 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
895 "\nAs json rpc call\n"
896 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
897 ;
34226be7
GA
898 throw runtime_error(msg);
899 }
900
901 string strAccount;
902 if (params.size() > 2)
903 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
904
905 // Construct using pay-to-script-hash:
34226be7 906 CScript inner = _createmultisig(params);
e3bc5698
JG
907 CScriptID innerID = inner.GetID();
908 pwalletMain->AddCScript(inner);
909
a41d5fe0 910 pwalletMain->SetAddressBook(innerID, strAccount, "send");
e3bc5698
JG
911 return CBitcoinAddress(innerID).ToString();
912}
913
914
915struct tallyitem
916{
51ed9ec9 917 int64_t nAmount;
e3bc5698 918 int nConf;
62c9b115 919 vector<uint256> txids;
e3bc5698
JG
920 tallyitem()
921 {
922 nAmount = 0;
923 nConf = std::numeric_limits<int>::max();
924 }
925};
926
927Value ListReceived(const Array& params, bool fByAccounts)
928{
929 // Minimum confirmations
930 int nMinDepth = 1;
931 if (params.size() > 0)
932 nMinDepth = params[0].get_int();
933
934 // Whether to include empty accounts
935 bool fIncludeEmpty = false;
936 if (params.size() > 1)
937 fIncludeEmpty = params[1].get_bool();
938
939 // Tally
940 map<CBitcoinAddress, tallyitem> mapTally;
941 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
942 {
943 const CWalletTx& wtx = (*it).second;
944
05df3fc6 945 if (wtx.IsCoinBase() || !IsFinalTx(wtx))
e3bc5698
JG
946 continue;
947
948 int nDepth = wtx.GetDepthInMainChain();
949 if (nDepth < nMinDepth)
950 continue;
951
952 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
953 {
954 CTxDestination address;
955 if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
956 continue;
957
958 tallyitem& item = mapTally[address];
959 item.nAmount += txout.nValue;
960 item.nConf = min(item.nConf, nDepth);
62c9b115 961 item.txids.push_back(wtx.GetHash());
e3bc5698
JG
962 }
963 }
964
965 // Reply
966 Array ret;
967 map<string, tallyitem> mapAccountTally;
61885513 968 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
969 {
970 const CBitcoinAddress& address = item.first;
61885513 971 const string& strAccount = item.second.name;
e3bc5698
JG
972 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
973 if (it == mapTally.end() && !fIncludeEmpty)
974 continue;
975
51ed9ec9 976 int64_t nAmount = 0;
e3bc5698
JG
977 int nConf = std::numeric_limits<int>::max();
978 if (it != mapTally.end())
979 {
980 nAmount = (*it).second.nAmount;
981 nConf = (*it).second.nConf;
982 }
983
984 if (fByAccounts)
985 {
986 tallyitem& item = mapAccountTally[strAccount];
987 item.nAmount += nAmount;
988 item.nConf = min(item.nConf, nConf);
989 }
990 else
991 {
992 Object obj;
993 obj.push_back(Pair("address", address.ToString()));
994 obj.push_back(Pair("account", strAccount));
995 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
996 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
62c9b115 997 Array transactions;
1a204694 998 if (it != mapTally.end())
62c9b115 999 {
1a204694
A
1000 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1001 {
1002 transactions.push_back(item.GetHex());
1003 }
62c9b115
A
1004 }
1005 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
1006 ret.push_back(obj);
1007 }
1008 }
1009
1010 if (fByAccounts)
1011 {
1012 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1013 {
51ed9ec9 1014 int64_t nAmount = (*it).second.nAmount;
e3bc5698
JG
1015 int nConf = (*it).second.nConf;
1016 Object obj;
1017 obj.push_back(Pair("account", (*it).first));
1018 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1019 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1020 ret.push_back(obj);
1021 }
1022 }
1023
1024 return ret;
1025}
1026
1027Value listreceivedbyaddress(const Array& params, bool fHelp)
1028{
1029 if (fHelp || params.size() > 2)
1030 throw runtime_error(
a6099ef3 1031 "listreceivedbyaddress ( minconf includeempty )\n"
1032 "\nList balances by receiving address.\n"
1033 "\nArguments:\n"
1034 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1035 "2. includeempty (numeric, optional, dafault=false) Whether to include addresses that haven't received any payments.\n"
1036
1037 "\nResult:\n"
1038 "[\n"
1039 " {\n"
1040 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1041 " \"account\" : \"accountname\", (string) The account of the receiving address. The default account is \"\".\n"
1042 " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
1043 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1044 " }\n"
1045 " ,...\n"
1046 "]\n"
1047
1048 "\nExamples:\n"
1049 + HelpExampleCli("listreceivedbyaddress", "")
1050 + HelpExampleCli("listreceivedbyaddress", "6 true")
1051 + HelpExampleRpc("listreceivedbyaddress", "6, true")
1052 );
e3bc5698
JG
1053
1054 return ListReceived(params, false);
1055}
1056
1057Value listreceivedbyaccount(const Array& params, bool fHelp)
1058{
1059 if (fHelp || params.size() > 2)
1060 throw runtime_error(
a6099ef3 1061 "listreceivedbyaccount ( minconf includeempty )\n"
1062 "\nList balances by account.\n"
1063 "\nArguments:\n"
1064 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1065 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1066
1067 "\nResult:\n"
1068 "[\n"
1069 " {\n"
1070 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1071 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1072 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1073 " }\n"
1074 " ,...\n"
1075 "]\n"
1076
1077 "\nExamples:\n"
1078 + HelpExampleCli("listreceivedbyaccount", "")
1079 + HelpExampleCli("listreceivedbyaccount", "6 true")
1080 + HelpExampleRpc("listreceivedbyaccount", "6, true")
1081 );
e3bc5698
JG
1082
1083 return ListReceived(params, true);
1084}
1085
cc6cfab3
LD
1086static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1087{
1088 CBitcoinAddress addr;
1089 if (addr.Set(dest))
1090 entry.push_back(Pair("address", addr.ToString()));
1091}
1092
e3bc5698
JG
1093void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1094{
51ed9ec9 1095 int64_t nFee;
e3bc5698 1096 string strSentAccount;
51ed9ec9
BD
1097 list<pair<CTxDestination, int64_t> > listReceived;
1098 list<pair<CTxDestination, int64_t> > listSent;
e3bc5698 1099
e07c8e91 1100 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
e3bc5698
JG
1101
1102 bool fAllAccounts = (strAccount == string("*"));
1103
e3bc5698
JG
1104 // Sent
1105 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1106 {
51ed9ec9 1107 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
e3bc5698
JG
1108 {
1109 Object entry;
1110 entry.push_back(Pair("account", strSentAccount));
cc6cfab3 1111 MaybePushAddress(entry, s.first);
2b72d46f
GA
1112 if (wtx.GetDepthInMainChain() < 0)
1113 entry.push_back(Pair("category", "conflicted"));
1114 else
1115 entry.push_back(Pair("category", "send"));
e3bc5698
JG
1116 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1117 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1118 if (fLong)
1119 WalletTxToJSON(wtx, entry);
1120 ret.push_back(entry);
1121 }
1122 }
1123
1124 // Received
1125 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1126 {
51ed9ec9 1127 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
e3bc5698
JG
1128 {
1129 string account;
1130 if (pwalletMain->mapAddressBook.count(r.first))
61885513 1131 account = pwalletMain->mapAddressBook[r.first].name;
e3bc5698
JG
1132 if (fAllAccounts || (account == strAccount))
1133 {
1134 Object entry;
1135 entry.push_back(Pair("account", account));
cc6cfab3 1136 MaybePushAddress(entry, r.first);
e07c8e91
LD
1137 if (wtx.IsCoinBase())
1138 {
1139 if (wtx.GetDepthInMainChain() < 1)
1140 entry.push_back(Pair("category", "orphan"));
1141 else if (wtx.GetBlocksToMaturity() > 0)
1142 entry.push_back(Pair("category", "immature"));
1143 else
1144 entry.push_back(Pair("category", "generate"));
1145 }
1146 else
2b72d46f
GA
1147 {
1148 if (wtx.GetDepthInMainChain() < 0)
1149 entry.push_back(Pair("category", "conflicted"));
1150 else
1151 entry.push_back(Pair("category", "receive"));
1152 }
e3bc5698
JG
1153 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1154 if (fLong)
1155 WalletTxToJSON(wtx, entry);
1156 ret.push_back(entry);
1157 }
1158 }
1159 }
1160}
1161
1162void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1163{
1164 bool fAllAccounts = (strAccount == string("*"));
1165
1166 if (fAllAccounts || acentry.strAccount == strAccount)
1167 {
1168 Object entry;
1169 entry.push_back(Pair("account", acentry.strAccount));
1170 entry.push_back(Pair("category", "move"));
1171 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1172 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1173 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1174 entry.push_back(Pair("comment", acentry.strComment));
1175 ret.push_back(entry);
1176 }
1177}
1178
1179Value listtransactions(const Array& params, bool fHelp)
1180{
1181 if (fHelp || params.size() > 3)
1182 throw runtime_error(
a6099ef3 1183 "listtransactions ( \"account\" count from )\n"
1184 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1185 "\nArguments:\n"
1186 "1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n"
1187 " If \"\" is set, it will list transactions for the default account.\n"
1188 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1189 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1190
1191 "\nResult:\n"
1192 "[\n"
1193 " {\n"
1194 " \"account\":\"accountname\", (string) The account name associated with the transaction. \n"
1195 " It will be \"\" for the default account.\n"
1196 " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n"
1197 " move transactions (category = move).\n"
1198 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1199 " transaction between accounts, and not associated with an address,\n"
1200 " transaction id or block. 'send' and 'receive' transactions are \n"
1201 " associated with an address, transaction id and block details\n"
1202 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1203 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1204 " and for the 'move' category for inbound funds.\n"
1205 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1206 " 'send' category of transactions.\n"
1207 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1208 " 'receive' category of transactions.\n"
1209 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1210 " category of transactions.\n"
1211 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1212 " category of transactions.\n"
1213 " \"txid\": \"transactionid\", (string) The transaction id (see https://blockchain.info/tx/[transactionid]. Available \n"
1214 " for 'send' and 'receive' category of transactions.\n"
1215 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1216 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1217 " for 'send' and 'receive' category of transactions.\n"
1218 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1219 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1220 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1221 " negative amounts).\n"
1222 " }\n"
1223 "]\n"
1224
1225 "\nExamples:\n"
1226 "\nList the most recent 10 transactions in the systems\n"
1227 + HelpExampleCli("listtransactions", "") +
1228 "\nList the most recent 10 transactions for the tabby account\n"
1229 + HelpExampleCli("listtransactions", "\"tabby\"") +
1230 "\nList transactions 100 to 120 from the tabby account\n"
1231 + HelpExampleCli("listtransactions", "\"tabby\" 20 100") +
1232 "\nAs a json rpc call\n"
1233 + HelpExampleRpc("listtransactions", "\"tabby\", 20, 100")
1234 );
e3bc5698
JG
1235
1236 string strAccount = "*";
1237 if (params.size() > 0)
1238 strAccount = params[0].get_str();
1239 int nCount = 10;
1240 if (params.size() > 1)
1241 nCount = params[1].get_int();
1242 int nFrom = 0;
1243 if (params.size() > 2)
1244 nFrom = params[2].get_int();
1245
1246 if (nCount < 0)
738835d7 1247 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 1248 if (nFrom < 0)
738835d7 1249 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698
JG
1250
1251 Array ret;
e3bc5698 1252
ddb709e9
LD
1253 std::list<CAccountingEntry> acentries;
1254 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1255
1256 // iterate backwards until we have nCount items to return:
c3f95ef1 1257 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
1258 {
1259 CWalletTx *const pwtx = (*it).second.first;
1260 if (pwtx != 0)
1261 ListTransactions(*pwtx, strAccount, 0, true, ret);
1262 CAccountingEntry *const pacentry = (*it).second.second;
1263 if (pacentry != 0)
1264 AcentryToJSON(*pacentry, strAccount, ret);
1265
1266 if ((int)ret.size() >= (nCount+nFrom)) break;
1267 }
1268 // ret is newest to oldest
1269
1270 if (nFrom > (int)ret.size())
1271 nFrom = ret.size();
1272 if ((nFrom + nCount) > (int)ret.size())
1273 nCount = ret.size() - nFrom;
1274 Array::iterator first = ret.begin();
1275 std::advance(first, nFrom);
1276 Array::iterator last = ret.begin();
1277 std::advance(last, nFrom+nCount);
1278
1279 if (last != ret.end()) ret.erase(last, ret.end());
1280 if (first != ret.begin()) ret.erase(ret.begin(), first);
1281
1282 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1283
1284 return ret;
1285}
1286
1287Value listaccounts(const Array& params, bool fHelp)
1288{
1289 if (fHelp || params.size() > 1)
1290 throw runtime_error(
a6099ef3 1291 "listaccounts ( minconf )\n"
1292 "\nReturns Object that has account names as keys, account balances as values.\n"
1293 "\nArguments:\n"
1294 "1. minconf (numeric, optional, default=1) Only onclude transactions with at least this many confirmations\n"
1295 "\nResult:\n"
1296 "{ (json object where keys are account names, and values are numeric balances\n"
1297 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1298 " ...\n"
1299 "}\n"
1300 "\nExamples:\n"
1301 "\nList account balances where there at least 1 confirmation\n"
1302 + HelpExampleCli("listaccounts", "") +
1303 "\nList account balances including zero confirmation transactions\n"
1304 + HelpExampleCli("listaccounts", "0") +
1305 "\nList account balances for 6 or more confirmations\n"
1306 + HelpExampleCli("listaccounts", "6") +
1307 "\nAs json rpc call\n"
1308 + HelpExampleRpc("listaccounts", "6")
1309 );
e3bc5698
JG
1310
1311 int nMinDepth = 1;
1312 if (params.size() > 0)
1313 nMinDepth = params[0].get_int();
1314
51ed9ec9 1315 map<string, int64_t> mapAccountBalances;
61885513 1316 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
e3bc5698 1317 if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
61885513 1318 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
1319 }
1320
1321 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1322 {
1323 const CWalletTx& wtx = (*it).second;
51ed9ec9 1324 int64_t nFee;
e3bc5698 1325 string strSentAccount;
51ed9ec9
BD
1326 list<pair<CTxDestination, int64_t> > listReceived;
1327 list<pair<CTxDestination, int64_t> > listSent;
e07c8e91 1328 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
e3bc5698 1329 mapAccountBalances[strSentAccount] -= nFee;
51ed9ec9 1330 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
e3bc5698
JG
1331 mapAccountBalances[strSentAccount] -= s.second;
1332 if (wtx.GetDepthInMainChain() >= nMinDepth)
1333 {
51ed9ec9 1334 BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
e3bc5698 1335 if (pwalletMain->mapAddressBook.count(r.first))
61885513 1336 mapAccountBalances[pwalletMain->mapAddressBook[r.first].name] += r.second;
e3bc5698
JG
1337 else
1338 mapAccountBalances[""] += r.second;
1339 }
1340 }
1341
1342 list<CAccountingEntry> acentries;
1343 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1344 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1345 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1346
1347 Object ret;
51ed9ec9 1348 BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
e3bc5698
JG
1349 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1350 }
1351 return ret;
1352}
1353
1354Value listsinceblock(const Array& params, bool fHelp)
1355{
1356 if (fHelp)
1357 throw runtime_error(
a6099ef3 1358 "listsinceblock ( \"blockhash\" target-confirmations )\n"
1359 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1360 "\nArguments:\n"
1361 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1362 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1363 "\nResult:\n"
1364 "{\n"
1365 " \"transactions\": [\n"
1366 " \"account\":\"accountname\", (string) The account name associated with the transaction. Will be \"\" for the default account.\n"
1367 " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
1368 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1369 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1370 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1371 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1372 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1373 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1374 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1375 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1376 " \"txid\": \"transactionid\", (string) The transaction id (see https://blockchain.info/tx/[transactionid]. Available for 'send' and 'receive' category of transactions.\n"
1377 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1378 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1379 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1380 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1381 " ],\n"
1382 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1383 "}\n"
1384 "\nExamples:\n"
1385 + HelpExampleCli("listsinceblock", "")
1386 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1387 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1388 );
e3bc5698
JG
1389
1390 CBlockIndex *pindex = NULL;
1391 int target_confirms = 1;
1392
1393 if (params.size() > 0)
1394 {
1395 uint256 blockId = 0;
1396
1397 blockId.SetHex(params[0].get_str());
e4daecda
PW
1398 std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(blockId);
1399 if (it != mapBlockIndex.end())
1400 pindex = it->second;
e3bc5698
JG
1401 }
1402
1403 if (params.size() > 1)
1404 {
1405 target_confirms = params[1].get_int();
1406
1407 if (target_confirms < 1)
738835d7 1408 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
1409 }
1410
4c6d41b8 1411 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
e3bc5698
JG
1412
1413 Array transactions;
1414
1415 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1416 {
1417 CWalletTx tx = (*it).second;
1418
1419 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1420 ListTransactions(tx, "*", 0, true, transactions);
1421 }
1422
4c6d41b8
PW
1423 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1424 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0;
e3bc5698
JG
1425
1426 Object ret;
1427 ret.push_back(Pair("transactions", transactions));
1428 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1429
1430 return ret;
1431}
1432
1433Value gettransaction(const Array& params, bool fHelp)
1434{
1435 if (fHelp || params.size() != 1)
1436 throw runtime_error(
a6099ef3 1437 "gettransaction \"txid\"\n"
1438 "\nGet detailed information about in-wallet transaction <txid>\n"
1439 "\nArguments:\n"
1440 "1. \"txid\" (string, required) The transaction id\n"
1441 "\nResult:\n"
1442 "{\n"
1443 " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
1444 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1445 " \"blockhash\" : \"hash\", (string) The block hash\n"
1446 " \"blockindex\" : xx, (numeric) The block index\n"
1447 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1448 " \"txid\" : \"transactionid\", (string) The transaction id, see also https://blockchain.info/tx/[transactionid]\n"
1449 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1450 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1451 " \"details\" : [\n"
1452 " {\n"
1453 " \"account\" : \"accountname\", (string) The account name involved in the transaction, can be \"\" for the default account.\n"
1454 " \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
1455 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1456 " \"amount\" : x.xxx (numeric) The amount in btc\n"
1457 " }\n"
1458 " ,...\n"
3a1c20b7
WL
1459 " ],\n"
1460 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 1461 "}\n"
1462
1463 "\nbExamples\n"
1464 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1465 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1466 );
e3bc5698
JG
1467
1468 uint256 hash;
1469 hash.SetHex(params[0].get_str());
1470
1471 Object entry;
1472 if (!pwalletMain->mapWallet.count(hash))
738835d7 1473 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
1474 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1475
51ed9ec9
BD
1476 int64_t nCredit = wtx.GetCredit();
1477 int64_t nDebit = wtx.GetDebit();
1478 int64_t nNet = nCredit - nDebit;
0733c1bd 1479 int64_t nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
1480
1481 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1482 if (wtx.IsFromMe())
1483 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1484
1485 WalletTxToJSON(wtx, entry);
1486
1487 Array details;
1488 ListTransactions(wtx, "*", 0, false, details);
1489 entry.push_back(Pair("details", details));
1490
3a1c20b7
WL
1491 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1492 ssTx << wtx;
1493 string strHex = HexStr(ssTx.begin(), ssTx.end());
1494 entry.push_back(Pair("hex", strHex));
1495
e3bc5698
JG
1496 return entry;
1497}
1498
1499
1500Value backupwallet(const Array& params, bool fHelp)
1501{
1502 if (fHelp || params.size() != 1)
1503 throw runtime_error(
a6099ef3 1504 "backupwallet \"destination\"\n"
1505 "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
1506 "\nArguments:\n"
1507 "1. \"destination\" (string) The destination directory or file\n"
1508 "\nExamples:\n"
1509 + HelpExampleCli("backupwallet", "\"backup.dat\"")
1510 + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1511 );
e3bc5698
JG
1512
1513 string strDest = params[0].get_str();
ad525e9c
PK
1514 if (!BackupWallet(*pwalletMain, strDest))
1515 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698
JG
1516
1517 return Value::null;
1518}
1519
1520
1521Value keypoolrefill(const Array& params, bool fHelp)
1522{
36bd46f1 1523 if (fHelp || params.size() > 1)
e3bc5698 1524 throw runtime_error(
a6099ef3 1525 "keypoolrefill ( newsize )\n"
1526 "\nFills the keypool."
1527 + HelpRequiringPassphrase() + "\n"
1528 "\nArguments\n"
1529 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1530 "\nExamples:\n"
1531 + HelpExampleCli("keypoolrefill", "")
1532 + HelpExampleRpc("keypoolrefill", "")
1533 );
e3bc5698 1534
f914c7a1
PK
1535 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1536 unsigned int kpSize = 0;
36bd46f1
JG
1537 if (params.size() > 0) {
1538 if (params[0].get_int() < 0)
f914c7a1
PK
1539 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1540 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
1541 }
1542
e3bc5698 1543 EnsureWalletIsUnlocked();
36bd46f1 1544 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 1545
36bd46f1 1546 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 1547 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698
JG
1548
1549 return Value::null;
1550}
1551
1552
92f2c1fe 1553static void LockWallet(CWallet* pWallet)
e3bc5698 1554{
92f2c1fe
GA
1555 LOCK(cs_nWalletUnlockTime);
1556 nWalletUnlockTime = 0;
1557 pWallet->Lock();
e3bc5698
JG
1558}
1559
1560Value walletpassphrase(const Array& params, bool fHelp)
1561{
1562 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1563 throw runtime_error(
a6099ef3 1564 "walletpassphrase \"passphrase\" timeout\n"
1565 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1566 "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
1567 "\nArguments:\n"
1568 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1569 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
1570 "\nExamples:\n"
1571 "\nunlock the wallet for 60 seconds\n"
1572 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1573 "\nLock the wallet again (before 60 seconds)\n"
1574 + HelpExampleCli("walletlock", "") +
1575 "\nAs json rpc call\n"
1576 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1577 );
1578
e3bc5698
JG
1579 if (fHelp)
1580 return true;
1581 if (!pwalletMain->IsCrypted())
738835d7 1582 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 1583
e3bc5698
JG
1584 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1585 SecureString strWalletPass;
1586 strWalletPass.reserve(100);
1587 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1588 // Alternately, find a way to make params[0] mlock()'d to begin with.
1589 strWalletPass = params[0].get_str().c_str();
1590
1591 if (strWalletPass.length() > 0)
1592 {
1593 if (!pwalletMain->Unlock(strWalletPass))
738835d7 1594 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1595 }
1596 else
1597 throw runtime_error(
1598 "walletpassphrase <passphrase> <timeout>\n"
1599 "Stores the wallet decryption key in memory for <timeout> seconds.");
1600
92f2c1fe
GA
1601 pwalletMain->TopUpKeyPool();
1602
51ed9ec9 1603 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
1604 LOCK(cs_nWalletUnlockTime);
1605 nWalletUnlockTime = GetTime() + nSleepTime;
1606 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698
JG
1607
1608 return Value::null;
1609}
1610
1611
1612Value walletpassphrasechange(const Array& params, bool fHelp)
1613{
1614 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1615 throw runtime_error(
a6099ef3 1616 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1617 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1618 "\nArguments:\n"
1619 "1. \"oldpassphrase\" (string) The current passphrase\n"
1620 "2. \"newpassphrase\" (string) The new passphrase\n"
1621 "\nExamples:\n"
1622 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1623 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1624 );
1625
e3bc5698
JG
1626 if (fHelp)
1627 return true;
1628 if (!pwalletMain->IsCrypted())
738835d7 1629 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
1630
1631 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1632 // Alternately, find a way to make params[0] mlock()'d to begin with.
1633 SecureString strOldWalletPass;
1634 strOldWalletPass.reserve(100);
1635 strOldWalletPass = params[0].get_str().c_str();
1636
1637 SecureString strNewWalletPass;
1638 strNewWalletPass.reserve(100);
1639 strNewWalletPass = params[1].get_str().c_str();
1640
1641 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1642 throw runtime_error(
1643 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1644 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1645
1646 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 1647 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1648
1649 return Value::null;
1650}
1651
1652
1653Value walletlock(const Array& params, bool fHelp)
1654{
1655 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1656 throw runtime_error(
1657 "walletlock\n"
a6099ef3 1658 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 1659 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 1660 "before being able to call any methods which require the wallet to be unlocked.\n"
1661 "\nExamples:\n"
1662 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1663 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1664 "\nPerform a send (requires passphrase set)\n"
1665 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1666 "\nClear the passphrase since we are done before 2 minutes is up\n"
1667 + HelpExampleCli("walletlock", "") +
1668 "\nAs json rpc call\n"
1669 + HelpExampleRpc("walletlock", "")
1670 );
1671
e3bc5698
JG
1672 if (fHelp)
1673 return true;
1674 if (!pwalletMain->IsCrypted())
738835d7 1675 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
1676
1677 {
1678 LOCK(cs_nWalletUnlockTime);
1679 pwalletMain->Lock();
1680 nWalletUnlockTime = 0;
1681 }
1682
1683 return Value::null;
1684}
1685
1686
1687Value encryptwallet(const Array& params, bool fHelp)
1688{
1689 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1690 throw runtime_error(
a6099ef3 1691 "encryptwallet \"passphrase\"\n"
1692 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
1693 "After this, any calls that interact with private keys such as sending or signing \n"
1694 "will require the passphrase to be set prior the making these calls.\n"
1695 "Use the walletpassphrase call for this, and then walletlock call.\n"
1696 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
1697 "Note that this will shutdown the server.\n"
1698 "\nArguments:\n"
1699 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
1700 "\nExamples:\n"
1701 "\nEncrypt you wallet\n"
1702 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
1703 "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
1704 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
1705 "\nNow we can so something like sign\n"
1706 + HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
1707 "\nNow lock the wallet again by removing the passphrase\n"
1708 + HelpExampleCli("walletlock", "") +
1709 "\nAs a json rpc call\n"
1710 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
1711 );
1712
e3bc5698
JG
1713 if (fHelp)
1714 return true;
1715 if (pwalletMain->IsCrypted())
738835d7 1716 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
1717
1718 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1719 // Alternately, find a way to make params[0] mlock()'d to begin with.
1720 SecureString strWalletPass;
1721 strWalletPass.reserve(100);
1722 strWalletPass = params[0].get_str().c_str();
1723
1724 if (strWalletPass.length() < 1)
1725 throw runtime_error(
1726 "encryptwallet <passphrase>\n"
1727 "Encrypts the wallet with <passphrase>.");
1728
1729 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 1730 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
1731
1732 // BDB seems to have a bad habit of writing old data into
1733 // slack space in .dat files; that is bad if the old data is
331544bc 1734 // unencrypted private keys. So:
e3bc5698 1735 StartShutdown();
6b3783a9 1736 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
1737}
1738
fdbb537d
JG
1739Value lockunspent(const Array& params, bool fHelp)
1740{
1741 if (fHelp || params.size() < 1 || params.size() > 2)
1742 throw runtime_error(
a6099ef3 1743 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
1744 "\nUpdates list of temporarily unspendable outputs.\n"
1745 "Temporarily lock (lock=true) or unlock (lock=false) specified transaction outputs.\n"
1746 "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
1747 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
1748 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
1749 "Also see the listunspent call\n"
1750 "\nArguments:\n"
1751 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
1752 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
1753 " [ (json array of json objects)\n"
1754 " {\n"
1755 " \"txid\":\"id\", (string) The transaction id\n"
1756 " \"vout\": n (numeric) The output number\n"
1757 " }\n"
1758 " ,...\n"
1759 " ]\n"
1760
1761 "\nResult:\n"
1762 "true|false (boolean) Whether the command was successful or not\n"
1763
1764 "\nExamples:\n"
1765 "\nList the unspent transactions\n"
1766 + HelpExampleCli("listunspent", "") +
1767 "\nLock an unspent transaction\n"
1768 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1769 "\nList the locked transactions\n"
1770 + HelpExampleCli("listlockunspent", "") +
1771 "\nUnlock the transaction again\n"
1772 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1773 "\nAs a json rpc call\n"
1774 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
1775 );
fdbb537d
JG
1776
1777 if (params.size() == 1)
1778 RPCTypeCheck(params, list_of(bool_type));
1779 else
1780 RPCTypeCheck(params, list_of(bool_type)(array_type));
1781
1782 bool fUnlock = params[0].get_bool();
1783
1784 if (params.size() == 1) {
1785 if (fUnlock)
1786 pwalletMain->UnlockAllCoins();
1787 return true;
1788 }
1789
1790 Array outputs = params[1].get_array();
1791 BOOST_FOREACH(Value& output, outputs)
1792 {
1793 if (output.type() != obj_type)
15117692 1794 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fdbb537d
JG
1795 const Object& o = output.get_obj();
1796
1797 RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type));
1798
1799 string txid = find_value(o, "txid").get_str();
1800 if (!IsHex(txid))
15117692 1801 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
1802
1803 int nOutput = find_value(o, "vout").get_int();
1804 if (nOutput < 0)
15117692 1805 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d
JG
1806
1807 COutPoint outpt(uint256(txid), nOutput);
1808
1809 if (fUnlock)
1810 pwalletMain->UnlockCoin(outpt);
1811 else
1812 pwalletMain->LockCoin(outpt);
1813 }
1814
1815 return true;
1816}
1817
1818Value listlockunspent(const Array& params, bool fHelp)
1819{
1820 if (fHelp || params.size() > 0)
1821 throw runtime_error(
1822 "listlockunspent\n"
a6099ef3 1823 "\nReturns list of temporarily unspendable outputs.\n"
1824 "See the lockunspent call to lock and unlock transactions for spending.\n"
1825 "\nResult:\n"
1826 "[\n"
1827 " {\n"
1828 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
1829 " \"vout\" : n (numeric) The vout value\n"
1830 " }\n"
1831 " ,...\n"
1832 "]\n"
1833 "\nExamples:\n"
1834 "\nList the unspent transactions\n"
1835 + HelpExampleCli("listunspent", "") +
1836 "\nLock an unspent transaction\n"
1837 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1838 "\nList the locked transactions\n"
1839 + HelpExampleCli("listlockunspent", "") +
1840 "\nUnlock the transaction again\n"
1841 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
1842 "\nAs a json rpc call\n"
1843 + HelpExampleRpc("listlockunspent", "")
1844 );
fdbb537d
JG
1845
1846 vector<COutPoint> vOutpts;
1847 pwalletMain->ListLockedCoins(vOutpts);
1848
1849 Array ret;
1850
1851 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
1852 Object o;
1853
1854 o.push_back(Pair("txid", outpt.hash.GetHex()));
1855 o.push_back(Pair("vout", (int)outpt.n));
1856 ret.push_back(o);
1857 }
1858
1859 return ret;
1860}
1861
a943bde6
WL
1862Value settxfee(const Array& params, bool fHelp)
1863{
1864 if (fHelp || params.size() < 1 || params.size() > 1)
1865 throw runtime_error(
1866 "settxfee amount\n"
6943cb9b 1867 "\nSet the transaction fee per kB.\n"
a943bde6 1868 "\nArguments:\n"
6943cb9b 1869 "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
1870 "\nResult\n"
1871 "true|false (boolean) Returns true if successful\n"
1872 "\nExamples:\n"
1873 + HelpExampleCli("settxfee", "0.00001")
1874 + HelpExampleRpc("settxfee", "0.00001")
1875 );
1876
1877 // Amount
1878 int64_t nAmount = 0;
1879 if (params[0].get_real() != 0.0)
1880 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
1881
1882 nTransactionFee = nAmount;
1883 return true;
1884}
1885
1886
This page took 0.364777 seconds and 4 git commands to generate.