Skip to content

Commit

Permalink
Implement lambdas in GetBeaconChainletRoot to improve readability
Browse files Browse the repository at this point in the history
Also make a few other improvements, such as verification that the
previous beacon to the original activated beacon has a status of
pending.
  • Loading branch information
jamescowens committed Feb 4, 2024
1 parent 4f09656 commit cb111dd
Showing 1 changed file with 71 additions and 115 deletions.
186 changes: 71 additions & 115 deletions src/gridcoin/beacon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,127 +800,100 @@ int BeaconRegistry::GetDBHeight()
Beacon_ptr BeaconRegistry::GetBeaconChainletRoot(Beacon_ptr beacon,
std::shared_ptr<std::vector<std::pair<uint256, int64_t>>> 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<uint256> 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<uint256> 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.
Expand All @@ -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;
Expand Down

0 comments on commit cb111dd

Please sign in to comment.