@@ -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,75 +1373,111 @@ 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+ // This happens because Seek() stops at equal or larger key but we only want equal one
1397+ continue ;
1398+ }
1399+
13891400 // Use legacy-aware deserialization for DB_LIST_DIFF_LEGACY entries
13901401 CDataStream s (SER_DISK, CLIENT_VERSION);
1391- if (!m_evoDb.GetRawDB ().ReadDataStream (k , s)) {
1402+ if (!m_evoDb.GetRawDB ().ReadDataStream (key , s)) {
13921403 break ;
13931404 }
13941405
13951406 CDeterministicMNListDiff legacyDiff;
13961407 legacyDiff.UnserializeLegacyFormat (s); // Use legacy format deserializer
1408+ snapshot.ApplyDiff (current_index, legacyDiff);
13971409
13981410 CDeterministicMNListDiff convertedDiff;
1399- convertedDiff.nHeight = legacyDiff.nHeight ;
14001411 convertedDiff.addedMNs = legacyDiff.addedMNs ;
14011412 convertedDiff.removedMns = legacyDiff.removedMns ;
14021413
14031414 // The conversion is already done by UnserializeLegacyFormat()!
14041415 // CDeterministicMNStateDiffLegacy.ToNewFormat() was called during deserialization
14051416 // So legacyDiff.updatedMNs already contains properly converted CDeterministicMNStateDiff objects
14061417
1407- // Simply copy the already-converted state diffs
1408- for (const auto & [internalId, stateDiff] : legacyDiff.updatedMNs ) {
1418+ // Copy the already-converted state diffs but make sure pubKeyOperator, nVersion and fields are set properly
1419+ for (auto & [internalId, stateDiff] : legacyDiff.updatedMNs ) {
1420+ auto dmn = snapshot.GetMNByInternalId (internalId);
1421+ if (!dmn) {
1422+ // shouldn't happen
1423+ throw std::runtime_error (strprintf (" %s: can't find an updated masternode, id=%d" , __func__, internalId));
1424+ }
1425+ if (!(stateDiff.fields & CDeterministicMNStateDiff::Field_nVersion)) {
1426+ if ((stateDiff.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) ||
1427+ (stateDiff.fields & CDeterministicMNStateDiff::Field_netInfo)) {
1428+ stateDiff.fields |= CDeterministicMNStateDiff::Field_nVersion;
1429+ stateDiff.state .nVersion = dmn->pdmnState ->nVersion ;
1430+ }
1431+ if (stateDiff.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) {
1432+ stateDiff.state .pubKeyOperator .SetLegacy (stateDiff.state .nVersion == ProTxVersion::LegacyBLS);
1433+ }
1434+ }
14091435 convertedDiff.updatedMNs .emplace (internalId, stateDiff);
14101436 }
14111437
14121438 // 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) );
1439+ batch.Write (std::make_pair (DB_LIST_DIFF, std::get<1 >(key )), convertedDiff);
1440+ keys_to_erase.push_back (current_index );
14151441
14161442 if (batch.SizeEstimate () >= (1 << 24 )) {
1417- LogPrintf (" CDeterministicMNManager::%s -- Writing new diffs...\n " , __func__);
1443+ LogPrintf (" CDeterministicMNManager::%s -- Writing new diffs, height=%d ...\n " , __func__, current_height );
14181444 m_evoDb.GetRawDB ().WriteBatch (batch);
14191445 batch.Clear ();
14201446 }
1421-
1422- pcursor->Next ();
14231447 }
1424- 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 ();
14291452
14301453 LogPrintf (" CDeterministicMNManager::%s -- Erasing %d legacy database entries after successful migration\n " ,
14311454 __func__, keys_to_erase.size ());
14321455
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 ));
1456+ // Delete all found legacy format entries
1457+ for (const auto & index : keys_to_erase) {
1458+ batch.Erase (std::make_pair (DB_LIST_DIFF_LEGACY, index-> GetBlockHash () ));
14361459
14371460 if (batch.SizeEstimate () >= (1 << 24 )) {
1438- LogPrintf (" CDeterministicMNManager::%s -- Erasing legacy diffs...\n " , __func__);
1461+ LogPrintf (" CDeterministicMNManager::%s -- Erasing legacy diffs, height=%d ...\n " , __func__, index-> nHeight );
14391462 m_evoDb.GetRawDB ().WriteBatch (batch);
14401463 batch.Clear ();
14411464 }
14421465 }
14431466
1444- LogPrintf (" CDeterministicMNManager::%s -- Erasing legacy diffs...\n " , __func__);
1467+ // Delete all dangling legacy format entries
1468+ auto start{std::make_tuple (DB_LIST_DIFF_LEGACY, uint256 ())};
1469+ pcursor->Seek (start);
1470+ while (pcursor->Valid ()) {
1471+ decltype (start) key;
1472+ if (!pcursor->GetKey (key) || std::get<0 >(key) != DB_LIST_DIFF_LEGACY) {
1473+ break ;
1474+ }
1475+ batch.Erase (std::make_pair (DB_LIST_DIFF_LEGACY, std::get<1 >(key)));
1476+ pcursor->Next ();
1477+ }
1478+ pcursor.reset ();
1479+
1480+ LogPrintf (" CDeterministicMNManager::%s -- Erasing legacy diffs, height=%d...\n " , __func__, tip_index->nHeight );
14451481 m_evoDb.GetRawDB ().WriteBatch (batch);
14461482 batch.Clear ();
14471483
0 commit comments