X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Frpc.cpp;h=3a573043f735e287a66be0e6e63d8e3bff376341;hb=4e87d341f75f13bbd7d108c31c03886fbc4df56f;hp=90e7f15a9164c945d619f5286636c40c56ea0ca6;hpb=84c3fb07b0b8199c7f85c5de280e7100bad0786f;p=novacoin.git diff --git a/src/rpc.cpp b/src/rpc.cpp index 90e7f15..3a57304 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -4,12 +4,18 @@ #include "headers.h" #include "cryptopp/sha.h" +#include "db.h" +#include "net.h" +#include "init.h" #undef printf #include #include #include +#include #ifdef USE_SSL #include +#include +#include typedef boost::asio::ssl::stream SSLStream; #endif #include "json/json_spirit_reader_template.h" @@ -21,6 +27,8 @@ typedef boost::asio::ssl::stream SSLStream; // a certain size around 145MB. If we need access to json_spirit outside this // file, we could use the compiled json_spirit option. +using namespace std; +using namespace boost; using namespace boost::asio; using namespace json_spirit; @@ -81,7 +89,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain())); entry.push_back(Pair("txid", wtx.GetHash().GetHex())); entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); - foreach(const PAIRTYPE(string,string)& item, wtx.mapValue) + BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } @@ -197,12 +205,26 @@ double GetDifficulty() { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. + if (pindexBest == NULL) return 1.0; - int nShift = 256 - 32 - 31; // to fit in a uint - double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint(); - double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint(); - return dMinimum / dCurrently; + int nShift = (pindexBest->nBits >> 24) & 0xff; + + double dDiff = + (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff); + + while (nShift < 29) + { + dDiff *= 256.0; + nShift++; + } + while (nShift > 29) + { + dDiff /= 256.0; + nShift--; + } + + return dDiff; } Value getdifficulty(const Array& params, bool fHelp) @@ -243,14 +265,14 @@ Value setgenerate(const Array& params, bool fHelp) { int nGenProcLimit = params[1].get_int(); fLimitProcessors = (nGenProcLimit != -1); - CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors); + WriteSetting("fLimitProcessors", fLimitProcessors); if (nGenProcLimit != -1) - CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); + WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); if (nGenProcLimit == 0) fGenerate = false; } - GenerateBitcoins(fGenerate); + GenerateBitcoins(fGenerate, pwalletMain); return Value::null; } @@ -277,7 +299,7 @@ Value getinfo(const Array& params, bool fHelp) Object obj; obj.push_back(Pair("version", (int)VERSION)); - obj.push_back(Pair("balance", ValueFromAmount(GetBalance()))); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("blocks", (int)nBestHeight)); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); @@ -286,7 +308,8 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("testnet", fTestNet)); - obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; @@ -302,56 +325,76 @@ Value getnewaddress(const Array& params, bool fHelp) "If [account] is specified (recommended), it is added to the address book " "so payments received with the address will be credited to [account]."); + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + if (pwalletMain->GetKeyPoolSize() < 1) + throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first"); + // Parse the account first so we don't generate a key if there's an error string strAccount; if (params.size() > 0) strAccount = AccountFromValue(params[0]); // Generate a new key that is added to wallet - string strAddress = PubKeyToAddress(GetKeyFromKeyPool()); + string strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool()); + + // This could be done in the same main CS as GetKeyFromKeyPool. + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) + pwalletMain->SetAddressBookName(strAddress, strAccount); - SetAddressBookName(strAddress, strAccount); return strAddress; } -// requires cs_main, cs_mapWallet locks +// requires cs_main, cs_mapWallet, cs_mapAddressBook locks string GetAccountAddress(string strAccount, bool bForceNew=false) { string strAddress; - CWalletDB walletdb; - walletdb.TxnBegin(); + CWalletDB walletdb(pwalletMain->strWalletFile); CAccount account; - walletdb.ReadAccount(strAccount, account); - - // Check if the current key has been used - if (!account.vchPubKey.empty()) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - CScript scriptPubKey; - scriptPubKey.SetBitcoinAddress(account.vchPubKey); - for (map::iterator it = mapWallet.begin(); - it != mapWallet.end() && !account.vchPubKey.empty(); - ++it) + walletdb.ReadAccount(strAccount, account); + + bool bKeyUsed = false; + + // Check if the current key has been used + if (!account.vchPubKey.empty()) { - const CWalletTx& wtx = (*it).second; - foreach(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - account.vchPubKey.clear(); + CScript scriptPubKey; + scriptPubKey.SetBitcoinAddress(account.vchPubKey); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty(); + ++it) + { + const CWalletTx& wtx = (*it).second; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + bKeyUsed = true; + } } - } - // Generate a new key - if (account.vchPubKey.empty() || bForceNew) - { - account.vchPubKey = GetKeyFromKeyPool(); - string strAddress = PubKeyToAddress(account.vchPubKey); - SetAddressBookName(strAddress, strAccount); - walletdb.WriteAccount(strAccount, account); + // Generate a new key + if (account.vchPubKey.empty() || bForceNew || bKeyUsed) + { + if (pwalletMain->GetKeyPoolSize() < 1) + { + if (bKeyUsed || bForceNew) + throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first"); + } + else + { + account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool(); + string strAddress = PubKeyToAddress(account.vchPubKey); + pwalletMain->SetAddressBookName(strAddress, strAccount); + walletdb.WriteAccount(strAccount, account); + } + } } - walletdb.TxnCommit(); strAddress = PubKeyToAddress(account.vchPubKey); return strAddress; @@ -370,7 +413,8 @@ Value getaccountaddress(const Array& params, bool fHelp) Value ret; CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { ret = GetAccountAddress(strAccount); } @@ -400,18 +444,19 @@ Value setaccount(const Array& params, bool fHelp) // Detect when changing the account of an address that is the 'unused current key' of another account: CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - if (mapAddressBook.count(strAddress)) + if (pwalletMain->mapAddressBook.count(strAddress)) { - string strOldAccount = mapAddressBook[strAddress]; + string strOldAccount = pwalletMain->mapAddressBook[strAddress]; if (strAddress == GetAccountAddress(strOldAccount)) GetAccountAddress(strOldAccount, true); } + + pwalletMain->SetAddressBookName(strAddress, strAccount); } - SetAddressBookName(strAddress, strAccount); return Value::null; } @@ -426,10 +471,10 @@ Value getaccount(const Array& params, bool fHelp) string strAddress = params[0].get_str(); string strAccount; - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - map::iterator mi = mapAddressBook.find(strAddress); - if (mi != mapAddressBook.end() && !(*mi).second.empty()) + map::iterator mi = pwalletMain->mapAddressBook.find(strAddress); + if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) strAccount = (*mi).second; } return strAccount; @@ -447,9 +492,9 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) // Find all addresses that have the given account Array ret; - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - foreach(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { const string& strAddress = item.first; const string& strName = item.second; @@ -465,12 +510,33 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) return ret; } +Value settxfee(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "settxfee \n" + " is a real and is rounded to the nearest 0.00000001"); + + // Amount + int64 nAmount = 0; + if (params[0].get_real() != 0.0) + nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts + + nTransactionFee = nAmount; + return true; +} + Value sendtoaddress(const Array& params, bool fHelp) { - if (fHelp || params.size() < 2 || params.size() > 4) + if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4)) throw runtime_error( "sendtoaddress [comment] [comment-to]\n" - " is a real and is rounded to the nearest 0.01"); + " is a real and is rounded to the nearest 0.00000001\n" + "requires wallet passphrase to be set with walletpassphrase first"); + if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4)) + throw runtime_error( + "sendtoaddress [comment] [comment-to]\n" + " is a real and is rounded to the nearest 0.00000001"); string strAddress = params[0].get_str(); @@ -485,8 +551,12 @@ Value sendtoaddress(const Array& params, bool fHelp) wtx.mapValue["to"] = params[3].get_str(); CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) { - string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); + if(pwalletMain->IsLocked()) + throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); + + string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); if (strError != "") throw JSONRPCError(-4, strError); } @@ -507,7 +577,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) CScript scriptPubKey; if (!scriptPubKey.SetBitcoinAddress(strAddress)) throw JSONRPCError(-5, "Invalid bitcoin address"); - if (!IsMine(scriptPubKey)) + if (!IsMine(*pwalletMain,scriptPubKey)) return (double)0.0; // Minimum confirmations @@ -517,15 +587,15 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) // Tally int64 nAmount = 0; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !wtx.IsFinal()) continue; - foreach(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (txout.scriptPubKey == scriptPubKey) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; @@ -538,9 +608,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) void GetAccountPubKeys(string strAccount, set& setPubKey) { - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - foreach(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { const string& strAddress = item.first; const string& strName = item.second; @@ -549,7 +619,7 @@ void GetAccountPubKeys(string strAccount, set& setPubKey) // We're only counting our own valid bitcoin addresses and not ip addresses CScript scriptPubKey; if (scriptPubKey.SetBitcoinAddress(strAddress)) - if (IsMine(scriptPubKey)) + if (IsMine(*pwalletMain,scriptPubKey)) setPubKey.insert(scriptPubKey); } } @@ -576,15 +646,15 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) // Tally int64 nAmount = 0; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !wtx.IsFinal()) continue; - foreach(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (setPubKey.count(txout.scriptPubKey)) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; @@ -598,10 +668,10 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) { int64 nBalance = 0; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { // Tally wallet transactions - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!wtx.IsFinal()) @@ -624,7 +694,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD int64 GetAccountBalance(const string& strAccount, int nMinDepth) { - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); return GetAccountBalance(walletdb, strAccount, nMinDepth); } @@ -638,7 +708,7 @@ Value getbalance(const Array& params, bool fHelp) "If [account] is specified, returns the balance in the account."); if (params.size() == 0) - return ValueFromAmount(GetBalance()); + return ValueFromAmount(pwalletMain->GetBalance()); int nMinDepth = 1; if (params.size() > 1) @@ -649,7 +719,7 @@ Value getbalance(const Array& params, bool fHelp) // (GetBalance() sums up all unspent TxOuts) // getbalance and getbalance '*' should always return the same number. int64 nBalance = 0; - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!wtx.IsFinal()) @@ -662,9 +732,9 @@ Value getbalance(const Array& params, bool fHelp) list > listSent; wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); if (wtx.GetDepthInMainChain() >= nMinDepth) - foreach(const PAIRTYPE(string,int64)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived) nBalance += r.second; - foreach(const PAIRTYPE(string,int64)& r, listSent) + BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listSent) nBalance -= r.second; nBalance -= allFee; nBalance += allGeneratedMature; @@ -697,26 +767,11 @@ Value movecmd(const Array& params, bool fHelp) if (params.size() > 4) strComment = params[4].get_str(); - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); walletdb.TxnBegin(); - // Check funds - if (!strFrom.empty()) - { - int64 nBalance = GetAccountBalance(walletdb, strFrom, nMinDepth); - if (nAmount > nBalance) - throw JSONRPCError(-6, "Account has insufficient funds"); - } - else - { - // move from "" account special case - int64 nBalance = GetAccountBalance(walletdb, strTo, nMinDepth); - if (nAmount > GetBalance() - nBalance) - throw JSONRPCError(-6, "Account has insufficient funds"); - } - int64 nNow = GetAdjustedTime(); // Debit @@ -745,10 +800,15 @@ Value movecmd(const Array& params, bool fHelp) Value sendfrom(const Array& params, bool fHelp) { - if (fHelp || params.size() < 3 || params.size() > 6) + if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6)) + throw runtime_error( + "sendfrom [minconf=1] [comment] [comment-to]\n" + " is a real and is rounded to the nearest 0.00000001\n" + "requires wallet passphrase to be set with walletpassphrase first"); + if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6)) throw runtime_error( "sendfrom [minconf=1] [comment] [comment-to]\n" - " is a real and is rounded to the nearest 0.01"); + " is a real and is rounded to the nearest 0.00000001"); string strAccount = AccountFromValue(params[0]); string strAddress = params[1].get_str(); @@ -765,15 +825,19 @@ Value sendfrom(const Array& params, bool fHelp) wtx.mapValue["to"] = params[5].get_str(); CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) { + if(pwalletMain->IsLocked()) + throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); + // Check funds int64 nBalance = GetAccountBalance(strAccount, nMinDepth); if (nAmount > nBalance) throw JSONRPCError(-6, "Account has insufficient funds"); // Send - string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); + string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); if (strError != "") throw JSONRPCError(-4, strError); } @@ -781,9 +845,15 @@ Value sendfrom(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } + Value sendmany(const Array& params, bool fHelp) { - if (fHelp || params.size() < 2 || params.size() > 4) + if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4)) + throw runtime_error( + "sendmany {address:amount,...} [minconf=1] [comment]\n" + "amounts are double-precision floating point numbers\n" + "requires wallet passphrase to be set with walletpassphrase first"); + if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4)) throw runtime_error( "sendmany {address:amount,...} [minconf=1] [comment]\n" "amounts are double-precision floating point numbers"); @@ -803,7 +873,7 @@ Value sendmany(const Array& params, bool fHelp) vector > vecSend; int64 totalAmount = 0; - foreach(const Pair& s, sendTo) + BOOST_FOREACH(const Pair& s, sendTo) { uint160 hash160; string strAddress = s.name_; @@ -822,24 +892,28 @@ Value sendmany(const Array& params, bool fHelp) } CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) { + if(pwalletMain->IsLocked()) + throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); + // Check funds int64 nBalance = GetAccountBalance(strAccount, nMinDepth); if (totalAmount > nBalance) throw JSONRPCError(-6, "Account has insufficient funds"); // Send - CReserveKey keyChange; + CReserveKey keyChange(pwalletMain); int64 nFeeRequired = 0; - bool fCreated = CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); if (!fCreated) { - if (totalAmount + nFeeRequired > GetBalance()) + if (totalAmount + nFeeRequired > pwalletMain->GetBalance()) throw JSONRPCError(-6, "Insufficient funds"); throw JSONRPCError(-4, "Transaction creation failed"); } - if (!CommitTransaction(wtx, keyChange)) + if (!pwalletMain->CommitTransaction(wtx, keyChange)) throw JSONRPCError(-4, "Transaction commit failed"); } @@ -872,9 +946,9 @@ Value ListReceived(const Array& params, bool fByAccounts) // Tally map mapTally; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !wtx.IsFinal()) @@ -884,7 +958,7 @@ Value ListReceived(const Array& params, bool fByAccounts) if (nDepth < nMinDepth) continue; - foreach(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.vout) { // Only counting our own bitcoin addresses and not ip addresses uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160(); @@ -901,9 +975,9 @@ Value ListReceived(const Array& params, bool fByAccounts) // Reply Array ret; map mapAccountTally; - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - foreach(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { const string& strAddress = item.first; const string& strAccount = item.second; @@ -1023,7 +1097,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Sent if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { - foreach(const PAIRTYPE(string, int64)& s, listSent) + BOOST_FOREACH(const PAIRTYPE(string, int64)& s, listSent) { Object entry; entry.push_back(Pair("account", strSentAccount)); @@ -1039,13 +1113,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - foreach(const PAIRTYPE(string, int64)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived) { string account; - if (mapAddressBook.count(r.first)) - account = mapAddressBook[r.first]; + if (pwalletMain->mapAddressBook.count(r.first)) + account = pwalletMain->mapAddressBook[r.first]; if (fAllAccounts || (account == strAccount)) { Object entry; @@ -1081,10 +1155,10 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar Value listtransactions(const Array& params, bool fHelp) { - if (fHelp || params.size() > 2) + if (fHelp || params.size() > 3) throw runtime_error( - "listtransactions [account] [count=10]\n" - "Returns up to [count] most recent transactions for account ."); + "listtransactions [account] [count=10] [from=0]\n" + "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account]."); string strAccount = "*"; if (params.size() > 0) @@ -1092,31 +1166,35 @@ Value listtransactions(const Array& params, bool fHelp) int nCount = 10; if (params.size() > 1) nCount = params[1].get_int(); + int nFrom = 0; + if (params.size() > 2) + nFrom = params[2].get_int(); Array ret; - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap: typedef pair TxPair; typedef multimap TxItems; TxItems txByTime; - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0))); } list acentries; walletdb.ListAccountCreditDebit(strAccount, acentries); - foreach(CAccountingEntry& entry, acentries) + BOOST_FOREACH(CAccountingEntry& entry, acentries) { txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } // Now: iterate backwards until we have nCount items to return: - for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it) + TxItems::reverse_iterator it = txByTime.rbegin(); + for (std::advance(it, nFrom); it != txByTime.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) @@ -1154,16 +1232,16 @@ Value listaccounts(const Array& params, bool fHelp) nMinDepth = params[0].get_int(); map mapAccountBalances; - CRITICAL_BLOCK(cs_mapWallet) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - foreach(const PAIRTYPE(string, string)& entry, mapAddressBook) { + BOOST_FOREACH(const PAIRTYPE(string, string)& entry, pwalletMain->mapAddressBook) { uint160 hash160; if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me mapAccountBalances[entry.second] = 0; } - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; int64 nGeneratedImmature, nGeneratedMature, nFee; @@ -1172,14 +1250,14 @@ Value listaccounts(const Array& params, bool fHelp) list > listSent; wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); mapAccountBalances[strSentAccount] -= nFee; - foreach(const PAIRTYPE(string, int64)& s, listSent) + BOOST_FOREACH(const PAIRTYPE(string, int64)& s, listSent) mapAccountBalances[strSentAccount] -= s.second; if (wtx.GetDepthInMainChain() >= nMinDepth) { mapAccountBalances[""] += nGeneratedMature; - foreach(const PAIRTYPE(string, int64)& r, listReceived) - if (mapAddressBook.count(r.first)) - mapAccountBalances[mapAddressBook[r.first]] += r.second; + BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived) + if (pwalletMain->mapAddressBook.count(r.first)) + mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; else mapAccountBalances[""] += r.second; } @@ -1187,12 +1265,12 @@ Value listaccounts(const Array& params, bool fHelp) } list acentries; - CWalletDB().ListAccountCreditDebit("*", acentries); - foreach(const CAccountingEntry& entry, acentries) + CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); + BOOST_FOREACH(const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; Object ret; - foreach(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) { + BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; @@ -1209,11 +1287,11 @@ Value gettransaction(const Array& params, bool fHelp) hash.SetHex(params[0].get_str()); Object entry; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - if (!mapWallet.count(hash)) + if (!pwalletMain->mapWallet.count(hash)) throw JSONRPCError(-5, "Invalid or non-wallet transaction id"); - const CWalletTx& wtx = mapWallet[hash]; + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; int64 nCredit = wtx.GetCredit(); int64 nDebit = wtx.GetDebit(); @@ -1224,10 +1302,10 @@ Value gettransaction(const Array& params, bool fHelp) if (wtx.IsFromMe()) entry.push_back(Pair("fee", ValueFromAmount(nFee))); - WalletTxToJSON(mapWallet[hash], entry); + WalletTxToJSON(pwalletMain->mapWallet[hash], entry); Array details; - ListTransactions(mapWallet[hash], "*", 0, false, details); + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); entry.push_back(Pair("details", details)); } @@ -1243,7 +1321,199 @@ Value backupwallet(const Array& params, bool fHelp) "Safely copies wallet.dat to destination, which can be a directory or a path with filename."); string strDest = params[0].get_str(); - BackupWallet(strDest); + BackupWallet(*pwalletMain, strDest); + + return Value::null; +} + + +Value keypoolrefill(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0)) + throw runtime_error( + "keypoolrefill\n" + "Fills the keypool, requires wallet passphrase to be set."); + if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0)) + throw runtime_error( + "keypoolrefill\n" + "Fills the keypool."); + + CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) + { + if (pwalletMain->IsLocked()) + throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + pwalletMain->TopUpKeyPool(); + } + + if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100)) + throw JSONRPCError(-4, "Error refreshing keypool."); + + return Value::null; +} + + +void ThreadTopUpKeyPool(void* parg) +{ + pwalletMain->TopUpKeyPool(); +} + +void ThreadCleanWalletPassphrase(void* parg) +{ + static int64 nWakeTime; + int64 nMyWakeTime = GetTime() + *((int*)parg); + static CCriticalSection cs_nWakeTime; + + if (nWakeTime == 0) + { + CRITICAL_BLOCK(cs_nWakeTime) + { + nWakeTime = nMyWakeTime; + } + + while (GetTime() < nWakeTime) + Sleep(GetTime() - nWakeTime); + + CRITICAL_BLOCK(cs_nWakeTime) + { + nWakeTime = 0; + } + } + else + { + CRITICAL_BLOCK(cs_nWakeTime) + { + if (nWakeTime < nMyWakeTime) + nWakeTime = nMyWakeTime; + } + free(parg); + return; + } + + pwalletMain->Lock(); + + delete (int*)parg; +} + +Value walletpassphrase(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) + throw runtime_error( + "walletpassphrase \n" + "Stores the wallet decryption key in memory for seconds."); + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called."); + + if (!pwalletMain->IsLocked()) + throw JSONRPCError(-17, "Error: Wallet is already unlocked."); + + // Note that the walletpassphrase is stored in params[0] which is not mlock()ed + string strWalletPass; + strWalletPass.reserve(100); + mlock(&strWalletPass[0], strWalletPass.capacity()); + strWalletPass = params[0].get_str(); + + CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) + { + if (strWalletPass.length() > 0) + { + if (!pwalletMain->Unlock(strWalletPass)) + { + fill(strWalletPass.begin(), strWalletPass.end(), '\0'); + munlock(&strWalletPass[0], strWalletPass.capacity()); + throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); + } + fill(strWalletPass.begin(), strWalletPass.end(), '\0'); + munlock(&strWalletPass[0], strWalletPass.capacity()); + } + else + throw runtime_error( + "walletpassphrase \n" + "Stores the wallet decryption key in memory for seconds."); + } + + CreateThread(ThreadTopUpKeyPool, NULL); + int* pnSleepTime = new int(params[1].get_int()); + CreateThread(ThreadCleanWalletPassphrase, pnSleepTime); + + return Value::null; +} + + +Value walletpassphrasechange(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); + + string strOldWalletPass; + strOldWalletPass.reserve(100); + mlock(&strOldWalletPass[0], strOldWalletPass.capacity()); + strOldWalletPass = params[0].get_str(); + + string strNewWalletPass; + strNewWalletPass.reserve(100); + mlock(&strNewWalletPass[0], strNewWalletPass.capacity()); + strNewWalletPass = params[1].get_str(); + + if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + + if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) + { + fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); + fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); + munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); + munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); + throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); + } + fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); + fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); + munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); + munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); + + return Value::null; +} + + +Value encryptwallet(const Array& params, bool fHelp) +{ + if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + if (fHelp) + return true; + if (pwalletMain->IsCrypted()) + throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called."); + + string strWalletPass; + strWalletPass.reserve(100); + mlock(&strWalletPass[0], strWalletPass.capacity()); + strWalletPass = params[0].get_str(); + + if (strWalletPass.length() < 1) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + + if (!pwalletMain->EncryptWallet(strWalletPass)) + { + fill(strWalletPass.begin(), strWalletPass.end(), '\0'); + munlock(&strWalletPass[0], strWalletPass.capacity()); + throw JSONRPCError(-16, "Error: Failed to encrypt the wallet."); + } + fill(strWalletPass.begin(), strWalletPass.end(), '\0'); + munlock(&strWalletPass[0], strWalletPass.capacity()); return Value::null; } @@ -1269,10 +1539,10 @@ Value validateaddress(const Array& params, bool fHelp) string currentAddress = Hash160ToAddress(hash160); ret.push_back(Pair("address", currentAddress)); ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0))); - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - if (mapAddressBook.count(currentAddress)) - ret.push_back(Pair("account", mapAddressBook[currentAddress])); + if (pwalletMain->mapAddressBook.count(currentAddress)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[currentAddress])); } } return ret; @@ -1299,7 +1569,7 @@ Value getwork(const Array& params, bool fHelp) static map > mapNewBlock; static vector vNewBlock; - static CReserveKey reservekey; + static CReserveKey reservekey(pwalletMain); if (params.size() == 0) { @@ -1315,7 +1585,7 @@ Value getwork(const Array& params, bool fHelp) { // Deallocate old blocks since they're obsolete now mapNewBlock.clear(); - foreach(CBlock* pblock, vNewBlock) + BOOST_FOREACH(CBlock* pblock, vNewBlock) delete pblock; vNewBlock.clear(); } @@ -1380,7 +1650,7 @@ Value getwork(const Array& params, bool fHelp) pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - return CheckWork(pblock, reservekey); + return CheckWork(pblock, *pwalletMain, reservekey); } } @@ -1400,43 +1670,48 @@ Value getwork(const Array& params, bool fHelp) pair pCallTable[] = { - make_pair("help", &help), - make_pair("stop", &stop), - make_pair("getblockcount", &getblockcount), - make_pair("getblocknumber", &getblocknumber), - make_pair("getconnectioncount", &getconnectioncount), - make_pair("getdifficulty", &getdifficulty), - make_pair("getgenerate", &getgenerate), - make_pair("setgenerate", &setgenerate), - make_pair("gethashespersec", &gethashespersec), - make_pair("getinfo", &getinfo), - make_pair("getnewaddress", &getnewaddress), - make_pair("getaccountaddress", &getaccountaddress), - make_pair("setaccount", &setaccount), - make_pair("setlabel", &setaccount), // deprecated - make_pair("getaccount", &getaccount), - make_pair("getlabel", &getaccount), // deprecated - make_pair("getaddressesbyaccount", &getaddressesbyaccount), - make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated - make_pair("sendtoaddress", &sendtoaddress), - make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress - make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress - make_pair("getreceivedbyaddress", &getreceivedbyaddress), - make_pair("getreceivedbyaccount", &getreceivedbyaccount), - make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated - make_pair("listreceivedbyaddress", &listreceivedbyaddress), - make_pair("listreceivedbyaccount", &listreceivedbyaccount), - make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated - make_pair("backupwallet", &backupwallet), - make_pair("validateaddress", &validateaddress), - make_pair("getbalance", &getbalance), - make_pair("move", &movecmd), - make_pair("sendfrom", &sendfrom), - make_pair("sendmany", &sendmany), - make_pair("gettransaction", &gettransaction), - make_pair("listtransactions", &listtransactions), - make_pair("getwork", &getwork), - make_pair("listaccounts", &listaccounts), + make_pair("help", &help), + make_pair("stop", &stop), + make_pair("getblockcount", &getblockcount), + make_pair("getblocknumber", &getblocknumber), + make_pair("getconnectioncount", &getconnectioncount), + make_pair("getdifficulty", &getdifficulty), + make_pair("getgenerate", &getgenerate), + make_pair("setgenerate", &setgenerate), + make_pair("gethashespersec", &gethashespersec), + make_pair("getinfo", &getinfo), + make_pair("getnewaddress", &getnewaddress), + make_pair("getaccountaddress", &getaccountaddress), + make_pair("setaccount", &setaccount), + make_pair("setlabel", &setaccount), // deprecated + make_pair("getaccount", &getaccount), + make_pair("getlabel", &getaccount), // deprecated + make_pair("getaddressesbyaccount", &getaddressesbyaccount), + make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated + make_pair("sendtoaddress", &sendtoaddress), + make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress + make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress + make_pair("getreceivedbyaddress", &getreceivedbyaddress), + make_pair("getreceivedbyaccount", &getreceivedbyaccount), + make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated + make_pair("listreceivedbyaddress", &listreceivedbyaddress), + make_pair("listreceivedbyaccount", &listreceivedbyaccount), + make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated + make_pair("backupwallet", &backupwallet), + make_pair("keypoolrefill", &keypoolrefill), + make_pair("walletpassphrase", &walletpassphrase), + make_pair("walletpassphrasechange", &walletpassphrasechange), + make_pair("encryptwallet", &encryptwallet), + make_pair("validateaddress", &validateaddress), + make_pair("getbalance", &getbalance), + make_pair("move", &movecmd), + make_pair("sendfrom", &sendfrom), + make_pair("sendmany", &sendmany), + make_pair("gettransaction", &gettransaction), + make_pair("listtransactions", &listtransactions), + make_pair("getwork", &getwork), + make_pair("listaccounts", &listaccounts), + make_pair("settxfee", &settxfee), }; map mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); @@ -1460,6 +1735,8 @@ string pAllowInSafeMode[] = "getaddressesbyaccount", "getaddressesbylabel", // deprecated "backupwallet", + "keypoolrefill", + "walletpassphrase", "validateaddress", "getwork", }; @@ -1484,7 +1761,7 @@ string HTTPPost(const string& strMsg, const map& mapRequestHeader << "Content-Type: application/json\r\n" << "Content-Length: " << strMsg.size() << "\r\n" << "Accept: application/json\r\n"; - foreach(const PAIRTYPE(string, string)& item, mapRequestHeaders) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders) s << item.first << ": " << item.second << "\r\n"; s << "\r\n" << strMsg; @@ -1504,7 +1781,7 @@ string rfc1123Time() return string(buffer); } -string HTTPReply(int nStatus, const string& strMsg) +static string HTTPReply(int nStatus, const string& strMsg) { if (nStatus == 401) return strprintf("HTTP/1.0 401 Authorization Required\r\n" @@ -1526,6 +1803,7 @@ string HTTPReply(int nStatus, const string& strMsg) string strStatus; if (nStatus == 200) strStatus = "OK"; else if (nStatus == 400) strStatus = "Bad Request"; + else if (nStatus == 403) strStatus = "Forbidden"; else if (nStatus == 404) strStatus = "Not Found"; else if (nStatus == 500) strStatus = "Internal Server Error"; return strprintf( @@ -1570,10 +1848,11 @@ int ReadHTTPHeader(std::basic_istream& stream, map& mapHea { string strHeader = str.substr(0, nColon); boost::trim(strHeader); + boost::to_lower(strHeader); string strValue = str.substr(nColon+1); boost::trim(strValue); mapHeadersRet[strHeader] = strValue; - if (strHeader == "Content-Length") + if (strHeader == "content-length") nLen = atoi(strValue.c_str()); } } @@ -1643,7 +1922,7 @@ string DecodeBase64(string s) bool HTTPAuthorized(map& mapHeaders) { - string strAuth = mapHeaders["Authorization"]; + string strAuth = mapHeaders["authorization"]; if (strAuth.substr(0,6) != "Basic ") return false; string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); @@ -1703,7 +1982,7 @@ bool ClientAllowed(const string& strAddress) if (strAddress == asio::ip::address_v4::loopback().to_string()) return true; const vector& vAllow = mapMultiArgs["-rpcallowip"]; - foreach(string strAllow, vAllow) + BOOST_FOREACH(string strAllow, vAllow) if (WildcardMatch(strAddress, strAllow)) return true; return false; @@ -1858,7 +2137,12 @@ void ThreadRPCServer2(void* parg) // Restrict callers by IP if (!ClientAllowed(peer.address().to_string())) + { + // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake. + if (!fUseSSL) + stream << HTTPReply(403, "") << std::flush; continue; + } map mapHeaders; string strRequest; @@ -1872,7 +2156,7 @@ void ThreadRPCServer2(void* parg) } // Check authorization - if (mapHeaders.count("Authorization") == 0) + if (mapHeaders.count("authorization") == 0) { stream << HTTPReply(401, "") << std::flush; continue; @@ -2069,6 +2353,7 @@ int CommandLineRPC(int argc, char *argv[]) if (strMethod == "setgenerate" && n > 0) ConvertTo(params[0]); if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); + if (strMethod == "settxfee" && n > 0) ConvertTo(params[0]); if (strMethod == "getamountreceived" && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo(params[1]); @@ -2087,7 +2372,9 @@ int CommandLineRPC(int argc, char *argv[]) if (strMethod == "sendfrom" && n > 2) ConvertTo(params[2]); if (strMethod == "sendfrom" && n > 3) ConvertTo(params[3]); if (strMethod == "listtransactions" && n > 1) ConvertTo(params[1]); + if (strMethod == "listtransactions" && n > 2) ConvertTo(params[2]); if (strMethod == "listaccounts" && n > 0) ConvertTo(params[0]); + if (strMethod == "walletpassphrase" && n > 1) ConvertTo(params[1]); if (strMethod == "sendmany" && n > 1) { string s = params[1].get_str();