diff --git a/src/gridcoin/project.cpp b/src/gridcoin/project.cpp index 18751fbb63..2a65ac8be5 100644 --- a/src/gridcoin/project.cpp +++ b/src/gridcoin/project.cpp @@ -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>> unit_test_blocks) + EXCLUSIVE_LOCKS_REQUIRED (cs_main) { if (superblock_ptr_in.IsEmpty()) { return; @@ -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()) { @@ -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(std::nullopt)))); + std::optional()))); } } } @@ -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; + } + + } } @@ -482,16 +500,27 @@ void AutoGreylist::RefreshWithSuperblock(SuperblockPtr superblock_ptr_in) EXCLUS // For some reason this is not working. //superblock_ptr.ReadFromDisk(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; - } + SuperblockPtr superblock_ptr; - SuperblockPtr superblock_ptr = block.GetClaim().m_superblock; - superblock_ptr.Rebind(index_ptr); + if (unit_test_blocks == nullptr) { + 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. diff --git a/src/gridcoin/project.h b/src/gridcoin/project.h index 57e3942dfc..5fc9eed33c 100644 --- a/src/gridcoin/project.h +++ b/src/gridcoin/project.h @@ -567,9 +567,9 @@ class AutoGreylist // Populate the initial historical entry from the initial baseline. UpdateHistoryEntry entry = UpdateHistoryEntry(0, TC_initial_bookmark, - std::optional {}, - std::optional {}, - std::optional {}); + std::optional(), + std::optional(), + std::optional()); m_update_history.push_back(entry); } @@ -615,8 +615,8 @@ class AutoGreylist // 64 bit TC averages will overflow a signed 64 integer, and if so, then simply divide by 2 before constructing the // fraction. This is extremely unlikely, given that the number of SB's processed from the baseline would have to be // one, and then the sum overflow the int64_t max. - uint64_t TC_7_SB_avg = m_TC_7_SB_sum / std::min(m_sb_from_baseline_processed, 7); - uint64_t TC_40_SB_avg = m_TC_40_SB_sum / std::min(m_sb_from_baseline_processed, 40); + uint64_t TC_7_SB_avg = m_TC_7_SB_sum / std::min(m_sb_from_baseline_processed, 6); + uint64_t TC_40_SB_avg = m_TC_40_SB_sum / std::min(m_sb_from_baseline_processed, 39); if (TC_7_SB_avg > (uint64_t) std::numeric_limits::max() || TC_40_SB_avg > (uint64_t) std::numeric_limits::max()) { @@ -642,8 +642,8 @@ 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. - if (sb_from_baseline <= 20) { + // this qualifies as a ZCD. We look back up to 19 from baseline (20 SBs total). + 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 // is std::nullopt, then this means no statistics available, which also is a ZCD. @@ -652,7 +652,7 @@ class AutoGreylist } } - // WAS part. Here we deal with two numbers, the 40 SB from baseline, and the 7 SB from baseline. We use + // WAS part. Here we deal with two numbers, the 40 SB (39 from baseline), and the 7 SB (6 from baseline). We use // the initial bookmark, and compute the difference, which is the same as adding up the deltas between // the TC's in each superblock. For updates with no total credit entry (i.e. std::optional is nullopt), // do not change the sums. @@ -664,11 +664,11 @@ class AutoGreylist } if (total_credit && m_TC_initial_bookmark > total_credit) { - if (sb_from_baseline <= 7) { + if (sb_from_baseline < 7) { m_TC_7_SB_sum = *m_TC_initial_bookmark - *total_credit; } - if (sb_from_baseline <= 40) { + if (sb_from_baseline < 40) { m_TC_40_SB_sum = *m_TC_initial_bookmark - *total_credit; } } @@ -685,7 +685,7 @@ class AutoGreylist 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))); + m_meets_greylisting_crit = (sb_from_baseline >= 1 && (zcd > 7 || was < Fraction(1, 10))); // Insert historical entry. UpdateHistoryEntry entry(sb_from_baseline, total_credit, zcd, was, m_meets_greylisting_crit); @@ -702,6 +702,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, @@ -806,7 +808,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>> unit_test_blocks = nullptr); //! //! \brief This refreshes the AutoGreylist object from an input Superblock that is going to be associated diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index e04bb67af0..047d636607 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -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 += "" + tr("Source") + ": "; - 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: diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 4bd8c075d7..6c64ef2ed3 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -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) @@ -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 diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 48b26bdbaf..2c9835e065 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -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"); @@ -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"); diff --git a/src/test/gridcoin/project_tests.cpp b/src/test/gridcoin/project_tests.cpp index fb10a2defe..46b56a9c0d 100644 --- a/src/test/gridcoin/project_tests.cpp +++ b/src/test/gridcoin/project_tests.cpp @@ -5,6 +5,7 @@ #include "main.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" +#include "wallet/generated_type.h" #include @@ -98,6 +99,41 @@ void DeleteProjectEntry(const uint32_t& payload_version, const std::string& name registry.Add({contract, dummy_tx, &dummy_index}); } +struct AutoGreylistEntryState +{ + AutoGreylistEntryState(uint8_t zcd_20_SB_count, + uint64_t TC_7_SB_sum, + uint64_t TC_40_SB_sum, + bool meets_greylisting_crit) + : m_zcd_20_SB_count(zcd_20_SB_count) + , m_TC_7_SB_sum(TC_7_SB_sum) + , m_TC_40_SB_sum(TC_40_SB_sum) + ,m_meets_greylisting_crit(meets_greylisting_crit) + {} + + uint8_t m_zcd_20_SB_count; + uint64_t m_TC_7_SB_sum; + uint64_t m_TC_40_SB_sum; + bool m_meets_greylisting_crit; + + bool operator==(const AutoGreylistEntryState& rhs) + { + bool equal = ( + (m_zcd_20_SB_count == rhs.m_zcd_20_SB_count) + && (m_TC_7_SB_sum == rhs.m_TC_7_SB_sum) + && (m_TC_40_SB_sum == rhs.m_TC_40_SB_sum) + && (m_meets_greylisting_crit == rhs.m_meets_greylisting_crit) + ); + + return equal; + } + + bool operator!=(const AutoGreylistEntryState& rhs) + { + return !(*this == rhs); + } +}; + //! //! \brief Dummy transaction for contract handler API. //! @@ -550,4 +586,703 @@ BOOST_AUTO_TEST_CASE(it_overwrites_projects_with_the_same_name) } } +BOOST_AUTO_TEST_CASE(it_auto_greylists_correctly) +{ + GRC::Whitelist& whitelist = GRC::GetWhitelist(); + + std::shared_ptr auto_greylist = GRC::GetAutoGreylistCache(); + + std::vector, + AutoGreylistEntryState>> input_expected_result_proj_tc_history; + + whitelist.Reset(); // Also resets auto_greylist. + + int height = 0; + int64_t time = 0; + + auto unit_test_blocks = std::make_shared>>(); + + // Add a project for testing. + AddProjectEntry(3, "autogreylist_test", "http://autogreylist.test", false, height, time, true); + + ++height; + ++time; + + CBlockIndex* index_ptr = new CBlockIndex; + CBlockIndex* index_ptr_prev; + + // superblock 0 - baseline after whitelisting, but no stats due to problem with project. + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + std::optional(), + AutoGreylistEntryState( + 0, // zcd_20_SB_count + 0, // TC_7_SB_sum + 0, // TC_40_SB_sum + false // meets_greylist_crit + ) + ) + ); + + // superblock 1 - first stats collection from project, TC = 1000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 1000, + AutoGreylistEntryState( + 1, + 0, + 0, + true + ) + ) + ); + + // superblock 2 - no stats again due to problem with project + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + std::optional(), + AutoGreylistEntryState( + 2, + 0, + 0, + true + ) + ) + ); + + // superblock 3 - no status again due to continuing problem with project + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + std::optional(), + AutoGreylistEntryState( + 3, + 0, + 0, + true + ) + ) + ); + + // superblock 4 - successful stats collection, but TC = 1000 still + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 1000, + AutoGreylistEntryState( + 4, + 0, + 0, + true + ) + ) + ); + + // superblock 5 - successful stats collection, TC = 2000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 2000, + AutoGreylistEntryState( + 4, + 1000, + 1000, + false + ) + ) + ); + + // superblock 6 - successful stats collection, TC = 3000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 3000, + AutoGreylistEntryState( + 4, + 2000, + 2000, + false + ) + ) + ); + + // superblock 7 - problem with stats collection + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + std::optional(), + AutoGreylistEntryState( + 5, + 2000, + 2000, + false + ) + ) + ); + + // superblock 8 - successful stats collection, TC = 3000 still + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 3000, + AutoGreylistEntryState( + 6, + 2000, + 2000, + false + ) + ) + ); + + // superblock 9 - successful stats collection, TC = 4000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 4000, + AutoGreylistEntryState( + 6, + 3000, + 3000, + false + ) + ) + ); + + // superblock 10 - successful stats collection, TC = 5000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5000, + AutoGreylistEntryState( + 6, + 4000, + 4000, + false + ) + ) + ); + + // superblock 11 - successful stats collection, TC = 5000 still + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5000, + AutoGreylistEntryState( + 7, + 3000, + 4000, + false + ) + ) + ); + + // superblock 12 - problem with stats collection + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + std::optional(), + AutoGreylistEntryState( + 8, + 2000, + 4000, + true + ) + ) + ); + + // superblock 13 - successful stats collection, reduced output TC = 5001 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5001, + AutoGreylistEntryState( + 8, + 2001, + 4001, + true + ) + ) + ); + + // superblock 14 - successful stats collection, reduced output TC = 5002 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5002, + AutoGreylistEntryState( + 8, + 2002, + 4002, + true + ) + ) + ); + + // superblock 15 - successful stats collection, reduced output TC = 5003 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5003, + AutoGreylistEntryState( + 8, + 1003, + 4003, + true + ) + ) + ); + + // superblock 16 - successful stats collection, reduced output TC = 5004 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5004, + AutoGreylistEntryState( + 8, + 4, + 4004, + true + ) + ) + ); + + // superblock 17 - successful stats collection, slightly improved output TC = 5200 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5200, + AutoGreylistEntryState( + 8, + 200, + 4200, + true + ) + ) + ); + + // superblock 18 - successful stats collection, degraded output TC = 5225 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5225, + AutoGreylistEntryState( + 8, + 224, + 4225, + true + ) + ) + ); + + // superblock 19 - successful stats collection, degraded output TC = 5230 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5230, + AutoGreylistEntryState( + 8, + 229, + 4230, + true + ) + ) + ); + + // superblock 20 - successful stats collection, further degraded output TC = 5231 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5231, + AutoGreylistEntryState( + 7, + 229, + 4231, + false + ) + ) + ); + + // superblock 21 - successful stats collection, further degraded output TC = 5232 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5232, + AutoGreylistEntryState( + 6, + 229, + 4232, + false + ) + ) + ); + + // superblock 22 - successful stats collection, further degraded output TC = 5233 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5233, + AutoGreylistEntryState( + 5, + 229, + 4233, + false + ) + ) + ); + + // superblock 23 - successful stats collection, further degraded output TC = 5234 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5234, + AutoGreylistEntryState( + 4, + 34, + 4234, + true + ) + ) + ); + + // superblock 24 - successful stats collection, further degraded output TC = 5235 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5235, + AutoGreylistEntryState( + 4, + 10, + 4235, + true + ) + ) + ); + + // superblock 25 - successful stats collection, degraded output TC = 5250 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 5250, + AutoGreylistEntryState( + 4, + 20, + 4250, + true + ) + ) + ); + + // superblock 26 - successful stats collection, resume "normal" output TC = 6250 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 6250, + AutoGreylistEntryState( + 3, + 1019, + 5250, + false + ) + ) + ); + + // superblock 27 - successful stats collection, TC = 7000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 7000, + AutoGreylistEntryState( + 2, + 1768, + 6000, + false + ) + ) + ); + + // superblock 28 - successful stats collection, TC = 8000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 8000, + AutoGreylistEntryState( + 2, + 2767, + 7000, + false + ) + ) + ); + + // superblock 29 - successful stats collection, TC = 9000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 9000, + AutoGreylistEntryState( + 2, + 3766, + 8000, + false + ) + ) + ); + + // superblock 30 - successful stats collection, TC = 10000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 10000, + AutoGreylistEntryState( + 1, + 4765, + 9000, + false + ) + ) + ); + + // superblock 31 - successful stats collection, TC = 11000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 11000, + AutoGreylistEntryState( + 1, + 5750, + 10000, + false + ) + ) + ); + + // superblock 32 - successful stats collection, TC = 12000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 12000, + AutoGreylistEntryState( + 0, + 5750, + 11000, + false + ) + ) + ); + + // superblock 33 - successful stats collection, TC = 13000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 13000, + AutoGreylistEntryState( + 0, + 6000, + 12000, + false + ) + ) + ); + + // superblock 34 - successful stats collection, TC = 14000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 14000, + AutoGreylistEntryState( + 0, + 6000, + 13000, + false + ) + ) + ); + // superblock 35 - successful stats collection, TC = 15000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 15000, + AutoGreylistEntryState( + 0, + 6000, + 14000, + false + ) + ) + ); + // superblock 36 - successful stats collection, TC = 16000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 16000, + AutoGreylistEntryState( + 0, + 6000, + 15000, + false + ) + ) + ); + // superblock 37 - successful stats collection, TC = 17000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 17000, + AutoGreylistEntryState( + 0, + 6000, + 16000, + false + ) + ) + ); + // superblock 38 - successful stats collection, TC = 18000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 18000, + AutoGreylistEntryState( + 0, + 6000, + 17000, + false + ) + ) + ); + // superblock 39 - successful stats collection, TC = 19000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 19000, + AutoGreylistEntryState( + 0, + 6000, + 18000, + false + ) + ) + ); + // superblock 40 - successful stats collection, TC = 20000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 20000, + AutoGreylistEntryState( + 0, + 6000, + 19000, + false + ) + ) + ); + + // superblock 41 - successful stats collection, TC = 21000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 21000, + AutoGreylistEntryState( + 0, + 6000, + 20000, + false + ) + ) + ); + + // superblock 42 - successful stats collection, TC = 22000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 22000, + AutoGreylistEntryState( + 0, + 6000, + 21000, + false + ) + ) + ); + + // superblock 43 - successful stats collection, TC = 23000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 23000, + AutoGreylistEntryState( + 0, + 6000, + 22000, + false + ) + ) + ); + + // superblock 44 - successful stats collection, TC = 24000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 24000, + AutoGreylistEntryState( + 0, + 6000, + 22000, + false + ) + ) + ); + + // superblock 45 - successful stats collection, TC = 25000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 25000, + AutoGreylistEntryState( + 0, + 6000, + 22000, + false + ) + ) + ); + + // superblock 46 - successful stats collection, TC = 26000 + input_expected_result_proj_tc_history.push_back( + std::make_tuple( + 26000, + AutoGreylistEntryState( + 0, + 6000, + 23000, + false + ) + ) + ); + + for (auto iter : input_expected_result_proj_tc_history) { + // Reset the auto greylist + auto_greylist->Reset(); + + // Build a fake superblock ptr for the test. + index_ptr_prev = index_ptr; + + index_ptr = new CBlockIndex; + + index_ptr->nHeight = height; + index_ptr->nTime = time; + index_ptr->MarkAsSuperblock(); + index_ptr->pprev = index_ptr_prev; + + GRC::Superblock superblock = GRC::Superblock(); + + // If the optional is nullopt, then don't insert into the superblock. + if (std::get<0>(iter)) { + superblock.m_projects_all_cpids_total_credits.m_projects_all_cpid_total_credits + .insert(std::make_pair("autogreylist_test", *std::get<0>(iter))); + } + + GRC::SuperblockPtr superblock_ptr = GRC::SuperblockPtr(); + superblock_ptr.Replace(superblock); + superblock_ptr.Rebind(index_ptr); + + unit_test_blocks->insert(std::make_pair(height, std::make_pair(index_ptr, superblock_ptr))); + + auto_greylist->RefreshWithSuperblock(superblock_ptr, unit_test_blocks); + + // Only one project in the test. + auto greylist_candidate = auto_greylist->begin()->second; + auto last_history_entry = greylist_candidate.GetUpdateHistory().back(); + + AutoGreylistEntryState entry_state_lhs(greylist_candidate.m_zcd_20_SB_count, + greylist_candidate.m_TC_7_SB_sum, + greylist_candidate.m_TC_40_SB_sum, + greylist_candidate.m_meets_greylisting_crit); + + AutoGreylistEntryState entry_state_rhs = std::get<1>(iter); + + LogPrintf("info: %s, height %i, sb %i", "it_auto_greylists_correctly", height, height - 1); + + if (entry_state_lhs != entry_state_rhs) { + error("%s:\n" + "lhs: zcd_20_SB_count = %u, TC_7_SB_sum = %" PRId64 ", TC_40_SB_sum = %" PRId64 + ", meets_greylisting_crit = %u \n" + "rhs: zcd_20_SB_count = %u, TC_7_SB_sum = %" PRId64 ", TC_40_SB_sum = %" PRId64 + ", meets_greylisting_crit = %u", + "it_auto_greylists_correctly", + entry_state_lhs.m_zcd_20_SB_count, + entry_state_lhs.m_TC_7_SB_sum, + entry_state_lhs.m_TC_40_SB_sum, + entry_state_lhs.m_meets_greylisting_crit, + entry_state_rhs.m_zcd_20_SB_count, + entry_state_rhs.m_TC_7_SB_sum, + entry_state_rhs.m_TC_40_SB_sum, + entry_state_rhs.m_meets_greylisting_crit + ); + } + + BOOST_CHECK(entry_state_lhs == entry_state_rhs); + + ++height; + } + + +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/generated_type.h b/src/wallet/generated_type.h index 0d2b28ca55..1cd659bfa6 100644 --- a/src/wallet/generated_type.h +++ b/src/wallet/generated_type.h @@ -6,6 +6,7 @@ #define BITCOIN_WALLET_GENERATED_TYPE_H /** (POS/POR) enums for CoinStake Transactions -- We should never get unknown but just in case!*/ +namespace GRC { enum MinedType { UNKNOWN = 0, @@ -20,5 +21,6 @@ enum MinedType MRC_RCV = 9, MRC_SEND = 10 }; +} #endif // BITCOIN_WALLET_GENERATED_TYPE_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 75214478b2..ae54b86deb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1430,18 +1430,18 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) else entry.pushKV("category", "generate"); - MinedType gentype = GetGeneratedType(pwalletMain, wtx.GetHash(), s.vout); + GRC::MinedType gentype = GetGeneratedType(pwalletMain, wtx.GetHash(), s.vout); switch (gentype) { - case MinedType::POR : entry.pushKV("type", "POR"); break; - case MinedType::POS : entry.pushKV("type", "POS"); break; - case MinedType::ORPHANED : entry.pushKV("type", "ORPHANED"); break; - case MinedType::POS_SIDE_STAKE_RCV : entry.pushKV("type", "POS SIDE STAKE RECEIVED"); break; - case MinedType::POR_SIDE_STAKE_RCV : entry.pushKV("type", "POR SIDE STAKE RECEIVED"); break; - case MinedType::POS_SIDE_STAKE_SEND : entry.pushKV("type", "POS SIDE STAKE SENT"); break; - case MinedType::POR_SIDE_STAKE_SEND : entry.pushKV("type", "POR SIDE STAKE SENT"); break; - case MinedType::MRC_SEND : entry.pushKV("type", "MRC PAYMENT SENT"); break; + case GRC::MinedType::POR : entry.pushKV("type", "POR"); break; + case GRC::MinedType::POS : entry.pushKV("type", "POS"); break; + case GRC::MinedType::ORPHANED : entry.pushKV("type", "ORPHANED"); break; + case GRC::MinedType::POS_SIDE_STAKE_RCV : entry.pushKV("type", "POS SIDE STAKE RECEIVED"); break; + case GRC::MinedType::POR_SIDE_STAKE_RCV : entry.pushKV("type", "POR SIDE STAKE RECEIVED"); break; + case GRC::MinedType::POS_SIDE_STAKE_SEND : entry.pushKV("type", "POS SIDE STAKE SENT"); break; + case GRC::MinedType::POR_SIDE_STAKE_SEND : entry.pushKV("type", "POR SIDE STAKE SENT"); break; + case GRC::MinedType::MRC_SEND : entry.pushKV("type", "MRC PAYMENT SENT"); break; default : entry.pushKV("type", "UNKNOWN"); break; } } @@ -1490,24 +1490,24 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) else entry.pushKV("category", "generate"); - MinedType gentype = GetGeneratedType(pwalletMain, wtx.GetHash(), r.vout); + GRC::MinedType gentype = GetGeneratedType(pwalletMain, wtx.GetHash(), r.vout); switch (gentype) { - case MinedType::POR : entry.pushKV("Type", "POR"); break; - case MinedType::POS : entry.pushKV("Type", "POS"); break; - case MinedType::ORPHANED : entry.pushKV("Type", "ORPHANED"); break; - case MinedType::POS_SIDE_STAKE_RCV : entry.pushKV("Type", "POS SIDE STAKE RECEIVED"); break; - case MinedType::POR_SIDE_STAKE_RCV : entry.pushKV("Type", "POR SIDE STAKE RECEIVED"); break; - case MinedType::POS_SIDE_STAKE_SEND : entry.pushKV("Type", "POS SIDE STAKE SENT"); break; - case MinedType::POR_SIDE_STAKE_SEND : entry.pushKV("Type", "POR SIDE STAKE SENT"); break; - case MinedType::MRC_RCV : entry.pushKV("Type", "MRC PAYMENT RECEIVED"); break; - case MinedType::MRC_SEND : entry.pushKV("Type", "MRC PAYMENT SENT"); break; + case GRC::MinedType::POR : entry.pushKV("Type", "POR"); break; + case GRC::MinedType::POS : entry.pushKV("Type", "POS"); break; + case GRC::MinedType::ORPHANED : entry.pushKV("Type", "ORPHANED"); break; + case GRC::MinedType::POS_SIDE_STAKE_RCV : entry.pushKV("Type", "POS SIDE STAKE RECEIVED"); break; + case GRC::MinedType::POR_SIDE_STAKE_RCV : entry.pushKV("Type", "POR SIDE STAKE RECEIVED"); break; + case GRC::MinedType::POS_SIDE_STAKE_SEND : entry.pushKV("Type", "POS SIDE STAKE SENT"); break; + case GRC::MinedType::POR_SIDE_STAKE_SEND : entry.pushKV("Type", "POR SIDE STAKE SENT"); break; + case GRC::MinedType::MRC_RCV : entry.pushKV("Type", "MRC PAYMENT RECEIVED"); break; + case GRC::MinedType::MRC_SEND : entry.pushKV("Type", "MRC PAYMENT SENT"); break; default : entry.pushKV("Type", "UNKNOWN"); break; } // Skip posting this entry if stakes only is desired and not an actual stake. - if (stakes_only && gentype != MinedType::POR && gentype != MinedType::POS) continue; + if (stakes_only && gentype != GRC::MinedType::POR && gentype != GRC::MinedType::POS) continue; } else { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 504532c160..af941b6880 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3040,39 +3040,39 @@ void CWallet::StoreLastBackupTime(const int64_t backup_time) CWalletDB(strWalletFile).WriteBackupTime(backup_time); } -MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned int vout) +GRC::MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned int vout) { CWalletTx wallettx; uint256 hashblock; if (!GetTransaction(tx, wallettx, hashblock)) - return MinedType::ORPHANED; + return GRC::MinedType::ORPHANED; BlockMap::iterator mi = mapBlockIndex.find(hashblock); if (mi == mapBlockIndex.end()) { - return MinedType::UNKNOWN; + return GRC::MinedType::UNKNOWN; } CBlockIndex* blkindex = mi->second; // If we are calling GetGeneratedType, this is a transaction // that corresponds (is integral to) the block. We check whether - // the block is a superblock, and if so we set the MinedType to + // the block is a superblock, and if so we set the GRC::MinedType to // SUPERBLOCK if vout is 1 as that should override the others here. if (vout == 1 && blkindex->IsSuperblock()) { - return MinedType::SUPERBLOCK; + return GRC::MinedType::SUPERBLOCK; } // Basic CoinStake Support if (wallettx.vout.size() == 2) { if (blkindex->ResearchSubsidy() == 0) - return MinedType::POS; + return GRC::MinedType::POS; else - return MinedType::POR; + return GRC::MinedType::POR; } // Side/Split Stake Support @@ -3091,10 +3091,10 @@ MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned in if (fIsCoinStakeMine && wallettx.vout[vout].scriptPubKey == wallettx.vout[1].scriptPubKey) { if (blkindex->ResearchSubsidy() == 0) - return MinedType::POS; + return GRC::MinedType::POS; else - return MinedType::POR; + return GRC::MinedType::POR; } else { @@ -3105,20 +3105,20 @@ MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned in if (fIsOutputMine) { if (blkindex->ResearchSubsidy() == 0) - return MinedType::POS_SIDE_STAKE_RCV; + return GRC::MinedType::POS_SIDE_STAKE_RCV; else - return MinedType::POR_SIDE_STAKE_RCV; + return GRC::MinedType::POR_SIDE_STAKE_RCV; } // ... or the output is not mine, then this must be a // sidestake sent to someone else or an MRC payment. else { if (blkindex->ResearchSubsidy() == 0 && vout < mrc_index_start) { - return MinedType::POS_SIDE_STAKE_SEND; + return GRC::MinedType::POS_SIDE_STAKE_SEND; } else if (vout >= mrc_index_start) { - return MinedType::MRC_SEND; + return GRC::MinedType::MRC_SEND; } else { - return MinedType::POR_SIDE_STAKE_SEND; + return GRC::MinedType::POR_SIDE_STAKE_SEND; } } } @@ -3130,11 +3130,11 @@ MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned in if (fIsOutputMine) { if (blkindex->ResearchSubsidy() == 0 && vout < mrc_index_start) { - return MinedType::POS_SIDE_STAKE_RCV; + return GRC::MinedType::POS_SIDE_STAKE_RCV; } else if (vout >= mrc_index_start) { - return MinedType::MRC_RCV; + return GRC::MinedType::MRC_RCV; } else { - return MinedType::POR_SIDE_STAKE_RCV; + return GRC::MinedType::POR_SIDE_STAKE_RCV; } } @@ -3144,7 +3144,7 @@ MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned in } } - return MinedType::UNKNOWN; + return GRC::MinedType::UNKNOWN; } bool CWallet::UpgradeWallet(int version, std::string& error) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5bf9f9dcef..0eda1ec7ef 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -35,7 +35,7 @@ class CReserveKey; class COutput; class CCoinControl; -MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned int vout); +GRC::MinedType GetGeneratedType(const CWallet *wallet, const uint256& tx, unsigned int vout); static const unsigned int DEFAULT_KEYPOOL_SIZE = 100; static const unsigned int DEFAULT_KEYPOOL_SIZE_PRE_HD = 1000; @@ -887,7 +887,7 @@ class CWalletTx : public CMerkleTx bool RevalidateTransaction(CTxDB& txdb); - MinedType GetGeneratedType(uint32_t vout_offset) const + GRC::MinedType GetGeneratedType(uint32_t vout_offset) const { return ::GetGeneratedType(pwallet, GetHash(), vout_offset); }