diff options
Diffstat (limited to 'src')
53 files changed, 957 insertions, 918 deletions
diff --git a/src/addrman.h b/src/addrman.h index 91e1f87f05..7652df66ae 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -266,8 +266,8 @@ public: // // This format is more complex, but significantly smaller (at most 1.5 MiB), and supports // changes to the ADDRMAN_ parameters without breaking the on-disk structure. - CRITICAL_BLOCK(cs) { + LOCK(cs); unsigned char nVersion = 0; READWRITE(nVersion); READWRITE(nKey); @@ -398,8 +398,8 @@ public: void Check() { #ifdef DEBUG_ADDRMAN - CRITICAL_BLOCK(cs) { + LOCK(cs); int err; if ((err=Check_())) printf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); @@ -411,8 +411,8 @@ public: bool Add(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty = 0) { bool fRet = false; - CRITICAL_BLOCK(cs) { + LOCK(cs); Check(); fRet |= Add_(addr, source, nTimePenalty); Check(); @@ -426,8 +426,8 @@ public: bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64 nTimePenalty = 0) { int nAdd = 0; - CRITICAL_BLOCK(cs) { + LOCK(cs); Check(); for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0; @@ -441,8 +441,8 @@ public: // Mark an entry as accessible. void Good(const CService &addr, int64 nTime = GetAdjustedTime()) { - CRITICAL_BLOCK(cs) { + LOCK(cs); Check(); Good_(addr, nTime); Check(); @@ -452,8 +452,8 @@ public: // Mark an entry as connection attempted to. void Attempt(const CService &addr, int64 nTime = GetAdjustedTime()) { - CRITICAL_BLOCK(cs) { + LOCK(cs); Check(); Attempt_(addr, nTime); Check(); @@ -465,8 +465,8 @@ public: CAddress Select(int nUnkBias = 50) { CAddress addrRet; - CRITICAL_BLOCK(cs) { + LOCK(cs); Check(); addrRet = Select_(nUnkBias); Check(); @@ -479,8 +479,10 @@ public: { Check(); std::vector<CAddress> vAddr; - CRITICAL_BLOCK(cs) + { + LOCK(cs); GetAddr_(vAddr); + } Check(); return vAddr; } @@ -488,8 +490,8 @@ public: // Mark an entry as currently-connected-to. void Connected(const CService &addr, int64 nTime = GetAdjustedTime()) { - CRITICAL_BLOCK(cs) { + LOCK(cs); Check(); Connected_(addr, nTime); Check(); diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 115164dc8b..7c991144d3 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -14,12 +14,10 @@ #include <boost/iostreams/stream.hpp> #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> -#ifdef USE_SSL #include <boost/asio/ssl.hpp> -#include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream; -#endif + #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" #include "json/json_spirit_utils.h" @@ -986,8 +984,6 @@ Value addmultisigaddress(const Array& params, bool fHelp) "If [account] is specified, assign address to [account]."; throw runtime_error(msg); } - if (!fTestNet) - throw runtime_error("addmultisigaddress available only when running -testnet\n"); int nRequired = params[0].get_int(); const Array& keys = params[1].get_array(); @@ -1659,8 +1655,8 @@ Value walletlock(const Array& params, bool fHelp) if (!pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called."); - CRITICAL_BLOCK(cs_nWalletUnlockTime) { + LOCK(cs_nWalletUnlockTime); pwalletMain->Lock(); nWalletUnlockTime = 0; } @@ -2283,7 +2279,6 @@ bool ClientAllowed(const string& strAddress) return false; } -#ifdef USE_SSL // // IOStream device that speaks SSL but can also speak non-SSL // @@ -2335,7 +2330,6 @@ private: bool fUseSSL; SSLStream& stream; }; -#endif void ThreadRPCServer(void* parg) { @@ -2378,7 +2372,7 @@ void ThreadRPCServer2(void* parg) "(you do not need to remember this password)\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"), strWhatAmI.c_str(), - GetConfigFile().c_str(), + GetConfigFile().string().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), _("Error"), wxOK | wxMODAL); QueueShutdown(); @@ -2390,51 +2384,51 @@ void ThreadRPCServer2(void* parg) asio::io_service io_service; ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332)); - ip::tcp::acceptor acceptor(io_service, endpoint); - - acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + ip::tcp::acceptor acceptor(io_service); + try + { + acceptor.open(endpoint.protocol()); + acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor.bind(endpoint); + acceptor.listen(socket_base::max_connections); + } + catch(boost::system::system_error &e) + { + ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()), + _("Error"), wxOK | wxMODAL); + QueueShutdown(); + return; + } -#ifdef USE_SSL ssl::context context(io_service, ssl::context::sslv23); if (fUseSSL) { context.set_options(ssl::context::no_sslv2); - filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert"); - if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile; - if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str()); - else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str()); - filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem"); - if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile; - if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem); - else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str()); - - string ciphers = GetArg("-rpcsslciphers", - "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"); - SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str()); - } -#else - if (fUseSSL) - throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries."); -#endif + + filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert")); + if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile; + if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string()); + else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str()); + + filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem")); + if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile; + if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem); + else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str()); + + string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"); + SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str()); + } loop { // Accept connection -#ifdef USE_SSL SSLStream sslStream(io_service, context); SSLIOStreamDevice d(sslStream, fUseSSL); iostreams::stream<SSLIOStreamDevice> stream(d); -#else - ip::tcp::iostream stream; -#endif ip::tcp::endpoint peer; vnThreadsRunning[THREAD_RPCSERVER]--; -#ifdef USE_SSL acceptor.accept(sslStream.lowest_layer(), peer); -#else - acceptor.accept(*stream.rdbuf(), peer); -#endif vnThreadsRunning[4]++; if (fShutdown) return; @@ -2524,9 +2518,10 @@ void ThreadRPCServer2(void* parg) { // Execute Value result; - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(pwalletMain->cs_wallet) + { + LOCK2(cs_main, pwalletMain->cs_wallet); result = (*(*mi).second)(params, false); + } // Send reply string strReply = JSONRPCReply(result, Value::null, id); @@ -2557,11 +2552,10 @@ Object CallRPC(const string& strMethod, const Array& params) throw runtime_error(strprintf( _("You must set rpcpassword=<password> in the configuration file:\n%s\n" "If the file does not exist, create it with owner-readable-only file permissions."), - GetConfigFile().c_str())); + GetConfigFile().string().c_str())); // Connect to localhost bool fUseSSL = GetBoolArg("-rpcssl"); -#ifdef USE_SSL asio::io_service io_service; ssl::context context(io_service, ssl::context::sslv23); context.set_options(ssl::context::no_sslv2); @@ -2570,15 +2564,6 @@ Object CallRPC(const string& strMethod, const Array& params) iostreams::stream<SSLIOStreamDevice> stream(d); if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"))) throw runtime_error("couldn't connect to server"); -#else - if (fUseSSL) - throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries."); - - ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")); - if (stream.fail()) - throw runtime_error("couldn't connect to server"); -#endif - // HTTP basic authentication string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]); diff --git a/src/crypter.cpp b/src/crypter.cpp index 6643bcddcd..83041addb4 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -73,14 +73,16 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); - - EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen); - EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen); + bool fOk = true; + EVP_CIPHER_CTX_init(&ctx); + if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); + if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen); + if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen); EVP_CIPHER_CTX_cleanup(&ctx); + if (!fOk) return false; + vchCiphertext.resize(nCLen + nFLen); return true; } @@ -98,14 +100,16 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); - - EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen); - EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen); + bool fOk = true; + EVP_CIPHER_CTX_init(&ctx); + if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); + if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen); + if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen); EVP_CIPHER_CTX_cleanup(&ctx); + if (!fOk) return false; + vchPlaintext.resize(nPLen + nFLen); return true; } diff --git a/src/db.cpp b/src/db.cpp index 2a09e2e673..839c0807cc 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -28,7 +28,6 @@ static bool fDbEnvInit = false; DbEnv dbenv(0); static map<string, int> mapFileUseCount; static map<string, Db*> mapDb; -static int64 nTxn = 0; static void EnvShutdown() { @@ -44,7 +43,7 @@ static void EnvShutdown() { printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno()); } - DbEnv(0).remove(GetDataDir().c_str(), 0); + DbEnv(0).remove(GetDataDir().string().c_str(), 0); } class CDBInit @@ -61,7 +60,7 @@ public: instance_of_cdbinit; -CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL) +CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL) { int ret; if (pszFile == NULL) @@ -73,29 +72,29 @@ CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL) if (fCreate) nFlags |= DB_CREATE; - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (!fDbEnvInit) { if (fShutdown) return; - string strDataDir = GetDataDir(); - string strLogDir = strDataDir + "/database"; - filesystem::create_directory(strLogDir.c_str()); - string strErrorFile = strDataDir + "/db.log"; - printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str()); + filesystem::path pathDataDir = GetDataDir(); + filesystem::path pathLogDir = pathDataDir / "database"; + filesystem::create_directory(pathLogDir); + filesystem::path pathErrorFile = pathDataDir / "db.log"; + printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); int nDbCache = GetArg("-dbcache", 25); - dbenv.set_lg_dir(strLogDir.c_str()); + dbenv.set_lg_dir(pathLogDir.string().c_str()); dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); dbenv.set_lg_bsize(1048576); dbenv.set_lg_max(10485760); dbenv.set_lk_max_locks(10000); dbenv.set_lk_max_objects(10000); - dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug + dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug dbenv.set_flags(DB_AUTO_COMMIT, 1); dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - ret = dbenv.open(strDataDir.c_str(), + ret = dbenv.open(pathDataDir.string().c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -127,8 +126,10 @@ CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL) { delete pdb; pdb = NULL; - CRITICAL_BLOCK(cs_db) + { + LOCK(cs_db); --mapFileUseCount[strFile]; + } strFile = ""; throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret)); } @@ -164,22 +165,18 @@ void CDB::Close() if (strFile == "blkindex.dat" && IsInitialBlockDownload()) nMinutes = 5; - if (nMinutes == 0 || nTxn > 200000) - { - nTxn = 0; - nMinutes = 0; - } - - dbenv.txn_checkpoint(0, nMinutes, 0); + dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); - CRITICAL_BLOCK(cs_db) + { + LOCK(cs_db); --mapFileUseCount[strFile]; + } } void static CloseDb(const string& strFile) { - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (mapDb[strFile] != NULL) { // Close the database handle @@ -195,8 +192,8 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) { while (!fShutdown) { - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) { // Flush log data to the dat file @@ -293,8 +290,8 @@ void DBFlush(bool fShutdown) printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started"); if (!fDbEnvInit) return; - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); map<string, int>::iterator mi = mapFileUseCount.begin(); while (mi != mapFileUseCount.end()) { @@ -344,7 +341,6 @@ bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex) { assert(!fClient); - nTxn++; return Write(make_pair(string("tx"), hash), txindex); } @@ -355,7 +351,6 @@ bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeigh // Add to tx index uint256 hash = tx.GetHash(); CTxIndex txindex(pos, tx.vout.size()); - nTxn++; return Write(make_pair(string("tx"), hash), txindex); } @@ -886,8 +881,8 @@ int CWalletDB::LoadWallet(CWallet* pwallet) bool fIsEncrypted = false; //// todo: shouldn't we catch exceptions and try to recover and continue? - CRITICAL_BLOCK(pwallet->cs_wallet) { + LOCK(pwallet->cs_wallet); int nMinVersion = 0; if (Read((string)"minversion", nMinVersion)) { @@ -1092,13 +1087,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) return DB_NEED_REWRITE; if (nFileVersion < CLIENT_VERSION) // Update - { - // Get rid of old debug.log file in current directory - if (nFileVersion <= 105 && !pszSetDataDir[0]) - unlink("debug.log"); - WriteVersion(CLIENT_VERSION); - } return DB_LOAD_OK; } @@ -1128,7 +1117,8 @@ void ThreadFlushWalletDB(void* parg) if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) { - TRY_CRITICAL_BLOCK(cs_db) + TRY_LOCK(cs_db,lockDb); + if (lockDb) { // Don't do this if any databases are in use int nRefCount = 0; @@ -1169,8 +1159,8 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) return false; while (!fShutdown) { - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0) { // Flush log data to the dat file @@ -1180,10 +1170,10 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat - filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile); + filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; filesystem::path pathDest(strDest); if (filesystem::is_directory(pathDest)) - pathDest = pathDest / wallet.strWalletFile; + pathDest /= wallet.strWalletFile; try { #if BOOST_VERSION >= 104000 diff --git a/src/init.cpp b/src/init.cpp index eecbc83edb..2be0027a5b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -40,10 +40,13 @@ void Shutdown(void* parg) static CCriticalSection cs_Shutdown; static bool fTaken; bool fFirstThread = false; - TRY_CRITICAL_BLOCK(cs_Shutdown) { - fFirstThread = !fTaken; - fTaken = true; + TRY_LOCK(cs_Shutdown, lockShutdown); + if (lockShutdown) + { + fFirstThread = !fTaken; + fTaken = true; + } } static bool fExit; if (fFirstThread) @@ -171,6 +174,7 @@ bool AppInit2(int argc, char* argv[]) " -splash \t\t " + _("Show splash screen on startup (default: 1)") + "\n" + " -datadir=<dir> \t\t " + _("Specify data directory") + "\n" + " -dbcache=<n> \t\t " + _("Set database cache size in megabytes (default: 25)") + "\n" + + " -dblogsize=<n> \t\t " + _("Set database disk log size in megabytes (default: 100)") + "\n" + " -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" + " -proxy=<ip:port> \t " + _("Connect through socks4 proxy") + "\n" + " -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" + @@ -221,14 +225,12 @@ bool AppInit2(int argc, char* argv[]) " -checkblocks=<n> \t\t " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + " -checklevel=<n> \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n"; -#ifdef USE_SSL strUsage += string() + _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" + " -rpcssl \t " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" + " -rpcsslcertificatechainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)") + "\n" + " -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)") + "\n" + " -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n"; -#endif strUsage += string() + " -? \t\t " + _("This help message") + "\n"; @@ -305,11 +307,11 @@ bool AppInit2(int argc, char* argv[]) } #endif - if (!fDebug && !pszSetDataDir[0]) + if (!fDebug) ShrinkDebugFile(); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - printf("Bitcoin version %s\n", FormatFullVersion().c_str()); - printf("Default data directory %s\n", GetDefaultDataDir().c_str()); + printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); + printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); if (GetBoolArg("-loadblockindextest")) { @@ -320,13 +322,13 @@ bool AppInit2(int argc, char* argv[]) } // Make sure only a single bitcoin process is using the data directory. - string strLockFile = GetDataDir() + "/.lock"; - FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist. + boost::filesystem::path pathLockFile = GetDataDir() / ".lock"; + FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist. if (file) fclose(file); - static boost::interprocess::file_lock lock(strLockFile.c_str()); + static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); if (!lock.try_lock()) { - ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), _("Bitcoin"), wxOK|wxMODAL); + ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().string().c_str()), _("Bitcoin"), wxOK|wxMODAL); return false; } @@ -582,20 +584,20 @@ bool AppInit2(int argc, char* argv[]) } #ifdef WIN32 -string StartupShortcutPath() +boost::filesystem::path StartupShortcutPath() { - return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk"; + return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk"; } bool GetStartOnSystemStartup() { - return filesystem::exists(StartupShortcutPath().c_str()); + return filesystem::exists(StartupShortcutPath()); } bool SetStartOnSystemStartup(bool fAutoStart) { // If the shortcut exists already, remove it for updating - remove(StartupShortcutPath().c_str()); + boost::filesystem::remove(StartupShortcutPath()); if (fAutoStart) { @@ -631,7 +633,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) { WCHAR pwsz[MAX_PATH]; // Ensure that the string is ANSI. - MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); // Save the link by calling IPersistFile::Save. hres = ppf->Save(pwsz, TRUE); ppf->Release(); @@ -657,15 +659,15 @@ boost::filesystem::path GetAutostartDir() namespace fs = boost::filesystem; char* pszConfigHome = getenv("XDG_CONFIG_HOME"); - if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart"); + if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; char* pszHome = getenv("HOME"); - if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart"); + if (pszHome) return fs::path(pszHome) / ".config" / "autostart"; return fs::path(); } boost::filesystem::path GetAutostartFilePath() { - return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop"); + return GetAutostartDir() / "bitcoin.desktop"; } bool GetStartOnSystemStartup() @@ -690,13 +692,7 @@ bool GetStartOnSystemStartup() bool SetStartOnSystemStartup(bool fAutoStart) { if (!fAutoStart) - { -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - unlink(GetAutostartFilePath().string().c_str()); -#else - unlink(GetAutostartFilePath().native_file_string().c_str()); -#endif - } + boost::filesystem::remove(GetAutostartFilePath()); else { char pszExePath[MAX_PATH+1]; diff --git a/src/keystore.cpp b/src/keystore.cpp index e76f7790f1..7b46f6b07a 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -21,31 +21,37 @@ bool CBasicKeyStore::AddKey(const CKey& key) { bool fCompressed = false; CSecret secret = key.GetSecret(fCompressed); - CRITICAL_BLOCK(cs_KeyStore) + { + LOCK(cs_KeyStore); mapKeys[CBitcoinAddress(key.GetPubKey())] = make_pair(secret, fCompressed); + } return true; } bool CBasicKeyStore::AddCScript(const CScript& redeemScript) { - CRITICAL_BLOCK(cs_KeyStore) + { + LOCK(cs_KeyStore); mapScripts[Hash160(redeemScript)] = redeemScript; + } return true; } bool CBasicKeyStore::HaveCScript(const uint160& hash) const { bool result; - CRITICAL_BLOCK(cs_KeyStore) + { + LOCK(cs_KeyStore); result = (mapScripts.count(hash) > 0); + } return result; } bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); ScriptMap::const_iterator mi = mapScripts.find(hash); if (mi != mapScripts.end()) { @@ -58,8 +64,8 @@ bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) c bool CCryptoKeyStore::SetCrypted() { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (fUseCrypto) return true; if (!mapKeys.empty()) @@ -71,8 +77,8 @@ bool CCryptoKeyStore::SetCrypted() bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!SetCrypted()) return false; @@ -84,6 +90,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) CSecret vchSecret; if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret)) return false; + if (vchSecret.size() != 32) + return false; CKey key; key.SetPubKey(vchPubKey); key.SetSecret(vchSecret); @@ -98,8 +106,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) bool CCryptoKeyStore::AddKey(const CKey& key) { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!IsCrypted()) return CBasicKeyStore::AddKey(key); @@ -121,8 +129,8 @@ bool CCryptoKeyStore::AddKey(const CKey& key) bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!SetCrypted()) return false; @@ -133,8 +141,8 @@ bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!IsCrypted()) return CBasicKeyStore::GetKey(address, keyOut); @@ -146,6 +154,8 @@ bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const CSecret vchSecret; if (!DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret)) return false; + if (vchSecret.size() != 32) + return false; keyOut.SetPubKey(vchPubKey); keyOut.SetSecret(vchSecret); return true; @@ -156,8 +166,8 @@ bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!IsCrypted()) return CKeyStore::GetPubKey(address, vchPubKeyOut); @@ -173,8 +183,8 @@ bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsi bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!mapCryptedKeys.empty() || IsCrypted()) return false; diff --git a/src/keystore.h b/src/keystore.h index c32db2620a..282eaaa047 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -54,15 +54,17 @@ public: bool HaveKey(const CBitcoinAddress &address) const { bool result; - CRITICAL_BLOCK(cs_KeyStore) + { + LOCK(cs_KeyStore); result = (mapKeys.count(address) > 0); + } return result; } void GetKeys(std::set<CBitcoinAddress> &setAddress) const { setAddress.clear(); - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); KeyMap::const_iterator mi = mapKeys.begin(); while (mi != mapKeys.end()) { @@ -73,8 +75,8 @@ public: } bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); KeyMap::const_iterator mi = mapKeys.find(address); if (mi != mapKeys.end()) { @@ -129,8 +131,10 @@ public: if (!IsCrypted()) return false; bool result; - CRITICAL_BLOCK(cs_KeyStore) + { + LOCK(cs_KeyStore); result = vMasterKey.empty(); + } return result; } @@ -139,8 +143,10 @@ public: if (!SetCrypted()) return false; - CRITICAL_BLOCK(cs_KeyStore) + { + LOCK(cs_KeyStore); vMasterKey.clear(); + } return true; } @@ -149,8 +155,8 @@ public: bool AddKey(const CKey& key); bool HaveKey(const CBitcoinAddress &address) const { - CRITICAL_BLOCK(cs_KeyStore) { + LOCK(cs_KeyStore); if (!IsCrypted()) return CBasicKeyStore::HaveKey(address); return mapCryptedKeys.count(address) > 0; diff --git a/src/main.cpp b/src/main.cpp index 7c49316b4a..bdafae8eb8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,11 +18,6 @@ using namespace boost; // Global state // -// Name of client reported in the 'version' message. Report the same name -// for both bitcoind and bitcoin-qt, to make it harder for attackers to -// target servers or GUI users specifically. -const std::string CLIENT_NAME("Satoshi"); - CCriticalSection cs_setpwalletRegistered; set<CWallet*> setpwalletRegistered; @@ -75,16 +70,16 @@ int64 nTransactionFee = 0; void RegisterWallet(CWallet* pwalletIn) { - CRITICAL_BLOCK(cs_setpwalletRegistered) { + LOCK(cs_setpwalletRegistered); setpwalletRegistered.insert(pwalletIn); } } void UnregisterWallet(CWallet* pwalletIn) { - CRITICAL_BLOCK(cs_setpwalletRegistered) { + LOCK(cs_setpwalletRegistered); setpwalletRegistered.erase(pwalletIn); } } @@ -478,9 +473,11 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi // Do we already have it? uint256 hash = GetHash(); - CRITICAL_BLOCK(cs_mapTransactions) + { + LOCK(cs_mapTransactions); if (mapTransactions.count(hash)) return false; + } if (fCheckInputs) if (txdb.ContainsTx(hash)) return false; @@ -552,8 +549,8 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi static int64 nLastTime; int64 nNow = GetTime(); - CRITICAL_BLOCK(cs) { + LOCK(cs); // Use an exponentially decaying ~10-minute window: dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); nLastTime = nNow; @@ -576,8 +573,8 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi } // Store transaction in memory - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); if (ptxOld) { printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str()); @@ -608,8 +605,8 @@ bool CTransaction::AddToMemoryPoolUnchecked() printf("AcceptToMemoryPoolUnchecked(): size %lu\n", mapTransactions.size()); // Add to memory pool without checking anything. Don't call this directly, // call AcceptToMemoryPool to properly check the transaction first. - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); uint256 hash = GetHash(); mapTransactions[hash] = *this; for (int i = 0; i < vin.size(); i++) @@ -624,8 +621,8 @@ bool CTransaction::AddToMemoryPoolUnchecked() bool CTransaction::RemoveFromMemoryPool() { // Remove transaction from memory pool - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); uint256 hash = GetHash(); if (mapTransactions.count(hash)) { @@ -702,8 +699,9 @@ bool CMerkleTx::AcceptToMemoryPool() bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) { - CRITICAL_BLOCK(cs_mapTransactions) + { + LOCK(cs_mapTransactions); // Add previous supporting transactions first BOOST_FOREACH(CMerkleTx& tx, vtxPrev) { @@ -1024,8 +1022,8 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) { // Get prev tx from single transactions in memory - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); if (!mapTransactions.count(prevout.hash)) return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); txPrev = mapTransactions[prevout.hash]; @@ -1190,8 +1188,8 @@ bool CTransaction::ClientConnectInputs() return false; // Take over previous transactions' spent pointers - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); int64 nValueIn = 0; for (int i = 0; i < vin.size(); i++) { @@ -1707,10 +1705,12 @@ bool CBlock::AcceptBlock() // Relay inventory, but don't relay old inventory during initial block download int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); if (hashBestChain == hash) - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) - pnode->PushInventory(CInv(MSG_BLOCK, hash)); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hash)); + } return true; } @@ -1822,7 +1822,7 @@ FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszM { if (nFile == -1) return NULL; - FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode); + FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode); if (!file) return NULL; if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) @@ -2052,8 +2052,8 @@ string GetWarnings(string strFor) } // Alerts - CRITICAL_BLOCK(cs_mapAlerts) { + LOCK(cs_mapAlerts); BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) { const CAlert& alert = item.second; @@ -2080,8 +2080,8 @@ bool CAlert::ProcessAlert() if (!IsInEffect()) return false; - CRITICAL_BLOCK(cs_mapAlerts) { + LOCK(cs_mapAlerts); // Cancel previous alerts for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) { @@ -2260,9 +2260,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Relay alerts - CRITICAL_BLOCK(cs_mapAlerts) + { + LOCK(cs_mapAlerts); BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) item.second.RelayTo(pfrom); + } pfrom->fSuccessfullyConnected = true; @@ -2316,8 +2318,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the setAddrKnowns of the chosen nodes prevent repeats static uint256 hashSalt; @@ -2428,8 +2430,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (inv.IsKnownType()) { // Send stream from relay memory - CRITICAL_BLOCK(cs_mapRelay) { + LOCK(cs_mapRelay); map<CInv, CDataStream>::iterator mi = mapRelay.find(inv); if (mi != mapRelay.end()) pfrom->PushMessage(inv.GetCommand(), (*mi).second); @@ -2634,8 +2636,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> hashReply; CRequestTracker tracker; - CRITICAL_BLOCK(pfrom->cs_mapRequests) { + LOCK(pfrom->cs_mapRequests); map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply); if (mi != pfrom->mapRequests.end()) { @@ -2662,9 +2664,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { // Relay pfrom->setKnown.insert(alert.GetHash()); - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) alert.RelayTo(pnode); + } } } @@ -2763,8 +2767,10 @@ bool ProcessMessages(CNode* pfrom) bool fRet = false; try { - CRITICAL_BLOCK(cs_main) + { + LOCK(cs_main); fRet = ProcessMessage(pfrom, strCommand, vMsg); + } if (fShutdown) return true; } @@ -2802,8 +2808,8 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto, bool fSendTrickle) { - CRITICAL_BLOCK(cs_main) { + LOCK(cs_main); // Don't send anything until we get their version message if (pto->nVersion == 0) return true; @@ -2819,8 +2825,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle) static int64 nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { // Periodically clear setAddrKnown to allow refresh broadcasts @@ -2871,8 +2877,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // vector<CInv> vInv; vector<CInv> vInvWait; - CRITICAL_BLOCK(pto->cs_inventory) { + LOCK(pto->cs_inventory); vInv.reserve(pto->vInventoryToSend.size()); vInvWait.reserve(pto->vInventoryToSend.size()); BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) @@ -3087,9 +3093,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Collect memory pool transactions into the block int64 nFees = 0; - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK2(cs_main, cs_mapTransactions); CTxDB txdb("r"); // Priority order to process transactions @@ -3317,8 +3322,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); // Found a solution - CRITICAL_BLOCK(cs_main) { + LOCK(cs_main); if (pblock->hashPrevBlock != hashBestChain) return error("BitcoinMiner : generated block is stale"); @@ -3326,8 +3331,10 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) reservekey.KeepKey(); // Track how many getdata requests this block gets - CRITICAL_BLOCK(wallet.cs_wallet) + { + LOCK(wallet.cs_wallet); wallet.mapRequestCount[pblock->GetHash()] = 0; + } // Process this block the same as if we had received it from another node if (!ProcessBlock(NULL, pblock)) @@ -3354,8 +3361,6 @@ void static BitcoinMiner(CWallet *pwallet) while (fGenerateBitcoins) { - if (AffinityBugWorkaround(ThreadBitcoinMiner)) - return; if (fShutdown) return; while (vNodes.empty() || IsInitialBlockDownload()) @@ -3443,8 +3448,8 @@ void static BitcoinMiner(CWallet *pwallet) if (GetTimeMillis() - nHPSTimerStart > 4000) { static CCriticalSection cs; - CRITICAL_BLOCK(cs) { + LOCK(cs); if (GetTimeMillis() - nHPSTimerStart > 4000) { dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); diff --git a/src/main.h b/src/main.h index 6c81abad56..1d46851ac2 100644 --- a/src/main.h +++ b/src/main.h @@ -10,6 +10,7 @@ #include "key.h" #include "script.h" #include "db.h" +#include "version.h" #ifdef WIN32 #include <io.h> /* for _commit */ @@ -30,10 +31,6 @@ class CInv; class CRequestTracker; class CNode; -static const int CLIENT_VERSION = 60099; -static const bool VERSION_IS_BETA = true; -extern const std::string CLIENT_NAME; - static const unsigned int MAX_BLOCK_SIZE = 1000000; static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 0bbe612a06..9f005424f6 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -10,7 +10,8 @@ INCLUDEPATHS= \ -I"$(DEPSDIR)/boost_1_47_0" \ -I"$(DEPSDIR)/db-4.8.30.NC/build_unix" \ -I"$(DEPSDIR)/openssl-1.0.0e/include" \ - -I"$(DEPSDIR)" + -I"$(DEPSDIR)" \ + -I"$(CURDIR)"/obj \ LIBPATHS= \ -L"$(DEPSDIR)/boost_1_47_0/stage/lib" \ @@ -26,7 +27,7 @@ LIBS= \ -l ssl \ -l crypto -DEFS=-D_MT -DWIN32 -D_WINDOWS -DNOPCH -DUSE_SSL -DBOOST_THREAD_USE_LIB +DEFS=-D_MT -DWIN32 -D_WINDOWS -DNOPCH -DBOOST_THREAD_USE_LIB DEBUGFLAGS=-g CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) @@ -43,6 +44,7 @@ LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l w HEADERS = $(wildcard *.h) OBJS= \ + obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ obj/addrman.o \ @@ -64,6 +66,11 @@ OBJS= \ all: bitcoind.exe +obj/build.h: FORCE + ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + obj/%.o: %.cpp $(HEADERS) i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $< @@ -85,3 +92,6 @@ clean: -rm -f headers.h.gch -rm -f bitcoind.exe -rm -f test_bitcoin.exe + -rm -f src/build.h + +FORCE: diff --git a/src/makefile.mingw b/src/makefile.mingw index 307fca7834..397fdf4f32 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -23,7 +23,7 @@ LIBS= \ -l ssl \ -l crypto -DEFS=-DWIN32 -D_WINDOWS -DNOPCH -DUSE_SSL -DBOOST_THREAD_USE_LIB +DEFS=-DWIN32 -D_WINDOWS -DNOPCH -DBOOST_THREAD_USE_LIB DEBUGFLAGS=-g CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) @@ -41,6 +41,7 @@ LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell HEADERS = $(wildcard *.h) OBJS= \ + obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ obj/addrman.o \ @@ -82,3 +83,4 @@ clean: -del /Q obj\test\* -del /Q test\*.o -del /Q headers.h.gch + -del /Q build.h diff --git a/src/makefile.osx b/src/makefile.osx index 6388a71e11..c5d3edbdc9 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -11,6 +11,7 @@ DEPSDIR=/opt/local INCLUDEPATHS= \ -I"$(CURDIR)" \ + -I"$(CURDIR)"/obj \ -I"$(DEPSDIR)/include" \ -I"$(DEPSDIR)/include/db48" @@ -49,15 +50,23 @@ LIBS += \ TESTDEFS += -DBOOST_TEST_DYN_LINK endif -DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DUSE_SSL +DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 + +ifdef RELEASE +# Compile for maximum compatibility and smallest size. +# This requires that dependencies are compiled +# the same way. +CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3 +else +CFLAGS = -g +endif -DEBUGFLAGS=-g # ppc doesn't work because we don't support big-endian -CFLAGS=-mmacosx-version-min=10.5 -arch i386 -O3 \ - -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-offsetof -Wformat-security \ +CFLAGS += -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-offsetof -Wformat-security \ $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) OBJS= \ + obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ obj/addrman.o \ @@ -92,6 +101,11 @@ all: bitcoind -include obj/*.P -include obj-test/*.P +obj/build.h: FORCE + ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + obj/%.o: %.cpp $(CXX) -c $(CFLAGS) -MMD -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ @@ -120,3 +134,6 @@ clean: -rm -f obj-test/*.o -rm -f obj/*.P -rm -f obj-test/*.P + -rm -f src/build.h + +FORCE: diff --git a/src/makefile.unix b/src/makefile.unix index 66e020bbef..79251dc7a6 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -6,7 +6,7 @@ USE_UPNP:=0 DEFS=-DNOPCH -DEFS += $(addprefix -I,$(CURDIR) $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) +DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) LMODE = dynamic @@ -39,10 +39,6 @@ ifneq (${USE_UPNP}, -) DEFS += -DUSE_UPNP=$(USE_UPNP) endif -ifneq (${USE_SSL}, 0) - DEFS += -DUSE_SSL -endif - LIBS+= \ -Wl,-B$(LMODE2) \ -l z \ @@ -89,6 +85,7 @@ xCXXFLAGS=-pthread -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-o $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) OBJS= \ + obj/version.o \ obj/checkpoints.o \ obj/netbase.o \ obj/addrman.o \ @@ -115,6 +112,11 @@ all: bitcoind -include obj/*.P -include obj-test/*.P +obj/build.h: FORCE + ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + obj/%.o: %.cpp $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ @@ -143,3 +145,6 @@ clean: -rm -f obj-test/*.o -rm -f obj/*.P -rm -f obj-test/*.P + -rm -f src/build.h + +FORCE: diff --git a/src/net.cpp b/src/net.cpp index 37e73c421a..8272b25561 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -64,6 +64,9 @@ map<CInv, int64> mapAlreadyAskedFor; set<CNetAddr> setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses; +static CWaitableCriticalSection csOutbound; +static int nOutbound = 0; +static CConditionVariable condOutbound; unsigned short GetListenPort() @@ -269,9 +272,11 @@ void ThreadGetMyExternalIP(void* parg) // setAddrKnown automatically filters any duplicate sends. CAddress addr(addrLocalHost); addr.nTime = GetAdjustedTime(); - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) pnode->PushAddress(addr); + } } } } @@ -289,111 +294,12 @@ void AddressCurrentlyConnected(const CService& addr) -void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) -{ - // If the dialog might get closed before the reply comes back, - // call this in the destructor so it doesn't get called after it's deleted. - CRITICAL_BLOCK(cs_vNodes) - { - BOOST_FOREACH(CNode* pnode, vNodes) - { - CRITICAL_BLOCK(pnode->cs_mapRequests) - { - for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();) - { - CRequestTracker& tracker = (*mi).second; - if (tracker.fn == fn && tracker.param1 == param1) - pnode->mapRequests.erase(mi++); - else - mi++; - } - } - } - } -} - - - - - - - -// -// Subscription methods for the broadcast and subscription system. -// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. -// -// The subscription system uses a meet-in-the-middle strategy. -// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers -// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through. -// - -bool AnySubscribed(unsigned int nChannel) -{ - if (pnodeLocalHost->IsSubscribed(nChannel)) - return true; - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->IsSubscribed(nChannel)) - return true; - return false; -} - -bool CNode::IsSubscribed(unsigned int nChannel) -{ - if (nChannel >= vfSubscribe.size()) - return false; - return vfSubscribe[nChannel]; -} - -void CNode::Subscribe(unsigned int nChannel, unsigned int nHops) -{ - if (nChannel >= vfSubscribe.size()) - return; - - if (!AnySubscribed(nChannel)) - { - // Relay subscribe - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode != this) - pnode->PushMessage("subscribe", nChannel, nHops); - } - - vfSubscribe[nChannel] = true; -} - -void CNode::CancelSubscribe(unsigned int nChannel) -{ - if (nChannel >= vfSubscribe.size()) - return; - - // Prevent from relaying cancel if wasn't subscribed - if (!vfSubscribe[nChannel]) - return; - vfSubscribe[nChannel] = false; - - if (!AnySubscribed(nChannel)) - { - // Relay subscription cancel - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode != this) - pnode->PushMessage("sub-cancel", nChannel); - } -} - - - - - - - CNode* FindNode(const CNetAddr& ip) { - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) if ((CNetAddr)pnode->addr == ip) return (pnode); @@ -403,8 +309,8 @@ CNode* FindNode(const CNetAddr& ip) CNode* FindNode(const CService& addr) { - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) if ((CService)pnode->addr == addr) return (pnode); @@ -458,8 +364,14 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) pnode->AddRef(nTimeout); else pnode->AddRef(); - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); vNodes.push_back(pnode); + } + { + WAITABLE_LOCK(csOutbound); + nOutbound++; + } pnode->nTimeConnected = GetTime(); return pnode; @@ -486,13 +398,6 @@ void CNode::CloseSocketDisconnect() void CNode::Cleanup() { - // All of a nodes broadcasts and subscriptions are automatically torn down - // when it goes down, so a node has to stay up to keep its broadcast going. - - // Cancel subscriptions - for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++) - if (vfSubscribe[nChannel]) - CancelSubscribe(nChannel); } @@ -522,8 +427,8 @@ void CNode::ClearBanned() bool CNode::IsBanned(CNetAddr ip) { bool fResult = false; - CRITICAL_BLOCK(cs_setBanned) { + LOCK(cs_setBanned); std::map<CNetAddr, int64>::iterator i = setBanned.find(ip); if (i != setBanned.end()) { @@ -547,9 +452,11 @@ bool CNode::Misbehaving(int howmuch) if (nMisbehavior >= GetArg("-banscore", 100)) { int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban - CRITICAL_BLOCK(cs_setBanned) + { + LOCK(cs_setBanned); if (setBanned[addr] < banTime) setBanned[addr] = banTime; + } CloseSocketDisconnect(); printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); return true; @@ -598,8 +505,8 @@ void ThreadSocketHandler2(void* parg) // // Disconnect nodes // - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); // Disconnect unused nodes vector<CNode*> vNodesCopy = vNodes; BOOST_FOREACH(CNode* pnode, vNodesCopy) @@ -610,6 +517,15 @@ void ThreadSocketHandler2(void* parg) // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); + if (!pnode->fInbound) + { + WAITABLE_LOCK(csOutbound); + nOutbound--; + + // Connection slot(s) were removed, notify connection creator(s) + NOTIFY(condOutbound); + } + // close socket and cleanup pnode->CloseSocketDisconnect(); pnode->Cleanup(); @@ -630,11 +546,23 @@ void ThreadSocketHandler2(void* parg) if (pnode->GetRefCount() <= 0) { bool fDelete = false; - TRY_CRITICAL_BLOCK(pnode->cs_vSend) - TRY_CRITICAL_BLOCK(pnode->cs_vRecv) - TRY_CRITICAL_BLOCK(pnode->cs_mapRequests) - TRY_CRITICAL_BLOCK(pnode->cs_inventory) - fDelete = true; + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) + { + TRY_LOCK(pnode->cs_vRecv, lockRecv); + if (lockRecv) + { + TRY_LOCK(pnode->cs_mapRequests, lockReq); + if (lockReq) + { + TRY_LOCK(pnode->cs_inventory, lockInv); + if (lockInv) + fDelete = true; + } + } + } + } if (fDelete) { vNodesDisconnected.remove(pnode); @@ -668,8 +596,8 @@ void ThreadSocketHandler2(void* parg) if(hListenSocket != INVALID_SOCKET) FD_SET(hListenSocket, &fdsetRecv); hSocketMax = max(hSocketMax, hListenSocket); - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { if (pnode->hSocket == INVALID_SOCKET) @@ -677,9 +605,11 @@ void ThreadSocketHandler2(void* parg) FD_SET(pnode->hSocket, &fdsetRecv); FD_SET(pnode->hSocket, &fdsetError); hSocketMax = max(hSocketMax, pnode->hSocket); - TRY_CRITICAL_BLOCK(pnode->cs_vSend) - if (!pnode->vSend.empty()) + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend && !pnode->vSend.empty()) FD_SET(pnode->hSocket, &fdsetSend); + } } } @@ -717,10 +647,12 @@ void ThreadSocketHandler2(void* parg) if (hSocket != INVALID_SOCKET) addr = CAddress(sockaddr); - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->fInbound) - nInbound++; + if (pnode->fInbound) + nInbound++; + } if (hSocket == INVALID_SOCKET) { @@ -729,9 +661,11 @@ void ThreadSocketHandler2(void* parg) } else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) { - CRITICAL_BLOCK(cs_setservAddNodeAddresses) + { + LOCK(cs_setservAddNodeAddresses); if (!setservAddNodeAddresses.count(addr)) closesocket(hSocket); + } } else if (CNode::IsBanned(addr)) { @@ -743,8 +677,10 @@ void ThreadSocketHandler2(void* parg) printf("accepted connection %s\n", addr.ToString().c_str()); CNode* pnode = new CNode(hSocket, addr, true); pnode->AddRef(); - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); vNodes.push_back(pnode); + } } } @@ -753,8 +689,8 @@ void ThreadSocketHandler2(void* parg) // Service each socket // vector<CNode*> vNodesCopy; - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); vNodesCopy = vNodes; BOOST_FOREACH(CNode* pnode, vNodesCopy) pnode->AddRef(); @@ -771,7 +707,8 @@ void ThreadSocketHandler2(void* parg) continue; if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) { - TRY_CRITICAL_BLOCK(pnode->cs_vRecv) + TRY_LOCK(pnode->cs_vRecv, lockRecv); + if (lockRecv) { CDataStream& vRecv = pnode->vRecv; unsigned int nPos = vRecv.size(); @@ -820,7 +757,8 @@ void ThreadSocketHandler2(void* parg) continue; if (FD_ISSET(pnode->hSocket, &fdsetSend)) { - TRY_CRITICAL_BLOCK(pnode->cs_vSend) + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) { CDataStream& vSend = pnode->vSend; if (!vSend.empty()) @@ -874,8 +812,8 @@ void ThreadSocketHandler2(void* parg) } } } - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodesCopy) pnode->Release(); } @@ -1278,8 +1216,6 @@ void ThreadOpenConnections2(void* parg) int64 nStart = GetTime(); loop { - int nOutbound = 0; - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; Sleep(500); vnThreadsRunning[THREAD_OPENCONNECTIONS]++; @@ -1287,23 +1223,15 @@ void ThreadOpenConnections2(void* parg) return; // Limit outbound connections - loop + int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; { - nOutbound = 0; - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (!pnode->fInbound) - nOutbound++; - int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS; - nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125)); - if (nOutbound < nMaxOutboundConnections) - break; - vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - Sleep(2000); - vnThreadsRunning[THREAD_OPENCONNECTIONS]++; - if (fShutdown) - return; + WAITABLE_LOCK(csOutbound); + WAIT(condOutbound, fShutdown || nOutbound < nMaxOutbound); } + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; + if (fShutdown) + return; bool fAddSeeds = false; @@ -1337,9 +1265,11 @@ void ThreadOpenConnections2(void* parg) // Only connect to one address per a.b.?.? range. // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. set<vector<unsigned char> > setConnected; - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) setConnected.insert(pnode->addr.GetGroup()); + } int64 nANow = GetAdjustedTime(); @@ -1405,9 +1335,11 @@ void ThreadOpenAddedConnections2(void* parg) if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0)) { vservAddressesToAdd.push_back(vservNode); - CRITICAL_BLOCK(cs_setservAddNodeAddresses) + { + LOCK(cs_setservAddNodeAddresses); BOOST_FOREACH(CService& serv, vservNode) setservAddNodeAddresses.insert(serv); + } } } loop @@ -1415,7 +1347,8 @@ void ThreadOpenAddedConnections2(void* parg) vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd; // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry // (keeping in mind that addnode entries can have many IPs if fAllowDNS) - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++) BOOST_FOREACH(CService& addrNode, *(it)) @@ -1425,6 +1358,7 @@ void ThreadOpenAddedConnections2(void* parg) it--; break; } + } BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses) { OpenNetworkConnection(CAddress(*(vserv.begin()))); @@ -1498,8 +1432,8 @@ void ThreadMessageHandler2(void* parg) while (!fShutdown) { vector<CNode*> vNodesCopy; - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); vNodesCopy = vNodes; BOOST_FOREACH(CNode* pnode, vNodesCopy) pnode->AddRef(); @@ -1512,20 +1446,26 @@ void ThreadMessageHandler2(void* parg) BOOST_FOREACH(CNode* pnode, vNodesCopy) { // Receive messages - TRY_CRITICAL_BLOCK(pnode->cs_vRecv) - ProcessMessages(pnode); + { + TRY_LOCK(pnode->cs_vRecv, lockRecv); + if (lockRecv) + ProcessMessages(pnode); + } if (fShutdown) return; // Send messages - TRY_CRITICAL_BLOCK(pnode->cs_vSend) - SendMessages(pnode, pnode == pnodeTrickle); + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) + SendMessages(pnode, pnode == pnodeTrickle); + } if (fShutdown) return; } - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodesCopy) pnode->Release(); } @@ -1752,6 +1692,7 @@ bool StopNode() fShutdown = true; nTransactionsUpdated++; int64 nStart = GetTime(); + NOTIFY_ALL(condOutbound); do { int nThreadsRunning = 0; @@ -29,7 +29,6 @@ extern int nBestHeight; inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); } inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); } -static const unsigned int PUBLISH_HOPS = 5; bool RecvLine(SOCKET hSocket, std::string& strLine); bool GetMyExternalIP(CNetAddr& ipRet); @@ -37,8 +36,6 @@ void AddressCurrentlyConnected(const CService& addr); CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CService& ip); CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); -void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); -bool AnySubscribed(unsigned int nChannel); void MapPort(bool fMapPort); bool BindListenPort(std::string& strError=REF(std::string())); void StartNode(void* parg); @@ -160,9 +157,6 @@ public: CCriticalSection cs_inventory; std::multimap<int64, CInv> mapAskFor; - // publish and subscription - std::vector<char> vfSubscribe; - CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) { nServices = 0; @@ -192,7 +186,6 @@ public: hashLastGetBlocksEnd = 0; nStartingHeight = -1; fGetAddr = false; - vfSubscribe.assign(256, false); nMisbehavior = 0; setInventoryKnown.max_size(SendBufferSize() / 1000); @@ -254,15 +247,19 @@ public: void AddInventoryKnown(const CInv& inv) { - CRITICAL_BLOCK(cs_inventory) + { + LOCK(cs_inventory); setInventoryKnown.insert(inv); + } } void PushInventory(const CInv& inv) { - CRITICAL_BLOCK(cs_inventory) + { + LOCK(cs_inventory); if (!setInventoryKnown.count(inv)) vInventoryToSend.push_back(inv); + } } void AskFor(const CInv& inv) @@ -526,8 +523,10 @@ public: uint256 hashReply; RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - CRITICAL_BLOCK(cs_mapRequests) + { + LOCK(cs_mapRequests); mapRequests[hashReply] = CRequestTracker(fn, param1); + } PushMessage(pszCommand, hashReply); } @@ -539,8 +538,10 @@ public: uint256 hashReply; RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - CRITICAL_BLOCK(cs_mapRequests) + { + LOCK(cs_mapRequests); mapRequests[hashReply] = CRequestTracker(fn, param1); + } PushMessage(pszCommand, hashReply, a1); } @@ -552,8 +553,10 @@ public: uint256 hashReply; RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - CRITICAL_BLOCK(cs_mapRequests) + { + LOCK(cs_mapRequests); mapRequests[hashReply] = CRequestTracker(fn, param1); + } PushMessage(pszCommand, hashReply, a1, a2); } @@ -599,9 +602,11 @@ public: inline void RelayInventory(const CInv& inv) { // Put on lists to offer to the other nodes - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) pnode->PushInventory(inv); + } } template<typename T> @@ -616,8 +621,8 @@ void RelayMessage(const CInv& inv, const T& a) template<> inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) { - CRITICAL_BLOCK(cs_mapRelay) { + LOCK(cs_mapRelay); // Expire old relay messages while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) { @@ -634,58 +639,4 @@ inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) } - - - - - - -// -// Templates for the publish and subscription system. -// The object being published as T& obj needs to have: -// a set<unsigned int> setSources member -// specializations of AdvertInsert and AdvertErase -// Currently implemented for CTable and CProduct. -// - -template<typename T> -void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) -{ - // Add to sources - obj.setSources.insert(pfrom->addr.ip); - - if (!AdvertInsert(obj)) - return; - - // Relay - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) - pnode->PushMessage("publish", nChannel, nHops, obj); -} - -template<typename T> -void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) -{ - uint256 hash = obj.GetHash(); - - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) - pnode->PushMessage("pub-cancel", nChannel, nHops, hash); - - AdvertErase(obj); -} - -template<typename T> -void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) -{ - // Remove a source - obj.setSources.erase(pfrom->addr.ip); - - // If no longer supported by any sources, cancel it - if (obj.setSources.empty()) - AdvertStopPublish(pfrom, nChannel, nHops, obj); -} - #endif diff --git a/src/qt/aboutdialog.cpp b/src/qt/aboutdialog.cpp index 08d7774067..0b98befe8d 100644 --- a/src/qt/aboutdialog.cpp +++ b/src/qt/aboutdialog.cpp @@ -2,6 +2,8 @@ #include "ui_aboutdialog.h" #include "clientmodel.h" +#include "version.h" + AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 88212835de..3e55c39e04 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -310,16 +310,12 @@ void AddressBookPage::on_showQRCode_clicked() QTableView *table = ui->tableView; QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - - QRCodeDialog *d; foreach (QModelIndex index, indexes) { - QString address = index.data().toString(), - label = index.sibling(index.row(), 0).data().toString(), - title = QString("%1 << %2 >>").arg(label).arg(address); + QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(); - QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this); - d->show(); + QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this); + dialog->show(); } #endif } diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 198a857b2d..05f3a81698 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -39,8 +39,8 @@ struct AddressTablePriv { cachedAddressTable.clear(); - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook) { const CBitcoinAddress& address = item.first; @@ -169,8 +169,8 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu // Double-check that we're not overwriting a receiving address if(rec->type == AddressTableEntry::Sending) { - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); // Remove old entry wallet->DelAddressBookName(rec->address.toStdString()); // Add new entry with new address @@ -254,8 +254,8 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString(); } // Check for duplicate addresses - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); if(wallet->mapAddressBook.count(strAddress)) { editStatus = DUPLICATE_ADDRESS; @@ -286,8 +286,10 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString(); } // Add entry - CRITICAL_BLOCK(wallet->cs_wallet) + { + LOCK(wallet->cs_wallet); wallet->SetAddressBookName(strAddress, strLabel); + } return QString::fromStdString(strAddress); } @@ -301,8 +303,8 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren // Also refuse to remove receiving addresses. return false; } - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); wallet->DelAddressBookName(rec->address.toStdString()); } return true; @@ -312,8 +314,8 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren */ QString AddressTableModel::labelForAddress(const QString &address) const { - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); CBitcoinAddress address_parsed(address.toStdString()); std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed); if (mi != wallet->mapAddressBook.end()) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 394e4a7661..bfb49cbcab 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -74,13 +74,13 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) return payFee; } -void ThreadSafeHandleURL(const std::string& strURL) +void ThreadSafeHandleURI(const std::string& strURI) { if(!guiref) return; - QMetaObject::invokeMethod(guiref, "handleURL", GUIUtil::blockingGUIThreadConnection(), - Q_ARG(QString, QString::fromStdString(strURL))); + QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(), + Q_ARG(QString, QString::fromStdString(strURI))); } void MainFrameRepaint() @@ -133,10 +133,10 @@ int main(int argc, char *argv[]) { if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0) { - const char *strURL = argv[i]; + const char *strURI = argv[i]; try { - boost::interprocess::message_queue mq(boost::interprocess::open_only, "BitcoinURL"); - if(mq.try_send(strURL, strlen(strURL), 0)) + boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME); + if(mq.try_send(strURI, strlen(strURI), 0)) exit(0); else break; @@ -248,21 +248,21 @@ int main(int argc, char *argv[]) window.show(); } - // Place this here as guiref has to be defined if we dont want to lose URLs + // Place this here as guiref has to be defined if we dont want to lose URIs ipcInit(); #if !defined(MAC_OSX) && !defined(WIN32) // TODO: implement qtipcserver.cpp for Mac and Windows - // Check for URL in argv + // Check for URI in argv for (int i = 1; i < argc; i++) { if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0) { - const char *strURL = argv[i]; + const char *strURI = argv[i]; try { - boost::interprocess::message_queue mq(boost::interprocess::open_only, "BitcoinURL"); - mq.try_send(strURL, strlen(strURL), 0); + boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME); + mq.try_send(strURI, strlen(strURI), 0); } catch (boost::interprocess::interprocess_exception &ex) { } diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 8f2bba2737..e631a65155 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -1,5 +1,5 @@ <RCC> - <qresource prefix="/icons" lang="edit"> + <qresource prefix="/icons"> <file alias="bitcoin">res/icons/bitcoin.png</file> <file alias="address-book">res/icons/address-book.png</file> <file alias="quit">res/icons/quit.png</file> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a60b585225..3c31f291c2 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -23,6 +23,7 @@ #include "guiconstants.h" #include "askpassphrasedialog.h" #include "notificator.h" +#include "guiutil.h" #ifdef Q_WS_MAC #include "macdockiconhandler.h" @@ -239,8 +240,8 @@ void BitcoinGUI::createActions() optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); optionsAction->setToolTip(tr("Modify configuration options for bitcoin")); optionsAction->setMenuRole(QAction::PreferencesRole); - openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this); - openBitcoinAction->setToolTip(tr("Show the Bitcoin window")); + toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("Show/Hide &Bitcoin"), this); + toggleHideAction->setToolTip(tr("Show or Hide the Bitcoin window")); exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); exportAction->setToolTip(tr("Export the data in the current tab to a file")); encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this); @@ -255,7 +256,7 @@ void BitcoinGUI::createActions() connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); - connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool))); connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet())); connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase())); @@ -387,12 +388,12 @@ void BitcoinGUI::createTrayIcon() #else // Note: On Mac, the dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); - connect(dockIconHandler, SIGNAL(dockIconClicked()), openBitcoinAction, SLOT(trigger())); + connect(dockIconHandler, SIGNAL(dockIconClicked()), toggleHideAction, SLOT(trigger())); trayIconMenu = dockIconHandler->dockMenu(); #endif // Configuration of the tray icon (or dock icon) icon menu - trayIconMenu->addAction(openBitcoinAction); + trayIconMenu->addAction(toggleHideAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(messageAction); #ifndef FIRST_CLASS_MESSAGING @@ -416,11 +417,33 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) if(reason == QSystemTrayIcon::Trigger) { // Click on system tray icon triggers "open bitcoin" - openBitcoinAction->trigger(); + toggleHideAction->trigger(); } } #endif +void BitcoinGUI::toggleHidden() +{ + // activateWindow() (sometimes) helps with keyboard focus on Windows + if(isHidden()) + { + show(); + activateWindow(); + } + else if(isMinimized()) + { + showNormal(); + activateWindow(); + } + else if(GUIUtil::isObscured(this)) + { + raise(); + activateWindow(); + } + else + hide(); +} + void BitcoinGUI::optionsClicked() { if(!clientModel || !clientModel->getOptionsModel()) @@ -715,7 +738,7 @@ void BitcoinGUI::gotoMessagePage(QString addr) void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event) { - // Accept only URLs + // Accept only URIs if(event->mimeData()->hasUrls()) event->acceptProposedAction(); } @@ -725,20 +748,20 @@ void BitcoinGUI::dropEvent(QDropEvent *event) if(event->mimeData()->hasUrls()) { gotoSendCoinsPage(); - QList<QUrl> urls = event->mimeData()->urls(); - foreach(const QUrl &url, urls) + QList<QUrl> uris = event->mimeData()->urls(); + foreach(const QUrl &uri, uris) { - sendCoinsPage->handleURL(url.toString()); + sendCoinsPage->handleURI(uri.toString()); } } event->acceptProposedAction(); } -void BitcoinGUI::handleURL(QString strURL) +void BitcoinGUI::handleURI(QString strURI) { gotoSendCoinsPage(); - sendCoinsPage->handleURL(strURL); + sendCoinsPage->handleURI(strURI); if(!isActiveWindow()) activateWindow(); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index c684d7cc3a..2cce8d3459 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -81,7 +81,7 @@ private: QAction *aboutAction; QAction *receiveCoinsAction; QAction *optionsAction; - QAction *openBitcoinAction; + QAction *toggleHideAction; QAction *exportAction; QAction *encryptWalletAction; QAction *backupWalletAction; @@ -125,7 +125,7 @@ public slots: @param[out] payFee true to pay the fee, false to not pay the fee */ void askFee(qint64 nFeeRequired, bool *payFee); - void handleURL(QString strURL); + void handleURI(QString strURI); void gotoMessagePage(); void gotoMessagePage(QString); @@ -166,6 +166,8 @@ private slots: /** Show window if hidden, unminimize when minimized */ void showNormalIfMinimized(); + /** Hide window if visible, show if hidden */ + void toggleHidden(); }; #endif diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 8163da0915..284bee0e8e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -88,3 +88,8 @@ QString ClientModel::formatFullVersion() const { return QString::fromStdString(FormatFullVersion()); } + +QString ClientModel::formatBuildDate() const +{ + return QString::fromStdString(CLIENT_DATE); +} diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 6366b4d617..8e7431a2f3 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -37,6 +37,7 @@ public: QString getStatusBarWarnings() const; QString formatFullVersion() const; + QString formatBuildDate() const; private: OptionsModel *optionsModel; diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui index 127b90965a..6e342e5e8a 100644 --- a/src/qt/forms/aboutdialog.ui +++ b/src/qt/forms/aboutdialog.ui @@ -52,6 +52,9 @@ <property name="text"> <string><b>Bitcoin</b> version</string> </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> </widget> </item> <item> @@ -62,6 +65,9 @@ <property name="textFormat"> <enum>Qt::RichText</enum> </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> </widget> </item> <item> @@ -93,6 +99,9 @@ This product includes software developed by the OpenSSL Project for use in the O <property name="wordWrap"> <bool>true</bool> </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> </widget> </item> <item> diff --git a/src/qt/forms/messagepage.ui b/src/qt/forms/messagepage.ui index 131e15bdb3..8bd6d8b54b 100644 --- a/src/qt/forms/messagepage.ui +++ b/src/qt/forms/messagepage.ui @@ -35,7 +35,7 @@ <item> <widget class="QValidatedLineEdit" name="signFrom"> <property name="toolTip"> - <string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string> + <string>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string> </property> <property name="maxLength"> <number>34</number> diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui index fa21f60b9e..714b1d6cd8 100644 --- a/src/qt/forms/qrcodedialog.ui +++ b/src/qt/forms/qrcodedialog.ui @@ -34,6 +34,9 @@ <property name="alignment"> <set>Qt::AlignCenter</set> </property> + <property name="wordWrap"> + <bool>true</bool> + </property> </widget> </item> <item> @@ -44,7 +47,7 @@ <item> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QCheckBox" name="chkReq"> + <widget class="QCheckBox" name="chkReqPayment"> <property name="enabled"> <bool>true</bool> </property> @@ -56,7 +59,7 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QLabel" name="lblAm1"> + <widget class="QLabel" name="lblAmount"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> <horstretch>0</horstretch> @@ -91,7 +94,7 @@ </widget> </item> <item> - <widget class="QLabel" name="lblAm2"> + <widget class="QLabel" name="lblBTC"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> <horstretch>0</horstretch> @@ -113,7 +116,7 @@ <item> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> - <widget class="QLabel" name="label_3"> + <widget class="QLabel" name="lblLabel"> <property name="text"> <string>Label:</string> </property> @@ -136,7 +139,7 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="label_4"> + <widget class="QLabel" name="lblMessage"> <property name="text"> <string>Message:</string> </property> @@ -194,7 +197,7 @@ <resources/> <connections> <connection> - <sender>chkReq</sender> + <sender>chkReqPayment</sender> <signal>clicked(bool)</signal> <receiver>lnReqAmount</receiver> <slot>setEnabled(bool)</slot> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index ad530a78e4..cb2473240e 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -19,31 +19,33 @@ #include <QDesktopServices> #include <QThread> -QString GUIUtil::dateTimeStr(qint64 nTime) +namespace GUIUtil { + +QString dateTimeStr(const QDateTime &date) { - return dateTimeStr(QDateTime::fromTime_t((qint32)nTime)); + return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm"); } -QString GUIUtil::dateTimeStr(const QDateTime &date) +QString dateTimeStr(qint64 nTime) { - return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm"); + return dateTimeStr(QDateTime::fromTime_t((qint32)nTime)); } -QFont GUIUtil::bitcoinAddressFont() +QFont bitcoinAddressFont() { QFont font("Monospace"); font.setStyleHint(QFont::TypeWriter); return font; } -void GUIUtil::setupAddressWidget(QLineEdit *widget, QWidget *parent) +void setupAddressWidget(QLineEdit *widget, QWidget *parent) { widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength); widget->setValidator(new BitcoinAddressValidator(parent)); widget->setFont(bitcoinAddressFont()); } -void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent) +void setupAmountWidget(QLineEdit *widget, QWidget *parent) { QDoubleValidator *amountValidator = new QDoubleValidator(parent); amountValidator->setDecimals(8); @@ -52,15 +54,15 @@ void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent) widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter); } -bool GUIUtil::parseBitcoinURL(const QUrl &url, SendCoinsRecipient *out) +bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) { - if(url.scheme() != QString("bitcoin")) + if(uri.scheme() != QString("bitcoin")) return false; SendCoinsRecipient rv; - rv.address = url.path(); + rv.address = uri.path(); rv.amount = 0; - QList<QPair<QString, QString> > items = url.queryItems(); + QList<QPair<QString, QString> > items = uri.queryItems(); for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++) { bool fShouldReturnFalse = false; @@ -97,21 +99,21 @@ bool GUIUtil::parseBitcoinURL(const QUrl &url, SendCoinsRecipient *out) return true; } -bool GUIUtil::parseBitcoinURL(QString url, SendCoinsRecipient *out) +bool parseBitcoinURI(QString uri, 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://")) + if(uri.startsWith("bitcoin://")) { - url.replace(0, 10, "bitcoin:"); + uri.replace(0, 10, "bitcoin:"); } - QUrl urlInstance(url); - return parseBitcoinURL(urlInstance, out); + QUrl uriInstance(uri); + return parseBitcoinURI(uriInstance, out); } -QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine) +QString HtmlEscape(const QString& str, bool fMultiLine) { QString escaped = Qt::escape(str); if(fMultiLine) @@ -121,12 +123,12 @@ QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine) return escaped; } -QString GUIUtil::HtmlEscape(const std::string& str, bool fMultiLine) +QString HtmlEscape(const std::string& str, bool fMultiLine) { return HtmlEscape(QString::fromStdString(str), fMultiLine); } -void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role) +void copyEntryData(QAbstractItemView *view, int column, int role) { if(!view || !view->selectionModel()) return; @@ -139,7 +141,7 @@ void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role) } } -QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption, +QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut) @@ -185,7 +187,7 @@ QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption, return result; } -Qt::ConnectionType GUIUtil::blockingGUIThreadConnection() +Qt::ConnectionType blockingGUIThreadConnection() { if(QThread::currentThread() != QCoreApplication::instance()->thread()) { @@ -196,3 +198,23 @@ Qt::ConnectionType GUIUtil::blockingGUIThreadConnection() return Qt::DirectConnection; } } + +bool checkPoint(const QPoint &p, const QWidget *w) +{ + QWidget *atW = qApp->widgetAt(w->mapToGlobal(p)); + if(!atW) return false; + return atW->topLevelWidget() == w; +} + +bool isObscured(QWidget *w) +{ + + return !(checkPoint(QPoint(0, 0), w) + && checkPoint(QPoint(w->width() - 1, 0), w) + && checkPoint(QPoint(0, w->height() - 1), w) + && checkPoint(QPoint(w->width() - 1, w->height() - 1), w) + && checkPoint(QPoint(w->width()/2, w->height()/2), w)); +} + +} // namespace GUIUtil + diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 06426d76bc..ea1a4795c0 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -13,30 +13,29 @@ class QAbstractItemView; QT_END_NAMESPACE class SendCoinsRecipient; -/** Static utility functions used by the Bitcoin Qt UI. +/** Utility functions used by the Bitcoin Qt UI. */ -class GUIUtil +namespace GUIUtil { -public: // Create human-readable string from date - static QString dateTimeStr(qint64 nTime); - static QString dateTimeStr(const QDateTime &datetime); + QString dateTimeStr(const QDateTime &datetime); + QString dateTimeStr(qint64 nTime); // Render bitcoin addresses in monospace font - static QFont bitcoinAddressFont(); + QFont bitcoinAddressFont(); // Set up widgets for address and amounts - static void setupAddressWidget(QLineEdit *widget, QWidget *parent); - static void setupAmountWidget(QLineEdit *widget, QWidget *parent); + void setupAddressWidget(QLineEdit *widget, QWidget *parent); + void setupAmountWidget(QLineEdit *widget, QWidget *parent); - // 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(QString url, SendCoinsRecipient *out); + // Parse "bitcoin:" URI into recipient object, return true on succesful parsing + // See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0 + bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out); + bool parseBitcoinURI(QString uri, SendCoinsRecipient *out); // HTML escaping for rich text controls - static QString HtmlEscape(const QString& str, bool fMultiLine=false); - static QString HtmlEscape(const std::string& str, bool fMultiLine=false); + QString HtmlEscape(const QString& str, bool fMultiLine=false); + QString HtmlEscape(const std::string& str, bool fMultiLine=false); /** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing is selected. @@ -44,7 +43,7 @@ public: @param[in] role Data role to extract from the model @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress */ - static void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole); + void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole); /** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when no suffix is provided by the user. @@ -56,18 +55,20 @@ public: @param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0). Can be useful when choosing the save file format based on suffix. */ - static QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(), + QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(), const QString &dir=QString(), const QString &filter=QString(), QString *selectedSuffixOut=0); - /** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking. @returns If called from the GUI thread, return a Qt::DirectConnection. If called from another thread, return a Qt::BlockingQueuedConnection. */ - static Qt::ConnectionType blockingGUIThreadConnection(); + Qt::ConnectionType blockingGUIThreadConnection(); + + // Determine whether a widget is hidden behind other windows + bool isObscured(QWidget *w); -}; +} // namespace GUIUtil #endif // GUIUTIL_H diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 75fd4ccf18..34d303233c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -175,18 +175,16 @@ MainOptionsPage::MainOptionsPage(QWidget *parent): minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar")); minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window")); layout->addWidget(minimize_to_tray); -#endif - - map_port_upnp = new QCheckBox(tr("Map port using &UPnP")); - map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.")); - layout->addWidget(map_port_upnp); -#ifndef Q_WS_MAC minimize_on_close = new QCheckBox(tr("M&inimize on close")); minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu.")); layout->addWidget(minimize_on_close); #endif + map_port_upnp = new QCheckBox(tr("Map port using &UPnP")); + map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.")); + layout->addWidget(map_port_upnp); + connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:")); connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)")); layout->addWidget(connect_socks4); diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp index 82959831de..9965f1438f 100644 --- a/src/qt/qrcodedialog.cpp +++ b/src/qt/qrcodedialog.cpp @@ -8,21 +8,19 @@ #include <qrencode.h> -#define EXPORT_IMAGE_SIZE 256 +#define EXPORT_IMAGE_SIZE 256 -QRCodeDialog::QRCodeDialog(const QString &title, const QString &addr, const QString &label, bool enableReq, QWidget *parent) : - QDialog(parent), - ui(new Ui::QRCodeDialog), - address(addr) +QRCodeDialog::QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent) : + QDialog(parent), ui(new Ui::QRCodeDialog), address(addr) { ui->setupUi(this); - setWindowTitle(title); + setWindowTitle(QString("%1").arg(address)); setAttribute(Qt::WA_DeleteOnClose); - ui->chkReq->setVisible(enableReq); + ui->chkReqPayment->setVisible(enableReq); ui->lnReqAmount->setVisible(enableReq); - ui->lblAm1->setVisible(enableReq); - ui->lblAm2->setVisible(enableReq); + ui->lblAmount->setVisible(enableReq); + ui->lblBTC->setVisible(enableReq); ui->lnLabel->setText(label); @@ -37,19 +35,28 @@ QRCodeDialog::~QRCodeDialog() void QRCodeDialog::genCode() { QString uri = getURI(); - //qDebug() << "Encoding:" << uri.toUtf8().constData(); - QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); - myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); - myImage.fill(0xffffff); - unsigned char *p = code->data; - for(int y = 0; y < code->width; y++) { - for(int x = 0; x < code->width; x++) { - myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff)); - p++; + + if (uri != "") + { + ui->lblQRCode->setText(""); + + QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); + myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); + myImage.fill(0xffffff); + unsigned char *p = code->data; + for (int y = 0; y < code->width; y++) + { + for (int x = 0; x < code->width; x++) + { + myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff)); + p++; + } } + QRcode_free(code); + ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300)); } - QRcode_free(code); - ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300)); + else + ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message.")); } QString QRCodeDialog::getURI() @@ -57,41 +64,49 @@ QString QRCodeDialog::getURI() QString ret = QString("bitcoin:%1").arg(address); int paramCount = 0; - if(ui->chkReq->isChecked() && ui->lnReqAmount->text().isEmpty() == false) { - bool ok= false; - double amount = ui->lnReqAmount->text().toDouble(&ok); - if(ok) { - ret += QString("?amount=%1X8").arg(ui->lnReqAmount->text()); + if (ui->chkReqPayment->isChecked() && !ui->lnReqAmount->text().isEmpty()) + { + bool ok = false; + ui->lnReqAmount->text().toDouble(&ok); + if (ok) + { + ret += QString("?amount=%1").arg(ui->lnReqAmount->text()); paramCount++; } } - if(ui->lnLabel->text().isEmpty() == false) { + if (!ui->lnLabel->text().isEmpty()) + { QString lbl(QUrl::toPercentEncoding(ui->lnLabel->text())); ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl); paramCount++; } - if(ui->lnMessage->text().isEmpty() == false) { + if (!ui->lnMessage->text().isEmpty()) + { QString msg(QUrl::toPercentEncoding(ui->lnMessage->text())); ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg); paramCount++; } - return ret; + // limit URI length to 255 chars, to prevent a DoS against the QR-Code dialog + if (ret.length() < 256) + return ret; + else + return QString(""); } -void QRCodeDialog::on_lnReqAmount_textChanged(const QString &) +void QRCodeDialog::on_lnReqAmount_textChanged(const QString &arg1) { genCode(); } -void QRCodeDialog::on_lnLabel_textChanged(const QString &) +void QRCodeDialog::on_lnLabel_textChanged(const QString &arg1) { genCode(); } -void QRCodeDialog::on_lnMessage_textChanged(const QString &) +void QRCodeDialog::on_lnMessage_textChanged(const QString &arg1) { genCode(); } @@ -99,12 +114,11 @@ void QRCodeDialog::on_lnMessage_textChanged(const QString &) void QRCodeDialog::on_btnSaveAs_clicked() { QString fn = GUIUtil::getSaveFileName(this, tr("Save Image..."), QString(), tr("PNG Images (*.png)")); - if(!fn.isEmpty()) { + if (!fn.isEmpty()) myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn); - } } -void QRCodeDialog::on_chkReq_toggled(bool) +void QRCodeDialog::on_chkReqPayment_toggled(bool) { genCode(); } diff --git a/src/qt/qrcodedialog.h b/src/qt/qrcodedialog.h index 7463a8810e..ad0611605b 100644 --- a/src/qt/qrcodedialog.h +++ b/src/qt/qrcodedialog.h @@ -13,7 +13,7 @@ class QRCodeDialog : public QDialog Q_OBJECT public: - explicit QRCodeDialog(const QString &title, const QString &address, const QString &label, bool allowReq, QWidget *parent = 0); + explicit QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent = 0); ~QRCodeDialog(); private slots: @@ -22,7 +22,7 @@ private slots: void on_lnMessage_textChanged(const QString &arg1); void on_btnSaveAs_clicked(); - void on_chkReq_toggled(bool checked); + void on_chkReqPayment_toggled(bool checked); private: Ui::QRCodeDialog *ui; diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp index 8b9270e178..3c7889ca71 100644 --- a/src/qt/qtipcserver.cpp +++ b/src/qt/qtipcserver.cpp @@ -8,6 +8,7 @@ #include <boost/date_time/posix_time/posix_time.hpp> #include "headers.h" +#include "qtipcserver.h" using namespace boost::interprocess; using namespace boost::posix_time; @@ -16,7 +17,7 @@ using namespace std; void ipcShutdown() { - message_queue::remove("BitcoinURL"); + message_queue::remove(BITCOINURI_QUEUE_NAME); } void ipcThread(void* parg) @@ -30,7 +31,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)) { - ThreadSafeHandleURL(std::string(strBuf, nSize)); + ThreadSafeHandleURI(std::string(strBuf, nSize)); Sleep(1000); } if (fShutdown) @@ -60,7 +61,7 @@ void ipcInit() size_t nSize; unsigned int nPriority; try { - mq = new message_queue(open_or_create, "BitcoinURL", 2, 256); + mq = new message_queue(open_or_create, BITCOINURI_QUEUE_NAME, 2, 256); // Make sure we don't lose any bitcoin: URIs for (int i = 0; i < 2; i++) @@ -68,15 +69,15 @@ void ipcInit() ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1); if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d)) { - ThreadSafeHandleURL(std::string(strBuf, nSize)); + ThreadSafeHandleURI(std::string(strBuf, nSize)); } else break; } // Make sure only one bitcoin instance is listening - message_queue::remove("BitcoinURL"); - mq = new message_queue(open_or_create, "BitcoinURL", 2, 256); + message_queue::remove(BITCOINURI_QUEUE_NAME); + mq = new message_queue(open_or_create, BITCOINURI_QUEUE_NAME, 2, 256); } catch (interprocess_exception &ex) { return; diff --git a/src/qt/qtipcserver.h b/src/qt/qtipcserver.h index 1de0334afd..fcff10d8da 100644 --- a/src/qt/qtipcserver.h +++ b/src/qt/qtipcserver.h @@ -1,2 +1,4 @@ +#define BITCOINURI_QUEUE_NAME "BitcoinURI" + void ipcInit(); void ipcShutdown(); diff --git a/src/qt/res/icons/connect4_16.png b/src/qt/res/icons/connect4_16.png Binary files differindex e2fe97d496..c1232f5682 100644 --- a/src/qt/res/icons/connect4_16.png +++ b/src/qt/res/icons/connect4_16.png diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 964313ea81..592ae6f45a 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -265,10 +265,10 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) } -void SendCoinsDialog::handleURL(const QString &url) +void SendCoinsDialog::handleURI(const QString &uri) { SendCoinsRecipient rv; - if(!GUIUtil::parseBitcoinURL(url, &rv)) + if(!GUIUtil::parseBitcoinURI(uri, &rv)) { return; } diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 4dc3f08bc5..5dcbfbeb61 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 QString &url); + void handleURI(const QString &uri); public slots: void clear(); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 0a08eafa1e..5b11e39ea3 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,11 +1,11 @@ #include <QTest>
#include <QObject>
-#include "urltests.h"
+#include "uritests.h"
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
- URLTests test1;
+ URITests test1;
QTest::qExec(&test1);
}
diff --git a/src/qt/test/urltests.cpp b/src/qt/test/uritests.cpp index 1f11795a9b..70c20be0ea 100644 --- a/src/qt/test/urltests.cpp +++ b/src/qt/test/uritests.cpp @@ -1,4 +1,4 @@ -#include "urltests.h" +#include "uritests.h" #include "../guiutil.h" #include "../walletmodel.h" @@ -13,59 +13,59 @@ struct SendCoinsRecipient }; */ -void URLTests::urlTests() +void URITests::uriTests() { SendCoinsRecipient rv; - QUrl url; - url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-dontexist=")); - QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); + QUrl uri; + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-dontexist=")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?dontexist=")); - QVERIFY(GUIUtil::parseBitcoinURL(url, &rv)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?dontexist=")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &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)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Wikipedia Example Address")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &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)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=0.001")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &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)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1.001")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &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)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=100&label=Wikipedia Example")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &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)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); - QVERIFY(GUIUtil::parseBitcoinURL("bitcoin://175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address", &rv)); + QVERIFY(GUIUtil::parseBitcoinURI("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)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-message=Wikipedia Example Address")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example")); - QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - url.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000.0&label=Wikipedia Example")); - QVERIFY(!GUIUtil::parseBitcoinURL(url, &rv)); + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000.0&label=Wikipedia Example")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); } diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h new file mode 100644 index 0000000000..1237516e5f --- /dev/null +++ b/src/qt/test/uritests.h @@ -0,0 +1,15 @@ +#ifndef URITESTS_H +#define URITESTS_H + +#include <QTest> +#include <QObject> + +class URITests : public QObject +{ + Q_OBJECT + +private slots: + void uriTests(); +}; + +#endif // URITESTS_H diff --git a/src/qt/test/urltests.h b/src/qt/test/urltests.h deleted file mode 100644 index 393c511390..0000000000 --- a/src/qt/test/urltests.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef URLTESTS_H -#define URLTESTS_H - -#include <QTest> -#include <QObject> - -class URLTests : public QObject -{ - Q_OBJECT - -private slots: - void urlTests(); -}; - -#endif // URLTESTS_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index c32a006f71..dd7dd61390 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -34,8 +34,9 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { QString strHTML; - CRITICAL_BLOCK(wallet->cs_wallet) + { + LOCK(wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; @@ -243,8 +244,9 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML += "<br><b>Inputs:</b>"; strHTML += "<ul>"; - CRITICAL_BLOCK(wallet->cs_wallet) + { + LOCK(wallet->cs_wallet); BOOST_FOREACH(const CTxIn& txin, wtx.vin) { COutPoint prevout = txin.prevout; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 480d4ac25e..aa11df979f 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -69,8 +69,8 @@ struct TransactionTablePriv qDebug() << "refreshWallet"; #endif cachedWallet.clear(); - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second)); @@ -95,8 +95,8 @@ struct TransactionTablePriv QList<uint256> updated_sorted = updated; qSort(updated_sorted); - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx) { const uint256 &hash = updated_sorted.at(update_idx); @@ -171,8 +171,8 @@ struct TransactionTablePriv // simply re-use the cached status. if(rec->statusUpdateNeeded()) { - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash); if(mi != wallet->mapWallet.end()) @@ -191,8 +191,8 @@ struct TransactionTablePriv QString describe(TransactionRecord *rec) { - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash); if(mi != wallet->mapWallet.end()) { @@ -229,9 +229,9 @@ void TransactionTableModel::update() QList<uint256> updated; // Check if there are changes to wallet map - TRY_CRITICAL_BLOCK(wallet->cs_wallet) { - if(!wallet->vWalletUpdated.empty()) + TRY_LOCK(wallet->cs_wallet, lockWallet); + if (lockWallet && !wallet->vWalletUpdated.empty()) { BOOST_FOREACH(uint256 hash, wallet->vWalletUpdated) { diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 6cc023792d..9c28a8abc8 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -32,8 +32,8 @@ qint64 WalletModel::getUnconfirmedBalance() const int WalletModel::getNumTransactions() const { int numTransactions = 0; - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); numTransactions = wallet->mapWallet.size(); } return numTransactions; @@ -115,9 +115,9 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK2(cs_main, wallet->cs_wallet); + // Sendmany std::vector<std::pair<CScript, int64> > vecSend; foreach(const SendCoinsRecipient &rcp, recipients) @@ -155,8 +155,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie foreach(const SendCoinsRecipient &rcp, recipients) { std::string strAddress = rcp.address.toStdString(); - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); if (!wallet->mapAddressBook.count(strAddress)) wallet->SetAddressBookName(strAddress, rcp.label.toStdString()); } @@ -227,8 +227,8 @@ bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase) bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass) { bool retval; - CRITICAL_BLOCK(wallet->cs_wallet) { + LOCK(wallet->cs_wallet); wallet->Lock(); // Make sure wallet is locked before attempting pass change retval = wallet->ChangeWalletPassphrase(oldPass, newPass); } diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index d59536e254..5bb4789cd3 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -6,15 +6,8 @@ #include "init.h" // for pwalletMain #include "bitcoinrpc.h" -// #include <boost/asio.hpp> -// #include <boost/iostreams/concepts.hpp> -// #include <boost/iostreams/stream.hpp> #include <boost/lexical_cast.hpp> -// #ifdef USE_SSL -// #include <boost/asio/ssl.hpp> -// typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream; -// #endif -// #include <boost/xpressive/xpressive_dynamic.hpp> + #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" #include "json/json_spirit_utils.h" @@ -67,9 +60,9 @@ Value importprivkey(const Array& params, bool fHelp) key.SetSecret(secret, fCompressed); CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey()); - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(pwalletMain->cs_wallet) { + LOCK2(cs_main, pwalletMain->cs_wallet); + pwalletMain->MarkDirty(); pwalletMain->SetAddressBookName(vchAddress, strLabel); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 94c0c77a44..db31f4988a 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -15,14 +15,15 @@ BOOST_AUTO_TEST_CASE(util_criticalsection) CCriticalSection cs; do { - CRITICAL_BLOCK(cs) - break; + LOCK(cs); + break; BOOST_ERROR("break was swallowed!"); } while(0); do { - TRY_CRITICAL_BLOCK(cs) + TRY_LOCK(cs, lockTest); + if (lockTest) break; BOOST_ERROR("break was swallowed!"); diff --git a/src/ui_interface.h b/src/ui_interface.h index 2e29f2af16..514768086d 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -40,7 +40,7 @@ extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK); extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption); -extern void ThreadSafeHandleURL(const std::string& strURL); +extern void ThreadSafeHandleURI(const std::string& strURI); extern void MainFrameRepaint(); extern void AddressBookRepaint(); extern void QueueShutdown(); diff --git a/src/util.cpp b/src/util.cpp index 4f34ab6163..5579a09351 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. + #include "headers.h" #include "strlcpy.h" #include <boost/algorithm/string/join.hpp> @@ -21,7 +22,6 @@ map<string, vector<string> > mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; -char pszSetDataDir[MAX_PATH] = ""; bool fRequestShutdown = false; bool fShutdown = false; bool fDaemon = false; @@ -33,16 +33,6 @@ bool fNoListen = false; bool fLogTimestamps = false; CMedianFilter<int64> vTimeOffsets(200,0); - - -// Workaround for "multiple definition of `_tls_used'" -// http://svn.boost.org/trac/boost/ticket/4258 -extern "C" void tss_cleanup_implemented() { } - - - - - // Init openssl library multithreading support static boost::interprocess::interprocess_mutex** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) @@ -174,10 +164,8 @@ inline int OutputDebugStringF(const char* pszFormat, ...) if (!fileout) { - char pszFile[MAX_PATH+100]; - GetDataDir(pszFile); - strlcat(pszFile, "/debug.log", sizeof(pszFile)); - fileout = fopen(pszFile, "a"); + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + fileout = fopen(pathDebug.string().c_str(), "a"); if (fileout) setbuf(fileout, NULL); // unbuffered } if (fileout) @@ -205,8 +193,8 @@ inline int OutputDebugStringF(const char* pszFormat, ...) static CCriticalSection cs_OutputDebugStringF; // accumulate a line at a time - CRITICAL_BLOCK(cs_OutputDebugStringF) { + LOCK(cs_OutputDebugStringF); static char pszBuffer[50000]; static char* pend; if (pend == NULL) @@ -777,101 +765,94 @@ void PrintExceptionContinue(std::exception* pex, const char* pszThread) } #ifdef WIN32 -string MyGetSpecialFolderPath(int nFolder, bool fCreate) +boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate) { + namespace fs = boost::filesystem; + char pszPath[MAX_PATH] = ""; if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) { - return pszPath; + return fs::path(pszPath); } else if (nFolder == CSIDL_STARTUP) { - return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup"; + return fs::path(getenv("USERPROFILE")) / "Start Menu" / "Programs" / "Startup"; } else if (nFolder == CSIDL_APPDATA) { - return getenv("APPDATA"); + return fs::path(getenv("APPDATA")); } - return ""; + return fs::path(""); } #endif -string GetDefaultDataDir() +boost::filesystem::path GetDefaultDataDir() { + namespace fs = boost::filesystem; + // Windows: C:\Documents and Settings\username\Application Data\Bitcoin // Mac: ~/Library/Application Support/Bitcoin // Unix: ~/.bitcoin #ifdef WIN32 // Windows - return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin"; + return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "Bitcoin"; #else + fs::path pathRet; char* pszHome = getenv("HOME"); if (pszHome == NULL || strlen(pszHome) == 0) - pszHome = (char*)"/"; - string strHome = pszHome; - if (strHome[strHome.size()-1] != '/') - strHome += '/'; + pathRet = fs::path("/"); + else + pathRet = fs::path(pszHome); #ifdef MAC_OSX // Mac - strHome += "Library/Application Support/"; - filesystem::create_directory(strHome.c_str()); - return strHome + "Bitcoin"; + pathRet /= "Library/Application Support"; + filesystem::create_directory(pathRet); + return pathRet / "Bitcoin"; #else // Unix - return strHome + ".bitcoin"; + return pathRet / ".bitcoin"; #endif #endif } -void GetDataDir(char* pszDir) +const boost::filesystem::path &GetDataDir(bool fNetSpecific) { - // pszDir must be at least MAX_PATH length. - int nVariation; - if (pszSetDataDir[0] != 0) - { - strlcpy(pszDir, pszSetDataDir, MAX_PATH); - nVariation = 0; - } - else - { - // This can be called during exceptions by printf, so we cache the - // value so we don't have to do memory allocations after that. - static char pszCachedDir[MAX_PATH]; - if (pszCachedDir[0] == 0) - strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir)); - strlcpy(pszDir, pszCachedDir, MAX_PATH); - nVariation = 1; - } - if (fTestNet) - { - char* p = pszDir + strlen(pszDir); - if (p > pszDir && p[-1] != '/' && p[-1] != '\\') - *p++ = '/'; - strcpy(p, "testnet"); - nVariation += 2; - } - static bool pfMkdir[4]; - if (!pfMkdir[nVariation]) - { - pfMkdir[nVariation] = true; - boost::filesystem::create_directory(pszDir); + namespace fs = boost::filesystem; + + static fs::path pathCached[2]; + static CCriticalSection csPathCached; + static bool cachedPath[2] = {false, false}; + + fs::path &path = pathCached[fNetSpecific]; + + // This can be called during exceptions by printf, so we cache the + // value so we don't have to do memory allocations after that. + if (cachedPath[fNetSpecific]) + return path; + + LOCK(csPathCached); + + if (mapArgs.count("-datadir")) { + path = mapArgs["-datadir"]; + } else { + path = GetDefaultDataDir(); + if (fNetSpecific && GetBoolArg("-testnet", false)) + path /= "testnet"; } -} -string GetDataDir() -{ - char pszDir[MAX_PATH]; - GetDataDir(pszDir); - return pszDir; + fs::create_directory(path); + + cachedPath[fNetSpecific]=true; + return path; } -string GetConfigFile() +boost::filesystem::path GetConfigFile() { namespace fs = boost::filesystem; - fs::path pathConfig(GetArg("-conf", "bitcoin.conf")); - if (!pathConfig.is_complete()) - pathConfig = fs::path(GetDataDir()) / pathConfig; - return pathConfig.string(); + + fs::path pathConfigFile(GetArg("-conf", "bitcoin.conf")); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + return pathConfigFile; } bool ReadConfigFile(map<string, string>& mapSettingsRet, @@ -880,26 +861,13 @@ bool ReadConfigFile(map<string, string>& mapSettingsRet, namespace fs = boost::filesystem; namespace pod = boost::program_options::detail; - if (mapSettingsRet.count("-datadir")) - { - if (fs::is_directory(fs::system_complete(mapSettingsRet["-datadir"]))) - { - fs::path pathDataDir = fs::system_complete(mapSettingsRet["-datadir"]); - strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir)); - } - else - { - return false; - } - } - fs::ifstream streamConfig(GetConfigFile()); if (!streamConfig.good()) return true; // No bitcoin.conf file is OK set<string> setOptions; setOptions.insert("*"); - + for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { // Don't overwrite existing settings so command line settings override bitcoin.conf @@ -915,18 +883,18 @@ bool ReadConfigFile(map<string, string>& mapSettingsRet, return true; } -string GetPidFile() +boost::filesystem::path GetPidFile() { namespace fs = boost::filesystem; - fs::path pathConfig(GetArg("-pid", "bitcoind.pid")); - if (!pathConfig.is_complete()) - pathConfig = fs::path(GetDataDir()) / pathConfig; - return pathConfig.string(); + + fs::path pathPidFile(GetArg("-pid", "bitcoind.pid")); + if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; + return pathPidFile; } -void CreatePidFile(string pidFile, pid_t pid) +void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { - FILE* file = fopen(pidFile.c_str(), "w"); + FILE* file = fopen(path.string().c_str(), "w"); if (file) { fprintf(file, "%d\n", pid); @@ -947,8 +915,8 @@ int GetFilesize(FILE* file) void ShrinkDebugFile() { // Scroll debug.log if it's getting too big - string strFile = GetDataDir() + "/debug.log"; - FILE* file = fopen(strFile.c_str(), "r"); + boost::filesystem::path pathLog = GetDataDir() / "debug.log"; + FILE* file = fopen(pathLog.string().c_str(), "r"); if (file && GetFilesize(file) > 10 * 1000000) { // Restart the file with some of the end @@ -957,7 +925,7 @@ void ShrinkDebugFile() int nBytes = fread(pch, 1, sizeof(pch), file); fclose(file); - file = fopen(strFile.c_str(), "w"); + file = fopen(pathLog.string().c_str(), "w"); if (file) { fwrite(pch, 1, nBytes, file); @@ -1071,12 +1039,7 @@ string FormatVersion(int nVersion) string FormatFullVersion() { - string s = FormatVersion(CLIENT_VERSION); - if (VERSION_IS_BETA) { - s += "-"; - s += _("beta"); - } - return s; + return CLIENT_BUILD; } // Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) @@ -1125,25 +1088,25 @@ private: int sourceLine; }; -typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack; +typedef std::vector< std::pair<void*, CLockLocation> > LockStack; static boost::interprocess::interprocess_mutex dd_mutex; -static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders; +static std::map<std::pair<void*, void*>, LockStack> lockorders; static boost::thread_specific_ptr<LockStack> lockstack; -static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2) +static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) { printf("POTENTIAL DEADLOCK DETECTED\n"); printf("Previous lock order was:\n"); - BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2) + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2) { if (i.first == mismatch.first) printf(" (1)"); if (i.first == mismatch.second) printf(" (2)"); printf(" %s\n", i.second.ToString().c_str()); } printf("Current lock order is:\n"); - BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1) + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1) { if (i.first == mismatch.first) printf(" (1)"); if (i.first == mismatch.second) printf(" (2)"); @@ -1151,7 +1114,7 @@ static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCrit } } -static void push_lock(CCriticalSection* c, const CLockLocation& locklocation) +static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) { bool fOrderOK = true; if (lockstack.get() == NULL) @@ -1162,16 +1125,16 @@ static void push_lock(CCriticalSection* c, const CLockLocation& locklocation) (*lockstack).push_back(std::make_pair(c, locklocation)); - BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack)) + if (!fTry) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) { if (i.first == c) break; - std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c); + std::pair<void*, void*> p1 = std::make_pair(i.first, c); if (lockorders.count(p1)) continue; lockorders[p1] = (*lockstack); - std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first); + std::pair<void*, void*> p2 = std::make_pair(c, i.first); if (lockorders.count(p2)) { potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); @@ -1193,62 +1156,14 @@ static void pop_lock() dd_mutex.unlock(); } -void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) -{ - push_lock(this, CLockLocation(pszName, pszFile, nLine)); -#ifdef DEBUG_LOCKCONTENTION - bool result = mutex.try_lock(); - if (!result) - { - printf("LOCKCONTENTION: %s\n", pszName); - printf("Locker: %s:%d\n", pszFile, nLine); - mutex.lock(); - printf("Locked\n"); - } -#else - mutex.lock(); -#endif -} -void CCriticalSection::Leave() +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - mutex.unlock(); - pop_lock(); -} -bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine) -{ - push_lock(this, CLockLocation(pszName, pszFile, nLine)); - bool result = mutex.try_lock(); - if (!result) pop_lock(); - return result; -} - -#else - -void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) -{ -#ifdef DEBUG_LOCKCONTENTION - bool result = mutex.try_lock(); - if (!result) - { - printf("LOCKCONTENTION: %s\n", pszName); - printf("Locker: %s:%d\n", pszFile, nLine); - mutex.lock(); - } -#else - mutex.lock(); -#endif -} - -void CCriticalSection::Leave() -{ - mutex.unlock(); + push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); } -bool CCriticalSection::TryEnter(const char*, const char*, int) +void LeaveCritical() { - bool result = mutex.try_lock(); - return result; + pop_lock(); } #endif /* DEBUG_LOCKORDER */ - diff --git a/src/util.h b/src/util.h index e4cf83f433..f6cb3caa1d 100644 --- a/src/util.h +++ b/src/util.h @@ -19,7 +19,12 @@ typedef int pid_t; /* define for windows compatiblity */ #include <string> #include <boost/thread.hpp> +#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/sync/interprocess_condition.hpp> +#include <boost/interprocess/sync/lock_options.hpp> #include <boost/date_time/gregorian/gregorian_types.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp> @@ -108,7 +113,6 @@ extern std::map<std::string, std::vector<std::string> > mapMultiArgs; extern bool fDebug; extern bool fPrintToConsole; extern bool fPrintToDebugger; -extern char pszSetDataDir[MAX_PATH]; extern bool fRequestShutdown; extern bool fShutdown; extern bool fDaemon; @@ -150,16 +154,15 @@ void ParseParameters(int argc, const char*const argv[]); bool WildcardMatch(const char* psz, const char* mask); bool WildcardMatch(const std::string& str, const std::string& mask); int GetFilesize(FILE* file); -void GetDataDir(char* pszDirRet); -std::string GetConfigFile(); -std::string GetPidFile(); -void CreatePidFile(std::string pidFile, pid_t pid); +boost::filesystem::path GetDefaultDataDir(); +const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); +boost::filesystem::path GetConfigFile(); +boost::filesystem::path GetPidFile(); +void CreatePidFile(const boost::filesystem::path &path, pid_t pid); bool ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet); #ifdef WIN32 -std::string MyGetSpecialFolderPath(int nFolder, bool fCreate); +boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate); #endif -std::string GetDefaultDataDir(); -std::string GetDataDir(); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); @@ -180,82 +183,127 @@ void AddTimeData(const CNetAddr& ip, int64 nTime); +/** Wrapped boost mutex: supports recursive locking, but no waiting */ +typedef boost::interprocess::interprocess_recursive_mutex CCriticalSection; -/** Wrapper to automatically initialize mutex. */ -class CCriticalSection -{ -protected: - boost::interprocess::interprocess_recursive_mutex mutex; -public: - explicit CCriticalSection() { } - ~CCriticalSection() { } - void Enter(const char* pszName, const char* pszFile, int nLine); - void Leave(); - bool TryEnter(const char* pszName, const char* pszFile, int nLine); -}; +/** Wrapped boost mutex: supports waiting but not recursive locking */ +typedef boost::interprocess::interprocess_mutex CWaitableCriticalSection; -/** RAII object that acquires mutex. Needed for exception safety. */ -class CCriticalBlock -{ -protected: - CCriticalSection* pcs; +#ifdef DEBUG_LOCKORDER +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); +void LeaveCritical(); +#else +void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} +void static inline LeaveCritical() {} +#endif +/** Wrapper around boost::interprocess::scoped_lock */ +template<typename Mutex> +class CMutexLock +{ +private: + boost::interprocess::scoped_lock<Mutex> lock; public: - CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine) + + void Enter(const char* pszName, const char* pszFile, int nLine) { - pcs = &csIn; - pcs->Enter(pszName, pszFile, nLine); + if (!lock.owns()) + { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); +#ifdef DEBUG_LOCKCONTENTION + if (!lock.try_lock()) + { + printf("LOCKCONTENTION: %s\n", pszName); + printf("Locker: %s:%d\n", pszFile, nLine); + } +#endif + lock.lock(); + } } - operator bool() const + void Leave() { - return true; + if (lock.owns()) + { + lock.unlock(); + LeaveCritical(); + } } - ~CCriticalBlock() + bool TryEnter(const char* pszName, const char* pszFile, int nLine) { - pcs->Leave(); + if (!lock.owns()) + { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); + lock.try_lock(); + if (!lock.owns()) + LeaveCritical(); + } + return lock.owns(); } -}; - -#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() - -/** RAII object that tries to acquire mutex. Needed for exception safety. */ -class CTryCriticalBlock -{ -protected: - CCriticalSection* pcs; + CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::interprocess::defer_lock) + { + if (fTry) + TryEnter(pszName, pszFile, nLine); + else + Enter(pszName, pszFile, nLine); + } -public: - CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine) + ~CMutexLock() { - pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL); + if (lock.owns()) + LeaveCritical(); } - operator bool() const + operator bool() { - return Entered(); + return lock.owns(); } - ~CTryCriticalBlock() + boost::interprocess::scoped_lock<Mutex> &GetLock() { - if (pcs) - { - pcs->Leave(); - } + return lock; } - bool Entered() const { return pcs != NULL; } }; -#define TRY_CRITICAL_BLOCK(cs) \ - if (CTryCriticalBlock criticalblock = CTryCriticalBlock(cs, #cs, __FILE__, __LINE__)) +typedef CMutexLock<CCriticalSection> CCriticalBlock; +typedef CMutexLock<CWaitableCriticalSection> CWaitableCriticalBlock; +typedef boost::interprocess::interprocess_condition CConditionVariable; + +/** Wait for a given condition inside a WAITABLE_CRITICAL_BLOCK */ +#define WAIT(name,condition) \ + do { while(!(condition)) { (name).wait(waitablecriticalblock.GetLock()); } } while(0) + +/** Notify waiting threads that a condition may hold now */ +#define NOTIFY(name) \ + do { (name).notify_one(); } while(0) + +#define NOTIFY_ALL(name) \ + do { (name).notify_all(); } while(0) + +#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) +#define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__) +#define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) +#define WAITABLE_LOCK(cs) CWaitableCriticalBlock waitablecriticalblock(cs, #cs, __FILE__, __LINE__) + +#define ENTER_CRITICAL_SECTION(cs) \ + { \ + EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \ + (cs).lock(); \ + } + +#define LEAVE_CRITICAL_SECTION(cs) \ + { \ + (cs).unlock(); \ + LeaveCritical(); \ + } + + +// This is exactly like std::string, but with a custom allocator. +// (secure_allocator<> is defined in serialize.h) +typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString; + @@ -658,26 +706,6 @@ inline void ExitThread(size_t nExitCode) -inline bool AffinityBugWorkaround(void(*pfn)(void*)) -{ -#ifdef WIN32 - // Sometimes after a few hours affinity gets stuck on one processor - DWORD_PTR dwProcessAffinityMask = -1; - DWORD_PTR dwSystemAffinityMask = -1; - GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask); - DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask); - DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask); - if (dwPrev2 != dwProcessAffinityMask) - { - printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask); - if (!CreateThread(pfn, NULL)) - printf("Error: CreateThread() failed\n"); - return true; - } -#endif - return false; -} - inline uint32_t ByteReverse(uint32_t value) { value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); diff --git a/src/version.cpp b/src/version.cpp new file mode 100644 index 0000000000..e1be5f491b --- /dev/null +++ b/src/version.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#include <string> + +#include "version.h" + +// Name of client reported in the 'version' message. Report the same name +// for both bitcoind and bitcoin-qt, to make it harder for attackers to +// target servers or GUI users specifically. +const std::string CLIENT_NAME("Satoshi"); + +// Client version number +#define CLIENT_VERSION_MAJOR 0 +#define CLIENT_VERSION_MINOR 6 +#define CLIENT_VERSION_REVISION 0 +#define CLIENT_VERSION_BUILD 99 +#define CLIENT_VERSION_SUFFIX "-beta" + +const int CLIENT_VERSION = 1000000 * CLIENT_VERSION_MAJOR + + 10000 * CLIENT_VERSION_MINOR + + 100 * CLIENT_VERSION_REVISION + + 1 * CLIENT_VERSION_BUILD; + + + +// The following part of the code determines the CLIENT_BUILD variable. +// Several mechanisms are used for this: +// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is +// generated by the build environment, possibly containing the output +// of git-describe in a macro called BUILD_DESC +// * secondly, if this is an exported version of the code, GIT_ARCHIVE will +// be defined (automatically using the export-subst git attribute), and +// GIT_COMMIT will contain the commit id. +// * then, three options exist for determining CLIENT_BUILD: +// * if BUILD_DESC is defined, use that literally (output of git-describe) +// * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit] +// * otherwise, use v[maj].[min].[rev].[build]-unk +// finally CLIENT_VERSION_SUFFIX is added + +// First, include build.h if requested +#ifdef HAVE_BUILD_INFO +# include "build.h" +#endif + +// git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$ +#ifdef GIT_ARCHIVE +# define GIT_COMMIT_ID "$Format:%h$" +# define GIT_COMMIT_DATE "$Format:%cD" +#endif + +#define STRINGIFY(s) #s + +#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \ + "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-g" commit + +#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \ + "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-unk" + +#ifndef BUILD_DESC +# ifdef GIT_COMMIT_ID +# define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID) +# else +# define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD) +# endif +#endif + +#ifndef BUILD_DATE +# ifdef GIT_COMMIT_DATE +# define BUILD_DATE GIT_COMMIT_DATE +# else +# define BUILD_DATE __DATE__ ", " __TIME__ +# endif +#endif + +const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX); +const std::string CLIENT_DATE(BUILD_DATE); diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000000..c93b28fb7d --- /dev/null +++ b/src/version.h @@ -0,0 +1,14 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_VERSION_H +#define BITCOIN_VERSION_H + +#include <string> + +extern const std::string CLIENT_NAME; +extern const std::string CLIENT_BUILD; +extern const std::string CLIENT_DATE; +extern const int CLIENT_VERSION; + +#endif diff --git a/src/wallet.cpp b/src/wallet.cpp index e444e5f696..97ed6aa580 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -49,8 +49,8 @@ bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector return false; if (!fFileBacked) return true; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); if (pwalletdbEncryption) return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret); else @@ -76,7 +76,8 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) CCrypter crypter; CKeyingMaterial vMasterKey; - CRITICAL_BLOCK(cs_wallet) + { + LOCK(cs_wallet); BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) @@ -86,6 +87,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) if (CCryptoKeyStore::Unlock(vMasterKey)) return true; } + } return false; } @@ -93,8 +95,8 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, { bool fWasLocked = IsLocked(); - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); Lock(); CCrypter crypter; @@ -228,8 +230,8 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey)) return false; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; if (fFileBacked) { @@ -275,8 +277,8 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) // Anytime a signature is successfully verified, it's proof the outpoint is spent. // Update the wallet spent flag if it doesn't know due to wallet.dat being // restored from backup or the user making copies of wallet.dat. - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); BOOST_FOREACH(const CTxIn& txin, tx.vin) { map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash); @@ -297,8 +299,8 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) void CWallet::MarkDirty() { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) item.second.MarkDirty(); } @@ -307,8 +309,8 @@ void CWallet::MarkDirty() bool CWallet::AddToWallet(const CWalletTx& wtxIn) { uint256 hash = wtxIn.GetHash(); - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); // Inserts only if not already there, returns tx inserted or tx found pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; @@ -382,8 +384,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) { uint256 hash = tx.GetHash(); - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); bool fExisted = mapWallet.count(hash); if (fExisted && !fUpdate) return false; if (fExisted || IsMine(tx) || IsFromMe(tx)) @@ -404,8 +406,8 @@ bool CWallet::EraseFromWallet(uint256 hash) { if (!fFileBacked) return false; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); if (mapWallet.erase(hash)) CWalletDB(strWalletFile).EraseTx(hash); } @@ -415,8 +417,8 @@ bool CWallet::EraseFromWallet(uint256 hash) bool CWallet::IsMine(const CTxIn &txin) const { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { @@ -431,8 +433,8 @@ bool CWallet::IsMine(const CTxIn &txin) const int64 CWallet::GetDebit(const CTxIn &txin) const { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { @@ -457,9 +459,11 @@ bool CWallet::IsChange(const CTxOut& txout) const // 'the change' will need to be implemented (maybe extend CWalletTx to remember // which output, if any, was change). if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address)) - CRITICAL_BLOCK(cs_wallet) - if (!mapAddressBook.count(address)) - return true; + { + LOCK(cs_wallet); + if (!mapAddressBook.count(address)) + return true; + } return false; } @@ -472,8 +476,8 @@ int CWalletTx::GetRequestCount() const { // Returns -1 if it wasn't being tracked int nRequests = -1; - CRITICAL_BLOCK(pwallet->cs_wallet) { + LOCK(pwallet->cs_wallet); if (IsCoinBase()) { // Generated block @@ -577,8 +581,8 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i nSent += s.second; nFee = allFee; } - CRITICAL_BLOCK(pwallet->cs_wallet) { + LOCK(pwallet->cs_wallet); BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived) { if (pwallet->mapAddressBook.count(r.first)) @@ -607,8 +611,8 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) vWorkQueue.push_back(txin.prevout.hash); // This critsect is OK because txdb is already open - CRITICAL_BLOCK(pwallet->cs_wallet) { + LOCK(pwallet->cs_wallet); map<uint256, const CMerkleTx*> mapWalletPrev; set<uint256> setAlreadyDone; for (int i = 0; i < vWorkQueue.size(); i++) @@ -666,8 +670,8 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) int ret = 0; CBlockIndex* pindex = pindexStart; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); while (pindex) { CBlock block; @@ -696,8 +700,9 @@ void CWallet::ReacceptWalletTransactions() { CTxDB txdb("r"); bool fRepeat = true; - while (fRepeat) CRITICAL_BLOCK(cs_wallet) + while (fRepeat) { + LOCK(cs_wallet); fRepeat = false; vector<CDiskTxPos> vMissingTx; BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) @@ -799,8 +804,8 @@ void CWallet::ResendWalletTransactions() // Rebroadcast any of our txes that aren't in a block yet printf("ResendWalletTransactions()\n"); CTxDB txdb("r"); - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); // Sort them in chronological order multimap<unsigned int, CWalletTx*> mapSorted; BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) @@ -833,8 +838,8 @@ void CWallet::ResendWalletTransactions() int64 CWallet::GetBalance() const { int64 nTotal = 0; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; @@ -850,8 +855,8 @@ int64 CWallet::GetBalance() const int64 CWallet::GetUnconfirmedBalance() const { int64 nTotal = 0; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; @@ -875,8 +880,8 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue; int64 nTotalLower = 0; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); vector<const CWalletTx*> vCoins; vCoins.reserve(mapWallet.size()); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1032,9 +1037,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW wtxNew.BindWallet(this); - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_wallet) { + LOCK2(cs_main, cs_wallet); // txdb must be opened before the mapWallet lock CTxDB txdb("r"); { @@ -1146,9 +1150,8 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& w // Call after CreateTransaction unless you want to abort bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_wallet) { + LOCK2(cs_main, cs_wallet); printf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); { // This is only to keep the database open to defeat the auto-flush for the @@ -1297,8 +1300,8 @@ bool CWallet::DelAddressBookName(const CBitcoinAddress& address) void CWallet::PrintWallet(const CBlock& block) { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); if (mapWallet.count(block.vtx[0].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; @@ -1310,8 +1313,8 @@ void CWallet::PrintWallet(const CBlock& block) bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) { @@ -1347,8 +1350,8 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) // bool CWallet::NewKeyPool() { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); CWalletDB walletdb(strWalletFile); BOOST_FOREACH(int64 nIndex, setKeyPool) walletdb.ErasePool(nIndex); @@ -1371,8 +1374,9 @@ bool CWallet::NewKeyPool() bool CWallet::TopUpKeyPool() { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); + if (IsLocked()) return false; @@ -1398,8 +1402,9 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) { nIndex = -1; keypool.vchPubKey.clear(); - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); + if (!IsLocked()) TopUpKeyPool(); @@ -1422,9 +1427,8 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) int64 CWallet::AddReserveKey(const CKeyPool& keypool) { - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_wallet) { + LOCK2(cs_main, cs_wallet); CWalletDB walletdb(strWalletFile); int64 nIndex = 1 + *(--setKeyPool.end()); @@ -1450,8 +1454,10 @@ void CWallet::KeepKey(int64 nIndex) void CWallet::ReturnKey(int64 nIndex) { // Return to key pool - CRITICAL_BLOCK(cs_wallet) + { + LOCK(cs_wallet); setKeyPool.insert(nIndex); + } printf("keypool return %"PRI64d"\n", nIndex); } @@ -1459,8 +1465,8 @@ bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse) { int64 nIndex = 0; CKeyPool keypool; - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); ReserveKeyFromKeyPool(nIndex, keypool); if (nIndex == -1) { @@ -1530,8 +1536,7 @@ void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress) CWalletDB walletdb(strWalletFile); - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_wallet) + LOCK2(cs_main, cs_wallet); BOOST_FOREACH(const int64& id, setKeyPool) { CKeyPool keypool; diff --git a/src/wallet.h b/src/wallet.h index e1065cff38..f864370acf 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -211,16 +211,18 @@ public: void UpdatedTransaction(const uint256 &hashTx) { - CRITICAL_BLOCK(cs_wallet) + { + LOCK(cs_wallet); vWalletUpdated.push_back(hashTx); + } } void PrintWallet(const CBlock& block); void Inventory(const uint256 &hash) { - CRITICAL_BLOCK(cs_wallet) { + LOCK(cs_wallet); std::map<uint256, int>::iterator mi = mapRequestCount.find(hash); if (mi != mapRequestCount.end()) (*mi).second++; |