Merge #6318: refactor: remove circular dependency governance/object over governance/classes

2e36832982 refactor: drop circular dependency governance/classes over governance/governance (Konstantin Akimov)
39f18ab154 refactor: move CGoveranceManager code from classes.cpp to governace.cpp (Konstantin Akimov)
350a5ca47c refactor: drop CSuperblock::GetGovernanceObject to simplify thread safety analysis over FindGovernanceObject (Konstantin Akimov)
5031f29441 refactor: add couple missing `const` for CGovernanceManager (Konstantin Akimov)
b240d08e09 refactor: move GetBestSuperblock to CGovernanceManager (Konstantin Akimov)
3641653174 refactor: move CSuperblockManager::IsValid to CGoveranceManager::IsValidSuperblock (Konstantin Akimov)
de8969f463 refactor: move ExecuteBestSuperblock to CGovernanceManager (Konstantin Akimov)
107d5b4941 refactor: move GetSuperblockPayments to CGovernanceManager (Konstantin Akimov)
7a470c441e refactor: move IsSuperblockTriggered to CGovernanceManager (Konstantin Akimov)
9638fdce6d refactor: pass mn_sync to CGovernanceManager ctor as a reference (UdjinM6)
7eb1634686 refactor: drop alias that is used only once (Konstantin Akimov)
1570a02c89 refactor: move ScopedLockBool from header to cpp file (Konstantin Akimov)
7aafb5a393 fix: add one more file to list of non-backported (flat-database.h) (Konstantin Akimov)
41f1a43236 fix: add missing const for member functions of CRateCheckBuffer (Konstantin Akimov)
982fc9a069 fix: avoid lock annotation for govman.cs in voteraw (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  This PR is preparation for bitcoin#19668, otherwise impossible to make lock annotations for CGovernanceManager properly.

  ## What was done?
  1. object mn_sync and peerman is pass to many methods of CGovernanceManager instead passing it to constructor.
  2. methods of class CSuperblockManager moved to CGovernanceManager where they belongs to.
  3. removed `CSuperblock::GetGovernanceObject` which makes a lot of mess with annotations of `govman.cs`

  And minor relevant improvements: moved ScopedLockBool from header to implementation, added multiple `const` for methods, added one more file `flat-database.h` to non-backported list

  ## How Has This Been Tested?
  Run unit and functional tests.

  ## Breaking Changes
  N/A

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas
  - [x] I have added or updated relevant unit/integration/functional/e2e tests
  - [x] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone

ACKs for top commit:
  UdjinM6:
    utACK 2e36832982
  PastaPastaPasta:
    utACK 2e36832982

Tree-SHA512: 59842c208f7ece46c9381fc3f9fc838d9ed1cf0fd2404eebf7fbd656c5df1fa5fd339410da83088089e2d954a017efb518cba290f6c5d45b5bcb91818041f931
This commit is contained in:
pasta 2024-10-08 17:08:33 -05:00
commit f93c763ac6
No known key found for this signature in database
GPG Key ID: E2F3D7916E722D38
14 changed files with 423 additions and 444 deletions

View File

@ -117,9 +117,9 @@ private:
}
try {
unsigned char pchMsgTmp[4];
std::string strMagicMessageTmp;
try {
// de-serialize file header (file specific magic message) and ..
ssObj >> strMagicMessageTmp;
@ -178,11 +178,11 @@ private:
}
public:
CFlatDB(std::string strFilenameIn, std::string strMagicMessageIn)
CFlatDB(std::string&& strFilenameIn, std::string&& strMagicMessageIn) :
pathDB{gArgs.GetDataDirNet() / strFilenameIn},
strFilename{strFilenameIn},
strMagicMessage{strMagicMessageIn}
{
pathDB = gArgs.GetDataDirNet() / strFilenameIn;
strFilename = strFilenameIn;
strMagicMessage = strMagicMessageIn;
}
bool Load(T& objToLoad)
@ -191,7 +191,7 @@ public:
return Read(objToLoad);
}
bool Store(T& objToSave)
bool Store(const T& objToSave)
{
LogPrintf("Verifying %s format...\n", strFilename);
T tmpObjToLoad;

View File

@ -8,7 +8,6 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <deploymentstatus.h>
#include <governance/governance.h>
#include <key_io.h>
#include <primitives/transaction.h>
#include <script/standard.h>
@ -94,300 +93,6 @@ CAmount ParsePaymentAmount(const std::string& strAmount)
return nAmount;
}
/**
* Add Governance Object
*/
bool CGovernanceManager::AddNewTrigger(uint256 nHash)
{
AssertLockHeld(cs);
// IF WE ALREADY HAVE THIS HASH, RETURN
if (mapTrigger.count(nHash)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Already have hash, nHash = %s, count = %d, size = %s\n",
__func__, nHash.GetHex(), mapTrigger.count(nHash), mapTrigger.size());
return false;
}
CSuperblock_sptr pSuperblock;
try {
auto pSuperblockTmp = std::make_shared<CSuperblock>(*this, nHash);
pSuperblock = pSuperblockTmp;
} catch (std::exception& e) {
LogPrintf("CGovernanceManager::%s -- Error creating superblock: %s\n", __func__, e.what());
return false;
} catch (...) {
LogPrintf("CGovernanceManager::%s -- Unknown Error creating superblock\n", __func__);
return false;
}
pSuperblock->SetStatus(SeenObjectStatus::Valid);
mapTrigger.insert(std::make_pair(nHash, pSuperblock));
return !pSuperblock->IsExpired(*this);
}
/**
*
* Clean And Remove
*
*/
void CGovernanceManager::CleanAndRemoveTriggers()
{
AssertLockHeld(cs);
// Remove triggers that are invalid or expired
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- mapTrigger.size() = %d\n", __func__, mapTrigger.size());
auto it = mapTrigger.begin();
while (it != mapTrigger.end()) {
bool remove = false;
CGovernanceObject* pObj = nullptr;
const CSuperblock_sptr& pSuperblock = it->second;
if (!pSuperblock) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- nullptr superblock\n", __func__);
remove = true;
} else {
pObj = FindGovernanceObject(it->first);
if (!pObj || pObj->GetObjectType() != GovernanceObject::TRIGGER) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or non-trigger superblock\n", __func__);
pSuperblock->SetStatus(SeenObjectStatus::ErrorInvalid);
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- superblock status = %d\n", __func__, ToUnderlying(pSuperblock->GetStatus()));
switch (pSuperblock->GetStatus()) {
case SeenObjectStatus::ErrorInvalid:
case SeenObjectStatus::Unknown:
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or invalid trigger found\n", __func__);
remove = true;
break;
case SeenObjectStatus::Valid:
case SeenObjectStatus::Executed: {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Valid trigger found\n", __func__);
if (pSuperblock->IsExpired(*this)) {
// update corresponding object
pObj->SetExpired();
remove = true;
}
break;
}
default:
break;
}
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- %smarked for removal\n", __func__, remove ? "" : "NOT ");
if (remove) {
std::string strDataAsPlainString = "nullptr";
if (pObj) {
strDataAsPlainString = pObj->GetDataAsPlainString();
// mark corresponding object for deletion
pObj->PrepareDeletion(GetTime<std::chrono::seconds>().count());
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Removing trigger object %s\n", __func__, strDataAsPlainString);
// delete the trigger
mapTrigger.erase(it++);
} else {
++it;
}
}
}
/**
* Get Active Triggers
*
* - Look through triggers and scan for active ones
* - Return the triggers in a list
*/
std::vector<CSuperblock_sptr> CGovernanceManager::GetActiveTriggers()
{
AssertLockHeld(cs);
std::vector<CSuperblock_sptr> vecResults;
// LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS
for (const auto& pair : mapTrigger) {
const CGovernanceObject* pObj = FindConstGovernanceObject(pair.first);
if (pObj) {
vecResults.push_back(pair.second);
}
}
return vecResults;
}
/**
* Is Superblock Triggered
*
* - Does this block have a non-executed and activated trigger?
*/
bool CSuperblockManager::IsSuperblockTriggered(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight)
{
LogPrint(BCLog::GOBJECT, "CSuperblockManager::IsSuperblockTriggered -- Start nBlockHeight = %d\n", nBlockHeight);
if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) {
return false;
}
LOCK(govman.cs);
// GET ALL ACTIVE TRIGGERS
std::vector<CSuperblock_sptr> vecTriggers = govman.GetActiveTriggers();
LogPrint(BCLog::GOBJECT, "CSuperblockManager::IsSuperblockTriggered -- vecTriggers.size() = %d\n", vecTriggers.size());
for (const auto& pSuperblock : vecTriggers) {
if (!pSuperblock) {
LogPrintf("CSuperblockManager::IsSuperblockTriggered -- Non-superblock found, continuing\n");
continue;
}
CGovernanceObject* pObj = pSuperblock->GetGovernanceObject(govman);
if (!pObj) {
LogPrintf("CSuperblockManager::IsSuperblockTriggered -- pObj == nullptr, continuing\n");
continue;
}
LogPrint(BCLog::GOBJECT, "CSuperblockManager::IsSuperblockTriggered -- data = %s\n", pObj->GetDataAsPlainString());
// note : 12.1 - is epoch calculation correct?
if (nBlockHeight != pSuperblock->GetBlockHeight()) {
LogPrint(BCLog::GOBJECT, "CSuperblockManager::IsSuperblockTriggered -- block height doesn't match nBlockHeight = %d, blockStart = %d, continuing\n",
nBlockHeight,
pSuperblock->GetBlockHeight());
continue;
}
// MAKE SURE THIS TRIGGER IS ACTIVE VIA FUNDING CACHE FLAG
pObj->UpdateSentinelVariables(tip_mn_list);
if (pObj->IsSetCachedFunding()) {
LogPrint(BCLog::GOBJECT, "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = true, returning true\n");
return true;
} else {
LogPrint(BCLog::GOBJECT, "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = false, continuing\n");
}
}
return false;
}
bool CSuperblockManager::GetBestSuperblock(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, int nBlockHeight)
{
if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) {
return false;
}
AssertLockHeld(govman.cs);
std::vector<CSuperblock_sptr> vecTriggers = govman.GetActiveTriggers();
int nYesCount = 0;
for (const auto& pSuperblock : vecTriggers) {
if (!pSuperblock || nBlockHeight != pSuperblock->GetBlockHeight()) {
continue;
}
const CGovernanceObject* pObj = pSuperblock->GetGovernanceObject(govman);
if (!pObj) {
continue;
}
// DO WE HAVE A NEW WINNER?
int nTempYesCount = pObj->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING);
if (nTempYesCount > nYesCount) {
nYesCount = nTempYesCount;
pSuperblockRet = pSuperblock;
}
}
return nYesCount > 0;
}
/**
* Get Superblock Payments
*
* - Returns payments for superblock
*/
bool CSuperblockManager::GetSuperblockPayments(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight, std::vector<CTxOut>& voutSuperblockRet)
{
LOCK(govman.cs);
// GET THE BEST SUPERBLOCK FOR THIS BLOCK HEIGHT
CSuperblock_sptr pSuperblock;
if (!CSuperblockManager::GetBestSuperblock(govman, tip_mn_list, pSuperblock, nBlockHeight)) {
LogPrint(BCLog::GOBJECT, "CSuperblockManager::GetSuperblockPayments -- Can't find superblock for height %d\n", nBlockHeight);
return false;
}
// make sure it's empty, just in case
voutSuperblockRet.clear();
// GET SUPERBLOCK OUTPUTS
// Superblock payments will be appended to the end of the coinbase vout vector
// TODO: How many payments can we add before things blow up?
// Consider at least following limits:
// - max coinbase tx size
// - max "budget" available
for (int i = 0; i < pSuperblock->CountPayments(); i++) {
CGovernancePayment payment;
if (pSuperblock->GetPayment(i, payment)) {
// SET COINBASE OUTPUT TO SUPERBLOCK SETTING
CTxOut txout = CTxOut(payment.nAmount, payment.script);
voutSuperblockRet.push_back(txout);
// PRINT NICE LOG OUTPUT FOR SUPERBLOCK PAYMENT
CTxDestination dest;
ExtractDestination(payment.script, dest);
LogPrint(BCLog::GOBJECT, "CSuperblockManager::GetSuperblockPayments -- NEW Superblock: output %d (addr %s, amount %d.%08d)\n",
i, EncodeDestination(dest), payment.nAmount / COIN, payment.nAmount % COIN);
} else {
LogPrint(BCLog::GOBJECT, "CSuperblockManager::GetSuperblockPayments -- Payment not found\n");
}
}
return true;
}
bool CSuperblockManager::IsValid(CGovernanceManager& govman, const CChain& active_chain, const CDeterministicMNList& tip_mn_list, const CTransaction& txNew, int nBlockHeight, CAmount blockReward)
{
// GET BEST SUPERBLOCK, SHOULD MATCH
LOCK(govman.cs);
CSuperblock_sptr pSuperblock;
if (CSuperblockManager::GetBestSuperblock(govman, tip_mn_list, pSuperblock, nBlockHeight)) {
return pSuperblock->IsValid(govman, active_chain, txNew, nBlockHeight, blockReward);
}
return false;
}
void CSuperblockManager::ExecuteBestSuperblock(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight)
{
LOCK(govman.cs);
CSuperblock_sptr pSuperblock;
if (GetBestSuperblock(govman, tip_mn_list, pSuperblock, nBlockHeight)) {
// All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid,
// tip wouldn't be updated if anything was wrong. Mark this trigger as executed.
pSuperblock->SetExecuted();
govman.ResetVotedFundingTrigger();
}
}
CSuperblock::
CSuperblock() :
nGovObjHash(),
@ -397,27 +102,20 @@ CSuperblock::
{
}
CSuperblock::
CSuperblock(CGovernanceManager& govman, uint256& nHash) :
CSuperblock::CSuperblock(const CGovernanceObject& govObj, uint256& nHash) :
nGovObjHash(nHash),
nBlockHeight(0),
nStatus(SeenObjectStatus::Unknown),
vecPayments()
{
const CGovernanceObject* pGovObj = GetGovernanceObject(govman);
LogPrint(BCLog::GOBJECT, "CSuperblock -- Constructor govobj: %s, nObjectType = %d\n", govObj.GetDataAsPlainString(),
ToUnderlying(govObj.GetObjectType()));
if (!pGovObj) {
throw std::runtime_error("CSuperblock: Failed to find Governance Object");
}
LogPrint(BCLog::GOBJECT, "CSuperblock -- Constructor pGovObj: %s, nObjectType = %d\n",
pGovObj->GetDataAsPlainString(), ToUnderlying(pGovObj->GetObjectType()));
if (pGovObj->GetObjectType() != GovernanceObject::TRIGGER) {
if (govObj.GetObjectType() != GovernanceObject::TRIGGER) {
throw std::runtime_error("CSuperblock: Governance Object not a trigger");
}
UniValue obj = pGovObj->GetJSONObject();
UniValue obj = govObj.GetJSONObject();
if (obj["type"].get_int() != ToUnderlying(GovernanceObject::TRIGGER)) {
throw std::runtime_error("CSuperblock: invalid data type");
@ -442,14 +140,6 @@ CSuperblock::CSuperblock(int nBlockHeight, std::vector<CGovernancePayment> vecPa
nGovObjHash = GetHash();
}
CGovernanceObject* CSuperblock::GetGovernanceObject(CGovernanceManager& govman)
{
AssertLockHeld(govman.cs);
CGovernanceObject* pObj = govman.FindGovernanceObject(nGovObjHash);
return pObj;
}
/**
* Is Valid Superblock Height
*
@ -598,7 +288,7 @@ CAmount CSuperblock::GetPaymentsTotalAmount()
* - Does this transaction match the superblock?
*/
bool CSuperblock::IsValid(CGovernanceManager& govman, const CChain& active_chain, const CTransaction& txNew, int nBlockHeight, CAmount blockReward)
bool CSuperblock::IsValid(const CChain& active_chain, const CTransaction& txNew, int nBlockHeight, CAmount blockReward)
{
// TODO : LOCK(cs);
// No reason for a lock here now since this method only accesses data
@ -616,8 +306,8 @@ bool CSuperblock::IsValid(CGovernanceManager& govman, const CChain& active_chain
int nPayments = CountPayments();
int nMinerAndMasternodePayments = nOutputs - nPayments;
LogPrint(BCLog::GOBJECT, "CSuperblock::IsValid -- nOutputs = %d, nPayments = %d, GetDataAsHexString = %s\n",
nOutputs, nPayments, GetGovernanceObject(govman)->GetDataAsHexString());
LogPrint(BCLog::GOBJECT, "CSuperblock::IsValid -- nOutputs = %d, nPayments = %d, hash = %s\n", nOutputs, nPayments,
nGovObjHash.ToString());
// We require an exact match (including order) between the expected
// superblock payments and the payments actually in the block.
@ -681,7 +371,7 @@ bool CSuperblock::IsValid(CGovernanceManager& govman, const CChain& active_chain
return true;
}
bool CSuperblock::IsExpired(const CGovernanceManager& govman) const
bool CSuperblock::IsExpired(int heightToTest) const
{
int nExpirationBlocks;
// Executed triggers are kept for another superblock cycle (approximately 1 month for mainnet).
@ -703,14 +393,14 @@ bool CSuperblock::IsExpired(const CGovernanceManager& govman) const
LogPrint(BCLog::GOBJECT, "CSuperblock::IsExpired -- nBlockHeight = %d, nExpirationBlock = %d\n", nBlockHeight, nExpirationBlock);
if (govman.GetCachedBlockHeight() > nExpirationBlock) {
if (heightToTest > nExpirationBlock) {
LogPrint(BCLog::GOBJECT, "CSuperblock::IsExpired -- Outdated trigger found\n");
return true;
}
if (Params().NetworkIDString() != CBaseChainParams::MAIN) {
// NOTE: this can happen on testnet/devnets due to reorgs, should never happen on mainnet
if (govman.GetCachedBlockHeight() + Params().GetConsensus().nSuperblockCycle * 2 < nBlockHeight) {
if (heightToTest + Params().GetConsensus().nSuperblockCycle * 2 < nBlockHeight) {
LogPrint(BCLog::GOBJECT, "CSuperblock::IsExpired -- Trigger is too far into the future\n");
return true;
}

View File

@ -11,9 +11,7 @@
#include <uint256.h>
class CChain;
class CGovernanceManager;
class CSuperblock;
class CSuperblockManager;
class CTxOut;
class CTransaction;
@ -21,26 +19,6 @@ using CSuperblock_sptr = std::shared_ptr<CSuperblock>;
CAmount ParsePaymentAmount(const std::string& strAmount);
/**
* Superblock Manager
*
* Class for querying superblock information
*/
class CSuperblockManager
{
private:
static bool GetBestSuperblock(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, int nBlockHeight);
public:
static bool IsSuperblockTriggered(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight);
static bool GetSuperblockPayments(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight, std::vector<CTxOut>& voutSuperblockRet);
static void ExecuteBestSuperblock(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight);
static bool IsValid(CGovernanceManager& govman, const CChain& active_chain, const CDeterministicMNList& tip_mn_list, const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
};
/**
* Governance Object Payment
*
@ -101,7 +79,7 @@ private:
public:
CSuperblock();
CSuperblock(int nBlockHeight, std::vector<CGovernancePayment> vecPayments);
explicit CSuperblock(CGovernanceManager& govman, uint256& nHash);
explicit CSuperblock(const CGovernanceObject& obj, uint256& nHash);
static bool IsValidBlockHeight(int nBlockHeight);
static void GetNearestSuperblocksHeights(int nBlockHeight, int& nLastSuperblockRet, int& nNextSuperblockRet);
@ -115,19 +93,19 @@ public:
// TELL THE ENGINE WE EXECUTED THIS EVENT
void SetExecuted() { nStatus = SeenObjectStatus::Executed; }
CGovernanceObject* GetGovernanceObject(CGovernanceManager& govman);
int GetBlockHeight() const
{
return nBlockHeight;
}
const uint256 GetGovernanceObjHash() const { return nGovObjHash; }
int CountPayments() const { return (int)vecPayments.size(); }
bool GetPayment(int nPaymentIndex, CGovernancePayment& paymentRet);
CAmount GetPaymentsTotalAmount();
bool IsValid(CGovernanceManager& govman, const CChain& active_chain, const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
bool IsExpired(const CGovernanceManager& govman) const;
bool IsValid(const CChain& active_chain, const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
bool IsExpired(int heightToTest) const;
std::vector<uint256> GetProposalHashes() const;
};

View File

@ -34,6 +34,25 @@ const std::string GovernanceStore::SERIALIZATION_VERSION_STRING = "CGovernanceMa
const int CGovernanceManager::MAX_TIME_FUTURE_DEVIATION = 60 * 60;
const int CGovernanceManager::RELIABLE_PROPAGATION_TIME = 60;
namespace {
class ScopedLockBool
{
bool& ref;
bool fPrevValue;
public:
ScopedLockBool(RecursiveMutex& _cs, bool& _ref, bool _value) :
ref(_ref)
{
AssertLockHeld(_cs);
fPrevValue = ref;
ref = _value;
}
~ScopedLockBool() { ref = fPrevValue; }
};
} // anonymous namespace
GovernanceStore::GovernanceStore() :
cs(),
mapObjects(),
@ -47,8 +66,8 @@ GovernanceStore::GovernanceStore() :
}
CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, CNetFulfilledRequestManager& netfulfilledman,
const ChainstateManager& chainman, const std::unique_ptr<CDeterministicMNManager>& dmnman,
const std::unique_ptr<CMasternodeSync>& mn_sync) :
const ChainstateManager& chainman,
const std::unique_ptr<CDeterministicMNManager>& dmnman, CMasternodeSync& mn_sync) :
m_db{std::make_unique<db_type>("governance.dat", "magicGovernanceCache")},
m_mn_metaman{mn_metaman},
m_netfulfilledman{netfulfilledman},
@ -125,7 +144,7 @@ bool CGovernanceManager::SerializeVoteForHash(const uint256& nHash, CDataStream&
PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv)
{
if (!IsValid()) return {};
if (m_mn_sync == nullptr || !m_mn_sync->IsBlockchainSynced()) return {};
if (!m_mn_sync.IsBlockchainSynced()) return {};
const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip();
// ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
@ -133,7 +152,7 @@ PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, Pe
// Ignore such requests until we are fully synced.
// We could start processing this after masternode list is synced
// but this is a heavy one so it's better to finish sync first.
if (!m_mn_sync->IsSynced()) return {};
if (!m_mn_sync.IsSynced()) return {};
uint256 nProp;
CBloomFilter filter;
@ -161,7 +180,7 @@ PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, Pe
WITH_LOCK(::cs_main, peerman.EraseObjectRequest(peer.GetId(), CInv(MSG_GOVERNANCE_OBJECT, nHash)));
if (!m_mn_sync->IsBlockchainSynced()) {
if (!m_mn_sync.IsBlockchainSynced()) {
LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode list not synced\n");
return {};
}
@ -225,7 +244,7 @@ PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, Pe
WITH_LOCK(::cs_main, peerman.EraseObjectRequest(peer.GetId(), CInv(MSG_GOVERNANCE_OBJECT_VOTE, nHash)));
// Ignore such messages until masternode list is synced
if (!m_mn_sync->IsBlockchainSynced()) {
if (!m_mn_sync.IsBlockchainSynced()) {
LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n");
return {};
}
@ -243,11 +262,11 @@ PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, Pe
CGovernanceException exception;
if (ProcessVote(&peer, vote, exception, connman)) {
LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- %s new\n", strHash);
m_mn_sync->BumpAssetLastTime("MNGOVERNANCEOBJECTVOTE");
vote.Relay(peerman, *m_mn_sync, tip_mn_list);
m_mn_sync.BumpAssetLastTime("MNGOVERNANCEOBJECTVOTE");
vote.Relay(peerman, m_mn_sync, tip_mn_list);
} else {
LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what());
if ((exception.GetNodePenalty() != 0) && m_mn_sync->IsSynced()) {
if ((exception.GetNodePenalty() != 0) && m_mn_sync.IsSynced()) {
return tl::unexpected{exception.GetNodePenalty()};
}
return {};
@ -273,7 +292,7 @@ void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj, PeerManager
if (pairVote.second < nNow) {
fRemove = true;
} else if (govobj.ProcessVote(m_mn_metaman, *this, tip_mn_list, vote, e)) {
vote.Relay(peerman, *Assert(m_mn_sync), tip_mn_list);
vote.Relay(peerman, m_mn_sync, tip_mn_list);
fRemove = true;
}
if (fRemove) {
@ -327,12 +346,12 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, PeerMana
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- %s new, received from peer %s\n", strHash, pfrom ? pfrom->GetLogString() : "nullptr");
govobj.Relay(peerman, *Assert(m_mn_sync));
govobj.Relay(peerman, m_mn_sync);
// Update the rate buffer
MasternodeRateUpdate(govobj);
m_mn_sync->BumpAssetLastTime("CGovernanceManager::AddGovernanceObject");
m_mn_sync.BumpAssetLastTime("CGovernanceManager::AddGovernanceObject");
// WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
@ -347,7 +366,7 @@ void CGovernanceManager::CheckAndRemove()
assert(m_mn_metaman.IsValid());
// Return on initial sync, spammed the debug.log and provided no use
if (m_mn_sync == nullptr || !m_mn_sync->IsBlockchainSynced()) return;
if (!m_mn_sync.IsBlockchainSynced()) return;
LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean\n");
@ -573,7 +592,7 @@ struct sortProposalsByVotes {
std::optional<const CSuperblock> CGovernanceManager::CreateSuperblockCandidate(int nHeight) const
{
if (!IsValid()) return std::nullopt;
if (m_mn_sync == nullptr || !m_mn_sync->IsSynced()) return std::nullopt;
if (!m_mn_sync.IsSynced()) return std::nullopt;
if (nHeight % Params().GetConsensus().nSuperblockCycle < Params().GetConsensus().nSuperblockCycle - Params().GetConsensus().nSuperblockMaturityWindow) return std::nullopt;
if (HasAlreadyVotedFundingTrigger()) return std::nullopt;
@ -777,7 +796,7 @@ void CGovernanceManager::VoteGovernanceTriggers(const std::optional<const CGover
// Vote NO-FUNDING for the rest of the active triggers
const auto activeTriggers = GetActiveTriggers();
for (const auto& trigger : activeTriggers) {
const auto govobj = trigger->GetGovernanceObject(*this);
const auto govobj = FindGovernanceObject(trigger->GetGovernanceObjHash());
const uint256 trigger_hash = govobj->GetHash();
if (trigger->GetBlockHeight() <= nCachedBlockHeight) {
// ignore triggers from the past
@ -843,7 +862,7 @@ void CGovernanceManager::ResetVotedFundingTrigger()
void CGovernanceManager::DoMaintenance(CConnman& connman)
{
if (!IsValid()) return;
if (m_mn_sync == nullptr || !m_mn_sync->IsSynced()) return;
if (!m_mn_sync.IsSynced()) return;
if (ShutdownRequested()) return;
// CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES
@ -857,7 +876,7 @@ void CGovernanceManager::DoMaintenance(CConnman& connman)
bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv)
{
// do not request objects until it's time to sync
if (!Assert(m_mn_sync)->IsBlockchainSynced()) return false;
if (!m_mn_sync.IsBlockchainSynced()) return false;
LOCK(cs);
@ -900,7 +919,7 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv)
void CGovernanceManager::SyncSingleObjVotes(CNode& peer, PeerManager& peerman, const uint256& nProp, const CBloomFilter& filter, CConnman& connman)
{
// do not provide any data until our node is synced
if (!Assert(m_mn_sync)->IsSynced()) return;
if (!m_mn_sync.IsSynced()) return;
int nVoteCount = 0;
@ -952,7 +971,7 @@ PeerMsgRet CGovernanceManager::SyncObjects(CNode& peer, PeerManager& peerman, CC
assert(m_netfulfilledman.IsValid());
// do not provide any data until our node is synced
if (!Assert(m_mn_sync)->IsSynced()) return {};
if (!m_mn_sync.IsSynced()) return {};
if (m_netfulfilledman.HasFulfilledRequest(peer.addr, NetMsgType::MNGOVERNANCESYNC)) {
// Asking for the whole list multiple times in a short period of time is no good
@ -1042,7 +1061,7 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo
fRateCheckBypassed = false;
if (!Assert(m_mn_sync)->IsSynced() || !fRateChecksEnabled) {
if (!m_mn_sync.IsSynced() || !fRateChecksEnabled) {
return true;
}
@ -1104,7 +1123,7 @@ bool CGovernanceManager::ProcessVoteAndRelay(const CGovernanceVote& vote, CGover
{
bool fOK = ProcessVote(/* pfrom = */ nullptr, vote, exception, connman);
if (fOK) {
vote.Relay(peerman, *Assert(m_mn_sync), Assert(m_dmnman)->GetListAtChainTip());
vote.Relay(peerman, m_mn_sync, Assert(m_dmnman)->GetListAtChainTip());
}
return fOK;
}
@ -1165,7 +1184,7 @@ bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote,
void CGovernanceManager::CheckPostponedObjects(PeerManager& peerman)
{
if (!Assert(m_mn_sync)->IsSynced()) return;
if (!m_mn_sync.IsSynced()) return;
LOCK2(cs_main, cs);
@ -1213,7 +1232,7 @@ void CGovernanceManager::CheckPostponedObjects(PeerManager& peerman)
if (fValid) {
if (fReady) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::CheckPostponedObjects -- additional relay: hash = %s\n", govobj.GetHash().ToString());
govobj.Relay(peerman, *m_mn_sync);
govobj.Relay(peerman, m_mn_sync);
} else {
it++;
continue;
@ -1524,7 +1543,7 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex, CConnman& co
CheckPostponedObjects(peerman);
CSuperblockManager::ExecuteBestSuperblock(*this, Assert(m_dmnman)->GetListAtChainTip(), pindex->nHeight);
ExecuteBestSuperblock(Assert(m_dmnman)->GetListAtChainTip(), pindex->nHeight);
}
void CGovernanceManager::RequestOrphanObjects(CConnman& connman)
@ -1574,7 +1593,7 @@ void CGovernanceManager::CleanOrphanObjects()
void CGovernanceManager::RemoveInvalidVotes()
{
if (!Assert(m_mn_sync)->IsSynced()) {
if (!m_mn_sync.IsSynced()) {
return;
}
@ -1616,6 +1635,296 @@ void CGovernanceManager::RemoveInvalidVotes()
lastMNListForVotingKeys = std::make_shared<CDeterministicMNList>(tip_mn_list);
}
/**
* Add Governance Object
*/
bool CGovernanceManager::AddNewTrigger(uint256 nHash)
{
AssertLockHeld(cs);
// IF WE ALREADY HAVE THIS HASH, RETURN
if (mapTrigger.count(nHash)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Already have hash, nHash = %s, count = %d, size = %s\n",
__func__, nHash.GetHex(), mapTrigger.count(nHash), mapTrigger.size());
return false;
}
CSuperblock_sptr pSuperblock;
try {
const CGovernanceObject* pGovObj = FindGovernanceObject(nHash);
if (!pGovObj) {
throw std::runtime_error("CSuperblock: Failed to find Governance Object");
}
pSuperblock = std::make_shared<CSuperblock>(*pGovObj, nHash);
} catch (std::exception& e) {
LogPrintf("CGovernanceManager::%s -- Error creating superblock: %s\n", __func__, e.what());
return false;
} catch (...) {
LogPrintf("CGovernanceManager::%s -- Unknown Error creating superblock\n", __func__);
return false;
}
pSuperblock->SetStatus(SeenObjectStatus::Valid);
mapTrigger.insert(std::make_pair(nHash, pSuperblock));
return !pSuperblock->IsExpired(GetCachedBlockHeight());
}
/**
*
* Clean And Remove
*
*/
void CGovernanceManager::CleanAndRemoveTriggers()
{
AssertLockHeld(cs);
// Remove triggers that are invalid or expired
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- mapTrigger.size() = %d\n", __func__, mapTrigger.size());
auto it = mapTrigger.begin();
while (it != mapTrigger.end()) {
bool remove = false;
CGovernanceObject* pObj = nullptr;
const CSuperblock_sptr& pSuperblock = it->second;
if (!pSuperblock) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- nullptr superblock\n", __func__);
remove = true;
} else {
pObj = FindGovernanceObject(it->first);
if (!pObj || pObj->GetObjectType() != GovernanceObject::TRIGGER) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or non-trigger superblock\n", __func__);
pSuperblock->SetStatus(SeenObjectStatus::ErrorInvalid);
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- superblock status = %d\n", __func__,
ToUnderlying(pSuperblock->GetStatus()));
switch (pSuperblock->GetStatus()) {
case SeenObjectStatus::ErrorInvalid:
case SeenObjectStatus::Unknown:
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or invalid trigger found\n", __func__);
remove = true;
break;
case SeenObjectStatus::Valid:
case SeenObjectStatus::Executed: {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Valid trigger found\n", __func__);
if (pSuperblock->IsExpired(GetCachedBlockHeight())) {
// update corresponding object
pObj->SetExpired();
remove = true;
}
break;
}
default:
break;
}
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- %smarked for removal\n", __func__, remove ? "" : "NOT ");
if (remove) {
std::string strDataAsPlainString = "nullptr";
if (pObj) {
strDataAsPlainString = pObj->GetDataAsPlainString();
// mark corresponding object for deletion
pObj->PrepareDeletion(GetTime<std::chrono::seconds>().count());
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Removing trigger object %s\n", __func__,
strDataAsPlainString);
// delete the trigger
mapTrigger.erase(it++);
} else {
++it;
}
}
}
/**
* Get Active Triggers
*
* - Look through triggers and scan for active ones
* - Return the triggers in a list
*/
std::vector<CSuperblock_sptr> CGovernanceManager::GetActiveTriggers() const
{
AssertLockHeld(cs);
std::vector<CSuperblock_sptr> vecResults;
// LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS
for (const auto& pair : mapTrigger) {
const CGovernanceObject* pObj = FindConstGovernanceObject(pair.first);
if (pObj) {
vecResults.push_back(pair.second);
}
}
return vecResults;
}
bool CGovernanceManager::IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight)
{
LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- Start nBlockHeight = %d\n", nBlockHeight);
if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) {
return false;
}
LOCK(cs);
// GET ALL ACTIVE TRIGGERS
std::vector<CSuperblock_sptr> vecTriggers = GetActiveTriggers();
LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- vecTriggers.size() = %d\n", vecTriggers.size());
for (const auto& pSuperblock : vecTriggers) {
if (!pSuperblock) {
LogPrintf("IsSuperblockTriggered -- Non-superblock found, continuing\n");
continue;
}
CGovernanceObject* pObj = FindGovernanceObject(pSuperblock->GetGovernanceObjHash());
if (!pObj) {
LogPrintf("IsSuperblockTriggered -- pObj == nullptr, continuing\n");
continue;
}
LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- data = %s\n", pObj->GetDataAsPlainString());
// note : 12.1 - is epoch calculation correct?
if (nBlockHeight != pSuperblock->GetBlockHeight()) {
LogPrint(BCLog::GOBJECT, /* Continued */
"IsSuperblockTriggered -- block height doesn't match nBlockHeight = %d, blockStart = %d, "
"continuing\n",
nBlockHeight, pSuperblock->GetBlockHeight());
continue;
}
// MAKE SURE THIS TRIGGER IS ACTIVE VIA FUNDING CACHE FLAG
pObj->UpdateSentinelVariables(tip_mn_list);
if (pObj->IsSetCachedFunding()) {
LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- fCacheFunding = true, returning true\n");
return true;
} else {
LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- fCacheFunding = false, continuing\n");
}
}
return false;
}
bool CGovernanceManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet,
int nBlockHeight)
{
if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) {
return false;
}
AssertLockHeld(cs);
std::vector<CSuperblock_sptr> vecTriggers = GetActiveTriggers();
int nYesCount = 0;
for (const auto& pSuperblock : vecTriggers) {
if (!pSuperblock || nBlockHeight != pSuperblock->GetBlockHeight()) {
continue;
}
const CGovernanceObject* pObj = FindGovernanceObject(pSuperblock->GetGovernanceObjHash());
if (!pObj) {
continue;
}
// DO WE HAVE A NEW WINNER?
int nTempYesCount = pObj->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING);
if (nTempYesCount > nYesCount) {
nYesCount = nTempYesCount;
pSuperblockRet = pSuperblock;
}
}
return nYesCount > 0;
}
bool CGovernanceManager::GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight,
std::vector<CTxOut>& voutSuperblockRet)
{
LOCK(cs);
// GET THE BEST SUPERBLOCK FOR THIS BLOCK HEIGHT
CSuperblock_sptr pSuperblock;
if (!GetBestSuperblock(tip_mn_list, pSuperblock, nBlockHeight)) {
LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Can't find superblock for height %d\n", nBlockHeight);
return false;
}
// make sure it's empty, just in case
voutSuperblockRet.clear();
// GET SUPERBLOCK OUTPUTS
// Superblock payments will be appended to the end of the coinbase vout vector
// TODO: How many payments can we add before things blow up?
// Consider at least following limits:
// - max coinbase tx size
// - max "budget" available
for (int i = 0; i < pSuperblock->CountPayments(); i++) {
CGovernancePayment payment;
if (pSuperblock->GetPayment(i, payment)) {
// SET COINBASE OUTPUT TO SUPERBLOCK SETTING
CTxOut txout = CTxOut(payment.nAmount, payment.script);
voutSuperblockRet.push_back(txout);
// PRINT NICE LOG OUTPUT FOR SUPERBLOCK PAYMENT
CTxDestination dest;
ExtractDestination(payment.script, dest);
LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- NEW Superblock: output %d (addr %s, amount %d.%08d)\n",
i, EncodeDestination(dest), payment.nAmount / COIN, payment.nAmount % COIN);
} else {
LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Payment not found\n");
}
}
return true;
}
bool CGovernanceManager::IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list,
const CTransaction& txNew, int nBlockHeight, CAmount blockReward)
{
// GET BEST SUPERBLOCK, SHOULD MATCH
LOCK(cs);
CSuperblock_sptr pSuperblock;
if (GetBestSuperblock(tip_mn_list, pSuperblock, nBlockHeight)) {
return pSuperblock->IsValid(active_chain, txNew, nBlockHeight, blockReward);
}
return false;
}
void CGovernanceManager::ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight)
{
LOCK(cs);
CSuperblock_sptr pSuperblock;
if (GetBestSuperblock(tip_mn_list, pSuperblock, nBlockHeight)) {
// All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid,
// tip wouldn't be updated if anything was wrong. Mark this trigger as executed.
pSuperblock->SetExecuted();
ResetVotedFundingTrigger();
}
}
bool AreSuperblocksEnabled(const CSporkManager& sporkman)
{
return sporkman.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED);

View File

@ -69,7 +69,7 @@ public:
fBufferEmpty = false;
}
int64_t GetMinTimestamp()
int64_t GetMinTimestamp() const
{
int nIndex = nDataStart;
int64_t nMin = std::numeric_limits<int64_t>::max();
@ -85,7 +85,7 @@ public:
return nMin;
}
int64_t GetMaxTimestamp()
int64_t GetMaxTimestamp() const
{
int nIndex = nDataStart;
int64_t nMax = 0;
@ -112,7 +112,7 @@ public:
return RATE_BUFFER_SIZE - nDataStart + nDataEnd;
}
double GetRate()
double GetRate() const
{
int nCount = GetCount();
if (nCount < RATE_BUFFER_SIZE) {
@ -228,29 +228,8 @@ class CGovernanceManager : public GovernanceStore
friend class CGovernanceObject;
private:
using hash_s_t = std::set<uint256>;
using db_type = CFlatDB<GovernanceStore>;
class ScopedLockBool
{
bool& ref;
bool fPrevValue;
public:
ScopedLockBool(RecursiveMutex& _cs, bool& _ref, bool _value) :
ref(_ref)
{
AssertLockHeld(_cs);
fPrevValue = ref;
ref = _value;
}
~ScopedLockBool()
{
ref = fPrevValue;
}
};
private:
static const int MAX_TIME_FUTURE_DEVIATION;
static const int RELIABLE_PROPAGATION_TIME;
@ -263,22 +242,22 @@ private:
CNetFulfilledRequestManager& m_netfulfilledman;
const ChainstateManager& m_chainman;
const std::unique_ptr<CDeterministicMNManager>& m_dmnman;
const std::unique_ptr<CMasternodeSync>& m_mn_sync;
CMasternodeSync& m_mn_sync;
int64_t nTimeLastDiff;
// keep track of current block height
int nCachedBlockHeight;
std::map<uint256, CGovernanceObject> mapPostponedObjects;
hash_s_t setAdditionalRelayObjects;
std::set<uint256> setAdditionalRelayObjects;
std::map<uint256, std::chrono::seconds> m_requested_hash_time;
bool fRateChecksEnabled;
std::optional<uint256> votedFundingYesTriggerHash;
std::map<uint256, std::shared_ptr<CSuperblock>> mapTrigger;
public:
explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, CNetFulfilledRequestManager& netfulfilledman, const ChainstateManager& chainman,
const std::unique_ptr<CDeterministicMNManager>& dmnman,
const std::unique_ptr<CMasternodeSync>& mn_sync);
explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, CNetFulfilledRequestManager& netfulfilledman,
const ChainstateManager& chainman,
const std::unique_ptr<CDeterministicMNManager>& dmnman, CMasternodeSync& mn_sync);
~CGovernanceManager();
bool LoadCache(bool load_cache);
@ -297,8 +276,10 @@ public:
PeerMsgRet ProcessMessage(CNode& peer, CConnman& connman, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv);
private:
void ResetVotedFundingTrigger();
public:
void DoMaintenance(CConnman& connman);
const CGovernanceObject* FindConstGovernanceObject(const uint256& nHash) const EXCLUSIVE_LOCKS_REQUIRED(cs);
@ -366,11 +347,34 @@ public:
* - Track governance objects which are triggers
* - After triggers are activated and executed, they can be removed
*/
std::vector<std::shared_ptr<CSuperblock>> GetActiveTriggers();
std::vector<std::shared_ptr<CSuperblock>> GetActiveTriggers() const;
bool AddNewTrigger(uint256 nHash);
void CleanAndRemoveTriggers();
// Superblocks related:
/**
* Is Superblock Triggered
*
* - Does this block have a non-executed and activated trigger?
*/
bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight);
/**
* Get Superblock Payments
*
* - Returns payments for superblock
*/
bool GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight,
std::vector<CTxOut>& voutSuperblockRet);
bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list,
const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
private:
void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight);
bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, int nBlockHeight);
std::optional<const CSuperblock> CreateSuperblockCandidate(int nHeight) const;
std::optional<const CGovernanceObject> CreateGovernanceTrigger(const std::optional<const CSuperblock>& sb_opt, PeerManager& peerman,
const CActiveMasternodeManager& mn_activeman);

View File

@ -1862,9 +1862,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
* need it or not further down and then query if the database is initialized
* to check if validation is enabled.
*/
node.govman = std::make_unique<CGovernanceManager>(*node.mn_metaman, *node.netfulfilledman, *node.chainman, node.dmnman, node.mn_sync);
node.mn_sync = std::make_unique<CMasternodeSync>(*node.connman, *node.netfulfilledman);
node.mn_sync = std::make_unique<CMasternodeSync>(*node.connman, *node.netfulfilledman, *node.govman);
node.govman = std::make_unique<CGovernanceManager>(*node.mn_metaman, *node.netfulfilledman, *node.chainman, node.dmnman, *node.mn_sync);
const bool fReset = fReindex;
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
@ -2282,7 +2282,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 10a: schedule Dash-specific tasks
node.scheduler->scheduleEvery(std::bind(&CNetFulfilledRequestManager::DoMaintenance, std::ref(*node.netfulfilledman)), std::chrono::minutes{1});
node.scheduler->scheduleEvery(std::bind(&CMasternodeSync::DoMaintenance, std::ref(*node.mn_sync), std::cref(*node.peerman)), std::chrono::seconds{1});
node.scheduler->scheduleEvery(std::bind(&CMasternodeSync::DoMaintenance, std::ref(*node.mn_sync), std::cref(*node.peerman), std::cref(*node.govman)), std::chrono::seconds{1});
node.scheduler->scheduleEvery(std::bind(&CMasternodeUtils::DoMaintenance, std::ref(*node.connman), std::ref(*node.dmnman), std::ref(*node.mn_sync), std::ref(*node.cj_ctx)), std::chrono::minutes{1});
node.scheduler->scheduleEvery(std::bind(&CDeterministicMNManager::DoMaintenance, std::ref(*node.dmnman)), std::chrono::seconds{10});

View File

@ -246,7 +246,7 @@ bool CMNPaymentsProcessor::IsBlockValueValid(const CBlock& block, const int nBlo
const auto tip_mn_list = m_dmnman.GetListAtChainTip();
if (!CSuperblockManager::IsSuperblockTriggered(m_govman, tip_mn_list, nBlockHeight)) {
if (!m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) {
// we are on a valid superblock height but a superblock was not triggered
// revert to block reward limits in this case
if(!isBlockRewardValueMet) {
@ -257,7 +257,7 @@ bool CMNPaymentsProcessor::IsBlockValueValid(const CBlock& block, const int nBlo
}
// this actually also checks for correct payees and not only amount
if (!CSuperblockManager::IsValid(m_govman, m_chainman.ActiveChain(), tip_mn_list, *block.vtx[0], nBlockHeight, blockReward)) {
if (!m_govman.IsValidSuperblock(m_chainman.ActiveChain(), tip_mn_list, *block.vtx[0], nBlockHeight, blockReward)) {
// triggered but invalid? that's weird
LogPrintf("CMNPaymentsProcessor::%s -- ERROR! Invalid superblock detected at height %d: %s", __func__, nBlockHeight, block.vtx[0]->ToString()); /* Continued */
// should NOT allow invalid superblocks, when superblocks are enabled
@ -302,8 +302,9 @@ bool CMNPaymentsProcessor::IsBlockPayeeValid(const CTransaction& txNew, const CB
if (AreSuperblocksEnabled(m_sporkman)) {
if (!check_superblock) return true;
const auto tip_mn_list = m_dmnman.GetListAtChainTip();
if (CSuperblockManager::IsSuperblockTriggered(m_govman, tip_mn_list, nBlockHeight)) {
if (CSuperblockManager::IsValid(m_govman, m_chainman.ActiveChain(), tip_mn_list, txNew, nBlockHeight, blockSubsidy + feeReward)) {
if (m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) {
if (m_govman.IsValidSuperblock(m_chainman.ActiveChain(), tip_mn_list, txNew, nBlockHeight,
blockSubsidy + feeReward)) {
LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Valid superblock at height %d: %s", __func__, nBlockHeight, txNew.ToString()); /* Continued */
// continue validation, should also pay MN
} else {
@ -330,9 +331,9 @@ void CMNPaymentsProcessor::FillBlockPayments(CMutableTransaction& txNew, const C
// only create superblocks if spork is enabled AND if superblock is actually triggered
// (height should be validated inside)
const auto tip_mn_list = m_dmnman.GetListAtChainTip();
if(AreSuperblocksEnabled(m_sporkman) && CSuperblockManager::IsSuperblockTriggered(m_govman, tip_mn_list, nBlockHeight)) {
if (AreSuperblocksEnabled(m_sporkman) && m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) {
LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Triggered superblock creation at height %d\n", __func__, nBlockHeight);
CSuperblockManager::GetSuperblockPayments(m_govman, tip_mn_list, nBlockHeight, voutSuperblockPaymentsRet);
m_govman.GetSuperblockPayments(tip_mn_list, nBlockHeight, voutSuperblockPaymentsRet);
}
if (!GetMasternodeTxOuts(pindexPrev, blockSubsidy, feeReward, voutMasternodePaymentsRet)) {

View File

@ -16,12 +16,11 @@
class CMasternodeSync;
CMasternodeSync::CMasternodeSync(CConnman& _connman, CNetFulfilledRequestManager& netfulfilledman, const CGovernanceManager& govman) :
CMasternodeSync::CMasternodeSync(CConnman& _connman, CNetFulfilledRequestManager& netfulfilledman) :
nTimeAssetSyncStarted(GetTime()),
nTimeLastBumped(GetTime()),
connman(_connman),
m_netfulfilledman(netfulfilledman),
m_govman(govman)
m_netfulfilledman(netfulfilledman)
{
}
@ -115,7 +114,7 @@ void CMasternodeSync::ProcessMessage(const CNode& peer, std::string_view msg_typ
LogPrint(BCLog::MNSYNC, "SYNCSTATUSCOUNT -- got inventory count: nItemID=%d nCount=%d peer=%d\n", nItemID, nCount, peer.GetId());
}
void CMasternodeSync::ProcessTick(const PeerManager& peerman)
void CMasternodeSync::ProcessTick(const PeerManager& peerman, const CGovernanceManager& govman)
{
assert(m_netfulfilledman.IsValid());
@ -144,7 +143,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman)
// gradually request the rest of the votes after sync finished
if(IsSynced()) {
m_govman.RequestGovernanceObjectVotes(snap.Nodes(), connman, peerman);
govman.RequestGovernanceObjectVotes(snap.Nodes(), connman, peerman);
return;
}
@ -219,7 +218,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman)
// GOVOBJ : SYNC GOVERNANCE ITEMS FROM OUR PEERS
if(nCurrentAsset == MASTERNODE_SYNC_GOVERNANCE) {
if (!m_govman.IsValid()) {
if (!govman.IsValid()) {
SwitchToNextAsset();
return;
}
@ -264,7 +263,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman)
if(!m_netfulfilledman.HasFulfilledRequest(pnode->addr, "governance-sync")) {
continue; // to early for this node
}
int nObjsLeftToAsk = m_govman.RequestGovernanceObjectVotes(*pnode, connman, peerman);
int nObjsLeftToAsk = govman.RequestGovernanceObjectVotes(*pnode, connman, peerman);
// check for data
if(nObjsLeftToAsk == 0) {
static int64_t nTimeNoObjectsLeft = 0;
@ -277,8 +276,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman)
// make sure the condition below is checked only once per tick
if(nLastTick == nTick) continue;
if (GetTime() - nTimeNoObjectsLeft > MASTERNODE_SYNC_TIMEOUT_SECONDS &&
m_govman.GetVoteCount() - nLastVotes < std::max(int(0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS)
) {
govman.GetVoteCount() - nLastVotes < std::max(int(0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS)) {
// We already asked for all objects, waited for MASTERNODE_SYNC_TIMEOUT_SECONDS
// after that and less then 0.01% or MASTERNODE_SYNC_TICK_SECONDS
// (i.e. 1 per second) votes were received during the last tick.
@ -290,7 +288,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman)
return;
}
nLastTick = nTick;
nLastVotes = m_govman.GetVoteCount();
nLastVotes = govman.GetVoteCount();
}
}
}
@ -368,9 +366,9 @@ void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlock
pindexNew->nHeight, pindexTip->nHeight, fInitialDownload, fReachedBestHeader);
}
void CMasternodeSync::DoMaintenance(const PeerManager& peerman)
void CMasternodeSync::DoMaintenance(const PeerManager& peerman, const CGovernanceManager& govman)
{
if (ShutdownRequested()) return;
ProcessTick(peerman);
ProcessTick(peerman, govman);
}

View File

@ -51,10 +51,9 @@ private:
CConnman& connman;
CNetFulfilledRequestManager& m_netfulfilledman;
const CGovernanceManager& m_govman;
public:
explicit CMasternodeSync(CConnman& _connman, CNetFulfilledRequestManager& netfulfilledman, const CGovernanceManager& govman);
explicit CMasternodeSync(CConnman& _connman, CNetFulfilledRequestManager& netfulfilledman);
void SendGovernanceSyncRequest(CNode* pnode) const;
@ -72,13 +71,13 @@ public:
void SwitchToNextAsset();
void ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv) const;
void ProcessTick(const PeerManager& peerman);
void ProcessTick(const PeerManager& peerman, const CGovernanceManager& govman);
void AcceptedBlockHeader(const CBlockIndex *pindexNew);
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload);
void UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlockIndex *pindexNew, bool fInitialDownload);
void DoMaintenance(const PeerManager& peerman);
void DoMaintenance(const PeerManager& peerman, const CGovernanceManager& govman);
};
#endif // BITCOIN_MASTERNODE_SYNC_H

View File

@ -956,14 +956,14 @@ static RPCHelpMan voteraw()
const NodeContext& node = EnsureAnyNodeContext(request.context);
CHECK_NONFATAL(node.govman);
GovernanceObject govObjType = WITH_LOCK(node.govman->cs, return [&](){
AssertLockHeld(node.govman->cs);
GovernanceObject govObjType = [&]() {
LOCK(node.govman->cs);
const CGovernanceObject *pGovObj = node.govman->FindConstGovernanceObject(hashGovObj);
if (!pGovObj) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Governance object not found");
}
return pGovObj->GetObjectType();
}());
}();
int64_t nTime = request.params[5].get_int64();

View File

@ -253,9 +253,9 @@ static std::string GetRequiredPaymentsString(CGovernanceManager& govman, const C
strPayments += ", " + EncodeDestination(dest);
}
}
if (CSuperblockManager::IsSuperblockTriggered(govman, tip_mn_list, nBlockHeight)) {
if (govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) {
std::vector<CTxOut> voutSuperblock;
if (!CSuperblockManager::GetSuperblockPayments(govman, tip_mn_list, nBlockHeight, voutSuperblock)) {
if (!govman.GetSuperblockPayments(tip_mn_list, nBlockHeight, voutSuperblock)) {
return strPayments + ", error";
}
std::string strSBPayees = "Unknown";

View File

@ -245,8 +245,8 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
m_node.mn_metaman = std::make_unique<CMasternodeMetaMan>();
m_node.netfulfilledman = std::make_unique<CNetFulfilledRequestManager>();
m_node.sporkman = std::make_unique<CSporkManager>();
m_node.govman = std::make_unique<CGovernanceManager>(*m_node.mn_metaman, *m_node.netfulfilledman, *m_node.chainman, m_node.dmnman, m_node.mn_sync);
m_node.mn_sync = std::make_unique<CMasternodeSync>(*m_node.connman, *m_node.netfulfilledman, *m_node.govman);
m_node.mn_sync = std::make_unique<CMasternodeSync>(*m_node.connman, *m_node.netfulfilledman);
m_node.govman = std::make_unique<CGovernanceManager>(*m_node.mn_metaman, *m_node.netfulfilledman, *m_node.chainman, m_node.dmnman, *m_node.mn_sync);
// Start script-checking threads. Set g_parallel_script_checks to true so they are used.
constexpr int script_check_threads = 2;

View File

@ -26,7 +26,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"evo/cbtx -> evo/simplifiedmns -> evo/cbtx"
"evo/deterministicmns -> llmq/commitment -> evo/deterministicmns"
"evo/deterministicmns -> llmq/utils -> evo/deterministicmns"
"governance/classes -> governance/governance -> governance/classes"
"governance/governance -> governance/object -> governance/governance"
"governance/governance -> masternode/sync -> governance/governance"
"llmq/chainlocks -> llmq/instantsend -> llmq/chainlocks"

View File

@ -9,6 +9,7 @@ src/coinjoin/*.h
src/ctpl_stl.h
src/cxxtimer.hpp
src/dsnotificationinterface.*
src/flat-database.h
src/evo/*.cpp
src/evo/*.h
src/governance/*.cpp