Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion src/gridcoin/researcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ const MiningPool g_pools[] = {
{ "7d0d73fe026d66fd4ab8d5d8da32a611", "grcpool.com", "https://grcpool.com/" },
{ "a914eba952be5dfcf73d926b508fd5fa", "grcpool.com-2", "https://grcpool.com/" },
{ "163f049997e8a2dee054d69a7720bf05", "grcpool.com-3", "https://grcpool.com/" },
{ "326bb50c0dd0ba9d46e15fae3484af35", "Arikado", "https://gridcoinpool.ru/" },
{ "326bb50c0dd0ba9d46e15fae3484af35", "grc.arikado.pool", "https://gridcoinpool.ru/" },
};

//!
Expand All @@ -245,6 +245,24 @@ bool IsPoolCpid(const Cpid cpid)
return false;
}

//!
//! \brief Determine whether the provided username belongs to a Gridcoin pool.
//!
//! \param cpid The BOINC account username for a project loaded from BOINC.
//!
//! \return \c true if the username matches a known Gridcoin pool's username.
//!
bool IsPoolUsername(const std::string& username)
{
for (const auto& pool : g_pools) {
if (pool.m_name == username) {
return true;
}
}

return false;
}

//!
//! \brief Fetch the contents of BOINC's client_state.xml file from disk.
//!
Expand Down Expand Up @@ -858,6 +876,20 @@ MiningProject MiningProject::Parse(const std::string& xml)
}
}

// Since we cannot match the project using a solo cruncher's email
// address above, the project may be attached to a pool. We cannot
// compare the pool's external CPID so we check the username. This
// is not as accurate, but it prevents the GUI from displaying the
// "malformed CPID" notice to pool users for BOINC servers that do
// not reply with an external CPID:
//
if (IsPoolUsername(ExtractXML(xml, "<user_name>", "</user_name>"))
&& !GetBoolArg("-pooloperator", false))
{
project.m_error = MiningProject::Error::POOL;
return project;
}

// For the extremely rare case that a BOINC project assigned a user a
// CPID that contains only zeroes, double check that a CPID parsed to
// zero is actually invalid:
Expand Down
58 changes: 51 additions & 7 deletions src/test/gridcoin/researcher_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void AddTestBeacon(const GRC::Cpid cpid)
const CKeyID key_id = public_key.GetID();
const int64_t now = GetAdjustedTime() + nBeaconCount;
nBeaconCount++;


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

BOOST_AUTO_TEST_CASE(it_detects_projects_with_pool_usernames)
{
// The XML string contains a subset of data found within a <project> element
// from BOINC's client_state.xml file. For this test case, we want to verify
// that it detects a pool account for projects that don't send back external
// CPIDs, so we leave the <external_cpid> field blank and provide a username
// for a known Gridcoin pool:
//
GRC::MiningProject project = GRC::MiningProject::Parse(
R"XML(
<project>
<master_url>https://example.com/</master_url>
<project_name>Project Name</project_name>
<team_name>Team Name</team_name>
<cross_project_id>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</cross_project_id>
<external_cpid></external_cpid>
<user_name>grcpool.com</user_name>
</project>
)XML");

BOOST_CHECK(project.m_error == GRC::MiningProject::Error::POOL);
}

BOOST_AUTO_TEST_CASE(it_determines_whether_a_project_is_whitelisted)
{
GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url",
Expand Down Expand Up @@ -936,11 +959,22 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
<external_cpid>7d0d73fe026d66fd4ab8d5d8da32a611</external_cpid>
</project>
)XML",
// Malformed RAC:
// Pool Username (for projects missing <external_cpid>):
R"XML(
<project>
<master_url>https://example.com/</master_url>
<project_name>Project Name 8</project_name>
<team_name>Gridcoin</team_name>
<user_expavg_credit>8.8</user_expavg_credit>
<external_cpid></external_cpid>
<user_name>grcpool.com</user_name>
</project>
)XML",
// Malformed RAC:
R"XML(
<project>
<master_url>https://example.com/</master_url>
<project_name>Project Name 9</project_name>
<team_name>Not Gridcoin</team_name>
<cross_project_id>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</cross_project_id>
<user_expavg_credit>FOO</user_expavg_credit>
Expand All @@ -955,7 +989,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(GRC::Researcher::Get()->Id() == GRC::MiningId::ForInvestor());

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

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

if (const GRC::ProjectOption project8 = projects.Try("project name 8")) {
BOOST_CHECK(project8->m_name == "project name 8");
BOOST_CHECK(project8->m_cpid == cpid);
BOOST_CHECK(project8->m_team == "not gridcoin");
BOOST_CHECK(project8->m_rac == 0.0);
BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::INVALID_TEAM);
BOOST_CHECK(project8->m_cpid.IsZero() == true);
BOOST_CHECK(project8->m_rac == 8.8);
BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::POOL);
BOOST_CHECK(project8->Eligible() == false);
} else {
BOOST_FAIL("Project 8 does not exist in the mining project map.");
}

if (const GRC::ProjectOption project9 = projects.Try("project name 9")) {
BOOST_CHECK(project9->m_name == "project name 9");
BOOST_CHECK(project9->m_cpid == cpid);
BOOST_CHECK(project9->m_team == "not gridcoin");
BOOST_CHECK(project9->m_rac == 0.0);
BOOST_CHECK(project9->m_error == GRC::MiningProject::Error::INVALID_TEAM);
BOOST_CHECK(project9->Eligible() == false);
} else {
BOOST_FAIL("Project 9 does not exist in the mining project map.");
}

// HasRAC should be false.
BOOST_CHECK(!GRC::Researcher::Get()->HasRAC());

Expand Down