From 02bced16615f072b1d9960e7e5027b6eb4f41384 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 4 Jan 2015 17:15:02 +0100 Subject: [PATCH 1/2] Bugfix: only track UTXO modification after lookup Otherwise, if CCoinsViewCache::ModifyCoins throws an exception in between setting hasModifier and constructing the CCoinsModifier, the cache ends up in an inconsistent state, resulting in an assert failure in the next modification. Bug discovered by Wladimir J. van der Laan. --- src/coins.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index bc430c9c7..4917de625 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -106,7 +106,6 @@ bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { assert(!hasModifier); - hasModifier = true; std::pair ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); if (ret.second) { if (!base->GetCoins(txid, ret.first->second.coins)) { @@ -247,7 +246,10 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const return tx.ComputePriority(dResult); } -CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {} +CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) { + assert(!cache.hasModifier); + cache.hasModifier = true; +} CCoinsModifier::~CCoinsModifier() { From e41345790f1041f5c5e5605d73a0af174769aa55 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 4 Jan 2015 19:11:44 +0100 Subject: [PATCH 2/2] Catch LevelDB errors during flush --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 2410230ef..6bc1cefed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1807,6 +1807,7 @@ enum FlushStateMode { bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { LOCK(cs_main); static int64_t nLastWrite = 0; + try { if ((mode == FLUSH_STATE_ALWAYS) || ((mode == FLUSH_STATE_PERIODIC || mode == FLUSH_STATE_IF_NEEDED) && pcoinsTip->GetCacheSize() > nCoinCacheSize) || (mode == FLUSH_STATE_PERIODIC && GetTimeMicros() > nLastWrite + DATABASE_WRITE_INTERVAL * 1000000)) { @@ -1846,6 +1847,9 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { } nLastWrite = GetTimeMicros(); } + } catch (const std::runtime_error& e) { + return state.Abort(std::string("System error while flushing: ") + e.what()); + } return true; }