bool CGovernanceObject::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman* connman) { LOCK(cs_fobject); std::string strResult; // do not process already known valid votes twice if (fileVotes.HasVote(vote.GetHash())) { // nothing to do here, not an error strResult = "CGovernanceObject::ProcessVote -- Already known valid vote"; LogPrint(BCLog::GOV, "%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_NONE); return false; } if (!mnodeman.Has(vote.GetMasternodeOutpoint())) { strResult = strprintf("CGovernanceObject::ProcessVote -- Masternode " + vote.GetMasternodeOutpoint().ToStringShort() + " not found"); LogPrint(BCLog::GOV, "%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_WARNING); if (cmmapOrphanVotes.Insert(vote.GetMasternodeOutpoint(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { if (pfrom) { mnodeman.AskForMN(pfrom, vote.GetMasternodeOutpoint(), connman); } LogPrintf("%s\n", strResult); } else { LogPrint(BCLog::GOV, "%s\n", strResult); } return false; } vote_m_it it = mapCurrentMNVotes.emplace(vote_m_t::value_type(vote.GetMasternodeOutpoint(), vote_rec_t())).first; vote_rec_t& voteRecordRef = it->second; vote_signal_enum_t eSignal = vote.GetSignal(); if (eSignal == VOTE_SIGNAL_NONE) { strResult = "CGovernanceObject::ProcessVote -- Vote signal: none"; LogPrint(BCLog::GOV, "%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_WARNING); return false; } if (eSignal > MAX_SUPPORTED_VOTE_SIGNAL) { strResult = strprintf("CGovernanceObject::ProcessVote -- Unsupported vote signal: " + CGovernanceVoting::ConvertSignalToString(vote.GetSignal())); LogPrintf("%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); return false; } vote_instance_m_it it2 = voteRecordRef.mapInstances.emplace(vote_instance_m_t::value_type(int(eSignal), vote_instance_t())).first; vote_instance_t& voteInstanceRef = it2->second; // Reject obsolete votes if (vote.GetTimestamp() < voteInstanceRef.nCreationTime) { strResult = "CGovernanceObject::ProcessVote -- Obsolete vote"; LogPrint(BCLog::GOV, "%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_NONE); return false; } int64_t nNow = GetAdjustedTime(); int64_t nVoteTimeUpdate = voteInstanceRef.nTime; if (governance.AreRateChecksEnabled()) { int64_t nTimeDelta = nNow - voteInstanceRef.nTime; if (nTimeDelta < GOVERNANCE_UPDATE_MIN) { strResult = strprintf("CGovernanceObject::ProcessVote -- Masternode voting too often, MN outpoint = " + vote.GetMasternodeOutpoint().ToStringShort() + ", governance object hash = " + GetHash().ToString() + ", time delta = %d", nTimeDelta); LogPrint(BCLog::GOV, "%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_TEMPORARY_ERROR); nVoteTimeUpdate = nNow; return false; } } // Finally check that the vote is actually valid (done last because of cost of signature verification) if (!vote.IsValid(true)) { strResult = strprintf("CGovernanceObject::ProcessVote -- Invalid vote, MN outpoint = " + vote.GetMasternodeOutpoint().ToStringShort() + ", governance object hash = " + GetHash().ToString() + ", vote hash = " + vote.GetHash().ToString()); LogPrintf("%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); governance.AddInvalidVote(vote); return false; } if (!mnodeman.AddGovernanceVote(vote.GetMasternodeOutpoint(), vote.GetParentHash())) { strResult = strprintf("CGovernanceObject::ProcessVote -- Unable to add governance vote, MN outpoint = " + vote.GetMasternodeOutpoint().ToStringShort() + ", governance object hash = " + GetHash().ToString()); LogPrint(BCLog::GOV, "%s\n", strResult); exception = CGovernanceException(strResult, GOVERNANCE_EXCEPTION_PERMANENT_ERROR); return false; } voteInstanceRef = vote_instance_t(vote.GetOutcome(), nVoteTimeUpdate, vote.GetTimestamp()); fileVotes.AddVote(vote); fDirtyCache = true; return true; }
bool CGovernanceObject::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) { LOCK(cs); // do not process already known valid votes twice if (fileVotes.HasVote(vote.GetHash())) { // nothing to do here, not an error std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Already known valid vote"; LogPrint("gobject", "%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_NONE); return false; } auto mnList = deterministicMNManager->GetListAtChainTip(); auto dmn = mnList.GetValidMNByCollateral(vote.GetMasternodeOutpoint()); if (!dmn) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Masternode " << vote.GetMasternodeOutpoint().ToStringShort() << " not found"; exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING); if (cmmapOrphanVotes.Insert(vote.GetMasternodeOutpoint(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { LogPrintf("%s\n", ostr.str()); } else { LogPrint("gobject", "%s\n", ostr.str()); } return false; } vote_m_it it = mapCurrentMNVotes.emplace(vote_m_t::value_type(vote.GetMasternodeOutpoint(), vote_rec_t())).first; vote_rec_t& voteRecordRef = it->second; vote_signal_enum_t eSignal = vote.GetSignal(); if (eSignal == VOTE_SIGNAL_NONE) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Vote signal: none"; LogPrint("gobject", "%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING); return false; } if (eSignal > MAX_SUPPORTED_VOTE_SIGNAL) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Unsupported vote signal: " << CGovernanceVoting::ConvertSignalToString(vote.GetSignal()); LogPrintf("%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); return false; } vote_instance_m_it it2 = voteRecordRef.mapInstances.emplace(vote_instance_m_t::value_type(int(eSignal), vote_instance_t())).first; vote_instance_t& voteInstanceRef = it2->second; // Reject obsolete votes if (vote.GetTimestamp() < voteInstanceRef.nCreationTime) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Obsolete vote"; LogPrint("gobject", "%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_NONE); return false; } else if (vote.GetTimestamp() == voteInstanceRef.nCreationTime) { // Someone is doing smth fishy, there can be no two votes from the same masternode // with the same timestamp for the same object and signal and yet different hash/outcome. std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Invalid vote, same timestamp for the different outcome"; if (vote.GetOutcome() < voteInstanceRef.eOutcome) { // This is an arbitrary comparison, we have to agree on some way // to pick the "winning" vote. ostr << ", rejected"; LogPrint("gobject", "%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_NONE); return false; } ostr << ", accepted"; LogPrint("gobject", "%s\n", ostr.str()); } int64_t nNow = GetAdjustedTime(); int64_t nVoteTimeUpdate = voteInstanceRef.nTime; if (governance.AreRateChecksEnabled()) { int64_t nTimeDelta = nNow - voteInstanceRef.nTime; if (nTimeDelta < GOVERNANCE_UPDATE_MIN) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Masternode voting too often" << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort() << ", governance object hash = " << GetHash().ToString() << ", time delta = " << nTimeDelta; LogPrint("gobject", "%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_TEMPORARY_ERROR); return false; } nVoteTimeUpdate = nNow; } bool onlyVotingKeyAllowed = nObjectType == GOVERNANCE_OBJECT_PROPOSAL && vote.GetSignal() == VOTE_SIGNAL_FUNDING; // Finally check that the vote is actually valid (done last because of cost of signature verification) if (!vote.IsValid(onlyVotingKeyAllowed)) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Invalid vote" << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort() << ", governance object hash = " << GetHash().ToString() << ", vote hash = " << vote.GetHash().ToString(); LogPrintf("%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); governance.AddInvalidVote(vote); return false; } if (!mmetaman.AddGovernanceVote(dmn->proTxHash, vote.GetParentHash())) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Unable to add governance vote" << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort() << ", governance object hash = " << GetHash().ToString(); LogPrint("gobject", "%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR); return false; } voteInstanceRef = vote_instance_t(vote.GetOutcome(), nVoteTimeUpdate, vote.GetTimestamp()); fileVotes.AddVote(vote); fDirtyCache = true; return true; }