|
|
|
@ -252,3 +252,48 @@ bool CBlockTreeDB::LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)
@@ -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; |
|
|
|
|
} |
|
|
|
|