diff --git a/src/gridcoin/researcher.cpp b/src/gridcoin/researcher.cpp index de239de2a3..025ab8030c 100644 --- a/src/gridcoin/researcher.cpp +++ b/src/gridcoin/researcher.cpp @@ -401,9 +401,10 @@ std::optional FallbackToCpidByEmail( //! \param projects Map of local projects loaded from BOINC's client_state.xml //! file. //! -void DetectSplitCpid(const MiningProjectMap& projects) +bool DetectSplitCpid(const MiningProjectMap& projects) { std::unordered_map eligible_cpids; + bool has_split_cpid = false; for (const auto& project_pair : projects) { if (project_pair.second.Eligible()) { @@ -411,9 +412,13 @@ void DetectSplitCpid(const MiningProjectMap& projects) project_pair.second.m_cpid, project_pair.second.m_name); } + + if (project_pair.second.m_error == MiningProject::Error::MISMATCHED_CPID) { + has_split_cpid = true; + } } - if (eligible_cpids.size() > 1) { + if (has_split_cpid || eligible_cpids.size() > 1) { std::string warning = "WARNING: Detected potential CPID split. "; warning += "Eligible CPIDs: \n"; @@ -423,7 +428,11 @@ void DetectSplitCpid(const MiningProjectMap& projects) } LogPrintf("%s", warning); + + return true; } + + return false; } //! @@ -1046,10 +1055,13 @@ Researcher::Researcher() Researcher::Researcher( MiningId mining_id, MiningProjectMap projects, - const GRC::BeaconError beacon_error) + const GRC::BeaconError beacon_error, + const bool has_split_cpid + ) : m_mining_id(std::move(mining_id)) , m_projects(std::move(projects)) , m_beacon_error(beacon_error) + , m_has_split_cpid(has_split_cpid) { } @@ -1205,15 +1217,17 @@ void Researcher::Reload(MiningProjectMap projects, GRC::BeaconError beacon_error } } + bool has_split_cpid = false; + if (const CpidOption cpid = mining_id.TryCpid()) { - DetectSplitCpid(projects); + has_split_cpid = DetectSplitCpid(projects); LogPrintf("Selected primary CPID: %s", cpid->ToString()); } else if (!projects.empty()) { LogPrintf("WARNING: no projects eligible for research rewards."); } StoreResearcher( - Researcher(std::move(mining_id), std::move(projects), beacon_error)); + Researcher(std::move(mining_id), std::move(projects), beacon_error, has_split_cpid)); } void Researcher::Refresh() @@ -1361,6 +1375,11 @@ GRC::BeaconError Researcher::BeaconError() const return m_beacon_error; } +bool Researcher::hasSplitCpid() const +{ + return m_has_split_cpid; +} + bool Researcher::ChangeMode(const ResearcherMode mode, std::string email) { email = ToLower(email); diff --git a/src/gridcoin/researcher.h b/src/gridcoin/researcher.h index c4cf6b3d5b..e4a7d5b293 100644 --- a/src/gridcoin/researcher.h +++ b/src/gridcoin/researcher.h @@ -387,11 +387,13 @@ class Researcher //! \param mining_id Represents a CPID or an investor. //! \param projects A set of local projects loaded from BOINC. //! \param beacon_error Last beacon advertisement error, if any. + //! \param has_split_cpid Existence of split cpid. //! Researcher( MiningId mining_id, MiningProjectMap projects, - const BeaconError beacon_error = GRC::BeaconError::NONE); + const BeaconError beacon_error = GRC::BeaconError::NONE, + bool has_split_cpid = false); //! //! \brief Set up the local researcher context. @@ -577,6 +579,13 @@ class Researcher //! GRC::BeaconError BeaconError() const; + //! + //! \brief Returns true if a split CPID situation exists (i.e. project list + //! refers to more than one CPID). + //! \return boolean of split cpid existence + //! + bool hasSplitCpid() const; + //! //! \brief Update how a user prefers to participate in the research reward //! protocol and set the node's BOINC account email address used to detect @@ -637,6 +646,7 @@ class Researcher MiningId m_mining_id; //!< CPID or INVESTOR variant. MiningProjectMap m_projects; //!< Local projects loaded from BOINC. GRC::BeaconError m_beacon_error; //!< Last beacon error that occurred, if any. + bool m_has_split_cpid; //!< Flag that indicates project list has more than one CPID }; // Researcher } diff --git a/src/qt/researcher/researchermodel.cpp b/src/qt/researcher/researchermodel.cpp index 2cb1f3269c..88b4486a51 100644 --- a/src/qt/researcher/researchermodel.cpp +++ b/src/qt/researcher/researchermodel.cpp @@ -235,7 +235,7 @@ bool ResearcherModel::actionNeeded() const } if (hasEligibleProjects()) { - return !hasActiveBeacon() && !hasPendingBeacon(); + return (!hasActiveBeacon() && !hasPendingBeacon()) || hasSplitCpid(); } return !hasPoolProjects(); @@ -276,6 +276,11 @@ bool ResearcherModel::hasRAC() const return m_researcher->HasRAC(); } +bool ResearcherModel::hasSplitCpid() const +{ + return m_researcher->hasSplitCpid(); +} + bool ResearcherModel::needsBeaconAuth() const { if (!hasPendingBeacon()) { diff --git a/src/qt/researcher/researchermodel.h b/src/qt/researcher/researchermodel.h index bcc5c77346..36dfc43fb9 100644 --- a/src/qt/researcher/researchermodel.h +++ b/src/qt/researcher/researchermodel.h @@ -94,6 +94,7 @@ class ResearcherModel : public QObject bool hasRenewableBeacon() const; bool hasMagnitude() const; bool hasRAC() const; + bool hasSplitCpid() const; bool needsBeaconAuth() const; QString email() const; @@ -121,6 +122,7 @@ class ResearcherModel : public QObject bool m_configured_for_investor_mode; bool m_wizard_open; bool m_out_of_sync; + bool m_split_cpid; bool m_privacy_enabled; QString m_theme_suffix; diff --git a/src/qt/researcher/researcherwizardsummarypage.cpp b/src/qt/researcher/researcherwizardsummarypage.cpp index 1ee10b9816..1813cfdf2c 100644 --- a/src/qt/researcher/researcherwizardsummarypage.cpp +++ b/src/qt/researcher/researcherwizardsummarypage.cpp @@ -128,6 +128,12 @@ void ResearcherWizardSummaryPage::refreshOverallStatus() } else if (!m_researcher_model->hasMagnitude()) { status = tr("Waiting for magnitude."); icon = QIcon(":/icons/scraper_waiting_light"); + } else if (m_researcher_model->hasSplitCpid()) { + status = tr("Likely split CPID - projects refer to more than one CPID. Please ensure all\n" + "of your projects are attached using the same email address and if you added\n" + "a project recently, update that project and then all other projects using the\n" + "update button in the BOINC manager."); + icon = QIcon(":/icons/warning"); } else { status = tr("Everything looks good."); icon = QIcon(":/icons/round_green_check");