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