Skip to content

Commit

Permalink
Upgrade from per-tx database to per-txout
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa authored and random-zebra committed Aug 23, 2020
1 parent a55eb98 commit aab17b3
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/coins.h
Expand Up @@ -90,6 +90,7 @@ class Coin
}
};

//! Legacy class to deserialize pre-pertxout database entries without reindex.
class CCoins
{
public:
Expand Down
9 changes: 8 additions & 1 deletion src/init.cpp
Expand Up @@ -1563,8 +1563,15 @@ bool AppInit2()
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsTip = new CCoinsViewCache(pcoinscatcher);

if (fReindex)
if (fReindex) {
pblocktree->WriteReindexing(true);
} else {
// If necessary, upgrade from older database format.
if (!pcoinsdbview->Upgrade()) {
strLoadError = _("Error upgrading chainstate database");
break;
}
}

// End loop if shutdown was requested
if (ShutdownRequested()) break;
Expand Down
60 changes: 53 additions & 7 deletions src/txdb.cpp
Expand Up @@ -28,11 +28,11 @@ static const char DB_MONEY_SUPPLY = 'M';

namespace {

struct CoinsEntry
struct CoinEntry
{
COutPoint* outpoint;
char key;
CoinsEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}

template<typename Stream>
void Serialize(Stream &s) const {
Expand All @@ -58,12 +58,12 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get

bool CCoinsViewDB::GetCoins(const COutPoint& outpoint, Coin& coin) const
{
return db.Read(CoinsEntry(&outpoint), coin);
return db.Read(CoinEntry(&outpoint), coin);
}

bool CCoinsViewDB::HaveCoins(const COutPoint& outpoint) const
{
return db.Exists(CoinsEntry(&outpoint));
return db.Exists(CoinEntry(&outpoint));
}

uint256 CCoinsViewDB::GetBestBlock() const
Expand All @@ -81,7 +81,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
size_t changed = 0;
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
CoinsEntry entry(&it->first);
CoinEntry entry(&it->first);
if (it->second.coins.IsPruned())
batch.Erase(entry);
else
Expand Down Expand Up @@ -148,7 +148,7 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const
// Cache key of first record
// Cache key of first record
if (i->pcursor->Valid()) {
CoinsEntry entry(&i->keyTmp.second);
CoinEntry entry(&i->keyTmp.second);
i->pcursor->GetKey(entry);
i->keyTmp.first = entry.key;
} else {
Expand Down Expand Up @@ -185,7 +185,7 @@ bool CCoinsViewDBCursor::Valid() const
void CCoinsViewDBCursor::Next()
{
pcursor->Next();
CoinsEntry entry(&keyTmp.second);
CoinEntry entry(&keyTmp.second);
if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
} else {
Expand Down Expand Up @@ -478,3 +478,49 @@ bool CZerocoinDB::WipeAccChecksums()
LogPrintf("%s: AccChecksum database removed.\n", __func__);
return true;
}

/** Upgrade the database from older formats.
*
* Currently implemented:
* - from the per-tx utxo model (4.2.0) to per-txout (4.2.99)
*/
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;
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, old_coins.fCoinStake);
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;
}
2 changes: 2 additions & 0 deletions src/txdb.h
Expand Up @@ -80,6 +80,8 @@ class CCoinsViewDB : public CCoinsView
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;
};

Expand Down

0 comments on commit aab17b3

Please sign in to comment.