Skip to content

Commit 7f3b7ac

Browse files
committed
Fix "malformed CPID" status for pool projects
Some old BOINC servers do not send the external CPID to the BOINC client. The pool-mode detection failed for these and reported the project with a malformed CPID in the researcher wizard. This adds a check that compares a user name from client_state.xml with known pools as a fallback for projects with blank CPIDs.
1 parent db56a7c commit 7f3b7ac

File tree

2 files changed

+84
-8
lines changed

2 files changed

+84
-8
lines changed

src/gridcoin/researcher.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ const MiningPool g_pools[] = {
224224
{ "7d0d73fe026d66fd4ab8d5d8da32a611", "grcpool.com", "https://grcpool.com/" },
225225
{ "a914eba952be5dfcf73d926b508fd5fa", "grcpool.com-2", "https://grcpool.com/" },
226226
{ "163f049997e8a2dee054d69a7720bf05", "grcpool.com-3", "https://grcpool.com/" },
227-
{ "326bb50c0dd0ba9d46e15fae3484af35", "Arikado", "https://gridcoinpool.ru/" },
227+
{ "326bb50c0dd0ba9d46e15fae3484af35", "grc.arikado.pool", "https://gridcoinpool.ru/" },
228228
};
229229

230230
//!
@@ -245,6 +245,24 @@ bool IsPoolCpid(const Cpid cpid)
245245
return false;
246246
}
247247

248+
//!
249+
//! \brief Determine whether the provided username belongs to a Gridcoin pool.
250+
//!
251+
//! \param cpid The BOINC account username for a project loaded from BOINC.
252+
//!
253+
//! \return \c true if the username matches a known Gridcoin pool's username.
254+
//!
255+
bool IsPoolUsername(const std::string& username)
256+
{
257+
for (const auto& pool : g_pools) {
258+
if (pool.m_name == username) {
259+
return true;
260+
}
261+
}
262+
263+
return false;
264+
}
265+
248266
//!
249267
//! \brief Fetch the contents of BOINC's client_state.xml file from disk.
250268
//!
@@ -858,6 +876,20 @@ MiningProject MiningProject::Parse(const std::string& xml)
858876
}
859877
}
860878

879+
// Since we cannot match the project using a solo cruncher's email
880+
// address above, the project may be attached to a pool. We cannot
881+
// compare the pool's external CPID so we check the username. This
882+
// is not as accurate, but it prevents the GUI from displaying the
883+
// "malformed CPID" notice to pool users for BOINC servers that do
884+
// not reply with an external CPID:
885+
//
886+
if (IsPoolUsername(ExtractXML(xml, "<user_name>", "</user_name>"))
887+
&& !GetBoolArg("-pooloperator", false))
888+
{
889+
project.m_error = MiningProject::Error::POOL;
890+
return project;
891+
}
892+
861893
// For the extremely rare case that a BOINC project assigned a user a
862894
// CPID that contains only zeroes, double check that a CPID parsed to
863895
// zero is actually invalid:

src/test/gridcoin/researcher_tests.cpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void AddTestBeacon(const GRC::Cpid cpid)
7474
const CKeyID key_id = public_key.GetID();
7575
const int64_t now = GetAdjustedTime() + nBeaconCount;
7676
nBeaconCount++;
77-
77+
7878

7979
// Dummy transaction for the contract handler API:
8080
CTransaction tx;
@@ -284,6 +284,29 @@ BOOST_AUTO_TEST_CASE(it_detects_projects_with_pool_cpids)
284284
BOOST_CHECK(project.m_error == GRC::MiningProject::Error::POOL);
285285
}
286286

287+
BOOST_AUTO_TEST_CASE(it_detects_projects_with_pool_usernames)
288+
{
289+
// The XML string contains a subset of data found within a <project> element
290+
// from BOINC's client_state.xml file. For this test case, we want to verify
291+
// that it detects a pool account for projects that don't send back external
292+
// CPIDs, so we leave the <external_cpid> field blank and provide a username
293+
// for a known Gridcoin pool:
294+
//
295+
GRC::MiningProject project = GRC::MiningProject::Parse(
296+
R"XML(
297+
<project>
298+
<master_url>https://example.com/</master_url>
299+
<project_name>Project Name</project_name>
300+
<team_name>Team Name</team_name>
301+
<cross_project_id>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</cross_project_id>
302+
<external_cpid></external_cpid>
303+
<user_name>grcpool.com</user_name>
304+
</project>
305+
)XML");
306+
307+
BOOST_CHECK(project.m_error == GRC::MiningProject::Error::POOL);
308+
}
309+
287310
BOOST_AUTO_TEST_CASE(it_determines_whether_a_project_is_whitelisted)
288311
{
289312
GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url",
@@ -936,11 +959,22 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
936959
<external_cpid>7d0d73fe026d66fd4ab8d5d8da32a611</external_cpid>
937960
</project>
938961
)XML",
939-
// Malformed RAC:
962+
// Pool Username (for projects missing <external_cpid>):
940963
R"XML(
941964
<project>
942965
<master_url>https://example.com/</master_url>
943966
<project_name>Project Name 8</project_name>
967+
<team_name>Gridcoin</team_name>
968+
<user_expavg_credit>8.8</user_expavg_credit>
969+
<external_cpid></external_cpid>
970+
<user_name>grcpool.com</user_name>
971+
</project>
972+
)XML",
973+
// Malformed RAC:
974+
R"XML(
975+
<project>
976+
<master_url>https://example.com/</master_url>
977+
<project_name>Project Name 9</project_name>
944978
<team_name>Not Gridcoin</team_name>
945979
<cross_project_id>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</cross_project_id>
946980
<user_expavg_credit>FOO</user_expavg_credit>
@@ -955,7 +989,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
955989
BOOST_CHECK(GRC::Researcher::Get()->Id() == GRC::MiningId::ForInvestor());
956990

957991
const GRC::MiningProjectMap& projects = GRC::Researcher::Get()->Projects();
958-
BOOST_CHECK(projects.size() == 8);
992+
BOOST_CHECK(projects.size() == 9);
959993

960994
if (const GRC::ProjectOption project1 = projects.Try("project name 1")) {
961995
BOOST_CHECK(project1->m_name == "project name 1");
@@ -1034,15 +1068,25 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
10341068

10351069
if (const GRC::ProjectOption project8 = projects.Try("project name 8")) {
10361070
BOOST_CHECK(project8->m_name == "project name 8");
1037-
BOOST_CHECK(project8->m_cpid == cpid);
1038-
BOOST_CHECK(project8->m_team == "not gridcoin");
1039-
BOOST_CHECK(project8->m_rac == 0.0);
1040-
BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::INVALID_TEAM);
1071+
BOOST_CHECK(project8->m_cpid.IsZero() == true);
1072+
BOOST_CHECK(project8->m_rac == 8.8);
1073+
BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::POOL);
10411074
BOOST_CHECK(project8->Eligible() == false);
10421075
} else {
10431076
BOOST_FAIL("Project 8 does not exist in the mining project map.");
10441077
}
10451078

1079+
if (const GRC::ProjectOption project9 = projects.Try("project name 9")) {
1080+
BOOST_CHECK(project9->m_name == "project name 9");
1081+
BOOST_CHECK(project9->m_cpid == cpid);
1082+
BOOST_CHECK(project9->m_team == "not gridcoin");
1083+
BOOST_CHECK(project9->m_rac == 0.0);
1084+
BOOST_CHECK(project9->m_error == GRC::MiningProject::Error::INVALID_TEAM);
1085+
BOOST_CHECK(project9->Eligible() == false);
1086+
} else {
1087+
BOOST_FAIL("Project 9 does not exist in the mining project map.");
1088+
}
1089+
10461090
// HasRAC should be false.
10471091
BOOST_CHECK(!GRC::Researcher::Get()->HasRAC());
10481092

0 commit comments

Comments
 (0)