Skip to content

Commit

Permalink
Implement auto greylist boost unit test
Browse files Browse the repository at this point in the history
Made small adjustments as a result of unit testing. Note that
a tough to track down error was occurring due to an incorrect
action from the MarkAsSuperblock() call on the CBlockIndex object.
It turns out this was a enum confusion caused by SUPERBLOCK
being used in two different enums in the same namespace. This
has been corrected by puting the MinedType enum in the GRC
namespace.

The rules have also been finalized to mean the 7 out of 20
ZCD's means 20 SB's lookback from the current, which is
actually 21 SB's including the baseline, and correspondingly
for the other intervals.

Also a grace period of 7 SB's from the baseline is used before the
rules are applied to allow enough statistics to be collected to
be meaningful.
  • Loading branch information
jamescowens committed Jan 24, 2025
1 parent 7960dfa commit 8a751ab
Show file tree
Hide file tree
Showing 10 changed files with 964 additions and 97 deletions.
63 changes: 46 additions & 17 deletions src/gridcoin/project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,9 @@ void AutoGreylist::Refresh() EXCLUSIVE_LOCKS_REQUIRED (cs_main)
RefreshWithSuperblock(superblock_ptr);
}

void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in) EXCLUSIVE_LOCKS_REQUIRED (cs_main)
void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in,
std::shared_ptr<std::map<int, std::pair<CBlockIndex*, SuperblockPtr>>> unit_test_blocks)
EXCLUSIVE_LOCKS_REQUIRED (cs_main)
{
if (superblock_ptr_in.IsEmpty()) {
return;
Expand All @@ -419,7 +421,7 @@ void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in) EXCLUS

LOCK(autogreylist_lock);

m_greylist_ptr->clear();
m_greylist_ptr->clear();

// No need to go further if the whitelist is empty (ignoring deleted records).
if (!whitelist.Populated()) {
Expand Down Expand Up @@ -452,13 +454,13 @@ void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in) EXCLUS
if (project != superblock_ptr_in->m_projects_all_cpids_total_credits.m_projects_all_cpid_total_credits.end()) {
// Record new greylist candidate entry baseline with the total credit for each project present in superblock.
m_greylist_ptr->insert(std::make_pair(iter.m_name,
GreylistCandidateEntry(iter.m_name, std::nearbyint(project->second))));
GreylistCandidateEntry(iter.m_name, project->second)));
} else {
// Record new greylist candidate entry with nullopt total credit. This is for a project that is in the whitelist,
// but does not have a project entry in the superblock. This would be because the scrapers could not converge on the
// project.
m_greylist_ptr->insert(std::make_pair(iter.m_name, GreylistCandidateEntry(iter.m_name,
std::optional<uint64_t>(std::nullopt))));
std::optional<uint64_t>())));
}
}
}
Expand All @@ -467,8 +469,24 @@ void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in) EXCLUS

CBlockIndex* index_ptr;
{
// Find the block index entry for the block before the provided superblock_ptr.
index_ptr = GRC::BlockFinder::FindByHeight(superblock_ptr_in.m_height - 1);
// Find the block index entry for the block before the provided superblock_ptr. This also implements the unit test
// substitute input structure.
if (unit_test_blocks == nullptr) {
index_ptr = GRC::BlockFinder::FindByHeight(superblock_ptr_in.m_height - 1);
} else {
// This only works if the unit_test_blocks are all superblocks, which they should be based on the setup of the
// unit test.
auto iter = unit_test_blocks->find(superblock_ptr_in.m_height - 1);

if (iter != unit_test_blocks->end()) {
// Get the unit test entry that corresponds to the superblock_ptr_in, which was processed above, and then
// get CBlockIndex* entry.
index_ptr = iter->second.first;
} else {
index_ptr = nullptr;
}

}
}


Expand All @@ -479,19 +497,30 @@ void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in) EXCLUS
continue;
}

// For some reason this is not working.
//superblock_ptr.ReadFromDisk(index_ptr);
SuperblockPtr superblock_ptr;

CBlock block;
if (!ReadBlockFromDisk(block, index_ptr, Params().GetConsensus())) {
error("%s: Failed to read block from disk with requested height %u",
__func__,
index_ptr->nHeight);
continue;
}
if (unit_test_blocks == nullptr) {
// For some reason this is not working.
//superblock_ptr.ReadFromDisk(index_ptr);

SuperblockPtr superblock_ptr = block.GetClaim().m_superblock;
superblock_ptr.Rebind(index_ptr);
CBlock block;

if (!ReadBlockFromDisk(block, index_ptr, Params().GetConsensus())) {
error("%s: Failed to read block from disk with requested height %u",
__func__,
index_ptr->nHeight);
continue;
}

superblock_ptr = block.GetClaim().m_superblock;
superblock_ptr.Rebind(index_ptr);
} else {
auto iter = unit_test_blocks->find(index_ptr->nHeight);

if (iter != unit_test_blocks->end()) {
superblock_ptr = iter->second.second;
}
}

// Stop if superblocks less than version 3 are encountered while going backwards. This will happen until we are 40
// superblocks past the 1st superblock after the height specified for the changeover to v3 superblocks.
Expand Down
23 changes: 16 additions & 7 deletions src/gridcoin/project.h
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,9 @@ class AutoGreylist
// Populate the initial historical entry from the initial baseline.
UpdateHistoryEntry entry = UpdateHistoryEntry(0,
TC_initial_bookmark,
std::optional<uint8_t> {},
std::optional<Fraction> {},
std::optional<bool> {});
std::optional<uint8_t>(),
std::optional<Fraction>(),
std::optional<bool>());

m_update_history.push_back(entry);
}
Expand Down Expand Up @@ -642,7 +642,7 @@ class AutoGreylist
if (sb_from_baseline > 0) {
// ZCD part. Remember we are going backwards, so if total_credit is greater than or equal to
// the bookmark, then we have zero or even negative project total credit between superblocks, so
// this qualifies as a ZCD.
// this qualifies as a ZCD. We look back up to 20 from baseline.
if (sb_from_baseline <= 20) {
// If total credit is greater than the bookmark, this means that (going forward in time) credit actually
// declined, so we must add a day for the credit decline (going forward in time). If total credit
Expand Down Expand Up @@ -684,8 +684,9 @@ class AutoGreylist
uint8_t zcd = GetZCD();
Fraction was = GetWAS();

// Apply rules and determine if greylisting criteria is met.
m_meets_greylisting_crit = (sb_from_baseline >= 2 && (zcd > 7 || was < Fraction(1, 10)));
// Apply rules and determine if greylisting criteria is met. To allow the statistics to stabilize before the
// rules are applied, a seven day grace period is provided after the whitelisting of the project.
m_meets_greylisting_crit = (sb_from_baseline >= 7 && (zcd > 7 || was < Fraction(1, 10)));

// Insert historical entry.
UpdateHistoryEntry entry(sb_from_baseline, total_credit, zcd, was, m_meets_greylisting_crit);
Expand All @@ -702,6 +703,8 @@ class AutoGreylist
//!
//! \param sb_from_baseline_processed
//! \param total_credit
//! \param zcd
//! \param was
//! \param meets_greylisting_crit
//!
UpdateHistoryEntry(uint8_t sb_from_baseline_processed,
Expand Down Expand Up @@ -806,7 +809,13 @@ class AutoGreylist
//! from a scraper convergence, or in the instance of this being called from Refresh(), could be the current
//! superblock on the chain.
//!
void RefreshWithSuperblock(SuperblockPtr superblock_ptr_in);
//! \param unit_test_blocks This is a map that is indexed by height, with linked CBlockIndex* pointers and paired
//! Superblock objects. This is intended as a substitute input structure for unit testing. It is optional and defaults to
//! nullptr, in which case the live chain data is used. One of the entries in the map must correspond to the Superblock_ptr
//! passed as the first parameter.
//!
void RefreshWithSuperblock(SuperblockPtr superblock_ptr_in,
std::shared_ptr<std::map<int, std::pair<CBlockIndex*, SuperblockPtr>>> unit_test_blocks = nullptr);

//!
//! \brief This refreshes the AutoGreylist object from an input Superblock that is going to be associated
Expand Down
22 changes: 11 additions & 11 deletions src/qt/transactiondesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,38 +114,38 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, unsigned int vo
// Update support for Side Stake and correctly show POS/POR as well
strHTML += "<b>" + tr("Source") + ":</b> ";

MinedType gentype = GetGeneratedType(wallet, wtx.GetHash(), vout);
GRC::MinedType gentype = GetGeneratedType(wallet, wtx.GetHash(), vout);

switch (gentype)
{
case MinedType::POS:
case GRC::MinedType::POS:
strHTML += tr("Mined - PoS");
break;
case MinedType::POR:
case GRC::MinedType::POR:
strHTML += tr("Mined - PoS+RR");
break;
case MinedType::ORPHANED:
case GRC::MinedType::ORPHANED:
strHTML += tr("Mined - Orphaned");
break;
case MinedType::POS_SIDE_STAKE_RCV:
case GRC::MinedType::POS_SIDE_STAKE_RCV:
strHTML += tr("PoS Side Stake Received");
break;
case MinedType::POR_SIDE_STAKE_RCV:
case GRC::MinedType::POR_SIDE_STAKE_RCV:
strHTML += tr("PoS+RR Side Stake Received");
break;
case MinedType::POS_SIDE_STAKE_SEND:
case GRC::MinedType::POS_SIDE_STAKE_SEND:
strHTML += tr("PoS Side Stake Sent");
break;
case MinedType::POR_SIDE_STAKE_SEND:
case GRC::MinedType::POR_SIDE_STAKE_SEND:
strHTML += tr("PoS+RR Side Stake Sent");
break;
case MinedType::MRC_RCV:
case GRC::MinedType::MRC_RCV:
strHTML += tr("MRC Payment Received");
break;
case MinedType::MRC_SEND:
case GRC::MinedType::MRC_SEND:
strHTML += tr("MRC Payment Sent");
break;
case MinedType::SUPERBLOCK:
case GRC::MinedType::SUPERBLOCK:
strHTML += tr("Mined - Superblock");
break;
default:
Expand Down
4 changes: 2 additions & 2 deletions src/qt/transactionrecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class TransactionStatus
, sortKey("")
, matures_in(0)
, status(Offline)
, generated_type(MinedType::UNKNOWN)
, generated_type(GRC::MinedType::UNKNOWN)
, depth(0)
, open_for(0)
, cur_num_blocks(-1)
Expand Down Expand Up @@ -54,7 +54,7 @@ class TransactionStatus
/** @name Reported status
@{*/
Status status;
MinedType generated_type;
GRC::MinedType generated_type;
int64_t depth;
int64_t open_for; /**< Timestamp if status==OpenUntilDate, otherwise number
of additional blocks that need to be mined before
Expand Down
40 changes: 20 additions & 20 deletions src/qt/transactiontablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,25 +406,25 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
{
switch (wtx->status.generated_type)
{
case MinedType::POS:
case GRC::MinedType::POS:
return tr("Mined - PoS");
case MinedType::POR:
case GRC::MinedType::POR:
return tr("Mined - PoS+RR");
case MinedType::ORPHANED:
case GRC::MinedType::ORPHANED:
return tr("Mined - Orphaned");
case MinedType::POS_SIDE_STAKE_RCV:
case GRC::MinedType::POS_SIDE_STAKE_RCV:
return tr("PoS Side Stake Received");
case MinedType::POR_SIDE_STAKE_RCV:
case GRC::MinedType::POR_SIDE_STAKE_RCV:
return tr("PoS+RR Side Stake Received");
case MinedType::POS_SIDE_STAKE_SEND:
case GRC::MinedType::POS_SIDE_STAKE_SEND:
return tr("PoS Side Stake Sent");
case MinedType::POR_SIDE_STAKE_SEND:
case GRC::MinedType::POR_SIDE_STAKE_SEND:
return tr("PoS+RR Side Stake Sent");
case MinedType::MRC_RCV:
case GRC::MinedType::MRC_RCV:
return tr("MRC Payment Received");
case MinedType::MRC_SEND:
case GRC::MinedType::MRC_SEND:
return tr("MRC Payment Sent");
case MinedType::SUPERBLOCK:
case GRC::MinedType::SUPERBLOCK:
return tr("Mined - Superblock");
default:
return tr("Mined - Unknown");
Expand Down Expand Up @@ -454,25 +454,25 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx
{
switch (wtx->status.generated_type)
{
case MinedType::POS:
case GRC::MinedType::POS:
return QIcon(":/icons/tx_pos");
case MinedType::POR:
case GRC::MinedType::POR:
return QIcon(":/icons/tx_por");
case MinedType::ORPHANED:
case GRC::MinedType::ORPHANED:
return QIcon(":/icons/transaction_conflicted");
case MinedType::POS_SIDE_STAKE_RCV:
case GRC::MinedType::POS_SIDE_STAKE_RCV:
return QIcon(":/icons/tx_pos_ss");
case MinedType::POR_SIDE_STAKE_RCV:
case GRC::MinedType::POR_SIDE_STAKE_RCV:
return QIcon(":/icons/tx_por_ss");
case MinedType::POS_SIDE_STAKE_SEND:
case GRC::MinedType::POS_SIDE_STAKE_SEND:
return QIcon(":/icons/tx_pos_ss_sent");
case MinedType::POR_SIDE_STAKE_SEND:
case GRC::MinedType::POR_SIDE_STAKE_SEND:
return QIcon(":/icons/tx_por_ss_sent");
case MinedType::MRC_RCV:
case GRC::MinedType::MRC_RCV:
return QIcon(":/icons/tx_por_ss");
case MinedType::MRC_SEND:
case GRC::MinedType::MRC_SEND:
return QIcon(":/icons/tx_por_ss_sent");
case MinedType::SUPERBLOCK:
case GRC::MinedType::SUPERBLOCK:
return QIcon(":/icons/superblock");
default:
return QIcon(":/icons/transaction_0");
Expand Down
Loading

0 comments on commit 8a751ab

Please sign in to comment.