Add wallet privkey encryption.
[novacoin.git] / src / rpc.cpp
index df5f123..3a57304 100644 (file)
@@ -4,12 +4,18 @@
 
 #include "headers.h"
 #include "cryptopp/sha.h"
+#include "db.h"
+#include "net.h"
+#include "init.h"
 #undef printf
 #include <boost/asio.hpp>
 #include <boost/iostreams/concepts.hpp>
 #include <boost/iostreams/stream.hpp>
+#include <boost/algorithm/string.hpp>
 #ifdef USE_SSL
 #include <boost/asio/ssl.hpp> 
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
 #endif
 #include "json/json_spirit_reader_template.h"
@@ -21,6 +27,8 @@ typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> 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<uint256, CWalletTx>::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<uint256, CWalletTx>::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<string, string>::iterator mi = mapAddressBook.find(strAddress);
-        if (mi != mapAddressBook.end() && !(*mi).second.empty())
+        map<string, string>::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;
@@ -483,7 +528,12 @@ Value settxfee(const Array& params, bool fHelp)
 
 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 <bitcoinaddress> <amount> [comment] [comment-to]\n"
+            "<amount> 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 <bitcoinaddress> <amount> [comment] [comment-to]\n"
             "<amount> is a real and is rounded to the nearest 0.00000001");
@@ -501,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);
     }
@@ -523,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
@@ -533,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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::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;
@@ -554,9 +608,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
 
 void GetAccountPubKeys(string strAccount, set<CScript>& 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;
@@ -565,7 +619,7 @@ void GetAccountPubKeys(string strAccount, set<CScript>& 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);
             }
         }
@@ -592,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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::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;
@@ -614,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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
         {
             const CWalletTx& wtx = (*it).second;
             if (!wtx.IsFinal())
@@ -640,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);
 }
 
@@ -654,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)
@@ -665,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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
         {
             const CWalletTx& wtx = (*it).second;
             if (!wtx.IsFinal())
@@ -678,9 +732,9 @@ Value getbalance(const Array& params, bool fHelp)
             list<pair<string, int64> > 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;
@@ -713,9 +767,9 @@ 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();
 
         int64 nNow = GetAdjustedTime();
@@ -746,7 +800,12 @@ 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 <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
+            "<amount> 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 <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
             "<amount> is a real and is rounded to the nearest 0.00000001");
@@ -766,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);
     }
@@ -782,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 <fromaccount> {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 <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
             "amounts are double-precision floating point numbers");
@@ -804,7 +873,7 @@ Value sendmany(const Array& params, bool fHelp)
     vector<pair<CScript, int64> > vecSend;
 
     int64 totalAmount = 0;
-    foreach(const Pair& s, sendTo)
+    BOOST_FOREACH(const Pair& s, sendTo)
     {
         uint160 hash160;
         string strAddress = s.name_;
@@ -823,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");
     }
 
@@ -873,9 +946,9 @@ Value ListReceived(const Array& params, bool fByAccounts)
 
     // Tally
     map<uint160, tallyitem> mapTally;
-    CRITICAL_BLOCK(cs_mapWallet)
+    CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
     {
-        for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
         {
             const CWalletTx& wtx = (*it).second;
             if (wtx.IsCoinBase() || !wtx.IsFinal())
@@ -885,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();
@@ -902,9 +975,9 @@ Value ListReceived(const Array& params, bool fByAccounts)
     // Reply
     Array ret;
     map<string, tallyitem> 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;
@@ -1024,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));
@@ -1040,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;
@@ -1098,23 +1171,23 @@ Value listtransactions(const Array& params, bool fHelp)
         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<CWalletTx*, CAccountingEntry*> TxPair;
         typedef multimap<int64, TxPair > TxItems;
         TxItems txByTime;
 
-        for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::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<CAccountingEntry> acentries;
         walletdb.ListAccountCreditDebit(strAccount, acentries);
-        foreach(CAccountingEntry& entry, acentries)
+        BOOST_FOREACH(CAccountingEntry& entry, acentries)
         {
             txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
         }
@@ -1159,16 +1232,16 @@ Value listaccounts(const Array& params, bool fHelp)
         nMinDepth = params[0].get_int();
 
     map<string, int64> 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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
         {
             const CWalletTx& wtx = (*it).second;
             int64 nGeneratedImmature, nGeneratedMature, nFee;
@@ -1177,14 +1250,14 @@ Value listaccounts(const Array& params, bool fHelp)
             list<pair<string, int64> > 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;
             }
@@ -1192,12 +1265,12 @@ Value listaccounts(const Array& params, bool fHelp)
     }
 
     list<CAccountingEntry> 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;
@@ -1214,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();
@@ -1229,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));
     }
 
@@ -1248,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 <passphrase> <timeout>\n"
+            "Stores the wallet decryption key in memory for <timeout> 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 <passphrase> <timeout>\n"
+                "Stores the wallet decryption key in memory for <timeout> 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 <oldpassphrase> <newpassphrase>\n"
+            "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
+    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 <oldpassphrase> <newpassphrase>\n"
+            "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
+
+    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 <passphrase>\n"
+            "Encrypts the wallet with <passphrase>.");
+    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 <passphrase>\n"
+            "Encrypts the wallet with <passphrase>.");
+
+    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;
 }
@@ -1274,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;
@@ -1304,7 +1569,7 @@ Value getwork(const Array& params, bool fHelp)
 
     static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
     static vector<CBlock*> vNewBlock;
-    static CReserveKey reservekey;
+    static CReserveKey reservekey(pwalletMain);
 
     if (params.size() == 0)
     {
@@ -1320,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();
             }
@@ -1385,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);
     }
 }
 
@@ -1405,44 +1670,48 @@ Value getwork(const Array& params, bool fHelp)
 
 pair<string, rpcfn_type> 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("settxfee",              &settxfee),
+    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<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
 
@@ -1466,6 +1735,8 @@ string pAllowInSafeMode[] =
     "getaddressesbyaccount",
     "getaddressesbylabel", // deprecated
     "backupwallet",
+    "keypoolrefill",
+    "walletpassphrase",
     "validateaddress",
     "getwork",
 };
@@ -1490,7 +1761,7 @@ string HTTPPost(const string& strMsg, const map<string,string>& 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;
 
@@ -1510,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"
@@ -1532,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(
@@ -1710,7 +1982,7 @@ bool ClientAllowed(const string& strAddress)
     if (strAddress == asio::ip::address_v4::loopback().to_string())
         return true;
     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
-    foreach(string strAllow, vAllow)
+    BOOST_FOREACH(string strAllow, vAllow)
         if (WildcardMatch(strAddress, strAllow))
             return true;
     return false;
@@ -1865,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<string, string> mapHeaders;
         string strRequest;
@@ -2097,6 +2374,7 @@ int CommandLineRPC(int argc, char *argv[])
         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
+        if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "sendmany"               && n > 1)
         {
             string s = params[1].get_str();