diff options
35 files changed, 497 insertions, 266 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index a8f6b2d86c..7444ff4ac1 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = -VERSION = 0.5.0 +VERSION = 0.5.1 INCLUDEPATH += src src/json src/qt DEFINES += QT_GUI BOOST_THREAD_USE_LIB CONFIG += no_include_pwd @@ -256,7 +256,7 @@ windows:RC_FILE = src/qt/res/bitcoin-qt.rc macx:HEADERS += src/qt/macdockiconhandler.h macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit -macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 BOOST_FILESYSTEM_VERSION=3 +macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 macx:ICON = src/qt/res/icons/bitcoin.icns macx:TARGET = "Bitcoin-Qt" diff --git a/contrib/debian/changelog b/contrib/debian/changelog index ccde9776d8..6355141036 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,15 @@ +bitcoin (0.5.0-natty0) natty; urgency=low + + * New upstream release. + + -- Matt Corallo <matt@bluematt.me> Mon, 21 Nov 2011 11:32:00 -0500 + +bitcoin (0.5.0~rc7-natty0) natty; urgency=low + + * New upstream release candidate. + + -- Matt Corallo <matt@bluematt.me> Sun, 20 Nov 2011 17:08:00 -0500 + bitcoin (0.5.0~rc3-natty0) natty; urgency=low * New upstream release candidate. diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 546ffc6e1f..5db418df3a 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -31,21 +31,23 @@ License: GPL-3+ Files: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, src/qt/res/src/*.svg Copyright: Wladimir van der Laan -License: CC-BY-3 - -Files: src/qt/res/icons/send.png -Copyright: Icons Land -License: Freeware Non-commercial -Comment: Icon Pack: Vista Style Arrow - Site: http://findicons.com/icon/231371/right3green +License: Expat -Files: src/qt/res/icons/address-book.png -Copyright: FatCow Web Hosting -License: CC-BY-3 -Comment: Icon Pack: Farm-Fresh Web - Site: http://findicons.com/icon/163938/book_open +Files: src/qt/res/icons/address-book.png, src/qt/res/icons/export.png, + src/qt/res/icons/history.png, src/qt/res/icons/key.png, + src/qt/res/icons/lock_*.png, src/qt/res/icons/overview.png, + src/qt/res/icons/receive.png, src/qt/res/icons/send.png, + src/qt/res/icons/synced.png +Copyright: David Vignoni (david@icon-king.com) + ICON KING - www.icon-king.com +License: LGPL +Comment: NUVOLA ICON THEME for KDE 3.x + Original icons: kaddressbook, klipper_dock, view-list-text, + key-password, encrypted/decrypted, go-home, go-down, + go-next, dialog-ok + Site: http://www.icon-king.com/projects/nuvola/ -Files: src/qt/res/icons/connect*.png, src/qt/res/icons/synced.png, src/qt/res/icons/lock_*.png +Files: src/qt/res/icons/connect*.png Copyright: schollidesign License: GPL-3+ Comment: Icon Pack: Human-O2 @@ -65,24 +67,11 @@ Copyright: http://www.everaldo.com License: LGPL Comment: Icon Pack: Crystal SVG -Files: src/qt/res/icons/receive.png, src/qt/res/icons/history.png, - src/qt/res/icons/export.png -Copyright: Oxygen team -License: CC-BY-SA-3 -Comment: Icon Pack: Oxygen - Site: http://www.oxygen-icons.org/ - Files: src/qt/res/icons/bitcoin.png, src/qt/res/icons/toolbar.png Copyright: Bitboy (optimized for 16x16 by Wladimir van der Laan) License: PUB-DOM Comment: Site: http://forum.bitcoin.org/?topic=1756.0 -Files: src/qt/res/icons/overview.png -Copyright: Jack Cai -License: CC-BY-ND-3 -Comment: Icon Pack: Primo - Site: http://findicons.com/icon/175944/home?id=176221# - Files: scripts/img/reload.xcf, src/qt/res/movies/update_spinner.mng Copyright: Everaldo (Everaldo Coelho) License: GPL-3+ @@ -94,12 +83,6 @@ License: PUB-DOM Copyright: Crobbo (forum) Comment: Site: https://bitcointalk.org/index.php?topic=32273.0 -Files: src/qt/res/icons/key.png -Copyright: VisualPharm (Ivan Boyko) -License: CC-BY-3 -Comment: Icon Pack: Must Have - Site: http://findicons.com/icon/51009/key?id=51009 - License: Expat Permission is hereby granted, free of charge, to any person obtaining a @@ -163,27 +146,6 @@ Comment: You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. -License: CC-BY-3 - This work is licensed under a Creative Commons Attribution 3.0 Unported - License. -Comment: - You can get a full copy of the license at - <http://creativecommons.org/licenses/by/3.0/>. - -License: CC-BY-ND-3 - This work is licensed under a Creative Commons Attribution-NoDerivs 3.0 - Unported License. -Comment: - You can get a full copy of the license at - <http://creativecommons.org/licenses/by-nd/3.0/>. - -License: CC-BY-ND-3 - This work is licensed under a Creative Commons Attribution-ShareAlike - 3.0 Unported License. -Comment: - You can get a full copy of the license at - <http://creativecommons.org/licenses/by-sa/3.0/>. - License: LGPL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py new file mode 100755 index 0000000000..fd8a8b7129 --- /dev/null +++ b/contrib/qt_translations.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +# Helpful little script that spits out a comma-separated list of +# language codes for Qt icons that should be included +# in binary bitcoin distributions + +import glob +import os +import re +import sys + +if len(sys.argv) != 3: + sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0]) + +d1 = sys.argv[1] +d2 = sys.argv[2] + +l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ]) +l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ]) + +print ",".join(sorted(l1.intersection(l2))) + diff --git a/doc/assets-attribution.txt b/doc/assets-attribution.txt index 91d2e65804..5cf0a734bf 100644 --- a/doc/assets-attribution.txt +++ b/doc/assets-attribution.txt @@ -1,21 +1,20 @@ Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, src/qt/res/src/*.svg Designer: Wladimir van der Laan -License: Creative Commons Attribution - -Icon: src/qt/res/icons/send.png -Icon Pack: Vista Style Arrow -Designer: Icons Land -License: Freeware Non-commercial -Site: http://findicons.com/icon/231371/right3green - -Icon: src/qt/res/icons/address-book.png -Icon Pack: Farm-Fresh Web -Designer: FatCow Web Hosting -License: Creative Commons Attribution (by) -Site: http://findicons.com/icon/163938/book_open +License: MIT + +Icon: src/qt/res/icons/address-book.png, src/qt/res/icons/export.png, + src/qt/res/icons/history.png, src/qt/res/icons/key.png, + src/qt/res/icons/lock_*.png, src/qt/res/icons/overview.png, + src/qt/res/icons/receive.png, src/qt/res/icons/send.png, + src/qt/res/icons/synced.png +Icon Pack: NUVOLA ICON THEME for KDE 3.x +Designer: David Vignoni (david@icon-king.com) + ICON KING - www.icon-king.com +License: LGPL +Site: http://www.icon-king.com/projects/nuvola/ -Icon: src/qt/res/icons/connect*.png, src/qt/res/icons/synced.png, src/qt/res/icons/lock_*.png +Icon: src/qt/res/icons/connect*.png Icon Pack: Human-O2 Designer: schollidesign License: GNU/GPL @@ -35,24 +34,11 @@ Designer: http://www.everaldo.com Icon Pack: Crystal SVG License: LGPL -Icon: src/qt/res/icons/receive.png, src/qt/res/icons/history.png, - src/qt/res/icons/export.png -Designer: Oxygen team -Icon Pack: Oxygen -License: Creative Common Attribution-ShareAlike 3.0 License or LGPL -Site: http://www.oxygen-icons.org/ - Icon: src/qt/res/icons/bitcoin.png, src/qt/res/icons/toolbar.png Designer: Bitboy (optimized for 16x16 by Wladimir van der Laan) License: Public Domain Site: http://forum.bitcoin.org/?topic=1756.0 -Icon: src/qt/res/icons/overview.png -Icon Pack: Primo -Designer: Jack Cai -License: Creative Commons Attribution No Derivatives (by-nd) -Site: http://findicons.com/icon/175944/home?id=176221# - Icon: scripts/img/reload.xcf (modified),src/qt/res/movies/update_spinner.mng Icon Pack: Kids Designer: Everaldo (Everaldo Coelho) @@ -64,10 +50,3 @@ Designer: Crobbo (forum) Site: https://bitcointalk.org/index.php?topic=32273.0 License: Public domain -Icon: src/qt/res/icons/key.png -Designer: VisualPharm (Ivan Boyko) -Icon Pack: Must Have -Site: http://findicons.com/icon/51009/key?id=51009 -License: Creative Commons Attribution (by) - - diff --git a/doc/release-process.txt b/doc/release-process.txt index 27e2cf5b93..ac388847c2 100644 --- a/doc/release-process.txt +++ b/doc/release-process.txt @@ -1,31 +1,21 @@ * update (commit) version in sources + bitcoin-qt.pro src/serialize.h share/setup.nsi -* update (commit) version in OSX app bundle - contrib/Bitcoin.app/Contents/Info.plist - - * CFBundleShortVersionString should have value like 0.5.0 - * CFBundleVersion should have value like 500 - * tag version in git - git tag -a v0.5.0 + git tag -a v0.5.1 * write release notes. git shortlog helps a lot: - git shortlog --no-merges v0.4.0.. - -* create source-only archive - - git archive --format=tar --prefix=bitcoin-0.5.0/ HEAD | \ - gzip -9c > ~/tmp/bitcoin-0.5.0-src.tar.gz + git shortlog --no-merges v0.5.0.. * perform gitian builds * From a directory containing the bitcoin source, gitian-builder and gitian.sigs export SIGNER=(your gitian key, ie bluematt, sipa, etc) - export VERSION=0.5.0 + export VERSION=0.5.1 cd ./gitian-builder * Fetch and build inputs: @@ -42,36 +32,36 @@ cp build/out/qt-win32-4.7.4-gitian.zip inputs/ * Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32: - ./bin/gbuild --commit bitcoin=v$VERSION ../bitcoin/contrib/gitian-descriptors/gitian.yml - ./bin/gsign --signer $SIGNER --release $VERSION --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian.yml + ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml pushd build/out - zip -r bitcoin-$VERSION-linux-gitian.zip * - mv bitcoin-$VERSION-linux-gitian.zip ../../ + zip -r bitcoin-${VERSION}-linux-gitian.zip * + mv bitcoin-${VERSION}-linux-gitian.zip ../../ popd - ./bin/gbuild --commit bitcoin=v$VERSION ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml - ./bin/gsign --signer $SIGNER --release $VERSION-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml pushd build/out - zip -r bitcoin-$VERSION-win32-gitian.zip * - mv bitcoin-$VERSION-win32-gitian.zip ../../ + zip -r bitcoin-${VERSION}-win32-gitian.zip * + mv bitcoin-${VERSION}-win32-gitian.zip ../../ popd Build output expected: - 1. linux 32-bit and 64-bit binaries + source (bitcoin-$VERSION-linux-gitian.zip) - 2. windows 32-bit binary, installer + source (bitcoin-$VERSION-win32-gitian.zip) - 3. Gitian signatures (in gitian.sigs/$VERSION[-win32]/(your gitian key)/ + 1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip) + 2. windows 32-bit binary, installer + source (bitcoin-${VERSION}-win32-gitian.zip) + 3. Gitian signatures (in gitian.sigs/${VERSION}[-win32]/(your gitian key)/ * repackage gitian builds for release as stand-alone zip/tar/installer exe * Linux .tar.gz: - unzip bitcoin-$VERSION-linux-gitian.zip -d bitcoin-$VERSION-linux - tar czvf bitcoin-$VERSION-linux.tar.gz bitcoin-$VERSION-linux - rm -rf bitcoin-$VERSION-linux + unzip bitcoin-${VERSION}-linux-gitian.zip -d bitcoin-${VERSION}-linux + tar czvf bitcoin-${VERSION}-linux.tar.gz bitcoin-${VERSION}-linux + rm -rf bitcoin-${VERSION}-linux * Windows .zip and setup.exe: - unzip bitcoin-$VERSION-win32-gitian.zip -d bitcoin-$VERSION-win32 - mv bitcoin-$VERSION-win32/bitcoin-*-setup.exe . - zip -r bitcoin-$VERSION-win32.zip bitcoin-$VERSION-win32 - rm -rf bitcoin-$VERSION-win32 + unzip bitcoin-${VERSION}-win32-gitian.zip -d bitcoin-${VERSION}-win32 + mv bitcoin-${VERSION}-win32/bitcoin-*-setup.exe . + zip -r bitcoin-${VERSION}-win32.zip bitcoin-${VERSION}-win32 + rm -rf bitcoin-${VERSION}-win32 * perform Mac build See this blog post for how Gavin set up his build environment and @@ -80,7 +70,8 @@ qmake USE_SSL=1 USE_UPNP=1 bitcoin-qt.pro make export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files - contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr de,es,ru -dmg -fancy contrib/macdeploy/fancy.plist + T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) + contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist Build output expected: Bitcoin-Qt.dmg @@ -93,36 +84,45 @@ * update forum version -* update wiki - * update wiki download links -* release gitian-signed gitian archives +* Commit your signature to gitian.sigs: + pushd gitian.sigs + git add ${VERSION}/${SIGNER} + git add ${VERSION}-win32/${SIGNER} + git commit -a + git push # Assuming you can push to the gitian.sigs tree + popd - * Collect enough gitian signatures to meet minimum_weight (see contrib/gitian-downloader/*-download-config) +------------------------------------------------------------------------- + +* After 3 or more people have gitian-built, repackage gitian-signed zips: * From a directory containing bitcoin source, gitian.sigs and gitian zips - export VERSION=0.5.0 - mkdir bitcoin-$VERSION-linux-gitian; cd bitcoin-$VERSION-linux-gitian - unzip ../bitcoin-$VERSION-linux-gitian.zip + export VERSION=0.5.1 + mkdir bitcoin-${VERSION}-linux-gitian + pushd bitcoin-${VERSION}-linux-gitian + unzip ../bitcoin-${VERSION}-linux-gitian.zip mkdir gitian cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ - for file in `ls ../gitian.sigs/$VERSION/`; do - cp ../gitian.sigs/$VERSION/$file/bitcoin-build.assert ./gitian/$file-build.assert - cp ../gitian.sigs/$VERSION/$file/bitcoin-build.assert.sig ./gitian/$file-build.assert.sig + for signer in $(ls ../gitian.sigs/${VERSION}/); do + cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig done - zip -r bitcoin-$VERSION-linux-gitian.zip * - cp bitcoin-$VERSION-linux-gitian.zip ../ - cd .. - mkdir bitcoin-$VERSION-linux-gitian; cd bitcoin-$VERSION-linux-gitian - unzip ../bitcoin-$VERSION-linux-gitian.zip + zip -r bitcoin-${VERSION}-linux-gitian.zip * + cp bitcoin-${VERSION}-linux-gitian.zip ../ + popd + mkdir bitcoin-${VERSION}-win32-gitian + pushd bitcoin-${VERSION}-win32-gitian + unzip ../bitcoin-${VERSION}-win32-gitian.zip mkdir gitian cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ - for file in `ls ../gitian.sigs/$VERSION/`; do - cp ../gitian.sigs/$VERSION/$file/bitcoin-build.assert ./gitian/$file-build.assert - cp ../gitian.sigs/$VERSION/$file/bitcoin-build.assert.sig ./gitian/$file-build.assert.sig + for signer in $(ls ../gitian.sigs/${VERSION}-win32/); do + cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig done - zip -r bitcoin-$VERSION-linux-gitian.zip * - cp bitcoin-$VERSION-linux-gitian.zip ../ + zip -r bitcoin-${VERSION}-win32-gitian.zip * + cp bitcoin-${VERSION}-win32-gitian.zip ../ + popd * Upload gitian zips to SourceForge diff --git a/share/setup.nsi b/share/setup.nsi index 19f5a5329b..0c0fa048af 100644 --- a/share/setup.nsi +++ b/share/setup.nsi @@ -5,7 +5,7 @@ SetCompressor /SOLID lzma # General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
-!define VERSION 0.5.0
+!define VERSION 0.5.1
!define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/
@@ -45,13 +45,13 @@ Var StartMenuGroup !insertmacro MUI_LANGUAGE English
# Installer attributes
-OutFile bitcoin-0.5.0-win32-setup.exe
+OutFile bitcoin-0.5.1-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on
XPStyle on
BrandingText " "
ShowInstDetails show
-VIProductVersion 0.5.0.0
+VIProductVersion 0.5.1.0
VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index a7ffe14e0c..2857b7575e 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -161,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 } @@ -1556,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()); @@ -1575,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"; } @@ -2177,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/aboutdialog.cpp b/src/qt/aboutdialog.cpp index 13d263b75c..a3aa6de841 100644 --- a/src/qt/aboutdialog.cpp +++ b/src/qt/aboutdialog.cpp @@ -12,7 +12,10 @@ AboutDialog::AboutDialog(QWidget *parent) : void AboutDialog::setModel(ClientModel *model) { - ui->versionLabel->setText(model->formatFullVersion()); + if(model) + { + ui->versionLabel->setText(model->formatFullVersion()); + } } AboutDialog::~AboutDialog() diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 6be59a082f..0a147c9e10 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -57,6 +57,8 @@ AddressBookPage::~AddressBookPage() void AddressBookPage::setModel(AddressTableModel *model) { this->model = model; + if(!model) + return; // Refresh list from core model->updateList(); @@ -96,16 +98,13 @@ void AddressBookPage::setModel(AddressTableModel *model) selectionChanged(); } -QTableView *AddressBookPage::getCurrentTable() -{ - return ui->tableView; -} - void AddressBookPage::on_copyToClipboard_clicked() { // Copy currently selected address to clipboard // (or nothing, if nothing selected) - QTableView *table = getCurrentTable(); + QTableView *table = ui->tableView; + if(!table->selectionModel()) + return; QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); foreach (QModelIndex index, indexes) @@ -117,6 +116,8 @@ void AddressBookPage::on_copyToClipboard_clicked() void AddressBookPage::on_newAddressButton_clicked() { + if(!model) + return; EditAddressDialog dlg( tab == SendingTab ? EditAddressDialog::NewSendingAddress : @@ -139,7 +140,9 @@ void AddressBookPage::on_newAddressButton_clicked() void AddressBookPage::on_deleteButton_clicked() { - QTableView *table = getCurrentTable(); + QTableView *table = ui->tableView; + if(!table->selectionModel()) + return; QModelIndexList indexes = table->selectionModel()->selectedRows(); if(!indexes.isEmpty()) { @@ -150,7 +153,9 @@ void AddressBookPage::on_deleteButton_clicked() void AddressBookPage::selectionChanged() { // Set button states based on selected tab and selection - QTableView *table = getCurrentTable(); + QTableView *table = ui->tableView; + if(!table->selectionModel()) + return; if(table->selectionModel()->hasSelection()) { @@ -174,12 +179,14 @@ void AddressBookPage::selectionChanged() void AddressBookPage::done(int retval) { + QTableView *table = ui->tableView; + if(!table->selectionModel() || !table->model()) + return; // When this is a tab/widget and not a model dialog, ignore "done" if(mode == ForEditing) return; // Figure out which address was selected, and return it - QTableView *table = getCurrentTable(); QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); foreach (QModelIndex index, indexes) diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 53c7728c8c..ef64d17539 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -47,8 +47,6 @@ private: QString returnValue; QSortFilterProxyModel *proxyModel; - QTableView *getCurrentTable(); - private slots: void on_deleteButton_clicked(); void on_newAddressButton_clicked(); diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index a297513a62..a574ef925b 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -72,6 +72,8 @@ void AskPassphraseDialog::setModel(WalletModel *model) void AskPassphraseDialog::accept() { std::string oldpass, newpass1, newpass2; + if(!model) + return; // TODO: mlock memory / munlock on return so they will not be swapped out, really need "mlockedstring" wrapper class to do this safely oldpass.reserve(MAX_PASSPHRASE_SIZE); newpass1.reserve(MAX_PASSPHRASE_SIZE); @@ -99,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 b9995fdd62..8641c723b0 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -267,58 +267,62 @@ void BitcoinGUI::createToolBars() void BitcoinGUI::setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; - - if(clientModel->isTestNet()) + if(clientModel) { - QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]"); - setWindowTitle(title_testnet); + if(clientModel->isTestNet()) + { + QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]"); + setWindowTitle(title_testnet); #ifndef Q_WS_MAC - setWindowIcon(QIcon(":icons/bitcoin_testnet")); + setWindowIcon(QIcon(":icons/bitcoin_testnet")); #else - MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); #endif - if(trayIcon) - { - trayIcon->setToolTip(title_testnet); - trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); + if(trayIcon) + { + trayIcon->setToolTip(title_testnet); + trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); + } } - } - // Keep up to date with client - setNumConnections(clientModel->getNumConnections()); - connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + // Keep up to date with client + setNumConnections(clientModel->getNumConnections()); + connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(clientModel->getNumBlocks()); - connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); + setNumBlocks(clientModel->getNumBlocks()); + connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); - // Report errors from network/worker thread - connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); + // Report errors from network/worker thread + connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); + } } void BitcoinGUI::setWalletModel(WalletModel *walletModel) { this->walletModel = walletModel; + if(walletModel) + { + // Report errors from wallet thread + connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); - // Report errors from wallet thread - connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); - - // Put transaction list in tabs - transactionView->setModel(walletModel); + // Put transaction list in tabs + transactionView->setModel(walletModel); - overviewPage->setModel(walletModel); - addressBookPage->setModel(walletModel->getAddressTableModel()); - receiveCoinsPage->setModel(walletModel->getAddressTableModel()); - sendCoinsPage->setModel(walletModel); + overviewPage->setModel(walletModel); + addressBookPage->setModel(walletModel->getAddressTableModel()); + receiveCoinsPage->setModel(walletModel->getAddressTableModel()); + sendCoinsPage->setModel(walletModel); - setEncryptionStatus(walletModel->getEncryptionStatus()); - connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int))); + setEncryptionStatus(walletModel->getEncryptionStatus()); + connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int))); - // Balloon popup for new transaction - connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(incomingTransaction(QModelIndex,int,int))); + // Balloon popup for new transaction + connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(incomingTransaction(QModelIndex,int,int))); - // Ask for passphrase if needed - connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + // Ask for passphrase if needed + connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + } } void BitcoinGUI::createTrayIcon() @@ -369,6 +373,8 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) void BitcoinGUI::optionsClicked() { + if(!clientModel || !clientModel->getOptionsModel()) + return; OptionsDialog dlg; dlg.setModel(clientModel->getOptionsModel()); dlg.exec(); @@ -398,6 +404,8 @@ void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumBlocks(int count) { + if(!clientModel) + return; int initTotal = clientModel->getNumBlocksAtStartup(); int total = clientModel->getNumBlocksOfPeers(); QString tooltip; @@ -470,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(); @@ -492,13 +500,16 @@ void BitcoinGUI::changeEvent(QEvent *e) void BitcoinGUI::closeEvent(QCloseEvent *event) { -#ifndef Q_WS_MAC // Ignored on Mac - if(!clientModel->getOptionsModel()->getMinimizeToTray() && - !clientModel->getOptionsModel()->getMinimizeOnClose()) + if(clientModel) { - qApp->quit(); - } +#ifndef Q_WS_MAC // Ignored on Mac + if(!clientModel->getOptionsModel()->getMinimizeToTray() && + !clientModel->getOptionsModel()->getMinimizeOnClose()) + { + qApp->quit(); + } #endif + } QMainWindow::closeEvent(event); } @@ -517,6 +528,8 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end) { + if(!walletModel || !clientModel) + return; TransactionTableModel *ttm = walletModel->getTransactionTableModel(); qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent) .data(Qt::EditRole).toULongLong(); @@ -654,6 +667,8 @@ void BitcoinGUI::setEncryptionStatus(int status) void BitcoinGUI::encryptWallet(bool status) { + if(!walletModel) + return; AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt: AskPassphraseDialog::Decrypt, this); dlg.setModel(walletModel); @@ -671,6 +686,8 @@ void BitcoinGUI::changePassphrase() void BitcoinGUI::unlockWallet() { + if(!walletModel) + return; // Unlock wallet when requested by wallet model if(walletModel->getEncryptionStatus() == WalletModel::Locked) { diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index 62c0b949aa..4b21b8c4be 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -48,7 +48,11 @@ bool CSVModelWriter::write() return false; QTextStream out(&file); - int numRows = model->rowCount(); + int numRows = 0; + if(model) + { + numRows = model->rowCount(); + } // Header row for(int i=0; i<columns.size(); ++i) diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 457e8cf0dc..8cc3c85d7a 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -56,6 +56,8 @@ void EditAddressDialog::loadRow(int row) bool EditAddressDialog::saveCurrentRow() { + if(!model) + return false; switch(mode) { case NewReceivingAddress: @@ -78,6 +80,8 @@ bool EditAddressDialog::saveCurrentRow() void EditAddressDialog::accept() { + if(!model) + return; if(!saveCurrentRow()) { switch(model->getEditStatus()) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 6dedde0272..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); @@ -143,30 +143,34 @@ void OverviewPage::setNumTransactions(int count) void OverviewPage::setModel(WalletModel *model) { this->model = model; + if(model) + { + // Set up transaction list + TransactionFilterProxy *filter = new TransactionFilterProxy(); + filter->setSourceModel(model->getTransactionTableModel()); + filter->setLimit(NUM_ITEMS); + filter->setDynamicSortFilter(true); + filter->setSortRole(Qt::EditRole); + filter->sort(TransactionTableModel::Status, Qt::DescendingOrder); - // Set up transaction list - TransactionFilterProxy *filter = new TransactionFilterProxy(); - filter->setSourceModel(model->getTransactionTableModel()); - filter->setLimit(NUM_ITEMS); - filter->setDynamicSortFilter(true); - filter->setSortRole(Qt::EditRole); - filter->sort(TransactionTableModel::Status, Qt::DescendingOrder); - - ui->listTransactions->setModel(filter); - ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); + ui->listTransactions->setModel(filter); + ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); - // Keep up to date with wallet - setBalance(model->getBalance(), model->getUnconfirmedBalance()); - connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64))); + // Keep up to date with wallet + setBalance(model->getBalance(), model->getUnconfirmedBalance()); + connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64))); - setNumTransactions(model->getNumTransactions()); - connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); + setNumTransactions(model->getNumTransactions()); + connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(displayUnitChanged())); + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(displayUnitChanged())); + } } void OverviewPage::displayUnitChanged() { + if(!model || !model->getOptionsModel()) + return; if(currentBalance != -1) setBalance(currentBalance, currentUnconfirmedBalance); 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/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 719cc51880..762f27dfa6 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -43,9 +43,11 @@ void SendCoinsDialog::setModel(WalletModel *model) entry->setModel(model); } } - - setBalance(model->getBalance(), model->getUnconfirmedBalance()); - connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64))); + if(model) + { + setBalance(model->getBalance(), model->getUnconfirmedBalance()); + connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64))); + } } SendCoinsDialog::~SendCoinsDialog() @@ -57,6 +59,10 @@ void SendCoinsDialog::on_sendButton_clicked() { QList<SendCoinsRecipient> recipients; bool valid = true; + + if(!model) + return; + for(int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget()); @@ -255,6 +261,9 @@ void SendCoinsDialog::handleURL(const QUrl *url) void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance) { Q_UNUSED(unconfirmedBalance); + if(!model || !model->getOptionsModel()) + return; + int unit = model->getOptionsModel()->getDisplayUnit(); ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance)); } diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 1802095b3a..23b11ccdde 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -44,6 +44,8 @@ void SendCoinsEntry::on_pasteButton_clicked() void SendCoinsEntry::on_addressBookButton_clicked() { + if(!model) + return; AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this); dlg.setModel(model->getAddressTableModel()); if(dlg.exec()) @@ -55,6 +57,8 @@ void SendCoinsEntry::on_addressBookButton_clicked() void SendCoinsEntry::on_payTo_textChanged(const QString &address) { + if(!model) + return; ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address)); } @@ -74,7 +78,7 @@ void SendCoinsEntry::clear() ui->addAsLabel->clear(); ui->payAmount->clear(); ui->payTo->setFocus(); - if(model) + if(model && model->getOptionsModel()) { ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); } diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index d39227c81f..2dcbf1ea8a 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -155,36 +155,39 @@ TransactionView::TransactionView(QWidget *parent) : void TransactionView::setModel(WalletModel *model) { this->model = model; - - transactionProxyModel = new TransactionFilterProxy(this); - transactionProxyModel->setSourceModel(model->getTransactionTableModel()); - transactionProxyModel->setDynamicSortFilter(true); - - transactionProxyModel->setSortRole(Qt::EditRole); - - transactionView->setModel(transactionProxyModel); - transactionView->setAlternatingRowColors(true); - transactionView->setSelectionBehavior(QAbstractItemView::SelectRows); - transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection); - transactionView->setSortingEnabled(true); - transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder); - transactionView->verticalHeader()->hide(); - - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Status, 23); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Date, 120); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Type, 120); - transactionView->horizontalHeader()->setResizeMode( - TransactionTableModel::ToAddress, QHeaderView::Stretch); - transactionView->horizontalHeader()->resizeSection( - TransactionTableModel::Amount, 100); - + if(model) + { + transactionProxyModel = new TransactionFilterProxy(this); + transactionProxyModel->setSourceModel(model->getTransactionTableModel()); + transactionProxyModel->setDynamicSortFilter(true); + + transactionProxyModel->setSortRole(Qt::EditRole); + + transactionView->setModel(transactionProxyModel); + transactionView->setAlternatingRowColors(true); + transactionView->setSelectionBehavior(QAbstractItemView::SelectRows); + transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection); + transactionView->setSortingEnabled(true); + transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder); + transactionView->verticalHeader()->hide(); + + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Status, 23); + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Date, 120); + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Type, 120); + transactionView->horizontalHeader()->setResizeMode( + TransactionTableModel::ToAddress, QHeaderView::Stretch); + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Amount, 100); + } } void TransactionView::chooseDate(int idx) { + if(!transactionProxyModel) + return; QDate current = QDate::currentDate(); dateRangeWidget->setVisible(false); switch(dateWidget->itemData(idx).toInt()) @@ -231,17 +234,23 @@ void TransactionView::chooseDate(int idx) void TransactionView::chooseType(int idx) { + if(!transactionProxyModel) + return; transactionProxyModel->setTypeFilter( typeWidget->itemData(idx).toInt()); } void TransactionView::changedPrefix(const QString &prefix) { + if(!transactionProxyModel) + return; transactionProxyModel->setAddressPrefix(prefix); } void TransactionView::changedAmount(const QString &amount) { + if(!transactionProxyModel) + return; qint64 amount_parsed = 0; if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed)) { @@ -294,6 +303,8 @@ void TransactionView::contextualMenu(const QPoint &point) void TransactionView::copyAddress() { + if(!transactionView->selectionModel()) + return; QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { @@ -303,6 +314,8 @@ void TransactionView::copyAddress() void TransactionView::copyLabel() { + if(!transactionView->selectionModel()) + return; QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { @@ -312,10 +325,14 @@ void TransactionView::copyLabel() void TransactionView::editLabel() { + if(!transactionView->selectionModel() ||!model) + return; QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { AddressTableModel *addressBook = model->getAddressTableModel(); + if(!addressBook) + return; QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString(); if(address.isEmpty()) { @@ -354,6 +371,8 @@ void TransactionView::editLabel() void TransactionView::showDetails() { + if(!transactionView->selectionModel()) + return; QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { @@ -400,6 +419,8 @@ QWidget *TransactionView::createDateRangeWidget() void TransactionView::dateRangeChanged() { + if(!transactionProxyModel) + return; transactionProxyModel->setDateRange( QDateTime(dateFrom->date()), QDateTime(dateTo->date()).addDays(1)); 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); |