diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoinrpc.cpp | 2 | ||||
-rw-r--r-- | src/checkpoints.cpp | 75 | ||||
-rw-r--r-- | src/checkpoints.h | 2 | ||||
-rw-r--r-- | src/checkqueue.h | 4 | ||||
-rw-r--r-- | src/init.cpp | 80 | ||||
-rw-r--r-- | src/main.cpp | 57 | ||||
-rw-r--r-- | src/main.h | 37 | ||||
-rw-r--r-- | src/makefile.linux-mingw | 15 | ||||
-rw-r--r-- | src/makefile.mingw | 15 | ||||
-rw-r--r-- | src/makefile.osx | 7 | ||||
-rw-r--r-- | src/makefile.unix | 6 | ||||
-rw-r--r-- | src/noui.cpp | 4 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 8 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 90 | ||||
-rw-r--r-- | src/qt/bitcoingui.h | 5 | ||||
-rw-r--r-- | src/qt/bitcoinstrings.cpp | 1 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 6 | ||||
-rw-r--r-- | src/qt/clientmodel.h | 1 | ||||
-rw-r--r-- | src/qt/guiconstants.h | 2 | ||||
-rw-r--r-- | src/qt/locale/bitcoin_en.ts | 55 | ||||
-rw-r--r-- | src/rpcwallet.cpp | 1 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 62 | ||||
-rw-r--r-- | src/txdb.cpp | 6 | ||||
-rw-r--r-- | src/txdb.h | 6 | ||||
-rw-r--r-- | src/ui_interface.h | 2 | ||||
-rw-r--r-- | src/util.cpp | 80 | ||||
-rw-r--r-- | src/util.h | 28 | ||||
-rw-r--r-- | src/wallet.cpp | 21 |
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't generate coins</source> <translation>Don'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 <n> 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 <ip> (default: 127.0.0.1)</source> <translation>Send commands to node running on <ip> (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: '%s'</source> <translation>Cannot resolve -bind address: '%s'</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: '%s'</translation> </message> <message> - <location line="+42"/> + <location line="+43"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</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=<password> 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; |