Skip to content

Commit 3fe15e7

Browse files
committed
Initial implementation of AutoGreylist (WIP)
This is the initial implementation of the AutoGreylist class. It also includes a diagnostic getautogreylist RPC to see the current results of the algorithm.
1 parent e827432 commit 3fe15e7

File tree

9 files changed

+414
-27
lines changed

9 files changed

+414
-27
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ GRIDCOIN_CORE_H = \
117117
gridcoin/contract/registry.h \
118118
gridcoin/contract/registry_db.h \
119119
gridcoin/cpid.h \
120+
gridcoin/fwd.h \
120121
gridcoin/gridcoin.h \
121122
gridcoin/magnitude.h \
122123
gridcoin/mrc.h \

src/gridcoin/fwd.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2014-2025 The Gridcoin developers
2+
// Distributed under the MIT/X11 software license, see the accompanying
3+
// file COPYING or https://opensource.org/licenses/mit-license.php.
4+
5+
#ifndef GRIDCOIN_FWD_H
6+
#define GRIDCOIN_FWD_H
7+
8+
namespace GRC
9+
{
10+
//!
11+
//! \brief Enumeration of project entry status. Unlike beacons this is for both storage
12+
//! and memory.
13+
//!
14+
//! UNKNOWN status is only encountered in trivially constructed empty
15+
//! project entries and should never be seen on the blockchain.
16+
//!
17+
//! DELETED status corresponds to a removed entry.
18+
//!
19+
//! ACTIVE corresponds to an active entry.
20+
//!
21+
//! GREYLISTED means that the project temporarily does not meet the whitelist qualification criteria.
22+
//!
23+
//! OUT_OF_BOUND must go at the end and be retained for the EnumBytes wrapper.
24+
//!
25+
enum class ProjectEntryStatus
26+
{
27+
UNKNOWN,
28+
DELETED,
29+
ACTIVE,
30+
MAN_GREYLISTED,
31+
AUTO_GREYLISTED,
32+
OUT_OF_BOUND
33+
};
34+
} // namespace GRC
35+
36+
#endif // GRIDCOIN_FWD_H
37+

src/gridcoin/project.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
// Distributed under the MIT/X11 software license, see the accompanying
33
// file COPYING or https://opensource.org/licenses/mit-license.php.
44

5+
#include "gridcoin/claim.h"
56
#include "main.h"
7+
#include "node/blockstorage.h"
8+
#include "gridcoin/support/block_finder.h"
69
#include "gridcoin/project.h"
10+
#include "gridcoin/quorum.h"
711
#include "node/ui_interface.h"
812

913
#include <algorithm>
@@ -296,6 +300,140 @@ WhitelistSnapshot WhitelistSnapshot::Sorted() const
296300
return WhitelistSnapshot(std::make_shared<ProjectList>(sorted), m_filter);
297301
}
298302

303+
// -----------------------------------------------------------------------------
304+
// Class: AutoGreylist - automatic greylisting
305+
// -----------------------------------------------------------------------------
306+
307+
AutoGreylist::AutoGreylist()
308+
: m_greylist_ptr(std::make_shared<Greylist>())
309+
, m_superblock_hash(uint256 {})
310+
{
311+
//m_greylist_ptr = std::make_shared<Greylist>();
312+
313+
Refresh();
314+
}
315+
316+
AutoGreylist::Greylist::const_iterator AutoGreylist::begin() const
317+
{
318+
return m_greylist_ptr->begin();
319+
}
320+
321+
AutoGreylist::Greylist::const_iterator AutoGreylist::end() const
322+
{
323+
return m_greylist_ptr->end();
324+
}
325+
326+
AutoGreylist::Greylist::size_type AutoGreylist::size() const
327+
{
328+
return m_greylist_ptr->size();
329+
}
330+
331+
void AutoGreylist::Refresh()
332+
{
333+
LOCK(cs_main);
334+
335+
// If the current superblock has not changed, then no need to do anything.
336+
if (!m_superblock_hash.IsNull() && Quorum::CurrentSuperblock()->GetHash() == m_superblock_hash) {
337+
return;
338+
}
339+
340+
SuperblockPtr superblock_ptr = Quorum::CurrentSuperblock();
341+
342+
if (!superblock_ptr.IsEmpty()) {
343+
RefreshWithSuperblock(superblock_ptr);
344+
}
345+
}
346+
347+
void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in)
348+
{
349+
LOCK(lock);
350+
351+
// We need the current whitelist, including all records except deleted. This will include greylisted projects,
352+
// whether currently marked as manually greylisted from protocol or overridden to auto greylisted by the auto greylist class.
353+
const WhitelistSnapshot whitelist = GetWhitelist().Snapshot(GRC::ProjectEntry::ProjectFilterFlag::ALL_BUT_DELETED);
354+
355+
m_greylist_ptr->clear();
356+
357+
for (const auto& iter : whitelist) {
358+
if (auto project = superblock_ptr_in->m_projects.Try(iter.m_name)) {
359+
// Record new greylist candidate entry baseline with the total credit for each project present in superblock.
360+
m_greylist_ptr->insert(std::make_pair(iter.m_name, GreylistCandidateEntry(iter.m_name, project->m_total_credit)));
361+
} else {
362+
// Record new greylist candidate entry with nullopt total credit. This is for a project that is in the whitelist,
363+
// but does not have a project entry in the superblock. This would be because the scrapers could not converge on the
364+
// project.
365+
m_greylist_ptr->insert(std::make_pair(iter.m_name, GreylistCandidateEntry(iter.m_name,
366+
std::optional<uint64_t>(std::nullopt))));
367+
}
368+
}
369+
370+
CBlockIndex* index_ptr;
371+
{
372+
// Find the block index entry for the block before the provided superblock_ptr.
373+
index_ptr = GRC::BlockFinder::FindByHeight(superblock_ptr_in.m_height - 1);
374+
}
375+
376+
//SuperblockPtr superblock_ptr;
377+
unsigned int superblock_count = 1; // The 0 (baseline) superblock was processed above. Here we start with 1 and go up to 40
378+
379+
while (index_ptr != nullptr && index_ptr->pprev != nullptr && superblock_count <= 40) {
380+
381+
if (!index_ptr->IsSuperblock()) {
382+
index_ptr = index_ptr->pprev;
383+
continue;
384+
}
385+
386+
// For some reason this is not working.
387+
//superblock_ptr.ReadFromDisk(index_ptr);
388+
389+
CBlock block;
390+
if (!ReadBlockFromDisk(block, index_ptr, Params().GetConsensus())) {
391+
error("%s: Failed to read block from disk with requested height %u",
392+
__func__,
393+
index_ptr->nHeight);
394+
continue;
395+
}
396+
397+
SuperblockPtr superblock_ptr = block.GetClaim().m_superblock;
398+
399+
for (const auto& iter : whitelist) {
400+
// This is guaranteed to succeed, because every whitelisted project was inserted as a new baseline entry above.
401+
auto greylist_entry = m_greylist_ptr->find(iter.m_name);
402+
403+
if (auto project = superblock_ptr->m_projects.Try(iter.m_name)) {
404+
// Update greylist candidate entry with the total credit for each project present in superblock.
405+
greylist_entry->second.UpdateGreylistCandidateEntry(project->m_total_credit, superblock_count);
406+
} else {
407+
// Record updated greylist candidate entry with nullopt total credit. This is for a project that is in the whitelist,
408+
// but does not have a project entry in this superblock. This would be because the scrapers could not converge on the
409+
// project for this superblock.
410+
greylist_entry->second.UpdateGreylistCandidateEntry(std::optional<uint64_t>(std::nullopt), superblock_count);
411+
}
412+
}
413+
414+
++superblock_count;
415+
index_ptr = index_ptr->pprev;
416+
}
417+
418+
// Purge candidate elements that do not meet auto greylist criteria.
419+
for (auto iter = m_greylist_ptr->begin(); iter != m_greylist_ptr->end(); ) {
420+
if (iter->second.GetZCD() < 7 && iter->second.GetWAS() >= Fraction(1, 10)) {
421+
// Candidate greylist entry does not meet auto greylist criteria, so remove from greylist entry map.
422+
iter = m_greylist_ptr->erase(iter);
423+
} else {
424+
iter++;
425+
}
426+
}
427+
}
428+
429+
// This is the global cached (singleton) for the auto greylist.
430+
std::shared_ptr<AutoGreylist> g_autogreylist_ptr = std::make_shared<AutoGreylist>();
431+
432+
std::shared_ptr<AutoGreylist> AutoGreylist::GetAutoGreylistCache()
433+
{
434+
return g_autogreylist_ptr;
435+
}
436+
299437
// -----------------------------------------------------------------------------
300438
// Class: Whitelist (Registry)
301439
// -----------------------------------------------------------------------------
@@ -304,6 +442,8 @@ WhitelistSnapshot Whitelist::Snapshot(const ProjectEntry::ProjectFilterFlag& fil
304442
{
305443
LOCK(cs_lock);
306444

445+
//AutoGreylist::GetAutoGreylistCache()->Refresh();
446+
307447
ProjectList projects;
308448

309449
for (const auto& iter : m_project_entries) {

0 commit comments

Comments
 (0)