aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/coins.h1
-rw-r--r--src/init.cpp6
-rw-r--r--src/txdb.cpp45
-rw-r--r--src/txdb.h2
4 files changed, 54 insertions, 0 deletions
diff --git a/src/coins.h b/src/coins.h
index 7f4dffc7ec..5ffb810aab 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -82,6 +82,7 @@ public:
}
};
+//! Legacy class to deserialize pre-pertxout database entries without reindex.
class CCoins
{
public:
diff --git a/src/init.cpp b/src/init.cpp
index 4420b6f658..8ce3847955 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1455,6 +1455,12 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
CleanupBlockRevFiles();
+ } else {
+ // If necessary, upgrade from older database format.
+ if (!pcoinsdbview->Upgrade()) {
+ strLoadError = _("Error upgrading chainstate database");
+ break;
+ }
}
if (!LoadBlockIndex(chainparams)) {
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 19c9002506..f4a6fad85b 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -252,3 +252,48 @@ bool CBlockTreeDB::LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)
return true;
}
+
+/** Upgrade the database from older formats.
+ *
+ * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
+ */
+bool CCoinsViewDB::Upgrade() {
+ std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
+ pcursor->Seek(std::make_pair(DB_COINS, uint256()));
+ if (!pcursor->Valid()) {
+ return true;
+ }
+
+ LogPrintf("Upgrading database...\n");
+ size_t batch_size = 1 << 24;
+ CDBBatch batch(db);
+ while (pcursor->Valid()) {
+ boost::this_thread::interruption_point();
+ std::pair<unsigned char, uint256> key;
+ if (pcursor->GetKey(key) && key.first == DB_COINS) {
+ CCoins old_coins;
+ if (!pcursor->GetValue(old_coins)) {
+ return error("%s: cannot parse CCoins record", __func__);
+ }
+ COutPoint outpoint(key.second, 0);
+ for (size_t i = 0; i < old_coins.vout.size(); ++i) {
+ if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
+ Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
+ outpoint.n = i;
+ CoinEntry entry(&outpoint);
+ batch.Write(entry, newcoin);
+ }
+ }
+ batch.Erase(key);
+ if (batch.SizeEstimate() > batch_size) {
+ db.WriteBatch(batch);
+ batch.Clear();
+ }
+ pcursor->Next();
+ } else {
+ break;
+ }
+ }
+ db.WriteBatch(batch);
+ return true;
+}
diff --git a/src/txdb.h b/src/txdb.h
index 189094737e..51dc355bba 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -77,6 +77,8 @@ public:
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
CCoinsViewCursor *Cursor() const override;
+ //! Attempt to update from an older database format. Returns whether an error occurred.
+ bool Upgrade();
size_t EstimateSize() const override;
};