aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitcoinrpc.cpp2
-rw-r--r--src/checkpoints.cpp75
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/checkqueue.h4
-rw-r--r--src/init.cpp80
-rw-r--r--src/main.cpp57
-rw-r--r--src/main.h37
-rw-r--r--src/makefile.linux-mingw15
-rw-r--r--src/makefile.mingw15
-rw-r--r--src/makefile.osx7
-rw-r--r--src/makefile.unix6
-rw-r--r--src/noui.cpp4
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/qt/bitcoingui.cpp90
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/qt/bitcoinstrings.cpp1
-rw-r--r--src/qt/clientmodel.cpp6
-rw-r--r--src/qt/clientmodel.h1
-rw-r--r--src/qt/guiconstants.h2
-rw-r--r--src/qt/locale/bitcoin_en.ts55
-rw-r--r--src/rpcwallet.cpp1
-rw-r--r--src/test/util_tests.cpp62
-rw-r--r--src/txdb.cpp6
-rw-r--r--src/txdb.h6
-rw-r--r--src/ui_interface.h2
-rw-r--r--src/util.cpp80
-rw-r--r--src/util.h28
-rw-r--r--src/wallet.cpp21
28 files changed, 502 insertions, 176 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 7751e4c8b6..230a248422 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -246,7 +246,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getblocktemplate", &getblocktemplate, true, false },
{ "submitblock", &submitblock, false, false },
{ "listsinceblock", &listsinceblock, false, false },
- { "dumpprivkey", &dumpprivkey, false, false },
+ { "dumpprivkey", &dumpprivkey, true, false },
{ "importprivkey", &importprivkey, false, false },
{ "listunspent", &listunspent, false, false },
{ "getrawtransaction", &getrawtransaction, false, false },
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index e2c420edd7..9b11f0b351 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -14,13 +14,25 @@ namespace Checkpoints
{
typedef std::map<int, uint256> MapCheckpoints;
- //
+ // How many times we expect transactions after the last checkpoint to
+ // be slower. This number is conservative. On multi-core CPUs with
+ // parallel signature checking enabled, this number is way too high.
+ // We prefer a progressbar that's faster at the end than the other
+ // way around, though.
+ static const double fSigcheckVerificationFactor = 15.0;
+
+ struct CCheckpointData {
+ const MapCheckpoints *mapCheckpoints;
+ int64 nTimeLastCheckpoint;
+ int64 nTransactionsLastCheckpoint;
+ double fTransactionsPerDay;
+ };
+
// What makes a good checkpoint block?
// + Is surrounded by blocks with reasonable timestamps
// (no blocks before with a timestamp after, none after with
// timestamp before)
// + Contains no strange transactions
- //
static MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
@@ -33,30 +45,81 @@ namespace Checkpoints
(210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
(216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
;
+ static const CCheckpointData data = {
+ &mapCheckpoints,
+ 1357902690, // * UNIX timestamp of last checkpoint block
+ 11011160, // * total number of transactions between genesis and last checkpoint
+ // (the tx=... number in the SetBestChain debug.log lines)
+ 50000.0 // * estimated number of transactions per day after checkpoint
+ };
- static MapCheckpoints mapCheckpointsTestnet =
+ static MapCheckpoints mapCheckpointsTestnet =
boost::assign::map_list_of
( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
;
+ static const CCheckpointData dataTestnet = {
+ &mapCheckpointsTestnet,
+ 1338180505,
+ 16341,
+ 300
+ };
+
+ const CCheckpointData &Checkpoints() {
+ if (fTestNet)
+ return dataTestnet;
+ else
+ return data;
+ }
bool CheckBlock(int nHeight, const uint256& hash)
{
if (!GetBoolArg("-checkpoints", true))
return true;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return true;
return hash == i->second;
}
+ // Guess how far we are in the verification process at the given block index
+ double GuessVerificationProgress(CBlockIndex *pindex) {
+ if (pindex==NULL)
+ return 0.0;
+
+ int64 nNow = time(NULL);
+
+ double fWorkBefore = 0.0; // Amount of work done before pindex
+ double fWorkAfter = 0.0; // Amount of work left after pindex (estimated)
+ // Work is defined as: 1.0 per transaction before the last checkoint, and
+ // fSigcheckVerificationFactor per transaction after.
+
+ const CCheckpointData &data = Checkpoints();
+
+ if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) {
+ double nCheapBefore = pindex->nChainTx;
+ double nCheapAfter = data.nTransactionsLastCheckpoint - pindex->nChainTx;
+ double nExpensiveAfter = (nNow - data.nTimeLastCheckpoint)/86400.0*data.fTransactionsPerDay;
+ fWorkBefore = nCheapBefore;
+ fWorkAfter = nCheapAfter + nExpensiveAfter*fSigcheckVerificationFactor;
+ } else {
+ double nCheapBefore = data.nTransactionsLastCheckpoint;
+ double nExpensiveBefore = pindex->nChainTx - data.nTransactionsLastCheckpoint;
+ double nExpensiveAfter = (nNow - pindex->nTime)/86400.0*data.fTransactionsPerDay;
+ fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor;
+ fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor;
+ }
+
+ return fWorkBefore / (fWorkBefore + fWorkAfter);
+ }
+
int GetTotalBlocksEstimate()
{
if (!GetBoolArg("-checkpoints", true))
return 0;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
return checkpoints.rbegin()->first;
}
@@ -66,7 +129,7 @@ namespace Checkpoints
if (!GetBoolArg("-checkpoints", true))
return NULL;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 70e936564c..dcfb44e10f 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -22,6 +22,8 @@ namespace Checkpoints
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
+
+ double GuessVerificationProgress(CBlockIndex *pindex);
}
#endif
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 36141dd74b..12dde36fe7 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -163,6 +163,10 @@ public:
condQuit.wait(lock);
}
+ ~CCheckQueue() {
+ Quit();
+ }
+
friend class CCheckQueueControl<T>;
};
diff --git a/src/init.cpp b/src/init.cpp
index 15a46946fa..64f91a349f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -82,6 +82,7 @@ void Shutdown(void* parg)
if (fFirstThread)
{
fShutdown = true;
+ fRequestShutdown = true;
nTransactionsUpdated++;
bitdb.Flush(false);
{
@@ -299,6 +300,7 @@ std::string HelpMessage()
" -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
+ " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
" -upgradewallet " + _("Upgrade wallet to latest format") + "\n" +
" -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
@@ -791,27 +793,69 @@ bool AppInit2()
nTotalCache -= nCoinDBCache;
nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes
- uiInterface.InitMessage(_("Loading block index..."));
+ bool fLoaded = false;
+ while (!fLoaded) {
+ bool fReset = fReindex;
+ std::string strLoadError;
- nStart = GetTimeMillis();
- pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
- pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
-
- if (fReindex)
- pblocktree->WriteReindexing(true);
-
- if (!LoadBlockIndex())
- return InitError(_("Error loading block database"));
+ uiInterface.InitMessage(_("Loading block index..."));
- // Initialize the block index (no-op if non-empty database was already loaded)
- if (!InitBlockIndex())
- return InitError(_("Error initializing block database"));
-
- uiInterface.InitMessage(_("Verifying block database integrity..."));
+ nStart = GetTimeMillis();
+ do {
+ try {
+ UnloadBlockIndex();
+ delete pcoinsTip;
+ delete pcoinsdbview;
+ delete pblocktree;
+
+ pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
+ pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+
+ if (fReindex)
+ pblocktree->WriteReindexing(true);
+
+ if (!LoadBlockIndex()) {
+ strLoadError = _("Error loading block database");
+ break;
+ }
+
+ // Initialize the block index (no-op if non-empty database was already loaded)
+ if (!InitBlockIndex()) {
+ strLoadError = _("Error initializing block database");
+ break;
+ }
+
+ uiInterface.InitMessage(_("Verifying database..."));
+ if (!VerifyDB()) {
+ strLoadError = _("Corrupted block database detected");
+ break;
+ }
+ } catch(std::exception &e) {
+ strLoadError = _("Error opening block database");
+ break;
+ }
- if (!VerifyDB())
- return InitError(_("Corrupted block database detected. Please restart the client with -reindex."));
+ fLoaded = true;
+ } while(false);
+
+ if (!fLoaded) {
+ // first suggest a reindex
+ if (!fReset) {
+ bool fRet = uiInterface.ThreadSafeMessageBox(
+ strLoadError + ".\n" + _("Do you want to rebuild the block database now?"),
+ "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
+ if (fRet) {
+ fReindex = true;
+ fRequestShutdown = false;
+ } else {
+ return false;
+ }
+ } else {
+ return InitError(strLoadError);
+ }
+ }
+ }
if (mapArgs.count("-txindex") && fTxIndex != GetBoolArg("-txindex", false))
return InitError(_("You need to rebuild the databases using -reindex to change -txindex"));
diff --git a/src/main.cpp b/src/main.cpp
index 8c115c26f9..794913d282 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -162,9 +162,9 @@ void static ResendWalletTransactions()
// CCoinsView implementations
//
-bool CCoinsView::GetCoins(uint256 txid, CCoins &coins) { return false; }
-bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; }
-bool CCoinsView::HaveCoins(uint256 txid) { return false; }
+bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; }
+bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
+bool CCoinsView::HaveCoins(const uint256 &txid) { return false; }
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
@@ -172,9 +172,9 @@ bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
-bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
-bool CCoinsViewBacked::SetCoins(uint256 txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
-bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); }
+bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); }
+bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
+bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); }
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
@@ -183,7 +183,7 @@ bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stat
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
-bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) {
+bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) {
if (cacheCoins.count(txid)) {
coins = cacheCoins[txid];
return true;
@@ -195,29 +195,30 @@ bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) {
return false;
}
-std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(uint256 txid) {
- std::map<uint256,CCoins>::iterator it = cacheCoins.find(txid);
- if (it != cacheCoins.end())
+std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
+ std::map<uint256,CCoins>::iterator it = cacheCoins.lower_bound(txid);
+ if (it != cacheCoins.end() && it->first == txid)
return it;
CCoins tmp;
if (!base->GetCoins(txid,tmp))
- return it;
- std::pair<std::map<uint256,CCoins>::iterator,bool> ret = cacheCoins.insert(std::make_pair(txid, tmp));
- return ret.first;
+ return cacheCoins.end();
+ std::map<uint256,CCoins>::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
+ tmp.swap(ret->second);
+ return ret;
}
-CCoins &CCoinsViewCache::GetCoins(uint256 txid) {
+CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
std::map<uint256,CCoins>::iterator it = FetchCoins(txid);
assert(it != cacheCoins.end());
return it->second;
}
-bool CCoinsViewCache::SetCoins(uint256 txid, const CCoins &coins) {
+bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
cacheCoins[txid] = coins;
return true;
}
-bool CCoinsViewCache::HaveCoins(uint256 txid) {
+bool CCoinsViewCache::HaveCoins(const uint256 &txid) {
return FetchCoins(txid) != cacheCoins.end();
}
@@ -254,7 +255,7 @@ unsigned int CCoinsViewCache::GetCacheSize() {
It does not check for spendings by memory pool transactions. */
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
-bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) {
+bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
if (base->GetCoins(txid, coins))
return true;
if (mempool.exists(txid)) {
@@ -265,7 +266,7 @@ bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) {
return false;
}
-bool CCoinsViewMemPool::HaveCoins(uint256 txid) {
+bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) {
return mempool.exists(txid) || base->HaveCoins(txid);
}
@@ -1533,7 +1534,7 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
}
}
-void static FlushBlockFile()
+void static FlushBlockFile(bool fFinalize = false)
{
LOCK(cs_LastBlockFile);
@@ -1541,12 +1542,16 @@ void static FlushBlockFile()
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
+ if (fFinalize)
+ TruncateFile(fileOld, infoLastBlockFile.nSize);
FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
+ if (fFinalize)
+ TruncateFile(fileOld, infoLastBlockFile.nUndoSize);
FileCommit(fileOld);
fclose(fileOld);
}
@@ -1965,7 +1970,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
} else {
while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
- FlushBlockFile();
+ FlushBlockFile(true);
nLastBlockFile++;
infoLastBlockFile.SetNull();
pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine
@@ -2653,6 +2658,18 @@ bool VerifyDB() {
return true;
}
+void UnloadBlockIndex()
+{
+ mapBlockIndex.clear();
+ setBlockIndexValid.clear();
+ pindexGenesisBlock = NULL;
+ nBestHeight = 0;
+ bnBestChainWork = 0;
+ bnBestInvalidWork = 0;
+ hashBestChain = 0;
+ pindexBest = NULL;
+}
+
bool LoadBlockIndex()
{
if (fTestNet)
diff --git a/src/main.h b/src/main.h
index d69aef94ea..c1af0c3706 100644
--- a/src/main.h
+++ b/src/main.h
@@ -139,6 +139,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
bool InitBlockIndex();
/** Load the block tree and coins database from disk */
bool LoadBlockIndex();
+/** Unload database information */
+void UnloadBlockIndex();
/** Verify consistency of the block and coin databases */
bool VerifyDB();
/** Print the loaded block tree */
@@ -907,6 +909,15 @@ public:
void Cleanup() {
while (vout.size() > 0 && vout.back().IsNull())
vout.pop_back();
+ if (vout.empty())
+ std::vector<CTxOut>().swap(vout);
+ }
+
+ void swap(CCoins &to) {
+ std::swap(to.fCoinBase, fCoinBase);
+ to.vout.swap(vout);
+ std::swap(to.nHeight, nHeight);
+ std::swap(to.nVersion, nVersion);
}
// equality test
@@ -2107,14 +2118,14 @@ class CCoinsView
{
public:
// Retrieve the CCoins (unspent transaction outputs) for a given txid
- virtual bool GetCoins(uint256 txid, CCoins &coins);
+ virtual bool GetCoins(const uint256 &txid, CCoins &coins);
// Modify the CCoins for a given txid
- virtual bool SetCoins(uint256 txid, const CCoins &coins);
+ virtual bool SetCoins(const uint256 &txid, const CCoins &coins);
// Just check whether we have data for a given txid.
// This may (but cannot always) return true for fully spent transactions
- virtual bool HaveCoins(uint256 txid);
+ virtual bool HaveCoins(const uint256 &txid);
// Retrieve the block index whose state this CCoinsView currently represents
virtual CBlockIndex *GetBestBlock();
@@ -2140,9 +2151,9 @@ protected:
public:
CCoinsViewBacked(CCoinsView &viewIn);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool SetCoins(const uint256 &txid, const CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn);
@@ -2161,9 +2172,9 @@ public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
// Standard CCoinsView methods
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool SetCoins(const uint256 &txid, const CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
@@ -2171,7 +2182,7 @@ public:
// Return a modifiable reference to a CCoins. Check HaveCoins first.
// Many methods explicitly require a CCoinsViewCache because of this method, to reduce
// copying.
- CCoins &GetCoins(uint256 txid);
+ CCoins &GetCoins(const uint256 &txid);
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
@@ -2181,7 +2192,7 @@ public:
unsigned int GetCacheSize();
private:
- std::map<uint256,CCoins>::iterator FetchCoins(uint256 txid);
+ std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid);
};
/** CCoinsView that brings transactions from a memorypool into view.
@@ -2193,8 +2204,8 @@ protected:
public:
CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
};
/** Global variable that points to the active CCoinsView (protected by cs_main) */
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index c3cbe90bcd..7509e2798e 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -4,6 +4,9 @@
DEPSDIR:=/usr/i586-mingw32msvc
+CC := i586-mingw32msvc-gcc
+CXX := i586-mingw32msvc-g++
+
USE_UPNP:=0
USE_IPV6:=1
@@ -58,6 +61,7 @@ LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l w
HEADERS = $(wildcard *.h)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -95,8 +99,7 @@ all: bitcoind.exe
DEFS += -I"$(CURDIR)/leveldb/include"
DEFS += -I"$(CURDIR)/leveldb/helpers"
leveldb/libleveldb.a:
- @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="$(INCLUDEPATHS)" LDFLAGS="$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd ..
-obj/leveldb.o: leveldb/libleveldb.a
+ @echo "Building LevelDB ..." && cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd ..
obj/build.h: FORCE
/bin/sh ../share/genbuild.sh obj/build.h
@@ -104,18 +107,18 @@ version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp $(HEADERS)
- i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $<
+ $(CXX) -c $(CFLAGS) -o $@ $<
bitcoind.exe: $(OBJS:obj/%=obj/%)
- i586-mingw32msvc-g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp $(HEADERS)
- i586-mingw32msvc-g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
+ $(CXX) -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- i586-mingw32msvc-g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework-mt-s $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework-mt-s $(LIBS)
clean:
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 366d32bd86..2e092ff686 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -15,6 +15,8 @@
# 'make clean' assumes it is running inside a MSYS shell, and uses 'rm'
# to remove files.
+CXX ?= g++
+
USE_UPNP:=-
USE_IPV6:=1
@@ -67,6 +69,7 @@ LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell
HEADERS = $(wildcard *.h)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -112,23 +115,21 @@ DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- cd leveldb && $(MAKE) OPT="$(DEBUGFLAGS)" TARGET_OS=NATIVE_WINDOWS libleveldb.a libmemenv.a && cd ..
-
-obj/leveldb.o: leveldb/libleveldb.a
+ cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" TARGET_OS=NATIVE_WINDOWS libleveldb.a libmemenv.a && cd ..
obj/%.o: %.cpp $(HEADERS)
- g++ -c $(CFLAGS) -o $@ $<
+ $(CXX) -c $(CFLAGS) -o $@ $<
bitcoind.exe: $(OBJS:obj/%=obj/%)
- g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp $(HEADERS)
- g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
+ $(CXX) -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework$(BOOST_SUFFIX) $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework$(BOOST_SUFFIX) $(LIBS)
clean:
rm -f bitcoind.exe test_bitcoin.exe
diff --git a/src/makefile.osx b/src/makefile.osx
index 8b7c559fa1..cdee781257 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -62,7 +62,7 @@ ifdef RELEASE
# the same way.
CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3
else
-CFLAGS = -g
+DEBUGFLAGS = -g
endif
# ppc doesn't work because we don't support big-endian
@@ -70,6 +70,7 @@ CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -130,8 +131,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
-obj/leveldb.o: leveldb/libleveldb.a
+ @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" libleveldb.a libmemenv.a && cd ..
# auto-generated dependencies:
-include obj/*.P
@@ -171,5 +171,6 @@ clean:
-rm -f obj/*.P
-rm -f obj-test/*.P
-rm -f obj/build.h
+ -cd leveldb && $(MAKE) clean || true
FORCE:
diff --git a/src/makefile.unix b/src/makefile.unix
index b52a0f8aea..ece2f59cf5 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -101,6 +101,7 @@ xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-para
xLDFLAGS=$(LDHARDENING) $(LDFLAGS)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -142,12 +143,12 @@ test check: test_bitcoin FORCE
#
# LevelDB support
#
+MAKEOVERRIDES =
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
-obj/leveldb.o: leveldb/libleveldb.a
+ @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(xCXXFLAGS)" libleveldb.a libmemenv.a && cd ..
# auto-generated dependencies:
-include obj/*.P
@@ -187,5 +188,6 @@ clean:
-rm -f obj/*.P
-rm -f obj-test/*.P
-rm -f obj/build.h
+ -cd leveldb && $(MAKE) clean || true
FORCE:
diff --git a/src/noui.cpp b/src/noui.cpp
index 302d059291..c0e00c4715 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -9,7 +9,7 @@
#include <string>
-static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
+static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
std::string strCaption;
// Check for usage of predefined caption
@@ -29,7 +29,7 @@ static int noui_ThreadSafeMessageBox(const std::string& message, const std::stri
printf("%s: %s\n", strCaption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
- return 4;
+ return false;
}
static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/)
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 1b5ef28ba9..75e9b965b1 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -35,23 +35,27 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets)
static BitcoinGUI *guiref;
static QSplashScreen *splashref;
-static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
+static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
// Message from network thread
if(guiref)
{
bool modal = (style & CClientUIInterface::MODAL);
+ bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button
QMetaObject::invokeMethod(guiref, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
- Q_ARG(unsigned int, style));
+ Q_ARG(unsigned int, style),
+ Q_ARG(bool*, &ret));
+ return ret;
}
else
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
+ return false;
}
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 9cd22ed297..f1bf5f5880 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -67,7 +67,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
aboutQtAction(0),
trayIcon(0),
notificator(0),
- rpcConsole(0)
+ rpcConsole(0),
+ prevBlocks(0)
{
resize(850, 550);
setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet"));
@@ -527,52 +528,17 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
importText = tr("Reindexing blocks on disk...");
}
- if(count < nTotalBlocks)
- {
- int nRemainingBlocks = nTotalBlocks - count;
- float nPercentageDone = count / (nTotalBlocks * 0.01f);
-
- progressBarLabel->setText(importText);
- progressBarLabel->setVisible(true);
- progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
- progressBar->setMaximum(nTotalBlocks);
- progressBar->setValue(count);
- progressBar->setVisible(true);
-
- tooltip = tr("Processed %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
- }
- else
- {
- progressBarLabel->setVisible(false);
-
- progressBar->setVisible(false);
- tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
- }
-
QDateTime lastBlockDate = clientModel->getLastBlockDate();
- int secs = lastBlockDate.secsTo(QDateTime::currentDateTime());
- QString text;
+ QDateTime currentDate = QDateTime::currentDateTime();
+ int secs = lastBlockDate.secsTo(currentDate);
- // Represent time from last generated block in human readable text
- if(secs <= 0)
- {
- // Fully up to date. Leave text empty.
- }
- else if(secs < 60)
- {
- text = tr("%n second(s) ago","",secs);
- }
- else if(secs < 60*60)
- {
- text = tr("%n minute(s) ago","",secs/60);
- }
- else if(secs < 24*60*60)
+ if(count < nTotalBlocks)
{
- text = tr("%n hour(s) ago","",secs/(60*60));
+ tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks);
}
else
{
- text = tr("%n day(s) ago","",secs/(60*60*24));
+ tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
}
// Set icon state: spinning if catching up, tick otherwise
@@ -582,20 +548,46 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
overviewPage->showOutOfSyncWarning(false);
+
+ progressBarLabel->setVisible(false);
+ progressBar->setVisible(false);
}
else
{
+ // Represent time from last generated block in human readable text
+ QString timeBehindText;
+ if(secs < 48*60*60)
+ {
+ timeBehindText = tr("%n hour(s)","",secs/(60*60));
+ }
+ else if(secs < 14*24*60*60)
+ {
+ timeBehindText = tr("%n day(s)","",secs/(24*60*60));
+ }
+ else
+ {
+ timeBehindText = tr("%n week(s)","",secs/(7*24*60*60));
+ }
+
+ progressBarLabel->setText(importText);
+ progressBarLabel->setVisible(true);
+ progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
+ progressBar->setMaximum(1000000000);
+ progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5);
+ progressBar->setVisible(true);
+
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
labelBlocksIcon->setMovie(syncIconMovie);
- syncIconMovie->start();
+ if(count != prevBlocks)
+ syncIconMovie->jumpToNextFrame();
+ prevBlocks = count;
overviewPage->showOutOfSyncWarning(true);
- }
- if(!text.isEmpty())
- {
tooltip += QString("<br>");
- tooltip += tr("Last received block was generated %1.").arg(text);
+ tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
+ tooltip += QString("<br>");
+ tooltip += tr("Transactions after this will not yet be visible.");
}
// Don't word-wrap this (fixed-width) tooltip
@@ -606,7 +598,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
progressBar->setToolTip(tooltip);
}
-void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style)
+void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
{
QString strTitle = tr("Bitcoin") + " - ";
// Default to information icon
@@ -646,7 +638,9 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
buttons = QMessageBox::Ok;
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons);
- mBox.exec();
+ int r = mBox.exec();
+ if (ret != NULL)
+ *ret = r == QMessageBox::Ok;
}
else
notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index b7afdb1c8c..8ce0335bcd 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -98,6 +98,8 @@ private:
RPCConsole *rpcConsole;
QMovie *syncIconMovie;
+ /** Keep track of previous number of blocks, to detect progress */
+ int prevBlocks;
/** Create the main UI actions. */
void createActions();
@@ -126,8 +128,9 @@ public slots:
@param[in] message the displayed text
@param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes)
@see CClientUIInterface::MessageBoxFlags
+ @param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only)
*/
- void message(const QString &title, const QString &message, unsigned int style);
+ void message(const QString &title, const QString &message, unsigned int style, bool *ret = NULL);
/** 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/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 5bd1517091..2c3d859c82 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -100,6 +100,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses,
QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 084ad12a56..858fbe241f 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -6,6 +6,7 @@
#include "alert.h"
#include "main.h"
+#include "checkpoints.h"
#include "ui_interface.h"
#include <QDateTime>
@@ -54,6 +55,11 @@ QDateTime ClientModel::getLastBlockDate() const
return QDateTime::fromTime_t(1231006505); // Genesis block's time
}
+double ClientModel::getVerificationProgress() const
+{
+ return Checkpoints::GuessVerificationProgress(pindexBest);
+}
+
void ClientModel::updateTimer()
{
// Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 1afccb7859..a3fe92048c 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -34,6 +34,7 @@ public:
int getNumBlocks() const;
int getNumBlocksAtStartup();
+ double getVerificationProgress() const;
QDateTime getLastBlockDate() const;
//! Return true if client connected to testnet
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 405ba396b7..92417834ec 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -2,7 +2,7 @@
#define GUICONSTANTS_H
/* Milliseconds between model updates */
-static const int MODEL_UPDATE_DELAY = 500;
+static const int MODEL_UPDATE_DELAY = 250;
/* AskPassphraseDialog -- Maximum passphrase length */
static const int MAX_PASSPHRASE_SIZE = 1024;
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 18249b1669..39062d0a2c 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -2179,7 +2179,7 @@ Address: %4
<translation>Bitcoin version</translation>
</message>
<message>
- <location line="+95"/>
+ <location line="+96"/>
<source>Usage:</source>
<translation>Usage:</translation>
</message>
@@ -2219,12 +2219,12 @@ Address: %4
<translation>Generate coins</translation>
</message>
<message>
- <location line="-26"/>
+ <location line="-27"/>
<source>Don&apos;t generate coins</source>
<translation>Don&apos;t generate coins</translation>
</message>
<message>
- <location line="+73"/>
+ <location line="+74"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
@@ -2244,12 +2244,12 @@ Address: %4
<translation>Maintain at most &lt;n&gt; connections to peers (default: 125)</translation>
</message>
<message>
- <location line="-46"/>
+ <location line="-47"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
- <location line="+77"/>
+ <location line="+78"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
@@ -2259,7 +2259,7 @@ Address: %4
<translation>Threshold for disconnecting misbehaving peers (default: 100)</translation>
</message>
<message>
- <location line="-129"/>
+ <location line="-130"/>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
<translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation>
</message>
@@ -2279,7 +2279,7 @@ Address: %4
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+75"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
@@ -2289,7 +2289,7 @@ Address: %4
<translation>Use the test network</translation>
</message>
<message>
- <location line="-105"/>
+ <location line="-106"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
<translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
</message>
@@ -2410,6 +2410,11 @@ If the file does not exist, create it with owner-readable-only file permissions.
</message>
<message>
<location line="+3"/>
+ <source>Error initializing block database</source>
+ <translation>Error initializing block database</translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Error loading block database</source>
<translation>Error loading block database</translation>
</message>
@@ -2659,22 +2664,22 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-65"/>
+ <location line="-66"/>
<source>Allow JSON-RPC connections from specified IP address</source>
<translation>Allow JSON-RPC connections from specified IP address</translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+75"/>
<source>Send commands to node running on &lt;ip&gt; (default: 127.0.0.1)</source>
<translation>Send commands to node running on &lt;ip&gt; (default: 127.0.0.1)</translation>
</message>
<message>
- <location line="-117"/>
+ <location line="-118"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+139"/>
+ <location line="+140"/>
<source>Upgrade wallet to latest format</source>
<translation>Upgrade wallet to latest format</translation>
</message>
@@ -2704,12 +2709,12 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Server private key (default: server.pem)</translation>
</message>
<message>
- <location line="-147"/>
+ <location line="-148"/>
<source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source>
<translation>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</translation>
</message>
<message>
- <location line="+159"/>
+ <location line="+160"/>
<source>This help message</source>
<translation>This help message</translation>
</message>
@@ -2719,7 +2724,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation>
</message>
<message>
- <location line="-83"/>
+ <location line="-84"/>
<source>Connect through socks proxy</source>
<translation>Connect through socks proxy</translation>
</message>
@@ -2729,7 +2734,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+54"/>
+ <location line="+55"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
@@ -2779,7 +2784,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Unknown -socks proxy version requested: %i</translation>
</message>
<message>
- <location line="-88"/>
+ <location line="-89"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -2789,7 +2794,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Cannot resolve -externalip address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+42"/>
+ <location line="+43"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</translation>
</message>
@@ -2814,7 +2819,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-56"/>
+ <location line="-57"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
@@ -2824,7 +2829,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Unable to bind to %s on this computer. Bitcoin is probably already running.</translation>
</message>
<message>
- <location line="+65"/>
+ <location line="+66"/>
<source>Find peers using internet relay chat (default: 0)</source>
<translation>Find peers using internet relay chat (default: 0)</translation>
</message>
@@ -2839,7 +2844,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-51"/>
+ <location line="-52"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -2854,17 +2859,17 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+61"/>
+ <location line="+62"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-55"/>
+ <location line="-56"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+78"/>
+ <location line="+79"/>
<source>To use the %s option</source>
<translation>To use the %s option</translation>
</message>
@@ -2874,7 +2879,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Error</translation>
</message>
<message>
- <location line="-28"/>
+ <location line="-29"/>
<source>You must set rpcpassword=&lt;password&gt; in the configuration file:
%s
If the file does not exist, create it with owner-readable-only file permissions.</source>
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 90a68f560a..21eb2fd1aa 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -75,6 +75,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight));
+ obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index f56969cba6..1b0ccad511 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -261,4 +261,66 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_CHECK(!IsHex("0x0000"));
}
+BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
+{
+ // Expected results for the determinstic seed.
+ const uint32_t exp_vals[11] = { 91632771U,1889679809U,3842137544U,3256031132U,
+ 1761911779U, 489223532U,2692793790U,2737472863U,
+ 2796262275U,1309899767U,840571781U};
+ // Expected 0s in rand()%(idx+2) for the determinstic seed.
+ const int exp_count[9] = {5013,3346,2415,1972,1644,1386,1176,1096,1009};
+ int i;
+ int count=0;
+
+ seed_insecure_rand();
+
+ //Does the non-determistic rand give us results that look too like the determinstic one?
+ for (i=0;i<10;i++)
+ {
+ int match = 0;
+ uint32_t rval = insecure_rand();
+ for (int j=0;j<11;j++)match |= rval==exp_vals[j];
+ count += match;
+ }
+ // sum(binomial(10,i)*(11/(2^32))^i*(1-(11/(2^32)))^(10-i),i,0,4) ~= 1-1/2^134.73
+ // So _very_ unlikely to throw a false failure here.
+ BOOST_CHECK(count<=4);
+
+ for (int mod=2;mod<11;mod++)
+ {
+ int mask = 1;
+ // Really rough binomal confidence approximation.
+ int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);
+ //mask is 2^ceil(log2(mod))-1
+ while(mask<mod-1)mask=(mask<<1)+1;
+
+ count = 0;
+ //How often does it get a zero from the uniform range [0,mod)?
+ for (i=0;i<10000;i++)
+ {
+ uint32_t rval;
+ do{
+ rval=insecure_rand()&mask;
+ }while(rval>=(uint32_t)mod);
+ count += rval==0;
+ }
+ BOOST_CHECK(count<=10000/mod+err);
+ BOOST_CHECK(count>=10000/mod-err);
+ }
+
+ seed_insecure_rand(true);
+
+ for (i=0;i<11;i++)
+ {
+ BOOST_CHECK_EQUAL(insecure_rand(),exp_vals[i]);
+ }
+
+ for (int mod=2;mod<11;mod++)
+ {
+ count = 0;
+ for (i=0;i<10000;i++) count += insecure_rand()%mod==0;
+ BOOST_CHECK_EQUAL(count,exp_count[mod-2]);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 8c01158254..ae7aceb7f1 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -22,17 +22,17 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}
-bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
+bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
return db.Read(make_pair('c', txid), coins);
}
-bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
+bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
CLevelDBBatch batch;
BatchWriteCoins(batch, txid, coins);
return db.WriteBatch(batch);
}
-bool CCoinsViewDB::HaveCoins(uint256 txid) {
+bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
return db.Exists(make_pair('c', txid));
}
diff --git a/src/txdb.h b/src/txdb.h
index eb8f574e46..f59fc5da86 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -16,9 +16,9 @@ protected:
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool SetCoins(const uint256 &txid, const CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 703e15f095..f7dbe20894 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -68,7 +68,7 @@ public:
};
/** Show message box. */
- boost::signals2::signal<void (const std::string& message, const std::string& caption, unsigned int style)> ThreadSafeMessageBox;
+ boost::signals2::signal<bool (const std::string& message, const std::string& caption, unsigned int style), boost::signals2::last_value<bool> > ThreadSafeMessageBox;
/** Ask the user whether they want to pay a fee or not. */
boost::signals2::signal<bool (int64 nFeeRequired), boost::signals2::last_value<bool> > ThreadSafeAskFee;
diff --git a/src/util.cpp b/src/util.cpp
index d8f05cb9fd..fc3e846a6b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -3,6 +3,15 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef WIN32
+// for posix_fallocate
+#ifdef __linux__
+#define _POSIX_C_SOURCE 200112L
+#endif
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
#include "util.h"
#include "sync.h"
#include "version.h"
@@ -1152,9 +1161,46 @@ int GetFilesize(FILE* file)
return nFilesize;
}
+bool TruncateFile(FILE *file, unsigned int length) {
+#if defined(WIN32)
+ return _chsize(_fileno(file), length) == 0;
+#else
+ return ftruncate(fileno(file), length) == 0;
+#endif
+}
+
// this function tries to make a particular range of a file allocated (corresponding to disk space)
// it is advisory, and the range specified in the arguments will never contain live data
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
+#if defined(WIN32)
+ // Windows-specific version
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
+ LARGE_INTEGER nFileSize;
+ int64 nEndPos = (int64)offset + length;
+ nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
+ nFileSize.u.HighPart = nEndPos >> 32;
+ SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
+ SetEndOfFile(hFile);
+#elif defined(MAC_OSX)
+ // OSX specific version
+ fstore_t fst;
+ fst.fst_flags = F_ALLOCATECONTIG;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = (off_t)offset + length;
+ fst.fst_bytesalloc = 0;
+ if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
+ fst.fst_flags = F_ALLOCATEALL;
+ fcntl(fileno(file), F_PREALLOCATE, &fst);
+ }
+ ftruncate(fileno(file), fst.fst_length);
+#elif defined(__linux__)
+ // Version using posix_fallocate
+ off_t nEndPos = (off_t)offset + length;
+ posix_fallocate(fileno(file), 0, nEndPos);
+#else
+ // Fallback version
+ // TODO: just write one byte per block
static const char buf[65536] = {};
fseek(file, offset, SEEK_SET);
while (length > 0) {
@@ -1164,6 +1210,7 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
length -= now;
}
+#endif
}
void ShrinkDebugFile()
@@ -1218,9 +1265,14 @@ void SetMockTime(int64 nMockTimeIn)
static int64 nTimeOffset = 0;
+int64 GetTimeOffset()
+{
+ return nTimeOffset;
+}
+
int64 GetAdjustedTime()
{
- return GetTime() + nTimeOffset;
+ return GetTime() + GetTimeOffset();
}
void AddTimeData(const CNetAddr& ip, int64 nTime)
@@ -1276,12 +1328,26 @@ void AddTimeData(const CNetAddr& ip, int64 nTime)
}
}
-
-
-
-
-
-
+uint32_t insecure_rand_Rz = 11;
+uint32_t insecure_rand_Rw = 11;
+void seed_insecure_rand(bool fDeterministic)
+{
+ //The seed values have some unlikely fixed points which we avoid.
+ if(fDeterministic)
+ {
+ insecure_rand_Rz = insecure_rand_Rw = 11;
+ } else {
+ uint32_t tmp;
+ do{
+ RAND_bytes((unsigned char*)&tmp,4);
+ }while(tmp==0 || tmp==0x9068ffffU);
+ insecure_rand_Rz=tmp;
+ do{
+ RAND_bytes((unsigned char*)&tmp,4);
+ }while(tmp==0 || tmp==0x464fffffU);
+ insecure_rand_Rw=tmp;
+ }
+}
string FormatVersion(int nVersion)
{
diff --git a/src/util.h b/src/util.h
index 97911d7493..d129d13692 100644
--- a/src/util.h
+++ b/src/util.h
@@ -193,6 +193,7 @@ bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
void FileCommit(FILE *fileout);
int GetFilesize(FILE* file);
+bool TruncateFile(FILE *file, unsigned int length);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
boost::filesystem::path GetDefaultDataDir();
@@ -212,6 +213,7 @@ uint256 GetRandHash();
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
+int64 GetTimeOffset();
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
void AddTimeData(const CNetAddr& ip, int64 nTime);
@@ -403,13 +405,27 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
*/
bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+/**
+ * MWC RNG of George Marsaglia
+ * This is intended to be fast. It has a period of 2^59.3, though the
+ * least significant 16 bits only have a period of about 2^30.1.
+ *
+ * @return random value
+ */
+extern uint32_t insecure_rand_Rz;
+extern uint32_t insecure_rand_Rw;
+static inline uint32_t insecure_rand(void)
+{
+ insecure_rand_Rz=36969*(insecure_rand_Rz&65535)+(insecure_rand_Rz>>16);
+ insecure_rand_Rw=18000*(insecure_rand_Rw&65535)+(insecure_rand_Rw>>16);
+ return (insecure_rand_Rw<<16)+insecure_rand_Rz;
+}
-
-
-
-
-
-
+/**
+ * Seed insecure_rand using the random pool.
+ * @param Deterministic Use a determinstic seed
+ */
+void seed_insecure_rand(bool fDeterministic=false);
/** Median filter over a stream of values.
* Returns the median of the last N numbers
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 2317ac31ac..eecb7d2d22 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -8,6 +8,7 @@
#include "crypter.h"
#include "ui_interface.h"
#include "base58.h"
+#include <boost/algorithm/string/replace.hpp>
using namespace std;
@@ -476,6 +477,16 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+
+ // notify an external script when a wallet transaction comes in or is updated
+ std::string strCmd = GetArg("-walletnotify", "");
+
+ if ( !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
}
return true;
}
@@ -973,6 +984,8 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
+ seed_insecure_rand();
+
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
@@ -982,7 +995,13 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
{
for (unsigned int i = 0; i < vValue.size(); i++)
{
- if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
+ //The solver here uses a randomized algorithm,
+ //the randomness serves no real security purpose but is just
+ //needed to prevent degenerate behavior and it is important
+ //that the rng fast. We do not use a constant random sequence,
+ //because there may be some privacy improvement by making
+ //the selection random.
+ if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;