Skip to content

Commit

Permalink
fix: actually vote no on triggers we don't like
Browse files Browse the repository at this point in the history
  • Loading branch information
UdjinM6 committed Nov 2, 2023
1 parent 25ee167 commit c3de9a8
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 50 deletions.
114 changes: 66 additions & 48 deletions src/governance/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ struct sortProposalsByVotes {
}
};

std::optional<CSuperblock> CGovernanceManager::CreateSuperblockCandidate(int nHeight) const
const std::optional<CSuperblock> CGovernanceManager::CreateSuperblockCandidate(int nHeight) const
{
if (!fMasternodeMode || fDisableGovernance) return std::nullopt;
if (::masternodeSync == nullptr || !::masternodeSync->IsSynced()) return std::nullopt;
Expand Down Expand Up @@ -663,63 +663,82 @@ std::optional<CSuperblock> CGovernanceManager::CreateSuperblockCandidate(int nHe
return CSuperblock(nNextSuperblock, std::move(payments));
}

void CGovernanceManager::CreateGovernanceTrigger(const CSuperblock& sb, CConnman& connman)
const std::optional<CGovernanceObject> CGovernanceManager::CreateGovernanceTrigger(const std::optional<CSuperblock>& sb_opt, CConnman& connman)
{
// no sb_opt, no trigger
if (!sb_opt.has_value()) return std::nullopt;

//TODO: Check if nHashParentIn, nRevision and nCollateralHashIn are correct
LOCK2(cs_main, cs);

// Check if identical trigger (equal DataHash()) is already created (signed by other masternode)
CGovernanceObject* gov_sb_voting{nullptr};
CGovernanceObject gov_sb(uint256(), 1, GetAdjustedTime(), uint256(), sb.GetHexStrData());
const auto identical_sb = FindGovernanceObjectByDataHash(gov_sb.GetDataHash());

if (identical_sb == nullptr) {
// Nobody submitted a trigger we'd like to see,
// so let's do it but only if we are the payee

const CBlockIndex *tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
auto mnList = deterministicMNManager->GetListForBlock(tip);
auto mn_payees = mnList.GetProjectedMNPayees(tip);
if (mn_payees.empty()) return;
{
LOCK(activeMasternodeInfoCs);
if (mn_payees.front()->proTxHash != activeMasternodeInfo.proTxHash) return;
gov_sb.SetMasternodeOutpoint(activeMasternodeInfo.outpoint);
gov_sb.Sign( *activeMasternodeInfo.blsKeyOperator);
}
if (std::string strError; !gov_sb.IsValidLocally(strError, true)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Created trigger is invalid:%s\n", __func__, strError);
return;
}
if (!MasternodeRateCheck(gov_sb)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Trigger rejected because of rate check failure hash(%s)\n", __func__, gov_sb.GetHash().ToString());
return;
}
// The trigger we just created looks good, submit it
AddGovernanceObject(gov_sb, connman);
gov_sb_voting = &gov_sb;
} else {
CGovernanceObject gov_sb(uint256(), 1, GetAdjustedTime(), uint256(), sb_opt.value().GetHexStrData());
if (auto identical_sb = FindGovernanceObjectByDataHash(gov_sb.GetDataHash())) {
// Somebody submitted a trigger with the same data, support it instead of submitting a duplicate
gov_sb_voting = identical_sb;
return std::make_optional<CGovernanceObject>(*identical_sb);
}

// Vote YES-FUNDING for the trigger we like
if (!VoteFundingTrigger(gov_sb_voting->GetHash(), VOTE_OUTCOME_YES, connman)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting YES-FUNDING for new trigger:%s failed\n", __func__, gov_sb_voting->GetHash().ToString());
return;
// Nobody submitted a trigger we'd like to see, so let's do it but only if we are the payee
auto mnList = deterministicMNManager->GetListForBlock(::ChainActive().Tip());
auto mn_payees = mnList.GetProjectedMNPayees(::ChainActive().Tip());

if (mn_payees.empty()) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s payee list is empty\n", __func__);
return std::nullopt;
}

votedFundingYesTriggerHash = gov_sb_voting->GetHash();
{
LOCK(activeMasternodeInfoCs);
if (mn_payees.front()->proTxHash != activeMasternodeInfo.proTxHash) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s we are not the payee, skipping\n", __func__);
return std::nullopt;
}
gov_sb.SetMasternodeOutpoint(activeMasternodeInfo.outpoint);
gov_sb.Sign( *activeMasternodeInfo.blsKeyOperator);
} // activeMasternodeInfoCs

// Vote NO-FUNDING for the rest of the active triggers
auto activeTriggers = triggerman.GetActiveTriggers();
for (const auto& trigger : activeTriggers) {
if (trigger->GetHash() == gov_sb_voting->GetHash()) continue; // Skip actual trigger
if (std::string strError; !gov_sb.IsValidLocally(strError, true)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Created trigger is invalid:%s\n", __func__, strError);
return std::nullopt;
}

if (!MasternodeRateCheck(gov_sb)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Trigger rejected because of rate check failure hash(%s)\n", __func__, gov_sb.GetHash().ToString());
return std::nullopt;
}

// The trigger we just created looks good, submit it
AddGovernanceObject(gov_sb, connman);
return std::make_optional<CGovernanceObject>(gov_sb);
}

if (!VoteFundingTrigger(trigger->GetHash(), VOTE_OUTCOME_NO, connman)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting NO-FUNDING for trigger:%s failed\n", __func__, trigger->GetHash().ToString());
void CGovernanceManager::VoteGovernanceTriggers(const std::optional<CGovernanceObject>& trigger_opt, CConnman& connman)
{
if (trigger_opt.has_value()) {
// We should never vote "yes" on another trigger or the same trigger twice
assert(!votedFundingYesTriggerHash.has_value());
// Vote YES-FUNDING for the trigger we like
const uint256 gov_sb_hash = trigger_opt.value().GetHash();
if (!VoteFundingTrigger(gov_sb_hash, VOTE_OUTCOME_YES, connman)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting YES-FUNDING for new trigger:%s failed\n", __func__, gov_sb_hash.ToString());
// this should never happen, bail out
return;
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting YES-FUNDING for new trigger:%s success\n", __func__, gov_sb_hash.ToString());
votedFundingYesTriggerHash = gov_sb_hash;
}

// Vote NO-FUNDING for the rest of the active triggers
const auto activeTriggers = triggerman.GetActiveTriggers();
for (const auto& trigger : activeTriggers) {
const uint256 trigger_hash = trigger->GetHash();
if (trigger_hash == votedFundingYesTriggerHash) continue; // Skip actual trigger
if (!VoteFundingTrigger(trigger_hash, VOTE_OUTCOME_NO, connman)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting NO-FUNDING for trigger:%s failed\n", __func__, trigger_hash.ToString());
// failing here is ok-ish
continue;
}
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting NO-FUNDING for trigger:%s success\n", __func__, trigger_hash.ToString());
}
}

Expand Down Expand Up @@ -1417,10 +1436,9 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex, CConnman& co
return;
}

auto sb_opt = CreateSuperblockCandidate(pindex->nHeight);
if (sb_opt.has_value()) {
CreateGovernanceTrigger(sb_opt.value(), connman);
}
const auto sb_opt = CreateSuperblockCandidate(pindex->nHeight);
const auto trigger_opt = CreateGovernanceTrigger(sb_opt, connman);
VoteGovernanceTriggers(trigger_opt, connman);

nCachedBlockHeight = pindex->nHeight;
LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight);
Expand Down
5 changes: 3 additions & 2 deletions src/governance/governance.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,9 @@ class CGovernanceManager : public GovernanceStore

void ProcessMessage(CNode& peer, PeerManager& peerman, CConnman& connman, std::string_view msg_type, CDataStream& vRecv);

std::optional<CSuperblock> CreateSuperblockCandidate(int nHeight) const;
void CreateGovernanceTrigger(const CSuperblock& sb, CConnman& connman);
const std::optional<CSuperblock> CreateSuperblockCandidate(int nHeight) const;
const std::optional<CGovernanceObject> CreateGovernanceTrigger(const std::optional<CSuperblock>& sb_opt, CConnman& connman);
void VoteGovernanceTriggers(const std::optional<CGovernanceObject>& trigger_opt, CConnman& connman);
bool VoteFundingTrigger(const uint256& nHash, const vote_outcome_enum_t outcome, CConnman& connman);
bool HasAlreadyVotedFundingTrigger() const;
void ResetVotedFundingTrigger();
Expand Down

0 comments on commit c3de9a8

Please sign in to comment.