Wladimir J. van der Laan 14 years ago
parent
commit
d421117620
  1. 6
      bitcoin-qt.pro
  2. 4
      contrib/Bitcoin.app/Contents/Info.plist
  3. 45
      doc/README
  4. 2
      doc/README_windows.txt
  5. 528
      locale/pl/LC_MESSAGES/bitcoin.po
  6. BIN
      locale/sv/LC_MESSAGES/bitcoin.mo
  7. 473
      locale/sv/LC_MESSAGES/bitcoin.po
  8. BIN
      share/pixmaps/bitcoin.ico
  9. BIN
      share/pixmaps/nsis-header.bmp
  10. BIN
      share/pixmaps/nsis-wizard.bmp
  11. 13
      share/setup.nsi
  12. 30
      share/uiproject.fbp
  13. 410
      src/bitcoinrpc.cpp
  14. 132
      src/crypter.cpp
  15. 96
      src/crypter.h
  16. 2
      src/cryptopp/cpu.cpp
  17. 59
      src/db.cpp
  18. 33
      src/db.h
  19. 13
      src/init.cpp
  20. 86
      src/key.h
  21. 133
      src/keystore.cpp
  22. 95
      src/keystore.h
  23. 10
      src/main.cpp
  24. 1
      src/main.h
  25. 29
      src/makefile.linux-mingw
  26. 4
      src/makefile.mingw
  27. 4
      src/makefile.osx
  28. 4
      src/makefile.unix
  29. 24
      src/net.cpp
  30. 3
      src/net.h
  31. 7
      src/qt/addresstablemodel.cpp
  32. 52
      src/script.cpp
  33. 2
      src/script.h
  34. 41
      src/serialize.h
  35. 273
      src/ui.cpp
  36. 2
      src/ui.h
  37. 10
      src/uibase.cpp
  38. 4
      src/uibase.h
  39. 8
      src/util.cpp
  40. 6
      src/util.h
  41. 275
      src/wallet.cpp
  42. 31
      src/wallet.h

6
bitcoin-qt.pro

@ -83,7 +83,8 @@ HEADERS += src/qt/bitcoingui.h \
src/bitcoinrpc.h \ src/bitcoinrpc.h \
src/qt/overviewpage.h \ src/qt/overviewpage.h \
src/qt/csvmodelwriter.h \ src/qt/csvmodelwriter.h \
src/qt/qtwin.h src/qt/qtwin.h \
src/crypter.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiontablemodel.cpp \ src/qt/transactiontablemodel.cpp \
src/qt/addresstablemodel.cpp \ src/qt/addresstablemodel.cpp \
@ -122,7 +123,8 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/bitcoinrpc.cpp \ src/bitcoinrpc.cpp \
src/qt/overviewpage.cpp \ src/qt/overviewpage.cpp \
src/qt/csvmodelwriter.cpp \ src/qt/csvmodelwriter.cpp \
src/qt/qtwin.cpp src/qt/qtwin.cpp \
src/crypter.cpp
RESOURCES += \ RESOURCES += \
src/qt/bitcoin.qrc src/qt/bitcoin.qrc

4
contrib/Bitcoin.app/Contents/Info.plist

@ -17,11 +17,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.3.24</string> <string>0.3.25</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>324</string> <string>325</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.5</string> <string>10.5</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>

45
doc/README

@ -1,4 +1,4 @@
Bitcoin 0.3.24 BETA Bitcoin 0.3.25 BETA
Copyright (c) 2009-2011 Bitcoin Developers Copyright (c) 2009-2011 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying Distributed under the MIT/X11 software license, see the accompanying
@ -24,6 +24,49 @@ Unpack the files into a directory and run:
bin/64/bitcoin (GUI, 64-bit) bin/64/bitcoin (GUI, 64-bit)
bin/64/bitcoind (headless, 64-bit) bin/64/bitcoind (headless, 64-bit)
Wallet Encryption
-----------------
Bitcoin supports native wallet encryption so that people who steal your
wallet file don't automatically get access to all of your Bitcoins.
In order to enable this feature, chose "Encrypt Wallet" from the
Options menu. You will be prompted to enter a passphrase, which
will be used as the key to encrypt your wallet and will be needed
every time you wish to send Bitcoins. If you lose this passphrase,
you will lose access to spend all of the bitcoins in your wallet,
no one, not even the Bitcoin developers can recover your Bitcoins.
This means you are responsible for your own security, store your
password in a secure location and do not forget it.
Remember that the encryption built into bitcoin only encrypts the
actual keys which are required to send your bitcoins, not the full
wallet. This means that someone who steals your wallet file will
be able to see all the addresses which belong to you, as well as the
relevant transactions, you are only protected from someone spending
your coins.
It is recommended that you backup your wallet file before you
encrypt your wallet. To do this, close the Bitcoin client and
copy the wallet.dat file from ~/.bitcoin/ on Linux, /Users/(user
name)/Application Support/Bitcoin/ on Mac OSX, and %APPDATA%/Bitcoin/
on Windows (that is /Users/(user name)/AppData/Roaming/Bitcoin on
Windows Vista and 7 and /Documents and Settings/(user name)/Application
Data/Bitcoin on Windows XP). Once you have copied that file to a
safe location, reopen the Bitcoin client and Encrypt your wallet.
If everything goes fine, delete the backup and enjoy your encrypted
wallet. Note that once you encrypt your wallet, you will never be
able to go back to a version of the Bitcoin client older than 0.4.
Keep in mind that you are always responsible for you own security.
All it takes is a slightly more advanced wallet-stealing trojan which
installs a keylogger to steal your wallet passphrase as you enter it
in addition to your wallet file and you have lost all your Bitcoins.
Wallet encryption cannot keep you safe if you do not practice
good security, such as running up-to-date antivirus software, only
entering your wallet passphrase in the Bitcoin client and using the
same passphrase only as your wallet passphrase.
See the documentation at the bitcoin wiki: See the documentation at the bitcoin wiki:
https://en.bitcoin.it/wiki/Main_Page https://en.bitcoin.it/wiki/Main_Page

2
doc/README_windows.txt

@ -1,4 +1,4 @@
Bitcoin 0.3.24 BETA Bitcoin 0.3.25 BETA
Copyright (c) 2009-2011 Bitcoin Developers Copyright (c) 2009-2011 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying Distributed under the MIT/X11 software license, see the accompanying

528
locale/pl/LC_MESSAGES/bitcoin.po

File diff suppressed because it is too large Load Diff

BIN
locale/sv/LC_MESSAGES/bitcoin.mo

Binary file not shown.

473
locale/sv/LC_MESSAGES/bitcoin.po

File diff suppressed because it is too large Load Diff

BIN
share/pixmaps/bitcoin.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 91 KiB

BIN
share/pixmaps/nsis-header.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
share/pixmaps/nsis-wizard.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

13
share/setup.nsi

@ -1,15 +1,20 @@
Name Bitcoin Name Bitcoin
RequestExecutionLevel highest RequestExecutionLevel highest
SetCompressor /SOLID lzma
# General Symbol Definitions # General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)" !define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.3.24 !define VERSION 0.3.25
!define COMPANY "Bitcoin project" !define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/ !define URL http://www.bitcoin.org/
# MUI Symbol Definitions # MUI Symbol Definitions
!define MUI_ICON "../share/pixmaps/bitcoin.ico" !define MUI_ICON "../share/pixmaps/bitcoin.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP "../share/pixmaps/nsis-header.bmp"
!define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM !define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM
!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY} !define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}
@ -17,6 +22,7 @@ RequestExecutionLevel highest
!define MUI_STARTMENUPAGE_DEFAULTFOLDER Bitcoin !define MUI_STARTMENUPAGE_DEFAULTFOLDER Bitcoin
!define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin.exe !define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin.exe
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
!define MUI_UNFINISHPAGE_NOAUTOCLOSE !define MUI_UNFINISHPAGE_NOAUTOCLOSE
# Included files # Included files
@ -39,12 +45,13 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English !insertmacro MUI_LANGUAGE English
# Installer attributes # Installer attributes
OutFile bitcoin-0.3.24-win32-setup.exe OutFile bitcoin-0.3.25-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on CRCCheck on
XPStyle on XPStyle on
BrandingText " "
ShowInstDetails show ShowInstDetails show
VIProductVersion 0.3.24.0 VIProductVersion 0.3.25.0
VIAddVersionKey ProductName Bitcoin VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyName "${COMPANY}"

30
share/uiproject.fbp

@ -162,6 +162,36 @@
<event name="OnMenuSelection">OnMenuOptionsChangeYourAddress</event> <event name="OnMenuSelection">OnMenuOptionsChangeYourAddress</event>
<event name="OnUpdateUI"></event> <event name="OnUpdateUI"></event>
</object> </object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ANY</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Encrypt Wallet...</property>
<property name="name">m_menuOptionsEncryptWallet</property>
<property name="permission">public</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsEncryptWallet</event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ANY</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Change Wallet Encryption Passphrase...</property>
<property name="name">m_menuOptionsChangeWalletPassphrase</property>
<property name="permission">public</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsChangeWalletPassphrase</event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxMenuItem" expanded="1"> <object class="wxMenuItem" expanded="1">
<property name="bitmap"></property> <property name="bitmap"></property>
<property name="checked">0</property> <property name="checked">0</property>

410
src/bitcoinrpc.cpp

@ -36,6 +36,9 @@ void ThreadRPCServer2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp); typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable; extern map<string, rpcfn_type> mapCallTable;
static int64 nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
Object JSONRPCError(int code, const string& message) 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("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet)); obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
if (pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj; 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 " "If [account] is specified (recommended), it is added to the address book "
"so payments received with the address will be credited to [account]."); "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 // Parse the account first so we don't generate a key if there's an error
string strAccount; string strAccount;
if (params.size() > 0) if (params.size() > 0)
strAccount = AccountFromValue(params[0]); strAccount = AccountFromValue(params[0]);
// Generate a new key that is added to wallet // 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. // This could be done in the same main CS as GetKeyFromKeyPool.
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
@ -346,37 +358,48 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
string strAddress; string strAddress;
CWalletDB walletdb(pwalletMain->strWalletFile); CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin();
CAccount account; CAccount account;
walletdb.ReadAccount(strAccount, account); CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
// Check if the current key has been used
if (!account.vchPubKey.empty())
{ {
CScript scriptPubKey; walletdb.ReadAccount(strAccount, account);
scriptPubKey.SetBitcoinAddress(account.vchPubKey);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); bool bKeyUsed = false;
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it) // Check if the current key has been used
if (!account.vchPubKey.empty())
{ {
const CWalletTx& wtx = (*it).second; CScript scriptPubKey;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) scriptPubKey.SetBitcoinAddress(account.vchPubKey);
if (txout.scriptPubKey == scriptPubKey) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
account.vchPubKey.clear(); 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 // Generate a new key
if (account.vchPubKey.empty() || bForceNew) if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
{ {
account.vchPubKey = pwalletMain->GetKeyFromKeyPool(); if (pwalletMain->GetKeyPoolSize() < 1)
string strAddress = PubKeyToAddress(account.vchPubKey); {
pwalletMain->SetAddressBookName(strAddress, strAccount); if (bKeyUsed || bForceNew)
walletdb.WriteAccount(strAccount, account); 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); strAddress = PubKeyToAddress(account.vchPubKey);
return strAddress; return strAddress;
@ -510,7 +533,12 @@ Value settxfee(const Array& params, bool fHelp)
Value sendtoaddress(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( throw runtime_error(
"sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n" "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001"); "<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(); wtx.mapValue["to"] = params[3].get_str();
CRITICAL_BLOCK(cs_main) 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); string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "") if (strError != "")
throw JSONRPCError(-4, strError); throw JSONRPCError(-4, strError);
@ -674,7 +706,7 @@ int64 GetAccountBalance(const string& strAccount, int nMinDepth)
Value getbalance(const Array& params, bool fHelp) Value getbalance(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 0 || params.size() > 2) if (fHelp || params.size() > 2)
throw runtime_error( throw runtime_error(
"getbalance [account] [minconf=1]\n" "getbalance [account] [minconf=1]\n"
"If [account] is not specified, returns the server's total available balance.\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 strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]); string strTo = AccountFromValue(params[1]);
int64 nAmount = AmountFromValue(params[2]); int64 nAmount = AmountFromValue(params[2]);
int nMinDepth = 1;
if (params.size() > 3) 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; string strComment;
if (params.size() > 4) if (params.size() > 4)
strComment = params[4].get_str(); strComment = params[4].get_str();
@ -773,7 +805,12 @@ Value movecmd(const Array& params, bool fHelp)
Value sendfrom(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( throw runtime_error(
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n" "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001"); "<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(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{ {
if(pwalletMain->IsLocked())
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
// Check funds // Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth); int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
if (nAmount > nBalance) if (nAmount > nBalance)
@ -809,9 +850,15 @@ Value sendfrom(const Array& params, bool fHelp)
return wtx.GetHash().GetHex(); return wtx.GetHash().GetHex();
} }
Value sendmany(const Array& params, bool fHelp) 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( throw runtime_error(
"sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n" "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
"amounts are double-precision floating point numbers"); "amounts are double-precision floating point numbers");
@ -851,7 +898,11 @@ Value sendmany(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{ {
if(pwalletMain->IsLocked())
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
// Check funds // Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth); int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
if (totalAmount > nBalance) 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) Value validateaddress(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 1) if (fHelp || params.size() != 1)
@ -1432,44 +1696,49 @@ Value getwork(const Array& params, bool fHelp)
pair<string, rpcfn_type> pCallTable[] = pair<string, rpcfn_type> pCallTable[] =
{ {
make_pair("help", &help), make_pair("help", &help),
make_pair("stop", &stop), make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount), make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber), make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount), make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty), make_pair("getdifficulty", &getdifficulty),
make_pair("getgenerate", &getgenerate), make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate), make_pair("setgenerate", &setgenerate),
make_pair("gethashespersec", &gethashespersec), make_pair("gethashespersec", &gethashespersec),
make_pair("getinfo", &getinfo), make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress), make_pair("getnewaddress", &getnewaddress),
make_pair("getaccountaddress", &getaccountaddress), make_pair("getaccountaddress", &getaccountaddress),
make_pair("setaccount", &setaccount), make_pair("setaccount", &setaccount),
make_pair("setlabel", &setaccount), // deprecated make_pair("setlabel", &setaccount), // deprecated
make_pair("getaccount", &getaccount), make_pair("getaccount", &getaccount),
make_pair("getlabel", &getaccount), // deprecated make_pair("getlabel", &getaccount), // deprecated
make_pair("getaddressesbyaccount", &getaddressesbyaccount), make_pair("getaddressesbyaccount", &getaddressesbyaccount),
make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
make_pair("sendtoaddress", &sendtoaddress), make_pair("sendtoaddress", &sendtoaddress),
make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress), make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbyaccount", &getreceivedbyaccount), make_pair("getreceivedbyaccount", &getreceivedbyaccount),
make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
make_pair("listreceivedbyaddress", &listreceivedbyaddress), make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbyaccount", &listreceivedbyaccount), make_pair("listreceivedbyaccount", &listreceivedbyaccount),
make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
make_pair("backupwallet", &backupwallet), make_pair("backupwallet", &backupwallet),
make_pair("validateaddress", &validateaddress), make_pair("keypoolrefill", &keypoolrefill),
make_pair("getbalance", &getbalance), make_pair("walletpassphrase", &walletpassphrase),
make_pair("move", &movecmd), make_pair("walletpassphrasechange", &walletpassphrasechange),
make_pair("sendfrom", &sendfrom), make_pair("walletlock", &walletlock),
make_pair("sendmany", &sendmany), make_pair("encryptwallet", &encryptwallet),
make_pair("gettransaction", &gettransaction), make_pair("validateaddress", &validateaddress),
make_pair("listtransactions", &listtransactions), make_pair("getbalance", &getbalance),
make_pair("getwork", &getwork), make_pair("move", &movecmd),
make_pair("listaccounts", &listaccounts), make_pair("sendfrom", &sendfrom),
make_pair("settxfee", &settxfee), 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])); map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
@ -1493,6 +1762,9 @@ string pAllowInSafeMode[] =
"getaddressesbyaccount", "getaddressesbyaccount",
"getaddressesbylabel", // deprecated "getaddressesbylabel", // deprecated
"backupwallet", "backupwallet",
"keypoolrefill",
"walletpassphrase",
"walletlock",
"validateaddress", "validateaddress",
"getwork", "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 > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]); if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]); 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) if (strMethod == "sendmany" && n > 1)
{ {
string s = params[1].get_str(); string s = params[1].get_str();
@ -2146,7 +2419,6 @@ int CommandLineRPC(int argc, char *argv[])
// Parse reply // Parse reply
const Value& result = find_value(reply, "result"); const Value& result = find_value(reply, "result");
const Value& error = find_value(reply, "error"); const Value& error = find_value(reply, "error");
const Value& id = find_value(reply, "id");
if (error.type() != null_type) if (error.type() != null_type)
{ {

132
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));
}

96
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

2
src/cryptopp/cpu.cpp

@ -80,7 +80,7 @@ bool CpuId(word32 input, word32 *output)
#endif #endif
} }
#ifndef _MSC_VER #if !CRYPTOPP_BOOL_X64 && !defined(_MSC_VER) && defined(__GNUC__)
static jmp_buf s_jmpNoSSE2; static jmp_buf s_jmpNoSSE2;
static void SigIllHandlerSSE2(int) static void SigIllHandlerSSE2(int)
{ {

59
src/db.cpp

@ -627,8 +627,6 @@ int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries) void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
{ {
int64 nCreditDebit = 0;
bool fAllAccounts = (strAccount == "*"); bool fAllAccounts = (strAccount == "*");
Dbc* pcursor = GetCursor(); 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(); pwallet->vchDefaultKey.clear();
int nFileVersion = 0; int nFileVersion = 0;
@ -685,12 +683,12 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
//// todo: shouldn't we catch exceptions and try to recover and continue? //// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_mapWallet) CRITICAL_BLOCK(pwallet->cs_mapWallet)
CRITICAL_BLOCK(pwallet->cs_mapKeys) CRITICAL_BLOCK(pwallet->cs_KeyStore)
{ {
// Get cursor // Get cursor
Dbc* pcursor = GetCursor(); Dbc* pcursor = GetCursor();
if (!pcursor) if (!pcursor)
return false; return DB_CORRUPT;
loop loop
{ {
@ -701,7 +699,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (ret == DB_NOTFOUND) if (ret == DB_NOTFOUND)
break; break;
else if (ret != 0) else if (ret != 0)
return false; return DB_CORRUPT;
// Unserialize // Unserialize
// Taking advantage of the fact that pair serialization // Taking advantage of the fact that pair serialization
@ -765,14 +763,42 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
{ {
vector<unsigned char> vchPubKey; vector<unsigned char> vchPubKey;
ssKey >> vchPubKey; ssKey >> vchPubKey;
CWalletKey wkey; CKey key;
if (strType == "key") if (strType == "key")
ssValue >> wkey.vchPrivKey; {
CPrivKey pkey;
ssValue >> pkey;
key.SetPrivKey(pkey);
}
else else
{
CWalletKey wkey;
ssValue >> wkey; ssValue >> wkey;
key.SetPrivKey(wkey.vchPrivKey);
pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey; }
mapPubKeys[Hash160(vchPubKey)] = vchPubKey; 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") else if (strType == "defaultkey")
{ {
@ -800,7 +826,6 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins; if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
#endif #endif
if (strKey == "nTransactionFee") ssValue >> nTransactionFee; if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
if (strKey == "addrIncoming") ssValue >> addrIncoming;
if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors; if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors; if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray; if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
@ -809,6 +834,13 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (strKey == "addrProxy") ssValue >> addrProxy; if (strKey == "addrProxy") ssValue >> addrProxy;
if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP; if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
} }
else if (strType == "minversion")
{
int nMinVersion = 0;
ssValue >> nMinVersion;
if (nMinVersion > VERSION)
return DB_TOO_NEW;
}
} }
pcursor->close(); pcursor->close();
} }
@ -819,7 +851,6 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
printf("nFileVersion = %d\n", nFileVersion); printf("nFileVersion = %d\n", nFileVersion);
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
printf("nTransactionFee = %"PRI64d"\n", nTransactionFee); printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
printf("fMinimizeToTray = %d\n", fMinimizeToTray); printf("fMinimizeToTray = %d\n", fMinimizeToTray);
printf("fMinimizeOnClose = %d\n", fMinimizeOnClose); printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
printf("fUseProxy = %d\n", fUseProxy); printf("fUseProxy = %d\n", fUseProxy);
@ -839,7 +870,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
} }
return true; return DB_LOAD_OK;
} }
void ThreadFlushWalletDB(void* parg) void ThreadFlushWalletDB(void* parg)

33
src/db.h

@ -88,7 +88,7 @@ protected:
if (!pdb) if (!pdb)
return false; return false;
if (fReadOnly) if (fReadOnly)
assert(("Write called on database in read-only mode", false)); assert(!"Write called on database in read-only mode");
// Key // Key
CDataStream ssKey(SER_DISK); CDataStream ssKey(SER_DISK);
@ -117,7 +117,7 @@ protected:
if (!pdb) if (!pdb)
return false; return false;
if (fReadOnly) if (fReadOnly)
assert(("Erase called on database in read-only mode", false)); assert(!"Erase called on database in read-only mode");
// Key // Key
CDataStream ssKey(SER_DISK); 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 class CWalletDB : public CDB
{ {
public: public:
@ -391,6 +399,25 @@ public:
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); 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) bool WriteBestBlock(const CBlockLocator& locator)
{ {
nWalletDBUpdated++; nWalletDBUpdated++;
@ -450,7 +477,7 @@ public:
int64 GetAccountCreditDebit(const std::string& strAccount); int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
bool LoadWallet(CWallet* pwallet); int LoadWallet(CWallet* pwallet);
}; };
#endif #endif

13
src/init.cpp

@ -386,8 +386,16 @@ bool AppInit2(int argc, char* argv[])
nStart = GetTimeMillis(); nStart = GetTimeMillis();
bool fFirstRun; bool fFirstRun;
pwalletMain = new CWallet("wallet.dat"); pwalletMain = new CWallet("wallet.dat");
if (!pwalletMain->LoadWallet(fFirstRun)) int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
strErrors += _("Error loading wallet.dat \n"); 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); printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain); RegisterWallet(pwalletMain);
@ -415,7 +423,6 @@ bool AppInit2(int argc, char* argv[])
//// debug print //// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight); printf("nBestHeight = %d\n", nBestHeight);
printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size());
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size()); printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapPubKeys.size() = %d\n", mapPubKeys.size()); printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size()); printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());

86
src/key.h

@ -31,6 +31,41 @@
// see www.keylength.com // see www.keylength.com
// script supports up to 75 for single byte push // 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 class key_error : public std::runtime_error
@ -42,8 +77,7 @@ public:
// secure_allocator is defined in serialize.h // 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> > CPrivKey;
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
class CKey class CKey
{ {
@ -102,6 +136,38 @@ public:
return true; 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 CPrivKey GetPrivKey() const
{ {
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
@ -154,22 +220,6 @@ public:
return false; return false;
return true; 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 #endif

133
src/keystore.cpp

@ -4,13 +4,7 @@
#include "headers.h" #include "headers.h"
#include "db.h" #include "db.h"
#include "crypter.h"
//////////////////////////////////////////////////////////////////////////////
//
// mapKeys
//
std::vector<unsigned char> CKeyStore::GenerateNewKey() std::vector<unsigned char> CKeyStore::GenerateNewKey()
{ {
@ -18,13 +12,14 @@ std::vector<unsigned char> CKeyStore::GenerateNewKey()
CKey key; CKey key;
key.MakeNewKey(); key.MakeNewKey();
if (!AddKey(key)) if (!AddKey(key))
throw std::runtime_error("GenerateNewKey() : AddKey failed"); throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey(); 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(); mapKeys[key.GetPubKey()] = key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
@ -32,3 +27,121 @@ bool CKeyStore::AddKey(const CKey& key)
return true; 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;
}

95
src/keystore.h

@ -4,27 +4,112 @@
#ifndef BITCOIN_KEYSTORE_H #ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H #define BITCOIN_KEYSTORE_H
#include "crypter.h"
class CKeyStore class CKeyStore
{ {
public: public:
std::map<std::vector<unsigned char>, CPrivKey> mapKeys; mutable CCriticalSection cs_KeyStore;
mutable CCriticalSection cs_mapKeys;
virtual bool AddKey(const CKey& key); 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 bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
{ {
return (mapKeys.count(vchPubKey) > 0); 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); std::map<std::vector<unsigned char>, CPrivKey>::const_iterator mi = mapKeys.find(vchPubKey);
if (mi != mapKeys.end()) if (mi != mapKeys.end())
{ {
keyOut = (*mi).second; keyOut.SetPrivKey((*mi).second);
return true; return true;
} }
return false; 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(); 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 #endif

10
src/main.cpp

@ -55,7 +55,6 @@ int64 nHPSTimerStart;
// Settings // Settings
int fGenerateBitcoins = false; int fGenerateBitcoins = false;
int64 nTransactionFee = 0; int64 nTransactionFee = 0;
CAddress addrIncoming;
int fLimitProcessors = false; int fLimitProcessors = false;
int nLimitProcessors = 1; int nLimitProcessors = 1;
int fMinimizeToTray = true; int fMinimizeToTray = true;
@ -1689,7 +1688,7 @@ string GetWarnings(string strFor)
return strStatusBar; return strStatusBar;
else if (strFor == "rpc") else if (strFor == "rpc")
return strRPC; return strRPC;
assert(("GetWarnings() : invalid parameter", false)); assert(!"GetWarnings() : invalid parameter");
return "error"; return "error";
} }
@ -1900,6 +1899,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return error("message addr size() = %d", vAddr.size()); return error("message addr size() = %d", vAddr.size());
// Store the new addresses // Store the new addresses
CAddrDB addrDB;
addrDB.TxnBegin();
int64 nNow = GetAdjustedTime(); int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60; int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr) BOOST_FOREACH(CAddress& addr, vAddr)
@ -1911,7 +1912,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
continue; continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60; addr.nTime = nNow - 5 * 24 * 60 * 60;
AddAddress(addr, 2 * 60 * 60); AddAddress(addr, 2 * 60 * 60, &addrDB);
pfrom->AddAddressKnown(addr); pfrom->AddAddressKnown(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) 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) if (vAddr.size() < 1000)
pfrom->fGetAddr = false; 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 // Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip)) 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 // Send back approval of order and pubkey to use
CScript scriptPubKey; CScript scriptPubKey;

1
src/main.h

@ -70,7 +70,6 @@ extern std::set<CWallet*> setpwalletRegistered;
// Settings // Settings
extern int fGenerateBitcoins; extern int fGenerateBitcoins;
extern int64 nTransactionFee; extern int64 nTransactionFee;
extern CAddress addrIncoming;
extern int fLimitProcessors; extern int fLimitProcessors;
extern int nLimitProcessors; extern int nLimitProcessors;
extern int fMinimizeToTray; extern int fMinimizeToTray;

29
src/makefile.linux-mingw

@ -4,6 +4,8 @@
DEPSDIR:=/usr/i586-mingw32msvc DEPSDIR:=/usr/i586-mingw32msvc
USE_UPNP:=0
INCLUDEPATHS= \ INCLUDEPATHS= \
-I"$(DEPSDIR)/boost_1_43_0" \ -I"$(DEPSDIR)/boost_1_43_0" \
-I"$(DEPSDIR)/db-4.7.25.NC/build_unix" \ -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__ DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) 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 \ 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 \
crypter.h init.h
bitcoin.exe: USE_UPNP:=1
ifdef USE_UPNP ifdef USE_UPNP
INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215" INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215" LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBS += -l miniupnpc -l iphlpapi LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif 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
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 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/wallet.o \
obj/rpc.o \ obj/rpc.o \
obj/init.o \ obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \ cryptopp/obj/sha.o \
cryptopp/obj/cpu.o cryptopp/obj/cpu.o

4
src/makefile.mingw

@ -33,7 +33,8 @@ DEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH -DUSE_SSL
DEBUGFLAGS=-g -D__WXDEBUG__ DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) 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 \ 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 ifdef USE_UPNP
INCLUDEPATHS += -I"C:\upnpc-exe-win32-20110215" INCLUDEPATHS += -I"C:\upnpc-exe-win32-20110215"
@ -55,6 +56,7 @@ OBJS= \
obj/wallet.o \ obj/wallet.o \
obj/rpc.o \ obj/rpc.o \
obj/init.o \ obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \ cryptopp/obj/sha.o \
cryptopp/obj/cpu.o cryptopp/obj/cpu.o

4
src/makefile.osx vendored

@ -33,7 +33,8 @@ DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
# ppc doesn't work because we don't support big-endian # 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) 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 \ 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= \ OBJS= \
obj/util.o \ obj/util.o \
@ -46,6 +47,7 @@ OBJS= \
obj/wallet.o \ obj/wallet.o \
obj/rpc.o \ obj/rpc.o \
obj/init.o \ obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \ cryptopp/obj/sha.o \
cryptopp/obj/cpu.o cryptopp/obj/cpu.o

4
src/makefile.unix

@ -39,7 +39,8 @@ LIBS+= \
DEBUGFLAGS=-g -D__WXDEBUG__ DEBUGFLAGS=-g -D__WXDEBUG__
CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) 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 \ 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= \ OBJS= \
obj/util.o \ obj/util.o \
@ -52,6 +53,7 @@ OBJS= \
obj/wallet.o \ obj/wallet.o \
obj/rpc.o \ obj/rpc.o \
obj/init.o \ obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \ cryptopp/obj/sha.o \
cryptopp/obj/cpu.o cryptopp/obj/cpu.o

24
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()) if (!addr.IsRoutable())
return false; return false;
@ -455,7 +455,10 @@ bool AddAddress(CAddress addr, int64 nTimePenalty)
// New address // New address
printf("AddAddress(%s)\n", addr.ToString().c_str()); printf("AddAddress(%s)\n", addr.ToString().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr)); mapAddresses.insert(make_pair(addr.GetKey(), addr));
CAddrDB().WriteAddress(addr); if (pAddrDB)
pAddrDB->WriteAddress(addr);
else
CAddrDB().WriteAddress(addr);
return true; return true;
} }
else else
@ -477,7 +480,12 @@ bool AddAddress(CAddress addr, int64 nTimePenalty)
fUpdated = true; fUpdated = true;
} }
if (fUpdated) if (fUpdated)
CAddrDB().WriteAddress(addrFound); {
if (pAddrDB)
pAddrDB->WriteAddress(addrFound);
else
CAddrDB().WriteAddress(addrFound);
}
} }
} }
return false; return false;
@ -831,7 +839,7 @@ void ThreadSocketHandler2(void* parg)
{ {
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
{ {
if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0) if (pnode->hSocket == INVALID_SOCKET)
continue; continue;
FD_SET(pnode->hSocket, &fdsetRecv); FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError); FD_SET(pnode->hSocket, &fdsetError);
@ -1158,6 +1166,8 @@ void DNSAddressSeed()
if (!fTestNet) if (!fTestNet)
{ {
printf("Loading addresses from DNS seeds (could take a while)\n"); 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++) { for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CAddress> vaddr; vector<CAddress> vaddr;
@ -1168,12 +1178,14 @@ void DNSAddressSeed()
if (addr.GetByte(3) != 127) if (addr.GetByte(3) != 127)
{ {
addr.nTime = 0; addr.nTime = 0;
AddAddress(addr); AddAddress(addr, 0, &addrDB);
found++; found++;
} }
} }
} }
} }
addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
} }
printf("%d addresses found from DNS seeds\n", found); printf("%d addresses found from DNS seeds\n", found);
@ -1700,7 +1712,7 @@ void StartNode(void* parg)
printf("Error: CreateThread(ThreadIRCSeed) failed\n"); printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections // Send and receive from sockets, accept connections
pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true); CreateThread(ThreadSocketHandler, NULL, true);
// Initiate outbound connections // Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL)) if (!CreateThread(ThreadOpenConnections, NULL))

3
src/net.h

@ -15,6 +15,7 @@
class CMessageHeader; class CMessageHeader;
class CAddress; class CAddress;
class CAddrDB;
class CInv; class CInv;
class CRequestTracker; class CRequestTracker;
class CNode; 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, 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 Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool GetMyExternalIP(unsigned int& ipRet); 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); void AddressCurrentlyConnected(const CAddress& addr);
CNode* FindNode(unsigned int ip); CNode* FindNode(unsigned int ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);

7
src/qt/addresstablemodel.cpp

@ -38,7 +38,7 @@ struct AddressTablePriv
{ {
cachedAddressTable.clear(); cachedAddressTable.clear();
CRITICAL_BLOCK(wallet->cs_mapKeys) CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(wallet->cs_mapAddressBook) CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wallet->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 // Generate a new address to associate with given label, optionally
// set as default receiving address. // set as default receiving address.
strAddress = PubKeyToAddress(wallet->GetKeyFromKeyPool()); strAddress = PubKeyToAddress(wallet->GetOrReuseKeyFromPool());
} }
else else
{ {
return QString(); return QString();
} }
// Add entry and update list // Add entry and update list
wallet->SetAddressBookName(strAddress, strLabel); CRITICAL_BLOCK(wallet->cs_mapAddressBook)
wallet->SetAddressBookName(strAddress, strLabel);
updateList(); updateList();
return QString::fromStdString(strAddress); return QString::fromStdString(strAddress);
} }

52
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_ABS: if (bn < bnZero) bn = -bn; break;
case OP_NOT: bn = (bn == bnZero); break; case OP_NOT: bn = (bn == bnZero); break;
case OP_0NOTEQUAL: bn = (bn != bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break;
default: assert(!"invalid opcode"); break;
} }
popstack(stack); popstack(stack);
stack.push_back(bn.getvch()); 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_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
default: assert(!"invalid opcode"); break;
} }
popstack(stack); popstack(stack);
popstack(stack); popstack(stack);
@ -1030,7 +1032,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false; return false;
// Compile solution // Compile solution
CRITICAL_BLOCK(keystore.cs_mapKeys) CRITICAL_BLOCK(keystore.cs_KeyStore)
{ {
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{ {
@ -1038,13 +1040,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
{ {
// Sign // Sign
const valtype& vchPubKey = item.second; const valtype& vchPubKey = item.second;
CPrivKey privkey; CKey key;
if (!keystore.GetPrivKey(vchPubKey, privkey)) if (!keystore.GetPrivKey(vchPubKey, key))
return false; return false;
if (hash != 0) if (hash != 0)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
if (!CKey::Sign(privkey, hash, vchSig)) if (!key.Sign(hash, vchSig))
return false; return false;
vchSig.push_back((unsigned char)nHashType); vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig; scriptSigRet << vchSig;
@ -1057,13 +1059,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
if (mi == mapPubKeys.end()) if (mi == mapPubKeys.end())
return false; return false;
const vector<unsigned char>& vchPubKey = (*mi).second; const vector<unsigned char>& vchPubKey = (*mi).second;
CPrivKey privkey; CKey key;
if (!keystore.GetPrivKey(vchPubKey, privkey)) if (!keystore.GetPrivKey(vchPubKey, key))
return false; return false;
if (hash != 0) if (hash != 0)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
if (!CKey::Sign(privkey, hash, vchSig)) if (!key.Sign(hash, vchSig))
return false; return false;
vchSig.push_back((unsigned char)nHashType); vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << vchPubKey; scriptSigRet << vchSig << vchPubKey;
@ -1089,8 +1091,40 @@ bool IsStandard(const CScript& scriptPubKey)
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{ {
CScript scriptSig; vector<pair<opcodetype, valtype> > vSolution;
return Solver(keystore, scriptPubKey, 0, 0, scriptSig); 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;
} }

2
src/script.h

@ -486,7 +486,7 @@ public:
{ {
// I'm not sure if this should push the script or concatenate scripts. // 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 // 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; return *this;
} }

41
src/serialize.h

@ -28,12 +28,36 @@ typedef unsigned long long uint64;
#if defined(_MSC_VER) && _MSC_VER < 1300 #if defined(_MSC_VER) && _MSC_VER < 1300
#define for if (false) ; else for #define for if (false) ; else for
#endif #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 CScript;
class CDataStream; class CDataStream;
class CAutoFile; class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000; static const unsigned int MAX_SIZE = 0x02000000;
static const int VERSION = 32400; static const int VERSION = 32500;
static const char* pszSubVer = ""; static const char* pszSubVer = "";
static const bool VERSION_IS_BETA = true; 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> template<typename T>
struct secure_allocator : public std::allocator<T> struct secure_allocator : public std::allocator<T>
@ -777,10 +802,22 @@ struct secure_allocator : public std::allocator<T>
template<typename _Other> struct rebind template<typename _Other> struct rebind
{ typedef secure_allocator<_Other> other; }; { 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) void deallocate(T* p, std::size_t n)
{ {
if (p != NULL) if (p != NULL)
{
memset(p, 0, sizeof(T) * n); memset(p, 0, sizeof(T) * n);
munlock(p, sizeof(T) * n);
}
std::allocator<T>::deallocate(p, n); std::allocator<T>::deallocate(p, n);
} }
}; };

273
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)) if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
m_textCtrlAddress->SetValue(PubKeyToAddress(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 // Fill listctrl with wallet transactions
RefreshListCtrl(); RefreshListCtrl();
} }
@ -1122,6 +1162,169 @@ void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
return; 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) void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
{ {
// Options->Options // Options->Options
@ -1182,8 +1385,19 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
return; return;
string strName = dialog.GetValue(); string strName = dialog.GetValue();
// Generate new key string strAddress;
string 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();
}
// Save // Save
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
@ -1947,7 +2161,12 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (fBitcoinAddress) if (fBitcoinAddress)
{ {
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{ {
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Send to bitcoin address // Send to bitcoin address
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
@ -1956,13 +2175,22 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (strError == "") if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending...")); wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError == "ABORTED") else if (strError == "ABORTED")
{
if (fWasLocked)
pwalletMain->Lock();
return; // leave send dialog open return; // leave send dialog open
}
else else
{ {
wxMessageBox(strError + " ", _("Sending...")); wxMessageBox(strError + " ", _("Sending..."));
EndModal(false); EndModal(false);
if (fWasLocked)
pwalletMain->Lock();
return; return;
} }
if (fWasLocked)
pwalletMain->Lock();
} }
} }
else else
@ -2246,16 +2474,27 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
Error(_("Insufficient funds")); Error(_("Insufficient funds"));
return; return;
} }
CReserveKey reservekey(pwalletMain); CReserveKey reservekey(pwalletMain);
int64 nFeeRequired; int64 nFeeRequired;
if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired)) CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{ {
if (nPrice + nFeeRequired > pwalletMain->GetBalance()) bool fWasLocked = pwalletMain->IsLocked();
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())); if (!GetWalletPassphrase())
else return;
Error(_("Transaction creation failed"));
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 // Transaction fee
if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this)) if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
@ -2382,7 +2621,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus(); m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data // Fill listctrl with address book data
CRITICAL_BLOCK(pwalletMain->cs_mapKeys) CRITICAL_BLOCK(pwalletMain->cs_KeyStore)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue(); string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
@ -2581,8 +2820,18 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
return; return;
strName = dialog.GetValue(); strName = dialog.GetValue();
// Generate new key CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool()); {
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Generate new key
strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
if (fWasLocked)
pwalletMain->Lock();
}
} }
// Add to list and select it // Add to list and select it

2
src/ui.h

@ -59,6 +59,8 @@ protected:
void OnMenuFileExit(wxCommandEvent& event); void OnMenuFileExit(wxCommandEvent& event);
void OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event); void OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event);
void OnMenuOptionsChangeYourAddress(wxCommandEvent& event); void OnMenuOptionsChangeYourAddress(wxCommandEvent& event);
void OnMenuOptionsEncryptWallet(wxCommandEvent& event);
void OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event);
void OnMenuOptionsOptions(wxCommandEvent& event); void OnMenuOptionsOptions(wxCommandEvent& event);
void OnMenuHelpAbout(wxCommandEvent& event); void OnMenuHelpAbout(wxCommandEvent& event);
void OnButtonSend(wxCommandEvent& event); void OnButtonSend(wxCommandEvent& event);

10
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_menuOptionsChangeYourAddress = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Your Receiving Addresses...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsChangeYourAddress ); 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; wxMenuItem* m_menuOptionsOptions;
m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_PREFERENCES, wxString( _("&Options...") ) , wxEmptyString, wxITEM_NORMAL ); m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_PREFERENCES, wxString( _("&Options...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsOptions ); 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( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Connect( m_menuFileExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) ); 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_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_menuOptionsOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Connect( m_menuHelpAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) ); this->Connect( m_menuHelpAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Connect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) ); 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( 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::OnMenuFileExit ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) ); 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::OnMenuOptionsOptions ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Disconnect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) ); this->Disconnect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );

4
src/uibase.h

@ -98,6 +98,8 @@ class CMainFrameBase : public wxFrame
virtual void OnPaint( wxPaintEvent& event ) { event.Skip(); } virtual void OnPaint( wxPaintEvent& event ) { event.Skip(); }
virtual void OnMenuFileExit( wxCommandEvent& event ) { event.Skip(); } virtual void OnMenuFileExit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsChangeYourAddress( 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 OnMenuOptionsOptions( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuHelpAbout( wxCommandEvent& event ) { event.Skip(); } virtual void OnMenuHelpAbout( wxCommandEvent& event ) { event.Skip(); }
virtual void OnButtonSend( wxCommandEvent& event ) { event.Skip(); } virtual void OnButtonSend( wxCommandEvent& event ) { event.Skip(); }
@ -115,6 +117,8 @@ class CMainFrameBase : public wxFrame
public: public:
wxMenu* m_menuOptions; wxMenu* m_menuOptions;
wxMenuItem* m_menuOptionsEncryptWallet;
wxMenuItem* m_menuOptionsChangeWalletPassphrase;
wxStatusBar* m_statusBar; wxStatusBar* m_statusBar;
wxTextCtrl* m_textCtrlAddress; wxTextCtrl* m_textCtrlAddress;
wxListCtrl* m_listCtrlAll; wxListCtrl* m_listCtrlAll;

8
src/util.cpp

@ -758,8 +758,8 @@ string GetPidFile()
void CreatePidFile(string pidFile, pid_t pid) void CreatePidFile(string pidFile, pid_t pid)
{ {
FILE* file; FILE* file = fopen(pidFile.c_str(), "w");
if (file = fopen(pidFile.c_str(), "w")) if (file)
{ {
fprintf(file, "%d\n", pid); fprintf(file, "%d\n", pid);
fclose(file); fclose(file);
@ -788,7 +788,9 @@ void ShrinkDebugFile()
fseek(file, -sizeof(pch), SEEK_END); fseek(file, -sizeof(pch), SEEK_END);
int nBytes = fread(pch, 1, sizeof(pch), file); int nBytes = fread(pch, 1, sizeof(pch), file);
fclose(file); fclose(file);
if (file = fopen(strFile.c_str(), "w"))
file = fopen(strFile.c_str(), "w");
if (file)
{ {
fwrite(pch, 1, nBytes, file); fwrite(pch, 1, nBytes, file);
fclose(file); fclose(file);

6
src/util.h

@ -262,7 +262,7 @@ public:
// I'd rather be careful than suffer the other more error prone syntax. // I'd rather be careful than suffer the other more error prone syntax.
// The compiler will optimise away all this loop junk. // The compiler will optimise away all this loop junk.
#define CRITICAL_BLOCK(cs) \ #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) for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
class CTryCriticalBlock class CTryCriticalBlock
@ -276,7 +276,7 @@ public:
}; };
#define TRY_CRITICAL_BLOCK(cs) \ #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) 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); return (pthread_cancel(hthread) == 0);
} }
inline void ExitThread(unsigned int nExitCode) inline void ExitThread(size_t nExitCode)
{ {
pthread_exit((void*)nExitCode); pthread_exit((void*)nExitCode);
} }

275
src/wallet.cpp

@ -5,11 +5,11 @@
#include "headers.h" #include "headers.h"
#include "db.h" #include "db.h"
#include "cryptopp/sha.h" #include "cryptopp/sha.h"
#include "crypter.h"
using namespace std; using namespace std;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// mapWallet // mapWallet
@ -17,10 +17,181 @@ using namespace std;
bool CWallet::AddKey(const CKey& key) bool CWallet::AddKey(const CKey& key)
{ {
this->CKeyStore::AddKey(key); if (!CCryptoKeyStore::AddKey(key))
return false;
if (!fFileBacked) if (!fFileBacked)
return true; 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) void CWallet::WalletUpdateSpent(const CTransaction &tx)
@ -98,7 +269,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
if (txout.scriptPubKey == scriptDefaultKey) if (txout.scriptPubKey == scriptDefaultKey)
SetDefaultKey(GetKeyFromKeyPool()); {
SetDefaultKey(GetOrReuseKeyFromPool());
SetAddressBookName(PubKeyToAddress(vchDefaultKey), "");
}
} }
#endif #endif
// Notify UI // Notify UI
@ -552,8 +726,6 @@ void CWallet::ResendWalletTransactions()
int64 CWallet::GetBalance() const int64 CWallet::GetBalance() const
{ {
int64 nStart = GetTimeMillis();
int64 nTotal = 0; int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
@ -566,7 +738,6 @@ int64 CWallet::GetBalance() const
} }
} }
//printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
return nTotal; return nTotal;
} }
@ -798,7 +969,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
// Reserve a new key pair from key pool // Reserve a new key pair from key pool
vector<unsigned char> vchPubKey = reservekey.GetReservedKey(); 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 // Fill a vout to ourself, using same address type as the payment
CScript scriptChange; CScript scriptChange;
@ -918,15 +1089,24 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
{ {
CReserveKey reservekey(this); CReserveKey reservekey(this);
int64 nFeeRequired; int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) CRITICAL_BLOCK(cs_vMasterKey)
{ {
string strError; if (IsLocked())
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()); string strError = _("Error: Wallet locked, unable to create transaction ");
else printf("SendMoney() : %s", strError.c_str());
strError = _("Error: Transaction creation failed "); return strError;
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)) 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) if (!fFileBacked)
return false; return false;
fFirstRunRet = false; fFirstRunRet = false;
if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this)) int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
return false; if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet;
fFirstRunRet = vchDefaultKey.empty(); fFirstRunRet = vchDefaultKey.empty();
if (!mapKeys.count(vchDefaultKey)) if (!HaveKey(vchDefaultKey))
{ {
// Create new default key // Create new keyUser and set as default key
RandAddSeedPerfmon(); RandAddSeedPerfmon();
SetDefaultKey(GetKeyFromKeyPool()); SetDefaultKey(GetOrReuseKeyFromPool());
if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), "")) if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
return false; return DB_LOAD_FAIL;
} }
CreateThread(ThreadFlushWalletDB, &strWalletFile); CreateThread(ThreadFlushWalletDB, &strWalletFile);
return true; return DB_LOAD_OK;
} }
@ -1048,14 +1229,16 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
return true; return true;
} }
void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) bool CWallet::TopUpKeyPool()
{ {
nIndex = -1;
keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool) CRITICAL_BLOCK(cs_setKeyPool)
CRITICAL_BLOCK(cs_vMasterKey)
{ {
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(strWalletFile);
// Top up key pool // Top up key pool
@ -1066,18 +1249,36 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
if (!setKeyPool.empty()) if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1; nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) 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); setKeyPool.insert(nEnd);
printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size()); 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 // Get the oldest key
assert(!setKeyPool.empty()); if(setKeyPool.empty())
return;
CWalletDB walletdb(strWalletFile);
nIndex = *(setKeyPool.begin()); nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool)) if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed"); throw runtime_error("ReserveKeyFromKeyPool() : read failed");
if (!mapKeys.count(keypool.vchPubKey)) if (!HaveKey(keypool.vchPubKey))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
assert(!keypool.vchPubKey.empty()); assert(!keypool.vchPubKey.empty());
printf("keypool reserve %"PRI64d"\n", nIndex); printf("keypool reserve %"PRI64d"\n", nIndex);
@ -1106,11 +1307,13 @@ void CWallet::ReturnKey(int64 nIndex)
printf("keypool return %"PRI64d"\n", nIndex); printf("keypool return %"PRI64d"\n", nIndex);
} }
vector<unsigned char> CWallet::GetKeyFromKeyPool() vector<unsigned char> CWallet::GetOrReuseKeyFromPool()
{ {
int64 nIndex = 0; int64 nIndex = 0;
CKeyPool keypool; CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool); ReserveKeyFromKeyPool(nIndex, keypool);
if(nIndex == -1)
return vchDefaultKey;
KeepKey(nIndex); KeepKey(nIndex);
return keypool.vchPubKey; return keypool.vchPubKey;
} }
@ -1120,6 +1323,8 @@ int64 CWallet::GetOldestKeyPoolTime()
int64 nIndex = 0; int64 nIndex = 0;
CKeyPool keypool; CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool); ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
return GetTime();
ReturnKey(nIndex); ReturnKey(nIndex);
return keypool.nTime; return keypool.nTime;
} }
@ -1130,7 +1335,13 @@ vector<unsigned char> CReserveKey::GetReservedKey()
{ {
CKeyPool keypool; CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, 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()); assert(!vchPubKey.empty());
return vchPubKey; return vchPubKey;

31
src/wallet.h

@ -12,12 +12,14 @@ class CWalletTx;
class CReserveKey; class CReserveKey;
class CWalletDB; class CWalletDB;
class CWallet : public CKeyStore class CWallet : public CCryptoKeyStore
{ {
private: private:
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; 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; bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
CWalletDB *pwalletdbEncryption;
CCriticalSection cs_pwalletdbEncryption;
public: public:
bool fFileBacked; bool fFileBacked;
@ -26,14 +28,22 @@ public:
std::set<int64> setKeyPool; std::set<int64> setKeyPool;
CCriticalSection cs_setKeyPool; CCriticalSection cs_setKeyPool;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
CWallet() CWallet()
{ {
fFileBacked = false; fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
} }
CWallet(std::string strWalletFileIn) CWallet(std::string strWalletFileIn)
{ {
strWalletFile = strWalletFileIn; strWalletFile = strWalletFileIn;
fFileBacked = true; fFileBacked = true;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
} }
mutable CCriticalSection cs_mapWallet; mutable CCriticalSection cs_mapWallet;
@ -48,7 +58,16 @@ public:
std::vector<unsigned char> vchDefaultKey; std::vector<unsigned char> vchDefaultKey;
// keystore implementation
bool AddKey(const CKey& key); 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 AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
bool EraseFromWallet(uint256 hash); bool EraseFromWallet(uint256 hash);
@ -65,10 +84,11 @@ public:
std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); 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); std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
bool TopUpKeyPool();
void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
void KeepKey(int64 nIndex); void KeepKey(int64 nIndex);
void ReturnKey(int64 nIndex); void ReturnKey(int64 nIndex);
std::vector<unsigned char> GetKeyFromKeyPool(); std::vector<unsigned char> GetOrReuseKeyFromPool();
int64 GetOldestKeyPoolTime(); int64 GetOldestKeyPoolTime();
bool IsMine(const CTxIn& txin) const; bool IsMine(const CTxIn& txin) const;
@ -148,7 +168,7 @@ public:
walletdb.WriteBestBlock(loc); walletdb.WriteBestBlock(loc);
} }
bool LoadWallet(bool& fFirstRunRet); int LoadWallet(bool& fFirstRunRet);
// bool BackupWallet(const std::string& strDest); // bool BackupWallet(const std::string& strDest);
// requires cs_mapAddressBook lock // requires cs_mapAddressBook lock
@ -175,6 +195,11 @@ public:
} }
} }
int GetKeyPoolSize()
{
return setKeyPool.size();
}
bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey); bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);

Loading…
Cancel
Save