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