diff options
48 files changed, 389 insertions, 232 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index e2097fd4b0..933f4a70da 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -19,14 +19,6 @@ OBJECTS_DIR = build MOC_DIR = build UI_DIR = build -# use: qmake "USE_QRCODE=1" -# libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support -contains(USE_QRCODE, 1) { - message(Building with QRCode support) - DEFINES += USE_QRCODE - LIBS += -lqrencode -} - # use: qmake "RELEASE=1" contains(RELEASE, 1) { # Mac: compile for maximum compatibility (10.5, 32-bit) @@ -38,6 +30,14 @@ contains(RELEASE, 1) { } } +# use: qmake "USE_QRCODE=1" +# libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support +contains(USE_QRCODE, 1) { + message(Building with QRCode support) + DEFINES += USE_QRCODE + LIBS += -lqrencode +} + # use: qmake "USE_UPNP=1" ( enabled by default; default) # or: qmake "USE_UPNP=0" (disabled by default) # or: qmake "USE_UPNP=-" (not supported) diff --git a/contrib/debian/control b/contrib/debian/control index c41664ca6f..745fd71ea8 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -15,7 +15,8 @@ Build-Depends: debhelper, libboost-thread-dev (>> 1.35) | libboost-thread1.35-dev, libboost-test-dev (>> 1.35) | libboost-test1.35-dev, qt4-qmake, - libqt4-dev + libqt4-dev, + libqrencode-dev Standards-Version: 3.9.2 Homepage: http://www.bitcoin.org/ Vcs-Git: git://github.com/bitcoin/bitcoin.git diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 5db418df3a..71fa77cf6c 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -37,7 +37,7 @@ 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 + src/qt/res/icons/synced.png, src/qt/res/icons/filesave.png Copyright: David Vignoni (david@icon-king.com) ICON KING - www.icon-king.com License: LGPL diff --git a/contrib/debian/rules b/contrib/debian/rules index a1d65652e3..6d6f119b59 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -20,7 +20,7 @@ override_dh_auto_clean: cd src; $(MAKE) -f makefile.unix clean override_dh_auto_configure: - qmake bitcoin-qt.pro + qmake bitcoin-qt.pro USE_SSL=1 USE_QRCODE=1 override_dh_auto_test: cd src; $(MAKE) -f makefile.unix test_bitcoin diff --git a/contrib/gitian-descriptors/deps-win32.yml b/contrib/gitian-descriptors/deps-win32.yml index 4485f3658f..0107b306ec 100644 --- a/contrib/gitian-descriptors/deps-win32.yml +++ b/contrib/gitian-descriptors/deps-win32.yml @@ -59,5 +59,3 @@ script: | cd .. # tar cjvpf "$OUTDIR/bitcoin-deps-0.0.1.tbz2" "$HOME/build" - - diff --git a/contrib/gitian-descriptors/gitian.yml b/contrib/gitian-descriptors/gitian.yml index 8a0ee0e038..086e09743d 100644 --- a/contrib/gitian-descriptors/gitian.yml +++ b/contrib/gitian-descriptors/gitian.yml @@ -16,13 +16,15 @@ packages: - "libssl-dev" - "git-core" - "unzip" -- "libqrencode-dev" +- "pkg-config" +- "libpng12-dev" reference_datetime: "2011-01-30 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" files: - "miniupnpc-1.6.tar.gz" +- "qrencode-3.2.0.tar.bz2" script: | INSTDIR="$HOME/install" export LIBRARY_PATH="$INSTDIR/lib" @@ -32,6 +34,12 @@ script: | INSTALLPREFIX=$INSTDIR make $MAKEOPTS install cd .. # + tar xjf qrencode-3.2.0.tar.bz2 + cd qrencode-3.2.0 + ./configure --prefix=$INSTDIR --enable-static --disable-shared + make $MAKEOPTS install + cd .. + # cd bitcoin mkdir -p $OUTDIR/src cp -a . $OUTDIR/src diff --git a/doc/assets-attribution.txt b/doc/assets-attribution.txt index 5cf0a734bf..fabcdeea76 100644 --- a/doc/assets-attribution.txt +++ b/doc/assets-attribution.txt @@ -7,7 +7,7 @@ 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 + src/qt/res/icons/synced.png, src/qt/res/icons/filesave.png Icon Pack: NUVOLA ICON THEME for KDE 3.x Designer: David Vignoni (david@icon-king.com) ICON KING - www.icon-king.com diff --git a/src/bignum.h b/src/bignum.h index 4143f6003d..a750025f3d 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -243,7 +243,7 @@ public: std::vector<unsigned char> getvch() const { unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) + if (nSize <= 4) return std::vector<unsigned char>(); std::vector<unsigned char> vch(nSize); BN_bn2mpi(this, &vch[0]); diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 5d38f042f9..be40e937b8 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -353,7 +353,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); + obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } @@ -1537,35 +1537,41 @@ void ThreadTopUpKeyPool(void* parg) void ThreadCleanWalletPassphrase(void* parg) { - int64 nMyWakeTime = GetTime() + *((int*)parg); + int64 nMyWakeTime = GetTimeMillis() + *((int*)parg) * 1000; + + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); if (nWalletUnlockTime == 0) { - CRITICAL_BLOCK(cs_nWalletUnlockTime) + nWalletUnlockTime = nMyWakeTime; + + do { - nWalletUnlockTime = nMyWakeTime; - } + if (nWalletUnlockTime==0) + break; + int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); + if (nToSleep <= 0) + break; + + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); + Sleep(nToSleep); + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - while (GetTime() < nWalletUnlockTime) - Sleep(GetTime() - nWalletUnlockTime); + } while(1); - CRITICAL_BLOCK(cs_nWalletUnlockTime) + if (nWalletUnlockTime) { nWalletUnlockTime = 0; + pwalletMain->Lock(); } } else { - CRITICAL_BLOCK(cs_nWalletUnlockTime) - { - if (nWalletUnlockTime < nMyWakeTime) - nWalletUnlockTime = nMyWakeTime; - } - delete (int*)parg; - return; + if (nWalletUnlockTime < nMyWakeTime) + nWalletUnlockTime = nMyWakeTime; } - pwalletMain->Lock(); + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); delete (int*)parg; } @@ -1655,9 +1661,9 @@ Value walletlock(const Array& params, bool fHelp) if (!pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called."); - pwalletMain->Lock(); CRITICAL_BLOCK(cs_nWalletUnlockTime) { + pwalletMain->Lock(); nWalletUnlockTime = 0; } @@ -1810,7 +1816,7 @@ Value getwork(const Array& params, bool fHelp) } // Update nTime - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->UpdateTime(pindexPrev); pblock->nNonce = 0; // Update nExtraNonce @@ -1910,7 +1916,7 @@ Value getmemorypool(const Array& params, bool fHelp) } // Update nTime - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->UpdateTime(pindexPrev); pblock->nNonce = 0; Array transactions; @@ -2349,15 +2355,15 @@ void ThreadRPCServer(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg)); try { - vnThreadsRunning[4]++; + vnThreadsRunning[THREAD_RPCSERVER]++; ThreadRPCServer2(parg); - vnThreadsRunning[4]--; + vnThreadsRunning[THREAD_RPCSERVER]--; } catch (std::exception& e) { - vnThreadsRunning[4]--; + vnThreadsRunning[THREAD_RPCSERVER]--; PrintException(&e, "ThreadRPCServer()"); } catch (...) { - vnThreadsRunning[4]--; + vnThreadsRunning[THREAD_RPCSERVER]--; PrintException(NULL, "ThreadRPCServer()"); } printf("ThreadRPCServer exiting\n"); @@ -2437,7 +2443,7 @@ void ThreadRPCServer2(void* parg) #endif ip::tcp::endpoint peer; - vnThreadsRunning[4]--; + vnThreadsRunning[THREAD_RPCSERVER]--; #ifdef USE_SSL acceptor.accept(sslStream.lowest_layer(), peer); #else diff --git a/src/db.cpp b/src/db.cpp index 3bdda61569..ea6d46a6e5 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -6,6 +6,7 @@ #include "headers.h" #include "db.h" #include "net.h" +#include <boost/version.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -939,6 +940,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) ssValue >> nMinVersion; if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; + pwallet->LoadMinVersion(nMinVersion); } else if (strType == "cscript") { @@ -1064,14 +1066,19 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) filesystem::path pathDest(strDest); if (filesystem::is_directory(pathDest)) pathDest = pathDest / wallet.strWalletFile; + + try { #if BOOST_VERSION >= 104000 - filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); + filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); #else - filesystem::copy_file(pathSrc, pathDest); + filesystem::copy_file(pathSrc, pathDest); #endif - printf("copied wallet.dat to %s\n", pathDest.string().c_str()); - - return true; + printf("copied wallet.dat to %s\n", pathDest.string().c_str()); + return true; + } catch(const filesystem::filesystem_error &e) { + printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what()); + return false; + } } } Sleep(100); @@ -486,6 +486,11 @@ public: return Write(std::make_pair(std::string("setting"), strKey), value); } + bool WriteMinVersion(int nVersion) + { + return Write(std::string("minversion"), nVersion); + } + bool ReadAccount(const std::string& strAccount, CAccount& account); bool WriteAccount(const std::string& strAccount, const CAccount& account); bool WriteAccountingEntry(const CAccountingEntry& acentry); diff --git a/src/init.cpp b/src/init.cpp index 22f34aa755..f09f044f16 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -197,6 +197,9 @@ bool AppInit2(int argc, char* argv[]) " -connect=<ip> \t\t " + _("Connect only to the specified node") + "\n" + " -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" + " -listen \t " + _("Accept connections from outside (default: 1)") + "\n" + +#ifdef QT_GUI + " -lang=<lang> \t\t " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" + +#endif " -dnsseed \t " + _("Find peers using DNS lookup (default: 1)") + "\n" + " -banscore=<n> \t " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -bantime=<n> \t " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + @@ -210,10 +213,10 @@ bool AppInit2(int argc, char* argv[]) #endif #endif " -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send") + "\n" + -#ifdef GUI +#ifdef QT_GUI " -server \t\t " + _("Accept command line and JSON-RPC commands") + "\n" + #endif -#ifndef WIN32 +#if !defined(WIN32) && !defined(QT_GUI) " -daemon \t\t " + _("Run in the background as a daemon and accept commands") + "\n" + #endif " -testnet \t\t " + _("Use the test network") + "\n" + @@ -246,14 +249,19 @@ bool AppInit2(int argc, char* argv[]) // Remove tabs strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end()); +#if defined(QT_GUI) && defined(WIN32) + // On windows, show a message box, as there is no stderr + wxMessageBox(strUsage, "Usage"); +#else fprintf(stderr, "%s", strUsage.c_str()); +#endif return false; } fTestNet = GetBoolArg("-testnet"); fDebug = GetBoolArg("-debug"); -#ifndef WIN32 +#if !defined(WIN32) && !defined(QT_GUI) fDaemon = GetBoolArg("-daemon"); #else fDaemon = false; @@ -284,7 +292,7 @@ bool AppInit2(int argc, char* argv[]) } #endif -#ifndef WIN32 +#if !defined(WIN32) && !defined(QT_GUI) if (fDaemon) { // Daemonize @@ -114,7 +114,7 @@ public: return fCompressedPubKey; } - void MakeNewKey(bool fCompressed = true) + void MakeNewKey(bool fCompressed) { if (!EC_KEY_generate_key(pkey)) throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); @@ -141,10 +141,13 @@ public: 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) + if (bn == NULL) throw key_error("CKey::SetSecret() : BN_bin2bn failed"); if (!EC_KEY_regenerate_key(pkey,bn)) + { + BN_clear_free(bn); throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); + } BN_clear_free(bn); fSet = true; if (fCompressed || fCompressedPubKey) diff --git a/src/keystore.cpp b/src/keystore.cpp index 18e5c377dc..e76f7790f1 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -8,16 +8,6 @@ #include "db.h" #include "script.h" -std::vector<unsigned char> CKeyStore::GenerateNewKey() -{ - RandAddSeedPerfmon(); - CKey key; - key.MakeNewKey(); - if (!AddKey(key)) - throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed"); - return key.GetPubKey(); -} - bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const { CKey key; diff --git a/src/keystore.h b/src/keystore.h index 7eea02def3..6757834bd8 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -29,8 +29,6 @@ public: virtual bool HaveCScript(const uint160 &hash) const =0; virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0; - // Generate a new key, and add it to the store - virtual std::vector<unsigned char> GenerateNewKey(); virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const { CKey key; diff --git a/src/main.cpp b/src/main.cpp index e4c6714eae..b73037fb6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -922,6 +922,15 @@ void static InvalidChainFound(CBlockIndex* pindexNew) printf("InvalidChainFound: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); } +void CBlock::UpdateTime(const CBlockIndex* pindexPrev) +{ + nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + + // Updating time can change work required on testnet: + if (fTestNet) + nBits = GetNextWorkRequired(pindexPrev, this); +} + @@ -3168,7 +3177,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->UpdateTime(pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get()); pblock->nNonce = 0; @@ -3326,6 +3335,7 @@ void static BitcoinMiner(CWallet *pwallet) FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1); unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); + unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8); unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12); @@ -3390,7 +3400,7 @@ void static BitcoinMiner(CWallet *pwallet) { nLogTime = GetTime(); printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); - printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0); + printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0); } } } @@ -3401,7 +3411,7 @@ void static BitcoinMiner(CWallet *pwallet) return; if (!fGenerateBitcoins) return; - if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors) + if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors) return; if (vNodes.empty()) break; @@ -3413,8 +3423,14 @@ void static BitcoinMiner(CWallet *pwallet) break; // Update nTime every few seconds - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->UpdateTime(pindexPrev); nBlockTime = ByteReverse(pblock->nTime); + if (fTestNet) + { + // Changing pblock->nTime can change work required on testnet: + nBlockBits = ByteReverse(pblock->nBits); + hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + } } } } @@ -3424,22 +3440,22 @@ void static ThreadBitcoinMiner(void* parg) CWallet* pwallet = (CWallet*)parg; try { - vnThreadsRunning[3]++; + vnThreadsRunning[THREAD_MINER]++; BitcoinMiner(pwallet); - vnThreadsRunning[3]--; + vnThreadsRunning[THREAD_MINER]--; } catch (std::exception& e) { - vnThreadsRunning[3]--; + vnThreadsRunning[THREAD_MINER]--; PrintException(&e, "ThreadBitcoinMiner()"); } catch (...) { - vnThreadsRunning[3]--; + vnThreadsRunning[THREAD_MINER]--; PrintException(NULL, "ThreadBitcoinMiner()"); } UIThreadCall(boost::bind(CalledSetStatusBar, "", 0)); nHPSTimerStart = 0; - if (vnThreadsRunning[3] == 0) + if (vnThreadsRunning[THREAD_MINER] == 0) dHashesPerSec = 0; - printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]); + printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]); } @@ -3459,7 +3475,7 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet) nProcessors = 1; if (fLimitProcessors && nProcessors > nLimitProcessors) nProcessors = nLimitProcessors; - int nAddThreads = nProcessors - vnThreadsRunning[3]; + int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER]; printf("Starting %d BitcoinMiner threads\n", nAddThreads); for (int i = 0; i < nAddThreads; i++) { diff --git a/src/main.h b/src/main.h index 908ada7d4f..d9f976c217 100644 --- a/src/main.h +++ b/src/main.h @@ -913,6 +913,7 @@ public: return (int64)nTime; } + void UpdateTime(const CBlockIndex* pindexPrev); uint256 BuildMerkleTree() const diff --git a/src/makefile.unix b/src/makefile.unix index 41452dec81..80b5bca341 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -7,7 +7,7 @@ USE_UPNP:=0 DEFS=-DNOPCH DEFS += $(addprefix -I,$(CURDIR) $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) -LIBS += $(addprefix -l,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) +LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) LMODE = dynamic LMODE2 = dynamic @@ -21,7 +21,7 @@ else endif # for boost 1.37, add -mt to the boost libraries -LIBS= \ +LIBS += \ -Wl,-B$(LMODE) \ -l boost_system$(BOOST_LIB_SUFFIX) \ -l boost_filesystem$(BOOST_LIB_SUFFIX) \ diff --git a/src/net.cpp b/src/net.cpp index 63829d0e0a..fd488ce671 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -38,8 +38,6 @@ bool OpenNetworkConnection(const CAddress& addrConnect); - - // // Global state variables // @@ -49,7 +47,7 @@ uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices); static CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; -array<int, 10> vnThreadsRunning; +array<int, THREAD_MAX> vnThreadsRunning; static SOCKET hListenSocket = INVALID_SOCKET; vector<CNode*> vNodes; @@ -67,7 +65,6 @@ CCriticalSection cs_setservAddNodeAddresses; - unsigned short GetListenPort() { return (unsigned short)(GetArg("-port", GetDefaultPort())); @@ -602,15 +599,15 @@ void ThreadSocketHandler(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg)); try { - vnThreadsRunning[0]++; + vnThreadsRunning[THREAD_SOCKETHANDLER]++; ThreadSocketHandler2(parg); - vnThreadsRunning[0]--; + vnThreadsRunning[THREAD_SOCKETHANDLER]--; } catch (std::exception& e) { - vnThreadsRunning[0]--; + vnThreadsRunning[THREAD_SOCKETHANDLER]--; PrintException(&e, "ThreadSocketHandler()"); } catch (...) { - vnThreadsRunning[0]--; + vnThreadsRunning[THREAD_SOCKETHANDLER]--; throw; // support pthread_cancel() } printf("ThreadSocketHandler exiting\n"); @@ -712,9 +709,9 @@ void ThreadSocketHandler2(void* parg) } } - vnThreadsRunning[0]--; + vnThreadsRunning[THREAD_SOCKETHANDLER]--; int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); - vnThreadsRunning[0]++; + vnThreadsRunning[THREAD_SOCKETHANDLER]++; if (fShutdown) return; if (nSelect == SOCKET_ERROR) @@ -740,13 +737,17 @@ void ThreadSocketHandler2(void* parg) struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); - CAddress addr(sockaddr); + CAddress addr; int nInbound = 0; + if (hSocket != INVALID_SOCKET) + addr = CAddress(sockaddr); + CRITICAL_BLOCK(cs_vNodes) BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->fInbound) nInbound++; + if (hSocket == INVALID_SOCKET) { if (WSAGetLastError() != WSAEWOULDBLOCK) @@ -923,15 +924,15 @@ void ThreadMapPort(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg)); try { - vnThreadsRunning[5]++; + vnThreadsRunning[THREAD_UPNP]++; ThreadMapPort2(parg); - vnThreadsRunning[5]--; + vnThreadsRunning[THREAD_UPNP]--; } catch (std::exception& e) { - vnThreadsRunning[5]--; + vnThreadsRunning[THREAD_UPNP]--; PrintException(&e, "ThreadMapPort()"); } catch (...) { - vnThreadsRunning[5]--; + vnThreadsRunning[THREAD_UPNP]--; PrintException(NULL, "ThreadMapPort()"); } printf("ThreadMapPort exiting\n"); @@ -1052,7 +1053,7 @@ void MapPort(bool fMapPort) fUseUPnP = fMapPort; WriteSetting("fUseUPnP", fUseUPnP); } - if (fUseUPnP && vnThreadsRunning[5] < 1) + if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1) { if (!CreateThread(ThreadMapPort, NULL)) printf("Error: ThreadMapPort(ThreadMapPort) failed\n"); @@ -1086,15 +1087,15 @@ void ThreadDNSAddressSeed(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); try { - vnThreadsRunning[6]++; + vnThreadsRunning[THREAD_DNSSEED]++; ThreadDNSAddressSeed2(parg); - vnThreadsRunning[6]--; + vnThreadsRunning[THREAD_DNSSEED]--; } catch (std::exception& e) { - vnThreadsRunning[6]--; + vnThreadsRunning[THREAD_DNSSEED]--; PrintException(&e, "ThreadDNSAddressSeed()"); } catch (...) { - vnThreadsRunning[6]--; + vnThreadsRunning[THREAD_DNSSEED]--; throw; // support pthread_cancel() } printf("ThreadDNSAddressSeed exiting\n"); @@ -1232,15 +1233,15 @@ void ThreadOpenConnections(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg)); try { - vnThreadsRunning[1]++; + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; ThreadOpenConnections2(parg); - vnThreadsRunning[1]--; + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; } catch (std::exception& e) { - vnThreadsRunning[1]--; + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; PrintException(&e, "ThreadOpenConnections()"); } catch (...) { - vnThreadsRunning[1]--; + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; PrintException(NULL, "ThreadOpenConnections()"); } printf("ThreadOpenConnections exiting\n"); @@ -1274,9 +1275,13 @@ void ThreadOpenConnections2(void* parg) int64 nStart = GetTime(); loop { - // Limit outbound connections - vnThreadsRunning[1]--; + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; Sleep(500); + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; + if (fShutdown) + return; + + // Limit outbound connections loop { int nOutbound = 0; @@ -1288,13 +1293,12 @@ void ThreadOpenConnections2(void* parg) nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125)); if (nOutbound < nMaxOutboundConnections) break; + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; Sleep(2000); + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; if (fShutdown) return; } - vnThreadsRunning[1]++; - if (fShutdown) - return; bool fAddSeeds = false; @@ -1403,15 +1407,15 @@ void ThreadOpenAddedConnections(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg)); try { - vnThreadsRunning[7]++; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; ThreadOpenAddedConnections2(parg); - vnThreadsRunning[7]--; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; } catch (std::exception& e) { - vnThreadsRunning[7]--; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; PrintException(&e, "ThreadOpenAddedConnections()"); } catch (...) { - vnThreadsRunning[7]--; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; PrintException(NULL, "ThreadOpenAddedConnections()"); } printf("ThreadOpenAddedConnections exiting\n"); @@ -1460,9 +1464,9 @@ void ThreadOpenAddedConnections2(void* parg) } if (fShutdown) return; - vnThreadsRunning[7]--; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; Sleep(120000); // Retry every 2 minutes - vnThreadsRunning[7]++; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; if (fShutdown) return; } @@ -1479,9 +1483,9 @@ bool OpenNetworkConnection(const CAddress& addrConnect) FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect)) return false; - vnThreadsRunning[1]--; + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; CNode* pnode = ConnectNode(addrConnect); - vnThreadsRunning[1]++; + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; if (fShutdown) return false; if (!pnode) @@ -1503,15 +1507,15 @@ void ThreadMessageHandler(void* parg) IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg)); try { - vnThreadsRunning[2]++; + vnThreadsRunning[THREAD_MESSAGEHANDLER]++; ThreadMessageHandler2(parg); - vnThreadsRunning[2]--; + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; } catch (std::exception& e) { - vnThreadsRunning[2]--; + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; PrintException(&e, "ThreadMessageHandler()"); } catch (...) { - vnThreadsRunning[2]--; + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; PrintException(NULL, "ThreadMessageHandler()"); } printf("ThreadMessageHandler exiting\n"); @@ -1559,11 +1563,11 @@ void ThreadMessageHandler2(void* parg) // Wait and allow messages to bunch up. // Reduce vnThreadsRunning so StopNode has permission to exit while // we're sleeping, but we must always check fShutdown after doing this. - vnThreadsRunning[2]--; + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; Sleep(100); if (fRequestShutdown) Shutdown(NULL); - vnThreadsRunning[2]++; + vnThreadsRunning[THREAD_MESSAGEHANDLER]++; if (fShutdown) return; } @@ -1766,23 +1770,26 @@ bool StopNode() fShutdown = true; nTransactionsUpdated++; int64 nStart = GetTime(); - while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0 - || (fHaveUPnP && vnThreadsRunning[5] > 0) || vnThreadsRunning[6] > 0 || vnThreadsRunning[7] > 0 - ) + do { + int nThreadsRunning = 0; + for (int n = 0; n < THREAD_MAX; n++) + nThreadsRunning += vnThreadsRunning[n]; + if (nThreadsRunning == 0) + break; if (GetTime() - nStart > 20) break; Sleep(20); - } - if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n"); - if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n"); - if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n"); - if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n"); - if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n"); - if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n"); - if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n"); - if (vnThreadsRunning[7] > 0) printf("ThreadOpenAddedConnections still running\n"); - while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0) + } while(true); + if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n"); + if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n"); + if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n"); + if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); + if (vnThreadsRunning[THREAD_RPCSERVER] > 0) printf("ThreadRPCServer still running\n"); + if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n"); + if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n"); + if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n"); + while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0) Sleep(20); Sleep(50); @@ -68,14 +68,26 @@ public: - +enum threadId +{ + THREAD_SOCKETHANDLER, + THREAD_OPENCONNECTIONS, + THREAD_MESSAGEHANDLER, + THREAD_MINER, + THREAD_RPCSERVER, + THREAD_UPNP, + THREAD_DNSSEED, + THREAD_ADDEDCONNECTIONS, + + THREAD_MAX +}; extern bool fClient; extern bool fAllowDNS; extern uint64 nLocalServices; extern CAddress addrLocalHost; extern uint64 nLocalHostNonce; -extern boost::array<int, 10> vnThreadsRunning; +extern boost::array<int, THREAD_MAX> vnThreadsRunning; extern std::vector<CNode*> vNodes; extern CCriticalSection cs_vNodes; @@ -279,7 +291,7 @@ public: void BeginMessage(const char* pszCommand) { - cs_vSend.Enter("cs_vSend", __FILE__, __LINE__); + ENTER_CRITICAL_SECTION(cs_vSend); if (nHeaderStart != -1) AbortMessage(); nHeaderStart = vSend.size(); @@ -298,7 +310,7 @@ public: vSend.resize(nHeaderStart); nHeaderStart = -1; nMessageStart = -1; - cs_vSend.Leave(); + LEAVE_CRITICAL_SECTION(cs_vSend); if (fDebug) printf("(aborted)\n"); @@ -336,7 +348,7 @@ public: nHeaderStart = -1; nMessageStart = -1; - cs_vSend.Leave(); + LEAVE_CRITICAL_SECTION(cs_vSend); } void EndMessageAbortIfEmpty() diff --git a/src/netbase.cpp b/src/netbase.cpp index 54aa933a54..7799a65972 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -402,7 +402,7 @@ bool CNetAddr::IsRFC6145() const bool CNetAddr::IsRFC4843() const { - return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && GetByte(12) & 0xF0 == 0x10); + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); } bool CNetAddr::IsLocal() const diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 8c4b0e6c10..354e87c983 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -27,18 +27,10 @@ QSplashScreen *splashref; int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y) { - // Message from main thread - if(guiref) - { - guiref->error(QString::fromStdString(caption), - QString::fromStdString(message)); - } - else - { - QMessageBox::critical(0, QString::fromStdString(caption), - QString::fromStdString(message), - QMessageBox::Ok, QMessageBox::Ok); - } + // Message from AppInit2(), always in main thread before main window is constructed + QMessageBox::critical(0, QString::fromStdString(caption), + QString::fromStdString(message), + QMessageBox::Ok, QMessageBox::Ok); return 4; } @@ -162,11 +154,13 @@ int main(int argc, char *argv[]) ParseParameters(argc, argv); - // Load language files for system locale: + // Get desired locale ("en_US") from command line or system locale + QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString())); + // Load language files for configured locale: // - First load the translator for the base language, without territory // - Then load the more specific locale translator - QString lang_territory = QLocale::system().name(); // "en_US" QString lang = lang_territory; + lang.truncate(lang_territory.lastIndexOf('_')); // "en" QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 5693ae187e..d823752c9c 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -37,6 +37,7 @@ <file alias="lock_closed">res/icons/lock_closed.png</file> <file alias="lock_open">res/icons/lock_open.png</file> <file alias="key">res/icons/key.png</file> + <file alias="filesave">res/icons/filesave.png</file> </qresource> <qresource prefix="/images"> <file alias="about">res/images/about.png</file> diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h index 6ca3bd6a05..9710d122b6 100644 --- a/src/qt/bitcoinaddressvalidator.h +++ b/src/qt/bitcoinaddressvalidator.h @@ -14,7 +14,7 @@ public: State validate(QString &input, int &pos) const; - static const int MaxAddressLength = 34; + static const int MaxAddressLength = 35; signals: public slots: diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b72f128291..65753a1839 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -46,6 +46,8 @@ #include <QStackedWidget> #include <QDateTime> #include <QMovie> +#include <QFileDialog> +#include <QDesktopServices> #include <QDragEnterEvent> #include <QUrl> @@ -163,6 +165,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): BitcoinGUI::~BitcoinGUI() { + if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) + trayIcon->hide(); #ifdef Q_WS_MAC delete appMenuBar; #endif @@ -243,6 +247,8 @@ void BitcoinGUI::createActions() encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this); encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet")); encryptWalletAction->setCheckable(true); + backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet"), this); + backupWalletAction->setToolTip(tr("Backup wallet to another location")); changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this); changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption")); @@ -252,6 +258,7 @@ void BitcoinGUI::createActions() connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormal())); connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool))); + connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet())); connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase())); } @@ -277,6 +284,7 @@ void BitcoinGUI::createMenuBar() QMenu *settings = appMenuBar->addMenu(tr("&Settings")); settings->addAction(encryptWalletAction); settings->addAction(changePassphraseAction); + settings->addAction(backupWalletAction); settings->addSeparator(); settings->addAction(optionsAction); @@ -723,7 +731,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event) QList<QUrl> urls = event->mimeData()->urls(); foreach(const QUrl &url, urls) { - sendCoinsPage->handleURL(&url); + sendCoinsPage->handleURL(url.toString()); } } @@ -733,8 +741,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event) void BitcoinGUI::handleURL(QString strURL) { gotoSendCoinsPage(); - QUrl url = QUrl(strURL); - sendCoinsPage->handleURL(&url); + sendCoinsPage->handleURL(strURL); } void BitcoinGUI::setEncryptionStatus(int status) @@ -778,6 +785,17 @@ void BitcoinGUI::encryptWallet(bool status) setEncryptionStatus(walletModel->getEncryptionStatus()); } +void BitcoinGUI::backupWallet() +{ + QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); + if(!filename.isEmpty()) { + if(!walletModel->backupWallet(filename)) { + QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location.")); + } + } +} + void BitcoinGUI::changePassphrase() { AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 37ab12577c..a522429000 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -86,6 +86,7 @@ private: QAction *openBitcoinAction; QAction *exportAction; QAction *encryptWalletAction; + QAction *backupWalletAction; QAction *changePassphraseAction; QAction *aboutQtAction; @@ -162,6 +163,8 @@ private slots: void incomingTransaction(const QModelIndex & parent, int start, int end); /** Encrypt the wallet */ void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); /** Change encrypted wallet passphrase */ void changePassphrase(); /** Ask for pass phrase to unlock wallet temporarily */ diff --git a/src/qt/forms/messagepage.ui b/src/qt/forms/messagepage.ui index 8afa4b59dd..131e15bdb3 100644 --- a/src/qt/forms/messagepage.ui +++ b/src/qt/forms/messagepage.ui @@ -17,7 +17,7 @@ <item> <widget class="QLabel" name="labelExplanation"> <property name="text"> - <string>You can sign messages with your addresses to prove you own them. Be careful to only sign statement you agree to with full details, as phishing attacks may try to trick you into signing access to them.</string> + <string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string> </property> <property name="textFormat"> <enum>Qt::AutoText</enum> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index b8e74203b9..ac69bd07e9 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -51,15 +51,15 @@ void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent) widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter); } -bool GUIUtil::parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out) +bool GUIUtil::parseBitcoinURL(const QUrl &url, SendCoinsRecipient *out) { - if(url->scheme() != QString("bitcoin")) + if(url.scheme() != QString("bitcoin")) return false; SendCoinsRecipient rv; - rv.address = url->path(); + rv.address = url.path(); rv.amount = 0; - QList<QPair<QString, QString> > items = url->queryItems(); + QList<QPair<QString, QString> > items = url.queryItems(); for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++) { bool fShouldReturnFalse = false; @@ -96,6 +96,20 @@ bool GUIUtil::parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out) return true; } +bool GUIUtil::parseBitcoinURL(QString url, SendCoinsRecipient *out) +{ + // Convert bitcoin:// to bitcoin: + // + // Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host, + // which will lowercase it (and thus invalidate the address). + if(url.startsWith("bitcoin://")) + { + url.replace(0, 10, "bitcoin:"); + } + QUrl urlInstance(url); + return parseBitcoinURL(urlInstance, out); +} + QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine) { QString escaped = Qt::escape(str); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 8c85668465..75ba53f206 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -31,7 +31,8 @@ public: // Parse "bitcoin:" URL into recipient object, return true on succesful parsing // See Bitcoin URL definition discussion here: https://bitcointalk.org/index.php?topic=33490.0 - static bool parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out); + static bool parseBitcoinURL(const QUrl &url, SendCoinsRecipient *out); + static bool parseBitcoinURL(QString url, SendCoinsRecipient *out); // HTML escaping for rich text controls static QString HtmlEscape(const QString& str, bool fMultiLine=false); diff --git a/src/qt/messagepage.cpp b/src/qt/messagepage.cpp index dee1837ed6..46a0cbae24 100644 --- a/src/qt/messagepage.cpp +++ b/src/qt/messagepage.cpp @@ -1,6 +1,12 @@ #include <string> #include <vector> +#include <QClipboard> +#include <QInputDialog> +#include <QList> +#include <QListWidgetItem> +#include <QMessageBox> + #include "main.h" #include "wallet.h" #include "init.h" @@ -13,12 +19,6 @@ #include "guiutil.h" #include "walletmodel.h" -#include <QClipboard> -#include <QInputDialog> -#include <QList> -#include <QListWidgetItem> -#include <QMessageBox> - MessagePage::MessagePage(QWidget *parent) : QDialog(parent), ui(new Ui::MessagePage) diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp index 90d5c14211..018461a9b2 100644 --- a/src/qt/qtipcserver.cpp +++ b/src/qt/qtipcserver.cpp @@ -30,16 +30,7 @@ void ipcThread(void* parg) ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100); if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) { - strBuf[nSize] = '\0'; - // Convert bitcoin:// URLs to bitcoin: URIs - if (strBuf[8] == '/' && strBuf[9] == '/') - { - for (int i = 8; i < 256; i++) - { - strBuf[i] = strBuf[i+2]; - } - } - ThreadSafeHandleURL(strBuf); + ThreadSafeHandleURL(std::string(strBuf, nSize)); Sleep(1000); } if (fShutdown) @@ -66,16 +57,7 @@ void ipcInit() ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1); if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) { - strBuf[nSize] = '\0'; - // Convert bitcoin:// URLs to bitcoin: URIs - if (strBuf[8] == '/' && strBuf[9] == '/') - { - for (int i = 8; i < 256; i++) - { - strBuf[i] = strBuf[i+2]; - } - } - ThreadSafeHandleURL(strBuf); + ThreadSafeHandleURL(std::string(strBuf, nSize)); } else break; diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png Binary files differnew file mode 100644 index 0000000000..ae13a151d5 --- /dev/null +++ b/src/qt/res/icons/filesave.png diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0d9a604d3b..964313ea81 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -265,7 +265,7 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) } -void SendCoinsDialog::handleURL(const QUrl *url) +void SendCoinsDialog::handleURL(const QString &url) { SendCoinsRecipient rv; if(!GUIUtil::parseBitcoinURL(url, &rv)) diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 847ee8b697..4dc3f08bc5 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -30,7 +30,7 @@ public: QWidget *setupTabChain(QWidget *prev); void pasteEntry(const SendCoinsRecipient &rv); - void handleURL(const QUrl *url); + void handleURL(const QString &url); public slots: void clear(); diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index ab5460f8c2..d98400c260 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -59,8 +59,9 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address) { if(!model) return; - ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address)); -} + // Fill in label from address book, if no label is filled in yet + if(ui->addAsLabel->text().isEmpty()) + ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));} void SendCoinsEntry::setModel(WalletModel *model) { diff --git a/src/qt/test/urltests.cpp b/src/qt/test/urltests.cpp index 5ecc846203..1f11795a9b 100644 --- a/src/qt/test/urltests.cpp +++ b/src/qt/test/urltests.cpp @@ -18,51 +18,54 @@ void URLTests::urlTests() SendCoinsRecipient rv; QUrl url; url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-dontexist=")); - QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?dontexist=")); - QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); QVERIFY(rv.amount == 0); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Wikipedia Example Address")); - QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString("Wikipedia Example Address")); QVERIFY(rv.amount == 0); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=0.001")); - QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); QVERIFY(rv.amount == 100000); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1.001")); - QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); QVERIFY(rv.amount == 100100000); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=100&label=Wikipedia Example")); - QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.amount == 10000000000); QVERIFY(rv.label == QString("Wikipedia Example")); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address")); - QVERIFY(GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); + + QVERIFY(GUIUtil::parseBitcoinURL("bitcoin://175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address", &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); // We currently dont implement the message paramenter (ok, yea, we break spec...) url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-message=Wikipedia Example Address")); - QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example")); - QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000.0&label=Wikipedia Example")); - QVERIFY(!GUIUtil::parseBitcoinURL(&url, &rv)); + QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index f028f10f6c..8344a653d5 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -5,6 +5,7 @@ #include "transactiontablemodel.h" #include "headers.h" +#include "db.h" // for BackupWallet #include <QTimer> #include <QSet> @@ -239,6 +240,11 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri return retval; } +bool WalletModel::backupWallet(const QString &filename) +{ + return BackupWallet(*wallet, filename.toLocal8Bit().data()); +} + // WalletModel::UnlockContext implementation WalletModel::UnlockContext WalletModel::requestUnlock() { diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 89e8cdd2a0..4123240e90 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -77,6 +77,8 @@ public: // Passphrase only needed when unlocking bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString()); bool changePassphrase(const SecureString &oldPass, const SecureString &newPass); + // Wallet backup + bool backupWallet(const QString &filename); // RAI object for unlocking wallet, returned by requestUnlock() class UnlockContext diff --git a/src/serialize.h b/src/serialize.h index 6eb4f4ee41..c046bf37ef 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -23,6 +23,7 @@ typedef long long int64; typedef unsigned long long uint64; #ifdef WIN32 +#define _WIN32_WINNT 0x0501 #include <windows.h> // This is used to attempt to keep keying material out of swap // Note that VirtualLock does not provide this as a guarantee on Windows, diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 56b18044b8..8ae9290fcc 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify) { CKey key[4]; for (int i = 0; i < 4; i++) - key[i].MakeNewKey(); + key[i].MakeNewKey(true); CScript a_and_b; a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; @@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) { CKey key[4]; for (int i = 0; i < 4; i++) - key[i].MakeNewKey(); + key[i].MakeNewKey(true); CScript a_and_b; a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; @@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CBitcoinAddress keyaddr[3]; for (int i = 0; i < 3; i++) { - key[i].MakeNewKey(); + key[i].MakeNewKey(true); keystore.AddKey(key[i]); keyaddr[i].SetPubKey(key[i].GetPubKey()); } @@ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign) CKey key[4]; for (int i = 0; i < 4; i++) { - key[i].MakeNewKey(); + key[i].MakeNewKey(true); keystore.AddKey(key[i]); } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index e3899113a3..aa72c00092 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(sign) CKey key[4]; for (int i = 0; i < 4; i++) { - key[i].MakeNewKey(); + key[i].MakeNewKey(true); keystore.AddKey(key[i]); } @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(set) std::vector<CKey> keys; for (int i = 0; i < 4; i++) { - key[i].MakeNewKey(); + key[i].MakeNewKey(true); keystore.AddKey(key[i]); keys.push_back(key[i]); } @@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) vector<CKey> keys; for (int i = 0; i < 3; i++) { - key[i].MakeNewKey(); + key[i].MakeNewKey(true); keystore.AddKey(key[i]); keys.push_back(key[i]); } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 79dd7f1bd3..493ea69d93 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -72,9 +72,9 @@ sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { CKey key1, key2, key3; - key1.MakeNewKey(); - key2.MakeNewKey(); - key3.MakeNewKey(); + key1.MakeNewKey(true); + key2.MakeNewKey(false); + key3.MakeNewKey(true); CScript scriptPubKey12; scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG; @@ -105,10 +105,10 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { CKey key1, key2, key3, key4; - key1.MakeNewKey(); - key2.MakeNewKey(); - key3.MakeNewKey(); - key4.MakeNewKey(); + key1.MakeNewKey(true); + key2.MakeNewKey(false); + key3.MakeNewKey(true); + key4.MakeNewKey(false); CScript scriptPubKey23; scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG; diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 0b0a4a62d8..d301313a9d 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) for (int i = 0; i < 3; i++) { CKey k; - k.MakeNewKey(); + k.MakeNewKey(true); keys.push_back(k); } CScript s2; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index cd4d7eed96..99163e55f2 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -38,7 +38,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) CKey key[4]; for (int i = 0; i < 4; i++) { - key[i].MakeNewKey(); + key[i].MakeNewKey(i % 2); keystoreRet.AddKey(key[i]); } diff --git a/src/util.cpp b/src/util.cpp index 12ac076f0d..f1af91de27 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -454,6 +454,21 @@ vector<unsigned char> ParseHex(const string& str) return ParseHex(str.c_str()); } +static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet) +{ + // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set + if (name.find("-no") == 0) + { + std::string positive("-"); + positive.append(name.begin()+3, name.end()); + if (mapSettingsRet.count(positive) == 0) + { + bool value = !GetBoolArg(name); + mapSettingsRet[positive] = (value ? "1" : "0"); + } + } +} + void ParseParameters(int argc, const char*const argv[]) { mapArgs.clear(); @@ -494,17 +509,8 @@ void ParseParameters(int argc, const char*const argv[]) name = singleDash; } - // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1, as long as -foo not set) - if (name.find("-no") == 0) - { - std::string positive("-"); - positive.append(name.begin()+3, name.end()); - if (mapArgs.count(positive) == 0) - { - bool value = !GetBoolArg(name); - mapArgs[positive] = (value ? "1" : "0"); - } - } + // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set + InterpretNegativeSetting(name, mapArgs); } } @@ -920,7 +926,11 @@ void ReadConfigFile(map<string, string>& mapSettingsRet, // Don't overwrite existing settings so command line settings override bitcoin.conf string strKey = string("-") + it->string_key; if (mapSettingsRet.count(strKey) == 0) + { mapSettingsRet[strKey] = it->value[0]; + // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set) + InterpretNegativeSetting(strKey, mapSettingsRet); + } mapMultiSettingsRet[strKey].push_back(it->value[0]); } } diff --git a/src/util.h b/src/util.h index 8dcedb147b..ddc8791b38 100644 --- a/src/util.h +++ b/src/util.h @@ -218,6 +218,12 @@ public: #define CRITICAL_BLOCK(cs) \ if (CCriticalBlock criticalblock = CCriticalBlock(cs, #cs, __FILE__, __LINE__)) +#define ENTER_CRITICAL_SECTION(cs) \ + (cs).Enter(#cs, __FILE__, __LINE__) + +#define LEAVE_CRITICAL_SECTION(cs) \ + (cs).Leave() + class CTryCriticalBlock { protected: diff --git a/src/wallet.cpp b/src/wallet.cpp index 1e769d7e61..30590c80e6 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -15,6 +15,23 @@ using namespace std; // mapWallet // +std::vector<unsigned char> CWallet::GenerateNewKey() +{ + bool fCompressed = true; // default to compressed public keys + + RandAddSeedPerfmon(); + CKey key; + key.MakeNewKey(fCompressed); + + // Compressed public keys were introduced in version 0.6.0 + if (fCompressed) + SetMinVersion(59900); + + if (!AddKey(key)) + throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); + return key.GetPubKey(); +} + bool CWallet::AddKey(const CKey& key) { if (!CCryptoKeyStore::AddKey(key)) @@ -131,6 +148,32 @@ public: ) }; +bool CWallet::SetMinVersion(int nVersion, CWalletDB* pwalletdbIn) +{ + if (nWalletVersion >= nVersion) + return true; + + nWalletVersion = nVersion; + + if (fFileBacked) + { + CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile); + if (nWalletVersion >= 40000) + { + // Versions prior to 0.4.0 did not support the "minversion" record. + // Use a CCorruptAddress to make them crash instead. + CCorruptAddress corruptAddress; + pwalletdb->WriteSetting("addrIncoming", corruptAddress); + } + if (nWalletVersion > 40000) + pwalletdb->WriteMinVersion(nWalletVersion); + if (!pwalletdbIn) + delete pwalletdb; + } + + return true; +} + bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { if (IsCrypted()) @@ -184,14 +227,15 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) 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. } + // Encryption was introduced in version 0.4.0 + SetMinVersion(40000, pwalletdbEncryption); + 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(); + delete pwalletdbEncryption; pwalletdbEncryption = NULL; } diff --git a/src/wallet.h b/src/wallet.h index 3fdef50c03..fea3297788 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -25,6 +25,8 @@ private: CWalletDB *pwalletdbEncryption; + int nWalletVersion; + public: mutable CCriticalSection cs_wallet; @@ -33,18 +35,21 @@ public: std::set<int64> setKeyPool; + typedef std::map<unsigned int, CMasterKey> MasterKeyMap; MasterKeyMap mapMasterKeys; unsigned int nMasterKeyMaxID; CWallet() { + nWalletVersion = 0; fFileBacked = false; nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; } CWallet(std::string strWalletFileIn) { + nWalletVersion = 0; strWalletFile = strWalletFileIn; fFileBacked = true; nMasterKeyMaxID = 0; @@ -61,11 +66,15 @@ public: std::vector<unsigned char> vchDefaultKey; // keystore implementation + // Generate a new key + std::vector<unsigned char> GenerateNewKey(); // Adds a key to the store, and saves it to disk. bool AddKey(const CKey& key); // Adds a key to the store, without saving it to disk (used by LoadWallet) bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } + bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; return true; } + // Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) @@ -206,6 +215,8 @@ public: bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey); + + bool SetMinVersion(int nVersion, CWalletDB* pwalletdbIn = NULL); }; |