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