diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoinrpc.cpp | 26 | ||||
-rw-r--r-- | src/db.cpp | 133 | ||||
-rw-r--r-- | src/db.h | 5 | ||||
-rw-r--r-- | src/init.cpp | 10 | ||||
-rw-r--r-- | src/qt/askpassphrasedialog.cpp | 3 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 6 | ||||
-rw-r--r-- | src/qt/overviewpage.cpp | 2 | ||||
-rw-r--r-- | src/qt/res/icons/address-book.png | bin | 1211 -> 1851 bytes | |||
-rw-r--r-- | src/qt/res/icons/export.png | bin | 1339 -> 2148 bytes | |||
-rw-r--r-- | src/qt/res/icons/history.png | bin | 746 -> 1432 bytes | |||
-rw-r--r-- | src/qt/res/icons/key.png | bin | 1239 -> 1727 bytes | |||
-rw-r--r-- | src/qt/res/icons/lock_closed.png | bin | 1237 -> 1679 bytes | |||
-rw-r--r-- | src/qt/res/icons/lock_open.png | bin | 1442 -> 1644 bytes | |||
-rw-r--r-- | src/qt/res/icons/overview.png | bin | 7015 -> 7936 bytes | |||
-rw-r--r-- | src/qt/res/icons/receive.png | bin | 1815 -> 1437 bytes | |||
-rw-r--r-- | src/qt/res/icons/send.png | bin | 1806 -> 1487 bytes | |||
-rw-r--r-- | src/qt/res/icons/synced.png | bin | 698 -> 781 bytes | |||
-rw-r--r-- | src/serialize.h | 2 | ||||
-rw-r--r-- | src/wallet.cpp | 47 | ||||
-rw-r--r-- | src/wallet.h | 1 |
20 files changed, 210 insertions, 25 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 6e2eac5a7e..2857b7575e 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -126,6 +126,7 @@ Value help(const Array& params, bool fHelp) // We already filter duplicates, but these deprecated screw up the sort order if (strMethod == "getamountreceived" || strMethod == "getallreceived" || + strMethod == "getblocknumber" || // deprecated (strMethod.find("label") != string::npos)) continue; if (strCommand != "" && strMethod != strCommand) @@ -160,10 +161,13 @@ Value stop(const Array& params, bool fHelp) throw runtime_error( "stop\n" "Stop bitcoin server."); - +#ifndef QT_GUI // Shutdown will take long enough that the response should get back CreateThread(Shutdown, NULL); return "bitcoin server stopping"; +#else + throw runtime_error("NYI: cannot shut down GUI with RPC command"); +#endif } @@ -178,12 +182,13 @@ Value getblockcount(const Array& params, bool fHelp) } +// deprecated Value getblocknumber(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getblocknumber\n" - "Returns the block number of the latest block in the longest block chain."); + "Deprecated. Use getblockcount."); return nBestHeight; } @@ -1554,6 +1559,11 @@ Value encryptwallet(const Array& params, bool fHelp) if (pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called."); +#ifdef QT_GUI + // shutting down via RPC while the GUI is running does not work (yet): + throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command"); +#endif + string strWalletPass; strWalletPass.reserve(100); mlock(&strWalletPass[0], strWalletPass.capacity()); @@ -1573,7 +1583,11 @@ Value encryptwallet(const Array& params, bool fHelp) fill(strWalletPass.begin(), strWalletPass.end(), '\0'); munlock(&strWalletPass[0], strWalletPass.capacity()); - return Value::null; + // BDB seems to have a bad habit of writing old data into + // slack space in .dat files; that is bad if the old data is + // unencrypted private keys. So: + CreateThread(Shutdown, NULL); + return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet"; } @@ -1858,7 +1872,7 @@ string pAllowInSafeMode[] = "help", "stop", "getblockcount", - "getblocknumber", + "getblocknumber", // deprecated "getconnectioncount", "getdifficulty", "getgenerate", @@ -2175,11 +2189,13 @@ void ThreadRPCServer2(void* parg) else if (mapArgs.count("-daemon")) strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); PrintConsole( - _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n" + _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"), strWhatAmI.c_str(), GetConfigFile().c_str()); +#ifndef QT_GUI CreateThread(Shutdown, NULL); +#endif return; } diff --git a/src/db.cpp b/src/db.cpp index 7de1f8df9a..9ac93b3506 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -28,6 +28,23 @@ DbEnv dbenv(0); static map<string, int> mapFileUseCount; static map<string, Db*> mapDb; +static void EnvShutdown() +{ + if (!fDbEnvInit) + return; + + fDbEnvInit = false; + try + { + dbenv.close(0); + } + catch (const DbException& e) + { + printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno()); + } + DbEnv(0).remove(GetDataDir().c_str(), 0); +} + class CDBInit { public: @@ -36,11 +53,7 @@ public: } ~CDBInit() { - if (fDbEnvInit) - { - dbenv.close(0); - fDbEnvInit = false; - } + EnvShutdown(); } } instance_of_cdbinit; @@ -165,6 +178,101 @@ void static CloseDb(const string& strFile) } } +bool CDB::Rewrite(const string& strFile, const char* pszSkip) +{ + while (!fShutdown) + { + CRITICAL_BLOCK(cs_db) + { + if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) + { + // Flush log data to the dat file + CloseDb(strFile); + dbenv.txn_checkpoint(0, 0, 0); + dbenv.lsn_reset(strFile.c_str(), 0); + mapFileUseCount.erase(strFile); + + bool fSuccess = true; + printf("Rewriting %s...\n", strFile.c_str()); + string strFileRes = strFile + ".rewrite"; + { // surround usage of db with extra {} + CDB db(strFile.c_str(), "r"); + Db* pdbCopy = new Db(&dbenv, 0); + + int ret = pdbCopy->open(NULL, // Txn pointer + strFileRes.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags + 0); + if (ret > 0) + { + printf("Cannot create database file %s\n", strFileRes.c_str()); + fSuccess = false; + } + + Dbc* pcursor = db.GetCursor(); + if (pcursor) + while (fSuccess) + { + CDataStream ssKey; + CDataStream ssValue; + int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); + if (ret == DB_NOTFOUND) + { + pcursor->close(); + break; + } + else if (ret != 0) + { + pcursor->close(); + fSuccess = false; + break; + } + if (pszSkip && + strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) + continue; + if (strncmp(&ssKey[0], "\x07version", 8) == 0) + { + // Update version: + ssValue.clear(); + ssValue << VERSION; + } + Dbt datKey(&ssKey[0], ssKey.size()); + Dbt datValue(&ssValue[0], ssValue.size()); + int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); + if (ret2 > 0) + fSuccess = false; + } + if (fSuccess) + { + db.Close(); + CloseDb(strFile); + if (pdbCopy->close(0)) + fSuccess = false; + delete pdbCopy; + } + } + if (fSuccess) + { + Db dbA(&dbenv, 0); + if (dbA.remove(strFile.c_str(), NULL, 0)) + fSuccess = false; + Db dbB(&dbenv, 0); + if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) + fSuccess = false; + } + if (!fSuccess) + printf("Rewriting of %s FAILED!\n", strFileRes.c_str()); + return fSuccess; + } + } + Sleep(100); + } + return false; +} + + void DBFlush(bool fShutdown) { // Flush log data to the actual data file @@ -196,9 +304,10 @@ void DBFlush(bool fShutdown) { char** listp; if (mapFileUseCount.empty()) + { dbenv.log_archive(&listp, DB_ARCH_REMOVE); - dbenv.close(0); - fDbEnvInit = false; + EnvShutdown(); + } } } } @@ -656,6 +765,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) pwallet->vchDefaultKey.clear(); int nFileVersion = 0; vector<uint256> vWalletUpgrade; + bool fIsEncrypted = false; // Modify defaults #ifndef WIN32 @@ -781,6 +891,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) ssValue >> vchPrivKey; if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) return DB_CORRUPT; + fIsEncrypted = true; } else if (strType == "defaultkey") { @@ -841,8 +952,11 @@ int CWalletDB::LoadWallet(CWallet* pwallet) printf("fUseUPnP = %d\n", fUseUPnP); - // Upgrade - if (nFileVersion < VERSION) + // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: + if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) + return DB_NEED_REWRITE; + + if (nFileVersion < VERSION) // Update { // Get rid of old debug.log file in current directory if (nFileVersion <= 105 && !pszSetDataDir[0]) @@ -851,7 +965,6 @@ int CWalletDB::LoadWallet(CWallet* pwallet) WriteVersion(VERSION); } - return DB_LOAD_OK; } @@ -28,14 +28,12 @@ class CBlockLocator; extern unsigned int nWalletDBUpdated; extern DbEnv dbenv; - extern void DBFlush(bool fShutdown); void ThreadFlushWalletDB(void* parg); bool BackupWallet(const CWallet& wallet, const std::string& strDest); - class CDB { protected: @@ -257,6 +255,8 @@ public: { return Write(std::string("version"), nVersion); } + + bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); }; @@ -349,6 +349,7 @@ enum DBErrors DB_CORRUPT, DB_TOO_NEW, DB_LOAD_FAIL, + DB_NEED_REWRITE }; class CWalletDB : public CDB diff --git a/src/init.cpp b/src/init.cpp index d6e153285e..a6d0ab56e3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -44,8 +44,8 @@ void Shutdown(void* parg) { static CCriticalSection cs_Shutdown; static bool fTaken; - bool fFirstThread; - CRITICAL_BLOCK(cs_Shutdown) + bool fFirstThread = false; + TRY_CRITICAL_BLOCK(cs_Shutdown) { fFirstThread = !fTaken; fTaken = true; @@ -362,6 +362,12 @@ bool AppInit2(int argc, char* argv[]) 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 if (nLoadWalletRet == DB_NEED_REWRITE) + { + strErrors += _("Wallet needed to be rewritten: restart Bitcoin to complete \n"); + wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR); + return false; + } else strErrors += _("Error loading wallet.dat \n"); } diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 89cdf43ba4..a574ef925b 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -101,7 +101,8 @@ void AskPassphraseDialog::accept() if(model->setWalletEncrypted(true, newpass1)) { QMessageBox::warning(this, tr("Wallet encrypted"), - tr("Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.")); + tr("Bitcoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.")); + QApplication::quit(); } else { diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 5ae3ce33e8..8641c723b0 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -478,11 +478,11 @@ void BitcoinGUI::error(const QString &title, const QString &message) void BitcoinGUI::changeEvent(QEvent *e) { #ifndef Q_WS_MAC // Ignored on Mac - if (e->type() == QEvent::WindowStateChange) + if(e->type() == QEvent::WindowStateChange) { - if (clientModel->getOptionsModel()->getMinimizeToTray()) + if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray()) { - if (isMinimized()) + if(isMinimized()) { hide(); e->ignore(); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index fe0987178c..5b5a8f5271 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -111,7 +111,7 @@ OverviewPage::OverviewPage(QWidget *parent) : ui->labelNumTransactions->setToolTip(tr("Total number of transactions in wallet")); // Recent transactions - ui->listTransactions->setStyleSheet("background:transparent"); + ui->listTransactions->setStyleSheet("QListView { background:transparent }"); ui->listTransactions->setItemDelegate(txdelegate); ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); ui->listTransactions->setSelectionMode(QAbstractItemView::NoSelection); diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png Binary files differindex 1086fbeb63..dbfc28ab3d 100644 --- a/src/qt/res/icons/address-book.png +++ b/src/qt/res/icons/address-book.png diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png Binary files differindex 69d59a38d2..1df9c2398d 100644 --- a/src/qt/res/icons/export.png +++ b/src/qt/res/icons/export.png diff --git a/src/qt/res/icons/history.png b/src/qt/res/icons/history.png Binary files differindex 60f1351783..10ac0e1592 100644 --- a/src/qt/res/icons/history.png +++ b/src/qt/res/icons/history.png diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png Binary files differindex 757cad47ed..ece0164f77 100644 --- a/src/qt/res/icons/key.png +++ b/src/qt/res/icons/key.png diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png Binary files differindex ce8da0bec7..c566510c40 100644 --- a/src/qt/res/icons/lock_closed.png +++ b/src/qt/res/icons/lock_closed.png diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png Binary files differindex 6a3a8edb23..c98ca8663b 100644 --- a/src/qt/res/icons/lock_open.png +++ b/src/qt/res/icons/lock_open.png diff --git a/src/qt/res/icons/overview.png b/src/qt/res/icons/overview.png Binary files differindex 6b94b43a2c..3b90fe5569 100644 --- a/src/qt/res/icons/overview.png +++ b/src/qt/res/icons/overview.png diff --git a/src/qt/res/icons/receive.png b/src/qt/res/icons/receive.png Binary files differindex e8f418a4f8..53ad1d1565 100644 --- a/src/qt/res/icons/receive.png +++ b/src/qt/res/icons/receive.png diff --git a/src/qt/res/icons/send.png b/src/qt/res/icons/send.png Binary files differindex 55ce550b4f..ceb91ea66d 100644 --- a/src/qt/res/icons/send.png +++ b/src/qt/res/icons/send.png diff --git a/src/qt/res/icons/synced.png b/src/qt/res/icons/synced.png Binary files differindex 8e428b6a70..4d7e0e8821 100644 --- a/src/qt/res/icons/synced.png +++ b/src/qt/res/icons/synced.png diff --git a/src/serialize.h b/src/serialize.h index beb87f1d04..78cff43d53 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -60,7 +60,7 @@ class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; -static const int VERSION = 50000; +static const int VERSION = 50100; static const char* pszSubVer = ""; static const bool VERSION_IS_BETA = true; diff --git a/src/wallet.cpp b/src/wallet.cpp index 64ee5c3b8c..af80cc16d5 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -187,6 +187,13 @@ bool CWallet::EncryptWallet(const string& strWalletPassphrase) } Lock(); + Unlock(strWalletPassphrase); + NewKeyPool(); + Lock(); + + // Need to completely rewrite the wallet file; if we don't, bdb might keep + // bits of the unencrypted private key in slack space in the database file. + CDB::Rewrite(strWalletFile); } return true; @@ -1142,6 +1149,18 @@ int CWallet::LoadWallet(bool& fFirstRunRet) return false; fFirstRunRet = false; int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); + if (nLoadWalletRet == DB_NEED_REWRITE) + { + if (CDB::Rewrite(strWalletFile, "\x04pool")) + { + setKeyPool.clear(); + // Note: can't top-up keypool here, because wallet is locked. + // User will be prompted to unlock wallet the next operation + // the requires a new key. + } + nLoadWalletRet = DB_NEED_REWRITE; + } + if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; fFirstRunRet = vchDefaultKey.empty(); @@ -1227,6 +1246,34 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) return true; } +// +// Mark old keypool keys as used, +// and generate all new keys +// +bool CWallet::NewKeyPool() +{ + CRITICAL_BLOCK(cs_wallet) + { + CWalletDB walletdb(strWalletFile); + BOOST_FOREACH(int64 nIndex, setKeyPool) + walletdb.ErasePool(nIndex); + setKeyPool.clear(); + + if (IsLocked()) + return false; + + int64 nKeys = max(GetArg("-keypool", 100), (int64)0); + for (int i = 0; i < nKeys; i++) + { + int64 nIndex = i+1; + walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); + setKeyPool.insert(nIndex); + } + printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys); + } + return true; +} + bool CWallet::TopUpKeyPool() { CRITICAL_BLOCK(cs_wallet) diff --git a/src/wallet.h b/src/wallet.h index 03c4703fc0..19de803390 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -90,6 +90,7 @@ public: std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); + bool NewKeyPool(); bool TopUpKeyPool(); void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); void KeepKey(int64 nIndex); |