From b7f7fe7620a9641090a3953f141ad2fdc3897295 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sat, 3 Feb 2024 11:55:05 -0500 Subject: [PATCH] Implement lambdas in GetBeaconChainletRoot to improve readability Also make a few other improvements, such as verification that the previous beacon to the original activated beacon has a status of pending. --- src/gridcoin/beacon.cpp | 186 +++++++++++++++------------------------- 1 file changed, 71 insertions(+), 115 deletions(-) diff --git a/src/gridcoin/beacon.cpp b/src/gridcoin/beacon.cpp index e26ef16d3d..c7eb77127d 100644 --- a/src/gridcoin/beacon.cpp +++ b/src/gridcoin/beacon.cpp @@ -800,127 +800,100 @@ int BeaconRegistry::GetDBHeight() Beacon_ptr BeaconRegistry::GetBeaconChainletRoot(Beacon_ptr beacon, std::shared_ptr>> beacon_chain_out) { - Cpid cpid = beacon->m_cpid; - - // The chain head itself. - auto beacon_iter = m_beacon_db.find(beacon->m_hash); - - if (beacon_iter == m_beacon_db.end()) { - // Beacon chainlet chainhead cannot be found. This is fatal. - - error("%s: Beacon chainlet is corrupted at chainhead for cpid %s: timestamp = %s" PRId64 ", ctx_hash = %s," - "prev_beacon_ctx_hash = %s, status = %s: not found in the registry.", + const auto ChainletErrorHandle = [this](unsigned int i, Beacon_ptr beacon, std::string error_message) { + error("%s: Beacon chainlet is corrupted at link %u for cpid %s: timestamp = %s" PRId64 ", ctx_hash = %s," + "prev_beacon_ctx_hash = %s, status = %s: %s.", __func__, + i, beacon->m_cpid.ToString(), beacon->m_timestamp, beacon->m_hash.GetHex(), beacon->m_previous_hash.GetHex(), - beacon->StatusToString()); + beacon->StatusToString(), + error_message); - std::string str_error = strprintf("ERROR: %s: Beacon chainlet is corrupted at chainhead for cpid %s: timestamp = %s" - PRId64 ", ctx_hash = %s, prev_beacon_ctx_hash = %s, status = %s: not found " - "in the registry.", + std::string str_error = strprintf("ERROR: %s: Beacon chainlet is corrupted at link %u for cpid %s: timestamp = %s" + PRId64 ", ctx_hash = %s, prev_beacon_ctx_hash = %s, status = %s: %s.", __func__, + i, beacon->m_cpid.ToString(), beacon->m_timestamp, beacon->m_hash.GetHex(), beacon->m_previous_hash.GetHex(), - beacon->StatusToString()); + beacon->StatusToString(), + error_message); Reset(); uiInterface.ThreadSafeMessageBox(str_error, "Gridcoin", CClientUIInterface::MSG_ERROR); - throw std::runtime_error(std::string {"The beacon registry is corrupted and Gridcoin cannot continue. Please restart."}); - } - - // Given that we have had rare situations where somehow circularity has occurred in the beacon chainlet, which either - // results in the current hash and previous hash being the same, or even suspected previous hash of another entry pointing - // back to a beacon in a circular manner, this vector is used to detect the circularity. - std::vector encountered_hashes { beacon->m_hash }; + throw std::runtime_error(std::string {"The beacon registry is corrupted and will be rebuilt on the next start. " + "Please restart."}); + }; - if (beacon_chain_out != nullptr) { - LogPrint(BCLog::LogFlags::ACCRUAL, "INFO %s: chainlet head beacon for cpid %s: timestamp = %" PRId64 ", ctx_hash = %s," + const auto ChainletLinkLog = [&beacon_chain_out](unsigned int i, Beacon_ptr beacon) { + LogPrint(BCLog::LogFlags::ACCRUAL, "INFO %s: beacon chainlet link %u for cpid %s: timestamp = %" PRId64 ", ctx_hash = %s," " prev_beacon_ctx_hash = %s, status = %s.", __func__, + i, beacon->m_cpid.ToString(), beacon->m_timestamp, beacon->m_hash.GetHex(), beacon->m_previous_hash.GetHex(), beacon->StatusToString()); + if (beacon_chain_out == nullptr) { + return; + } + beacon_chain_out->push_back(std::make_pair(beacon->m_hash, beacon->m_timestamp)); + }; + + unsigned int i = 0; + + // Given that we have had rare situations where somehow circularity has occurred in the beacon chainlet, which either + // results in the current hash and previous hash being the same, or even suspected previous hash of another entry pointing + // back to a beacon in a circular manner, this vector is used to detect the circularity. + std::vector encountered_hashes; + + // The chain head itself. (This uses a scope to separate beacon_iter.) + { + auto beacon_iter = m_beacon_db.find(beacon->m_hash); + + if (beacon_iter == m_beacon_db.end()) { + // Beacon chainlet chainhead cannot be found. This is fatal. + ChainletErrorHandle(i, beacon, "not found in the registry"); + } + + // Make sure status is renewed or active. + if (beacon_iter->second->m_status != BeaconStatusForStorage::ACTIVE + && beacon_iter->second->m_status != BeaconStatusForStorage::RENEWAL) { + ChainletErrorHandle(i, beacon, "beacon status is not active or renewal"); + } + + encountered_hashes.push_back(beacon->m_hash); + + ChainletLinkLog(i, beacon); + + ++i; } // Walk back the entries in the historical beacon map linked by renewal prev tx hash until the first // beacon in the renewal chain is found (the original advertisement). The accrual starts no earlier // than here. - unsigned int i = 0; - while (beacon->Renewed()) { // Select previous beacon in chainlet auto beacon_iter = m_beacon_db.find(beacon->m_previous_hash); if (beacon_iter == m_beacon_db.end()) { - // Linked beacon in chainlet cannot be found. This is fatal. - - error("%s: Beacon chainlet is corrupted at %u links back for cpid %s: timestamp = %s" PRId64 ", ctx_hash = %s," - "prev_beacon_ctx_hash = %s, status = %s: prev_beacon not found in the registry.", - __func__, - i + 1, - beacon->m_cpid.ToString(), - beacon->m_timestamp, - beacon->m_hash.GetHex(), - beacon->m_previous_hash.GetHex(), - beacon->StatusToString()); - - std::string str_error = strprintf("ERROR: %s: Beacon chainlet is corrupted at %u links back for cpid %s: timestamp = %s" - PRId64 ", ctx_hash = %s, prev_beacon_ctx_hash = %s, status = %s: prev_beacon not found " - "in the registry.", - __func__, - i + 1, - beacon->m_cpid.ToString(), - beacon->m_timestamp, - beacon->m_hash.GetHex(), - beacon->m_previous_hash.GetHex(), - beacon->StatusToString()); - - Reset(); - - uiInterface.ThreadSafeMessageBox(str_error, "Gridcoin", CClientUIInterface::MSG_ERROR); - - throw std::runtime_error(std::string {"The beacon registry is corrupted and Gridcoin cannot continue. Please restart."}); + ChainletErrorHandle(i, beacon, "previous beacon not found in the registry"); } if (std::find(encountered_hashes.begin(), encountered_hashes.end(), beacon->m_previous_hash) != encountered_hashes.end()) { // If circularity is found this is an indication of corruption of beacon state and is fatal. // Produce an error message, reset the beacon registry, and require a restart of the node. - - error("%s: Circularity encountered in beacon ownership chain for beacon with CPID %s, starting at hash %s, " - "at %u linked entries back from the start, with offending hash %s.", - __func__, - cpid.ToString(), - beacon->m_hash.GetHex(), - i + 1, - beacon->m_previous_hash.GetHex()); - - std::string str_error = strprintf("ERROR: %s: Circularity encountered in beacon ownership chain for beacon with CPID %s, " - "starting at hash %s, at %u linked entries back from the start, with offending hash %s.\n" - "\n" - "The client cannot continue and the beacon history has been reset and will be rebuilt " - "on the next restart. Please restart Gridcoin.", - __func__, - cpid.ToString(), - beacon->m_hash.GetHex(), - i + 1, - beacon->m_previous_hash.GetHex()); - - Reset(); - - uiInterface.ThreadSafeMessageBox(str_error, "Gridcoin", CClientUIInterface::MSG_ERROR); - - throw std::runtime_error(std::string {"The beacon registry is corrupted and Gridcoin cannot continue. Please restart."}); + ChainletErrorHandle(i, beacon, "circularity encountered"); } // Reassign previous beacon to beacon. @@ -929,51 +902,34 @@ Beacon_ptr BeaconRegistry::GetBeaconChainletRoot(Beacon_ptr beacon, encountered_hashes.push_back(beacon->m_hash); if (beacon_chain_out != nullptr) { - LogPrint(BCLog::LogFlags::ACCRUAL, "INFO %s: beacon %u links back for cpid %s: timestamp = %" PRId64 ", ctx_hash = %s," - " prev_beacon_ctx_hash = %s, status = %s.", - __func__, - i + 1, - beacon->m_cpid.ToString(), - beacon->m_timestamp, - beacon->m_hash.GetHex(), - beacon->m_previous_hash.GetHex(), - beacon->StatusToString()); - - beacon_chain_out->push_back(std::make_pair(beacon->m_hash, beacon->m_timestamp)); + ChainletLinkLog(i, beacon); } ++i; } - // Check of initial advertised beacon's previous hash. - if (std::find(encountered_hashes.begin(), encountered_hashes.end(), beacon->m_previous_hash) != encountered_hashes.end()) { - // If circularity is found this is an indication of corruption of beacon state and is fatal. - // Produce an error message, reset the beacon registry, and require a restart of the node. + // Check of initial advertised beacon's previous hash. This should point to the pending beacon that was activated and not + // anywhere else. + { + // Select previous beacon in chainlet + auto beacon_iter = m_beacon_db.find(beacon->m_previous_hash); - error("%s: Circularity encountered in beacon ownership chain for beacon with CPID %s, starting at hash %s, " - "at %u linked entries back from the start, with offending hash %s.", - __func__, - cpid.ToString(), - beacon->m_hash.GetHex(), - i + 1, - beacon->m_previous_hash.GetHex()); - - std::string str_error = strprintf("ERROR: %s: Circularity encountered in beacon ownership chain for beacon with CPID %s, " - "starting at hash %s, at %u linked entries back from the start, with offending hash %s.\n" - "\n" - "The client cannot continue and the beacon history has been reset and will be rebuilt " - "on the next restart. Please restart Gridcoin.", - __func__, - cpid.ToString(), - beacon->m_hash.GetHex(), - i + 1, - beacon->m_previous_hash.GetHex()); + if (beacon_iter == m_beacon_db.end()) { + ChainletErrorHandle(i, beacon, "previous beacon not found in the registry"); + } - Reset(); + // Make sure status of previous beacon is pending. + if (beacon_iter->second->m_status != BeaconStatusForStorage::PENDING) { + ChainletErrorHandle(i, beacon, "previous beacon to the beacon marked active is not pending"); + } - uiInterface.ThreadSafeMessageBox(str_error, "Gridcoin", CClientUIInterface::MSG_ERROR); + if (std::find(encountered_hashes.begin(), encountered_hashes.end(), beacon->m_previous_hash) != encountered_hashes.end()) { + // If circularity is found this is an indication of corruption of beacon state and is fatal. + // Produce an error message, reset the beacon registry, and require a restart of the node. + ChainletErrorHandle(i, beacon, "circularity encountered"); + } - throw std::runtime_error(std::string {"The beacon registry is corrupted and Gridcoin cannot continue. Please restart."}); + // Note that we do not actually walk back to the pending beacon. The parameter beacon remains at the activated beacon. } return beacon;