Skip to content

Commit aab17b3

Browse files
siparandom-zebra
authored andcommitted
Upgrade from per-tx database to per-txout
1 parent a55eb98 commit aab17b3

File tree

4 files changed

+64
-8
lines changed

4 files changed

+64
-8
lines changed

src/coins.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class Coin
9090
}
9191
};
9292

93+
//! Legacy class to deserialize pre-pertxout database entries without reindex.
9394
class CCoins
9495
{
9596
public:

src/init.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1563,8 +1563,15 @@ bool AppInit2()
15631563
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
15641564
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
15651565

1566-
if (fReindex)
1566+
if (fReindex) {
15671567
pblocktree->WriteReindexing(true);
1568+
} else {
1569+
// If necessary, upgrade from older database format.
1570+
if (!pcoinsdbview->Upgrade()) {
1571+
strLoadError = _("Error upgrading chainstate database");
1572+
break;
1573+
}
1574+
}
15681575

15691576
// End loop if shutdown was requested
15701577
if (ShutdownRequested()) break;

src/txdb.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ static const char DB_MONEY_SUPPLY = 'M';
2828

2929
namespace {
3030

31-
struct CoinsEntry
31+
struct CoinEntry
3232
{
3333
COutPoint* outpoint;
3434
char key;
35-
CoinsEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
35+
explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
3636

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

5959
bool CCoinsViewDB::GetCoins(const COutPoint& outpoint, Coin& coin) const
6060
{
61-
return db.Read(CoinsEntry(&outpoint), coin);
61+
return db.Read(CoinEntry(&outpoint), coin);
6262
}
6363

6464
bool CCoinsViewDB::HaveCoins(const COutPoint& outpoint) const
6565
{
66-
return db.Exists(CoinsEntry(&outpoint));
66+
return db.Exists(CoinEntry(&outpoint));
6767
}
6868

6969
uint256 CCoinsViewDB::GetBestBlock() const
@@ -81,7 +81,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
8181
size_t changed = 0;
8282
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
8383
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
84-
CoinsEntry entry(&it->first);
84+
CoinEntry entry(&it->first);
8585
if (it->second.coins.IsPruned())
8686
batch.Erase(entry);
8787
else
@@ -148,7 +148,7 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const
148148
// Cache key of first record
149149
// Cache key of first record
150150
if (i->pcursor->Valid()) {
151-
CoinsEntry entry(&i->keyTmp.second);
151+
CoinEntry entry(&i->keyTmp.second);
152152
i->pcursor->GetKey(entry);
153153
i->keyTmp.first = entry.key;
154154
} else {
@@ -185,7 +185,7 @@ bool CCoinsViewDBCursor::Valid() const
185185
void CCoinsViewDBCursor::Next()
186186
{
187187
pcursor->Next();
188-
CoinsEntry entry(&keyTmp.second);
188+
CoinEntry entry(&keyTmp.second);
189189
if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
190190
keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
191191
} else {
@@ -478,3 +478,49 @@ bool CZerocoinDB::WipeAccChecksums()
478478
LogPrintf("%s: AccChecksum database removed.\n", __func__);
479479
return true;
480480
}
481+
482+
/** Upgrade the database from older formats.
483+
*
484+
* Currently implemented:
485+
* - from the per-tx utxo model (4.2.0) to per-txout (4.2.99)
486+
*/
487+
bool CCoinsViewDB::Upgrade() {
488+
std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
489+
pcursor->Seek(std::make_pair(DB_COINS, uint256()));
490+
if (!pcursor->Valid()) {
491+
return true;
492+
}
493+
494+
LogPrintf("Upgrading database...\n");
495+
size_t batch_size = 1 << 24;
496+
CDBBatch batch;
497+
while (pcursor->Valid()) {
498+
boost::this_thread::interruption_point();
499+
std::pair<unsigned char, uint256> key;
500+
if (pcursor->GetKey(key) && key.first == DB_COINS) {
501+
CCoins old_coins;
502+
if (!pcursor->GetValue(old_coins)) {
503+
return error("%s: cannot parse CCoins record", __func__);
504+
}
505+
COutPoint outpoint(key.second, 0);
506+
for (size_t i = 0; i < old_coins.vout.size(); ++i) {
507+
if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
508+
Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase, old_coins.fCoinStake);
509+
outpoint.n = i;
510+
CoinEntry entry(&outpoint);
511+
batch.Write(entry, newcoin);
512+
}
513+
}
514+
batch.Erase(key);
515+
if (batch.SizeEstimate() > batch_size) {
516+
db.WriteBatch(batch);
517+
batch.Clear();
518+
}
519+
pcursor->Next();
520+
} else {
521+
break;
522+
}
523+
}
524+
db.WriteBatch(batch);
525+
return true;
526+
}

src/txdb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class CCoinsViewDB : public CCoinsView
8080
bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) override;
8181
CCoinsViewCursor* Cursor() const override;
8282

83+
//! Attempt to update from an older database format. Returns whether an error occurred.
84+
bool Upgrade();
8385
size_t EstimateSize() const override;
8486
};
8587

0 commit comments

Comments
 (0)