aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2011-07-15 16:08:38 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2011-07-15 16:42:44 +0200
commitd4211176208b5e4ae4a699c6ce3239447752cdb2 (patch)
tree2f1c91d534d1571e3a04c000d66590964bbc213e /src
parenta24b23622e504f5134dd8011af5bbe68cb9443f1 (diff)
parent5b0fc31b1c3d25039262ae2043474b35c14bd30b (diff)
Merge branch 'master' of https://github.com/bitcoin/bitcoin
Diffstat (limited to 'src')
-rw-r--r--src/bitcoinrpc.cpp410
-rw-r--r--src/crypter.cpp132
-rw-r--r--src/crypter.h96
-rw-r--r--src/cryptopp/cpu.cpp2
-rw-r--r--src/db.cpp59
-rw-r--r--src/db.h33
-rw-r--r--src/init.cpp13
-rw-r--r--src/key.h86
-rw-r--r--src/keystore.cpp133
-rw-r--r--src/keystore.h95
-rw-r--r--src/main.cpp10
-rw-r--r--src/main.h1
-rw-r--r--src/makefile.linux-mingw29
-rw-r--r--src/makefile.mingw4
-rw-r--r--src/makefile.osx4
-rw-r--r--src/makefile.unix4
-rw-r--r--src/net.cpp24
-rw-r--r--src/net.h3
-rw-r--r--src/qt/addresstablemodel.cpp7
-rw-r--r--src/script.cpp52
-rw-r--r--src/script.h2
-rw-r--r--src/serialize.h41
-rw-r--r--src/ui.cpp273
-rw-r--r--src/ui.h2
-rw-r--r--src/uibase.cpp10
-rw-r--r--src/uibase.h4
-rw-r--r--src/util.cpp8
-rw-r--r--src/util.h6
-rw-r--r--src/wallet.cpp275
-rw-r--r--src/wallet.h31
30 files changed, 1626 insertions, 223 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 0493c6a08f..872f52eb89 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -36,6 +36,9 @@ void ThreadRPCServer2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;
+static int64 nWalletUnlockTime;
+static CCriticalSection cs_nWalletUnlockTime;
+
Object JSONRPCError(int code, const string& message)
{
@@ -309,7 +312,10 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
+ if (pwalletMain->IsCrypted())
+ obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
@@ -324,13 +330,19 @@ 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(pwalletMain->GetKeyFromKeyPool());
+ string strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
// This could be done in the same main CS as GetKeyFromKeyPool.
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
@@ -346,37 +358,48 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
string strAddress;
CWalletDB walletdb(pwalletMain->strWalletFile);
- walletdb.TxnBegin();
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 = pwalletMain->mapWallet.begin();
- it != pwalletMain->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;
- BOOST_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 = pwalletMain->GetKeyFromKeyPool();
- string strAddress = PubKeyToAddress(account.vchPubKey);
- pwalletMain->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;
@@ -510,7 +533,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");
@@ -528,7 +556,11 @@ Value sendtoaddress(const Array& params, bool fHelp)
wtx.mapValue["to"] = params[3].get_str();
CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
+ 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);
@@ -674,7 +706,7 @@ int64 GetAccountBalance(const string& strAccount, int nMinDepth)
Value getbalance(const Array& params, bool fHelp)
{
- if (fHelp || params.size() < 0 || params.size() > 2)
+ if (fHelp || params.size() > 2)
throw runtime_error(
"getbalance [account] [minconf=1]\n"
"If [account] is not specified, returns the server's total available balance.\n"
@@ -733,9 +765,9 @@ Value movecmd(const Array& params, bool fHelp)
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
int64 nAmount = AmountFromValue(params[2]);
- int nMinDepth = 1;
if (params.size() > 3)
- nMinDepth = params[3].get_int();
+ // unused parameter, used to be nMinDepth, keep type-checking it though
+ (void)params[3].get_int();
string strComment;
if (params.size() > 4)
strComment = params[4].get_str();
@@ -773,7 +805,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");
@@ -794,7 +831,11 @@ Value sendfrom(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main)
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)
@@ -809,9 +850,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");
@@ -851,7 +898,11 @@ Value sendmany(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main)
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)
@@ -1281,6 +1332,219 @@ Value backupwallet(const Array& params, bool fHelp)
}
+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)
+{
+ int64 nMyWakeTime = GetTime() + *((int*)parg);
+
+ if (nWalletUnlockTime == 0)
+ {
+ CRITICAL_BLOCK(cs_nWalletUnlockTime)
+ {
+ nWalletUnlockTime = nMyWakeTime;
+ }
+
+ while (GetTime() < nWalletUnlockTime)
+ Sleep(GetTime() - nWalletUnlockTime);
+
+ CRITICAL_BLOCK(cs_nWalletUnlockTime)
+ {
+ nWalletUnlockTime = 0;
+ }
+ }
+ else
+ {
+ CRITICAL_BLOCK(cs_nWalletUnlockTime)
+ {
+ if (nWalletUnlockTime < nMyWakeTime)
+ nWalletUnlockTime = 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 walletlock(const Array& params, bool fHelp)
+{
+ if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
+ throw runtime_error(
+ "walletlock\n"
+ "Removes the wallet encryption key from memory, locking the wallet.\n"
+ "After calling this method, you will need to call walletpassphrase again\n"
+ "before being able to call any methods which require the wallet to be unlocked.");
+ if (fHelp)
+ return true;
+ if (!pwalletMain->IsCrypted())
+ throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
+
+ pwalletMain->Lock();
+ CRITICAL_BLOCK(cs_nWalletUnlockTime)
+ {
+ nWalletUnlockTime = 0;
+ }
+
+ 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;
+}
+
+
Value validateaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -1432,44 +1696,49 @@ 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("walletlock", &walletlock),
+ 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]));
@@ -1493,6 +1762,9 @@ string pAllowInSafeMode[] =
"getaddressesbyaccount",
"getaddressesbylabel", // deprecated
"backupwallet",
+ "keypoolrefill",
+ "walletpassphrase",
+ "walletlock",
"validateaddress",
"getwork",
};
@@ -2130,6 +2402,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();
@@ -2146,7 +2419,6 @@ int CommandLineRPC(int argc, char *argv[])
// Parse reply
const Value& result = find_value(reply, "result");
const Value& error = find_value(reply, "error");
- const Value& id = find_value(reply, "id");
if (error.type() != null_type)
{
diff --git a/src/crypter.cpp b/src/crypter.cpp
new file mode 100644
index 0000000000..9a8e6ca89a
--- /dev/null
+++ b/src/crypter.cpp
@@ -0,0 +1,132 @@
+// Copyright (c) 2011 The Bitcoin Developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <vector>
+#include <string>
+#include "headers.h"
+#ifdef __WXMSW__
+#include <windows.h>
+#endif
+
+#include "crypter.h"
+#include "main.h"
+#include "util.h"
+
+bool CCrypter::SetKeyFromPassphrase(const std::string& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
+{
+ if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
+ return false;
+
+ // Try to keep the keydata out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
+ // Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
+ // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
+ mlock(&chKey[0], sizeof chKey);
+ mlock(&chIV[0], sizeof chIV);
+
+ int i = 0;
+ if (nDerivationMethod == 0)
+ i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
+ (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
+
+ if (i != WALLET_CRYPTO_KEY_SIZE)
+ {
+ memset(&chKey, 0, sizeof chKey);
+ memset(&chIV, 0, sizeof chIV);
+ return false;
+ }
+
+ fKeySet = true;
+ return true;
+}
+
+bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
+{
+ if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
+ return false;
+
+ // Try to keep the keydata out of swap
+ // Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
+ // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
+ mlock(&chKey[0], sizeof chKey);
+ mlock(&chIV[0], sizeof chIV);
+
+ memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
+ memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
+
+ fKeySet = true;
+ return true;
+}
+
+bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
+{
+ if (!fKeySet)
+ return false;
+
+ // max ciphertext len for a n bytes of plaintext is
+ // n + AES_BLOCK_SIZE - 1 bytes
+ int nLen = vchPlaintext.size();
+ int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
+ vchCiphertext = std::vector<unsigned char> (nCLen);
+
+ EVP_CIPHER_CTX ctx;
+
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
+
+ EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
+ EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen);
+
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ vchCiphertext.resize(nCLen + nFLen);
+ return true;
+}
+
+bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
+{
+ if (!fKeySet)
+ return false;
+
+ // plaintext will always be equal to or lesser than length of ciphertext
+ int nLen = vchCiphertext.size();
+ int nPLen = nLen, nFLen = 0;
+
+ vchPlaintext = CKeyingMaterial(nPLen);
+
+ EVP_CIPHER_CTX ctx;
+
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
+
+ EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
+ EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen);
+
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ vchPlaintext.resize(nPLen + nFLen);
+ return true;
+}
+
+
+bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
+{
+ CCrypter cKeyCrypter;
+ std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
+ memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
+ if(!cKeyCrypter.SetKey(vMasterKey, chIV))
+ return false;
+ return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
+}
+
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
+{
+ CCrypter cKeyCrypter;
+ std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
+ memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
+ if(!cKeyCrypter.SetKey(vMasterKey, chIV))
+ return false;
+ return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
+}
diff --git a/src/crypter.h b/src/crypter.h
new file mode 100644
index 0000000000..5b95ea415e
--- /dev/null
+++ b/src/crypter.h
@@ -0,0 +1,96 @@
+// Copyright (c) 2011 The Bitcoin Developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef __CRYPTER_H__
+#define __CRYPTER_H__
+
+#include "key.h"
+
+const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
+const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
+
+/*
+Private key encryption is done based on a CMasterKey,
+which holds a salt and random encryption key.
+
+CMasterKeys is encrypted using AES-256-CBC using a key
+derived using derivation method nDerivationMethod
+(0 == EVP_sha512()) and derivation iterations nDeriveIterations.
+vchOtherDerivationParameters is provided for alternative algorithms
+which may require more parameters (such as scrypt).
+
+Wallet Private Keys are then encrypted using AES-256-CBC
+with the double-sha256 of the private key as the IV, and the
+master key's key as the encryption key.
+*/
+
+class CMasterKey
+{
+public:
+ std::vector<unsigned char> vchCryptedKey;
+ std::vector<unsigned char> vchSalt;
+ // 0 = EVP_sha512()
+ // 1 = scrypt()
+ unsigned int nDerivationMethod;
+ unsigned int nDeriveIterations;
+ // Use this for more parameters to key derivation,
+ // such as the various parameters to scrypt
+ std::vector<unsigned char> vchOtherDerivationParameters;
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(vchCryptedKey);
+ READWRITE(vchSalt);
+ READWRITE(nDerivationMethod);
+ READWRITE(nDeriveIterations);
+ READWRITE(vchOtherDerivationParameters);
+ )
+ CMasterKey()
+ {
+ // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
+ // ie slightly lower than the lowest hardware we need bother supporting
+ nDeriveIterations = 25000;
+ nDerivationMethod = 0;
+ vchOtherDerivationParameters = std::vector<unsigned char>(0);
+ }
+};
+
+typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
+
+class CCrypter
+{
+private:
+ unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
+ unsigned char chIV[WALLET_CRYPTO_KEY_SIZE];
+ bool fKeySet;
+
+public:
+ bool SetKeyFromPassphrase(const std::string &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);
+ bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext);
+ bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext);
+ bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
+
+ void CleanKey()
+ {
+ memset(&chKey, 0, sizeof chKey);
+ memset(&chIV, 0, sizeof chIV);
+ munlock(&chKey, sizeof chKey);
+ munlock(&chIV, sizeof chIV);
+ fKeySet = false;
+ }
+
+ CCrypter()
+ {
+ fKeySet = false;
+ }
+
+ ~CCrypter()
+ {
+ CleanKey();
+ }
+};
+
+bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext);
+
+#endif
diff --git a/src/cryptopp/cpu.cpp b/src/cryptopp/cpu.cpp
index 3e46804212..8789dc3176 100644
--- a/src/cryptopp/cpu.cpp
+++ b/src/cryptopp/cpu.cpp
@@ -80,7 +80,7 @@ bool CpuId(word32 input, word32 *output)
#endif
}
-#ifndef _MSC_VER
+#if !CRYPTOPP_BOOL_X64 && !defined(_MSC_VER) && defined(__GNUC__)
static jmp_buf s_jmpNoSSE2;
static void SigIllHandlerSSE2(int)
{
diff --git a/src/db.cpp b/src/db.cpp
index f044355a35..6692db239f 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -627,8 +627,6 @@ int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
{
- int64 nCreditDebit = 0;
-
bool fAllAccounts = (strAccount == "*");
Dbc* pcursor = GetCursor();
@@ -670,7 +668,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
}
-bool CWalletDB::LoadWallet(CWallet* pwallet)
+int CWalletDB::LoadWallet(CWallet* pwallet)
{
pwallet->vchDefaultKey.clear();
int nFileVersion = 0;
@@ -685,12 +683,12 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
//// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_mapWallet)
- CRITICAL_BLOCK(pwallet->cs_mapKeys)
+ CRITICAL_BLOCK(pwallet->cs_KeyStore)
{
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
- return false;
+ return DB_CORRUPT;
loop
{
@@ -701,7 +699,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
- return false;
+ return DB_CORRUPT;
// Unserialize
// Taking advantage of the fact that pair serialization
@@ -765,14 +763,42 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
{
vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
- CWalletKey wkey;
+ CKey key;
if (strType == "key")
- ssValue >> wkey.vchPrivKey;
+ {
+ CPrivKey pkey;
+ ssValue >> pkey;
+ key.SetPrivKey(pkey);
+ }
else
+ {
+ CWalletKey wkey;
ssValue >> wkey;
-
- pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey;
- mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
+ key.SetPrivKey(wkey.vchPrivKey);
+ }
+ if (!pwallet->LoadKey(key))
+ return DB_CORRUPT;
+ }
+ else if (strType == "mkey")
+ {
+ unsigned int nID;
+ ssKey >> nID;
+ CMasterKey kMasterKey;
+ ssValue >> kMasterKey;
+ if(pwallet->mapMasterKeys.count(nID) != 0)
+ return DB_CORRUPT;
+ pwallet->mapMasterKeys[nID] = kMasterKey;
+ if (pwallet->nMasterKeyMaxID < nID)
+ pwallet->nMasterKeyMaxID = nID;
+ }
+ else if (strType == "ckey")
+ {
+ vector<unsigned char> vchPubKey;
+ ssKey >> vchPubKey;
+ vector<unsigned char> vchPrivKey;
+ ssValue >> vchPrivKey;
+ if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
+ return DB_CORRUPT;
}
else if (strType == "defaultkey")
{
@@ -800,7 +826,6 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
#endif
if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
- if (strKey == "addrIncoming") ssValue >> addrIncoming;
if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
@@ -809,6 +834,13 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (strKey == "addrProxy") ssValue >> addrProxy;
if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
}
+ else if (strType == "minversion")
+ {
+ int nMinVersion = 0;
+ ssValue >> nMinVersion;
+ if (nMinVersion > VERSION)
+ return DB_TOO_NEW;
+ }
}
pcursor->close();
}
@@ -819,7 +851,6 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
printf("nFileVersion = %d\n", nFileVersion);
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
- printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
printf("fMinimizeToTray = %d\n", fMinimizeToTray);
printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
printf("fUseProxy = %d\n", fUseProxy);
@@ -839,7 +870,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
}
- return true;
+ return DB_LOAD_OK;
}
void ThreadFlushWalletDB(void* parg)
diff --git a/src/db.h b/src/db.h
index b89b34e009..049857b3ab 100644
--- a/src/db.h
+++ b/src/db.h
@@ -88,7 +88,7 @@ protected:
if (!pdb)
return false;
if (fReadOnly)
- assert(("Write called on database in read-only mode", false));
+ assert(!"Write called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK);
@@ -117,7 +117,7 @@ protected:
if (!pdb)
return false;
if (fReadOnly)
- assert(("Erase called on database in read-only mode", false));
+ assert(!"Erase called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK);
@@ -342,6 +342,14 @@ public:
+enum DBErrors
+{
+ DB_LOAD_OK,
+ DB_CORRUPT,
+ DB_TOO_NEW,
+ DB_LOAD_FAIL,
+};
+
class CWalletDB : public CDB
{
public:
@@ -391,6 +399,25 @@ public:
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
}
+ bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
+ {
+ nWalletDBUpdated++;
+ if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
+ return false;
+ if (fEraseUnencryptedKey)
+ {
+ Erase(std::make_pair(std::string("key"), vchPubKey));
+ Erase(std::make_pair(std::string("wkey"), vchPubKey));
+ }
+ return true;
+ }
+
+ bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
+ }
+
bool WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
@@ -450,7 +477,7 @@ public:
int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
- bool LoadWallet(CWallet* pwallet);
+ int LoadWallet(CWallet* pwallet);
};
#endif
diff --git a/src/init.cpp b/src/init.cpp
index adbfa18c6a..b69abb647a 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -386,8 +386,16 @@ bool AppInit2(int argc, char* argv[])
nStart = GetTimeMillis();
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
- if (!pwalletMain->LoadWallet(fFirstRun))
- strErrors += _("Error loading wallet.dat \n");
+ int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
+ if (nLoadWalletRet != DB_LOAD_OK)
+ {
+ if (nLoadWalletRet == DB_CORRUPT)
+ strErrors += _("Error loading wallet.dat: Wallet corrupted \n");
+ else if (nLoadWalletRet == DB_TOO_NEW)
+ strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin \n");
+ else
+ strErrors += _("Error loading wallet.dat \n");
+ }
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
@@ -415,7 +423,6 @@ bool AppInit2(int argc, char* argv[])
//// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
- printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size());
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
diff --git a/src/key.h b/src/key.h
index c973d6eb82..c43e4ee235 100644
--- a/src/key.h
+++ b/src/key.h
@@ -31,6 +31,41 @@
// see www.keylength.com
// script supports up to 75 for single byte push
+int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
+{
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+ EC_POINT *pub_key = NULL;
+
+ if (!eckey) return 0;
+
+ const EC_GROUP *group = EC_KEY_get0_group(eckey);
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ goto err;
+
+ pub_key = EC_POINT_new(group);
+
+ if (pub_key == NULL)
+ goto err;
+
+ if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
+ goto err;
+
+ EC_KEY_set_private_key(eckey,priv_key);
+ EC_KEY_set_public_key(eckey,pub_key);
+
+ ok = 1;
+
+err:
+
+ if (pub_key)
+ EC_POINT_free(pub_key);
+ if (ctx != NULL)
+ BN_CTX_free(ctx);
+
+ return(ok);
+}
class key_error : public std::runtime_error
@@ -42,8 +77,7 @@ public:
// secure_allocator is defined in serialize.h
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
-
-
+typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
class CKey
{
@@ -102,6 +136,38 @@ public:
return true;
}
+ bool SetSecret(const CSecret& vchSecret)
+ {
+ EC_KEY_free(pkey);
+ pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if (pkey == NULL)
+ throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
+ if (vchSecret.size() != 32)
+ throw key_error("CKey::SetSecret() : secret must be 32 bytes");
+ BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
+ if (bn == NULL)
+ throw key_error("CKey::SetSecret() : BN_bin2bn failed");
+ if (!EC_KEY_regenerate_key(pkey,bn))
+ throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
+ BN_clear_free(bn);
+ fSet = true;
+ return true;
+ }
+
+ CSecret GetSecret() const
+ {
+ CSecret vchRet;
+ vchRet.resize(32);
+ const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
+ int nBytes = BN_num_bytes(bn);
+ if (bn == NULL)
+ throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
+ int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
+ if (n != nBytes)
+ throw key_error("CKey::GetSecret(): BN_bn2bin failed");
+ return vchRet;
+ }
+
CPrivKey GetPrivKey() const
{
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
@@ -154,22 +220,6 @@ public:
return false;
return true;
}
-
- static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, std::vector<unsigned char>& vchSig)
- {
- CKey key;
- if (!key.SetPrivKey(vchPrivKey))
- return false;
- return key.Sign(hash, vchSig);
- }
-
- static bool Verify(const std::vector<unsigned char>& vchPubKey, uint256 hash, const std::vector<unsigned char>& vchSig)
- {
- CKey key;
- if (!key.SetPubKey(vchPubKey))
- return false;
- return key.Verify(hash, vchSig);
- }
};
#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index bfad27c6d3..de13958a8b 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -4,13 +4,7 @@
#include "headers.h"
#include "db.h"
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// mapKeys
-//
+#include "crypter.h"
std::vector<unsigned char> CKeyStore::GenerateNewKey()
{
@@ -18,13 +12,14 @@ std::vector<unsigned char> CKeyStore::GenerateNewKey()
CKey key;
key.MakeNewKey();
if (!AddKey(key))
- throw std::runtime_error("GenerateNewKey() : AddKey failed");
+ throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey();
}
-bool CKeyStore::AddKey(const CKey& key)
+bool CBasicKeyStore::AddKey(const CKey& key)
{
- CRITICAL_BLOCK(cs_mapKeys)
+ CRITICAL_BLOCK(cs_mapPubKeys)
+ CRITICAL_BLOCK(cs_KeyStore)
{
mapKeys[key.GetPubKey()] = key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
@@ -32,3 +27,121 @@ bool CKeyStore::AddKey(const CKey& key)
return true;
}
+std::vector<unsigned char> CCryptoKeyStore::GenerateNewKey()
+{
+ RandAddSeedPerfmon();
+ CKey key;
+ key.MakeNewKey();
+ if (!AddKey(key))
+ throw std::runtime_error("CCryptoKeyStore::GenerateNewKey() : AddKey failed");
+ return key.GetPubKey();
+}
+
+bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
+{
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ if (!SetCrypted())
+ return false;
+
+ std::map<std::vector<unsigned char>, std::vector<unsigned char> >::const_iterator mi = mapCryptedKeys.begin();
+ for (; mi != mapCryptedKeys.end(); ++mi)
+ {
+ const std::vector<unsigned char> &vchPubKey = (*mi).first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
+ CSecret vchSecret;
+ if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
+ return false;
+ CKey key;
+ key.SetSecret(vchSecret);
+ if (key.GetPubKey() == vchPubKey)
+ break;
+ return false;
+ }
+ vMasterKey = vMasterKeyIn;
+ }
+ return true;
+}
+
+bool CCryptoKeyStore::AddKey(const CKey& key)
+{
+ CRITICAL_BLOCK(cs_KeyStore)
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ if (!IsCrypted())
+ return CBasicKeyStore::AddKey(key);
+
+ if (IsLocked())
+ return false;
+
+ std::vector<unsigned char> vchCryptedSecret;
+ std::vector<unsigned char> vchPubKey = key.GetPubKey();
+ if (!EncryptSecret(vMasterKey, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
+ return false;
+
+ if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
+ return false;
+ }
+ return true;
+}
+
+
+bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
+{
+ CRITICAL_BLOCK(cs_mapPubKeys)
+ CRITICAL_BLOCK(cs_KeyStore)
+ {
+ if (!SetCrypted())
+ return false;
+
+ mapCryptedKeys[vchPubKey] = vchCryptedSecret;
+ mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
+ }
+ return true;
+}
+
+bool CCryptoKeyStore::GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const
+{
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ if (!IsCrypted())
+ return CBasicKeyStore::GetPrivKey(vchPubKey, keyOut);
+
+ std::map<std::vector<unsigned char>, std::vector<unsigned char> >::const_iterator mi = mapCryptedKeys.find(vchPubKey);
+ if (mi != mapCryptedKeys.end())
+ {
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
+ CSecret vchSecret;
+ if (!DecryptSecret(vMasterKey, (*mi).second, Hash((*mi).first.begin(), (*mi).first.end()), vchSecret))
+ return false;
+ keyOut.SetSecret(vchSecret);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
+{
+ CRITICAL_BLOCK(cs_KeyStore)
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ if (!mapCryptedKeys.empty() || IsCrypted())
+ return false;
+
+ fUseCrypto = true;
+ CKey key;
+ BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
+ {
+ if (!key.SetPrivKey(mKey.second))
+ return false;
+ std::vector<unsigned char> vchCryptedSecret;
+ if (!EncryptSecret(vMasterKeyIn, key.GetSecret(), Hash(mKey.first.begin(), mKey.first.end()), vchCryptedSecret))
+ return false;
+ if (!AddCryptedKey(mKey.first, vchCryptedSecret))
+ return false;
+ }
+ mapKeys.clear();
+ }
+ return true;
+}
diff --git a/src/keystore.h b/src/keystore.h
index 6080d7d7f5..0dc09f05b8 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -4,27 +4,112 @@
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
+#include "crypter.h"
+
class CKeyStore
{
public:
- std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
- mutable CCriticalSection cs_mapKeys;
- virtual bool AddKey(const CKey& key);
+ mutable CCriticalSection cs_KeyStore;
+
+ virtual bool AddKey(const CKey& key) =0;
+ virtual bool HaveKey(const std::vector<unsigned char> &vchPubKey) const =0;
+ virtual bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const =0;
+ virtual std::vector<unsigned char> GenerateNewKey();
+};
+
+typedef std::map<std::vector<unsigned char>, CPrivKey> KeyMap;
+
+class CBasicKeyStore : public CKeyStore
+{
+protected:
+ KeyMap mapKeys;
+
+public:
+ bool AddKey(const CKey& key);
bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
{
return (mapKeys.count(vchPubKey) > 0);
}
- bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CPrivKey& keyOut) const
+ bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const
{
std::map<std::vector<unsigned char>, CPrivKey>::const_iterator mi = mapKeys.find(vchPubKey);
if (mi != mapKeys.end())
{
- keyOut = (*mi).second;
+ keyOut.SetPrivKey((*mi).second);
return true;
}
return false;
}
+};
+
+class CCryptoKeyStore : public CBasicKeyStore
+{
+private:
+ std::map<std::vector<unsigned char>, std::vector<unsigned char> > mapCryptedKeys;
+
+ CKeyingMaterial vMasterKey;
+
+ // if fUseCrypto is true, mapKeys must be empty
+ // if fUseCrypto is false, vMasterKey must be empty
+ bool fUseCrypto;
+
+protected:
+ bool SetCrypted()
+ {
+ if (fUseCrypto)
+ return true;
+ if (!mapKeys.empty())
+ return false;
+ fUseCrypto = true;
+ return true;
+ }
+
+ // will encrypt previously unencrypted keys
+ bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
+
+ bool Unlock(const CKeyingMaterial& vMasterKeyIn);
+
+public:
+ mutable CCriticalSection cs_vMasterKey; //No guarantees master key wont get locked before you can use it, so lock this first
+
+ CCryptoKeyStore() : fUseCrypto(false)
+ {
+ }
+
+ bool IsCrypted() const
+ {
+ return fUseCrypto;
+ }
+
+ bool IsLocked() const
+ {
+ if (!IsCrypted())
+ return false;
+ return vMasterKey.empty();
+ }
+
+ bool Lock()
+ {
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ if (!SetCrypted())
+ return false;
+
+ vMasterKey.clear();
+ }
+ return true;
+ }
+
+ virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
std::vector<unsigned char> GenerateNewKey();
+ bool AddKey(const CKey& key);
+ bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
+ {
+ if (!IsCrypted())
+ return CBasicKeyStore::HaveKey(vchPubKey);
+ return mapCryptedKeys.count(vchPubKey) > 0;
+ }
+ bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const;
};
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 594f1d3bc4..e3ad35044e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -55,7 +55,6 @@ int64 nHPSTimerStart;
// Settings
int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
-CAddress addrIncoming;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
@@ -1689,7 +1688,7 @@ string GetWarnings(string strFor)
return strStatusBar;
else if (strFor == "rpc")
return strRPC;
- assert(("GetWarnings() : invalid parameter", false));
+ assert(!"GetWarnings() : invalid parameter");
return "error";
}
@@ -1900,6 +1899,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return error("message addr size() = %d", vAddr.size());
// Store the new addresses
+ CAddrDB addrDB;
+ addrDB.TxnBegin();
int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
@@ -1911,7 +1912,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
- AddAddress(addr, 2 * 60 * 60);
+ AddAddress(addr, 2 * 60 * 60, &addrDB);
pfrom->AddAddressKnown(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
@@ -1942,6 +1943,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
}
}
+ addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
}
@@ -2213,7 +2215,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
- mapReuseKey[pfrom->addr.ip] = pwalletMain->GetKeyFromKeyPool();
+ mapReuseKey[pfrom->addr.ip] = pwalletMain->GetOrReuseKeyFromPool();
// Send back approval of order and pubkey to use
CScript scriptPubKey;
diff --git a/src/main.h b/src/main.h
index 124c7c2671..d34f68f9d0 100644
--- a/src/main.h
+++ b/src/main.h
@@ -70,7 +70,6 @@ extern std::set<CWallet*> setpwalletRegistered;
// Settings
extern int fGenerateBitcoins;
extern int64 nTransactionFee;
-extern CAddress addrIncoming;
extern int fLimitProcessors;
extern int nLimitProcessors;
extern int fMinimizeToTray;
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 3fb18ff28d..59ff03c48d 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -4,6 +4,8 @@
DEPSDIR:=/usr/i586-mingw32msvc
+USE_UPNP:=0
+
INCLUDEPATHS= \
-I"$(DEPSDIR)/boost_1_43_0" \
-I"$(DEPSDIR)/db-4.7.25.NC/build_unix" \
@@ -34,23 +36,15 @@ DEFS=-D_MT -DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH -DUSE_SSL
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
- script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
-
-bitcoin.exe: USE_UPNP:=1
- ifdef USE_UPNP
- INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
- LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
- LIBS += -l miniupnpc -l iphlpapi
- DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
- endif
-
-bitcoind.exe: USE_UPNP:=0
- ifdef USE_UPNP
- INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
- LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
- LIBS += -l miniupnpc -l iphlpapi
- DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
- endif
+ script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
+ crypter.h init.h
+
+ifdef USE_UPNP
+ INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
+ LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
+ LIBS += -l miniupnpc -l iphlpapi
+ DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
+endif
LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi
@@ -65,6 +59,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
+ obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 507833be48..16a0540094 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -33,7 +33,8 @@ DEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH -DUSE_SSL
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
- script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
+ script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
+ init.h crypter.h
ifdef USE_UPNP
INCLUDEPATHS += -I"C:\upnpc-exe-win32-20110215"
@@ -55,6 +56,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
+ obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o
diff --git a/src/makefile.osx b/src/makefile.osx
index 784596b72d..89788562c3 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -33,7 +33,8 @@ DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
# ppc doesn't work because we don't support big-endian
CFLAGS=-mmacosx-version-min=10.5 -arch i386 -arch x86_64 -O3 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
- script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
+ script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
+ init.h crypter.h
OBJS= \
obj/util.o \
@@ -46,6 +47,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
+ obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o
diff --git a/src/makefile.unix b/src/makefile.unix
index bb26bf5edd..0567f8b75e 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -39,7 +39,8 @@ LIBS+= \
DEBUGFLAGS=-g -D__WXDEBUG__
CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
- script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
+ script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
+ init.h crypter.h
OBJS= \
obj/util.o \
@@ -52,6 +53,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
+ obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o
diff --git a/src/net.cpp b/src/net.cpp
index 0d3348da72..2a90f6d0cc 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -440,7 +440,7 @@ void ThreadGetMyExternalIP(void* parg)
-bool AddAddress(CAddress addr, int64 nTimePenalty)
+bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
{
if (!addr.IsRoutable())
return false;
@@ -455,7 +455,10 @@ bool AddAddress(CAddress addr, int64 nTimePenalty)
// New address
printf("AddAddress(%s)\n", addr.ToString().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
- CAddrDB().WriteAddress(addr);
+ if (pAddrDB)
+ pAddrDB->WriteAddress(addr);
+ else
+ CAddrDB().WriteAddress(addr);
return true;
}
else
@@ -477,7 +480,12 @@ bool AddAddress(CAddress addr, int64 nTimePenalty)
fUpdated = true;
}
if (fUpdated)
- CAddrDB().WriteAddress(addrFound);
+ {
+ if (pAddrDB)
+ pAddrDB->WriteAddress(addrFound);
+ else
+ CAddrDB().WriteAddress(addrFound);
+ }
}
}
return false;
@@ -831,7 +839,7 @@ void ThreadSocketHandler2(void* parg)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
- if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
+ if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
@@ -1158,6 +1166,8 @@ void DNSAddressSeed()
if (!fTestNet)
{
printf("Loading addresses from DNS seeds (could take a while)\n");
+ CAddrDB addrDB;
+ addrDB.TxnBegin();
for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CAddress> vaddr;
@@ -1168,12 +1178,14 @@ void DNSAddressSeed()
if (addr.GetByte(3) != 127)
{
addr.nTime = 0;
- AddAddress(addr);
+ AddAddress(addr, 0, &addrDB);
found++;
}
}
}
}
+
+ addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
}
printf("%d addresses found from DNS seeds\n", found);
@@ -1700,7 +1712,7 @@ void StartNode(void* parg)
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
- pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
+ CreateThread(ThreadSocketHandler, NULL, true);
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
diff --git a/src/net.h b/src/net.h
index 8f21de8dc9..d896defc82 100644
--- a/src/net.h
+++ b/src/net.h
@@ -15,6 +15,7 @@
class CMessageHeader;
class CAddress;
+class CAddrDB;
class CInv;
class CRequestTracker;
class CNode;
@@ -40,7 +41,7 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout
bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool GetMyExternalIP(unsigned int& ipRet);
-bool AddAddress(CAddress addr, int64 nTimePenalty=0);
+bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
void AddressCurrentlyConnected(const CAddress& addr);
CNode* FindNode(unsigned int ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 9ca7542016..4578ca740f 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -38,7 +38,7 @@ struct AddressTablePriv
{
cachedAddressTable.clear();
- CRITICAL_BLOCK(wallet->cs_mapKeys)
+ CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wallet->mapAddressBook)
@@ -255,14 +255,15 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
{
// Generate a new address to associate with given label, optionally
// set as default receiving address.
- strAddress = PubKeyToAddress(wallet->GetKeyFromKeyPool());
+ strAddress = PubKeyToAddress(wallet->GetOrReuseKeyFromPool());
}
else
{
return QString();
}
// Add entry and update list
- wallet->SetAddressBookName(strAddress, strLabel);
+ CRITICAL_BLOCK(wallet->cs_mapAddressBook)
+ wallet->SetAddressBookName(strAddress, strLabel);
updateList();
return QString::fromStdString(strAddress);
}
diff --git a/src/script.cpp b/src/script.cpp
index bd1b5b3c5f..654aaa10e3 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -580,6 +580,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
case OP_ABS: if (bn < bnZero) bn = -bn; break;
case OP_NOT: bn = (bn == bnZero); break;
case OP_0NOTEQUAL: bn = (bn != bnZero); break;
+ default: assert(!"invalid opcode"); break;
}
popstack(stack);
stack.push_back(bn.getvch());
@@ -659,6 +660,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
+ default: assert(!"invalid opcode"); break;
}
popstack(stack);
popstack(stack);
@@ -1030,7 +1032,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false;
// Compile solution
- CRITICAL_BLOCK(keystore.cs_mapKeys)
+ CRITICAL_BLOCK(keystore.cs_KeyStore)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
@@ -1038,13 +1040,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
{
// Sign
const valtype& vchPubKey = item.second;
- CPrivKey privkey;
- if (!keystore.GetPrivKey(vchPubKey, privkey))
+ CKey key;
+ if (!keystore.GetPrivKey(vchPubKey, key))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
- if (!CKey::Sign(privkey, hash, vchSig))
+ if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig;
@@ -1057,13 +1059,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
if (mi == mapPubKeys.end())
return false;
const vector<unsigned char>& vchPubKey = (*mi).second;
- CPrivKey privkey;
- if (!keystore.GetPrivKey(vchPubKey, privkey))
+ CKey key;
+ if (!keystore.GetPrivKey(vchPubKey, key))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
- if (!CKey::Sign(privkey, hash, vchSig))
+ if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << vchPubKey;
@@ -1089,8 +1091,40 @@ bool IsStandard(const CScript& scriptPubKey)
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
- CScript scriptSig;
- return Solver(keystore, scriptPubKey, 0, 0, scriptSig);
+ vector<pair<opcodetype, valtype> > vSolution;
+ if (!Solver(scriptPubKey, vSolution))
+ return false;
+
+ // Compile solution
+ CRITICAL_BLOCK(keystore.cs_KeyStore)
+ {
+ BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ {
+ if (item.first == OP_PUBKEY)
+ {
+ // Sign
+ const valtype& vchPubKey = item.second;
+ if (!keystore.HaveKey(vchPubKey))
+ return false;
+ }
+ else if (item.first == OP_PUBKEYHASH)
+ {
+ // Sign and give pubkey
+ map<uint160, valtype>::iterator mi = mapPubKeys.find(uint160(item.second));
+ if (mi == mapPubKeys.end())
+ return false;
+ const vector<unsigned char>& vchPubKey = (*mi).second;
+ if (!keystore.HaveKey(vchPubKey))
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
diff --git a/src/script.h b/src/script.h
index ae9fdfffa2..2a36db2faf 100644
--- a/src/script.h
+++ b/src/script.h
@@ -486,7 +486,7 @@ public:
{
// I'm not sure if this should push the script or concatenate scripts.
// If there's ever a use for pushing a script onto a script, delete this member fn
- assert(("warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate", false));
+ assert(!"warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate");
return *this;
}
diff --git a/src/serialize.h b/src/serialize.h
index 31862a71a9..cb3a3ea03c 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -28,12 +28,36 @@ typedef unsigned long long uint64;
#if defined(_MSC_VER) && _MSC_VER < 1300
#define for if (false) ; else for
#endif
+
+#ifdef __WXMSW__
+// This is used to attempt to keep keying material out of swap
+// Note that VirtualLock does not provide this as a guarantee on Windows,
+// but, in practice, memory that has been VirtualLock'd almost never gets written to
+// the pagefile except in rare circumstances where memory is extremely low.
+#define mlock(p, n) VirtualLock((p), (n));
+#define munlock(p, n) VirtualUnlock((p), (n));
+#else
+#include <sys/mman.h>
+#include <limits.h>
+/* This comes from limits.h if it's not defined there set a sane default */
+#ifndef PAGESIZE
+#include <unistd.h>
+#define PAGESIZE sysconf(_SC_PAGESIZE)
+#endif
+#define mlock(a,b) \
+ mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
+ (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+#define munlock(a,b) \
+ munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
+ (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+#endif
+
class CScript;
class CDataStream;
class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
-static const int VERSION = 32400;
+static const int VERSION = 32500;
static const char* pszSubVer = "";
static const bool VERSION_IS_BETA = true;
@@ -755,7 +779,8 @@ struct ser_streamplaceholder
//
-// Allocator that clears its contents before deletion
+// Allocator that locks its contents from being paged
+// out of memory and clears its contents before deletion.
//
template<typename T>
struct secure_allocator : public std::allocator<T>
@@ -777,10 +802,22 @@ struct secure_allocator : public std::allocator<T>
template<typename _Other> struct rebind
{ typedef secure_allocator<_Other> other; };
+ T* allocate(std::size_t n, const void *hint = 0)
+ {
+ T *p;
+ p = std::allocator<T>::allocate(n, hint);
+ if (p != NULL)
+ mlock(p, sizeof(T) * n);
+ return p;
+ }
+
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
+ {
memset(p, 0, sizeof(T) * n);
+ munlock(p, sizeof(T) * n);
+ }
std::allocator<T>::deallocate(p, n);
}
};
diff --git a/src/ui.cpp b/src/ui.cpp
index ff0b4afb55..eae0a4f4c8 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -245,6 +245,41 @@ void SetDefaultReceivingAddress(const string& strAddress)
}
}
+bool GetWalletPassphrase()
+{
+ if (pwalletMain->IsLocked())
+ {
+ string strWalletPass;
+ strWalletPass.reserve(100);
+ mlock(&strWalletPass[0], strWalletPass.capacity());
+
+ // obtain current wallet encrypt/decrypt key, from passphrase
+ // Note that the passphrase is not mlock()d during this entry and could potentially
+ // be obtained from disk long after bitcoin has run.
+ strWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
+ _("Passphrase")).ToStdString();
+
+ if (!strWalletPass.size())
+ {
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ wxMessageBox(_("Please supply the current wallet decryption passphrase."), "Bitcoin");
+ return false;
+ }
+
+ if (!pwalletMain->Unlock(strWalletPass))
+ {
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin");
+ return false;
+ }
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ }
+ return true;
+}
+
@@ -333,6 +368,11 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
+ if (pwalletMain->IsCrypted())
+ m_menuOptions->Remove(m_menuOptionsEncryptWallet);
+ else
+ m_menuOptions->Remove(m_menuOptionsChangeWalletPassphrase);
+
// Fill listctrl with wallet transactions
RefreshListCtrl();
}
@@ -1122,6 +1162,169 @@ void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
return;
}
+void CMainFrame::OnMenuOptionsEncryptWallet(wxCommandEvent& event)
+{
+ // Options->Encrypt Wallet
+ if (pwalletMain->IsCrypted())
+ {
+ wxMessageBox(_("Wallet already encrypted."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ string strWalletPass;
+ strWalletPass.reserve(100);
+ mlock(&strWalletPass[0], strWalletPass.capacity());
+
+ // obtain current wallet encrypt/decrypt key, from passphrase
+ // Note that the passphrase is not mlock()d during this entry and could potentially
+ // be obtained from disk long after bitcoin has run.
+ strWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase to the wallet.\nPlease use a passphrase of 10 or more random characters, or eight or more words."),
+ _("Passphrase")).ToStdString();
+
+ if (!strWalletPass.size())
+ {
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ if(wxMessageBox(_("WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR BITCOINS!\nAre you sure you wish to encrypt your wallet?"), "Bitcoin", wxYES_NO) != wxYES)
+ return;
+
+ string strWalletPassTest;
+ strWalletPassTest.reserve(100);
+ mlock(&strWalletPassTest[0], strWalletPassTest.capacity());
+ strWalletPassTest = wxGetPasswordFromUser(_("Please re-enter your new wallet passphrase."),
+ _("Passphrase")).ToStdString();
+
+ if (strWalletPassTest != strWalletPass)
+ {
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
+ wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ if (!pwalletMain->EncryptWallet(strWalletPass))
+ {
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
+ wxMessageBox(_("Wallet encryption failed."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+ fill(strWalletPass.begin(), strWalletPass.end(), '\0');
+ fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
+ munlock(&strWalletPass[0], strWalletPass.capacity());
+ munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
+ wxMessageBox(_("Wallet Encrypted.\nRemember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."), "Bitcoin");
+
+ m_menuOptions->Remove(m_menuOptionsEncryptWallet);
+ m_menuOptions->Insert(m_menuOptions->GetMenuItemCount() - 1, m_menuOptionsChangeWalletPassphrase);
+}
+
+void CMainFrame::OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event)
+{
+ // Options->Change Wallet Encryption Passphrase
+ if (!pwalletMain->IsCrypted())
+ {
+ wxMessageBox(_("Wallet is unencrypted, please encrypt it first."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ string strOldWalletPass;
+ strOldWalletPass.reserve(100);
+ mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
+
+ // obtain current wallet encrypt/decrypt key, from passphrase
+ // Note that the passphrase is not mlock()d during this entry and could potentially
+ // be obtained from disk long after bitcoin has run.
+ strOldWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
+ _("Passphrase")).ToStdString();
+
+ CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
+ {
+ bool fWasLocked = pwalletMain->IsLocked();
+ pwalletMain->Lock();
+
+ if (!strOldWalletPass.size() || !pwalletMain->Unlock(strOldWalletPass))
+ {
+ fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
+ munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
+ wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ if (fWasLocked)
+ pwalletMain->Lock();
+
+ string strNewWalletPass;
+ strNewWalletPass.reserve(100);
+ mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
+
+ // obtain new wallet encrypt/decrypt key, from passphrase
+ // Note that the passphrase is not mlock()d during this entry and could potentially
+ // be obtained from disk long after bitcoin has run.
+ strNewWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase for the wallet."),
+ _("Passphrase")).ToStdString();
+
+ if (!strNewWalletPass.size())
+ {
+ fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
+ fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
+ munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
+ munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
+ wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ string strNewWalletPassTest;
+ strNewWalletPassTest.reserve(100);
+ mlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
+
+ // obtain new wallet encrypt/decrypt key, from passphrase
+ // Note that the passphrase is not mlock()d during this entry and could potentially
+ // be obtained from disk long after bitcoin has run.
+ strNewWalletPassTest = wxGetPasswordFromUser(_("Re-enter the new passphrase for the wallet."),
+ _("Passphrase")).ToStdString();
+
+ if (strNewWalletPassTest != strNewWalletPass)
+ {
+ fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
+ fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
+ fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
+ munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
+ munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
+ munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
+ wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+
+ if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
+ {
+ fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
+ fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
+ fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
+ munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
+ munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
+ munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
+ wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
+ return;
+ }
+ fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
+ fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
+ fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
+ munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
+ munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
+ munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
+ wxMessageBox(_("Wallet Passphrase Changed."), "Bitcoin");
+ }
+}
+
void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
{
// Options->Options
@@ -1182,8 +1385,19 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
return;
string strName = dialog.GetValue();
- // Generate new key
- string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
+ string strAddress;
+ CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
+ {
+ bool fWasLocked = pwalletMain->IsLocked();
+ if (!GetWalletPassphrase())
+ return;
+
+ // Generate new key
+ strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
+
+ if (fWasLocked)
+ pwalletMain->Lock();
+ }
// Save
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
@@ -1947,7 +2161,12 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (fBitcoinAddress)
{
CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
+ bool fWasLocked = pwalletMain->IsLocked();
+ if (!GetWalletPassphrase())
+ return;
+
// Send to bitcoin address
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
@@ -1956,13 +2175,22 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError == "ABORTED")
+ {
+ if (fWasLocked)
+ pwalletMain->Lock();
return; // leave send dialog open
+ }
else
{
wxMessageBox(strError + " ", _("Sending..."));
EndModal(false);
+ if (fWasLocked)
+ pwalletMain->Lock();
return;
}
+
+ if (fWasLocked)
+ pwalletMain->Lock();
}
}
else
@@ -2246,16 +2474,27 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
Error(_("Insufficient funds"));
return;
}
+
CReserveKey reservekey(pwalletMain);
int64 nFeeRequired;
- if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
+ CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
- if (nPrice + nFeeRequired > pwalletMain->GetBalance())
- Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
- else
- Error(_("Transaction creation failed"));
- return;
- }
+ bool fWasLocked = pwalletMain->IsLocked();
+ if (!GetWalletPassphrase())
+ return;
+
+ if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
+ {
+ if (nPrice + nFeeRequired > pwalletMain->GetBalance())
+ Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
+ else
+ Error(_("Transaction creation failed"));
+ return;
+ }
+
+ if (fWasLocked)
+ pwalletMain->Lock();
+ }
// Transaction fee
if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
@@ -2382,7 +2621,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data
- CRITICAL_BLOCK(pwalletMain->cs_mapKeys)
+ CRITICAL_BLOCK(pwalletMain->cs_KeyStore)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
@@ -2581,8 +2820,18 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
return;
strName = dialog.GetValue();
- // Generate new key
- strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
+ CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
+ {
+ bool fWasLocked = pwalletMain->IsLocked();
+ if (!GetWalletPassphrase())
+ return;
+
+ // Generate new key
+ strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
+
+ if (fWasLocked)
+ pwalletMain->Lock();
+ }
}
// Add to list and select it
diff --git a/src/ui.h b/src/ui.h
index 3f06ad90cb..3bf741534c 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -59,6 +59,8 @@ protected:
void OnMenuFileExit(wxCommandEvent& event);
void OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event);
void OnMenuOptionsChangeYourAddress(wxCommandEvent& event);
+ void OnMenuOptionsEncryptWallet(wxCommandEvent& event);
+ void OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event);
void OnMenuOptionsOptions(wxCommandEvent& event);
void OnMenuHelpAbout(wxCommandEvent& event);
void OnButtonSend(wxCommandEvent& event);
diff --git a/src/uibase.cpp b/src/uibase.cpp
index 1b901a1edb..18eec44138 100644
--- a/src/uibase.cpp
+++ b/src/uibase.cpp
@@ -32,6 +32,12 @@ CMainFrameBase::CMainFrameBase( wxWindow* parent, wxWindowID id, const wxString&
m_menuOptionsChangeYourAddress = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Your Receiving Addresses...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsChangeYourAddress );
+ m_menuOptionsEncryptWallet = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Encrypt Wallet...") ) , wxEmptyString, wxITEM_NORMAL );
+ m_menuOptions->Append( m_menuOptionsEncryptWallet );
+
+ m_menuOptionsChangeWalletPassphrase = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Change Wallet Encryption Passphrase...") ) , wxEmptyString, wxITEM_NORMAL );
+ m_menuOptions->Append( m_menuOptionsChangeWalletPassphrase );
+
wxMenuItem* m_menuOptionsOptions;
m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_PREFERENCES, wxString( _("&Options...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsOptions );
@@ -187,6 +193,8 @@ CMainFrameBase::CMainFrameBase( wxWindow* parent, wxWindowID id, const wxString&
this->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Connect( m_menuFileExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) );
this->Connect( m_menuOptionsChangeYourAddress->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) );
+ this->Connect( m_menuOptionsEncryptWallet->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsEncryptWallet ) );
+ this->Connect( m_menuOptionsChangeWalletPassphrase->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeWalletPassphrase ) );
this->Connect( m_menuOptionsOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Connect( m_menuHelpAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Connect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );
@@ -245,6 +253,8 @@ CMainFrameBase::~CMainFrameBase()
this->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) );
+ this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsEncryptWallet ) );
+ this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeWalletPassphrase ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Disconnect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );
diff --git a/src/uibase.h b/src/uibase.h
index 78f3d1b385..ca0730b20e 100644
--- a/src/uibase.h
+++ b/src/uibase.h
@@ -98,6 +98,8 @@ class CMainFrameBase : public wxFrame
virtual void OnPaint( wxPaintEvent& event ) { event.Skip(); }
virtual void OnMenuFileExit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsChangeYourAddress( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnMenuOptionsEncryptWallet( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnMenuOptionsChangeWalletPassphrase( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsOptions( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuHelpAbout( wxCommandEvent& event ) { event.Skip(); }
virtual void OnButtonSend( wxCommandEvent& event ) { event.Skip(); }
@@ -115,6 +117,8 @@ class CMainFrameBase : public wxFrame
public:
wxMenu* m_menuOptions;
+ wxMenuItem* m_menuOptionsEncryptWallet;
+ wxMenuItem* m_menuOptionsChangeWalletPassphrase;
wxStatusBar* m_statusBar;
wxTextCtrl* m_textCtrlAddress;
wxListCtrl* m_listCtrlAll;
diff --git a/src/util.cpp b/src/util.cpp
index 3d89f6a829..7cd92d2e8e 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -758,8 +758,8 @@ string GetPidFile()
void CreatePidFile(string pidFile, pid_t pid)
{
- FILE* file;
- if (file = fopen(pidFile.c_str(), "w"))
+ FILE* file = fopen(pidFile.c_str(), "w");
+ if (file)
{
fprintf(file, "%d\n", pid);
fclose(file);
@@ -788,7 +788,9 @@ void ShrinkDebugFile()
fseek(file, -sizeof(pch), SEEK_END);
int nBytes = fread(pch, 1, sizeof(pch), file);
fclose(file);
- if (file = fopen(strFile.c_str(), "w"))
+
+ file = fopen(strFile.c_str(), "w");
+ if (file)
{
fwrite(pch, 1, nBytes, file);
fclose(file);
diff --git a/src/util.h b/src/util.h
index 4c1e74b7da..7ac36c0f4a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -262,7 +262,7 @@ public:
// I'd rather be careful than suffer the other more error prone syntax.
// The compiler will optimise away all this loop junk.
#define CRITICAL_BLOCK(cs) \
- for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
+ for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \
for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
class CTryCriticalBlock
@@ -276,7 +276,7 @@ public:
};
#define TRY_CRITICAL_BLOCK(cs) \
- for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
+ for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by TRY_CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \
for (CTryCriticalBlock criticalblock(cs); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()) && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
@@ -646,7 +646,7 @@ inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
return (pthread_cancel(hthread) == 0);
}
-inline void ExitThread(unsigned int nExitCode)
+inline void ExitThread(size_t nExitCode)
{
pthread_exit((void*)nExitCode);
}
diff --git a/src/wallet.cpp b/src/wallet.cpp
index fa57755242..3e1bb8e287 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -5,11 +5,11 @@
#include "headers.h"
#include "db.h"
#include "cryptopp/sha.h"
+#include "crypter.h"
using namespace std;
-
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
@@ -17,10 +17,181 @@ using namespace std;
bool CWallet::AddKey(const CKey& key)
{
- this->CKeyStore::AddKey(key);
+ if (!CCryptoKeyStore::AddKey(key))
+ return false;
if (!fFileBacked)
return true;
- return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
+ if (!IsCrypted())
+ return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
+ return true;
+}
+
+bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
+{
+ if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
+ return false;
+ if (!fFileBacked)
+ return true;
+ CRITICAL_BLOCK(cs_pwalletdbEncryption)
+ {
+ if (pwalletdbEncryption)
+ return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ else
+ return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ }
+}
+
+bool CWallet::Unlock(const string& strWalletPassphrase)
+{
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ if (!IsLocked())
+ return false;
+
+ CCrypter crypter;
+ CKeyingMaterial vMasterKey;
+
+ BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ {
+ if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
+ return false;
+ if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
+ return false;
+ if (CCryptoKeyStore::Unlock(vMasterKey))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
+{
+ CRITICAL_BLOCK(cs_vMasterKey)
+ {
+ bool fWasLocked = IsLocked();
+
+ Lock();
+
+ CCrypter crypter;
+ CKeyingMaterial vMasterKey;
+ BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ {
+ if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
+ return false;
+ if(!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
+ return false;
+ if (CCryptoKeyStore::Unlock(vMasterKey))
+ {
+ int64 nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
+ pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
+
+ nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
+ pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+
+ if (pMasterKey.second.nDeriveIterations < 25000)
+ pMasterKey.second.nDeriveIterations = 25000;
+
+ printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
+
+ if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
+ return false;
+ if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
+ return false;
+ CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
+ if (fWasLocked)
+ Lock();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+// This class implements an addrIncoming entry that causes pre-0.4
+// clients to crash on startup if reading a private-key-encrypted wallet.
+class CCorruptAddress
+{
+public:
+ IMPLEMENT_SERIALIZE
+ (
+ if (nType & SER_DISK)
+ READWRITE(nVersion);
+ )
+};
+
+bool CWallet::EncryptWallet(const string& strWalletPassphrase)
+{
+ CRITICAL_BLOCK(cs_mapPubKeys)
+ CRITICAL_BLOCK(cs_KeyStore)
+ CRITICAL_BLOCK(cs_vMasterKey)
+ CRITICAL_BLOCK(cs_pwalletdbEncryption)
+ {
+ if (IsCrypted())
+ return false;
+
+ CKeyingMaterial vMasterKey;
+ RandAddSeedPerfmon();
+
+ vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
+ RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
+
+ CMasterKey kMasterKey;
+
+ RandAddSeedPerfmon();
+ kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
+ RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
+
+ CCrypter crypter;
+ int64 nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
+ kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
+
+ nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
+ kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+
+ if (kMasterKey.nDeriveIterations < 25000)
+ kMasterKey.nDeriveIterations = 25000;
+
+ printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
+
+ if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
+ return false;
+ if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
+ return false;
+
+ mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
+ if (fFileBacked)
+ {
+ pwalletdbEncryption = new CWalletDB(strWalletFile);
+ pwalletdbEncryption->TxnBegin();
+ pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
+ }
+
+ if (!EncryptKeys(vMasterKey))
+ {
+ if (fFileBacked)
+ pwalletdbEncryption->TxnAbort();
+ exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
+ }
+
+ if (fFileBacked)
+ {
+ CCorruptAddress corruptAddress;
+ pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
+ if (!pwalletdbEncryption->TxnCommit())
+ exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
+
+ pwalletdbEncryption->Close();
+ pwalletdbEncryption = NULL;
+ }
+
+ Lock();
+ }
+ return true;
}
void CWallet::WalletUpdateSpent(const CTransaction &tx)
@@ -98,7 +269,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
if (txout.scriptPubKey == scriptDefaultKey)
- SetDefaultKey(GetKeyFromKeyPool());
+ {
+ SetDefaultKey(GetOrReuseKeyFromPool());
+ SetAddressBookName(PubKeyToAddress(vchDefaultKey), "");
+ }
}
#endif
// Notify UI
@@ -552,8 +726,6 @@ void CWallet::ResendWalletTransactions()
int64 CWallet::GetBalance() const
{
- int64 nStart = GetTimeMillis();
-
int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
@@ -566,7 +738,6 @@ int64 CWallet::GetBalance() const
}
}
- //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
return nTotal;
}
@@ -798,7 +969,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
// Reserve a new key pair from key pool
vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
- assert(mapKeys.count(vchPubKey));
+ // assert(mapKeys.count(vchPubKey));
// Fill a vout to ourself, using same address type as the payment
CScript scriptChange;
@@ -918,15 +1089,24 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
{
CReserveKey reservekey(this);
int64 nFeeRequired;
- if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
+ CRITICAL_BLOCK(cs_vMasterKey)
{
- string strError;
- if (nValue + nFeeRequired > GetBalance())
- strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
- else
- strError = _("Error: Transaction creation failed ");
- printf("SendMoney() : %s", strError.c_str());
- return strError;
+ if (IsLocked())
+ {
+ string strError = _("Error: Wallet locked, unable to create transaction ");
+ printf("SendMoney() : %s", strError.c_str());
+ return strError;
+ }
+ if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
+ {
+ string strError;
+ if (nValue + nFeeRequired > GetBalance())
+ strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
+ else
+ strError = _("Error: Transaction creation failed ");
+ printf("SendMoney() : %s", strError.c_str());
+ return strError;
+ }
}
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
@@ -961,27 +1141,28 @@ string CWallet::SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWall
-bool CWallet::LoadWallet(bool& fFirstRunRet)
+int CWallet::LoadWallet(bool& fFirstRunRet)
{
if (!fFileBacked)
return false;
fFirstRunRet = false;
- if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this))
- return false;
+ int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
+ if (nLoadWalletRet != DB_LOAD_OK)
+ return nLoadWalletRet;
fFirstRunRet = vchDefaultKey.empty();
- if (!mapKeys.count(vchDefaultKey))
+ if (!HaveKey(vchDefaultKey))
{
- // Create new default key
+ // Create new keyUser and set as default key
RandAddSeedPerfmon();
- SetDefaultKey(GetKeyFromKeyPool());
+ SetDefaultKey(GetOrReuseKeyFromPool());
if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
- return false;
+ return DB_LOAD_FAIL;
}
CreateThread(ThreadFlushWalletDB, &strWalletFile);
- return true;
+ return DB_LOAD_OK;
}
@@ -1048,14 +1229,16 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
+bool CWallet::TopUpKeyPool()
{
- nIndex = -1;
- keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
+ CRITICAL_BLOCK(cs_vMasterKey)
{
+ if (IsLocked())
+ return false;
+
CWalletDB walletdb(strWalletFile);
// Top up key pool
@@ -1066,18 +1249,36 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
- throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
+ throw runtime_error("TopUpKeyPool() : writing generated key failed");
setKeyPool.insert(nEnd);
printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
}
+ }
+ return true;
+}
+
+void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
+{
+ nIndex = -1;
+ keypool.vchPubKey.clear();
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(cs_setKeyPool)
+ {
+ if (!IsLocked())
+ TopUpKeyPool();
// Get the oldest key
- assert(!setKeyPool.empty());
+ if(setKeyPool.empty())
+ return;
+
+ CWalletDB walletdb(strWalletFile);
+
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed");
- if (!mapKeys.count(keypool.vchPubKey))
+ if (!HaveKey(keypool.vchPubKey))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
assert(!keypool.vchPubKey.empty());
printf("keypool reserve %"PRI64d"\n", nIndex);
@@ -1106,11 +1307,13 @@ void CWallet::ReturnKey(int64 nIndex)
printf("keypool return %"PRI64d"\n", nIndex);
}
-vector<unsigned char> CWallet::GetKeyFromKeyPool()
+vector<unsigned char> CWallet::GetOrReuseKeyFromPool()
{
int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
+ if(nIndex == -1)
+ return vchDefaultKey;
KeepKey(nIndex);
return keypool.vchPubKey;
}
@@ -1120,6 +1323,8 @@ int64 CWallet::GetOldestKeyPoolTime()
int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
+ if (nIndex == -1)
+ return GetTime();
ReturnKey(nIndex);
return keypool.nTime;
}
@@ -1130,7 +1335,13 @@ vector<unsigned char> CReserveKey::GetReservedKey()
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
- vchPubKey = keypool.vchPubKey;
+ if (nIndex != -1)
+ vchPubKey = keypool.vchPubKey;
+ else
+ {
+ printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
+ vchPubKey = pwallet->vchDefaultKey;
+ }
}
assert(!vchPubKey.empty());
return vchPubKey;
diff --git a/src/wallet.h b/src/wallet.h
index 078d7e6e97..490745a717 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -12,12 +12,14 @@ class CWalletTx;
class CReserveKey;
class CWalletDB;
-class CWallet : public CKeyStore
+class CWallet : public CCryptoKeyStore
{
private:
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
+ CWalletDB *pwalletdbEncryption;
+ CCriticalSection cs_pwalletdbEncryption;
public:
bool fFileBacked;
@@ -26,14 +28,22 @@ public:
std::set<int64> setKeyPool;
CCriticalSection cs_setKeyPool;
+ typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
+ MasterKeyMap mapMasterKeys;
+ unsigned int nMasterKeyMaxID;
+
CWallet()
{
fFileBacked = false;
+ nMasterKeyMaxID = 0;
+ pwalletdbEncryption = NULL;
}
CWallet(std::string strWalletFileIn)
{
strWalletFile = strWalletFileIn;
fFileBacked = true;
+ nMasterKeyMaxID = 0;
+ pwalletdbEncryption = NULL;
}
mutable CCriticalSection cs_mapWallet;
@@ -48,7 +58,16 @@ public:
std::vector<unsigned char> vchDefaultKey;
+ // keystore implementation
bool AddKey(const CKey& key);
+ bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
+ bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+ bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
+
+ bool Unlock(const std::string& strWalletPassphrase);
+ bool ChangeWalletPassphrase(const std::string& strOldWalletPassphrase, const std::string& strNewWalletPassphrase);
+ bool EncryptWallet(const std::string& strWalletPassphrase);
+
bool AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
bool EraseFromWallet(uint256 hash);
@@ -65,10 +84,11 @@ public:
std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+ bool TopUpKeyPool();
void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
void KeepKey(int64 nIndex);
void ReturnKey(int64 nIndex);
- std::vector<unsigned char> GetKeyFromKeyPool();
+ std::vector<unsigned char> GetOrReuseKeyFromPool();
int64 GetOldestKeyPoolTime();
bool IsMine(const CTxIn& txin) const;
@@ -148,7 +168,7 @@ public:
walletdb.WriteBestBlock(loc);
}
- bool LoadWallet(bool& fFirstRunRet);
+ int LoadWallet(bool& fFirstRunRet);
// bool BackupWallet(const std::string& strDest);
// requires cs_mapAddressBook lock
@@ -175,6 +195,11 @@ public:
}
}
+ int GetKeyPoolSize()
+ {
+ return setKeyPool.size();
+ }
+
bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);