aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/chainparams.h6
-rw-r--r--src/db.cpp77
-rw-r--r--src/db.h6
-rw-r--r--src/main.cpp33
-rw-r--r--src/net.cpp4
-rw-r--r--src/net.h2
-rw-r--r--src/protocol.cpp13
-rw-r--r--src/protocol.h8
-rw-r--r--src/qt/bitcoingui.cpp10
-rw-r--r--src/qt/bitcoingui.h4
-rw-r--r--src/qt/clientmodel.cpp18
-rw-r--r--src/qt/clientmodel.h5
-rw-r--r--src/qt/guiutil.cpp46
-rw-r--r--src/qt/rpcconsole.cpp9
-rw-r--r--src/qt/rpcconsole.h4
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/test/DoS_tests.cpp4
-rw-r--r--src/test/accounting_tests.cpp4
-rw-r--r--src/test/alert_tests.cpp4
-rw-r--r--src/test/main_tests.cpp4
-rw-r--r--src/test/miner_tests.cpp4
-rw-r--r--src/test/rpc_tests.cpp4
-rw-r--r--src/test/rpc_wallet_tests.cpp4
-rw-r--r--src/test/test_bitcoin.cpp28
-rw-r--r--src/test/test_bitcoin.h18
-rw-r--r--src/test/wallet_tests.cpp4
-rw-r--r--src/util.h1
-rw-r--r--src/walletdb.cpp6
30 files changed, 218 insertions, 116 deletions
diff --git a/.travis.yml b/.travis.yml
index e08e78dab..9c18729b4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,7 @@ env:
global:
- MAKEJOBS=-j3
- RUN_TESTS=false
+ - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID
- CCACHE_SIZE=100M
- CCACHE_TEMPDIR=/tmp/.ccache-temp
- CCACHE_COMPRESS=1
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 6774745de..e9d99323c 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -66,6 +66,7 @@ BITCOIN_TESTS =\
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
test/test_bitcoin.cpp \
+ test/test_bitcoin.h \
test/timedata_tests.cpp \
test/transaction_tests.cpp \
test/uint256_tests.cpp \
diff --git a/src/chainparams.h b/src/chainparams.h
index 86b84df66..78b575d8f 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -14,8 +14,6 @@
#include <vector>
-typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
-
struct CDNSSeedData {
std::string name, host;
CDNSSeedData(const std::string &strName, const std::string &strHost) : name(strName), host(strHost) {}
@@ -42,7 +40,7 @@ public:
};
const uint256& HashGenesisBlock() const { return hashGenesisBlock; }
- const MessageStartChars& MessageStart() const { return pchMessageStart; }
+ const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
const arith_uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; }
@@ -83,7 +81,7 @@ protected:
CChainParams() {}
uint256 hashGenesisBlock;
- MessageStartChars pchMessageStart;
+ CMessageHeader::MessageStartChars pchMessageStart;
//! Raw pub key bytes for the broadcast alert signing key.
std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
diff --git a/src/db.cpp b/src/db.cpp
index 3246e4b67..36946b7dc 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -39,22 +39,31 @@ void CDBEnv::EnvShutdown()
return;
fDbEnvInit = false;
- int ret = dbenv.close(0);
+ int ret = dbenv->close(0);
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
DbEnv(0).remove(path.string().c_str(), 0);
}
-CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS)
+void CDBEnv::Reset()
{
+ delete dbenv;
+ dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
fDbEnvInit = false;
fMockDb = false;
}
+CDBEnv::CDBEnv() : dbenv(NULL)
+{
+ Reset();
+}
+
CDBEnv::~CDBEnv()
{
EnvShutdown();
+ delete dbenv;
+ dbenv = NULL;
}
void CDBEnv::Close()
@@ -79,17 +88,17 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
if (GetBoolArg("-privdb", true))
nEnvFlags |= DB_PRIVATE;
- dbenv.set_lg_dir(pathLogDir.string().c_str());
- dbenv.set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
- dbenv.set_lg_bsize(0x10000);
- dbenv.set_lg_max(1048576);
- dbenv.set_lk_max_locks(40000);
- dbenv.set_lk_max_objects(40000);
- dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
- dbenv.set_flags(DB_AUTO_COMMIT, 1);
- dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
- dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
- int ret = dbenv.open(path.string().c_str(),
+ dbenv->set_lg_dir(pathLogDir.string().c_str());
+ dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
+ dbenv->set_lg_bsize(0x10000);
+ dbenv->set_lg_max(1048576);
+ dbenv->set_lk_max_locks(40000);
+ dbenv->set_lk_max_objects(40000);
+ dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
+ dbenv->set_flags(DB_AUTO_COMMIT, 1);
+ dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
+ dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
+ int ret = dbenv->open(path.string().c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -116,14 +125,14 @@ void CDBEnv::MakeMock()
LogPrint("db", "CDBEnv::MakeMock\n");
- dbenv.set_cachesize(1, 0, 1);
- dbenv.set_lg_bsize(10485760 * 4);
- dbenv.set_lg_max(10485760);
- dbenv.set_lk_max_locks(10000);
- dbenv.set_lk_max_objects(10000);
- dbenv.set_flags(DB_AUTO_COMMIT, 1);
- dbenv.log_set_config(DB_LOG_IN_MEMORY, 1);
- int ret = dbenv.open(NULL,
+ dbenv->set_cachesize(1, 0, 1);
+ dbenv->set_lg_bsize(10485760 * 4);
+ dbenv->set_lg_max(10485760);
+ dbenv->set_lk_max_locks(10000);
+ dbenv->set_lk_max_objects(10000);
+ dbenv->set_flags(DB_AUTO_COMMIT, 1);
+ dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
+ int ret = dbenv->open(NULL,
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -144,7 +153,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDB
LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0);
- Db db(&dbenv, 0);
+ Db db(dbenv, 0);
int result = db.verify(strFile.c_str(), NULL, NULL, 0);
if (result == 0)
return VERIFY_OK;
@@ -167,7 +176,7 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector<CDBEnv::
stringstream strDump;
- Db db(&dbenv, 0);
+ Db db(dbenv, 0);
int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
if (result == DB_VERIFY_BAD) {
LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
@@ -208,10 +217,10 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector<CDBEnv::
void CDBEnv::CheckpointLSN(const std::string& strFile)
{
- dbenv.txn_checkpoint(0, 0, 0);
+ dbenv->txn_checkpoint(0, 0, 0);
if (fMockDb)
return;
- dbenv.lsn_reset(strFile.c_str(), 0);
+ dbenv->lsn_reset(strFile.c_str(), 0);
}
@@ -237,7 +246,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
++bitdb.mapFileUseCount[strFile];
pdb = bitdb.mapDb[strFile];
if (pdb == NULL) {
- pdb = new Db(&bitdb.dbenv, 0);
+ pdb = new Db(bitdb.dbenv, 0);
bool fMockDb = bitdb.IsMock();
if (fMockDb) {
@@ -284,7 +293,7 @@ void CDB::Flush()
if (fReadOnly)
nMinutes = 1;
- bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0);
+ bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0);
}
void CDB::Close()
@@ -324,7 +333,7 @@ bool CDBEnv::RemoveDb(const string& strFile)
this->CloseDb(strFile);
LOCK(cs_db);
- int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
+ int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
return (rc == 0);
}
@@ -344,7 +353,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
CDB db(strFile.c_str(), "r");
- Db* pdbCopy = new Db(&bitdb.dbenv, 0);
+ Db* pdbCopy = new Db(bitdb.dbenv, 0);
int ret = pdbCopy->open(NULL, // Txn pointer
strFileRes.c_str(), // Filename
@@ -394,10 +403,10 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
}
}
if (fSuccess) {
- Db dbA(&bitdb.dbenv, 0);
+ Db dbA(bitdb.dbenv, 0);
if (dbA.remove(strFile.c_str(), NULL, 0))
fSuccess = false;
- Db dbB(&bitdb.dbenv, 0);
+ Db dbB(bitdb.dbenv, 0);
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
fSuccess = false;
}
@@ -430,10 +439,10 @@ void CDBEnv::Flush(bool fShutdown)
// Move log data to the dat file
CloseDb(strFile);
LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile);
- dbenv.txn_checkpoint(0, 0, 0);
+ dbenv->txn_checkpoint(0, 0, 0);
LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile);
if (!fMockDb)
- dbenv.lsn_reset(strFile.c_str(), 0);
+ dbenv->lsn_reset(strFile.c_str(), 0);
LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile);
mapFileUseCount.erase(mi++);
} else
@@ -443,7 +452,7 @@ void CDBEnv::Flush(bool fShutdown)
if (fShutdown) {
char** listp;
if (mapFileUseCount.empty()) {
- dbenv.log_archive(&listp, DB_ARCH_REMOVE);
+ dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
if (!fMockDb)
boost::filesystem::remove_all(path / "database");
diff --git a/src/db.h b/src/db.h
index d208907c8..71133f969 100644
--- a/src/db.h
+++ b/src/db.h
@@ -39,12 +39,14 @@ private:
public:
mutable CCriticalSection cs_db;
- DbEnv dbenv;
+ DbEnv *dbenv;
std::map<std::string, int> mapFileUseCount;
std::map<std::string, Db*> mapDb;
CDBEnv();
~CDBEnv();
+ void Reset();
+
void MakeMock();
bool IsMock() { return fMockDb; }
@@ -79,7 +81,7 @@ public:
DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
{
DbTxn* ptxn = NULL;
- int ret = dbenv.txn_begin(NULL, &ptxn, flags);
+ int ret = dbenv->txn_begin(NULL, &ptxn, flags);
if (!ptxn || ret != 0)
return NULL;
return ptxn;
diff --git a/src/main.cpp b/src/main.cpp
index 183dff6d3..e16887fa4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -54,7 +54,6 @@ bool fTxIndex = false;
bool fIsBareMultisigStd = true;
unsigned int nCoinCacheSize = 5000;
-
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(1000);
@@ -3088,10 +3087,31 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
void UnloadBlockIndex()
{
- mapBlockIndex.clear();
+ LOCK(cs_main);
setBlockIndexCandidates.clear();
chainActive.SetTip(NULL);
pindexBestInvalid = NULL;
+ pindexBestHeader = NULL;
+ mempool.clear();
+ mapOrphanTransactions.clear();
+ mapOrphanTransactionsByPrev.clear();
+ nSyncStarted = 0;
+ mapBlocksUnlinked.clear();
+ vinfoBlockFile.clear();
+ nLastBlockFile = 0;
+ nBlockSequenceId = 1;
+ mapBlockSource.clear();
+ mapBlocksInFlight.clear();
+ nQueuedValidatedHeaders = 0;
+ nPreferredDownload = 0;
+ setDirtyBlockIndex.clear();
+ setDirtyFileInfo.clear();
+ mapNodeState.clear();
+
+ BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
+ delete entry.second;
+ }
+ mapBlockIndex.clear();
}
bool LoadBlockIndex()
@@ -4024,7 +4044,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "getaddr")
+ // This asymmetric behavior for inbound and outbound connections was introduced
+ // to prevent a fingerprinting attack: an attacker can send specific fake addresses
+ // to users' AddrMan and later request them by sending getaddr messages.
+ // Making users (which are behind NAT and can only make outgoing connections) ignore
+ // getaddr message mitigates the attack.
+ else if ((strCommand == "getaddr") && (pfrom->fInbound))
{
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
@@ -4308,7 +4333,7 @@ bool ProcessMessages(CNode* pfrom)
// Read header
CMessageHeader& hdr = msg.hdr;
- if (!hdr.IsValid())
+ if (!hdr.IsValid(Params().MessageStart()))
{
LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id);
continue;
diff --git a/src/net.cpp b/src/net.cpp
index 08d1d5740..0723ee218 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -510,7 +510,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
// get current incomplete message, or create a new one
if (vRecvMsg.empty() ||
vRecvMsg.back().complete())
- vRecvMsg.push_back(CNetMessage(SER_NETWORK, nRecvVersion));
+ vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, nRecvVersion));
CNetMessage& msg = vRecvMsg.back();
@@ -1976,7 +1976,7 @@ void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSen
{
ENTER_CRITICAL_SECTION(cs_vSend);
assert(ssSend.size() == 0);
- ssSend << CMessageHeader(pszCommand, 0);
+ ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0);
LogPrint("net", "sending: %s ", SanitizeString(pszCommand));
}
diff --git a/src/net.h b/src/net.h
index 24275d4a9..7dd02b84e 100644
--- a/src/net.h
+++ b/src/net.h
@@ -185,7 +185,7 @@ public:
int64_t nTime; // time (in microseconds) of message receipt.
- CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) {
+ CNetMessage(const CMessageHeader::MessageStartChars& pchMessageStartIn, int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), hdr(pchMessageStartIn), vRecv(nTypeIn, nVersionIn) {
hdrbuf.resize(24);
in_data = false;
nHdrPos = 0;
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 74ac706d6..568580a59 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -5,7 +5,6 @@
#include "protocol.h"
-#include "chainparams.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -21,17 +20,17 @@ static const char* ppszTypeName[] =
"filtered block"
};
-CMessageHeader::CMessageHeader()
+CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
{
- memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE);
+ memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);
memset(pchCommand, 0, sizeof(pchCommand));
nMessageSize = -1;
nChecksum = 0;
}
-CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
+CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn)
{
- memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE);
+ memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);
memset(pchCommand, 0, sizeof(pchCommand));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn;
@@ -43,10 +42,10 @@ std::string CMessageHeader::GetCommand() const
return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE));
}
-bool CMessageHeader::IsValid() const
+bool CMessageHeader::IsValid(const MessageStartChars& pchMessageStartIn) const
{
// Check start string
- if (memcmp(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0)
+ if (memcmp(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE) != 0)
return false;
// Check the command string for errors
diff --git a/src/protocol.h b/src/protocol.h
index f8394ce52..e838c0d36 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -29,11 +29,13 @@
class CMessageHeader
{
public:
- CMessageHeader();
- CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn);
+ typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
+
+ CMessageHeader(const MessageStartChars& pchMessageStartIn);
+ CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn);
std::string GetCommand() const;
- bool IsValid() const;
+ bool IsValid(const MessageStartChars& messageStart) const;
ADD_SERIALIZE_METHODS;
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index a0dcb46e2..1ec968ff2 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -340,6 +340,7 @@ void BitcoinGUI::createActions()
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
showHelpMessageAction = new QAction(TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
+ showHelpMessageAction->setMenuRole(QAction::NoRole);
showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options"));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
@@ -435,8 +436,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(clientModel->getNumBlocks());
- connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+ setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate());
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(setNumBlocks(int,QDateTime)));
// Receive and report messages from client model
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
@@ -652,7 +653,7 @@ void BitcoinGUI::setNumConnections(int count)
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
-void BitcoinGUI::setNumBlocks(int count)
+void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
{
if(!clientModel)
return;
@@ -680,9 +681,8 @@ void BitcoinGUI::setNumBlocks(int count)
QString tooltip;
- QDateTime lastBlockDate = clientModel->getLastBlockDate();
QDateTime currentDate = QDateTime::currentDateTime();
- qint64 secs = lastBlockDate.secsTo(currentDate);
+ qint64 secs = blockDate.secsTo(currentDate);
tooltip = tr("Processed %n blocks of transaction history.", "", count);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index fd776d63f..5a289a904 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -143,8 +143,8 @@ signals:
public slots:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
- /** Set number of blocks shown in the UI */
- void setNumBlocks(int count);
+ /** Set number of blocks and last block date shown in the UI */
+ void setNumBlocks(int count, const QDateTime& blockDate);
/** Notify the user of an event from the core network or transaction handling code.
@param[in] title the message box / notification title
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 729eb84a1..dc32f8157 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -18,7 +18,6 @@
#include <stdint.h>
-#include <QDateTime>
#include <QDebug>
#include <QTimer>
@@ -29,6 +28,7 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
optionsModel(optionsModel),
peerTableModel(0),
cachedNumBlocks(0),
+ cachedBlockDate(QDateTime()),
cachedReindexing(0),
cachedImporting(0),
pollTimer(0)
@@ -79,10 +79,11 @@ quint64 ClientModel::getTotalBytesSent() const
QDateTime ClientModel::getLastBlockDate() const
{
LOCK(cs_main);
+
if (chainActive.Tip())
return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
- else
- return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
+
+ return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
}
double ClientModel::getVerificationProgress() const
@@ -97,21 +98,26 @@ void ClientModel::updateTimer()
// periodical polls if the core is holding the locks for a longer time -
// for example, during a wallet rescan.
TRY_LOCK(cs_main, lockMain);
- if(!lockMain)
+ if (!lockMain)
return;
+
// Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
// Periodically check and update with a timer.
int newNumBlocks = getNumBlocks();
+ QDateTime newBlockDate = getLastBlockDate();
// check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state
if (cachedNumBlocks != newNumBlocks ||
- cachedReindexing != fReindex || cachedImporting != fImporting)
+ cachedBlockDate != newBlockDate ||
+ cachedReindexing != fReindex ||
+ cachedImporting != fImporting)
{
cachedNumBlocks = newNumBlocks;
+ cachedBlockDate = newBlockDate;
cachedReindexing = fReindex;
cachedImporting = fImporting;
- emit numBlocksChanged(newNumBlocks);
+ emit numBlocksChanged(newNumBlocks, newBlockDate);
}
emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 7b74728b2..214701810 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -6,6 +6,7 @@
#define BITCOIN_QT_CLIENTMODEL_H
#include <QObject>
+#include <QDateTime>
class AddressTableModel;
class OptionsModel;
@@ -15,7 +16,6 @@ class TransactionTableModel;
class CWallet;
QT_BEGIN_NAMESPACE
-class QDateTime;
class QTimer;
QT_END_NAMESPACE
@@ -73,6 +73,7 @@ private:
PeerTableModel *peerTableModel;
int cachedNumBlocks;
+ QDateTime cachedBlockDate;
bool cachedReindexing;
bool cachedImporting;
@@ -83,7 +84,7 @@ private:
signals:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count);
+ void numBlocksChanged(int count, const QDateTime& blockDate);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 2a13f43ea..9db0a7597 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -40,6 +40,7 @@
#if BOOST_FILESYSTEM_VERSION >= 3
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
#endif
+#include <boost/scoped_array.hpp>
#include <QAbstractItemView>
#include <QApplication>
@@ -567,12 +568,17 @@ TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* t
#ifdef WIN32
boost::filesystem::path static StartupShortcutPath()
{
+ if (GetBoolArg("-testnet", false))
+ return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk";
+ else if (GetBoolArg("-regtest", false))
+ return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (regtest).lnk";
+
return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk";
}
bool GetStartOnSystemStartup()
{
- // check for Bitcoin.lnk
+ // check for Bitcoin*.lnk
return boost::filesystem::exists(StartupShortcutPath());
}
@@ -588,8 +594,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
// Get a pointer to the IShellLink interface.
IShellLink* psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER, IID_IShellLink,
- reinterpret_cast<void**>(&psl));
+ CLSCTX_INPROC_SERVER, IID_IShellLink,
+ reinterpret_cast<void**>(&psl));
if (SUCCEEDED(hres))
{
@@ -597,20 +603,34 @@ bool SetStartOnSystemStartup(bool fAutoStart)
TCHAR pszExePath[MAX_PATH];
GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
- TCHAR pszArgs[5] = TEXT("-min");
+ // Start client minimized
+ QString strArgs = "-min";
+ // Set -testnet /-regtest options
+ strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false)));
+
+#ifdef UNICODE
+ boost::scoped_array<TCHAR> args(new TCHAR[strArgs.length() + 1]);
+ // Convert the QString to TCHAR*
+ strArgs.toWCharArray(args.get());
+ // Add missing '\0'-termination to string
+ args[strArgs.length()] = '\0';
+#endif
// Set the path to the shortcut target
psl->SetPath(pszExePath);
PathRemoveFileSpec(pszExePath);
psl->SetWorkingDirectory(pszExePath);
psl->SetShowCmd(SW_SHOWMINNOACTIVE);
- psl->SetArguments(pszArgs);
+#ifndef UNICODE
+ psl->SetArguments(strArgs.toStdString().c_str());
+#else
+ psl->SetArguments(args.get());
+#endif
// Query IShellLink for the IPersistFile interface for
// saving the shortcut in persistent storage.
IPersistFile* ppf = NULL;
- hres = psl->QueryInterface(IID_IPersistFile,
- reinterpret_cast<void**>(&ppf));
+ hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf));
if (SUCCEEDED(hres))
{
WCHAR pwsz[MAX_PATH];
@@ -630,11 +650,10 @@ bool SetStartOnSystemStartup(bool fAutoStart)
}
return true;
}
-
#elif defined(Q_OS_LINUX)
// Follow the Desktop Application Autostart Spec:
-// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
boost::filesystem::path static GetAutostartDir()
{
@@ -690,8 +709,13 @@ bool SetStartOnSystemStartup(bool fAutoStart)
// Write a bitcoin.desktop file to the autostart directory:
optionFile << "[Desktop Entry]\n";
optionFile << "Type=Application\n";
- optionFile << "Name=Bitcoin\n";
- optionFile << "Exec=" << pszExePath << " -min\n";
+ if (GetBoolArg("-testnet", false))
+ optionFile << "Name=Bitcoin (testnet)\n";
+ else if (GetBoolArg("-regtest", false))
+ optionFile << "Name=Bitcoin (regtest)\n";
+ else
+ optionFile << "Name=Bitcoin\n";
+ optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false));
optionFile << "Terminal=false\n";
optionFile << "Hidden=false\n";
optionFile.close();
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 9f3991c4c..ccde44fb2 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -293,8 +293,8 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(model->getNumBlocks());
- connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+ setNumBlocks(model->getNumBlocks(), model->getLastBlockDate());
+ connect(model, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(setNumBlocks(int,QDateTime)));
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
@@ -404,11 +404,10 @@ void RPCConsole::setNumConnections(int count)
ui->numberOfConnections->setText(connections);
}
-void RPCConsole::setNumBlocks(int count)
+void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate)
{
ui->numberOfBlocks->setText(QString::number(count));
- if(clientModel)
- ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
+ ui->lastBlockTime->setText(blockDate.toString());
}
void RPCConsole::on_lineEdit_returnPressed()
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index fff5cfbf5..8737be35d 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -63,8 +63,8 @@ public slots:
void message(int category, const QString &message, bool html = false);
/** Set number of connections shown in the UI */
void setNumConnections(int count);
- /** Set number of blocks shown in the UI */
- void setNumBlocks(int count);
+ /** Set number of blocks and last block date shown in the UI */
+ void setNumBlocks(int count, const QDateTime& blockDate);
/** Go forward or back in history */
void browseHistory(int offset);
/** Scroll console view to end */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 5aef2d753..4f3230a8c 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -121,7 +121,7 @@ void SendCoinsDialog::setClientModel(ClientModel *clientModel)
this->clientModel = clientModel;
if (clientModel) {
- connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(updateSmartFeeLabel()));
}
}
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 9407511ec..bf2554875 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -16,6 +16,8 @@
#include "serialize.h"
#include "util.h"
+#include "test/test_bitcoin.h"
+
#include <stdint.h>
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
@@ -41,7 +43,7 @@ CService ip(uint32_t i)
return CService(CNetAddr(s), Params().GetDefaultPort());
}
-BOOST_AUTO_TEST_SUITE(DoS_tests)
+BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(DoS_banning)
{
diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp
index da07b8c7a..36499f01a 100644
--- a/src/test/accounting_tests.cpp
+++ b/src/test/accounting_tests.cpp
@@ -5,6 +5,8 @@
#include "wallet.h"
#include "walletdb.h"
+#include "test/test_bitcoin.h"
+
#include <stdint.h>
#include <boost/foreach.hpp>
@@ -12,7 +14,7 @@
extern CWallet* pwalletMain;
-BOOST_AUTO_TEST_SUITE(accounting_tests)
+BOOST_FIXTURE_TEST_SUITE(accounting_tests, TestingSetup)
static void
GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results)
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index efc921171..5e1f5f029 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -15,6 +15,8 @@
#include "util.h"
#include "utilstrencodings.h"
+#include "test/test_bitcoin.h"
+
#include <fstream>
#include <boost/filesystem/operations.hpp>
@@ -78,7 +80,7 @@
}
#endif
-struct ReadAlerts
+struct ReadAlerts : public TestingSetup
{
ReadAlerts()
{
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 2a72a220a..1927f3dea 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -5,9 +5,11 @@
#include "primitives/transaction.h"
#include "main.h"
+#include "test/test_bitcoin.h"
+
#include <boost/test/unit_test.hpp>
-BOOST_AUTO_TEST_SUITE(main_tests)
+BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 44c57a8ea..6ab9cb8a4 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -8,9 +8,11 @@
#include "uint256.h"
#include "util.h"
+#include "test/test_bitcoin.h"
+
#include <boost/test/unit_test.hpp>
-BOOST_AUTO_TEST_SUITE(miner_tests)
+BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
static
struct {
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 1c6963001..45cb551d0 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -8,6 +8,8 @@
#include "base58.h"
#include "netbase.h"
+#include "test/test_bitcoin.h"
+
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
@@ -45,7 +47,7 @@ Value CallRPC(string args)
}
-BOOST_AUTO_TEST_SUITE(rpc_tests)
+BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 57c49c2df..44475076b 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -8,6 +8,8 @@
#include "base58.h"
#include "wallet.h"
+#include "test/test_bitcoin.h"
+
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
@@ -19,7 +21,7 @@ extern Value CallRPC(string args);
extern CWallet* pwalletMain;
-BOOST_AUTO_TEST_SUITE(rpc_wallet_tests)
+BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(rpc_addmultisig)
{
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index f2dae99d6..5df417b8e 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -4,6 +4,8 @@
#define BOOST_TEST_MODULE Bitcoin Test Suite
+#include "test_bitcoin.h"
+
#include "main.h"
#include "random.h"
#include "txdb.h"
@@ -24,18 +26,15 @@ CWallet* pwalletMain;
extern bool fPrintToConsole;
extern void noui_connect();
-struct TestingSetup {
- CCoinsViewDB *pcoinsdbview;
- boost::filesystem::path pathTemp;
- boost::thread_group threadGroup;
-
- TestingSetup() {
+TestingSetup::TestingSetup()
+{
fPrintToDebugLog = false; // don't want to write to debug.log file
SelectParams(CBaseChainParams::UNITTEST);
noui_connect();
#ifdef ENABLE_WALLET
bitdb.MakeMock();
#endif
+ ClearDatadirCache();
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
boost::filesystem::create_directories(pathTemp);
mapArgs["-datadir"] = pathTemp.string();
@@ -53,27 +52,28 @@ struct TestingSetup {
for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck);
RegisterNodeSignals(GetNodeSignals());
- }
- ~TestingSetup()
- {
+}
+
+TestingSetup::~TestingSetup()
+{
+ UnregisterNodeSignals(GetNodeSignals());
threadGroup.interrupt_all();
threadGroup.join_all();
- UnregisterNodeSignals(GetNodeSignals());
#ifdef ENABLE_WALLET
+ UnregisterValidationInterface(pwalletMain);
delete pwalletMain;
pwalletMain = NULL;
#endif
+ UnloadBlockIndex();
delete pcoinsTip;
delete pcoinsdbview;
delete pblocktree;
#ifdef ENABLE_WALLET
bitdb.Flush(true);
+ bitdb.Reset();
#endif
boost::filesystem::remove_all(pathTemp);
- }
-};
-
-BOOST_GLOBAL_FIXTURE(TestingSetup);
+}
void Shutdown(void* parg)
{
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
new file mode 100644
index 000000000..c1448dcde
--- /dev/null
+++ b/src/test/test_bitcoin.h
@@ -0,0 +1,18 @@
+#ifndef BITCOIN_TEST_TEST_BITCOIN_H
+#define BITCOIN_TEST_TEST_BITCOIN_H
+
+#include "txdb.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
+
+struct TestingSetup {
+ CCoinsViewDB *pcoinsdbview;
+ boost::filesystem::path pathTemp;
+ boost::thread_group threadGroup;
+
+ TestingSetup();
+ ~TestingSetup();
+};
+
+#endif
diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp
index 289cc8c90..25c8fab33 100644
--- a/src/test/wallet_tests.cpp
+++ b/src/test/wallet_tests.cpp
@@ -9,6 +9,8 @@
#include <utility>
#include <vector>
+#include "test/test_bitcoin.h"
+
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
@@ -23,7 +25,7 @@ using namespace std;
typedef set<pair<const CWalletTx*,unsigned int> > CoinSet;
-BOOST_AUTO_TEST_SUITE(wallet_tests)
+BOOST_FIXTURE_TEST_SUITE(wallet_tests, TestingSetup)
static CWallet wallet;
static vector<COutput> vCoins;
diff --git a/src/util.h b/src/util.h
index bbb0e8103..4d0cb7136 100644
--- a/src/util.h
+++ b/src/util.h
@@ -94,6 +94,7 @@ bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
bool TryCreateDirectory(const boost::filesystem::path& p);
boost::filesystem::path GetDefaultDataDir();
const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
+void ClearDatadirCache();
boost::filesystem::path GetConfigFile();
#ifndef WIN32
boost::filesystem::path GetPidFile();
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index b2daf036f..ddec57d9a 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -903,8 +903,8 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
int64_t now = GetTime();
std::string newFilename = strprintf("wallet.%d.bak", now);
- int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL,
- newFilename.c_str(), DB_AUTO_COMMIT);
+ int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL,
+ newFilename.c_str(), DB_AUTO_COMMIT);
if (result == 0)
LogPrintf("Renamed %s to %s\n", filename, newFilename);
else
@@ -923,7 +923,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
bool fSuccess = allOK;
- boost::scoped_ptr<Db> pdbCopy(new Db(&dbenv.dbenv, 0));
+ boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name