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