diff options
-rw-r--r-- | src/main.cpp | 53 | ||||
-rw-r--r-- | src/main.h | 3 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 1 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 37 | ||||
-rw-r--r-- | src/qt/bitcoingui.h | 9 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 2 | ||||
-rw-r--r-- | src/qt/clientmodel.h | 2 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 2 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 7 | ||||
-rw-r--r-- | src/util.cpp | 22 | ||||
-rw-r--r-- | src/util.h | 1 |
11 files changed, 104 insertions, 35 deletions
diff --git a/src/main.cpp b/src/main.cpp index 8279924a3c..21c54befcb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -818,7 +818,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx) } -bool CTxMemPool::remove(CTransaction &tx) +bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive) { // Remove transaction from memory pool { @@ -826,6 +826,13 @@ bool CTxMemPool::remove(CTransaction &tx) uint256 hash = tx.GetHash(); if (mapTx.count(hash)) { + if (fRecursive) { + for (unsigned int i = 0; i < tx.vout.size(); i++) { + std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i)); + if (it != mapNextTx.end()) + remove(*it->second.ptx, true); + } + } BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); mapTx.erase(hash); @@ -835,6 +842,21 @@ bool CTxMemPool::remove(CTransaction &tx) return true; } +bool CTxMemPool::removeConflicts(const CTransaction &tx) +{ + // Remove transactions which depend on inputs of tx, recursively + LOCK(cs); + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout); + if (it != mapNextTx.end()) { + const CTransaction &txConflict = *it->second.ptx; + if (txConflict != tx) + remove(txConflict, true); + } + } + return true; +} + void CTxMemPool::clear() { LOCK(cs); @@ -1645,7 +1667,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust bool SetBestChain(CBlockIndex* pindexNew) { - CCoinsViewCache &view = *pcoinsTip; + // All modifications to the coin state will be done in this cache. + // Only when all have succeeded, we push it to pcoinsTip. + CCoinsViewCache view(*pcoinsTip, true); // special case for attaching the genesis block // note that no ConnectBlock is called, so its coinbase output is non-spendable @@ -1698,11 +1722,8 @@ bool SetBestChain(CBlockIndex* pindexNew) CBlock block; if (!block.ReadFromDisk(pindex)) return error("SetBestBlock() : ReadFromDisk for disconnect failed"); - CCoinsViewCache viewTemp(view, true); - if (!block.DisconnectBlock(pindex, viewTemp)) + if (!block.DisconnectBlock(pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after disconnect"); // Queue memory transactions to resurrect BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -1716,26 +1737,27 @@ bool SetBestChain(CBlockIndex* pindexNew) CBlock block; if (!block.ReadFromDisk(pindex)) return error("SetBestBlock() : ReadFromDisk for connect failed"); - CCoinsViewCache viewTemp(view, true); - if (!block.ConnectBlock(pindex, viewTemp)) { + if (!block.ConnectBlock(pindex, view)) { InvalidChainFound(pindexNew); InvalidBlockFound(pindex); return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); } - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after connect"); // Queue memory transactions to delete BOOST_FOREACH(const CTransaction& tx, block.vtx) vDelete.push_back(tx); } + // Flush changes to global coin state + if (!view.Flush()) + return error("SetBestBlock() : unable to modify coin state"); + // Make sure it's successfully written to disk before changing memory structure bool fIsInitialDownload = IsInitialBlockDownload(); - if (!fIsInitialDownload || view.GetCacheSize() > nCoinCacheSize) { + if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) { FlushBlockFile(); pblocktree->Sync(); - if (!view.Flush()) + if (!pcoinsTip->Flush()) return false; } @@ -1757,8 +1779,10 @@ bool SetBestChain(CBlockIndex* pindexNew) tx.AcceptToMemoryPool(false); // Delete redundant memory transactions that are in the connected branch - BOOST_FOREACH(CTransaction& tx, vDelete) + BOOST_FOREACH(CTransaction& tx, vDelete) { mempool.remove(tx); + mempool.removeConflicts(tx); + } // Update best block in wallet (so we can detect restored wallets) if (!fIsInitialDownload) @@ -3730,6 +3754,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move map<uint256, vector<COrphan*> > mapDependers; + bool fPrintPriority = GetBoolArg("-printpriority"); // This vector will be sorted into a priority queue: vector<TxPriority> vecPriority; @@ -3876,7 +3901,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) nBlockSigOps += nTxSigOps; nFees += nTxFees; - if (fDebug && GetBoolArg("-printpriority")) + if (fPrintPriority) { printf("priority %.1f feeperkb %.1f txid %s\n", dPriority, dFeePerKb, tx.GetHash().ToString().c_str()); diff --git a/src/main.h b/src/main.h index a5f60fe945..4bd4782ccb 100644 --- a/src/main.h +++ b/src/main.h @@ -1831,7 +1831,8 @@ public: bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs); bool addUnchecked(const uint256& hash, CTransaction &tx); - bool remove(CTransaction &tx); + bool remove(const CTransaction &tx, bool fRecursive = false); + bool removeConflicts(const CTransaction &tx); void clear(); void queryHashes(std::vector<uint256>& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d64114e131..95d956dd8c 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -45,7 +45,6 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string& modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(caption)), Q_ARG(QString, QString::fromStdString(message)), - Q_ARG(bool, modal), Q_ARG(unsigned int, style)); } else diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index e2350c09ee..3fe86501f6 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -90,7 +90,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): // Create the toolbars createToolBars(); - // Create the tray icon (or setup the dock icon) + // Create system tray icon and notification createTrayIcon(); // Create tabs @@ -354,12 +354,17 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // Just attach " [testnet]" to the existing tooltip trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]")); trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); - toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); } + toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); aboutAction->setIcon(QIcon(":/icons/toolbar_testnet")); } + // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions, + // while the client has not yet fully loaded + if(trayIcon) + createTrayIconMenu(); + // Keep up to date with client setNumConnections(clientModel->getNumConnections()); connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); @@ -368,7 +373,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); // Receive and report messages from network/worker thread - connect(clientModel, SIGNAL(message(QString,QString,bool,unsigned int)), this, SLOT(message(QString,QString,bool,unsigned int))); + connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); overviewPage->setClientModel(clientModel); rpcConsole->setClientModel(clientModel); @@ -383,7 +388,7 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) if(walletModel) { // Receive and report messages from wallet thread - connect(walletModel, SIGNAL(message(QString,QString,bool,unsigned int)), this, SLOT(message(QString,QString,bool,unsigned int))); + connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); // Put transaction list in tabs transactionView->setModel(walletModel); @@ -407,16 +412,26 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) void BitcoinGUI::createTrayIcon() { - QMenu *trayIconMenu; #ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); - trayIconMenu = new QMenu(this); - trayIcon->setContextMenu(trayIconMenu); + trayIcon->setToolTip(tr("Bitcoin client")); trayIcon->setIcon(QIcon(":/icons/toolbar")); + trayIcon->show(); +#endif + + notificator = new Notificator(qApp->applicationName(), trayIcon); +} + +void BitcoinGUI::createTrayIconMenu() +{ + QMenu *trayIconMenu; +#ifndef Q_OS_MAC + trayIconMenu = new QMenu(this); + trayIcon->setContextMenu(trayIconMenu); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); - trayIcon->show(); #else // Note: On Mac, the dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); @@ -438,8 +453,6 @@ void BitcoinGUI::createTrayIcon() trayIconMenu->addSeparator(); trayIconMenu->addAction(quitAction); #endif - - notificator = new Notificator(qApp->applicationName(), trayIcon); } #ifndef Q_OS_MAC @@ -593,7 +606,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) progressBar->setToolTip(tooltip); } -void BitcoinGUI::message(const QString &title, const QString &message, bool modal, unsigned int style) +void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style) { QString strTitle = tr("Bitcoin") + " - "; // Default to information icon @@ -626,7 +639,7 @@ void BitcoinGUI::message(const QString &title, const QString &message, bool moda } // Display message - if (modal) { + if (style & CClientUIInterface::MODAL) { // Check for buttons, use OK as default, if none was supplied QMessageBox::StandardButton buttons; if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK))) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 151b108be7..3faf6d948c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -105,8 +105,10 @@ private: void createMenuBar(); /** Create the toolbars */ void createToolBars(); - /** Create system tray (notification) icon */ + /** Create system tray icon and notification */ void createTrayIcon(); + /** Create system tray menu (or setup the dock menu) */ + void createTrayIconMenu(); public slots: /** Set number of connections shown in the UI */ @@ -122,11 +124,10 @@ public slots: /** Notify the user of an event from the core network or transaction handling code. @param[in] title the message box / notification title @param[in] message the displayed text - @param[in] modal true to use a message box, false to use a notification - @param[in] style style definitions (icon and used buttons - buttons only for message boxes) + @param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes) @see CClientUIInterface::MessageBoxFlags */ - void message(const QString &title, const QString &message, bool modal, unsigned int style); + void message(const QString &title, const QString &message, unsigned int style); /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f8fa412019..ce112803f8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -84,7 +84,7 @@ void ClientModel::updateAlert(const QString &hash, int status) CAlert alert = CAlert::getAlertByHash(hash_256); if(!alert.IsNull()) { - emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false, CClientUIInterface::ICON_ERROR); + emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); } } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index b16b2d5004..1afccb7859 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -71,7 +71,7 @@ signals: void alertsChanged(const QString &warnings); //! Asynchronous message notification - void message(const QString &title, const QString &message, bool modal, unsigned int style); + void message(const QString &title, const QString &message, unsigned int style); public slots: void updateTimer(); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 3c8d5903b0..fd5c8c4d4f 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -148,7 +148,7 @@ signals: void requireUnlock(); // Asynchronous message notification - void message(const QString &title, const QString &message, bool modal, unsigned int style); + void message(const QString &title, const QString &message, unsigned int style); public slots: /* Wallet status might have changed */ diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index e4ba0259ba..b98816d53d 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -1,10 +1,12 @@ #define BOOST_TEST_MODULE Bitcoin Test Suite #include <boost/test/unit_test.hpp> +#include <boost/filesystem.hpp> #include "db.h" #include "txdb.h" #include "main.h" #include "wallet.h" +#include "util.h" CWallet* pwalletMain; CClientUIInterface uiInterface; @@ -14,11 +16,15 @@ extern void noui_connect(); struct TestingSetup { CCoinsViewDB *pcoinsdbview; + boost::filesystem::path pathTemp; TestingSetup() { fPrintToDebugger = true; // don't want to write to debug.log file noui_connect(); bitdb.MakeMock(); + pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(*pcoinsdbview); @@ -36,6 +42,7 @@ struct TestingSetup { delete pcoinsdbview; delete pblocktree; bitdb.Flush(true); + boost::filesystem::remove_all(pathTemp); } }; diff --git a/src/util.cpp b/src/util.cpp index 2f36c66067..bd8ad8acd0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1310,6 +1310,28 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif +boost::filesystem::path GetTempPath() { +#if BOOST_FILESYSTEM_VERSION == 3 + return boost::filesystem::temp_directory_path(); +#else + // TODO: remove when we don't support filesystem v2 anymore + boost::filesystem::path path; +#ifdef WIN32 + char pszPath[MAX_PATH] = ""; + + if (GetTempPathA(MAX_PATH, pszPath)) + path = boost::filesystem::path(pszPath); +#else + path = boost::filesystem::path("/tmp"); +#endif + if (path.empty() || !boost::filesystem::is_directory(path)) { + printf("GetTempPath(): failed to find temp path\n"); + return boost::filesystem::path(""); + } + return path; +#endif +} + void runCommand(std::string strCommand) { int nErr = ::system(strCommand.c_str()); diff --git a/src/util.h b/src/util.h index b798f60aa7..ada0dd3790 100644 --- a/src/util.h +++ b/src/util.h @@ -207,6 +207,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif +boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); |