aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.cpp53
-rw-r--r--src/main.h3
-rw-r--r--src/qt/bitcoin.cpp1
-rw-r--r--src/qt/bitcoingui.cpp37
-rw-r--r--src/qt/bitcoingui.h9
-rw-r--r--src/qt/clientmodel.cpp2
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/test/test_bitcoin.cpp7
-rw-r--r--src/util.cpp22
-rw-r--r--src/util.h1
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);