From b31bf9669f18ac0d1b0ce2d4d245570c3d32eb7b Mon Sep 17 00:00:00 2001 From: jamescowens Date: Sat, 21 Nov 2020 16:06:31 -0500 Subject: [PATCH] Add check for minimum housekeeping complete in scraper This commit adds an optional parameter to ScraperGetSuperblockContract, the boolean bFromHousekeeping. This optional parameter is set true when run from the ScraperHousekeeping function, causes the corresponding bMinHousekeepingComplete flag in the global cache to be set true. The superblock validator will skip validation with the state Result:UNKNOWN if this flag is false, which allows a grace period of nScraperSleep right after wallet startup where a superblock can be accepted without validation. --- src/gridcoin/scraper/scraper.cpp | 16 +++++++--------- src/gridcoin/scraper/scraper.h | 2 +- src/gridcoin/superblock.h | 15 ++++++++++++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/gridcoin/scraper/scraper.cpp b/src/gridcoin/scraper/scraper.cpp index e73e37fd49..4acc25f1b5 100755 --- a/src/gridcoin/scraper/scraper.cpp +++ b/src/gridcoin/scraper/scraper.cpp @@ -1277,18 +1277,15 @@ UniValue testnewsb(const UniValue& params, bool fHelp); bool ScraperHousekeeping() { - // Periodically generate converged manifests and generate SB core and "contract" - // This will probably be reduced to the commented out call as we near final testing, - // because ScraperGetSuperblockContract(false) is called from the subscriber interface - // with the boolean false, meaning don't store the stats. - // Lock both cs_Scraper and cs_StructScraperFileManifest. + // Periodically generate converged manifests and generate SB contract and store in cache. Superblock superblock; { + // Lock both cs_Scraper and cs_StructScraperFileManifest. LOCK2(cs_Scraper, cs_StructScraperFileManifest); - superblock = ScraperGetSuperblockContract(true, false); + superblock = ScraperGetSuperblockContract(true, false, true); } { @@ -1327,8 +1324,6 @@ bool ScraperHousekeeping() if (log.archive(false, plogfile_out)) _log(logattribute::INFO, "ScraperHousekeeping", "Archived scraper.log to " + plogfile_out.filename().string()); - //log.closelogfile(); - return true; } @@ -5056,7 +5051,7 @@ ScraperPendingBeaconMap GetVerifiedBeaconsForReport(bool from_global) * Subscriber * ************************/ -Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats, bool bContractDirectFromStatsUpdate) +Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats, bool bContractDirectFromStatsUpdate, bool bFromHousekeeping) { Superblock empty_superblock; @@ -5135,6 +5130,9 @@ Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats, bool bContrac // Mark the cache clean, because it was just updated. ConvergedScraperStatsCache.bClean = true; + // If called from housekeeping, mark bMinHousekeepingComplete true + if (bFromHousekeeping) ConvergedScraperStatsCache.bMinHousekeepingComplete = true; + // Signal UI of SBContract status if (superblock.WellFormed()) { diff --git a/src/gridcoin/scraper/scraper.h b/src/gridcoin/scraper/scraper.h index 7773da05fd..dfc96a0bab 100644 --- a/src/gridcoin/scraper/scraper.h +++ b/src/gridcoin/scraper/scraper.h @@ -98,7 +98,7 @@ ScraperStatsAndVerifiedBeacons GetScraperStatsByConvergedManifest(const Converge bool IsScraperAuthorized(); bool IsScraperAuthorizedToBroadcastManifests(CBitcoinAddress& AddressOut, CKey& KeyOut); bool IsScraperMaximumManifestPublishingRateExceeded(int64_t& nTime, CPubKey& PubKey); -GRC::Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats = false, bool bContractDirectFromStatsUpdate = false); +GRC::Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats = false, bool bContractDirectFromStatsUpdate = false, bool bFromHousekeeping = false); scraperSBvalidationtype ValidateSuperblock(const GRC::Superblock& NewFormatSuperblock, bool bUseCache = true, unsigned int nReducedCacheBits = 32); std::vector GetVerifiedBeaconIDs(const ConvergedManifest& StructConvergedManifest); std::vector GetVerifiedBeaconIDs(const ScraperPendingBeaconMap& VerifiedBeaconMap); diff --git a/src/gridcoin/superblock.h b/src/gridcoin/superblock.h index a366b68f81..4947966bdf 100644 --- a/src/gridcoin/superblock.h +++ b/src/gridcoin/superblock.h @@ -1551,6 +1551,7 @@ struct ConvergedScraperStats ConvergedScraperStats() : Convergence(), NewFormatSuperblock() { bClean = false; + bMinHousekeepingComplete = false; nTime = 0; mScraperConvergedStats = {}; @@ -1560,6 +1561,7 @@ struct ConvergedScraperStats ConvergedScraperStats(const int64_t nTime_in, const ConvergedManifest& Convergence) : Convergence(Convergence) { bClean = false; + bMinHousekeepingComplete = false; nTime = nTime_in; @@ -1569,7 +1571,18 @@ struct ConvergedScraperStats // Flag to indicate cache is clean or dirty (i.e. state change of underlying statistics has occurred. // This flag is marked true in ScraperGetSuperblockContract() and false on receipt or deletion of // statistics objects. - bool bClean = false; + bool bClean; + + // This flag tracks the completion of at least one iteration of the housekeeping loop. The purpose of this flag + // is to ensure enough time has gone by after a (re)start of the wallet that a complete set of manifests/parts + // have been collected. Trying to form a contract too early may result in a local convergence that may not + // match an incoming superblock that comes in very close to the wallet start, and if enough manifests/parts are + // missing the backup validation checks will fail, resulting in a forked client due to failure to validate + // the superblock. This should help the difficult corner case of a wallet restarted literally a minute or two + // before the superblock is received. This has the effect of allowing a grace period of nScraperSleep after the + // wallet start where an incoming superblock will allowed with Result::UNKNOWN, rather than rejected with + // Result::INVALID. + bool bMinHousekeepingComplete; int64_t nTime; ScraperStats mScraperConvergedStats;