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