Skip to content

Commit

Permalink
Merge pull request #2758 from jamescowens/enhance_checkpoint_fail_act…
Browse files Browse the repository at this point in the history
…ions

gui, util: Enhance verify checkpoints fail handling; use RegistryBookmarks for DB passivation
  • Loading branch information
jamescowens authored Apr 8, 2024
2 parents 7847923 + ddf33f6 commit 1c31aa3
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 137 deletions.
15 changes: 0 additions & 15 deletions src/gridcoin/beacon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,21 +1391,6 @@ BeaconRegistry::BeaconDB &BeaconRegistry::GetBeaconDB()
return m_beacon_db;
}

// This is static and called by the scheduler.
void BeaconRegistry::RunDBPassivation()
{
TRY_LOCK(cs_main, locked_main);

if (!locked_main)
{
return;
}

BeaconRegistry& beacons = GetBeaconRegistry();

beacons.PassivateDB();
}

template<> const std::string BeaconRegistry::BeaconDB::KeyType()
{
return std::string("beacon");
Expand Down
7 changes: 1 addition & 6 deletions src/gridcoin/beacon.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ class BeaconRegistry : public IContractHandler
//!
//! \return The number of elements passivated.
//!
uint64_t PassivateDB();
uint64_t PassivateDB() override;

//!
//! \brief This function walks the linked beacon entries back (using the m_previous_hash member) from a provided
Expand All @@ -795,11 +795,6 @@ class BeaconRegistry : public IContractHandler
//!
bool SetNeedsIsContractCorrection(bool flag);

//!
//! \brief A static function that is called by the scheduler to run the beacon database passivation.
//!
static void RunDBPassivation();

//!
//! \brief Specializes the template RegistryDB for the ScraperEntry class
//!
Expand Down
15 changes: 15 additions & 0 deletions src/gridcoin/contract/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef GRIDCOIN_CONTRACT_HANDLER_H
#define GRIDCOIN_CONTRACT_HANDLER_H

#include <cstdint>
#include <string>

class CBlockIndex;
Expand Down Expand Up @@ -153,6 +154,20 @@ struct IContractHandler
//! \param height
//!
virtual void SetDBHeight(int& height);

//!
//! \brief Passivates the elements in the underlying db, which means remove from memory elements in the
//! historical map that are not referenced by any of the in memory maps. The backing store of
//! the element removed from memory is retained and will be transparently restored if find()
//! is called on the hash key for the element.
//!
//! \return The number of elements passivated.
//!
virtual uint64_t PassivateDB()
{
// The default method here does nothing.
return uint64_t {0};
};
};

} // namespace GRC
Expand Down
78 changes: 52 additions & 26 deletions src/gridcoin/gridcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extern bool fExplorer;
extern unsigned int nScraperSleep;
extern unsigned int nActiveBeforeSB;
extern bool fScraperActive;
extern bool fQtActive;

void Scraper(bool bSingleShot = false);
void ScraperSubscriber();
Expand All @@ -40,17 +41,29 @@ namespace {
//!
void ShowChainCorruptedMessage()
{
uiInterface.ThreadSafeMessageBox(
_("WARNING: Blockchain data may be corrupted.\n\n"
"Gridcoin detected bad index entries. This may occur because of an "
"unexpected exit, a power failure, or a late software upgrade.\n\n"
"Please exit Gridcoin, open the data directory, and delete:\n"
" - the blk****.dat files\n"
" - the txleveldb folder\n\n"
"Your wallet will re-download the blockchain. Your balance may "
"appear incorrect until the synchronization finishes.\n" ),
"Gridcoin",
CClientUIInterface::BTN_OK | CClientUIInterface::MODAL);
fResetBlockchainRequest = true;

if (fQtActive) {
uiInterface.ThreadSafeMessageBox(
_("ERROR: Checkpoint mismatch: Blockchain data may be corrupted.\n\n"
"Gridcoin detected bad index entries. This may occur because of a "
"late software upgrade, unexpected exit, or a power failure. "
"Your blockchain data is being reset and your wallet will resync "
"from genesis when you restart. Your balance may appear incorrect "
"until the synchronization finishes."),
"Gridcoin",
CClientUIInterface::BTN_OK | CClientUIInterface::MODAL);
} else {
uiInterface.ThreadSafeMessageBox(
_("ERROR: Checkpoint mismatch: Blockchain data may be corrupted.\n\n"
"Gridcoin detected bad index entries. This may occur because of a "
"late software upgrade, unexpected exit, or a power failure. "
"Please run gridcoinresearchd with the -resetblockchaindata "
"parameter. Your wallet will re-download the blockchain. Your "
"balance may appear incorrect until the synchronization finishes." ),
"Gridcoin",
CClientUIInterface::BTN_OK | CClientUIInterface::MODAL);
}
}

//!
Expand Down Expand Up @@ -361,20 +374,23 @@ void InitializeExplorerFeatures()
//! whether the index contains invalid state caused by an unclean shutdown.
//! This condition was originally detected by an assertion in a routine for
//! stake modifier checksum verification. Because Gridcoin removed modifier
//! checksums and checkpoints, we reinstate that assertion here as a formal
//! inspection.
//! checksums, we reinstate that assertion here as a formal inspection done
//! at initialization before the VerifyCheckpoints.
//!
//! This function checks that no block index entries contain a null pointer
//! to a previous block. The symptom may indicate a deeper problem that can
//! be resolved by tuning disk synchronization in LevelDB. Until then, this
//! heuristic has proven itself to be effective for identifying a corrupted
//! database.
//! database. This type of error has not been seen in the wild in several
//! years as of Gridcoin 5.4.7.0, but is retained for thoroughness.
//!
void CheckBlockIndexJob()
bool CheckBlockIndex()
{
LogPrintf("Gridcoin: checking block index...");
uiInterface.InitMessage(_("Checking block index..."));

bool corrupted = false;
// Block index integrity status
bool status = true;

if (pindexGenesisBlock) {
LOCK(cs_main);
Expand All @@ -383,18 +399,20 @@ void CheckBlockIndexJob()
const CBlockIndex* const pindex = index_pair.second;

if (!pindex || !(pindex->pprev || pindex == pindexGenesisBlock)) {
corrupted = true;
status = false;
break;
}
}
}

if (!corrupted) {
if (status) {
LogPrintf("Gridcoin: block index is clean");
return;
return status;
}

ShowChainCorruptedMessage();

return status;
}

//!
Expand Down Expand Up @@ -466,11 +484,8 @@ void ScheduleRegistriesPassivation(CScheduler& scheduler)
{
// Run registry database passivation every 5 minutes. This is a very thin call most of the time.
// Please see the PassivateDB function and passivate_db.
// TODO: Turn into a loop using extension of RegistryBookmarks
scheduler.scheduleEvery(BeaconRegistry::RunDBPassivation, std::chrono::minutes{5});
scheduler.scheduleEvery(ScraperRegistry::RunDBPassivation, std::chrono::minutes{5});
scheduler.scheduleEvery(ProtocolRegistry::RunDBPassivation, std::chrono::minutes{5});
scheduler.scheduleEvery(Whitelist::RunDBPassivation, std::chrono::minutes{5});

scheduler.scheduleEvery(RunDBPassivation, std::chrono::minutes{5});
}
} // Anonymous namespace

Expand All @@ -490,6 +505,9 @@ bool GRC::Initialize(ThreadHandlerPtr threads, CBlockIndex* pindexBest)
{
LogPrintf("Gridcoin: initializing...");

if (!CheckBlockIndex()) {
return false;
}
if (!VerifyCheckpoints(pindexBest)) {
return false;
}
Expand Down Expand Up @@ -518,8 +536,6 @@ void GRC::CloseResearcherRegistryFile()

void GRC::ScheduleBackgroundJobs(CScheduler& scheduler)
{
scheduler.schedule(CheckBlockIndexJob, std::chrono::system_clock::now());

// Primitive, but this is what the scraper does in the scraper housekeeping
// loop. It checks to see if the logs need to be archived by default every
// 5 mins. Note that passing false to the archive function means that if we
Expand Down Expand Up @@ -589,3 +605,13 @@ skip:;
return true;
}

void GRC::RunDBPassivation()
{
LOCK(cs_main);

for (const auto& contract_type : RegistryBookmarks::CONTRACT_TYPES_WITH_REG_DB) {
Registry& registry = RegistryBookmarks::GetRegistryWithDB(contract_type);

registry.PassivateDB();
}
}
6 changes: 6 additions & 0 deletions src/gridcoin/gridcoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ void ScheduleBackgroundJobs(CScheduler& scheduler);
//! \return \c true if no errors occurred.
//!
bool CleanConfig();

//!
//! \brief Function to allow cycling through DB passivation for all contract types backed
//! with registry db.
//!
void RunDBPassivation();
} // namespace GRC

#endif // GRIDCOIN_GRIDCOIN_H
15 changes: 0 additions & 15 deletions src/gridcoin/project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,21 +541,6 @@ Whitelist::ProjectEntryDB &Whitelist::GetProjectDB()
return m_project_db;
}

// This is static and called by the scheduler.
void Whitelist::RunDBPassivation()
{
TRY_LOCK(cs_main, locked_main);

if (!locked_main)
{
return;
}

Whitelist& project_entries = GetWhitelist();

project_entries.PassivateDB();
}

template<> const std::string Whitelist::ProjectEntryDB::KeyType()
{
return std::string("project");
Expand Down
9 changes: 2 additions & 7 deletions src/gridcoin/project.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,19 +603,14 @@ class Whitelist : public IContractHandler
void ResetInMemoryOnly();

//!
//! \brief Passivates the elements in the scraper db, which means remove from memory elements in the
//! \brief Passivates the elements in the project db, which means remove from memory elements in the
//! historical map that are not referenced by m_projects. The backing store of the element removed
//! from memory is retained and will be transparently restored if find() is called on the hash key
//! for the element.
//!
//! \return The number of elements passivated.
//!
uint64_t PassivateDB();

//!
//! \brief A static function that is called by the scheduler to run the project entry database passivation.
//!
static void RunDBPassivation();
uint64_t PassivateDB() override;

//!
//! \brief Specializes the template RegistryDB for the ScraperEntry class. Note that std::set<ProjectEntry> is not
Expand Down
15 changes: 0 additions & 15 deletions src/gridcoin/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,21 +528,6 @@ ProtocolRegistry::ProtocolEntryDB &ProtocolRegistry::GetProtocolEntryDB()
return m_protocol_db;
}

// This is static and called by the scheduler.
void ProtocolRegistry::RunDBPassivation()
{
TRY_LOCK(cs_main, locked_main);

if (!locked_main)
{
return;
}

ProtocolRegistry& protocol_entries = GetProtocolRegistry();

protocol_entries.PassivateDB();
}

template<> const std::string ProtocolRegistry::ProtocolEntryDB::KeyType()
{
return std::string("protocol");
Expand Down
7 changes: 1 addition & 6 deletions src/gridcoin/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,12 +559,7 @@ class ProtocolRegistry : public IContractHandler
//!
//! \return The number of elements passivated.
//!
uint64_t PassivateDB();

//!
//! \brief A static function that is called by the scheduler to run the protocol entry database passivation.
//!
static void RunDBPassivation();
uint64_t PassivateDB() override;

//!
//! \brief Specializes the template RegistryDB for the ProtocolEntry class. Note that std::set<ProtocolEntry>
Expand Down
15 changes: 0 additions & 15 deletions src/gridcoin/scraper/scraper_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,21 +573,6 @@ ScraperRegistry::ScraperEntryDB &ScraperRegistry::GetScraperDB()
return m_scraper_db;
}

// This is static and called by the scheduler.
void ScraperRegistry::RunDBPassivation()
{
TRY_LOCK(cs_main, locked_main);

if (!locked_main)
{
return;
}

ScraperRegistry& scraper_entries = GetScraperRegistry();

scraper_entries.PassivateDB();
}

template<> const std::string ScraperRegistry::ScraperEntryDB::KeyType()
{
return std::string("scraper");
Expand Down
7 changes: 1 addition & 6 deletions src/gridcoin/scraper/scraper_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,7 @@ class ScraperRegistry : public IContractHandler
//!
//! \return The number of elements passivated.
//!
uint64_t PassivateDB();

//!
//! \brief A static function that is called by the scheduler to run the scraper entry database passivation.
//!
static void RunDBPassivation();
uint64_t PassivateDB() override;

//!
//! \brief Specializes the template RegistryDB for the ScraperEntry class. Note that std::set<ScraperEntry> is
Expand Down
15 changes: 0 additions & 15 deletions src/gridcoin/sidestake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1164,21 +1164,6 @@ SideStakeRegistry::SideStakeDB &SideStakeRegistry::GetSideStakeDB()
return m_sidestake_db;
}

// This is static and called by the scheduler.
void SideStakeRegistry::RunDBPassivation()
{
TRY_LOCK(cs_main, locked_main);

if (!locked_main)
{
return;
}

SideStakeRegistry& SideStake_entries = GetSideStakeRegistry();

SideStake_entries.PassivateDB();
}

template<> const std::string SideStakeRegistry::SideStakeDB::KeyType()
{
return std::string("SideStake");
Expand Down
7 changes: 1 addition & 6 deletions src/gridcoin/sidestake.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,19 +830,14 @@ class SideStakeRegistry : public IContractHandler
//!
//! \return The number of elements passivated.
//!
uint64_t PassivateDB();
uint64_t PassivateDB() override;

//!
//! \brief This method parses the config file for local sidestakes. It is based on the original GetSideStakingStatusAndAlloc()
//! that was in miner.cpp prior to the implementation of the SideStake class.
//!
void LoadLocalSideStakesFromConfig();

//!
//! \brief A static function that is called by the scheduler to run the sidestake entry database passivation.
//!
static void RunDBPassivation();

//!
//! \brief Specializes the template RegistryDB for the SideStake class. Note that std::set<MandatorySideStake>
//! is not actually used.
Expand Down
Loading

0 comments on commit 1c31aa3

Please sign in to comment.