Merge pull request #404 from TheBlueMatt/newenc
[VerusCoin.git] / src / rpc.cpp
CommitLineData
0a61b0df 1// Copyright (c) 2010 Satoshi Nakamoto
2// Distributed under the MIT/X11 software license, see the accompanying
3// file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5#include "headers.h"
776d0f34 6#include "cryptopp/sha.h"
1512d5ce 7#include "db.h"
40c2614e 8#include "net.h"
edd309e5 9#include "init.h"
0a61b0df 10#undef printf
11#include <boost/asio.hpp>
ed54768f 12#include <boost/iostreams/concepts.hpp>
13#include <boost/iostreams/stream.hpp>
31f29312 14#include <boost/algorithm/string.hpp>
ed54768f 15#ifdef USE_SSL
16#include <boost/asio/ssl.hpp>
926e14b3 17#include <boost/filesystem.hpp>
31f29312 18#include <boost/filesystem/fstream.hpp>
ed54768f 19typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
20#endif
0a61b0df 21#include "json/json_spirit_reader_template.h"
22#include "json/json_spirit_writer_template.h"
23#include "json/json_spirit_utils.h"
24#define printf OutputDebugStringF
25// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26// precompiled in headers.h. The problem might be when the pch file goes over
27// a certain size around 145MB. If we need access to json_spirit outside this
28// file, we could use the compiled json_spirit option.
29
223b6f1b
WL
30using namespace std;
31using namespace boost;
ed54768f 32using namespace boost::asio;
0a61b0df 33using namespace json_spirit;
34
35void ThreadRPCServer2(void* parg);
36typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37extern map<string, rpcfn_type> mapCallTable;
38
98545d2c
MC
39static int64 nWalletUnlockTime;
40static CCriticalSection cs_nWalletUnlockTime;
41
0a61b0df 42
d743f035 43Object JSONRPCError(int code, const string& message)
44{
45 Object error;
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
48 return error;
49}
50
0a61b0df 51
52void PrintConsole(const char* format, ...)
53{
54 char buffer[50000];
55 int limit = sizeof(buffer);
56 va_list arg_ptr;
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
59 va_end(arg_ptr);
60 if (ret < 0 || ret >= limit)
61 {
62 ret = limit - 1;
63 buffer[limit-1] = 0;
64 }
776d0f34 65 printf("%s", buffer);
0a61b0df 66#if defined(__WXMSW__) && defined(GUI)
67 MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
68#else
69 fprintf(stdout, "%s", buffer);
70#endif
71}
72
73
e4ff4e68 74int64 AmountFromValue(const Value& value)
75{
76 double dAmount = value.get_real();
77 if (dAmount <= 0.0 || dAmount > 21000000.0)
78 throw JSONRPCError(-3, "Invalid amount");
789259d2 79 int64 nAmount = roundint64(dAmount * COIN);
e4ff4e68 80 if (!MoneyRange(nAmount))
81 throw JSONRPCError(-3, "Invalid amount");
82 return nAmount;
83}
84
bfd471f5 85Value ValueFromAmount(int64 amount)
86{
87 return (double)amount / (double)COIN;
88}
89
90void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
91{
92 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
93 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
1c0bf23b 94 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
223b6f1b 95 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
bfd471f5 96 entry.push_back(Pair(item.first, item.second));
97}
0a61b0df 98
809ee795 99string AccountFromValue(const Value& value)
100{
101 string strAccount = value.get_str();
102 if (strAccount == "*")
103 throw JSONRPCError(-11, "Invalid account name");
104 return strAccount;
105}
0a61b0df 106
107
108
109///
110/// Note: This interface may still be subject to change.
111///
112
113
114Value help(const Array& params, bool fHelp)
115{
116 if (fHelp || params.size() > 1)
117 throw runtime_error(
118 "help [command]\n"
119 "List commands, or get help for a command.");
120
121 string strCommand;
122 if (params.size() > 0)
123 strCommand = params[0].get_str();
124
125 string strRet;
126 set<rpcfn_type> setDone;
127 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
128 {
129 string strMethod = (*mi).first;
130 // We already filter duplicates, but these deprecated screw up the sort order
131 if (strMethod == "getamountreceived" ||
e4ff4e68 132 strMethod == "getallreceived" ||
133 (strMethod.find("label") != string::npos))
0a61b0df 134 continue;
135 if (strCommand != "" && strMethod != strCommand)
136 continue;
137 try
138 {
139 Array params;
140 rpcfn_type pfn = (*mi).second;
141 if (setDone.insert(pfn).second)
142 (*pfn)(params, true);
143 }
144 catch (std::exception& e)
145 {
146 // Help text is returned in an exception
147 string strHelp = string(e.what());
148 if (strCommand == "")
149 if (strHelp.find('\n') != -1)
150 strHelp = strHelp.substr(0, strHelp.find('\n'));
151 strRet += strHelp + "\n";
152 }
153 }
154 if (strRet == "")
155 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
156 strRet = strRet.substr(0,strRet.size()-1);
157 return strRet;
158}
159
160
161Value stop(const Array& params, bool fHelp)
162{
163 if (fHelp || params.size() != 0)
164 throw runtime_error(
165 "stop\n"
166 "Stop bitcoin server.");
167
168 // Shutdown will take long enough that the response should get back
169 CreateThread(Shutdown, NULL);
170 return "bitcoin server stopping";
171}
172
173
174Value getblockcount(const Array& params, bool fHelp)
175{
176 if (fHelp || params.size() != 0)
177 throw runtime_error(
178 "getblockcount\n"
179 "Returns the number of blocks in the longest block chain.");
180
181 return nBestHeight;
182}
183
184
185Value getblocknumber(const Array& params, bool fHelp)
186{
187 if (fHelp || params.size() != 0)
188 throw runtime_error(
189 "getblocknumber\n"
190 "Returns the block number of the latest block in the longest block chain.");
191
192 return nBestHeight;
193}
194
195
196Value getconnectioncount(const Array& params, bool fHelp)
197{
198 if (fHelp || params.size() != 0)
199 throw runtime_error(
200 "getconnectioncount\n"
201 "Returns the number of connections to other nodes.");
202
203 return (int)vNodes.size();
204}
205
206
207double GetDifficulty()
208{
209 // Floating point number that is a multiple of the minimum difficulty,
210 // minimum difficulty = 1.0.
5e1e458e 211
0a61b0df 212 if (pindexBest == NULL)
213 return 1.0;
5e1e458e
PW
214 int nShift = (pindexBest->nBits >> 24) & 0xff;
215
216 double dDiff =
217 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
218
219 while (nShift < 29)
220 {
221 dDiff *= 256.0;
222 nShift++;
223 }
224 while (nShift > 29)
225 {
226 dDiff /= 256.0;
227 nShift--;
228 }
229
230 return dDiff;
0a61b0df 231}
232
233Value getdifficulty(const Array& params, bool fHelp)
234{
235 if (fHelp || params.size() != 0)
236 throw runtime_error(
237 "getdifficulty\n"
238 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
239
240 return GetDifficulty();
241}
242
243
0a61b0df 244Value getgenerate(const Array& params, bool fHelp)
245{
246 if (fHelp || params.size() != 0)
247 throw runtime_error(
248 "getgenerate\n"
249 "Returns true or false.");
250
251 return (bool)fGenerateBitcoins;
252}
253
254
255Value setgenerate(const Array& params, bool fHelp)
256{
257 if (fHelp || params.size() < 1 || params.size() > 2)
258 throw runtime_error(
259 "setgenerate <generate> [genproclimit]\n"
260 "<generate> is true or false to turn generation on or off.\n"
261 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
262
263 bool fGenerate = true;
264 if (params.size() > 0)
265 fGenerate = params[0].get_bool();
266
267 if (params.size() > 1)
268 {
269 int nGenProcLimit = params[1].get_int();
270 fLimitProcessors = (nGenProcLimit != -1);
64c7ee7e 271 WriteSetting("fLimitProcessors", fLimitProcessors);
0a61b0df 272 if (nGenProcLimit != -1)
64c7ee7e 273 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
59948a6e 274 if (nGenProcLimit == 0)
275 fGenerate = false;
0a61b0df 276 }
277
64c7ee7e 278 GenerateBitcoins(fGenerate, pwalletMain);
0a61b0df 279 return Value::null;
280}
281
282
283Value gethashespersec(const Array& params, bool fHelp)
284{
285 if (fHelp || params.size() != 0)
286 throw runtime_error(
287 "gethashespersec\n"
288 "Returns a recent hashes per second performance measurement while generating.");
289
290 if (GetTimeMillis() - nHPSTimerStart > 8000)
291 return (boost::int64_t)0;
292 return (boost::int64_t)dHashesPerSec;
293}
294
295
296Value getinfo(const Array& params, bool fHelp)
297{
298 if (fHelp || params.size() != 0)
299 throw runtime_error(
300 "getinfo\n"
301 "Returns an object containing various state info.");
302
303 Object obj;
304 obj.push_back(Pair("version", (int)VERSION));
64c7ee7e 305 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
0a61b0df 306 obj.push_back(Pair("blocks", (int)nBestHeight));
307 obj.push_back(Pair("connections", (int)vNodes.size()));
308 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
309 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
310 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
311 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
312 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
c285051c 313 obj.push_back(Pair("testnet", fTestNet));
64c7ee7e 314 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
4e87d341 315 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
83b9f427 316 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
98545d2c
MC
317 if (pwalletMain->IsCrypted())
318 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
0a61b0df 319 obj.push_back(Pair("errors", GetWarnings("statusbar")));
320 return obj;
321}
322
323
324Value getnewaddress(const Array& params, bool fHelp)
325{
326 if (fHelp || params.size() > 1)
327 throw runtime_error(
e4ff4e68 328 "getnewaddress [account]\n"
0a61b0df 329 "Returns a new bitcoin address for receiving payments. "
e4ff4e68 330 "If [account] is specified (recommended), it is added to the address book "
331 "so payments received with the address will be credited to [account].");
0a61b0df 332
4e87d341
MC
333 if (!pwalletMain->IsLocked())
334 pwalletMain->TopUpKeyPool();
335
336 if (pwalletMain->GetKeyPoolSize() < 1)
337 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
338
e4ff4e68 339 // Parse the account first so we don't generate a key if there's an error
340 string strAccount;
0a61b0df 341 if (params.size() > 0)
809ee795 342 strAccount = AccountFromValue(params[0]);
0a61b0df 343
344 // Generate a new key that is added to wallet
4e87d341 345 string strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
0a61b0df 346
4d410cfc
SG
347 // This could be done in the same main CS as GetKeyFromKeyPool.
348 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
349 pwalletMain->SetAddressBookName(strAddress, strAccount);
350
0a61b0df 351 return strAddress;
352}
353
354
4d410cfc 355// requires cs_main, cs_mapWallet, cs_mapAddressBook locks
fa446a56 356string GetAccountAddress(string strAccount, bool bForceNew=false)
e4ff4e68 357{
fa446a56 358 string strAddress;
e4ff4e68 359
64c7ee7e 360 CWalletDB walletdb(pwalletMain->strWalletFile);
e4ff4e68 361
f5f1878b 362 CAccount account;
4e87d341 363 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
f5f1878b 364 {
4e87d341
MC
365 walletdb.ReadAccount(strAccount, account);
366
367 bool bKeyUsed = false;
368
369 // Check if the current key has been used
370 if (!account.vchPubKey.empty())
e4ff4e68 371 {
4e87d341
MC
372 CScript scriptPubKey;
373 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
374 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
375 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
376 ++it)
377 {
378 const CWalletTx& wtx = (*it).second;
379 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
380 if (txout.scriptPubKey == scriptPubKey)
381 bKeyUsed = true;
382 }
e4ff4e68 383 }
384
4e87d341
MC
385 // Generate a new key
386 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
387 {
388 if (pwalletMain->GetKeyPoolSize() < 1)
389 {
390 if (bKeyUsed || bForceNew)
391 throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first");
392 }
393 else
394 {
395 account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool();
396 string strAddress = PubKeyToAddress(account.vchPubKey);
397 pwalletMain->SetAddressBookName(strAddress, strAccount);
398 walletdb.WriteAccount(strAccount, account);
399 }
400 }
e4ff4e68 401 }
f5f1878b 402
f5f1878b
JG
403 strAddress = PubKeyToAddress(account.vchPubKey);
404
fa446a56
GA
405 return strAddress;
406}
407
408Value getaccountaddress(const Array& params, bool fHelp)
409{
410 if (fHelp || params.size() != 1)
411 throw runtime_error(
412 "getaccountaddress <account>\n"
413 "Returns the current bitcoin address for receiving payments to this account.");
414
415 // Parse the account first so we don't generate a key if there's an error
416 string strAccount = AccountFromValue(params[0]);
417
f5f1878b
JG
418 Value ret;
419
420 CRITICAL_BLOCK(cs_main)
64c7ee7e 421 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
4d410cfc 422 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
f5f1878b
JG
423 {
424 ret = GetAccountAddress(strAccount);
425 }
426
427 return ret;
e4ff4e68 428}
429
430
fa446a56 431
e4ff4e68 432Value setaccount(const Array& params, bool fHelp)
0a61b0df 433{
434 if (fHelp || params.size() < 1 || params.size() > 2)
435 throw runtime_error(
e4ff4e68 436 "setaccount <bitcoinaddress> <account>\n"
437 "Sets the account associated with the given address.");
0a61b0df 438
439 string strAddress = params[0].get_str();
279ab5e6
MC
440 uint160 hash160;
441 bool isValid = AddressToHash160(strAddress, hash160);
442 if (!isValid)
c1f74f15 443 throw JSONRPCError(-5, "Invalid bitcoin address");
279ab5e6
MC
444
445
e4ff4e68 446 string strAccount;
0a61b0df 447 if (params.size() > 1)
809ee795 448 strAccount = AccountFromValue(params[1]);
0a61b0df 449
fa446a56 450 // Detect when changing the account of an address that is the 'unused current key' of another account:
f5f1878b 451 CRITICAL_BLOCK(cs_main)
64c7ee7e
PW
452 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
453 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
fa446a56 454 {
64c7ee7e 455 if (pwalletMain->mapAddressBook.count(strAddress))
fa446a56 456 {
64c7ee7e 457 string strOldAccount = pwalletMain->mapAddressBook[strAddress];
fa446a56
GA
458 if (strAddress == GetAccountAddress(strOldAccount))
459 GetAccountAddress(strOldAccount, true);
460 }
4d410cfc
SG
461
462 pwalletMain->SetAddressBookName(strAddress, strAccount);
fa446a56
GA
463 }
464
0a61b0df 465 return Value::null;
466}
467
468
e4ff4e68 469Value getaccount(const Array& params, bool fHelp)
0a61b0df 470{
471 if (fHelp || params.size() != 1)
472 throw runtime_error(
e4ff4e68 473 "getaccount <bitcoinaddress>\n"
474 "Returns the account associated with the given address.");
0a61b0df 475
476 string strAddress = params[0].get_str();
477
e4ff4e68 478 string strAccount;
64c7ee7e 479 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
0a61b0df 480 {
64c7ee7e
PW
481 map<string, string>::iterator mi = pwalletMain->mapAddressBook.find(strAddress);
482 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
e4ff4e68 483 strAccount = (*mi).second;
0a61b0df 484 }
e4ff4e68 485 return strAccount;
0a61b0df 486}
487
488
e4ff4e68 489Value getaddressesbyaccount(const Array& params, bool fHelp)
0a61b0df 490{
491 if (fHelp || params.size() != 1)
492 throw runtime_error(
e4ff4e68 493 "getaddressesbyaccount <account>\n"
494 "Returns the list of addresses for the given account.");
0a61b0df 495
809ee795 496 string strAccount = AccountFromValue(params[0]);
0a61b0df 497
e4ff4e68 498 // Find all addresses that have the given account
0a61b0df 499 Array ret;
64c7ee7e 500 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
0a61b0df 501 {
64c7ee7e 502 BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook)
0a61b0df 503 {
504 const string& strAddress = item.first;
505 const string& strName = item.second;
e4ff4e68 506 if (strName == strAccount)
0a61b0df 507 {
508 // We're only adding valid bitcoin addresses and not ip addresses
509 CScript scriptPubKey;
510 if (scriptPubKey.SetBitcoinAddress(strAddress))
511 ret.push_back(strAddress);
512 }
513 }
514 }
515 return ret;
516}
517
d9068ad5
JG
518Value settxfee(const Array& params, bool fHelp)
519{
520 if (fHelp || params.size() < 1 || params.size() > 1)
521 throw runtime_error(
522 "settxfee <amount>\n"
523 "<amount> is a real and is rounded to the nearest 0.00000001");
524
525 // Amount
526 int64 nAmount = 0;
527 if (params[0].get_real() != 0.0)
528 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
529
530 nTransactionFee = nAmount;
531 return true;
532}
533
0a61b0df 534Value sendtoaddress(const Array& params, bool fHelp)
535{
4e87d341
MC
536 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
537 throw runtime_error(
538 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
539 "<amount> is a real and is rounded to the nearest 0.00000001\n"
540 "requires wallet passphrase to be set with walletpassphrase first");
541 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0a61b0df 542 throw runtime_error(
543 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
e8adcf88 544 "<amount> is a real and is rounded to the nearest 0.00000001");
0a61b0df 545
546 string strAddress = params[0].get_str();
547
548 // Amount
e4ff4e68 549 int64 nAmount = AmountFromValue(params[1]);
0a61b0df 550
551 // Wallet comments
552 CWalletTx wtx;
553 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
809ee795 554 wtx.mapValue["comment"] = params[2].get_str();
0a61b0df 555 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
556 wtx.mapValue["to"] = params[3].get_str();
557
f5f1878b 558 CRITICAL_BLOCK(cs_main)
4e87d341 559 CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
f5f1878b 560 {
4e87d341
MC
561 if(pwalletMain->IsLocked())
562 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
563
64c7ee7e 564 string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
f5f1878b
JG
565 if (strError != "")
566 throw JSONRPCError(-4, strError);
567 }
568
e4ff4e68 569 return wtx.GetHash().GetHex();
0a61b0df 570}
571
572
0a61b0df 573Value getreceivedbyaddress(const Array& params, bool fHelp)
574{
575 if (fHelp || params.size() < 1 || params.size() > 2)
576 throw runtime_error(
577 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
578 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
579
580 // Bitcoin address
581 string strAddress = params[0].get_str();
582 CScript scriptPubKey;
583 if (!scriptPubKey.SetBitcoinAddress(strAddress))
d743f035 584 throw JSONRPCError(-5, "Invalid bitcoin address");
64c7ee7e 585 if (!IsMine(*pwalletMain,scriptPubKey))
0a61b0df 586 return (double)0.0;
587
588 // Minimum confirmations
589 int nMinDepth = 1;
590 if (params.size() > 1)
591 nMinDepth = params[1].get_int();
592
593 // Tally
594 int64 nAmount = 0;
64c7ee7e 595 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
0a61b0df 596 {
64c7ee7e 597 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0a61b0df 598 {
599 const CWalletTx& wtx = (*it).second;
600 if (wtx.IsCoinBase() || !wtx.IsFinal())
601 continue;
602
223b6f1b 603 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0a61b0df 604 if (txout.scriptPubKey == scriptPubKey)
605 if (wtx.GetDepthInMainChain() >= nMinDepth)
606 nAmount += txout.nValue;
607 }
608 }
609
83b9f427 610 return ValueFromAmount(nAmount);
0a61b0df 611}
612
613
bfd471f5 614void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey)
0a61b0df 615{
64c7ee7e 616 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
0a61b0df 617 {
64c7ee7e 618 BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook)
0a61b0df 619 {
620 const string& strAddress = item.first;
621 const string& strName = item.second;
e4ff4e68 622 if (strName == strAccount)
0a61b0df 623 {
624 // We're only counting our own valid bitcoin addresses and not ip addresses
625 CScript scriptPubKey;
626 if (scriptPubKey.SetBitcoinAddress(strAddress))
64c7ee7e 627 if (IsMine(*pwalletMain,scriptPubKey))
0a61b0df 628 setPubKey.insert(scriptPubKey);
629 }
630 }
631 }
bfd471f5 632}
633
634
635Value getreceivedbyaccount(const Array& params, bool fHelp)
636{
637 if (fHelp || params.size() < 1 || params.size() > 2)
638 throw runtime_error(
639 "getreceivedbyaccount <account> [minconf=1]\n"
640 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
641
642 // Minimum confirmations
643 int nMinDepth = 1;
644 if (params.size() > 1)
645 nMinDepth = params[1].get_int();
646
647 // Get the set of pub keys that have the label
809ee795 648 string strAccount = AccountFromValue(params[0]);
bfd471f5 649 set<CScript> setPubKey;
650 GetAccountPubKeys(strAccount, setPubKey);
0a61b0df 651
0a61b0df 652 // Tally
653 int64 nAmount = 0;
64c7ee7e 654 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
0a61b0df 655 {
64c7ee7e 656 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0a61b0df 657 {
658 const CWalletTx& wtx = (*it).second;
659 if (wtx.IsCoinBase() || !wtx.IsFinal())
660 continue;
661
223b6f1b 662 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0a61b0df 663 if (setPubKey.count(txout.scriptPubKey))
664 if (wtx.GetDepthInMainChain() >= nMinDepth)
665 nAmount += txout.nValue;
666 }
667 }
668
669 return (double)nAmount / (double)COIN;
670}
671
672
e4ff4e68 673int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
674{
e4ff4e68 675 int64 nBalance = 0;
64c7ee7e 676 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
e4ff4e68 677 {
678 // Tally wallet transactions
64c7ee7e 679 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
e4ff4e68 680 {
681 const CWalletTx& wtx = (*it).second;
682 if (!wtx.IsFinal())
683 continue;
684
bfd471f5 685 int64 nGenerated, nReceived, nSent, nFee;
809ee795 686 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
e4ff4e68 687
bfd471f5 688 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
689 nBalance += nReceived;
690 nBalance += nGenerated - nSent - nFee;
e4ff4e68 691 }
692
693 // Tally internal accounting entries
694 nBalance += walletdb.GetAccountCreditDebit(strAccount);
695 }
696
697 return nBalance;
698}
699
700int64 GetAccountBalance(const string& strAccount, int nMinDepth)
701{
64c7ee7e 702 CWalletDB walletdb(pwalletMain->strWalletFile);
e4ff4e68 703 return GetAccountBalance(walletdb, strAccount, nMinDepth);
704}
705
706
707Value getbalance(const Array& params, bool fHelp)
708{
d7f1d200 709 if (fHelp || params.size() > 2)
e4ff4e68 710 throw runtime_error(
711 "getbalance [account] [minconf=1]\n"
712 "If [account] is not specified, returns the server's total available balance.\n"
713 "If [account] is specified, returns the balance in the account.");
714
715 if (params.size() == 0)
64c7ee7e 716 return ValueFromAmount(pwalletMain->GetBalance());
e4ff4e68 717
72e962cf
GA
718 int nMinDepth = 1;
719 if (params.size() > 1)
720 nMinDepth = params[1].get_int();
721
1d23c743
GA
722 if (params[0].get_str() == "*") {
723 // Calculate total balance a different way from GetBalance()
724 // (GetBalance() sums up all unspent TxOuts)
725 // getbalance and getbalance '*' should always return the same number.
726 int64 nBalance = 0;
64c7ee7e 727 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1d23c743
GA
728 {
729 const CWalletTx& wtx = (*it).second;
72e962cf
GA
730 if (!wtx.IsFinal())
731 continue;
732
198fd7b0
GA
733 int64 allGeneratedImmature, allGeneratedMature, allFee;
734 allGeneratedImmature = allGeneratedMature = allFee = 0;
1d23c743
GA
735 string strSentAccount;
736 list<pair<string, int64> > listReceived;
737 list<pair<string, int64> > listSent;
198fd7b0 738 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
72e962cf 739 if (wtx.GetDepthInMainChain() >= nMinDepth)
223b6f1b 740 BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
72e962cf 741 nBalance += r.second;
223b6f1b 742 BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listSent)
1d23c743
GA
743 nBalance -= r.second;
744 nBalance -= allFee;
198fd7b0 745 nBalance += allGeneratedMature;
1d23c743 746 }
83b9f427 747 return ValueFromAmount(nBalance);
1d23c743
GA
748 }
749
809ee795 750 string strAccount = AccountFromValue(params[0]);
e4ff4e68 751
752 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
753
83b9f427 754 return ValueFromAmount(nBalance);
e4ff4e68 755}
756
757
758Value movecmd(const Array& params, bool fHelp)
759{
760 if (fHelp || params.size() < 3 || params.size() > 5)
761 throw runtime_error(
762 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
763 "Move from one account in your wallet to another.");
764
809ee795 765 string strFrom = AccountFromValue(params[0]);
766 string strTo = AccountFromValue(params[1]);
e4ff4e68 767 int64 nAmount = AmountFromValue(params[2]);
768 int nMinDepth = 1;
769 if (params.size() > 3)
770 nMinDepth = params[3].get_int();
771 string strComment;
772 if (params.size() > 4)
773 strComment = params[4].get_str();
774
64c7ee7e 775 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
e4ff4e68 776 {
64c7ee7e 777 CWalletDB walletdb(pwalletMain->strWalletFile);
e4ff4e68 778 walletdb.TxnBegin();
779
e4ff4e68 780 int64 nNow = GetAdjustedTime();
781
782 // Debit
783 CAccountingEntry debit;
809ee795 784 debit.strAccount = strFrom;
e4ff4e68 785 debit.nCreditDebit = -nAmount;
786 debit.nTime = nNow;
787 debit.strOtherAccount = strTo;
788 debit.strComment = strComment;
809ee795 789 walletdb.WriteAccountingEntry(debit);
e4ff4e68 790
791 // Credit
792 CAccountingEntry credit;
809ee795 793 credit.strAccount = strTo;
e4ff4e68 794 credit.nCreditDebit = nAmount;
795 credit.nTime = nNow;
796 credit.strOtherAccount = strFrom;
797 credit.strComment = strComment;
809ee795 798 walletdb.WriteAccountingEntry(credit);
e4ff4e68 799
800 walletdb.TxnCommit();
801 }
802 return true;
803}
804
805
806Value sendfrom(const Array& params, bool fHelp)
807{
4e87d341
MC
808 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
809 throw runtime_error(
810 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
811 "<amount> is a real and is rounded to the nearest 0.00000001\n"
812 "requires wallet passphrase to be set with walletpassphrase first");
813 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
e4ff4e68 814 throw runtime_error(
815 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
e8adcf88 816 "<amount> is a real and is rounded to the nearest 0.00000001");
e4ff4e68 817
809ee795 818 string strAccount = AccountFromValue(params[0]);
e4ff4e68 819 string strAddress = params[1].get_str();
820 int64 nAmount = AmountFromValue(params[2]);
821 int nMinDepth = 1;
822 if (params.size() > 3)
823 nMinDepth = params[3].get_int();
824
825 CWalletTx wtx;
826 wtx.strFromAccount = strAccount;
827 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
809ee795 828 wtx.mapValue["comment"] = params[4].get_str();
e4ff4e68 829 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
830 wtx.mapValue["to"] = params[5].get_str();
831
f5f1878b 832 CRITICAL_BLOCK(cs_main)
64c7ee7e 833 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
4e87d341 834 CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
e4ff4e68 835 {
4e87d341
MC
836 if(pwalletMain->IsLocked())
837 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
838
e4ff4e68 839 // Check funds
840 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
841 if (nAmount > nBalance)
842 throw JSONRPCError(-6, "Account has insufficient funds");
843
844 // Send
64c7ee7e 845 string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
e4ff4e68 846 if (strError != "")
847 throw JSONRPCError(-4, strError);
848 }
849
850 return wtx.GetHash().GetHex();
851}
852
4e87d341 853
b931ed85
GA
854Value sendmany(const Array& params, bool fHelp)
855{
4e87d341
MC
856 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
857 throw runtime_error(
858 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
859 "amounts are double-precision floating point numbers\n"
860 "requires wallet passphrase to be set with walletpassphrase first");
861 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
b931ed85
GA
862 throw runtime_error(
863 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
864 "amounts are double-precision floating point numbers");
865
866 string strAccount = AccountFromValue(params[0]);
867 Object sendTo = params[1].get_obj();
868 int nMinDepth = 1;
869 if (params.size() > 2)
870 nMinDepth = params[2].get_int();
871
872 CWalletTx wtx;
873 wtx.strFromAccount = strAccount;
874 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
875 wtx.mapValue["comment"] = params[3].get_str();
876
877 set<string> setAddress;
878 vector<pair<CScript, int64> > vecSend;
879
880 int64 totalAmount = 0;
223b6f1b 881 BOOST_FOREACH(const Pair& s, sendTo)
b931ed85
GA
882 {
883 uint160 hash160;
884 string strAddress = s.name_;
885
886 if (setAddress.count(strAddress))
887 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+strAddress);
888 setAddress.insert(strAddress);
889
890 CScript scriptPubKey;
891 if (!scriptPubKey.SetBitcoinAddress(strAddress))
892 throw JSONRPCError(-5, string("Invalid bitcoin address:")+strAddress);
893 int64 nAmount = AmountFromValue(s.value_);
894 totalAmount += nAmount;
895
896 vecSend.push_back(make_pair(scriptPubKey, nAmount));
897 }
898
6f074b71 899 CRITICAL_BLOCK(cs_main)
64c7ee7e 900 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
4e87d341 901 CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
b931ed85 902 {
4e87d341
MC
903 if(pwalletMain->IsLocked())
904 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
905
b931ed85
GA
906 // Check funds
907 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
908 if (totalAmount > nBalance)
909 throw JSONRPCError(-6, "Account has insufficient funds");
910
911 // Send
64c7ee7e 912 CReserveKey keyChange(pwalletMain);
b931ed85 913 int64 nFeeRequired = 0;
64c7ee7e 914 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
b931ed85
GA
915 if (!fCreated)
916 {
64c7ee7e 917 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
b931ed85
GA
918 throw JSONRPCError(-6, "Insufficient funds");
919 throw JSONRPCError(-4, "Transaction creation failed");
920 }
64c7ee7e 921 if (!pwalletMain->CommitTransaction(wtx, keyChange))
b931ed85
GA
922 throw JSONRPCError(-4, "Transaction commit failed");
923 }
924
925 return wtx.GetHash().GetHex();
926}
e4ff4e68 927
0a61b0df 928
929struct tallyitem
930{
931 int64 nAmount;
932 int nConf;
933 tallyitem()
934 {
935 nAmount = 0;
936 nConf = INT_MAX;
937 }
938};
939
e4ff4e68 940Value ListReceived(const Array& params, bool fByAccounts)
0a61b0df 941{
942 // Minimum confirmations
943 int nMinDepth = 1;
944 if (params.size() > 0)
945 nMinDepth = params[0].get_int();
946
947 // Whether to include empty accounts
948 bool fIncludeEmpty = false;
949 if (params.size() > 1)
950 fIncludeEmpty = params[1].get_bool();
951
952 // Tally
953 map<uint160, tallyitem> mapTally;
64c7ee7e 954 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
0a61b0df 955 {
64c7ee7e 956 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0a61b0df 957 {
958 const CWalletTx& wtx = (*it).second;
959 if (wtx.IsCoinBase() || !wtx.IsFinal())
960 continue;
961
962 int nDepth = wtx.GetDepthInMainChain();
963 if (nDepth < nMinDepth)
964 continue;
965
223b6f1b 966 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0a61b0df 967 {
968 // Only counting our own bitcoin addresses and not ip addresses
969 uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
970 if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
971 continue;
972
973 tallyitem& item = mapTally[hash160];
974 item.nAmount += txout.nValue;
975 item.nConf = min(item.nConf, nDepth);
976 }
977 }
978 }
979
980 // Reply
981 Array ret;
e4ff4e68 982 map<string, tallyitem> mapAccountTally;
64c7ee7e 983 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
0a61b0df 984 {
64c7ee7e 985 BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook)
0a61b0df 986 {
987 const string& strAddress = item.first;
e4ff4e68 988 const string& strAccount = item.second;
0a61b0df 989 uint160 hash160;
990 if (!AddressToHash160(strAddress, hash160))
991 continue;
992 map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
993 if (it == mapTally.end() && !fIncludeEmpty)
994 continue;
995
996 int64 nAmount = 0;
997 int nConf = INT_MAX;
998 if (it != mapTally.end())
999 {
1000 nAmount = (*it).second.nAmount;
1001 nConf = (*it).second.nConf;
1002 }
1003
e4ff4e68 1004 if (fByAccounts)
0a61b0df 1005 {
e4ff4e68 1006 tallyitem& item = mapAccountTally[strAccount];
0a61b0df 1007 item.nAmount += nAmount;
1008 item.nConf = min(item.nConf, nConf);
1009 }
1010 else
1011 {
1012 Object obj;
1013 obj.push_back(Pair("address", strAddress));
e4ff4e68 1014 obj.push_back(Pair("account", strAccount));
1015 obj.push_back(Pair("label", strAccount)); // deprecated
83b9f427 1016 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
0a61b0df 1017 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1018 ret.push_back(obj);
1019 }
1020 }
1021 }
1022
e4ff4e68 1023 if (fByAccounts)
0a61b0df 1024 {
e4ff4e68 1025 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
0a61b0df 1026 {
1027 int64 nAmount = (*it).second.nAmount;
1028 int nConf = (*it).second.nConf;
1029 Object obj;
e4ff4e68 1030 obj.push_back(Pair("account", (*it).first));
1031 obj.push_back(Pair("label", (*it).first)); // deprecated
83b9f427 1032 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
0a61b0df 1033 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1034 ret.push_back(obj);
1035 }
1036 }
1037
1038 return ret;
1039}
1040
1041Value listreceivedbyaddress(const Array& params, bool fHelp)
1042{
1043 if (fHelp || params.size() > 2)
1044 throw runtime_error(
1045 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1046 "[minconf] is the minimum number of confirmations before payments are included.\n"
1047 "[includeempty] whether to include addresses that haven't received any payments.\n"
1048 "Returns an array of objects containing:\n"
1049 " \"address\" : receiving address\n"
e4ff4e68 1050 " \"account\" : the account of the receiving address\n"
0a61b0df 1051 " \"amount\" : total amount received by the address\n"
1052 " \"confirmations\" : number of confirmations of the most recent transaction included");
1053
1054 return ListReceived(params, false);
1055}
1056
e4ff4e68 1057Value listreceivedbyaccount(const Array& params, bool fHelp)
0a61b0df 1058{
1059 if (fHelp || params.size() > 2)
1060 throw runtime_error(
e4ff4e68 1061 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
0a61b0df 1062 "[minconf] is the minimum number of confirmations before payments are included.\n"
e4ff4e68 1063 "[includeempty] whether to include accounts that haven't received any payments.\n"
0a61b0df 1064 "Returns an array of objects containing:\n"
e4ff4e68 1065 " \"account\" : the account of the receiving addresses\n"
1066 " \"amount\" : total amount received by addresses with this account\n"
0a61b0df 1067 " \"confirmations\" : number of confirmations of the most recent transaction included");
1068
1069 return ListReceived(params, true);
1070}
1071
80be6e69 1072void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
bfd471f5 1073{
198fd7b0 1074 int64 nGeneratedImmature, nGeneratedMature, nFee;
809ee795 1075 string strSentAccount;
1076 list<pair<string, int64> > listReceived;
ddb68ace 1077 list<pair<string, int64> > listSent;
198fd7b0 1078 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
bfd471f5 1079
809ee795 1080 bool fAllAccounts = (strAccount == string("*"));
1081
1082 // Generated blocks assigned to account ""
198fd7b0 1083 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
bfd471f5 1084 {
809ee795 1085 Object entry;
1086 entry.push_back(Pair("account", string("")));
198fd7b0
GA
1087 if (nGeneratedImmature)
1088 {
1089 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1090 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1091 }
1092 else
1093 {
1094 entry.push_back(Pair("category", "generate"));
1095 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1096 }
80be6e69
GA
1097 if (fLong)
1098 WalletTxToJSON(wtx, entry);
809ee795 1099 ret.push_back(entry);
1100 }
bfd471f5 1101
809ee795 1102 // Sent
ddb68ace 1103 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
809ee795 1104 {
223b6f1b 1105 BOOST_FOREACH(const PAIRTYPE(string, int64)& s, listSent)
ddb68ace
GA
1106 {
1107 Object entry;
1108 entry.push_back(Pair("account", strSentAccount));
1109 entry.push_back(Pair("address", s.first));
1110 entry.push_back(Pair("category", "send"));
1111 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1112 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
80be6e69
GA
1113 if (fLong)
1114 WalletTxToJSON(wtx, entry);
ddb68ace
GA
1115 ret.push_back(entry);
1116 }
809ee795 1117 }
bfd471f5 1118
809ee795 1119 // Received
1120 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
64c7ee7e 1121 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
809ee795 1122 {
223b6f1b 1123 BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
ddb68ace
GA
1124 {
1125 string account;
64c7ee7e
PW
1126 if (pwalletMain->mapAddressBook.count(r.first))
1127 account = pwalletMain->mapAddressBook[r.first];
ddb68ace 1128 if (fAllAccounts || (account == strAccount))
809ee795 1129 {
1130 Object entry;
ddb68ace
GA
1131 entry.push_back(Pair("account", account));
1132 entry.push_back(Pair("address", r.first));
809ee795 1133 entry.push_back(Pair("category", "receive"));
1134 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
80be6e69
GA
1135 if (fLong)
1136 WalletTxToJSON(wtx, entry);
809ee795 1137 ret.push_back(entry);
1138 }
ddb68ace 1139 }
809ee795 1140 }
bfd471f5 1141
809ee795 1142}
bfd471f5 1143
809ee795 1144void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1145{
1146 bool fAllAccounts = (strAccount == string("*"));
bfd471f5 1147
809ee795 1148 if (fAllAccounts || acentry.strAccount == strAccount)
1149 {
1150 Object entry;
1151 entry.push_back(Pair("account", acentry.strAccount));
1152 entry.push_back(Pair("category", "move"));
f86655fd 1153 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
809ee795 1154 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1155 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1156 entry.push_back(Pair("comment", acentry.strComment));
1157 ret.push_back(entry);
bfd471f5 1158 }
1159}
1160
1161Value listtransactions(const Array& params, bool fHelp)
1162{
59d18adc 1163 if (fHelp || params.size() > 3)
bfd471f5 1164 throw runtime_error(
5aef2c0d
CAF
1165 "listtransactions [account] [count=10] [from=0]\n"
1166 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
bfd471f5 1167
809ee795 1168 string strAccount = "*";
1169 if (params.size() > 0)
1170 strAccount = params[0].get_str();
bfd471f5 1171 int nCount = 10;
1172 if (params.size() > 1)
1173 nCount = params[1].get_int();
5aef2c0d
CAF
1174 int nFrom = 0;
1175 if (params.size() > 2)
1176 nFrom = params[2].get_int();
bfd471f5 1177
809ee795 1178 Array ret;
64c7ee7e 1179 CWalletDB walletdb(pwalletMain->strWalletFile);
bfd471f5 1180
64c7ee7e 1181 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
bfd471f5 1182 {
809ee795 1183 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1184 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1185 typedef multimap<int64, TxPair > TxItems;
1186 TxItems txByTime;
1187
64c7ee7e 1188 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
809ee795 1189 {
1190 CWalletTx* wtx = &((*it).second);
47908a89 1191 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
809ee795 1192 }
1193 list<CAccountingEntry> acentries;
1194 walletdb.ListAccountCreditDebit(strAccount, acentries);
223b6f1b 1195 BOOST_FOREACH(CAccountingEntry& entry, acentries)
809ee795 1196 {
47908a89 1197 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
809ee795 1198 }
1199
1200 // Now: iterate backwards until we have nCount items to return:
c0430f42
GA
1201 TxItems::reverse_iterator it = txByTime.rbegin();
1202 for (std::advance(it, nFrom); it != txByTime.rend(); ++it)
809ee795 1203 {
1204 CWalletTx *const pwtx = (*it).second.first;
1205 if (pwtx != 0)
80be6e69 1206 ListTransactions(*pwtx, strAccount, 0, true, ret);
809ee795 1207 CAccountingEntry *const pacentry = (*it).second.second;
1208 if (pacentry != 0)
1209 AcentryToJSON(*pacentry, strAccount, ret);
1210
1211 if (ret.size() >= nCount) break;
1212 }
1213 // ret is now newest to oldest
1214 }
1215
1216 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1217 if (ret.size() > nCount)
1218 {
1219 Array::iterator last = ret.begin();
1220 std::advance(last, nCount);
1221 ret.erase(last, ret.end());
bfd471f5 1222 }
809ee795 1223 std::reverse(ret.begin(), ret.end()); // oldest to newest
bfd471f5 1224
809ee795 1225 return ret;
1226}
1227
1228Value listaccounts(const Array& params, bool fHelp)
1229{
1230 if (fHelp || params.size() > 1)
1231 throw runtime_error(
1232 "listaccounts [minconf=1]\n"
1233 "Returns Object that has account names as keys, account balances as values.");
1234
1235 int nMinDepth = 1;
2eb09b66
GA
1236 if (params.size() > 0)
1237 nMinDepth = params[0].get_int();
809ee795 1238
1239 map<string, int64> mapAccountBalances;
64c7ee7e
PW
1240 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
1241 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
809ee795 1242 {
64c7ee7e 1243 BOOST_FOREACH(const PAIRTYPE(string, string)& entry, pwalletMain->mapAddressBook) {
0a4cb869
ES
1244 uint160 hash160;
1245 if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me
1246 mapAccountBalances[entry.second] = 0;
1247 }
809ee795 1248
64c7ee7e 1249 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
809ee795 1250 {
1251 const CWalletTx& wtx = (*it).second;
198fd7b0 1252 int64 nGeneratedImmature, nGeneratedMature, nFee;
809ee795 1253 string strSentAccount;
1254 list<pair<string, int64> > listReceived;
ddb68ace 1255 list<pair<string, int64> > listSent;
198fd7b0 1256 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
ddb68ace 1257 mapAccountBalances[strSentAccount] -= nFee;
223b6f1b 1258 BOOST_FOREACH(const PAIRTYPE(string, int64)& s, listSent)
ddb68ace 1259 mapAccountBalances[strSentAccount] -= s.second;
809ee795 1260 if (wtx.GetDepthInMainChain() >= nMinDepth)
1261 {
198fd7b0 1262 mapAccountBalances[""] += nGeneratedMature;
223b6f1b 1263 BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
64c7ee7e
PW
1264 if (pwalletMain->mapAddressBook.count(r.first))
1265 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
d9574c2f
GA
1266 else
1267 mapAccountBalances[""] += r.second;
809ee795 1268 }
1269 }
1270 }
1271
1272 list<CAccountingEntry> acentries;
64c7ee7e 1273 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
223b6f1b 1274 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
809ee795 1275 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1276
1277 Object ret;
223b6f1b 1278 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
809ee795 1279 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1280 }
bfd471f5 1281 return ret;
1282}
1283
1284Value gettransaction(const Array& params, bool fHelp)
1285{
1286 if (fHelp || params.size() != 1)
1287 throw runtime_error(
1288 "gettransaction <txid>\n"
1289 "Get detailed information about <txid>");
1290
1291 uint256 hash;
1292 hash.SetHex(params[0].get_str());
1293
1294 Object entry;
64c7ee7e 1295 CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
bfd471f5 1296 {
64c7ee7e 1297 if (!pwalletMain->mapWallet.count(hash))
80be6e69 1298 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
64c7ee7e 1299 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
bfd471f5 1300
1301 int64 nCredit = wtx.GetCredit();
1302 int64 nDebit = wtx.GetDebit();
1303 int64 nNet = nCredit - nDebit;
1304 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1305
1306 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1307 if (wtx.IsFromMe())
1308 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
80be6e69 1309
64c7ee7e 1310 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
80be6e69
GA
1311
1312 Array details;
64c7ee7e 1313 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
80be6e69 1314 entry.push_back(Pair("details", details));
bfd471f5 1315 }
1316
1317 return entry;
1318}
1319
0a61b0df 1320
d743f035 1321Value backupwallet(const Array& params, bool fHelp)
1322{
1323 if (fHelp || params.size() != 1)
1324 throw runtime_error(
1325 "backupwallet <destination>\n"
1326 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1327
1328 string strDest = params[0].get_str();
64c7ee7e 1329 BackupWallet(*pwalletMain, strDest);
d743f035 1330
1331 return Value::null;
1332}
1333
c891967b 1334
4e87d341
MC
1335Value keypoolrefill(const Array& params, bool fHelp)
1336{
1337 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1338 throw runtime_error(
1339 "keypoolrefill\n"
1340 "Fills the keypool, requires wallet passphrase to be set.");
1341 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1342 throw runtime_error(
1343 "keypoolrefill\n"
1344 "Fills the keypool.");
1345
1346 CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
1347 {
1348 if (pwalletMain->IsLocked())
1349 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1350
1351 pwalletMain->TopUpKeyPool();
1352 }
1353
1354 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1355 throw JSONRPCError(-4, "Error refreshing keypool.");
1356
1357 return Value::null;
1358}
1359
1360
1361void ThreadTopUpKeyPool(void* parg)
1362{
1363 pwalletMain->TopUpKeyPool();
1364}
1365
1366void ThreadCleanWalletPassphrase(void* parg)
1367{
4e87d341 1368 int64 nMyWakeTime = GetTime() + *((int*)parg);
4e87d341 1369
98545d2c 1370 if (nWalletUnlockTime == 0)
4e87d341 1371 {
98545d2c 1372 CRITICAL_BLOCK(cs_nWalletUnlockTime)
4e87d341 1373 {
98545d2c 1374 nWalletUnlockTime = nMyWakeTime;
4e87d341
MC
1375 }
1376
98545d2c
MC
1377 while (GetTime() < nWalletUnlockTime)
1378 Sleep(GetTime() - nWalletUnlockTime);
4e87d341 1379
98545d2c 1380 CRITICAL_BLOCK(cs_nWalletUnlockTime)
4e87d341 1381 {
98545d2c 1382 nWalletUnlockTime = 0;
4e87d341
MC
1383 }
1384 }
1385 else
1386 {
98545d2c 1387 CRITICAL_BLOCK(cs_nWalletUnlockTime)
4e87d341 1388 {
98545d2c
MC
1389 if (nWalletUnlockTime < nMyWakeTime)
1390 nWalletUnlockTime = nMyWakeTime;
4e87d341
MC
1391 }
1392 free(parg);
1393 return;
1394 }
1395
1396 pwalletMain->Lock();
1397
1398 delete (int*)parg;
1399}
1400
1401Value walletpassphrase(const Array& params, bool fHelp)
1402{
1403 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1404 throw runtime_error(
1405 "walletpassphrase <passphrase> <timeout>\n"
1406 "Stores the wallet decryption key in memory for <timeout> seconds.");
1407 if (fHelp)
1408 return true;
1409 if (!pwalletMain->IsCrypted())
1410 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1411
1412 if (!pwalletMain->IsLocked())
1413 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1414
1415 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1416 string strWalletPass;
1417 strWalletPass.reserve(100);
1418 mlock(&strWalletPass[0], strWalletPass.capacity());
1419 strWalletPass = params[0].get_str();
1420
1421 CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
1422 {
1423 if (strWalletPass.length() > 0)
1424 {
1425 if (!pwalletMain->Unlock(strWalletPass))
1426 {
1427 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1428 munlock(&strWalletPass[0], strWalletPass.capacity());
1429 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1430 }
1431 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1432 munlock(&strWalletPass[0], strWalletPass.capacity());
1433 }
1434 else
1435 throw runtime_error(
1436 "walletpassphrase <passphrase> <timeout>\n"
1437 "Stores the wallet decryption key in memory for <timeout> seconds.");
1438 }
1439
1440 CreateThread(ThreadTopUpKeyPool, NULL);
1441 int* pnSleepTime = new int(params[1].get_int());
1442 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1443
1444 return Value::null;
1445}
1446
1447
1448Value walletpassphrasechange(const Array& params, bool fHelp)
1449{
1450 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1451 throw runtime_error(
1452 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1453 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1454 if (fHelp)
1455 return true;
1456 if (!pwalletMain->IsCrypted())
1457 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1458
1459 string strOldWalletPass;
1460 strOldWalletPass.reserve(100);
1461 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1462 strOldWalletPass = params[0].get_str();
1463
1464 string strNewWalletPass;
1465 strNewWalletPass.reserve(100);
1466 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1467 strNewWalletPass = params[1].get_str();
1468
1469 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1470 throw runtime_error(
1471 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1472 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1473
1474 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1475 {
1476 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1477 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1478 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1479 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1480 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1481 }
1482 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1483 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1484 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1485 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1486
1487 return Value::null;
1488}
1489
1490
fbeb5fb4
MC
1491Value walletlock(const Array& params, bool fHelp)
1492{
1493 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1494 throw runtime_error(
1495 "walletlock\n"
1496 "Removes the wallet encryption key from memory, locking the wallet.\n"
1497 "After calling this method, you will need to call walletpassphrase again\n"
1498 "before being able to call any methods which require the wallet to be unlocked.");
1499 if (fHelp)
1500 return true;
1501 if (!pwalletMain->IsCrypted())
1502 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1503
1504 pwalletMain->Lock();
1505 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1506 {
1507 nWalletUnlockTime = 0;
1508 }
1509
1510 return Value::null;
1511}
1512
1513
4e87d341
MC
1514Value encryptwallet(const Array& params, bool fHelp)
1515{
1516 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1517 throw runtime_error(
1518 "encryptwallet <passphrase>\n"
1519 "Encrypts the wallet with <passphrase>.");
1520 if (fHelp)
1521 return true;
1522 if (pwalletMain->IsCrypted())
1523 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1524
1525 string strWalletPass;
1526 strWalletPass.reserve(100);
1527 mlock(&strWalletPass[0], strWalletPass.capacity());
1528 strWalletPass = params[0].get_str();
1529
1530 if (strWalletPass.length() < 1)
1531 throw runtime_error(
1532 "encryptwallet <passphrase>\n"
1533 "Encrypts the wallet with <passphrase>.");
1534
1535 if (!pwalletMain->EncryptWallet(strWalletPass))
1536 {
1537 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1538 munlock(&strWalletPass[0], strWalletPass.capacity());
1539 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1540 }
1541 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1542 munlock(&strWalletPass[0], strWalletPass.capacity());
1543
1544 return Value::null;
1545}
1546
1547
2ea5fa07 1548Value validateaddress(const Array& params, bool fHelp)
1549{
1550 if (fHelp || params.size() != 1)
1551 throw runtime_error(
1552 "validateaddress <bitcoinaddress>\n"
1553 "Return information about <bitcoinaddress>.");
1554
1555 string strAddress = params[0].get_str();
1556 uint160 hash160;
1557 bool isValid = AddressToHash160(strAddress, hash160);
d743f035 1558
2ea5fa07 1559 Object ret;
1560 ret.push_back(Pair("isvalid", isValid));
1561 if (isValid)
1562 {
1563 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1564 // version of the address:
e4ff4e68 1565 string currentAddress = Hash160ToAddress(hash160);
1566 ret.push_back(Pair("address", currentAddress));
2ea5fa07 1567 ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0)));
64c7ee7e 1568 CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
e4ff4e68 1569 {
64c7ee7e
PW
1570 if (pwalletMain->mapAddressBook.count(currentAddress))
1571 ret.push_back(Pair("account", pwalletMain->mapAddressBook[currentAddress]));
e4ff4e68 1572 }
2ea5fa07 1573 }
1574 return ret;
1575}
0a61b0df 1576
1577
776d0f34 1578Value getwork(const Array& params, bool fHelp)
1579{
1580 if (fHelp || params.size() > 1)
1581 throw runtime_error(
1582 "getwork [data]\n"
1583 "If [data] is not specified, returns formatted hash data to work on:\n"
1584 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1585 " \"data\" : block data\n"
1586 " \"hash1\" : formatted hash buffer for second hash\n"
1587 " \"target\" : little endian hash target\n"
1588 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1589
1590 if (vNodes.empty())
1591 throw JSONRPCError(-9, "Bitcoin is not connected!");
1592
1593 if (IsInitialBlockDownload())
1594 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1595
1596 static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
1597 static vector<CBlock*> vNewBlock;
64c7ee7e 1598 static CReserveKey reservekey(pwalletMain);
776d0f34 1599
1600 if (params.size() == 0)
1601 {
1602 // Update block
1603 static unsigned int nTransactionsUpdatedLast;
1604 static CBlockIndex* pindexPrev;
1605 static int64 nStart;
1606 static CBlock* pblock;
1607 if (pindexPrev != pindexBest ||
1608 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1609 {
1610 if (pindexPrev != pindexBest)
1611 {
1612 // Deallocate old blocks since they're obsolete now
1613 mapNewBlock.clear();
223b6f1b 1614 BOOST_FOREACH(CBlock* pblock, vNewBlock)
776d0f34 1615 delete pblock;
1616 vNewBlock.clear();
1617 }
1618 nTransactionsUpdatedLast = nTransactionsUpdated;
1619 pindexPrev = pindexBest;
1620 nStart = GetTime();
1621
1622 // Create new block
1623 pblock = CreateNewBlock(reservekey);
1624 if (!pblock)
1625 throw JSONRPCError(-7, "Out of memory");
1626 vNewBlock.push_back(pblock);
1627 }
1628
1629 // Update nTime
1630 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1631 pblock->nNonce = 0;
1632
1633 // Update nExtraNonce
1634 static unsigned int nExtraNonce = 0;
1635 static int64 nPrevTime = 0;
1636 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, nPrevTime);
1637
1638 // Save
1639 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
1640
1641 // Prebuild hash buffers
1642 char pmidstate[32];
1643 char pdata[128];
1644 char phash1[64];
1645 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1646
1647 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1648
1649 Object result;
1650 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1651 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1652 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1653 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1654 return result;
1655 }
1656 else
1657 {
1658 // Parse parameters
1659 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1660 if (vchData.size() != 128)
1661 throw JSONRPCError(-8, "Invalid parameter");
1662 CBlock* pdata = (CBlock*)&vchData[0];
1663
1664 // Byte reverse
1665 for (int i = 0; i < 128/4; i++)
1666 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1667
1668 // Get saved block
1669 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1670 return false;
1671 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1672 unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
1673
1674 pblock->nTime = pdata->nTime;
1675 pblock->nNonce = pdata->nNonce;
1676 pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
1677 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1678
64c7ee7e 1679 return CheckWork(pblock, *pwalletMain, reservekey);
776d0f34 1680 }
1681}
1682
1683
0a61b0df 1684
1685
1686
1687
1688
1689
1690
1691
1692
1693//
1694// Call Table
1695//
1696
1697pair<string, rpcfn_type> pCallTable[] =
1698{
4e87d341
MC
1699 make_pair("help", &help),
1700 make_pair("stop", &stop),
1701 make_pair("getblockcount", &getblockcount),
1702 make_pair("getblocknumber", &getblocknumber),
1703 make_pair("getconnectioncount", &getconnectioncount),
1704 make_pair("getdifficulty", &getdifficulty),
1705 make_pair("getgenerate", &getgenerate),
1706 make_pair("setgenerate", &setgenerate),
1707 make_pair("gethashespersec", &gethashespersec),
1708 make_pair("getinfo", &getinfo),
1709 make_pair("getnewaddress", &getnewaddress),
1710 make_pair("getaccountaddress", &getaccountaddress),
1711 make_pair("setaccount", &setaccount),
1712 make_pair("setlabel", &setaccount), // deprecated
1713 make_pair("getaccount", &getaccount),
1714 make_pair("getlabel", &getaccount), // deprecated
1715 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1716 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1717 make_pair("sendtoaddress", &sendtoaddress),
1718 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1719 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1720 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1721 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1722 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1723 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1724 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1725 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1726 make_pair("backupwallet", &backupwallet),
1727 make_pair("keypoolrefill", &keypoolrefill),
1728 make_pair("walletpassphrase", &walletpassphrase),
1729 make_pair("walletpassphrasechange", &walletpassphrasechange),
fbeb5fb4 1730 make_pair("walletlock", &walletlock),
4e87d341
MC
1731 make_pair("encryptwallet", &encryptwallet),
1732 make_pair("validateaddress", &validateaddress),
1733 make_pair("getbalance", &getbalance),
1734 make_pair("move", &movecmd),
1735 make_pair("sendfrom", &sendfrom),
1736 make_pair("sendmany", &sendmany),
1737 make_pair("gettransaction", &gettransaction),
1738 make_pair("listtransactions", &listtransactions),
1739 make_pair("getwork", &getwork),
1740 make_pair("listaccounts", &listaccounts),
1741 make_pair("settxfee", &settxfee),
0a61b0df 1742};
1743map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1744
986b5e25 1745string pAllowInSafeMode[] =
1746{
1747 "help",
1748 "stop",
1749 "getblockcount",
1750 "getblocknumber",
1751 "getconnectioncount",
1752 "getdifficulty",
1753 "getgenerate",
1754 "setgenerate",
1755 "gethashespersec",
1756 "getinfo",
1757 "getnewaddress",
1758 "getaccountaddress",
1759 "setlabel",
1760 "getaccount",
1761 "getlabel", // deprecated
1762 "getaddressesbyaccount",
1763 "getaddressesbylabel", // deprecated
1764 "backupwallet",
4e87d341
MC
1765 "keypoolrefill",
1766 "walletpassphrase",
fbeb5fb4 1767 "walletlock",
986b5e25 1768 "validateaddress",
1769 "getwork",
1770};
1771set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1772
0a61b0df 1773
1774
1775
1776//
1777// HTTP protocol
1778//
1779// This ain't Apache. We're just using HTTP header for the length field
1780// and to be compatible with other JSON-RPC implementations.
1781//
1782
1783string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1784{
1785 ostringstream s;
1786 s << "POST / HTTP/1.1\r\n"
17616eac 1787 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
0a61b0df 1788 << "Host: 127.0.0.1\r\n"
1789 << "Content-Type: application/json\r\n"
1790 << "Content-Length: " << strMsg.size() << "\r\n"
1791 << "Accept: application/json\r\n";
223b6f1b 1792 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
d743f035 1793 s << item.first << ": " << item.second << "\r\n";
0a61b0df 1794 s << "\r\n" << strMsg;
1795
1796 return s.str();
1797}
1798
c285051c 1799string rfc1123Time()
1800{
d98beea8 1801 char buffer[64];
c285051c 1802 time_t now;
1803 time(&now);
1804 struct tm* now_gmt = gmtime(&now);
9ff411f7
GA
1805 string locale(setlocale(LC_TIME, NULL));
1806 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1807 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1808 setlocale(LC_TIME, locale.c_str());
c285051c 1809 return string(buffer);
1810}
1811
c9e70d4c 1812static string HTTPReply(int nStatus, const string& strMsg)
0a61b0df 1813{
1814 if (nStatus == 401)
c285051c 1815 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1816 "Date: %s\r\n"
17616eac 1817 "Server: bitcoin-json-rpc/%s\r\n"
0a61b0df 1818 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1819 "Content-Type: text/html\r\n"
809ee795 1820 "Content-Length: 296\r\n"
0a61b0df 1821 "\r\n"
1822 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1823 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1824 "<HTML>\r\n"
1825 "<HEAD>\r\n"
1826 "<TITLE>Error</TITLE>\r\n"
1827 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1828 "</HEAD>\r\n"
1829 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
17616eac 1830 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
0a61b0df 1831 string strStatus;
d743f035 1832 if (nStatus == 200) strStatus = "OK";
1833 else if (nStatus == 400) strStatus = "Bad Request";
c9e70d4c 1834 else if (nStatus == 403) strStatus = "Forbidden";
d743f035 1835 else if (nStatus == 404) strStatus = "Not Found";
1836 else if (nStatus == 500) strStatus = "Internal Server Error";
0a61b0df 1837 return strprintf(
1838 "HTTP/1.1 %d %s\r\n"
c285051c 1839 "Date: %s\r\n"
0a61b0df 1840 "Connection: close\r\n"
1841 "Content-Length: %d\r\n"
1842 "Content-Type: application/json\r\n"
17616eac 1843 "Server: bitcoin-json-rpc/%s\r\n"
0a61b0df 1844 "\r\n"
1845 "%s",
1846 nStatus,
1847 strStatus.c_str(),
c285051c 1848 rfc1123Time().c_str(),
0a61b0df 1849 strMsg.size(),
17616eac 1850 FormatFullVersion().c_str(),
0a61b0df 1851 strMsg.c_str());
1852}
1853
ed54768f 1854int ReadHTTPStatus(std::basic_istream<char>& stream)
0a61b0df 1855{
1856 string str;
1857 getline(stream, str);
1858 vector<string> vWords;
1859 boost::split(vWords, str, boost::is_any_of(" "));
efae3da4 1860 if (vWords.size() < 2)
1861 return 500;
1862 return atoi(vWords[1].c_str());
0a61b0df 1863}
1864
ed54768f 1865int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
0a61b0df 1866{
1867 int nLen = 0;
1868 loop
1869 {
1870 string str;
1871 std::getline(stream, str);
1872 if (str.empty() || str == "\r")
1873 break;
1874 string::size_type nColon = str.find(":");
1875 if (nColon != string::npos)
1876 {
1877 string strHeader = str.substr(0, nColon);
1878 boost::trim(strHeader);
e6ad2c87 1879 boost::to_lower(strHeader);
0a61b0df 1880 string strValue = str.substr(nColon+1);
1881 boost::trim(strValue);
1882 mapHeadersRet[strHeader] = strValue;
e6ad2c87 1883 if (strHeader == "content-length")
0a61b0df 1884 nLen = atoi(strValue.c_str());
1885 }
1886 }
1887 return nLen;
1888}
1889
ed54768f 1890int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
0a61b0df 1891{
1892 mapHeadersRet.clear();
1893 strMessageRet = "";
1894
1895 // Read status
1896 int nStatus = ReadHTTPStatus(stream);
1897
1898 // Read header
1899 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
d743f035 1900 if (nLen < 0 || nLen > MAX_SIZE)
0a61b0df 1901 return 500;
1902
1903 // Read message
d743f035 1904 if (nLen > 0)
1905 {
1906 vector<char> vch(nLen);
1907 stream.read(&vch[0], nLen);
1908 strMessageRet = string(vch.begin(), vch.end());
1909 }
0a61b0df 1910
1911 return nStatus;
1912}
1913
1914string EncodeBase64(string s)
1915{
1916 BIO *b64, *bmem;
1917 BUF_MEM *bptr;
1918
1919 b64 = BIO_new(BIO_f_base64());
1920 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1921 bmem = BIO_new(BIO_s_mem());
1922 b64 = BIO_push(b64, bmem);
1923 BIO_write(b64, s.c_str(), s.size());
1924 BIO_flush(b64);
1925 BIO_get_mem_ptr(b64, &bptr);
1926
1927 string result(bptr->data, bptr->length);
1928 BIO_free_all(b64);
1929
1930 return result;
1931}
1932
1933string DecodeBase64(string s)
1934{
1935 BIO *b64, *bmem;
1936
1937 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1938
1939 b64 = BIO_new(BIO_f_base64());
1940 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1941 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1942 bmem = BIO_push(b64, bmem);
1943 BIO_read(bmem, buffer, s.size());
1944 BIO_free_all(bmem);
1945
1946 string result(buffer);
1947 free(buffer);
1948 return result;
1949}
1950
1951bool HTTPAuthorized(map<string, string>& mapHeaders)
1952{
e6ad2c87 1953 string strAuth = mapHeaders["authorization"];
0a61b0df 1954 if (strAuth.substr(0,6) != "Basic ")
1955 return false;
1956 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1957 string strUserPass = DecodeBase64(strUserPass64);
1958 string::size_type nColon = strUserPass.find(":");
1959 if (nColon == string::npos)
1960 return false;
1961 string strUser = strUserPass.substr(0, nColon);
1962 string strPassword = strUserPass.substr(nColon+1);
1963 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1964}
1965
1966//
d743f035 1967// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1968// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1969// unspecified (HTTP errors and contents of 'error').
0a61b0df 1970//
d743f035 1971// 1.0 spec: http://json-rpc.org/wiki/specification
1972// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
0a61b0df 1973// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1974//
1975
1976string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1977{
1978 Object request;
1979 request.push_back(Pair("method", strMethod));
1980 request.push_back(Pair("params", params));
1981 request.push_back(Pair("id", id));
1982 return write_string(Value(request), false) + "\n";
1983}
1984
1985string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1986{
1987 Object reply;
1988 if (error.type() != null_type)
1989 reply.push_back(Pair("result", Value::null));
1990 else
1991 reply.push_back(Pair("result", result));
1992 reply.push_back(Pair("error", error));
1993 reply.push_back(Pair("id", id));
1994 return write_string(Value(reply), false) + "\n";
1995}
1996
809ee795 1997void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1998{
1999 // Send error reply from json-rpc error object
2000 int nStatus = 500;
2001 int code = find_value(objError, "code").get_int();
2002 if (code == -32600) nStatus = 400;
2003 else if (code == -32601) nStatus = 404;
2004 string strReply = JSONRPCReply(Value::null, objError, id);
2005 stream << HTTPReply(nStatus, strReply) << std::flush;
2006}
2007
efae3da4 2008bool ClientAllowed(const string& strAddress)
2009{
2010 if (strAddress == asio::ip::address_v4::loopback().to_string())
2011 return true;
2012 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
223b6f1b 2013 BOOST_FOREACH(string strAllow, vAllow)
efae3da4 2014 if (WildcardMatch(strAddress, strAllow))
2015 return true;
2016 return false;
2017}
2018
ed54768f 2019#ifdef USE_SSL
2020//
2021// IOStream device that speaks SSL but can also speak non-SSL
2022//
2023class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2024public:
2025 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2026 {
2027 fUseSSL = fUseSSLIn;
2028 fNeedHandshake = fUseSSLIn;
2029 }
0a61b0df 2030
ed54768f 2031 void handshake(ssl::stream_base::handshake_type role)
2032 {
2033 if (!fNeedHandshake) return;
2034 fNeedHandshake = false;
2035 stream.handshake(role);
2036 }
2037 std::streamsize read(char* s, std::streamsize n)
2038 {
2039 handshake(ssl::stream_base::server); // HTTPS servers read first
2040 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2041 return stream.next_layer().read_some(asio::buffer(s, n));
2042 }
2043 std::streamsize write(const char* s, std::streamsize n)
2044 {
2045 handshake(ssl::stream_base::client); // HTTPS clients write first
2046 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2047 return asio::write(stream.next_layer(), asio::buffer(s, n));
2048 }
2049 bool connect(const std::string& server, const std::string& port)
2050 {
2051 ip::tcp::resolver resolver(stream.get_io_service());
2052 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2053 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2054 ip::tcp::resolver::iterator end;
2055 boost::system::error_code error = asio::error::host_not_found;
2056 while (error && endpoint_iterator != end)
2057 {
2058 stream.lowest_layer().close();
2059 stream.lowest_layer().connect(*endpoint_iterator++, error);
2060 }
2061 if (error)
2062 return false;
2063 return true;
2064 }
0a61b0df 2065
ed54768f 2066private:
2067 bool fNeedHandshake;
2068 bool fUseSSL;
2069 SSLStream& stream;
2070};
2071#endif
0a61b0df 2072
2073void ThreadRPCServer(void* parg)
2074{
2075 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2076 try
2077 {
2078 vnThreadsRunning[4]++;
2079 ThreadRPCServer2(parg);
2080 vnThreadsRunning[4]--;
2081 }
2082 catch (std::exception& e) {
2083 vnThreadsRunning[4]--;
2084 PrintException(&e, "ThreadRPCServer()");
2085 } catch (...) {
2086 vnThreadsRunning[4]--;
2087 PrintException(NULL, "ThreadRPCServer()");
2088 }
2089 printf("ThreadRPCServer exiting\n");
2090}
2091
2092void ThreadRPCServer2(void* parg)
2093{
2094 printf("ThreadRPCServer started\n");
2095
2096 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2097 {
2098 string strWhatAmI = "To use bitcoind";
2099 if (mapArgs.count("-server"))
2100 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2101 else if (mapArgs.count("-daemon"))
2102 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2103 PrintConsole(
2104 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2105 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2106 strWhatAmI.c_str(),
2107 GetConfigFile().c_str());
2108 CreateThread(Shutdown, NULL);
2109 return;
2110 }
2111
bdde31d7 2112 bool fUseSSL = GetBoolArg("-rpcssl");
ed54768f 2113 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2114
2115 asio::io_service io_service;
2116 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2117 ip::tcp::acceptor acceptor(io_service, endpoint);
2118
8fd402bf 2119 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2120
ed54768f 2121#ifdef USE_SSL
2122 ssl::context context(io_service, ssl::context::sslv23);
2123 if (fUseSSL)
2124 {
2125 context.set_options(ssl::context::no_sslv2);
2126 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2127 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2128 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2129 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2130 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2131 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2132 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2133 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2134
2135 string ciphers = GetArg("-rpcsslciphers",
2136 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2137 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2138 }
2139#else
2140 if (fUseSSL)
bdde31d7 2141 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
ed54768f 2142#endif
0a61b0df 2143
2144 loop
2145 {
2146 // Accept connection
ed54768f 2147#ifdef USE_SSL
2148 SSLStream sslStream(io_service, context);
2149 SSLIOStreamDevice d(sslStream, fUseSSL);
2150 iostreams::stream<SSLIOStreamDevice> stream(d);
2151#else
2152 ip::tcp::iostream stream;
2153#endif
2154
2155 ip::tcp::endpoint peer;
0a61b0df 2156 vnThreadsRunning[4]--;
ed54768f 2157#ifdef USE_SSL
2158 acceptor.accept(sslStream.lowest_layer(), peer);
2159#else
0a61b0df 2160 acceptor.accept(*stream.rdbuf(), peer);
ed54768f 2161#endif
0a61b0df 2162 vnThreadsRunning[4]++;
2163 if (fShutdown)
2164 return;
2165
efae3da4 2166 // Restrict callers by IP
2167 if (!ClientAllowed(peer.address().to_string()))
c9e70d4c 2168 {
e913574e
GS
2169 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2170 if (!fUseSSL)
2171 stream << HTTPReply(403, "") << std::flush;
0a61b0df 2172 continue;
c9e70d4c 2173 }
0a61b0df 2174
0a61b0df 2175 map<string, string> mapHeaders;
2176 string strRequest;
809ee795 2177
47908a89 2178 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
809ee795 2179 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2180 { // Timed out:
2181 acceptor.cancel();
2182 printf("ThreadRPCServer ReadHTTP timeout\n");
2183 continue;
2184 }
0a61b0df 2185
2186 // Check authorization
e6ad2c87 2187 if (mapHeaders.count("authorization") == 0)
0a61b0df 2188 {
d743f035 2189 stream << HTTPReply(401, "") << std::flush;
0a61b0df 2190 continue;
2191 }
2192 if (!HTTPAuthorized(mapHeaders))
2193 {
2194 // Deter brute-forcing short passwords
2195 if (mapArgs["-rpcpassword"].size() < 15)
2196 Sleep(50);
2197
d743f035 2198 stream << HTTPReply(401, "") << std::flush;
0a61b0df 2199 printf("ThreadRPCServer incorrect password attempt\n");
2200 continue;
2201 }
2202
d743f035 2203 Value id = Value::null;
2204 try
0a61b0df 2205 {
d743f035 2206 // Parse request
2207 Value valRequest;
2208 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2209 throw JSONRPCError(-32700, "Parse error");
2210 const Object& request = valRequest.get_obj();
2211
2212 // Parse id now so errors from here on will have the id
2213 id = find_value(request, "id");
2214
2215 // Parse method
2216 Value valMethod = find_value(request, "method");
2217 if (valMethod.type() == null_type)
2218 throw JSONRPCError(-32600, "Missing method");
2219 if (valMethod.type() != str_type)
2220 throw JSONRPCError(-32600, "Method must be a string");
2221 string strMethod = valMethod.get_str();
776d0f34 2222 if (strMethod != "getwork")
2223 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
d743f035 2224
2225 // Parse params
2226 Value valParams = find_value(request, "params");
2227 Array params;
2228 if (valParams.type() == array_type)
2229 params = valParams.get_array();
2230 else if (valParams.type() == null_type)
2231 params = Array();
2232 else
2233 throw JSONRPCError(-32600, "Params must be an array");
2234
2235 // Find method
2236 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2237 if (mi == mapCallTable.end())
2238 throw JSONRPCError(-32601, "Method not found");
2239
986b5e25 2240 // Observe safe mode
2241 string strWarning = GetWarnings("rpc");
2242 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2243 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2244
0a61b0df 2245 try
2246 {
0a61b0df 2247 // Execute
0a61b0df 2248 Value result = (*(*mi).second)(params, false);
2249
2250 // Send reply
2251 string strReply = JSONRPCReply(result, Value::null, id);
d743f035 2252 stream << HTTPReply(200, strReply) << std::flush;
0a61b0df 2253 }
2254 catch (std::exception& e)
2255 {
809ee795 2256 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
0a61b0df 2257 }
d743f035 2258 }
2259 catch (Object& objError)
2260 {
809ee795 2261 ErrorReply(stream, objError, id);
d743f035 2262 }
2263 catch (std::exception& e)
2264 {
809ee795 2265 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
0a61b0df 2266 }
2267 }
2268}
2269
2270
2271
2272
d743f035 2273Object CallRPC(const string& strMethod, const Array& params)
0a61b0df 2274{
2275 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2276 throw runtime_error(strprintf(
2277 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2278 "If the file does not exist, create it with owner-readable-only file permissions."),
2279 GetConfigFile().c_str()));
2280
2281 // Connect to localhost
bdde31d7 2282 bool fUseSSL = GetBoolArg("-rpcssl");
ed54768f 2283#ifdef USE_SSL
2284 asio::io_service io_service;
2285 ssl::context context(io_service, ssl::context::sslv23);
2286 context.set_options(ssl::context::no_sslv2);
2287 SSLStream sslStream(io_service, context);
2288 SSLIOStreamDevice d(sslStream, fUseSSL);
2289 iostreams::stream<SSLIOStreamDevice> stream(d);
2290 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2291 throw runtime_error("couldn't connect to server");
2292#else
2293 if (fUseSSL)
bdde31d7 2294 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
ed54768f 2295
2296 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
0a61b0df 2297 if (stream.fail())
2298 throw runtime_error("couldn't connect to server");
ed54768f 2299#endif
2300
0a61b0df 2301
2302 // HTTP basic authentication
2303 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2304 map<string, string> mapRequestHeaders;
2305 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2306
2307 // Send request
2308 string strRequest = JSONRPCRequest(strMethod, params, 1);
2309 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2310 stream << strPost << std::flush;
2311
2312 // Receive reply
2313 map<string, string> mapHeaders;
2314 string strReply;
2315 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2316 if (nStatus == 401)
2317 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
d743f035 2318 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
0a61b0df 2319 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2320 else if (strReply.empty())
2321 throw runtime_error("no response from server");
2322
2323 // Parse reply
2324 Value valReply;
2325 if (!read_string(strReply, valReply))
2326 throw runtime_error("couldn't parse reply from server");
2327 const Object& reply = valReply.get_obj();
2328 if (reply.empty())
2329 throw runtime_error("expected reply to have result, error and id properties");
2330
d743f035 2331 return reply;
0a61b0df 2332}
2333
2334
2335
2336
2337template<typename T>
2338void ConvertTo(Value& value)
2339{
2340 if (value.type() == str_type)
2341 {
2342 // reinterpret string as unquoted json value
2343 Value value2;
2344 if (!read_string(value.get_str(), value2))
2345 throw runtime_error("type mismatch");
2346 value = value2.get_value<T>();
2347 }
2348 else
2349 {
2350 value = value.get_value<T>();
2351 }
2352}
2353
2354int CommandLineRPC(int argc, char *argv[])
2355{
d743f035 2356 string strPrint;
2357 int nRet = 0;
0a61b0df 2358 try
2359 {
2360 // Skip switches
2361 while (argc > 1 && IsSwitchChar(argv[1][0]))
2362 {
2363 argc--;
2364 argv++;
2365 }
2366
2367 // Method
2368 if (argc < 2)
2369 throw runtime_error("too few parameters");
2370 string strMethod = argv[1];
2371
2372 // Parameters default to strings
2373 Array params;
2374 for (int i = 2; i < argc; i++)
2375 params.push_back(argv[i]);
2376 int n = params.size();
2377
2378 //
2379 // Special case non-string parameter types
2380 //
2381 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2382 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2383 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
d9068ad5 2384 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
0a61b0df 2385 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2386 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
e4ff4e68 2387 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2388 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
0a61b0df 2389 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2390 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]);
2391 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2392 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
e4ff4e68 2393 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2394 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2395 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2396 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2397 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2398 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2399 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2400 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2401 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
bfd471f5 2402 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
ec86134a 2403 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2eb09b66 2404 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
4e87d341 2405 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
b931ed85
GA
2406 if (strMethod == "sendmany" && n > 1)
2407 {
2408 string s = params[1].get_str();
2409 Value v;
2410 if (!read_string(s, v) || v.type() != obj_type)
2411 throw runtime_error("type mismatch");
2412 params[1] = v.get_obj();
2413 }
2414 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
0a61b0df 2415
2416 // Execute
d743f035 2417 Object reply = CallRPC(strMethod, params);
2418
2419 // Parse reply
2420 const Value& result = find_value(reply, "result");
2421 const Value& error = find_value(reply, "error");
0a61b0df 2422
d743f035 2423 if (error.type() != null_type)
0a61b0df 2424 {
d743f035 2425 // Error
2426 strPrint = "error: " + write_string(error, false);
2427 int code = find_value(error.get_obj(), "code").get_int();
2428 nRet = abs(code);
2429 }
2430 else
2431 {
2432 // Result
2433 if (result.type() == null_type)
2434 strPrint = "";
2435 else if (result.type() == str_type)
2436 strPrint = result.get_str();
2437 else
2438 strPrint = write_string(result, true);
0a61b0df 2439 }
0a61b0df 2440 }
d743f035 2441 catch (std::exception& e)
2442 {
2443 strPrint = string("error: ") + e.what();
2444 nRet = 87;
2445 }
2446 catch (...)
2447 {
2448 PrintException(NULL, "CommandLineRPC()");
2449 }
2450
2451 if (strPrint != "")
2452 {
0a61b0df 2453#if defined(__WXMSW__) && defined(GUI)
d743f035 2454 // Windows GUI apps can't print to command line,
2455 // so settle for a message box yuck
2456 MyMessageBox(strPrint, "Bitcoin", wxOK);
0a61b0df 2457#else
d743f035 2458 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
0a61b0df 2459#endif
0a61b0df 2460 }
d743f035 2461 return nRet;
0a61b0df 2462}
2463
2464
2465
2466
2467#ifdef TEST
2468int main(int argc, char *argv[])
2469{
2470#ifdef _MSC_VER
2471 // Turn off microsoft heap dump noise
2472 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2473 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2474#endif
2475 setbuf(stdin, NULL);
2476 setbuf(stdout, NULL);
2477 setbuf(stderr, NULL);
2478
2479 try
2480 {
2481 if (argc >= 2 && string(argv[1]) == "-server")
2482 {
2483 printf("server ready\n");
2484 ThreadRPCServer(NULL);
2485 }
2486 else
2487 {
2488 return CommandLineRPC(argc, argv);
2489 }
2490 }
2491 catch (std::exception& e) {
2492 PrintException(&e, "main()");
2493 } catch (...) {
2494 PrintException(NULL, "main()");
2495 }
2496 return 0;
2497}
2498#endif
This page took 0.427835 seconds and 4 git commands to generate.