@@ -1364,7 +1364,7 @@ bool CDeterministicMNManager::IsMigrationRequired() const
13641364 return false ; // No legacy format found
13651365}
13661366
1367- bool CDeterministicMNManager::MigrateLegacyDiffs ()
1367+ bool CDeterministicMNManager::MigrateLegacyDiffs (const CBlockIndex* const tip_index )
13681368{
13691369 // CRITICAL: This migration converts ALL stored CDeterministicMNListDiff entries
13701370 // from legacy database key (DB_LIST_DIFF_LEGACY) to new key (DB_LIST_DIFF) format
@@ -1373,77 +1373,122 @@ bool CDeterministicMNManager::MigrateLegacyDiffs()
13731373
13741374 LogPrintf (" CDeterministicMNManager::%s -- Starting migration to nVersion-first format\n " , __func__);
13751375
1376- std::vector<uint256 > keys_to_erase;
1376+ std::vector<const CBlockIndex* > keys_to_erase;
13771377
13781378 CDBBatch batch (m_evoDb.GetRawDB ());
13791379 std::unique_ptr<CDBIterator> pcursor{m_evoDb.GetRawDB ().NewIterator ()};
1380- auto start{std::make_tuple (DB_LIST_DIFF_LEGACY, uint256 ())};
1381- pcursor->Seek (start);
13821380
1383- while (pcursor->Valid ()) {
1384- decltype (start) k;
1385- if (!pcursor->GetKey (k) || std::get<0 >(k) != DB_LIST_DIFF_LEGACY) {
1381+ // Keep track of the list to get correct nVersion at the current height
1382+ CDeterministicMNList snapshot;
1383+
1384+ const auto start_height{Params ().GetConsensus ().DeploymentHeight (Consensus::DEPLOYMENT_DIP0003)};
1385+ for (auto current_height : irange::range (start_height, tip_index->nHeight + 1 )) {
1386+ auto current_index = tip_index->GetAncestor (current_height);
1387+ auto target_key{std::make_tuple (DB_LIST_DIFF_LEGACY, current_index->GetBlockHash ())};
1388+ pcursor->Seek (target_key);
1389+
1390+ decltype (target_key) key;
1391+ if (!pcursor->Valid () || !pcursor->GetKey (key) || std::get<0 >(key) != DB_LIST_DIFF_LEGACY) {
13861392 break ;
13871393 }
13881394
1395+ if (std::get<1 >(key) != current_index->GetBlockHash ()) {
1396+ throw std::ios_base::failure (" Invalid data, we must have legacy diffs for each height" );
1397+ }
1398+
13891399 // Use legacy-aware deserialization for DB_LIST_DIFF_LEGACY entries
13901400 CDataStream s (SER_DISK, CLIENT_VERSION);
1391- if (!m_evoDb.GetRawDB ().ReadDataStream (k , s)) {
1401+ if (!m_evoDb.GetRawDB ().ReadDataStream (key , s)) {
13921402 break ;
13931403 }
13941404
13951405 CDeterministicMNListDiff legacyDiff;
13961406 legacyDiff.UnserializeLegacyFormat (s); // Use legacy format deserializer
1407+ snapshot.ApplyDiff (current_index, legacyDiff);
13971408
13981409 CDeterministicMNListDiff convertedDiff;
1399- convertedDiff.nHeight = legacyDiff.nHeight ;
14001410 convertedDiff.addedMNs = legacyDiff.addedMNs ;
14011411 convertedDiff.removedMns = legacyDiff.removedMns ;
14021412
14031413 // The conversion is already done by UnserializeLegacyFormat()!
14041414 // CDeterministicMNStateDiffLegacy.ToNewFormat() was called during deserialization
14051415 // So legacyDiff.updatedMNs already contains properly converted CDeterministicMNStateDiff objects
14061416
1407- // Simply copy the already-converted state diffs
1408- for (const auto & [internalId, stateDiff] : legacyDiff.updatedMNs ) {
1417+ // Copy the already-converted state diffs but make sure pubKeyOperator, nVersion and fields are set properly
1418+ for (auto & [internalId, stateDiff] : legacyDiff.updatedMNs ) {
1419+ auto dmn = snapshot.GetMNByInternalId (internalId);
1420+ if (!dmn) {
1421+ // shouldn't happen
1422+ throw std::runtime_error (strprintf (" %s: can't find an updated masternode, id=%d" , __func__, internalId));
1423+ }
1424+ if (!(stateDiff.fields & CDeterministicMNStateDiff::Field_nVersion)) {
1425+ if ((stateDiff.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) ||
1426+ (stateDiff.fields & CDeterministicMNStateDiff::Field_netInfo)) {
1427+ stateDiff.fields |= CDeterministicMNStateDiff::Field_nVersion;
1428+ stateDiff.state .nVersion = dmn->pdmnState ->nVersion ;
1429+ }
1430+ if (stateDiff.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) {
1431+ stateDiff.state .pubKeyOperator .SetLegacy (stateDiff.state .nVersion == ProTxVersion::LegacyBLS);
1432+ }
1433+ }
14091434 convertedDiff.updatedMNs .emplace (internalId, stateDiff);
14101435 }
14111436
14121437 // Write the converted diff to new database key
1413- batch.Write (std::make_pair (DB_LIST_DIFF, std::get<1 >(k )), convertedDiff);
1414- keys_to_erase.push_back (std::get< 1 >(k) );
1438+ batch.Write (std::make_pair (DB_LIST_DIFF, std::get<1 >(key )), convertedDiff);
1439+ keys_to_erase.push_back (current_index );
14151440
14161441 if (batch.SizeEstimate () >= (1 << 24 )) {
1417- LogPrintf (" CDeterministicMNManager::%s -- Writing new diffs...\n " , __func__);
1442+ LogPrintf (" CDeterministicMNManager::%s -- Writing new diffs, height=%d ...\n " , __func__, current_height );
14181443 m_evoDb.GetRawDB ().WriteBatch (batch);
14191444 batch.Clear ();
14201445 }
1421-
1422- pcursor->Next ();
14231446 }
14241447 pcursor.reset ();
14251448
1426- LogPrintf (" CDeterministicMNManager::%s -- Writing new diffs...\n " , __func__);
1449+ LogPrintf (" CDeterministicMNManager::%s -- Writing new diffs, height=%d ...\n " , __func__, tip_index-> nHeight );
14271450 m_evoDb.GetRawDB ().WriteBatch (batch);
14281451 batch.Clear ();
1452+ LogPrintf (" CDeterministicMNManager::%s -- Wrote %d new diffs\n " , __func__, keys_to_erase.size ());
14291453
1430- LogPrintf (" CDeterministicMNManager::%s -- Erasing %d legacy database entries after successful migration\n " ,
1431- __func__, keys_to_erase.size ());
1432-
1433- // Delete all legacy format entries
1434- for (const auto & blockHash : keys_to_erase) {
1435- batch.Erase (std::make_pair (DB_LIST_DIFF_LEGACY, blockHash));
1454+ // Delete all found legacy format entries
1455+ for (const auto & index : keys_to_erase) {
1456+ batch.Erase (std::make_pair (DB_LIST_DIFF_LEGACY, index->GetBlockHash ()));
14361457
14371458 if (batch.SizeEstimate () >= (1 << 24 )) {
1438- LogPrintf (" CDeterministicMNManager::%s -- Erasing legacy diffs...\n " , __func__);
1459+ LogPrintf (" CDeterministicMNManager::%s -- Erasing found legacy diffs, height=%d...\n " , __func__,
1460+ index->nHeight );
14391461 m_evoDb.GetRawDB ().WriteBatch (batch);
14401462 batch.Clear ();
14411463 }
14421464 }
14431465
1444- LogPrintf (" CDeterministicMNManager::%s -- Erasing legacy diffs...\n " , __func__);
1466+ LogPrintf (" CDeterministicMNManager::%s -- Erasing found legacy diffs, height=%d...\n " , __func__, tip_index->nHeight );
1467+ m_evoDb.GetRawDB ().WriteBatch (batch);
1468+ batch.Clear ();
1469+ LogPrintf (" CDeterministicMNManager::%s -- Erased %d found legacy diffs\n " , __func__, keys_to_erase.size ());
1470+
1471+ // Delete all dangling legacy format entries
1472+ std::unique_ptr<CDBIterator> pcursor_dangling{m_evoDb.GetRawDB ().NewIterator ()};
1473+ auto start{std::make_tuple (DB_LIST_DIFF_LEGACY, uint256 ())};
1474+ pcursor_dangling->Seek (start);
1475+ int count{0 };
1476+ while (pcursor_dangling->Valid ()) {
1477+ decltype (start) key;
1478+ if (!pcursor_dangling->GetKey (key) || std::get<0 >(key) != DB_LIST_DIFF_LEGACY) {
1479+ break ;
1480+ }
1481+ LogPrintf (" CDeterministicMNManager::%s -- Erasing dangling legacy diff, hash=%s\n " , __func__,
1482+ std::get<1 >(key).ToString ());
1483+ batch.Erase (std::make_pair (DB_LIST_DIFF_LEGACY, std::get<1 >(key)));
1484+ pcursor_dangling->Next ();
1485+ ++count;
1486+ }
1487+ pcursor_dangling.reset ();
1488+
14451489 m_evoDb.GetRawDB ().WriteBatch (batch);
14461490 batch.Clear ();
1491+ LogPrintf (" CDeterministicMNManager::%s -- Erased %d dangling legacy diffs\n " , __func__, count);
14471492
14481493 LogPrintf (" CDeterministicMNManager::%s -- Compacting database...\n " , __func__);
14491494 m_evoDb.GetRawDB ().CompactFull ();
0 commit comments