diff --git a/src/governance/classes.cpp b/src/governance/classes.cpp index 3e15bd280e..df3c6f3774 100644 --- a/src/governance/classes.cpp +++ b/src/governance/classes.cpp @@ -94,290 +94,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(*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().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 CGovernanceManager::GetActiveTriggers() const -{ - AssertLockHeld(cs); - std::vector 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 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, - "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) const -{ - if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { - return false; - } - - AssertLockHeld(cs); - std::vector 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& 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(*this, 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(); - } -} - CSuperblock:: CSuperblock() : nGovObjHash(), diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 39a0ca21ac..920cedee16 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -1634,6 +1634,293 @@ void CGovernanceManager::RemoveInvalidVotes() lastMNListForVotingKeys = std::make_shared(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 { + auto pSuperblockTmp = std::make_shared(*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().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 CGovernanceManager::GetActiveTriggers() const +{ + AssertLockHeld(cs); + std::vector 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 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 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& 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(*this, 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);