Projects : bitcoin : asciilifeform_maxint_locks_corrected

bitcoin/src/bitcoinrpc.cpp

Dir - Raw

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