1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
12 #include "ui_interface.h"
13 #include "bitcoinrpc.h"
16 #include <boost/asio.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/iostreams/concepts.hpp>
19 #include <boost/iostreams/stream.hpp>
20 #include <boost/algorithm/string.hpp>
21 #include <boost/lexical_cast.hpp>
22 #include <boost/asio/ssl.hpp>
23 #include <boost/filesystem/fstream.hpp>
24 typedef boost::asio::ssl::stream
<boost::asio::ip::tcp::socket
> SSLStream
;
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.
33 using namespace boost
;
34 using namespace boost::asio
;
35 using namespace json_spirit
;
37 void ThreadRPCServer2(void* parg
);
39 static std::string strRPCUserColonPass
;
41 static int64 nWalletUnlockTime
;
42 static CCriticalSection cs_nWalletUnlockTime
;
44 extern Value
dumpprivkey(const Array
& params
, bool fHelp
);
45 extern Value
importprivkey(const Array
& params
, bool fHelp
);
47 const Object emptyobj
;
49 void ThreadRPCServer3(void* parg
);
51 Object
JSONRPCError(int code
, const string
& message
)
54 error
.push_back(Pair("code", code
));
55 error
.push_back(Pair("message", message
));
59 double GetDifficulty(const CBlockIndex
* blockindex
= NULL
)
61 // Floating point number that is a multiple of the minimum difficulty,
62 // minimum difficulty = 1.0.
63 if (blockindex
== NULL
)
65 if (pindexBest
== NULL
)
68 blockindex
= pindexBest
;
71 int nShift
= (blockindex
->nBits
>> 24) & 0xff;
74 (double)0x0000ffff / (double)(blockindex
->nBits
& 0x00ffffff);
91 int64
AmountFromValue(const Value
& value
)
93 double dAmount
= value
.get_real();
94 if (dAmount
<= 0.0 || dAmount
> 21000000.0)
95 throw JSONRPCError(-3, "Invalid amount");
96 int64 nAmount
= roundint64(dAmount
* COIN
);
97 if (!MoneyRange(nAmount
))
98 throw JSONRPCError(-3, "Invalid amount");
102 Value
ValueFromAmount(int64 amount
)
104 return (double)amount
/ (double)COIN
;
108 HexBits(unsigned int nBits
)
114 uBits
.nBits
= htonl((int32_t)nBits
);
115 return HexStr(BEGIN(uBits
.cBits
), END(uBits
.cBits
));
127 FindDecompose(const Object
& decompositions
, const char* pcType
, const char* pcDefault
)
129 Value val
= find_value(decompositions
, pcType
);
130 std::string strDecompose
= (val
.type() == null_type
) ? pcDefault
: val
.get_str();
132 if (strDecompose
== "no")
134 if (strDecompose
== "hash")
136 if (strDecompose
== "hex")
138 if (strDecompose
== "asm")
140 if (strDecompose
== "obj")
142 throw JSONRPCError(-18, "Invalid decomposition");
145 void WalletTxToJSON(const CWalletTx
& wtx
, Object
& entry
)
147 int confirms
= wtx
.GetDepthInMainChain();
148 entry
.push_back(Pair("confirmations", confirms
));
151 entry
.push_back(Pair("blockhash", wtx
.hashBlock
.GetHex()));
152 entry
.push_back(Pair("blockindex", wtx
.nIndex
));
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
));
161 ScriptSigToJSON(const CTxIn
& txin
, Object
& out
)
163 out
.push_back(Pair("asm", txin
.scriptSig
.ToString()));
164 out
.push_back(Pair("hex", HexStr(txin
.scriptSig
.begin(), txin
.scriptSig
.end())));
167 uint256 hashTxprevBlock
;
168 if (!GetTransaction(txin
.prevout
.hash
, txprev
, hashTxprevBlock
))
172 vector
<CBitcoinAddress
> addresses
;
175 if (!ExtractAddresses(txprev
.vout
[txin
.prevout
.n
].scriptPubKey
, type
,
176 addresses
, nRequired
))
178 out
.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD
)));
182 out
.push_back(Pair("type", GetTxnOutputType(type
)));
183 if (type
== TX_MULTISIG
)
185 // TODO: Need to handle this specially since not all input addresses are required...
190 BOOST_FOREACH(const CBitcoinAddress
& addr
, addresses
)
191 a
.push_back(addr
.ToString());
192 out
.push_back(Pair("addresses", a
));
196 ScriptPubKeyToJSON(const CScript
& scriptPubKey
, Object
& out
)
199 vector
<CBitcoinAddress
> addresses
;
202 out
.push_back(Pair("asm", scriptPubKey
.ToString()));
203 out
.push_back(Pair("hex", HexStr(scriptPubKey
.begin(), scriptPubKey
.end())));
205 if (!ExtractAddresses(scriptPubKey
, type
, addresses
, nRequired
))
207 out
.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD
)));
211 out
.push_back(Pair("reqSigs", nRequired
));
212 out
.push_back(Pair("type", GetTxnOutputType(type
)));
215 BOOST_FOREACH(const CBitcoinAddress
& addr
, addresses
)
216 a
.push_back(addr
.ToString());
217 out
.push_back(Pair("addresses", a
));
220 void TxToJSON(const CTransaction
&tx
, Object
& entry
, const Object
& decompositions
)
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
)));
226 enum DecomposeMode decomposeScript
= FindDecompose(decompositions
, "script", "asm");
229 BOOST_FOREACH(const CTxIn
& txin
, tx
.vin
)
233 in
.push_back(Pair("coinbase", HexStr(txin
.scriptSig
.begin(), txin
.scriptSig
.end())));
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
));
240 switch (decomposeScript
) {
244 in
.push_back(Pair("scriptSig", HexStr(txin
.scriptSig
.begin(), txin
.scriptSig
.end())));
247 in
.push_back(Pair("scriptSig", txin
.scriptSig
.ToString()));
252 ScriptSigToJSON(txin
, o
);
253 in
.push_back(Pair("scriptSig", o
));
257 throw JSONRPCError(-18, "Invalid script decomposition");
260 in
.push_back(Pair("sequence", (boost::int64_t)txin
.nSequence
));
263 entry
.push_back(Pair("vin", vin
));
265 BOOST_FOREACH(const CTxOut
& txout
, tx
.vout
)
268 out
.push_back(Pair("value", ValueFromAmount(txout
.nValue
)));
269 switch (decomposeScript
) {
273 out
.push_back(Pair("scriptPubKey", HexStr(txout
.scriptPubKey
.begin(), txout
.scriptPubKey
.end())));
276 out
.push_back(Pair("scriptPubKey", txout
.scriptPubKey
.ToString()));
281 ScriptPubKeyToJSON(txout
.scriptPubKey
, o
);
282 out
.push_back(Pair("scriptPubKey", o
));
286 throw JSONRPCError(-18, "Invalid script decomposition");
290 entry
.push_back(Pair("vout", vout
));
293 void AnyTxToJSON(const uint256 hash
, const CTransaction
* ptx
, Object
& entry
, const Object
& decompositions
);
295 string
AccountFromValue(const Value
& value
)
297 string strAccount
= value
.get_str();
298 if (strAccount
== "*")
299 throw JSONRPCError(-11, "Invalid account name");
303 Object
blockToJSON(const CBlock
& block
, const CBlockIndex
* blockindex
, const Object
& decompositions
)
306 result
.push_back(Pair("hash", block
.GetHash().GetHex()));
307 CMerkleTx
txGen(block
.vtx
[0]);
308 txGen
.SetMerkleBranch(&block
);
309 result
.push_back(Pair("confirmations", (int)txGen
.GetDepthInMainChain()));
310 result
.push_back(Pair("size", (int)::GetSerializeSize(block
, SER_NETWORK
, PROTOCOL_VERSION
)));
311 result
.push_back(Pair("height", blockindex
->nHeight
));
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
));
316 result
.push_back(Pair("bits", HexBits(block
.nBits
)));
317 result
.push_back(Pair("difficulty", GetDifficulty(blockindex
)));
319 enum DecomposeMode decomposeTxn
= FindDecompose(decompositions
, "tx", "hash");
323 switch (decomposeTxn
) {
325 BOOST_FOREACH (const CTransaction
&tx
, block
.vtx
)
328 AnyTxToJSON(tx
.GetHash(), &tx
, entry
, decompositions
);
329 txs
.push_back(entry
);
333 BOOST_FOREACH (const CTransaction
&tx
, block
.vtx
)
335 CDataStream
ssTx(SER_NETWORK
, PROTOCOL_VERSION
);
338 txs
.push_back(HexStr(ssTx
.begin(), ssTx
.end()));
342 BOOST_FOREACH (const CTransaction
&tx
, block
.vtx
)
343 txs
.push_back(tx
.GetHash().GetHex());
346 throw JSONRPCError(-18, "Invalid transaction decomposition");
348 result
.push_back(Pair("tx", txs
));
351 if (blockindex
->pprev
)
352 result
.push_back(Pair("previousblockhash", blockindex
->pprev
->GetBlockHash().GetHex()));
353 if (blockindex
->pnext
)
354 result
.push_back(Pair("nextblockhash", blockindex
->pnext
->GetBlockHash().GetHex()));
362 /// Note: This interface may still be subject to change.
365 string
CRPCTable::help(string strCommand
) const
368 set
<rpcfn_type
> setDone
;
369 for (map
<string
, const CRPCCommand
*>::const_iterator mi
= mapCommands
.begin(); mi
!= mapCommands
.end(); ++mi
)
371 const CRPCCommand
*pcmd
= mi
->second
;
372 string strMethod
= mi
->first
;
373 // We already filter duplicates, but these deprecated screw up the sort order
374 if (strMethod
== "getamountreceived" ||
375 strMethod
== "getallreceived" ||
376 strMethod
== "getblocknumber" || // deprecated
377 (strMethod
.find("label") != string::npos
))
379 if (strCommand
!= "" && strMethod
!= strCommand
)
384 rpcfn_type pfn
= pcmd
->actor
;
385 if (setDone
.insert(pfn
).second
)
386 (*pfn
)(params
, true);
388 catch (std::exception
& e
)
390 // Help text is returned in an exception
391 string strHelp
= string(e
.what());
392 if (strCommand
== "")
393 if (strHelp
.find('\n') != string::npos
)
394 strHelp
= strHelp
.substr(0, strHelp
.find('\n'));
395 strRet
+= strHelp
+ "\n";
399 strRet
= strprintf("help: unknown command: %s\n", strCommand
.c_str());
400 strRet
= strRet
.substr(0,strRet
.size()-1);
404 Value
help(const Array
& params
, bool fHelp
)
406 if (fHelp
|| params
.size() > 1)
409 "List commands, or get help for a command.");
412 if (params
.size() > 0)
413 strCommand
= params
[0].get_str();
415 return tableRPC
.help(strCommand
);
419 Value
stop(const Array
& params
, bool fHelp
)
421 if (fHelp
|| params
.size() != 0)
424 "Stop bitcoin server.");
425 // Shutdown will take long enough that the response should get back
427 return "bitcoin server stopping";
431 Value
getblockcount(const Array
& params
, bool fHelp
)
433 if (fHelp
|| params
.size() != 0)
436 "Returns the number of blocks in the longest block chain.");
443 Value
getblocknumber(const Array
& params
, bool fHelp
)
445 if (fHelp
|| params
.size() != 0)
448 "Deprecated. Use getblockcount.");
454 Value
getconnectioncount(const Array
& params
, bool fHelp
)
456 if (fHelp
|| params
.size() != 0)
458 "getconnectioncount\n"
459 "Returns the number of connections to other nodes.");
461 return (int)vNodes
.size();
465 Value
getdifficulty(const Array
& params
, bool fHelp
)
467 if (fHelp
|| params
.size() != 0)
470 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
472 return GetDifficulty();
476 Value
getgenerate(const Array
& params
, bool fHelp
)
478 if (fHelp
|| params
.size() != 0)
481 "Returns true or false.");
483 return GetBoolArg("-gen");
487 Value
setgenerate(const Array
& params
, bool fHelp
)
489 if (fHelp
|| params
.size() < 1 || params
.size() > 2)
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.");
495 bool fGenerate
= true;
496 if (params
.size() > 0)
497 fGenerate
= params
[0].get_bool();
499 if (params
.size() > 1)
501 int nGenProcLimit
= params
[1].get_int();
502 mapArgs
["-genproclimit"] = itostr(nGenProcLimit
);
503 if (nGenProcLimit
== 0)
506 mapArgs
["-gen"] = (fGenerate
? "1" : "0");
508 GenerateBitcoins(fGenerate
, pwalletMain
);
513 Value
gethashespersec(const Array
& params
, bool fHelp
)
515 if (fHelp
|| params
.size() != 0)
518 "Returns a recent hashes per second performance measurement while generating.");
520 if (GetTimeMillis() - nHPSTimerStart
> 8000)
521 return (boost::int64_t)0;
522 return (boost::int64_t)dHashesPerSec
;
526 Value
getinfo(const Array
& params
, bool fHelp
)
528 if (fHelp
|| params
.size() != 0)
531 "Returns an object containing various state info.");
534 obj
.push_back(Pair("version", (int)CLIENT_VERSION
));
535 obj
.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION
));
536 obj
.push_back(Pair("walletversion", pwalletMain
->GetVersion()));
537 obj
.push_back(Pair("balance", ValueFromAmount(pwalletMain
->GetBalance())));
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())));
541 obj
.push_back(Pair("difficulty", (double)GetDifficulty()));
542 obj
.push_back(Pair("testnet", fTestNet
));
543 obj
.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain
->GetOldestKeyPoolTime()));
544 obj
.push_back(Pair("keypoolsize", pwalletMain
->GetKeyPoolSize()));
545 obj
.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee
)));
546 if (pwalletMain
->IsCrypted())
547 obj
.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime
/ 1000));
548 obj
.push_back(Pair("errors", GetWarnings("statusbar")));
553 Value
getmininginfo(const Array
& params
, bool fHelp
)
555 if (fHelp
|| params
.size() != 0)
558 "Returns an object containing mining-related information.");
561 obj
.push_back(Pair("blocks", (int)nBestHeight
));
562 obj
.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize
));
563 obj
.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx
));
564 obj
.push_back(Pair("difficulty", (double)GetDifficulty()));
565 obj
.push_back(Pair("errors", GetWarnings("statusbar")));
566 obj
.push_back(Pair("generate", GetBoolArg("-gen")));
567 obj
.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
568 obj
.push_back(Pair("hashespersec", gethashespersec(params
, false)));
569 obj
.push_back(Pair("pooledtx", (uint64_t)mempool
.size()));
570 obj
.push_back(Pair("testnet", fTestNet
));
575 Value
getnewaddress(const Array
& params
, bool fHelp
)
577 if (fHelp
|| params
.size() > 1)
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].");
584 // Parse the account first so we don't generate a key if there's an error
586 if (params
.size() > 0)
587 strAccount
= AccountFromValue(params
[0]);
589 if (!pwalletMain
->IsLocked())
590 pwalletMain
->TopUpKeyPool();
592 // Generate a new key that is added to wallet
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
);
598 pwalletMain
->SetAddressBookName(address
, strAccount
);
600 return address
.ToString();
604 CBitcoinAddress
GetAccountAddress(string strAccount
, bool bForceNew
=false)
606 CWalletDB
walletdb(pwalletMain
->strWalletFile
);
609 walletdb
.ReadAccount(strAccount
, account
);
611 bool bKeyUsed
= false;
613 // Check if the current key has been used
614 if (!account
.vchPubKey
.empty())
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();
622 const CWalletTx
& wtx
= (*it
).second
;
623 BOOST_FOREACH(const CTxOut
& txout
, wtx
.vout
)
624 if (txout
.scriptPubKey
== scriptPubKey
)
629 // Generate a new key
630 if (account
.vchPubKey
.empty() || bForceNew
|| bKeyUsed
)
632 if (!pwalletMain
->GetKeyFromPool(account
.vchPubKey
, false))
633 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
635 pwalletMain
->SetAddressBookName(CBitcoinAddress(account
.vchPubKey
), strAccount
);
636 walletdb
.WriteAccount(strAccount
, account
);
639 return CBitcoinAddress(account
.vchPubKey
);
642 Value
getaccountaddress(const Array
& params
, bool fHelp
)
644 if (fHelp
|| params
.size() != 1)
646 "getaccountaddress <account>\n"
647 "Returns the current bitcoin address for receiving payments to this account.");
649 // Parse the account first so we don't generate a key if there's an error
650 string strAccount
= AccountFromValue(params
[0]);
654 ret
= GetAccountAddress(strAccount
).ToString();
661 Value
setaccount(const Array
& params
, bool fHelp
)
663 if (fHelp
|| params
.size() < 1 || params
.size() > 2)
665 "setaccount <bitcoinaddress> <account>\n"
666 "Sets the account associated with the given address.");
668 CBitcoinAddress
address(params
[0].get_str());
669 if (!address
.IsValid())
670 throw JSONRPCError(-5, "Invalid bitcoin address");
674 if (params
.size() > 1)
675 strAccount
= AccountFromValue(params
[1]);
677 // Detect when changing the account of an address that is the 'unused current key' of another account:
678 if (pwalletMain
->mapAddressBook
.count(address
))
680 string strOldAccount
= pwalletMain
->mapAddressBook
[address
];
681 if (address
== GetAccountAddress(strOldAccount
))
682 GetAccountAddress(strOldAccount
, true);
685 pwalletMain
->SetAddressBookName(address
, strAccount
);
691 Value
getaccount(const Array
& params
, bool fHelp
)
693 if (fHelp
|| params
.size() != 1)
695 "getaccount <bitcoinaddress>\n"
696 "Returns the account associated with the given address.");
698 CBitcoinAddress
address(params
[0].get_str());
699 if (!address
.IsValid())
700 throw JSONRPCError(-5, "Invalid bitcoin address");
703 map
<CBitcoinAddress
, string
>::iterator mi
= pwalletMain
->mapAddressBook
.find(address
);
704 if (mi
!= pwalletMain
->mapAddressBook
.end() && !(*mi
).second
.empty())
705 strAccount
= (*mi
).second
;
710 Value
getaddressesbyaccount(const Array
& params
, bool fHelp
)
712 if (fHelp
|| params
.size() != 1)
714 "getaddressesbyaccount <account>\n"
715 "Returns the list of addresses for the given account.");
717 string strAccount
= AccountFromValue(params
[0]);
719 // Find all addresses that have the given account
721 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, string
)& item
, pwalletMain
->mapAddressBook
)
723 const CBitcoinAddress
& address
= item
.first
;
724 const string
& strName
= item
.second
;
725 if (strName
== strAccount
)
726 ret
.push_back(address
.ToString());
731 Value
settxfee(const Array
& params
, bool fHelp
)
733 if (fHelp
|| params
.size() < 1 || params
.size() > 1)
735 "settxfee <amount>\n"
736 "<amount> is a real and is rounded to the nearest 0.00000001");
740 if (params
[0].get_real() != 0.0)
741 nAmount
= AmountFromValue(params
[0]); // rejects 0.0 amounts
743 nTransactionFee
= nAmount
;
747 Value
sendtoaddress(const Array
& params
, bool fHelp
)
749 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() < 2 || params
.size() > 4))
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))
756 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
757 "<amount> is a real and is rounded to the nearest 0.00000001");
759 CBitcoinAddress
address(params
[0].get_str());
760 if (!address
.IsValid())
761 throw JSONRPCError(-5, "Invalid bitcoin address");
764 int64 nAmount
= AmountFromValue(params
[1]);
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();
773 if (pwalletMain
->IsLocked())
774 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
776 string strError
= pwalletMain
->SendMoneyToBitcoinAddress(address
, nAmount
, wtx
);
778 throw JSONRPCError(-4, strError
);
780 return wtx
.GetHash().GetHex();
783 Value
signmessage(const Array
& params
, bool fHelp
)
785 if (fHelp
|| params
.size() != 2)
787 "signmessage <bitcoinaddress> <message>\n"
788 "Sign a message with the private key of an address");
790 if (pwalletMain
->IsLocked())
791 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
793 string strAddress
= params
[0].get_str();
794 string strMessage
= params
[1].get_str();
796 CBitcoinAddress
addr(strAddress
);
798 throw JSONRPCError(-3, "Invalid address");
801 if (!pwalletMain
->GetKey(addr
, key
))
802 throw JSONRPCError(-4, "Private key not available");
804 CDataStream
ss(SER_GETHASH
, 0);
805 ss
<< strMessageMagic
;
808 vector
<unsigned char> vchSig
;
809 if (!key
.SignCompact(Hash(ss
.begin(), ss
.end()), vchSig
))
810 throw JSONRPCError(-5, "Sign failed");
812 return EncodeBase64(&vchSig
[0], vchSig
.size());
815 Value
verifymessage(const Array
& params
, bool fHelp
)
817 if (fHelp
|| params
.size() != 3)
819 "verifymessage <bitcoinaddress> <signature> <message>\n"
820 "Verify a signed message");
822 string strAddress
= params
[0].get_str();
823 string strSign
= params
[1].get_str();
824 string strMessage
= params
[2].get_str();
826 CBitcoinAddress
addr(strAddress
);
828 throw JSONRPCError(-3, "Invalid address");
830 bool fInvalid
= false;
831 vector
<unsigned char> vchSig
= DecodeBase64(strSign
.c_str(), &fInvalid
);
834 throw JSONRPCError(-5, "Malformed base64 encoding");
836 CDataStream
ss(SER_GETHASH
, 0);
837 ss
<< strMessageMagic
;
841 if (!key
.SetCompactSignature(Hash(ss
.begin(), ss
.end()), vchSig
))
844 return (CBitcoinAddress(key
.GetPubKey()) == addr
);
848 Value
getreceivedbyaddress(const Array
& params
, bool fHelp
)
850 if (fHelp
|| params
.size() < 1 || params
.size() > 2)
852 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
853 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
856 CBitcoinAddress address
= CBitcoinAddress(params
[0].get_str());
857 CScript scriptPubKey
;
858 if (!address
.IsValid())
859 throw JSONRPCError(-5, "Invalid bitcoin address");
860 scriptPubKey
.SetBitcoinAddress(address
);
861 if (!IsMine(*pwalletMain
,scriptPubKey
))
864 // Minimum confirmations
866 if (params
.size() > 1)
867 nMinDepth
= params
[1].get_int();
871 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
873 const CWalletTx
& wtx
= (*it
).second
;
874 if (wtx
.IsCoinBase() || !wtx
.IsFinal())
877 BOOST_FOREACH(const CTxOut
& txout
, wtx
.vout
)
878 if (txout
.scriptPubKey
== scriptPubKey
)
879 if (wtx
.GetDepthInMainChain() >= nMinDepth
)
880 nAmount
+= txout
.nValue
;
883 return ValueFromAmount(nAmount
);
887 void GetAccountAddresses(string strAccount
, set
<CBitcoinAddress
>& setAddress
)
889 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, string
)& item
, pwalletMain
->mapAddressBook
)
891 const CBitcoinAddress
& address
= item
.first
;
892 const string
& strName
= item
.second
;
893 if (strName
== strAccount
)
894 setAddress
.insert(address
);
899 Value
getreceivedbyaccount(const Array
& params
, bool fHelp
)
901 if (fHelp
|| params
.size() < 1 || params
.size() > 2)
903 "getreceivedbyaccount <account> [minconf=1]\n"
904 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
906 // Minimum confirmations
908 if (params
.size() > 1)
909 nMinDepth
= params
[1].get_int();
911 // Get the set of pub keys assigned to account
912 string strAccount
= AccountFromValue(params
[0]);
913 set
<CBitcoinAddress
> setAddress
;
914 GetAccountAddresses(strAccount
, setAddress
);
918 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
920 const CWalletTx
& wtx
= (*it
).second
;
921 if (wtx
.IsCoinBase() || !wtx
.IsFinal())
924 BOOST_FOREACH(const CTxOut
& txout
, wtx
.vout
)
926 CBitcoinAddress address
;
927 if (ExtractAddress(txout
.scriptPubKey
, address
) && pwalletMain
->HaveKey(address
) && setAddress
.count(address
))
928 if (wtx
.GetDepthInMainChain() >= nMinDepth
)
929 nAmount
+= txout
.nValue
;
933 return (double)nAmount
/ (double)COIN
;
937 int64
GetAccountBalance(CWalletDB
& walletdb
, const string
& strAccount
, int nMinDepth
)
941 // Tally wallet transactions
942 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
944 const CWalletTx
& wtx
= (*it
).second
;
948 int64 nGenerated
, nReceived
, nSent
, nFee
;
949 wtx
.GetAccountAmounts(strAccount
, nGenerated
, nReceived
, nSent
, nFee
);
951 if (nReceived
!= 0 && wtx
.GetDepthInMainChain() >= nMinDepth
)
952 nBalance
+= nReceived
;
953 nBalance
+= nGenerated
- nSent
- nFee
;
956 // Tally internal accounting entries
957 nBalance
+= walletdb
.GetAccountCreditDebit(strAccount
);
962 int64
GetAccountBalance(const string
& strAccount
, int nMinDepth
)
964 CWalletDB
walletdb(pwalletMain
->strWalletFile
);
965 return GetAccountBalance(walletdb
, strAccount
, nMinDepth
);
969 Value
getbalance(const Array
& params
, bool fHelp
)
971 if (fHelp
|| params
.size() > 2)
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.");
977 if (params
.size() == 0)
978 return ValueFromAmount(pwalletMain
->GetBalance());
981 if (params
.size() > 1)
982 nMinDepth
= params
[1].get_int();
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.
989 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
991 const CWalletTx
& wtx
= (*it
).second
;
995 int64 allGeneratedImmature
, allGeneratedMature
, allFee
;
996 allGeneratedImmature
= allGeneratedMature
= allFee
= 0;
997 string strSentAccount
;
998 list
<pair
<CBitcoinAddress
, int64
> > listReceived
;
999 list
<pair
<CBitcoinAddress
, int64
> > listSent
;
1000 wtx
.GetAmounts(allGeneratedImmature
, allGeneratedMature
, listReceived
, listSent
, allFee
, strSentAccount
);
1001 if (wtx
.GetDepthInMainChain() >= nMinDepth
)
1003 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
,int64
)& r
, listReceived
)
1004 nBalance
+= r
.second
;
1006 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
,int64
)& r
, listSent
)
1007 nBalance
-= r
.second
;
1009 nBalance
+= allGeneratedMature
;
1011 return ValueFromAmount(nBalance
);
1014 string strAccount
= AccountFromValue(params
[0]);
1016 int64 nBalance
= GetAccountBalance(strAccount
, nMinDepth
);
1018 return ValueFromAmount(nBalance
);
1022 Value
movecmd(const Array
& params
, bool fHelp
)
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.");
1029 string strFrom
= AccountFromValue(params
[0]);
1030 string strTo
= AccountFromValue(params
[1]);
1031 int64 nAmount
= AmountFromValue(params
[2]);
1032 if (params
.size() > 3)
1033 // unused parameter, used to be nMinDepth, keep type-checking it though
1034 (void)params
[3].get_int();
1036 if (params
.size() > 4)
1037 strComment
= params
[4].get_str();
1039 CWalletDB
walletdb(pwalletMain
->strWalletFile
);
1040 if (!walletdb
.TxnBegin())
1041 throw JSONRPCError(-20, "database error");
1043 int64 nNow
= GetAdjustedTime();
1046 CAccountingEntry debit
;
1047 debit
.strAccount
= strFrom
;
1048 debit
.nCreditDebit
= -nAmount
;
1050 debit
.strOtherAccount
= strTo
;
1051 debit
.strComment
= strComment
;
1052 walletdb
.WriteAccountingEntry(debit
);
1055 CAccountingEntry credit
;
1056 credit
.strAccount
= strTo
;
1057 credit
.nCreditDebit
= nAmount
;
1058 credit
.nTime
= nNow
;
1059 credit
.strOtherAccount
= strFrom
;
1060 credit
.strComment
= strComment
;
1061 walletdb
.WriteAccountingEntry(credit
);
1063 if (!walletdb
.TxnCommit())
1064 throw JSONRPCError(-20, "database error");
1070 Value
sendfrom(const Array
& params
, bool fHelp
)
1072 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() < 3 || params
.size() > 6))
1073 throw runtime_error(
1074 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
1075 "<amount> is a real and is rounded to the nearest 0.00000001\n"
1076 "requires wallet passphrase to be set with walletpassphrase first");
1077 if (!pwalletMain
->IsCrypted() && (fHelp
|| params
.size() < 3 || params
.size() > 6))
1078 throw runtime_error(
1079 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
1080 "<amount> is a real and is rounded to the nearest 0.00000001");
1082 string strAccount
= AccountFromValue(params
[0]);
1083 CBitcoinAddress
address(params
[1].get_str());
1084 if (!address
.IsValid())
1085 throw JSONRPCError(-5, "Invalid bitcoin address");
1086 int64 nAmount
= AmountFromValue(params
[2]);
1088 if (params
.size() > 3)
1089 nMinDepth
= params
[3].get_int();
1092 wtx
.strFromAccount
= strAccount
;
1093 if (params
.size() > 4 && params
[4].type() != null_type
&& !params
[4].get_str().empty())
1094 wtx
.mapValue
["comment"] = params
[4].get_str();
1095 if (params
.size() > 5 && params
[5].type() != null_type
&& !params
[5].get_str().empty())
1096 wtx
.mapValue
["to"] = params
[5].get_str();
1098 if (pwalletMain
->IsLocked())
1099 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1102 int64 nBalance
= GetAccountBalance(strAccount
, nMinDepth
);
1103 if (nAmount
> nBalance
)
1104 throw JSONRPCError(-6, "Account has insufficient funds");
1107 string strError
= pwalletMain
->SendMoneyToBitcoinAddress(address
, nAmount
, wtx
);
1109 throw JSONRPCError(-4, strError
);
1111 return wtx
.GetHash().GetHex();
1115 Value
sendmany(const Array
& params
, bool fHelp
)
1117 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() < 2 || params
.size() > 4))
1118 throw runtime_error(
1119 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1120 "amounts are double-precision floating point numbers\n"
1121 "requires wallet passphrase to be set with walletpassphrase first");
1122 if (!pwalletMain
->IsCrypted() && (fHelp
|| params
.size() < 2 || params
.size() > 4))
1123 throw runtime_error(
1124 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1125 "amounts are double-precision floating point numbers");
1127 string strAccount
= AccountFromValue(params
[0]);
1128 Object sendTo
= params
[1].get_obj();
1130 if (params
.size() > 2)
1131 nMinDepth
= params
[2].get_int();
1134 wtx
.strFromAccount
= strAccount
;
1135 if (params
.size() > 3 && params
[3].type() != null_type
&& !params
[3].get_str().empty())
1136 wtx
.mapValue
["comment"] = params
[3].get_str();
1138 set
<CBitcoinAddress
> setAddress
;
1139 vector
<pair
<CScript
, int64
> > vecSend
;
1141 int64 totalAmount
= 0;
1142 BOOST_FOREACH(const Pair
& s
, sendTo
)
1144 CBitcoinAddress
address(s
.name_
);
1145 if (!address
.IsValid())
1146 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s
.name_
);
1148 if (setAddress
.count(address
))
1149 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s
.name_
);
1150 setAddress
.insert(address
);
1152 CScript scriptPubKey
;
1153 scriptPubKey
.SetBitcoinAddress(address
);
1154 int64 nAmount
= AmountFromValue(s
.value_
);
1155 totalAmount
+= nAmount
;
1157 vecSend
.push_back(make_pair(scriptPubKey
, nAmount
));
1160 if (pwalletMain
->IsLocked())
1161 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1164 int64 nBalance
= GetAccountBalance(strAccount
, nMinDepth
);
1165 if (totalAmount
> nBalance
)
1166 throw JSONRPCError(-6, "Account has insufficient funds");
1169 CReserveKey
keyChange(pwalletMain
);
1170 int64 nFeeRequired
= 0;
1171 bool fCreated
= pwalletMain
->CreateTransaction(vecSend
, wtx
, keyChange
, nFeeRequired
);
1174 if (totalAmount
+ nFeeRequired
> pwalletMain
->GetBalance())
1175 throw JSONRPCError(-6, "Insufficient funds");
1176 throw JSONRPCError(-4, "Transaction creation failed");
1178 if (!pwalletMain
->CommitTransaction(wtx
, keyChange
))
1179 throw JSONRPCError(-4, "Transaction commit failed");
1181 return wtx
.GetHash().GetHex();
1184 Value
addmultisigaddress(const Array
& params
, bool fHelp
)
1186 if (fHelp
|| params
.size() < 2 || params
.size() > 3)
1188 string msg
= "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1189 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1190 "each key is a bitcoin address or hex-encoded public key\n"
1191 "If [account] is specified, assign address to [account].";
1192 throw runtime_error(msg
);
1195 int nRequired
= params
[0].get_int();
1196 const Array
& keys
= params
[1].get_array();
1198 if (params
.size() > 2)
1199 strAccount
= AccountFromValue(params
[2]);
1201 // Gather public keys
1203 throw runtime_error("a multisignature address must require at least one key to redeem");
1204 if ((int)keys
.size() < nRequired
)
1205 throw runtime_error(
1206 strprintf("not enough keys supplied "
1207 "(got %d keys, but need at least %d to redeem)", keys
.size(), nRequired
));
1208 std::vector
<CKey
> pubkeys
;
1209 pubkeys
.resize(keys
.size());
1210 for (unsigned int i
= 0; i
< keys
.size(); i
++)
1212 const std::string
& ks
= keys
[i
].get_str();
1214 // Case 1: bitcoin address and we have full public key:
1215 CBitcoinAddress
address(ks
);
1216 if (address
.IsValid())
1218 if (address
.IsScript())
1219 throw runtime_error(
1220 strprintf("%s is a pay-to-script address",ks
.c_str()));
1221 std::vector
<unsigned char> vchPubKey
;
1222 if (!pwalletMain
->GetPubKey(address
, vchPubKey
))
1223 throw runtime_error(
1224 strprintf("no full public key for address %s",ks
.c_str()));
1225 if (vchPubKey
.empty() || !pubkeys
[i
].SetPubKey(vchPubKey
))
1226 throw runtime_error(" Invalid public key: "+ks
);
1229 // Case 2: hex public key
1232 vector
<unsigned char> vchPubKey
= ParseHex(ks
);
1233 if (vchPubKey
.empty() || !pubkeys
[i
].SetPubKey(vchPubKey
))
1234 throw runtime_error(" Invalid public key: "+ks
);
1238 throw runtime_error(" Invalid public key: "+ks
);
1242 // Construct using pay-to-script-hash:
1244 inner
.SetMultisig(nRequired
, pubkeys
);
1246 uint160 scriptHash
= Hash160(inner
);
1247 CScript scriptPubKey
;
1248 scriptPubKey
.SetPayToScriptHash(inner
);
1249 pwalletMain
->AddCScript(inner
);
1250 CBitcoinAddress address
;
1251 address
.SetScriptHash160(scriptHash
);
1253 pwalletMain
->SetAddressBookName(address
, strAccount
);
1254 return address
.ToString();
1265 nConf
= std::numeric_limits
<int>::max();
1269 Value
ListReceived(const Array
& params
, bool fByAccounts
)
1271 // Minimum confirmations
1273 if (params
.size() > 0)
1274 nMinDepth
= params
[0].get_int();
1276 // Whether to include empty accounts
1277 bool fIncludeEmpty
= false;
1278 if (params
.size() > 1)
1279 fIncludeEmpty
= params
[1].get_bool();
1282 map
<CBitcoinAddress
, tallyitem
> mapTally
;
1283 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
1285 const CWalletTx
& wtx
= (*it
).second
;
1287 if (wtx
.IsCoinBase() || !wtx
.IsFinal())
1290 int nDepth
= wtx
.GetDepthInMainChain();
1291 if (nDepth
< nMinDepth
)
1294 BOOST_FOREACH(const CTxOut
& txout
, wtx
.vout
)
1296 CBitcoinAddress address
;
1297 if (!ExtractAddress(txout
.scriptPubKey
, address
) || !pwalletMain
->HaveKey(address
) || !address
.IsValid())
1300 tallyitem
& item
= mapTally
[address
];
1301 item
.nAmount
+= txout
.nValue
;
1302 item
.nConf
= min(item
.nConf
, nDepth
);
1308 map
<string
, tallyitem
> mapAccountTally
;
1309 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, string
)& item
, pwalletMain
->mapAddressBook
)
1311 const CBitcoinAddress
& address
= item
.first
;
1312 const string
& strAccount
= item
.second
;
1313 map
<CBitcoinAddress
, tallyitem
>::iterator it
= mapTally
.find(address
);
1314 if (it
== mapTally
.end() && !fIncludeEmpty
)
1318 int nConf
= std::numeric_limits
<int>::max();
1319 if (it
!= mapTally
.end())
1321 nAmount
= (*it
).second
.nAmount
;
1322 nConf
= (*it
).second
.nConf
;
1327 tallyitem
& item
= mapAccountTally
[strAccount
];
1328 item
.nAmount
+= nAmount
;
1329 item
.nConf
= min(item
.nConf
, nConf
);
1334 obj
.push_back(Pair("address", address
.ToString()));
1335 obj
.push_back(Pair("account", strAccount
));
1336 obj
.push_back(Pair("amount", ValueFromAmount(nAmount
)));
1337 obj
.push_back(Pair("confirmations", (nConf
== std::numeric_limits
<int>::max() ? 0 : nConf
)));
1344 for (map
<string
, tallyitem
>::iterator it
= mapAccountTally
.begin(); it
!= mapAccountTally
.end(); ++it
)
1346 int64 nAmount
= (*it
).second
.nAmount
;
1347 int nConf
= (*it
).second
.nConf
;
1349 obj
.push_back(Pair("account", (*it
).first
));
1350 obj
.push_back(Pair("amount", ValueFromAmount(nAmount
)));
1351 obj
.push_back(Pair("confirmations", (nConf
== std::numeric_limits
<int>::max() ? 0 : nConf
)));
1359 Value
listreceivedbyaddress(const Array
& params
, bool fHelp
)
1361 if (fHelp
|| params
.size() > 2)
1362 throw runtime_error(
1363 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1364 "[minconf] is the minimum number of confirmations before payments are included.\n"
1365 "[includeempty] whether to include addresses that haven't received any payments.\n"
1366 "Returns an array of objects containing:\n"
1367 " \"address\" : receiving address\n"
1368 " \"account\" : the account of the receiving address\n"
1369 " \"amount\" : total amount received by the address\n"
1370 " \"confirmations\" : number of confirmations of the most recent transaction included");
1372 return ListReceived(params
, false);
1375 Value
listreceivedbyaccount(const Array
& params
, bool fHelp
)
1377 if (fHelp
|| params
.size() > 2)
1378 throw runtime_error(
1379 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1380 "[minconf] is the minimum number of confirmations before payments are included.\n"
1381 "[includeempty] whether to include accounts that haven't received any payments.\n"
1382 "Returns an array of objects containing:\n"
1383 " \"account\" : the account of the receiving addresses\n"
1384 " \"amount\" : total amount received by addresses with this account\n"
1385 " \"confirmations\" : number of confirmations of the most recent transaction included");
1387 return ListReceived(params
, true);
1390 void ListTransactions(const CWalletTx
& wtx
, const string
& strAccount
, int nMinDepth
, bool fLong
, Array
& ret
)
1392 int64 nGeneratedImmature
, nGeneratedMature
, nFee
;
1393 string strSentAccount
;
1394 list
<pair
<CBitcoinAddress
, int64
> > listReceived
;
1395 list
<pair
<CBitcoinAddress
, int64
> > listSent
;
1397 wtx
.GetAmounts(nGeneratedImmature
, nGeneratedMature
, listReceived
, listSent
, nFee
, strSentAccount
);
1399 bool fAllAccounts
= (strAccount
== string("*"));
1401 // Generated blocks assigned to account ""
1402 if ((nGeneratedMature
+nGeneratedImmature
) != 0 && (fAllAccounts
|| strAccount
== ""))
1405 entry
.push_back(Pair("account", string("")));
1406 if (nGeneratedImmature
)
1408 entry
.push_back(Pair("category", wtx
.GetDepthInMainChain() ? "immature" : "orphan"));
1409 entry
.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature
)));
1413 entry
.push_back(Pair("category", "generate"));
1414 entry
.push_back(Pair("amount", ValueFromAmount(nGeneratedMature
)));
1417 WalletTxToJSON(wtx
, entry
);
1418 ret
.push_back(entry
);
1422 if ((!listSent
.empty() || nFee
!= 0) && (fAllAccounts
|| strAccount
== strSentAccount
))
1424 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, int64
)& s
, listSent
)
1427 entry
.push_back(Pair("account", strSentAccount
));
1428 entry
.push_back(Pair("address", s
.first
.ToString()));
1429 entry
.push_back(Pair("category", "send"));
1430 entry
.push_back(Pair("amount", ValueFromAmount(-s
.second
)));
1431 entry
.push_back(Pair("fee", ValueFromAmount(-nFee
)));
1433 WalletTxToJSON(wtx
, entry
);
1434 ret
.push_back(entry
);
1439 if (listReceived
.size() > 0 && wtx
.GetDepthInMainChain() >= nMinDepth
)
1441 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, int64
)& r
, listReceived
)
1444 if (pwalletMain
->mapAddressBook
.count(r
.first
))
1445 account
= pwalletMain
->mapAddressBook
[r
.first
];
1446 if (fAllAccounts
|| (account
== strAccount
))
1449 entry
.push_back(Pair("account", account
));
1450 entry
.push_back(Pair("address", r
.first
.ToString()));
1451 entry
.push_back(Pair("category", "receive"));
1452 entry
.push_back(Pair("amount", ValueFromAmount(r
.second
)));
1454 WalletTxToJSON(wtx
, entry
);
1455 ret
.push_back(entry
);
1461 void AcentryToJSON(const CAccountingEntry
& acentry
, const string
& strAccount
, Array
& ret
)
1463 bool fAllAccounts
= (strAccount
== string("*"));
1465 if (fAllAccounts
|| acentry
.strAccount
== strAccount
)
1468 entry
.push_back(Pair("account", acentry
.strAccount
));
1469 entry
.push_back(Pair("category", "move"));
1470 entry
.push_back(Pair("time", (boost::int64_t)acentry
.nTime
));
1471 entry
.push_back(Pair("amount", ValueFromAmount(acentry
.nCreditDebit
)));
1472 entry
.push_back(Pair("otheraccount", acentry
.strOtherAccount
));
1473 entry
.push_back(Pair("comment", acentry
.strComment
));
1474 ret
.push_back(entry
);
1478 Value
listtransactions(const Array
& params
, bool fHelp
)
1480 if (fHelp
|| params
.size() > 3)
1481 throw runtime_error(
1482 "listtransactions [account] [count=10] [from=0]\n"
1483 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1485 string strAccount
= "*";
1486 if (params
.size() > 0)
1487 strAccount
= params
[0].get_str();
1489 if (params
.size() > 1)
1490 nCount
= params
[1].get_int();
1492 if (params
.size() > 2)
1493 nFrom
= params
[2].get_int();
1496 throw JSONRPCError(-8, "Negative count");
1498 throw JSONRPCError(-8, "Negative from");
1501 CWalletDB
walletdb(pwalletMain
->strWalletFile
);
1503 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1504 typedef pair
<CWalletTx
*, CAccountingEntry
*> TxPair
;
1505 typedef multimap
<int64
, TxPair
> TxItems
;
1508 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1509 // would make this much faster for applications that do this a lot.
1510 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
1512 CWalletTx
* wtx
= &((*it
).second
);
1513 txByTime
.insert(make_pair(wtx
->GetTxTime(), TxPair(wtx
, (CAccountingEntry
*)0)));
1515 list
<CAccountingEntry
> acentries
;
1516 walletdb
.ListAccountCreditDebit(strAccount
, acentries
);
1517 BOOST_FOREACH(CAccountingEntry
& entry
, acentries
)
1519 txByTime
.insert(make_pair(entry
.nTime
, TxPair((CWalletTx
*)0, &entry
)));
1522 // iterate backwards until we have nCount items to return:
1523 for (TxItems::reverse_iterator it
= txByTime
.rbegin(); it
!= txByTime
.rend(); ++it
)
1525 CWalletTx
*const pwtx
= (*it
).second
.first
;
1527 ListTransactions(*pwtx
, strAccount
, 0, true, ret
);
1528 CAccountingEntry
*const pacentry
= (*it
).second
.second
;
1530 AcentryToJSON(*pacentry
, strAccount
, ret
);
1532 if ((int)ret
.size() >= (nCount
+nFrom
)) break;
1534 // ret is newest to oldest
1536 if (nFrom
> (int)ret
.size())
1538 if ((nFrom
+ nCount
) > (int)ret
.size())
1539 nCount
= ret
.size() - nFrom
;
1540 Array::iterator first
= ret
.begin();
1541 std::advance(first
, nFrom
);
1542 Array::iterator last
= ret
.begin();
1543 std::advance(last
, nFrom
+nCount
);
1545 if (last
!= ret
.end()) ret
.erase(last
, ret
.end());
1546 if (first
!= ret
.begin()) ret
.erase(ret
.begin(), first
);
1548 std::reverse(ret
.begin(), ret
.end()); // Return oldest to newest
1553 Value
listaccounts(const Array
& params
, bool fHelp
)
1555 if (fHelp
|| params
.size() > 1)
1556 throw runtime_error(
1557 "listaccounts [minconf=1]\n"
1558 "Returns Object that has account names as keys, account balances as values.");
1561 if (params
.size() > 0)
1562 nMinDepth
= params
[0].get_int();
1564 map
<string
, int64
> mapAccountBalances
;
1565 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, string
)& entry
, pwalletMain
->mapAddressBook
) {
1566 if (pwalletMain
->HaveKey(entry
.first
)) // This address belongs to me
1567 mapAccountBalances
[entry
.second
] = 0;
1570 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); ++it
)
1572 const CWalletTx
& wtx
= (*it
).second
;
1573 int64 nGeneratedImmature
, nGeneratedMature
, nFee
;
1574 string strSentAccount
;
1575 list
<pair
<CBitcoinAddress
, int64
> > listReceived
;
1576 list
<pair
<CBitcoinAddress
, int64
> > listSent
;
1577 wtx
.GetAmounts(nGeneratedImmature
, nGeneratedMature
, listReceived
, listSent
, nFee
, strSentAccount
);
1578 mapAccountBalances
[strSentAccount
] -= nFee
;
1579 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, int64
)& s
, listSent
)
1580 mapAccountBalances
[strSentAccount
] -= s
.second
;
1581 if (wtx
.GetDepthInMainChain() >= nMinDepth
)
1583 mapAccountBalances
[""] += nGeneratedMature
;
1584 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress
, int64
)& r
, listReceived
)
1585 if (pwalletMain
->mapAddressBook
.count(r
.first
))
1586 mapAccountBalances
[pwalletMain
->mapAddressBook
[r
.first
]] += r
.second
;
1588 mapAccountBalances
[""] += r
.second
;
1592 list
<CAccountingEntry
> acentries
;
1593 CWalletDB(pwalletMain
->strWalletFile
).ListAccountCreditDebit("*", acentries
);
1594 BOOST_FOREACH(const CAccountingEntry
& entry
, acentries
)
1595 mapAccountBalances
[entry
.strAccount
] += entry
.nCreditDebit
;
1598 BOOST_FOREACH(const PAIRTYPE(string
, int64
)& accountBalance
, mapAccountBalances
) {
1599 ret
.push_back(Pair(accountBalance
.first
, ValueFromAmount(accountBalance
.second
)));
1604 Value
listsinceblock(const Array
& params
, bool fHelp
)
1607 throw runtime_error(
1608 "listsinceblock [blockhash] [target-confirmations]\n"
1609 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1611 CBlockIndex
*pindex
= NULL
;
1612 int target_confirms
= 1;
1614 if (params
.size() > 0)
1616 uint256 blockId
= 0;
1618 blockId
.SetHex(params
[0].get_str());
1619 pindex
= CBlockLocator(blockId
).GetBlockIndex();
1622 if (params
.size() > 1)
1624 target_confirms
= params
[1].get_int();
1626 if (target_confirms
< 1)
1627 throw JSONRPCError(-8, "Invalid parameter");
1630 int depth
= pindex
? (1 + nBestHeight
- pindex
->nHeight
) : -1;
1634 for (map
<uint256
, CWalletTx
>::iterator it
= pwalletMain
->mapWallet
.begin(); it
!= pwalletMain
->mapWallet
.end(); it
++)
1636 CWalletTx tx
= (*it
).second
;
1638 if (depth
== -1 || tx
.GetDepthInMainChain() < depth
)
1639 ListTransactions(tx
, "*", 0, true, transactions
);
1644 if (target_confirms
== 1)
1646 lastblock
= hashBestChain
;
1650 int target_height
= pindexBest
->nHeight
+ 1 - target_confirms
;
1653 for (block
= pindexBest
;
1654 block
&& block
->nHeight
> target_height
;
1655 block
= block
->pprev
) { }
1657 lastblock
= block
? block
->GetBlockHash() : 0;
1661 ret
.push_back(Pair("transactions", transactions
));
1662 ret
.push_back(Pair("lastblock", lastblock
.GetHex()));
1668 AnyTxToJSON(const uint256 hash
, const CTransaction
* ptx
, Object
& entry
, const Object
& decompositions
)
1670 if (pwalletMain
->mapWallet
.count(hash
))
1672 const CWalletTx
& wtx
= pwalletMain
->mapWallet
[hash
];
1674 TxToJSON(wtx
, entry
, decompositions
);
1676 int64 nCredit
= wtx
.GetCredit();
1677 int64 nDebit
= wtx
.GetDebit();
1678 int64 nNet
= nCredit
- nDebit
;
1679 int64 nFee
= (wtx
.IsFromMe() ? wtx
.GetValueOut() - nDebit
: 0);
1681 entry
.push_back(Pair("amount", ValueFromAmount(nNet
- nFee
)));
1683 entry
.push_back(Pair("fee", ValueFromAmount(nFee
)));
1685 WalletTxToJSON(wtx
, entry
);
1688 ListTransactions(pwalletMain
->mapWallet
[hash
], "*", 0, false, details
);
1689 entry
.push_back(Pair("details", details
));
1694 uint256 hashBlock
= 0;
1695 if ((!ptx
) && GetTransaction(hash
, tx
, hashBlock
))
1699 entry
.push_back(Pair("txid", hash
.GetHex()));
1700 TxToJSON(*ptx
, entry
, decompositions
);
1702 entry
.push_back(Pair("confirmations", 0));
1705 entry
.push_back(Pair("blockhash", hashBlock
.GetHex()));
1706 map
<uint256
, CBlockIndex
*>::iterator mi
= mapBlockIndex
.find(hashBlock
);
1707 if (mi
!= mapBlockIndex
.end() && (*mi
).second
)
1709 CBlockIndex
* pindex
= (*mi
).second
;
1710 if (pindex
->IsInMainChain())
1712 entry
.push_back(Pair("confirmations", 1 + nBestHeight
- pindex
->nHeight
));
1713 entry
.push_back(Pair("time", (boost::int64_t)pindex
->nTime
));
1716 entry
.push_back(Pair("confirmations", 0));
1721 throw JSONRPCError(-5, "No information available about transaction");
1725 Value
gettransaction(const Array
& params
, bool fHelp
)
1727 if (fHelp
|| params
.size() < 1 || params
.size() > 2)
1728 throw runtime_error(
1729 "gettransaction <txid> [decompositions]\n"
1730 "Get detailed information about <txid>");
1733 hash
.SetHex(params
[0].get_str());
1737 AnyTxToJSON(hash
, NULL
, entry
,
1738 (params
.size() > 1) ? params
[1].get_obj() : emptyobj
);
1744 Value
backupwallet(const Array
& params
, bool fHelp
)
1746 if (fHelp
|| params
.size() != 1)
1747 throw runtime_error(
1748 "backupwallet <destination>\n"
1749 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1751 string strDest
= params
[0].get_str();
1752 BackupWallet(*pwalletMain
, strDest
);
1758 Value
keypoolrefill(const Array
& params
, bool fHelp
)
1760 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() > 0))
1761 throw runtime_error(
1763 "Fills the keypool, requires wallet passphrase to be set.");
1764 if (!pwalletMain
->IsCrypted() && (fHelp
|| params
.size() > 0))
1765 throw runtime_error(
1767 "Fills the keypool.");
1769 if (pwalletMain
->IsLocked())
1770 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1772 pwalletMain
->TopUpKeyPool();
1774 if (pwalletMain
->GetKeyPoolSize() < GetArg("-keypool", 100))
1775 throw JSONRPCError(-4, "Error refreshing keypool.");
1781 void ThreadTopUpKeyPool(void* parg
)
1783 pwalletMain
->TopUpKeyPool();
1786 void ThreadCleanWalletPassphrase(void* parg
)
1788 int64 nMyWakeTime
= GetTimeMillis() + *((int64
*)parg
) * 1000;
1790 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime
);
1792 if (nWalletUnlockTime
== 0)
1794 nWalletUnlockTime
= nMyWakeTime
;
1798 if (nWalletUnlockTime
==0)
1800 int64 nToSleep
= nWalletUnlockTime
- GetTimeMillis();
1804 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime
);
1806 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime
);
1810 if (nWalletUnlockTime
)
1812 nWalletUnlockTime
= 0;
1813 pwalletMain
->Lock();
1818 if (nWalletUnlockTime
< nMyWakeTime
)
1819 nWalletUnlockTime
= nMyWakeTime
;
1822 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime
);
1824 delete (int64
*)parg
;
1827 Value
walletpassphrase(const Array
& params
, bool fHelp
)
1829 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() != 2))
1830 throw runtime_error(
1831 "walletpassphrase <passphrase> <timeout>\n"
1832 "Stores the wallet decryption key in memory for <timeout> seconds.");
1835 if (!pwalletMain
->IsCrypted())
1836 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1838 if (!pwalletMain
->IsLocked())
1839 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1841 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1842 SecureString strWalletPass
;
1843 strWalletPass
.reserve(100);
1844 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1845 // Alternately, find a way to make params[0] mlock()'d to begin with.
1846 strWalletPass
= params
[0].get_str().c_str();
1848 if (strWalletPass
.length() > 0)
1850 if (!pwalletMain
->Unlock(strWalletPass
))
1851 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1854 throw runtime_error(
1855 "walletpassphrase <passphrase> <timeout>\n"
1856 "Stores the wallet decryption key in memory for <timeout> seconds.");
1858 CreateThread(ThreadTopUpKeyPool
, NULL
);
1859 int64
* pnSleepTime
= new int64(params
[1].get_int64());
1860 CreateThread(ThreadCleanWalletPassphrase
, pnSleepTime
);
1866 Value
walletpassphrasechange(const Array
& params
, bool fHelp
)
1868 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() != 2))
1869 throw runtime_error(
1870 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1871 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1874 if (!pwalletMain
->IsCrypted())
1875 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1877 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1878 // Alternately, find a way to make params[0] mlock()'d to begin with.
1879 SecureString strOldWalletPass
;
1880 strOldWalletPass
.reserve(100);
1881 strOldWalletPass
= params
[0].get_str().c_str();
1883 SecureString strNewWalletPass
;
1884 strNewWalletPass
.reserve(100);
1885 strNewWalletPass
= params
[1].get_str().c_str();
1887 if (strOldWalletPass
.length() < 1 || strNewWalletPass
.length() < 1)
1888 throw runtime_error(
1889 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1890 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1892 if (!pwalletMain
->ChangeWalletPassphrase(strOldWalletPass
, strNewWalletPass
))
1893 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1899 Value
walletlock(const Array
& params
, bool fHelp
)
1901 if (pwalletMain
->IsCrypted() && (fHelp
|| params
.size() != 0))
1902 throw runtime_error(
1904 "Removes the wallet encryption key from memory, locking the wallet.\n"
1905 "After calling this method, you will need to call walletpassphrase again\n"
1906 "before being able to call any methods which require the wallet to be unlocked.");
1909 if (!pwalletMain
->IsCrypted())
1910 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1913 LOCK(cs_nWalletUnlockTime
);
1914 pwalletMain
->Lock();
1915 nWalletUnlockTime
= 0;
1922 Value
encryptwallet(const Array
& params
, bool fHelp
)
1924 if (!pwalletMain
->IsCrypted() && (fHelp
|| params
.size() != 1))
1925 throw runtime_error(
1926 "encryptwallet <passphrase>\n"
1927 "Encrypts the wallet with <passphrase>.");
1930 if (pwalletMain
->IsCrypted())
1931 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1933 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1934 // Alternately, find a way to make params[0] mlock()'d to begin with.
1935 SecureString strWalletPass
;
1936 strWalletPass
.reserve(100);
1937 strWalletPass
= params
[0].get_str().c_str();
1939 if (strWalletPass
.length() < 1)
1940 throw runtime_error(
1941 "encryptwallet <passphrase>\n"
1942 "Encrypts the wallet with <passphrase>.");
1944 if (!pwalletMain
->EncryptWallet(strWalletPass
))
1945 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1947 // BDB seems to have a bad habit of writing old data into
1948 // slack space in .dat files; that is bad if the old data is
1949 // unencrypted private keys. So:
1951 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1955 Value
validateaddress(const Array
& params
, bool fHelp
)
1957 if (fHelp
|| params
.size() != 1)
1958 throw runtime_error(
1959 "validateaddress <bitcoinaddress>\n"
1960 "Return information about <bitcoinaddress>.");
1962 CBitcoinAddress
address(params
[0].get_str());
1963 bool isValid
= address
.IsValid();
1966 ret
.push_back(Pair("isvalid", isValid
));
1969 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1970 // version of the address:
1971 string currentAddress
= address
.ToString();
1972 ret
.push_back(Pair("address", currentAddress
));
1973 if (pwalletMain
->HaveKey(address
))
1975 ret
.push_back(Pair("ismine", true));
1976 std::vector
<unsigned char> vchPubKey
;
1977 pwalletMain
->GetPubKey(address
, vchPubKey
);
1978 ret
.push_back(Pair("pubkey", HexStr(vchPubKey
)));
1980 key
.SetPubKey(vchPubKey
);
1981 ret
.push_back(Pair("iscompressed", key
.IsCompressed()));
1983 else if (pwalletMain
->HaveCScript(address
.GetHash160()))
1985 ret
.push_back(Pair("isscript", true));
1987 pwalletMain
->GetCScript(address
.GetHash160(), subscript
);
1988 ret
.push_back(Pair("ismine", ::IsMine(*pwalletMain
, subscript
)));
1989 std::vector
<CBitcoinAddress
> addresses
;
1990 txnouttype whichType
;
1992 ExtractAddresses(subscript
, whichType
, addresses
, nRequired
);
1993 ret
.push_back(Pair("script", GetTxnOutputType(whichType
)));
1995 BOOST_FOREACH(const CBitcoinAddress
& addr
, addresses
)
1996 a
.push_back(addr
.ToString());
1997 ret
.push_back(Pair("addresses", a
));
1998 if (whichType
== TX_MULTISIG
)
1999 ret
.push_back(Pair("sigsrequired", nRequired
));
2002 ret
.push_back(Pair("ismine", false));
2003 if (pwalletMain
->mapAddressBook
.count(address
))
2004 ret
.push_back(Pair("account", pwalletMain
->mapAddressBook
[address
]));
2009 Value
getwork(const Array
& params
, bool fHelp
)
2011 if (fHelp
|| params
.size() > 1)
2012 throw runtime_error(
2014 "If [data] is not specified, returns formatted hash data to work on:\n"
2015 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
2016 " \"data\" : block data\n"
2017 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
2018 " \"target\" : little endian hash target\n"
2019 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2022 throw JSONRPCError(-9, "Bitcoin is not connected!");
2024 if (IsInitialBlockDownload())
2025 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
2027 typedef map
<uint256
, pair
<CBlock
*, CScript
> > mapNewBlock_t
;
2028 static mapNewBlock_t mapNewBlock
; // FIXME: thread safety
2029 static vector
<CBlock
*> vNewBlock
;
2030 static CReserveKey
reservekey(pwalletMain
);
2032 if (params
.size() == 0)
2035 static unsigned int nTransactionsUpdatedLast
;
2036 static CBlockIndex
* pindexPrev
;
2037 static int64 nStart
;
2038 static CBlock
* pblock
;
2039 if (pindexPrev
!= pindexBest
||
2040 (nTransactionsUpdated
!= nTransactionsUpdatedLast
&& GetTime() - nStart
> 60))
2042 if (pindexPrev
!= pindexBest
)
2044 // Deallocate old blocks since they're obsolete now
2045 mapNewBlock
.clear();
2046 BOOST_FOREACH(CBlock
* pblock
, vNewBlock
)
2050 nTransactionsUpdatedLast
= nTransactionsUpdated
;
2051 pindexPrev
= pindexBest
;
2055 pblock
= CreateNewBlock(reservekey
);
2057 throw JSONRPCError(-7, "Out of memory");
2058 vNewBlock
.push_back(pblock
);
2062 pblock
->UpdateTime(pindexPrev
);
2065 // Update nExtraNonce
2066 static unsigned int nExtraNonce
= 0;
2067 IncrementExtraNonce(pblock
, pindexPrev
, nExtraNonce
);
2070 mapNewBlock
[pblock
->hashMerkleRoot
] = make_pair(pblock
, pblock
->vtx
[0].vin
[0].scriptSig
);
2072 // Prebuild hash buffers
2076 FormatHashBuffers(pblock
, pmidstate
, pdata
, phash1
);
2078 uint256 hashTarget
= CBigNum().SetCompact(pblock
->nBits
).getuint256();
2081 result
.push_back(Pair("midstate", HexStr(BEGIN(pmidstate
), END(pmidstate
)))); // deprecated
2082 result
.push_back(Pair("data", HexStr(BEGIN(pdata
), END(pdata
))));
2083 result
.push_back(Pair("hash1", HexStr(BEGIN(phash1
), END(phash1
)))); // deprecated
2084 result
.push_back(Pair("target", HexStr(BEGIN(hashTarget
), END(hashTarget
))));
2090 vector
<unsigned char> vchData
= ParseHex(params
[0].get_str());
2091 if (vchData
.size() != 128)
2092 throw JSONRPCError(-8, "Invalid parameter");
2093 CBlock
* pdata
= (CBlock
*)&vchData
[0];
2096 for (int i
= 0; i
< 128/4; i
++)
2097 ((unsigned int*)pdata
)[i
] = ByteReverse(((unsigned int*)pdata
)[i
]);
2100 if (!mapNewBlock
.count(pdata
->hashMerkleRoot
))
2102 CBlock
* pblock
= mapNewBlock
[pdata
->hashMerkleRoot
].first
;
2104 pblock
->nTime
= pdata
->nTime
;
2105 pblock
->nNonce
= pdata
->nNonce
;
2106 pblock
->vtx
[0].vin
[0].scriptSig
= mapNewBlock
[pdata
->hashMerkleRoot
].second
;
2107 pblock
->hashMerkleRoot
= pblock
->BuildMerkleTree();
2109 return CheckWork(pblock
, *pwalletMain
, reservekey
);
2114 Value
getmemorypool(const Array
& params
, bool fHelp
)
2116 if (fHelp
|| params
.size() > 1)
2117 throw runtime_error(
2118 "getmemorypool [data]\n"
2119 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2120 " \"version\" : block version\n"
2121 " \"previousblockhash\" : hash of current highest block\n"
2122 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2123 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2124 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2125 " \"time\" : timestamp appropriate for next block\n"
2126 " \"mintime\" : minimum timestamp appropriate for next block\n"
2127 " \"curtime\" : current timestamp\n"
2128 " \"bits\" : compressed target of next block\n"
2129 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2131 if (params
.size() == 0)
2134 throw JSONRPCError(-9, "Bitcoin is not connected!");
2136 if (IsInitialBlockDownload())
2137 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
2139 static CReserveKey
reservekey(pwalletMain
);
2142 static unsigned int nTransactionsUpdatedLast
;
2143 static CBlockIndex
* pindexPrev
;
2144 static int64 nStart
;
2145 static CBlock
* pblock
;
2146 if (pindexPrev
!= pindexBest
||
2147 (nTransactionsUpdated
!= nTransactionsUpdatedLast
&& GetTime() - nStart
> 5))
2149 nTransactionsUpdatedLast
= nTransactionsUpdated
;
2150 pindexPrev
= pindexBest
;
2156 pblock
= CreateNewBlock(reservekey
);
2158 throw JSONRPCError(-7, "Out of memory");
2162 pblock
->UpdateTime(pindexPrev
);
2166 BOOST_FOREACH(CTransaction tx
, pblock
->vtx
) {
2170 CDataStream
ssTx(SER_NETWORK
, PROTOCOL_VERSION
);
2173 transactions
.push_back(HexStr(ssTx
.begin(), ssTx
.end()));
2177 result
.push_back(Pair("version", pblock
->nVersion
));
2178 result
.push_back(Pair("previousblockhash", pblock
->hashPrevBlock
.GetHex()));
2179 result
.push_back(Pair("transactions", transactions
));
2180 result
.push_back(Pair("coinbasevalue", (int64_t)pblock
->vtx
[0].vout
[0].nValue
));
2181 result
.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS
.begin(), COINBASE_FLAGS
.end())));
2182 result
.push_back(Pair("time", (int64_t)pblock
->nTime
));
2183 result
.push_back(Pair("mintime", (int64_t)pindexPrev
->GetMedianTimePast()+1));
2184 result
.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2185 result
.push_back(Pair("bits", HexBits(pblock
->nBits
)));
2192 CDataStream
ssBlock(ParseHex(params
[0].get_str()), SER_NETWORK
, PROTOCOL_VERSION
);
2196 return ProcessBlock(NULL
, &pblock
);
2200 Value
getblockhash(const Array
& params
, bool fHelp
)
2202 if (fHelp
|| params
.size() != 1)
2203 throw runtime_error(
2204 "getblockhash <index>\n"
2205 "Returns hash of block in best-block-chain at <index>.");
2207 int nHeight
= params
[0].get_int();
2208 if (nHeight
< 0 || nHeight
> nBestHeight
)
2209 throw runtime_error("Block number out of range.");
2212 CBlockIndex
* pblockindex
= mapBlockIndex
[hashBestChain
];
2213 while (pblockindex
->nHeight
> nHeight
)
2214 pblockindex
= pblockindex
->pprev
;
2215 return pblockindex
->phashBlock
->GetHex();
2218 Value
getblock(const Array
& params
, bool fHelp
)
2220 if (fHelp
|| params
.size() < 1 || params
.size() > 2)
2221 throw runtime_error(
2222 "getblock <hash> [decompositions]\n"
2223 "Returns details of a block with given block-hash.");
2225 std::string strHash
= params
[0].get_str();
2226 uint256
hash(strHash
);
2228 if (mapBlockIndex
.count(hash
) == 0)
2229 throw JSONRPCError(-5, "Block not found");
2232 CBlockIndex
* pblockindex
= mapBlockIndex
[hash
];
2233 block
.ReadFromDisk(pblockindex
, true);
2235 return blockToJSON(block
, pblockindex
,
2236 (params
.size() > 1) ? params
[1].get_obj() : emptyobj
);
2254 static const CRPCCommand vRPCCommands
[] =
2255 { // name function safe mode?
2256 // ------------------------ ----------------------- ----------
2257 { "help", &help
, true },
2258 { "stop", &stop
, true },
2259 { "getblockcount", &getblockcount
, true },
2260 { "getblocknumber", &getblocknumber
, true },
2261 { "getconnectioncount", &getconnectioncount
, true },
2262 { "getdifficulty", &getdifficulty
, true },
2263 { "getgenerate", &getgenerate
, true },
2264 { "setgenerate", &setgenerate
, true },
2265 { "gethashespersec", &gethashespersec
, true },
2266 { "getinfo", &getinfo
, true },
2267 { "getmininginfo", &getmininginfo
, true },
2268 { "getnewaddress", &getnewaddress
, true },
2269 { "getaccountaddress", &getaccountaddress
, true },
2270 { "setaccount", &setaccount
, true },
2271 { "getaccount", &getaccount
, false },
2272 { "getaddressesbyaccount", &getaddressesbyaccount
, true },
2273 { "sendtoaddress", &sendtoaddress
, false },
2274 { "getreceivedbyaddress", &getreceivedbyaddress
, false },
2275 { "getreceivedbyaccount", &getreceivedbyaccount
, false },
2276 { "listreceivedbyaddress", &listreceivedbyaddress
, false },
2277 { "listreceivedbyaccount", &listreceivedbyaccount
, false },
2278 { "backupwallet", &backupwallet
, true },
2279 { "keypoolrefill", &keypoolrefill
, true },
2280 { "walletpassphrase", &walletpassphrase
, true },
2281 { "walletpassphrasechange", &walletpassphrasechange
, false },
2282 { "walletlock", &walletlock
, true },
2283 { "encryptwallet", &encryptwallet
, false },
2284 { "validateaddress", &validateaddress
, true },
2285 { "getbalance", &getbalance
, false },
2286 { "move", &movecmd
, false },
2287 { "sendfrom", &sendfrom
, false },
2288 { "sendmany", &sendmany
, false },
2289 { "addmultisigaddress", &addmultisigaddress
, false },
2290 { "getblock", &getblock
, false },
2291 { "getblockhash", &getblockhash
, false },
2292 { "gettransaction", &gettransaction
, false },
2293 { "listtransactions", &listtransactions
, false },
2294 { "signmessage", &signmessage
, false },
2295 { "verifymessage", &verifymessage
, false },
2296 { "getwork", &getwork
, true },
2297 { "listaccounts", &listaccounts
, false },
2298 { "settxfee", &settxfee
, false },
2299 { "getmemorypool", &getmemorypool
, true },
2300 { "listsinceblock", &listsinceblock
, false },
2301 { "dumpprivkey", &dumpprivkey
, false },
2302 { "importprivkey", &importprivkey
, false },
2305 CRPCTable::CRPCTable()
2308 for (vcidx
= 0; vcidx
< (sizeof(vRPCCommands
) / sizeof(vRPCCommands
[0])); vcidx
++)
2310 const CRPCCommand
*pcmd
;
2312 pcmd
= &vRPCCommands
[vcidx
];
2313 mapCommands
[pcmd
->name
] = pcmd
;
2317 const CRPCCommand
*CRPCTable::operator[](string name
) const
2319 map
<string
, const CRPCCommand
*>::const_iterator it
= mapCommands
.find(name
);
2320 if (it
== mapCommands
.end())
2322 return (*it
).second
;
2328 // This ain't Apache. We're just using HTTP header for the length field
2329 // and to be compatible with other JSON-RPC implementations.
2332 string
HTTPPost(const string
& strMsg
, const map
<string
,string
>& mapRequestHeaders
)
2335 s
<< "POST / HTTP/1.1\r\n"
2336 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2337 << "Host: 127.0.0.1\r\n"
2338 << "Content-Type: application/json\r\n"
2339 << "Content-Length: " << strMsg
.size() << "\r\n"
2340 << "Connection: close\r\n"
2341 << "Accept: application/json\r\n";
2342 BOOST_FOREACH(const PAIRTYPE(string
, string
)& item
, mapRequestHeaders
)
2343 s
<< item
.first
<< ": " << item
.second
<< "\r\n";
2344 s
<< "\r\n" << strMsg
;
2349 string
rfc1123Time()
2354 struct tm
* now_gmt
= gmtime(&now
);
2355 string
locale(setlocale(LC_TIME
, NULL
));
2356 setlocale(LC_TIME
, "C"); // we want posix (aka "C") weekday/month strings
2357 strftime(buffer
, sizeof(buffer
), "%a, %d %b %Y %H:%M:%S +0000", now_gmt
);
2358 setlocale(LC_TIME
, locale
.c_str());
2359 return string(buffer
);
2362 static string
HTTPReply(int nStatus
, const string
& strMsg
, bool keepalive
)
2365 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2367 "Server: bitcoin-json-rpc/%s\r\n"
2368 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2369 "Content-Type: text/html\r\n"
2370 "Content-Length: 296\r\n"
2372 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2373 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2376 "<TITLE>Error</TITLE>\r\n"
2377 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2379 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2380 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2381 const char *cStatus
;
2382 if (nStatus
== 200) cStatus
= "OK";
2383 else if (nStatus
== 400) cStatus
= "Bad Request";
2384 else if (nStatus
== 403) cStatus
= "Forbidden";
2385 else if (nStatus
== 404) cStatus
= "Not Found";
2386 else if (nStatus
== 500) cStatus
= "Internal Server Error";
2389 "HTTP/1.1 %d %s\r\n"
2391 "Connection: %s\r\n"
2392 "Content-Length: %d\r\n"
2393 "Content-Type: application/json\r\n"
2394 "Server: bitcoin-json-rpc/%s\r\n"
2399 rfc1123Time().c_str(),
2400 keepalive
? "keep-alive" : "close",
2402 FormatFullVersion().c_str(),
2406 int ReadHTTPStatus(std::basic_istream
<char>& stream
, int &proto
)
2409 getline(stream
, str
);
2410 vector
<string
> vWords
;
2411 boost::split(vWords
, str
, boost::is_any_of(" "));
2412 if (vWords
.size() < 2)
2415 const char *ver
= strstr(str
.c_str(), "HTTP/1.");
2417 proto
= atoi(ver
+7);
2418 return atoi(vWords
[1].c_str());
2421 int ReadHTTPHeader(std::basic_istream
<char>& stream
, map
<string
, string
>& mapHeadersRet
)
2427 std::getline(stream
, str
);
2428 if (str
.empty() || str
== "\r")
2430 string::size_type nColon
= str
.find(":");
2431 if (nColon
!= string::npos
)
2433 string strHeader
= str
.substr(0, nColon
);
2434 boost::trim(strHeader
);
2435 boost::to_lower(strHeader
);
2436 string strValue
= str
.substr(nColon
+1);
2437 boost::trim(strValue
);
2438 mapHeadersRet
[strHeader
] = strValue
;
2439 if (strHeader
== "content-length")
2440 nLen
= atoi(strValue
.c_str());
2446 int ReadHTTP(std::basic_istream
<char>& stream
, map
<string
, string
>& mapHeadersRet
, string
& strMessageRet
)
2448 mapHeadersRet
.clear();
2453 int nStatus
= ReadHTTPStatus(stream
, nProto
);
2456 int nLen
= ReadHTTPHeader(stream
, mapHeadersRet
);
2457 if (nLen
< 0 || nLen
> (int)MAX_SIZE
)
2463 vector
<char> vch(nLen
);
2464 stream
.read(&vch
[0], nLen
);
2465 strMessageRet
= string(vch
.begin(), vch
.end());
2468 string sConHdr
= mapHeadersRet
["connection"];
2470 if ((sConHdr
!= "close") && (sConHdr
!= "keep-alive"))
2473 mapHeadersRet
["connection"] = "keep-alive";
2475 mapHeadersRet
["connection"] = "close";
2481 bool HTTPAuthorized(map
<string
, string
>& mapHeaders
)
2483 string strAuth
= mapHeaders
["authorization"];
2484 if (strAuth
.substr(0,6) != "Basic ")
2486 string strUserPass64
= strAuth
.substr(6); boost::trim(strUserPass64
);
2487 string strUserPass
= DecodeBase64(strUserPass64
);
2488 return strUserPass
== strRPCUserColonPass
;
2492 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2493 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2494 // unspecified (HTTP errors and contents of 'error').
2496 // 1.0 spec: http://json-rpc.org/wiki/specification
2497 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2498 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2501 string
JSONRPCRequest(const string
& strMethod
, const Array
& params
, const Value
& id
)
2504 request
.push_back(Pair("method", strMethod
));
2505 request
.push_back(Pair("params", params
));
2506 request
.push_back(Pair("id", id
));
2507 return write_string(Value(request
), false) + "\n";
2510 string
JSONRPCReply(const Value
& result
, const Value
& error
, const Value
& id
)
2513 if (error
.type() != null_type
)
2514 reply
.push_back(Pair("result", Value::null
));
2516 reply
.push_back(Pair("result", result
));
2517 reply
.push_back(Pair("error", error
));
2518 reply
.push_back(Pair("id", id
));
2519 return write_string(Value(reply
), false) + "\n";
2522 void ErrorReply(std::ostream
& stream
, const Object
& objError
, const Value
& id
)
2524 // Send error reply from json-rpc error object
2526 int code
= find_value(objError
, "code").get_int();
2527 if (code
== -32600) nStatus
= 400;
2528 else if (code
== -32601) nStatus
= 404;
2529 string strReply
= JSONRPCReply(Value::null
, objError
, id
);
2530 stream
<< HTTPReply(nStatus
, strReply
, false) << std::flush
;
2533 bool ClientAllowed(const string
& strAddress
)
2535 if (strAddress
== asio::ip::address_v4::loopback().to_string())
2537 const vector
<string
>& vAllow
= mapMultiArgs
["-rpcallowip"];
2538 BOOST_FOREACH(string strAllow
, vAllow
)
2539 if (WildcardMatch(strAddress
, strAllow
))
2545 // IOStream device that speaks SSL but can also speak non-SSL
2547 class SSLIOStreamDevice
: public iostreams::device
<iostreams::bidirectional
> {
2549 SSLIOStreamDevice(SSLStream
&streamIn
, bool fUseSSLIn
) : stream(streamIn
)
2551 fUseSSL
= fUseSSLIn
;
2552 fNeedHandshake
= fUseSSLIn
;
2555 void handshake(ssl::stream_base::handshake_type role
)
2557 if (!fNeedHandshake
) return;
2558 fNeedHandshake
= false;
2559 stream
.handshake(role
);
2561 std::streamsize
read(char* s
, std::streamsize n
)
2563 handshake(ssl::stream_base::server
); // HTTPS servers read first
2564 if (fUseSSL
) return stream
.read_some(asio::buffer(s
, n
));
2565 return stream
.next_layer().read_some(asio::buffer(s
, n
));
2567 std::streamsize
write(const char* s
, std::streamsize n
)
2569 handshake(ssl::stream_base::client
); // HTTPS clients write first
2570 if (fUseSSL
) return asio::write(stream
, asio::buffer(s
, n
));
2571 return asio::write(stream
.next_layer(), asio::buffer(s
, n
));
2573 bool connect(const std::string
& server
, const std::string
& port
)
2575 ip::tcp::resolver
resolver(stream
.get_io_service());
2576 ip::tcp::resolver::query
query(server
.c_str(), port
.c_str());
2577 ip::tcp::resolver::iterator endpoint_iterator
= resolver
.resolve(query
);
2578 ip::tcp::resolver::iterator end
;
2579 boost::system::error_code error
= asio::error::host_not_found
;
2580 while (error
&& endpoint_iterator
!= end
)
2582 stream
.lowest_layer().close();
2583 stream
.lowest_layer().connect(*endpoint_iterator
++, error
);
2591 bool fNeedHandshake
;
2596 class AcceptedConnection
2599 SSLStream sslStream
;
2600 SSLIOStreamDevice d
;
2601 iostreams::stream
<SSLIOStreamDevice
> stream
;
2603 ip::tcp::endpoint peer
;
2605 AcceptedConnection(asio::io_service
&io_service
, ssl::context
&context
,
2606 bool fUseSSL
) : sslStream(io_service
, context
), d(sslStream
, fUseSSL
),
2610 void ThreadRPCServer(void* parg
)
2612 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg
));
2615 vnThreadsRunning
[THREAD_RPCLISTENER
]++;
2616 ThreadRPCServer2(parg
);
2617 vnThreadsRunning
[THREAD_RPCLISTENER
]--;
2619 catch (std::exception
& e
) {
2620 vnThreadsRunning
[THREAD_RPCLISTENER
]--;
2621 PrintException(&e
, "ThreadRPCServer()");
2623 vnThreadsRunning
[THREAD_RPCLISTENER
]--;
2624 PrintException(NULL
, "ThreadRPCServer()");
2626 printf("ThreadRPCServer exited\n");
2629 void ThreadRPCServer2(void* parg
)
2631 printf("ThreadRPCServer started\n");
2633 strRPCUserColonPass
= mapArgs
["-rpcuser"] + ":" + mapArgs
["-rpcpassword"];
2634 if (mapArgs
["-rpcpassword"] == "")
2636 unsigned char rand_pwd
[32];
2637 RAND_bytes(rand_pwd
, 32);
2638 string strWhatAmI
= "To use bitcoind";
2639 if (mapArgs
.count("-server"))
2640 strWhatAmI
= strprintf(_("To use the %s option"), "\"-server\"");
2641 else if (mapArgs
.count("-daemon"))
2642 strWhatAmI
= strprintf(_("To use the %s option"), "\"-daemon\"");
2643 ThreadSafeMessageBox(strprintf(
2644 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2645 "It is recommended you use the following random password:\n"
2646 "rpcuser=bitcoinrpc\n"
2648 "(you do not need to remember this password)\n"
2649 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2651 GetConfigFile().string().c_str(),
2652 EncodeBase58(&rand_pwd
[0],&rand_pwd
[0]+32).c_str()),
2653 _("Error"), wxOK
| wxMODAL
);
2658 bool fUseSSL
= GetBoolArg("-rpcssl");
2659 asio::ip::address bindAddress
= mapArgs
.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2661 asio::io_service io_service
;
2662 ip::tcp::endpoint
endpoint(bindAddress
, GetArg("-rpcport", 8332));
2663 ip::tcp::acceptor
acceptor(io_service
);
2666 acceptor
.open(endpoint
.protocol());
2667 acceptor
.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2668 acceptor
.bind(endpoint
);
2669 acceptor
.listen(socket_base::max_connections
);
2671 catch(boost::system::system_error
&e
)
2673 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint
.port(), e
.what()),
2674 _("Error"), wxOK
| wxMODAL
);
2679 ssl::context
context(io_service
, ssl::context::sslv23
);
2682 context
.set_options(ssl::context::no_sslv2
);
2684 filesystem::path
pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2685 if (!pathCertFile
.is_complete()) pathCertFile
= filesystem::path(GetDataDir()) / pathCertFile
;
2686 if (filesystem::exists(pathCertFile
)) context
.use_certificate_chain_file(pathCertFile
.string());
2687 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile
.string().c_str());
2689 filesystem::path
pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2690 if (!pathPKFile
.is_complete()) pathPKFile
= filesystem::path(GetDataDir()) / pathPKFile
;
2691 if (filesystem::exists(pathPKFile
)) context
.use_private_key_file(pathPKFile
.string(), ssl::context::pem
);
2692 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile
.string().c_str());
2694 string strCiphers
= GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2695 SSL_CTX_set_cipher_list(context
.impl(), strCiphers
.c_str());
2700 // Accept connection
2701 AcceptedConnection
*conn
=
2702 new AcceptedConnection(io_service
, context
, fUseSSL
);
2704 vnThreadsRunning
[THREAD_RPCLISTENER
]--;
2705 acceptor
.accept(conn
->sslStream
.lowest_layer(), conn
->peer
);
2706 vnThreadsRunning
[THREAD_RPCLISTENER
]++;
2714 // Restrict callers by IP. It is important to
2715 // do this before starting client thread, to filter out
2716 // certain DoS and misbehaving clients.
2717 if (!ClientAllowed(conn
->peer
.address().to_string()))
2719 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2721 conn
->stream
<< HTTPReply(403, "", false) << std::flush
;
2725 // start HTTP client thread
2726 else if (!CreateThread(ThreadRPCServer3
, conn
)) {
2727 printf("Failed to create RPC server client thread\n");
2733 void ThreadRPCServer3(void* parg
)
2735 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer3(parg
));
2736 vnThreadsRunning
[THREAD_RPCHANDLER
]++;
2737 AcceptedConnection
*conn
= (AcceptedConnection
*) parg
;
2741 if (fShutdown
|| !fRun
)
2743 conn
->stream
.close();
2745 --vnThreadsRunning
[THREAD_RPCHANDLER
];
2748 map
<string
, string
> mapHeaders
;
2751 ReadHTTP(conn
->stream
, mapHeaders
, strRequest
);
2753 // Check authorization
2754 if (mapHeaders
.count("authorization") == 0)
2756 conn
->stream
<< HTTPReply(401, "", false) << std::flush
;
2759 if (!HTTPAuthorized(mapHeaders
))
2761 printf("ThreadRPCServer incorrect password attempt from %s\n", conn
->peer
.address().to_string().c_str());
2762 /* Deter brute-forcing short passwords.
2763 If this results in a DOS the user really
2764 shouldn't have their RPC port exposed.*/
2765 if (mapArgs
["-rpcpassword"].size() < 20)
2768 conn
->stream
<< HTTPReply(401, "", false) << std::flush
;
2771 if (mapHeaders
["connection"] == "close")
2774 Value id
= Value::null
;
2779 if (!read_string(strRequest
, valRequest
) || valRequest
.type() != obj_type
)
2780 throw JSONRPCError(-32700, "Parse error");
2781 const Object
& request
= valRequest
.get_obj();
2783 // Parse id now so errors from here on will have the id
2784 id
= find_value(request
, "id");
2787 Value valMethod
= find_value(request
, "method");
2788 if (valMethod
.type() == null_type
)
2789 throw JSONRPCError(-32600, "Missing method");
2790 if (valMethod
.type() != str_type
)
2791 throw JSONRPCError(-32600, "Method must be a string");
2792 string strMethod
= valMethod
.get_str();
2793 if (strMethod
!= "getwork" && strMethod
!= "getmemorypool")
2794 printf("ThreadRPCServer method=%s\n", strMethod
.c_str());
2797 Value valParams
= find_value(request
, "params");
2799 if (valParams
.type() == array_type
)
2800 params
= valParams
.get_array();
2801 else if (valParams
.type() == null_type
)
2804 throw JSONRPCError(-32600, "Params must be an array");
2806 Value result
= tableRPC
.execute(strMethod
, params
);
2809 string strReply
= JSONRPCReply(result
, Value::null
, id
);
2810 conn
->stream
<< HTTPReply(200, strReply
, fRun
) << std::flush
;
2812 catch (Object
& objError
)
2814 ErrorReply(conn
->stream
, objError
, id
);
2817 catch (std::exception
& e
)
2819 ErrorReply(conn
->stream
, JSONRPCError(-32700, e
.what()), id
);
2825 vnThreadsRunning
[THREAD_RPCHANDLER
]--;
2828 json_spirit::Value
CRPCTable::execute(const std::string
&strMethod
, const json_spirit::Array
¶ms
) const
2831 const CRPCCommand
*pcmd
= tableRPC
[strMethod
];
2833 throw JSONRPCError(-32601, "Method not found");
2835 // Observe safe mode
2836 string strWarning
= GetWarnings("rpc");
2837 if (strWarning
!= "" && !GetBoolArg("-disablesafemode") &&
2839 throw JSONRPCError(-2, string("Safe mode: ") + strWarning
);
2846 LOCK2(cs_main
, pwalletMain
->cs_wallet
);
2847 result
= pcmd
->actor(params
, false);
2851 catch (std::exception
& e
)
2853 throw JSONRPCError(-1, e
.what());
2858 Object
CallRPC(const string
& strMethod
, const Array
& params
)
2860 if (mapArgs
["-rpcuser"] == "" && mapArgs
["-rpcpassword"] == "")
2861 throw runtime_error(strprintf(
2862 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2863 "If the file does not exist, create it with owner-readable-only file permissions."),
2864 GetConfigFile().string().c_str()));
2866 // Connect to localhost
2867 bool fUseSSL
= GetBoolArg("-rpcssl");
2868 asio::io_service io_service
;
2869 ssl::context
context(io_service
, ssl::context::sslv23
);
2870 context
.set_options(ssl::context::no_sslv2
);
2871 SSLStream
sslStream(io_service
, context
);
2872 SSLIOStreamDevice
d(sslStream
, fUseSSL
);
2873 iostreams::stream
<SSLIOStreamDevice
> stream(d
);
2874 if (!d
.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2875 throw runtime_error("couldn't connect to server");
2877 // HTTP basic authentication
2878 string strUserPass64
= EncodeBase64(mapArgs
["-rpcuser"] + ":" + mapArgs
["-rpcpassword"]);
2879 map
<string
, string
> mapRequestHeaders
;
2880 mapRequestHeaders
["Authorization"] = string("Basic ") + strUserPass64
;
2883 string strRequest
= JSONRPCRequest(strMethod
, params
, 1);
2884 string strPost
= HTTPPost(strRequest
, mapRequestHeaders
);
2885 stream
<< strPost
<< std::flush
;
2888 map
<string
, string
> mapHeaders
;
2890 int nStatus
= ReadHTTP(stream
, mapHeaders
, strReply
);
2892 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2893 else if (nStatus
>= 400 && nStatus
!= 400 && nStatus
!= 404 && nStatus
!= 500)
2894 throw runtime_error(strprintf("server returned HTTP error %d", nStatus
));
2895 else if (strReply
.empty())
2896 throw runtime_error("no response from server");
2900 if (!read_string(strReply
, valReply
))
2901 throw runtime_error("couldn't parse reply from server");
2902 const Object
& reply
= valReply
.get_obj();
2904 throw runtime_error("expected reply to have result, error and id properties");
2912 template<typename T
>
2913 void ConvertTo(Value
& value
)
2915 if (value
.type() == str_type
)
2917 // reinterpret string as unquoted json value
2919 if (!read_string(value
.get_str(), value2
))
2920 throw runtime_error("type mismatch");
2921 value
= value2
.get_value
<T
>();
2925 value
= value
.get_value
<T
>();
2929 // Convert strings to command-specific RPC representation
2930 Array
RPCConvertValues(const std::string
&strMethod
, const std::vector
<std::string
> &strParams
)
2933 BOOST_FOREACH(const std::string
¶m
, strParams
)
2934 params
.push_back(param
);
2936 int n
= params
.size();
2939 // Special case non-string parameter types
2941 if (strMethod
== "setgenerate" && n
> 0) ConvertTo
<bool>(params
[0]);
2942 if (strMethod
== "setgenerate" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2943 if (strMethod
== "sendtoaddress" && n
> 1) ConvertTo
<double>(params
[1]);
2944 if (strMethod
== "settxfee" && n
> 0) ConvertTo
<double>(params
[0]);
2945 if (strMethod
== "getreceivedbyaddress" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2946 if (strMethod
== "getreceivedbyaccount" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2947 if (strMethod
== "listreceivedbyaddress" && n
> 0) ConvertTo
<boost::int64_t>(params
[0]);
2948 if (strMethod
== "listreceivedbyaddress" && n
> 1) ConvertTo
<bool>(params
[1]);
2949 if (strMethod
== "listreceivedbyaccount" && n
> 0) ConvertTo
<boost::int64_t>(params
[0]);
2950 if (strMethod
== "listreceivedbyaccount" && n
> 1) ConvertTo
<bool>(params
[1]);
2951 if (strMethod
== "getbalance" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2952 if (strMethod
== "getblock" && n
> 1) ConvertTo
<Object
>(params
[1]);
2953 if (strMethod
== "getblockhash" && n
> 0) ConvertTo
<boost::int64_t>(params
[0]);
2954 if (strMethod
== "gettransaction" && n
> 1) ConvertTo
<Object
>(params
[1]);
2955 if (strMethod
== "move" && n
> 2) ConvertTo
<double>(params
[2]);
2956 if (strMethod
== "move" && n
> 3) ConvertTo
<boost::int64_t>(params
[3]);
2957 if (strMethod
== "sendfrom" && n
> 2) ConvertTo
<double>(params
[2]);
2958 if (strMethod
== "sendfrom" && n
> 3) ConvertTo
<boost::int64_t>(params
[3]);
2959 if (strMethod
== "listtransactions" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2960 if (strMethod
== "listtransactions" && n
> 2) ConvertTo
<boost::int64_t>(params
[2]);
2961 if (strMethod
== "listaccounts" && n
> 0) ConvertTo
<boost::int64_t>(params
[0]);
2962 if (strMethod
== "walletpassphrase" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2963 if (strMethod
== "listsinceblock" && n
> 1) ConvertTo
<boost::int64_t>(params
[1]);
2964 if (strMethod
== "sendmany" && n
> 1)
2966 string s
= params
[1].get_str();
2968 if (!read_string(s
, v
) || v
.type() != obj_type
)
2969 throw runtime_error("type mismatch");
2970 params
[1] = v
.get_obj();
2972 if (strMethod
== "sendmany" && n
> 2) ConvertTo
<boost::int64_t>(params
[2]);
2973 if (strMethod
== "addmultisigaddress" && n
> 0) ConvertTo
<boost::int64_t>(params
[0]);
2974 if (strMethod
== "addmultisigaddress" && n
> 1)
2976 string s
= params
[1].get_str();
2978 if (!read_string(s
, v
) || v
.type() != array_type
)
2979 throw runtime_error("type mismatch "+s
);
2980 params
[1] = v
.get_array();
2985 int CommandLineRPC(int argc
, char *argv
[])
2992 while (argc
> 1 && IsSwitchChar(argv
[1][0]))
3000 throw runtime_error("too few parameters");
3001 string strMethod
= argv
[1];
3003 // Parameters default to strings
3004 std::vector
<std::string
> strParams(&argv
[2], &argv
[argc
]);
3005 Array params
= RPCConvertValues(strMethod
, strParams
);
3008 Object reply
= CallRPC(strMethod
, params
);
3011 const Value
& result
= find_value(reply
, "result");
3012 const Value
& error
= find_value(reply
, "error");
3014 if (error
.type() != null_type
)
3017 strPrint
= "error: " + write_string(error
, false);
3018 int code
= find_value(error
.get_obj(), "code").get_int();
3024 if (result
.type() == null_type
)
3026 else if (result
.type() == str_type
)
3027 strPrint
= result
.get_str();
3029 strPrint
= write_string(result
, true);
3032 catch (std::exception
& e
)
3034 strPrint
= string("error: ") + e
.what();
3039 PrintException(NULL
, "CommandLineRPC()");
3044 fprintf((nRet
== 0 ? stdout
: stderr
), "%s\n", strPrint
.c_str());
3053 int main(int argc
, char *argv
[])
3056 // Turn off microsoft heap dump noise
3057 _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
);
3058 _CrtSetReportFile(_CRT_WARN
, CreateFile("NUL", GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0));
3060 setbuf(stdin
, NULL
);
3061 setbuf(stdout
, NULL
);
3062 setbuf(stderr
, NULL
);
3066 if (argc
>= 2 && string(argv
[1]) == "-server")
3068 printf("server ready\n");
3069 ThreadRPCServer(NULL
);
3073 return CommandLineRPC(argc
, argv
);
3076 catch (std::exception
& e
) {
3077 PrintException(&e
, "main()");
3079 PrintException(NULL
, "main()");
3085 const CRPCTable tableRPC
;