Merge pull request #2594 from codablock/pr_dip3_cleanup_directlyusedmnmgr

Directly use deterministicMNManager instead of compat code in CMasternodeMan
This commit is contained in:
Alexander Block 2019-01-02 06:58:33 +01:00 committed by GitHub
commit 46a6fc33e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 525 additions and 857 deletions

View File

@ -151,6 +151,15 @@ CDeterministicMNCPtr CDeterministicMNList::GetMNByCollateral(const COutPoint& co
return GetUniquePropertyMN(collateralOutpoint);
}
CDeterministicMNCPtr CDeterministicMNList::GetValidMNByCollateral(const COutPoint& collateralOutpoint) const
{
auto dmn = GetMNByCollateral(collateralOutpoint);
if (dmn && !IsMNValid(dmn)) {
return nullptr;
}
return dmn;
}
static int CompareByLastPaid_GetHeight(const CDeterministicMN& dmn)
{
int height = dmn.pdmnState->nLastPaidHeight;
@ -826,20 +835,6 @@ CDeterministicMNList CDeterministicMNManager::GetListAtChainTip()
return GetListForBlock(tipBlockHash);
}
bool CDeterministicMNManager::HasValidMNCollateralAtChainTip(const COutPoint& outpoint)
{
auto mnList = GetListAtChainTip();
auto dmn = mnList.GetMNByCollateral(outpoint);
return dmn && mnList.IsMNValid(dmn);
}
bool CDeterministicMNManager::HasMNCollateralAtChainTip(const COutPoint& outpoint)
{
auto mnList = GetListAtChainTip();
auto dmn = mnList.GetMNByCollateral(outpoint);
return dmn != nullptr;
}
bool CDeterministicMNManager::IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n)
{
if (tx->nVersion != 3 || tx->nType != TRANSACTION_PROVIDER_REGISTER) {

View File

@ -289,10 +289,23 @@ public:
{
return GetMN(proTxHash) != nullptr;
}
bool HasValidMN(const uint256& proTxHash) const
{
return GetValidMN(proTxHash) != nullptr;
}
bool HasMNByCollateral(const COutPoint& collateralOutpoint) const
{
return GetMNByCollateral(collateralOutpoint) != nullptr;
}
bool HasValidMNByCollateral(const COutPoint& collateralOutpoint) const
{
return GetValidMNByCollateral(collateralOutpoint) != nullptr;
}
CDeterministicMNCPtr GetMN(const uint256& proTxHash) const;
CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const;
CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey);
CDeterministicMNCPtr GetMNByCollateral(const COutPoint& collateralOutpoint) const;
CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const;
CDeterministicMNCPtr GetMNPayee() const;
/**
@ -479,10 +492,6 @@ public:
CDeterministicMNList GetListForBlock(const uint256& blockHash);
CDeterministicMNList GetListAtChainTip();
// TODO remove after removal of old non-deterministic lists
bool HasValidMNCollateralAtChainTip(const COutPoint& outpoint);
bool HasMNCollateralAtChainTip(const COutPoint& outpoint);
// Test if given TX is a ProRegTx which also contains the collateral at index n
bool IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n);

View File

@ -116,14 +116,13 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom,
return false;
}
if (!mnodeman.Has(vote.GetMasternodeOutpoint())) {
auto mnList = deterministicMNManager->GetListAtChainTip();
if (!mnList.HasValidMNByCollateral(vote.GetMasternodeOutpoint())) {
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))) {
if (pfrom) {
mnodeman.AskForMN(pfrom, vote.GetMasternodeOutpoint(), connman);
}
LogPrintf("%s\n", ostr.str());
} else {
LogPrint("gobject", "%s\n", ostr.str());
@ -212,9 +211,11 @@ void CGovernanceObject::ClearMasternodeVotes()
{
LOCK(cs);
auto mnList = deterministicMNManager->GetListAtChainTip();
vote_m_it it = mapCurrentMNVotes.begin();
while (it != mapCurrentMNVotes.end()) {
if (!mnodeman.Has(it->first)) {
if (!mnList.HasValidMNByCollateral(it->first)) {
fileVotes.RemoveVotesFromMasternode(it->first);
mapCurrentMNVotes.erase(it++);
} else {
@ -552,9 +553,11 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
return true;
}
auto mnList = deterministicMNManager->GetListAtChainTip();
std::string strOutpoint = masternodeOutpoint.ToStringShort();
masternode_info_t infoMn;
if (!mnodeman.GetMasternodeInfo(masternodeOutpoint, infoMn)) {
auto dmn = mnList.GetValidMNByCollateral(masternodeOutpoint);
if (!dmn) {
CMasternode::CollateralStatus err = CMasternode::CheckCollateral(masternodeOutpoint, CKeyID());
if (err == CMasternode::COLLATERAL_UTXO_NOT_FOUND) {
strError = "Failed to find Masternode UTXO, missing masternode=" + strOutpoint + "\n";
@ -572,16 +575,9 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
}
// Check that we have a valid MN signature
if (deterministicMNManager->IsDIP3Active()) {
if (!CheckSignature(infoMn.blsPubKeyOperator)) {
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.blsPubKeyOperator.ToString();
return false;
}
} else {
if (!CheckSignature(infoMn.legacyKeyIDOperator)) {
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.legacyKeyIDOperator.ToString();
return false;
}
if (!CheckSignature(dmn->pdmnState->pubKeyOperator)) {
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.ToString();
return false;
}
return true;
@ -779,7 +775,7 @@ void CGovernanceObject::UpdateSentinelVariables()
{
// CALCULATE MINIMUM SUPPORT LEVELS REQUIRED
int nMnCount = mnodeman.CountEnabled();
int nMnCount = (int)deterministicMNManager->GetListAtChainTip().GetValidMNsCount();
if (nMnCount == 0) return;
// CALCULATE THE MINUMUM VOTE COUNT REQUIRED FOR FULL SIGNAL
@ -812,6 +808,7 @@ void CGovernanceObject::UpdateSentinelVariables()
void CGovernanceObject::CheckOrphanVotes(CConnman& connman)
{
int64_t nNow = GetAdjustedTime();
auto mnList = deterministicMNManager->GetListAtChainTip();
const vote_cmm_t::list_t& listVotes = cmmapOrphanVotes.GetItemList();
vote_cmm_t::list_cit it = listVotes.begin();
while (it != listVotes.end()) {
@ -821,7 +818,7 @@ void CGovernanceObject::CheckOrphanVotes(CConnman& connman)
const CGovernanceVote& vote = pairVote.first;
if (pairVote.second < nNow) {
fRemove = true;
} else if (!mnodeman.Has(vote.GetMasternodeOutpoint())) {
} else if (!mnList.HasValidMNByCollateral(vote.GetMasternodeOutpoint())) {
++it;
continue;
}

View File

@ -256,20 +256,16 @@ bool CGovernanceVote::IsValid(bool useVotingKey) const
return false;
}
masternode_info_t infoMn;
if (!mnodeman.GetMasternodeInfo(masternodeOutpoint, infoMn)) {
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(masternodeOutpoint);
if (!dmn) {
LogPrint("gobject", "CGovernanceVote::IsValid -- Unknown Masternode - %s\n", masternodeOutpoint.ToStringShort());
return false;
}
if (useVotingKey) {
return CheckSignature(infoMn.keyIDVoting);
return CheckSignature(dmn->pdmnState->keyIDVoting);
} else {
if (deterministicMNManager->IsDIP3Active()) {
return CheckSignature(infoMn.blsPubKeyOperator);
} else {
return CheckSignature(infoMn.legacyKeyIDOperator);
}
return CheckSignature(dmn->pdmnState->pubKeyOperator);
}
}

View File

@ -515,12 +515,17 @@ std::vector<CGovernanceVote> CGovernanceManager::GetCurrentVotes(const uint256&
if (it == mapObjects.end()) return vecResult;
const CGovernanceObject& govobj = it->second;
CMasternode mn;
std::map<COutPoint, CMasternode> mapMasternodes;
auto mnList = deterministicMNManager->GetListAtChainTip();
std::map<COutPoint, CDeterministicMNCPtr> mapMasternodes;
if (mnCollateralOutpointFilter.IsNull()) {
mapMasternodes = mnodeman.GetFullMasternodeMap();
} else if (mnodeman.Get(mnCollateralOutpointFilter, mn)) {
mapMasternodes[mnCollateralOutpointFilter] = mn;
mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
mapMasternodes.emplace(dmn->collateralOutpoint, dmn);
});
} else {
auto dmn = mnList.GetValidMNByCollateral(mnCollateralOutpointFilter);
if (dmn) {
mapMasternodes.emplace(dmn->collateralOutpoint, dmn);
}
}
// Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object
@ -1074,7 +1079,7 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector<CNode*>&
int nMaxObjRequestsPerNode = 1;
size_t nProjectedVotes = 2000;
if (Params().NetworkIDString() != CBaseChainParams::MAIN) {
nMaxObjRequestsPerNode = std::max(1, int(nProjectedVotes / std::max(1, mnodeman.size())));
nMaxObjRequestsPerNode = std::max(1, int(nProjectedVotes / std::max(1, (int)deterministicMNManager->GetListAtChainTip().GetValidMNsCount())));
}
{

View File

@ -245,8 +245,7 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman)
int nRank;
uint256 quorumModifierHash;
int nMinRequiredProtocol = std::max(MIN_INSTANTSEND_PROTO_VERSION, mnpayments.GetMinMasternodePaymentsProto());
if (!mnodeman.GetMasternodeRank(activeMasternodeInfo.outpoint, nRank, quorumModifierHash, nLockInputHeight, nMinRequiredProtocol)) {
if (!mnodeman.GetMasternodeRank(activeMasternodeInfo.outpoint, nRank, quorumModifierHash, nLockInputHeight)) {
LogPrint("instantsend", "CInstantSend::Vote -- Can't calculate rank for masternode %s\n", activeMasternodeInfo.outpoint.ToStringShort());
continue;
}
@ -469,7 +468,8 @@ void CInstantSend::UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidat
txLockCandidate.MarkOutpointAsAttacked(vote.GetOutpoint());
it2->second.MarkOutpointAsAttacked(vote.GetOutpoint());
// apply maximum PoSe ban score to this masternode i.e. PoSe-ban it instantly
mnodeman.PoSeBan(vote.GetMasternodeOutpoint());
// TODO Call new PoSe system when it's ready
//mnodeman.PoSeBan(vote.GetMasternodeOutpoint());
// NOTE: This vote must be relayed further to let all other nodes know about such
// misbehaviour of this masternode. This way they should also be able to construct
// conflicting lock and PoSe-ban this masternode.
@ -1029,22 +1029,25 @@ bool CTxLockRequest::IsSimple() const
bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const
{
if (!mnodeman.Has(outpointMasternode)) {
auto mnList = deterministicMNManager->GetListAtChainTip();
if (!mnList.HasValidMNByCollateral(outpointMasternode)) {
LogPrint("instantsend", "CTxLockVote::IsValid -- Unknown masternode %s\n", outpointMasternode.ToStringShort());
mnodeman.AskForMN(pnode, outpointMasternode, connman);
return false;
}
// Verify that masternodeProTxHash belongs to the same MN referred by the collateral
// Only v13 nodes will send us locks with this field set, and only after spork15 activation
// This is a leftover from the legacy non-deterministic MN list where we used the collateral to identify MNs
// TODO eventually remove the collateral from CTxLockVote
if (!masternodeProTxHash.IsNull()) {
masternode_info_t mnInfo;
if (!mnodeman.GetMasternodeInfo(masternodeProTxHash, mnInfo) || mnInfo.outpoint != outpointMasternode) {
auto dmn = mnList.GetValidMN(masternodeProTxHash);
if (!dmn || dmn->collateralOutpoint != outpointMasternode) {
LogPrint("instantsend", "CTxLockVote::IsValid -- invalid masternodeProTxHash %s\n", masternodeProTxHash.ToString());
return false;
}
} else if (deterministicMNManager->IsDIP3Active()) {
LogPrint("instantsend", "CTxLockVote::IsValid -- missing masternodeProTxHash while DIP3 is active\n");
} else {
LogPrint("instantsend", "CTxLockVote::IsValid -- missing masternodeProTxHash\n");
return false;
}
@ -1058,8 +1061,7 @@ bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const
int nRank;
uint256 expectedQuorumModifierHash;
int nMinRequiredProtocol = std::max(MIN_INSTANTSEND_PROTO_VERSION, mnpayments.GetMinMasternodePaymentsProto());
if (!mnodeman.GetMasternodeRank(outpointMasternode, nRank, expectedQuorumModifierHash, nLockInputHeight, nMinRequiredProtocol)) {
if (!mnodeman.GetMasternodeRank(outpointMasternode, nRank, expectedQuorumModifierHash, nLockInputHeight)) {
//can be caused by past versions trying to vote with an invalid protocol
LogPrint("instantsend", "CTxLockVote::IsValid -- Can't calculate rank for masternode %s\n", outpointMasternode.ToStringShort());
return false;
@ -1105,83 +1107,33 @@ bool CTxLockVote::CheckSignature() const
{
std::string strError;
masternode_info_t infoMn;
if (!mnodeman.GetMasternodeInfo(outpointMasternode, infoMn)) {
LogPrintf("CTxLockVote::CheckSignature -- Unknown Masternode: masternode=%s\n", outpointMasternode.ToString());
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(masternodeProTxHash);
if (!dmn) {
LogPrintf("CTxLockVote::CheckSignature -- Unknown Masternode: masternode=%s\n", masternodeProTxHash.ToString());
return false;
}
if (deterministicMNManager->IsDIP3Active()) {
uint256 hash = GetSignatureHash();
uint256 hash = GetSignatureHash();
CBLSSignature sig;
sig.SetBuf(vchMasternodeSignature);
if (!sig.IsValid() || !sig.VerifyInsecure(infoMn.blsPubKeyOperator, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, infoMn.legacyKeyIDOperator, vchMasternodeSignature, strError)) {
// could be a signature in old format
std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
if (!CMessageSigner::VerifyMessage(infoMn.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) {
// nope, not in old format either
LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
}
} else {
std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
if (!CMessageSigner::VerifyMessage(infoMn.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
CBLSSignature sig;
sig.SetBuf(vchMasternodeSignature);
if (!sig.IsValid() || !sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;
}
bool CTxLockVote::Sign()
{
std::string strError;
if (deterministicMNManager->IsDIP3Active()) {
uint256 hash = GetSignatureHash();
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
sig.GetBuf(vchMasternodeSignature);
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchMasternodeSignature)) {
LogPrintf("CTxLockVote::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchMasternodeSignature, strError)) {
LogPrintf("CTxLockVote::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
if (!CMessageSigner::SignMessage(strMessage, vchMasternodeSignature, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CTxLockVote::Sign -- SignMessage() failed\n");
return false;
}
if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) {
LogPrintf("CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
sig.GetBuf(vchMasternodeSignature);
return true;
}

View File

@ -641,36 +641,16 @@ bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward,
// Is this masternode scheduled to get paid soon?
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 blocks of votes
bool CMasternodePayments::IsScheduled(const masternode_info_t& mnInfo, int nNotBlockHeight) const
bool CMasternodePayments::IsScheduled(const CDeterministicMNCPtr& dmnIn, int nNotBlockHeight) const
{
LOCK(cs_mapMasternodeBlocks);
if (deterministicMNManager->IsDIP3Active()) {
auto projectedPayees = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(8);
for (const auto &dmn : projectedPayees) {
if (dmn->collateralOutpoint == mnInfo.outpoint) {
return true;
}
}
return false;
}
if(!masternodeSync.IsMasternodeListSynced()) return false;
CScript mnpayee;
mnpayee = GetScriptForDestination(mnInfo.keyIDCollateralAddress);
for(int64_t h = nCachedBlockHeight; h <= nCachedBlockHeight + 8; h++){
if(h == nNotBlockHeight) continue;
std::vector<CTxOut> voutMasternodePayments;
if(GetBlockTxOuts(h, 0, voutMasternodePayments)) {
for (const auto& txout : voutMasternodePayments) {
if (txout.scriptPubKey == mnpayee)
return true;
}
auto projectedPayees = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(8);
for (const auto &dmn : projectedPayees) {
if (dmn->proTxHash == dmnIn->proTxHash) {
return true;
}
}
return false;
}
@ -1046,7 +1026,7 @@ void CMasternodePayments::CheckBlockVotes(int nBlockHeight)
voteHash.ToString());
continue;
}
if (itVote->second.masternodeOutpoint == mn.second.outpoint) {
if (itVote->second.masternodeOutpoint == mn.second->collateralOutpoint) {
payee = itVote->second.payee;
found = true;
break;
@ -1061,12 +1041,12 @@ void CMasternodePayments::CheckBlockVotes(int nBlockHeight)
CBitcoinAddress address2(address1);
debugStr += strprintf(" - %s - voted for %s\n",
mn.second.outpoint.ToStringShort(), address2.ToString());
mn.second->collateralOutpoint.ToStringShort(), address2.ToString());
} else {
mapMasternodesDidNotVote.emplace(mn.second.outpoint, 0).first->second++;
mapMasternodesDidNotVote.emplace(mn.second->collateralOutpoint, 0).first->second++;
debugStr += strprintf(" - %s - no vote received\n",
mn.second.outpoint.ToStringShort());
mn.second->collateralOutpoint.ToStringShort());
}
if (++i >= MNPAYMENTS_SIGNATURES_TOTAL) break;

View File

@ -200,7 +200,7 @@ public:
bool GetBlockTxOuts(int nBlockHeight, CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet) const;
bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const;
bool IsScheduled(const masternode_info_t& mnInfo, int nNotBlockHeight) const;
bool IsScheduled(const CDeterministicMNCPtr& dmn, int nNotBlockHeight) const;
bool UpdateLastVote(const CMasternodePaymentVote& vote);

View File

@ -42,10 +42,10 @@ struct CompareLastPaidBlock
struct CompareScoreMN
{
bool operator()(const std::pair<arith_uint256, const CMasternode*>& t1,
const std::pair<arith_uint256, const CMasternode*>& t2) const
bool operator()(const std::pair<arith_uint256, const CDeterministicMNCPtr&>& t1,
const std::pair<arith_uint256, const CDeterministicMNCPtr&>& t2) const
{
return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->outpoint < t2.second->outpoint);
return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->collateralOutpoint < t2.second->collateralOutpoint);
}
};
@ -127,6 +127,16 @@ void CMasternodeMan::AskForMN(CNode* pnode, const COutPoint& outpoint, CConnman&
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSEG, outpoint));
}
bool CMasternodeMan::IsValidForMixingTxes(const COutPoint& outpoint)
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if (!pmn) {
return false;
}
return pmn->IsValidForMixingTxes();
}
bool CMasternodeMan::AllowMixing(const COutPoint &outpoint)
{
LOCK(cs);
@ -153,6 +163,16 @@ bool CMasternodeMan::DisallowMixing(const COutPoint &outpoint)
return true;
}
int64_t CMasternodeMan::GetLastDsq(const COutPoint& outpoint)
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if (!pmn) {
return 0;
}
return pmn->nLastDsq;
}
bool CMasternodeMan::PoSeBan(const COutPoint &outpoint)
{
LOCK(cs);
@ -237,9 +257,9 @@ void CMasternodeMan::CheckAndRemove(CConnman& connman)
// ask first MNB_RECOVERY_QUORUM_TOTAL masternodes we can connect to and we haven't asked recently
for(int i = 0; setRequested.size() < MNB_RECOVERY_QUORUM_TOTAL && i < (int)vecMasternodeRanks.size(); i++) {
// avoid banning
if(mWeAskedForMasternodeListEntry.count(it->first) && mWeAskedForMasternodeListEntry[it->first].count(vecMasternodeRanks[i].second.addr)) continue;
if(mWeAskedForMasternodeListEntry.count(it->first) && mWeAskedForMasternodeListEntry[it->first].count(vecMasternodeRanks[i].second->pdmnState->addr)) continue;
// didn't ask recently, ok to ask now
CService addr = vecMasternodeRanks[i].second.addr;
CService addr = vecMasternodeRanks[i].second->pdmnState->addr;
setRequested.insert(addr);
listScheduledMnbRequestConnections.push_back(std::make_pair(addr, hash));
fAskedForMnbRecovery = true;
@ -633,7 +653,7 @@ bool CMasternodeMan::Has(const COutPoint& outpoint)
{
LOCK(cs);
if (deterministicMNManager->IsDIP3Active()) {
return deterministicMNManager->HasValidMNCollateralAtChainTip(outpoint);
return deterministicMNManager->GetListAtChainTip().HasValidMNByCollateral(outpoint);
} else {
return mapMasternodes.find(outpoint) != mapMasternodes.end();
}
@ -679,7 +699,7 @@ bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool f
if(mnpair.second.nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto()) continue;
//it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it
if(mnpayments.IsScheduled(mnpair.second, nBlockHeight)) continue;
//if(mnpayments.IsScheduled(mnpair.second, nBlockHeight)) continue;
//it's too new, wait for a cycle
if(fFilterSigTime && mnpair.second.sigTime + (nMnCount*2.6*60) > GetAdjustedTime()) continue;
@ -727,51 +747,6 @@ bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool f
return mnInfoRet.fInfoValid;
}
masternode_info_t CMasternodeMan::FindRandomNotInVec(const std::vector<COutPoint> &vecToExclude, int nProtocolVersion)
{
LOCK(cs);
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
int nCountEnabled = CountEnabled(nProtocolVersion);
int nCountNotExcluded = nCountEnabled - vecToExclude.size();
LogPrintf("CMasternodeMan::FindRandomNotInVec -- %d enabled masternodes, %d masternodes to choose from\n", nCountEnabled, nCountNotExcluded);
if(nCountNotExcluded < 1) return masternode_info_t();
// fill a vector of pointers
std::vector<const CMasternode*> vpMasternodesShuffled;
for (const auto& mnpair : mapMasternodes) {
vpMasternodesShuffled.push_back(&mnpair.second);
}
FastRandomContext insecure_rand;
// shuffle pointers
std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecure_rand);
bool fExclude;
// loop through
for (const auto& pmn : vpMasternodesShuffled) {
if(pmn->nProtocolVersion < nProtocolVersion || !pmn->IsEnabled()) continue;
fExclude = false;
for (const auto& outpointToExclude : vecToExclude) {
if(pmn->outpoint == outpointToExclude) {
fExclude = true;
break;
}
}
if(fExclude) continue;
if (deterministicMNManager->IsDIP3Active() && !deterministicMNManager->HasValidMNCollateralAtChainTip(pmn->outpoint))
continue;
// found the one not in vecToExclude
LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- found, masternode=%s\n", pmn->outpoint.ToStringShort());
return pmn->GetInfo();
}
LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- failed\n");
return masternode_info_t();
}
std::map<COutPoint, CMasternode> CMasternodeMan::GetFullMasternodeMap()
{
LOCK(cs);
@ -791,33 +766,18 @@ std::map<COutPoint, CMasternode> CMasternodeMan::GetFullMasternodeMap()
}
}
bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol)
bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet)
{
AssertLockHeld(cs);
vecMasternodeScoresRet.clear();
if (deterministicMNManager->IsDIP3Active()) {
auto mnList = deterministicMNManager->GetListAtChainTip();
auto scores = mnList.CalculateScores(nBlockHash);
for (const auto& p : scores) {
auto* mn = Find(p.second->collateralOutpoint);
vecMasternodeScoresRet.emplace_back(p.first, mn);
}
} else {
if (!masternodeSync.IsMasternodeListSynced())
return false;
if (mapMasternodes.empty())
return false;
// calculate scores
for (const auto& mnpair : mapMasternodes) {
if (mnpair.second.nProtocolVersion >= nMinProtocol) {
vecMasternodeScoresRet.push_back(std::make_pair(mnpair.second.CalculateScore(nBlockHash), &mnpair.second));
}
}
auto mnList = deterministicMNManager->GetListAtChainTip();
auto scores = mnList.CalculateScores(nBlockHash);
for (const auto& p : scores) {
vecMasternodeScoresRet.emplace_back(p.first, p.second);
}
sort(vecMasternodeScoresRet.rbegin(), vecMasternodeScoresRet.rend(), CompareScoreMN());
return !vecMasternodeScoresRet.empty();
}
@ -845,13 +805,13 @@ bool CMasternodeMan::GetMasternodeRank(const COutPoint& outpoint, int& nRankRet,
LOCK(cs);
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(blockHashRet, vecMasternodeScores, nMinProtocol))
if (!GetMasternodeScores(blockHashRet, vecMasternodeScores))
return false;
int nRank = 0;
for (const auto& scorePair : vecMasternodeScores) {
nRank++;
if(scorePair.second->outpoint == outpoint) {
if(scorePair.second->collateralOutpoint == outpoint) {
nRankRet = nRank;
return true;
}
@ -877,13 +837,13 @@ bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMast
LOCK(cs);
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol))
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores))
return false;
int nRank = 0;
for (const auto& scorePair : vecMasternodeScores) {
nRank++;
vecMasternodeRanksRet.push_back(std::make_pair(nRank, *scorePair.second));
vecMasternodeRanksRet.push_back(std::make_pair(nRank, scorePair.second));
}
return true;
@ -891,17 +851,17 @@ bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMast
void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman)
{
std::vector<masternode_info_t> vecMnInfo; // will be empty when no wallet
std::vector<CDeterministicMNCPtr> vecDmns; // will be empty when no wallet
#ifdef ENABLE_WALLET
privateSendClient.GetMixingMasternodesInfo(vecMnInfo);
privateSendClient.GetMixingMasternodesInfo(vecDmns);
#endif // ENABLE_WALLET
connman.ForEachNode(CConnman::AllNodes, [&vecMnInfo](CNode* pnode) {
connman.ForEachNode(CConnman::AllNodes, [&](CNode* pnode) {
if (pnode->fMasternode) {
#ifdef ENABLE_WALLET
bool fFound = false;
for (const auto& mnInfo : vecMnInfo) {
if (pnode->addr == mnInfo.addr) {
for (const auto& dmn : vecDmns) {
if (pnode->addr == dmn->pdmnState->addr) {
fFound = true;
break;
}
@ -1213,7 +1173,7 @@ void CMasternodeMan::DoFullVerificationStep(CConnman& connman)
(int)MAX_POSE_RANK);
return;
}
if(rankPair.second.outpoint == activeMasternodeInfo.outpoint) {
if(rankPair.second->collateralOutpoint == activeMasternodeInfo.outpoint) {
nMyRank = rankPair.first;
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d masternodes\n",
nMyRank, nRanksTotal, (int)MAX_POSE_CONNECTIONS);
@ -1231,20 +1191,20 @@ void CMasternodeMan::DoFullVerificationStep(CConnman& connman)
auto it = vecMasternodeRanks.begin() + nOffset;
while(it != vecMasternodeRanks.end()) {
if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) {
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping...\n",
it->second.IsPoSeVerified() ? "verified" : "",
it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "",
it->second.IsPoSeBanned() ? "banned" : "",
it->second.outpoint.ToStringShort(), it->second.addr.ToString());
nOffset += MAX_POSE_CONNECTIONS;
if(nOffset >= (int)vecMasternodeRanks.size()) break;
it += MAX_POSE_CONNECTIONS;
continue;
}
// if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) {
// LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping...\n",
// it->second.IsPoSeVerified() ? "verified" : "",
// it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "",
// it->second.IsPoSeBanned() ? "banned" : "",
// it->second.outpoint.ToStringShort(), it->second.addr.ToString());
// nOffset += MAX_POSE_CONNECTIONS;
// if(nOffset >= (int)vecMasternodeRanks.size()) break;
// it += MAX_POSE_CONNECTIONS;
// continue;
// }
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Verifying masternode %s rank %d/%d address %s\n",
it->second.outpoint.ToStringShort(), it->first, nRanksTotal, it->second.addr.ToString());
CAddress addr = CAddress(it->second.addr, NODE_NETWORK);
it->second->collateralOutpoint.ToStringShort(), it->first, nRanksTotal, it->second->pdmnState->addr.ToString());
CAddress addr = CAddress(it->second->pdmnState->addr, NODE_NETWORK);
if(CheckVerifyRequestAddr(addr, connman)) {
vAddr.push_back(addr);
if((int)vAddr.size() >= MAX_POSE_CONNECTIONS) break;

View File

@ -8,6 +8,8 @@
#include "masternode.h"
#include "sync.h"
#include "evo/deterministicmns.h"
class CMasternodeMan;
class CConnman;
@ -16,9 +18,9 @@ extern CMasternodeMan mnodeman;
class CMasternodeMan
{
public:
typedef std::pair<arith_uint256, const CMasternode*> score_pair_t;
typedef std::pair<arith_uint256, CDeterministicMNCPtr> score_pair_t;
typedef std::vector<score_pair_t> score_pair_vec_t;
typedef std::pair<int, const CMasternode> rank_pair_t;
typedef std::pair<int, CDeterministicMNCPtr> rank_pair_t;
typedef std::vector<rank_pair_t> rank_pair_vec_t;
private:
@ -80,7 +82,7 @@ private:
/// Find an entry
CMasternode* Find(const COutPoint& outpoint);
bool GetMasternodeScores(const uint256& nBlockHash, score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol = 0);
bool GetMasternodeScores(const uint256& nBlockHash, score_pair_vec_t& vecMasternodeScoresRet);
void SyncSingle(CNode* pnode, const COutPoint& outpoint, CConnman& connman);
void SyncAll(CNode* pnode, CConnman& connman);
@ -137,8 +139,10 @@ public:
void AskForMN(CNode *pnode, const COutPoint& outpoint, CConnman& connman);
bool PoSeBan(const COutPoint &outpoint);
bool IsValidForMixingTxes(const COutPoint &outpoint);
bool AllowMixing(const COutPoint &outpoint);
bool DisallowMixing(const COutPoint &outpoint);
int64_t GetLastDsq(const COutPoint &outpoint);
/// Check all Masternodes
void Check();
@ -180,9 +184,6 @@ public:
/// Same as above but use current block height
bool GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet);
/// Find a random entry
masternode_info_t FindRandomNotInVec(const std::vector<COutPoint> &vecToExclude, int nProtocolVersion = -1);
std::map<COutPoint, CMasternode> GetFullMasternodeMap();
bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0);

View File

@ -2079,21 +2079,20 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true; // not an error
}
CMasternode mn;
if(!mnodeman.Get(dstx.masternodeOutpoint, mn)) {
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(dstx.masternodeOutpoint);
if(!dmn) {
LogPrint("privatesend", "DSTX -- Can't find masternode %s to verify %s\n", dstx.masternodeOutpoint.ToStringShort(), hashTx.ToString());
return false;
}
if(!mn.IsValidForMixingTxes()) {
if(!mnodeman.IsValidForMixingTxes(dstx.masternodeOutpoint)) {
LogPrint("privatesend", "DSTX -- Masternode %s is sending too many transactions %s\n", dstx.masternodeOutpoint.ToStringShort(), hashTx.ToString());
return true;
// TODO: Not an error? Could it be that someone is relaying old DSTXes
// we have no idea about (e.g we were offline)? How to handle them?
}
if (!dstx.CheckSignature(mn.legacyKeyIDOperator, mn.blsPubKeyOperator)) {
if (!dstx.CheckSignature(dmn->pdmnState->pubKeyOperator)) {
LogPrint("privatesend", "DSTX -- CheckSignature() failed for %s\n", hashTx.ToString());
return false;
}

View File

@ -61,12 +61,13 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
if (dsq.IsExpired()) return;
masternode_info_t infoMn;
if (!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, infoMn)) return;
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
if (!dmn) return;
if (!dsq.CheckSignature(infoMn.legacyKeyIDOperator, infoMn.blsPubKeyOperator)) {
// we probably have outdated info
mnodeman.AskForMN(pfrom, dsq.masternodeOutpoint, connman);
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator)) {
LOCK(cs_main);
Misbehaving(pfrom->id, 10);
return;
}
@ -74,9 +75,9 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
if (dsq.fReady) {
LOCK(cs_deqsessions);
for (auto& session : deqSessions) {
masternode_info_t mnMixing;
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing.addr == infoMn.addr && session.GetState() == POOL_STATE_QUEUE) {
LogPrint("privatesend", "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), infoMn.addr.ToString());
CDeterministicMNCPtr mnMixing;
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->pdmnState->addr == dmn->pdmnState->addr && session.GetState() == POOL_STATE_QUEUE) {
LogPrint("privatesend", "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
session.SubmitDenominate(connman);
return;
}
@ -89,25 +90,26 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
for (const auto& q : vecPrivateSendQueue) {
if (q.masternodeOutpoint == dsq.masternodeOutpoint) {
// no way same mn can send another "not yet ready" dsq this soon
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", infoMn.addr.ToString());
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", dmn->pdmnState->ToString());
return;
}
}
int nThreshold = infoMn.nLastDsq + mnodeman.CountMasternodes() / 5;
LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", infoMn.nLastDsq, nThreshold, mnodeman.nDsqCount);
int64_t nLastDsq = mnodeman.GetLastDsq(dsq.masternodeOutpoint);
int nThreshold = nLastDsq + mnList.GetValidMNsCount() / 5;
LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", nLastDsq, nThreshold, mnodeman.nDsqCount);
//don't allow a few nodes to dominate the queuing process
if (infoMn.nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) {
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", infoMn.addr.ToString());
if (nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) {
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->proTxHash.ToString());
return;
}
if (!mnodeman.AllowMixing(dsq.masternodeOutpoint)) return;
LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), infoMn.addr.ToString());
LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
for (auto& session : deqSessions) {
masternode_info_t mnMixing;
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing.outpoint == dsq.masternodeOutpoint) {
CDeterministicMNCPtr mnMixing;
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->collateralOutpoint == dsq.masternodeOutpoint) {
dsq.fTried = true;
}
}
@ -139,8 +141,8 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string&
return;
}
if (!infoMixingMasternode.fInfoValid) return;
if (infoMixingMasternode.addr != pfrom->addr) {
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->addr != pfrom->addr) {
//LogPrintf("DSSTATUSUPDATE -- message doesn't match current Masternode: infoMixingMasternode %s addr %s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString());
return;
}
@ -181,8 +183,8 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string&
return;
}
if (!infoMixingMasternode.fInfoValid) return;
if (infoMixingMasternode.addr != pfrom->addr) {
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->addr != pfrom->addr) {
//LogPrintf("DSFINALTX -- message doesn't match current Masternode: infoMixingMasternode %s addr %s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString());
return;
}
@ -208,9 +210,9 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string&
return;
}
if (!infoMixingMasternode.fInfoValid) return;
if (infoMixingMasternode.addr != pfrom->addr) {
LogPrint("privatesend", "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString());
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->addr != pfrom->addr) {
LogPrint("privatesend", "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n", mixingMasternode->pdmnState->addr.ToString(), pfrom->addr.ToString());
return;
}
@ -258,7 +260,7 @@ void CPrivateSendClientSession::SetNull()
// Client side
nEntriesCount = 0;
fLastEntryAccepted = false;
infoMixingMasternode = masternode_info_t();
mixingMasternode = nullptr;
pendingDsaRequest = CPendingDsaRequest();
CPrivateSendBaseSession::SetNull();
@ -368,22 +370,22 @@ std::string CPrivateSendClientManager::GetSessionDenoms()
return strSessionDenoms.empty() ? "N/A" : strSessionDenoms;
}
bool CPrivateSendClientSession::GetMixingMasternodeInfo(masternode_info_t& mnInfoRet) const
bool CPrivateSendClientSession::GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const
{
mnInfoRet = infoMixingMasternode.fInfoValid ? infoMixingMasternode : masternode_info_t();
return infoMixingMasternode.fInfoValid;
ret = mixingMasternode;
return ret != nullptr;
}
bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vector<masternode_info_t>& vecMnInfoRet) const
bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const
{
LOCK(cs_deqsessions);
for (const auto& session : deqSessions) {
masternode_info_t mnInfo;
if (session.GetMixingMasternodeInfo(mnInfo)) {
vecMnInfoRet.push_back(mnInfo);
CDeterministicMNCPtr dmn;
if (session.GetMixingMasternodeInfo(dmn)) {
vecDmnsRet.push_back(dmn);
}
}
return !vecMnInfoRet.empty();
return !vecDmnsRet.empty();
}
//
@ -578,7 +580,7 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr
if (!pwalletMain) return false;
if (fMasternodeMode || pnode == nullptr) return false;
if (!infoMixingMasternode.fInfoValid) return false;
if (!mixingMasternode) return false;
finalMutableTransaction = finalTransactionNew;
LogPrintf("CPrivateSendClientSession::SignFinalTransaction -- finalMutableTransaction=%s", finalMutableTransaction.ToString());
@ -588,7 +590,7 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr
sort(finalMutableTransaction.vout.begin(), finalMutableTransaction.vout.end(), CompareOutputBIP69());
if (finalMutableTransaction.GetHash() != finalTransactionNew.GetHash()) {
LogPrintf("CPrivateSendClientSession::SignFinalTransaction -- WARNING! Masternode %s is not BIP69 compliant!\n", infoMixingMasternode.outpoint.ToStringShort());
LogPrintf("CPrivateSendClientSession::SignFinalTransaction -- WARNING! Masternode %s is not BIP69 compliant!\n", mixingMasternode->proTxHash.ToString());
UnlockCoins();
keyHolderStorage.ReturnAll();
SetNull();
@ -832,7 +834,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
return false;
}
if (mnodeman.size() == 0) {
if (deterministicMNManager->GetListAtChainTip().GetValidMNsCount() == 0) {
LogPrint("privatesend", "CPrivateSendClientSession::DoAutomaticDenominating -- No Masternodes detected\n");
strAutoDenomResult = _("No Masternodes detected.");
return false;
@ -952,7 +954,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool
return false;
}
int nMnCountEnabled = mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION);
int nMnCountEnabled = deterministicMNManager->GetListAtChainTip().GetValidMNsCount();
// If we've used 90% of the Masternode list then drop the oldest first ~30%
int nThreshold_high = nMnCountEnabled * 0.9;
@ -990,31 +992,65 @@ void CPrivateSendClientManager::AddUsedMasternode(const COutPoint& outpointMn)
vecMasternodesUsed.push_back(outpointMn);
}
masternode_info_t CPrivateSendClientManager::GetNotUsedMasternode()
CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode()
{
return mnodeman.FindRandomNotInVec(vecMasternodesUsed, MIN_PRIVATESEND_PEER_PROTO_VERSION);
auto mnList = deterministicMNManager->GetListAtChainTip();
int nCountEnabled = mnList.GetValidMNsCount();
int nCountNotExcluded = nCountEnabled - vecMasternodesUsed.size();
LogPrintf("CPrivateSendClientManager::%s -- %d enabled masternodes, %d masternodes to choose from\n", __func__, nCountEnabled, nCountNotExcluded);
if(nCountNotExcluded < 1) {
return nullptr;
}
// fill a vector
std::vector<CDeterministicMNCPtr> vpMasternodesShuffled;
vpMasternodesShuffled.reserve((size_t)nCountEnabled);
mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
vpMasternodesShuffled.emplace_back(dmn);
});
FastRandomContext insecure_rand;
// shuffle pointers
std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecure_rand);
std::set<COutPoint> excludeSet(vecMasternodesUsed.begin(), vecMasternodesUsed.end());
// loop through
for (const auto& dmn : vpMasternodesShuffled) {
if (excludeSet.count(dmn->collateralOutpoint)) {
continue;
}
LogPrint("masternode", "CPrivateSendClientManager::%s -- found, masternode=%s\n", __func__, dmn->collateralOutpoint.ToStringShort());
return dmn;
}
LogPrint("masternode", "CPrivateSendClientManager::%s -- failed\n", __func__);
return nullptr;
}
bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman)
{
if (!pwalletMain) return false;
auto mnList = deterministicMNManager->GetListAtChainTip();
std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations();
// Look through the queues and see if anything matches
CPrivateSendQueue dsq;
while (privateSendClient.GetQueueItemAndTry(dsq)) {
masternode_info_t infoMn;
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
if (!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, infoMn)) {
if (!dmn) {
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- dsq masternode is not in masternode list, masternode=%s\n", dsq.masternodeOutpoint.ToStringShort());
continue;
}
if (infoMn.nProtocolVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) continue;
// skip next mn payments winners
if (mnpayments.IsScheduled(infoMn, 0)) {
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping winner, masternode=%s\n", infoMn.outpoint.ToStringShort());
if (mnpayments.IsScheduled(dmn, 0)) {
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping winner, masternode=%s\n", dmn->proTxHash.ToString());
continue;
}
@ -1042,20 +1078,20 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize
privateSendClient.AddUsedMasternode(dsq.masternodeOutpoint);
if (connman.IsMasternodeOrDisconnectRequested(infoMn.addr)) {
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString());
if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) {
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString());
continue;
}
nSessionDenom = dsq.nDenom;
infoMixingMasternode = infoMn;
pendingDsaRequest = CPendingDsaRequest(infoMn.addr, CPrivateSendAccept(nSessionDenom, txMyCollateral));
connman.AddPendingMasternode(infoMn.addr);
mixingMasternode = dmn;
pendingDsaRequest = CPendingDsaRequest(dmn->pdmnState->addr, CPrivateSendAccept(nSessionDenom, txMyCollateral));
connman.AddPendingMasternode(dmn->pdmnState->addr);
// TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION
SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTime();
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- pending connection (from queue): nSessionDenom: %d (%s), addr=%s\n",
nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), infoMn.addr.ToString());
nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), dmn->pdmnState->addr.ToString());
strAutoDenomResult = _("Trying to connect...");
return true;
}
@ -1068,7 +1104,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nValueMin, CAmount nBalanc
if (!pwalletMain) return false;
int nTries = 0;
int nMnCount = mnodeman.CountMasternodes();
int nMnCount = deterministicMNManager->GetListAtChainTip().GetValidMNsCount();
// ** find the coins we'll use
std::vector<CTxIn> vecTxIn;
@ -1082,39 +1118,40 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nValueMin, CAmount nBalanc
// otherwise, try one randomly
while (nTries < 10) {
masternode_info_t infoMn = privateSendClient.GetNotUsedMasternode();
auto dmn = privateSendClient.GetRandomNotUsedMasternode();
if (!infoMn.fInfoValid) {
if (!dmn) {
LogPrintf("CPrivateSendClientSession::StartNewQueue -- Can't find random masternode!\n");
strAutoDenomResult = _("Can't find random Masternode.");
return false;
}
privateSendClient.AddUsedMasternode(infoMn.outpoint);
privateSendClient.AddUsedMasternode(dmn->collateralOutpoint);
// skip next mn payments winners
if (mnpayments.IsScheduled(infoMn, 0)) {
LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping winner, masternode=%s\n", infoMn.outpoint.ToStringShort());
if (mnpayments.IsScheduled(dmn, 0)) {
LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping winner, masternode=%s\n", dmn->proTxHash.ToString());
nTries++;
continue;
}
if (infoMn.nLastDsq != 0 && infoMn.nLastDsq + nMnCount / 5 > mnodeman.nDsqCount) {
int64_t nLastDsq = mnodeman.GetLastDsq(dmn->collateralOutpoint);
if (nLastDsq != 0 && nLastDsq + nMnCount / 5 > mnodeman.nDsqCount) {
LogPrintf("CPrivateSendClientSession::StartNewQueue -- Too early to mix on this masternode!"
" masternode=%s addr=%s nLastDsq=%d CountEnabled/5=%d nDsqCount=%d\n",
infoMn.outpoint.ToStringShort(), infoMn.addr.ToString(), infoMn.nLastDsq,
dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToString(), nLastDsq,
nMnCount / 5, mnodeman.nDsqCount);
nTries++;
continue;
}
if (connman.IsMasternodeOrDisconnectRequested(infoMn.addr)) {
LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString());
if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) {
LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString());
nTries++;
continue;
}
LogPrintf("CPrivateSendClientSession::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, infoMn.addr.ToString());
LogPrintf("CPrivateSendClientSession::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, dmn->pdmnState->addr.ToString());
std::vector<CAmount> vecAmounts;
pwalletMain->ConvertList(vecTxIn, vecAmounts);
@ -1123,14 +1160,14 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nValueMin, CAmount nBalanc
nSessionDenom = CPrivateSend::GetDenominationsByAmounts(vecAmounts);
}
infoMixingMasternode = infoMn;
connman.AddPendingMasternode(infoMn.addr);
pendingDsaRequest = CPendingDsaRequest(infoMn.addr, CPrivateSendAccept(nSessionDenom, txMyCollateral));
mixingMasternode = dmn;
connman.AddPendingMasternode(dmn->pdmnState->addr);
pendingDsaRequest = CPendingDsaRequest(dmn->pdmnState->addr, CPrivateSendAccept(nSessionDenom, txMyCollateral));
// TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION
SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTime();
LogPrintf("CPrivateSendClientSession::StartNewQueue -- pending connection, nSessionDenom: %d (%s), addr=%s\n",
nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), infoMn.addr.ToString());
nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), dmn->pdmnState->addr.ToString());
strAutoDenomResult = _("Trying to connect...");
return true;
}
@ -1596,9 +1633,9 @@ bool CPrivateSendClientSession::CreateDenominated(const CompactTallyItem& tallyI
void CPrivateSendClientSession::RelayIn(const CPrivateSendEntry& entry, CConnman& connman)
{
if (!infoMixingMasternode.fInfoValid) return;
if (!mixingMasternode) return;
connman.ForNode(infoMixingMasternode.addr, [&entry, &connman](CNode* pnode) {
connman.ForNode(mixingMasternode->pdmnState->addr, [&entry, &connman](CNode* pnode) {
LogPrintf("CPrivateSendClientSession::RelayIn -- found master, relaying message to %s\n", pnode->addr.ToString());
CNetMsgMaker msgMaker(pnode->GetSendVersion());
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSVIN, entry));

View File

@ -10,8 +10,11 @@
#include "privatesend.h"
#include "wallet/wallet.h"
#include "evo/deterministicmns.h"
class CPrivateSendClientManager;
class CConnman;
class CNode;
static const int DENOMS_COUNT_MAX = 100;
@ -92,7 +95,7 @@ private:
std::string strLastMessage;
std::string strAutoDenomResult;
masternode_info_t infoMixingMasternode;
CDeterministicMNCPtr mixingMasternode;
CMutableTransaction txMyCollateral; // client side collateral
CPendingDsaRequest pendingDsaRequest;
@ -139,7 +142,7 @@ public:
fLastEntryAccepted(false),
strLastMessage(),
strAutoDenomResult(),
infoMixingMasternode(),
mixingMasternode(),
txMyCollateral(),
pendingDsaRequest(),
keyHolderStorage()
@ -154,7 +157,7 @@ public:
std::string GetStatus(bool fWaitForBlock);
bool GetMixingMasternodeInfo(masternode_info_t& mnInfoRet) const;
bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const;
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false);
@ -235,7 +238,7 @@ public:
std::string GetStatuses();
std::string GetSessionDenoms();
bool GetMixingMasternodesInfo(std::vector<masternode_info_t>& vecMnInfoRet) const;
bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const;
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false);
@ -245,7 +248,7 @@ public:
void ProcessPendingDsaRequest(CConnman& connman);
void AddUsedMasternode(const COutPoint& outpointMn);
masternode_info_t GetNotUsedMasternode();
CDeterministicMNCPtr GetRandomNotUsedMasternode();
void UpdatedSuccessBlock();

View File

@ -10,6 +10,7 @@
#include "init.h"
#include "masternode-sync.h"
#include "masternodeman.h"
#include "net_processing.h"
#include "netmessagemaker.h"
#include "script/interpreter.h"
#include "txmempool.h"
@ -44,8 +45,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
LogPrint("privatesend", "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CPrivateSend::GetDenominationsToString(dsa.nDenom), dsa.txCollateral.ToString());
masternode_info_t mnInfo;
if (!mnodeman.GetMasternodeInfo(activeMasternodeInfo.outpoint, mnInfo)) {
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint);
if (!dmn) {
PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
return;
}
@ -65,7 +67,8 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
}
}
if (mnInfo.nLastDsq != 0 && mnInfo.nLastDsq + mnodeman.CountMasternodes() / 5 > mnodeman.nDsqCount) {
int64_t nLastDsq = mnodeman.GetLastDsq(dmn->collateralOutpoint);
if (nLastDsq != 0 && nLastDsq + mnList.GetValidMNsCount() / 5 > mnodeman.nDsqCount) {
LogPrintf("DSACCEPT -- last dsq too recent, must wait: addr=%s\n", pfrom->addr.ToString());
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
return;
@ -111,12 +114,13 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
if (dsq.IsExpired()) return;
masternode_info_t mnInfo;
if (!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, mnInfo)) return;
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
if (!dmn) return;
if (!dsq.CheckSignature(mnInfo.legacyKeyIDOperator, mnInfo.blsPubKeyOperator)) {
// we probably have outdated info
mnodeman.AskForMN(pfrom, dsq.masternodeOutpoint, connman);
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator)) {
LOCK(cs_main);
Misbehaving(pfrom->id, 10);
return;
}
@ -124,21 +128,22 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
for (const auto& q : vecPrivateSendQueue) {
if (q.masternodeOutpoint == dsq.masternodeOutpoint) {
// no way same mn can send another "not yet ready" dsq this soon
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", mnInfo.addr.ToString());
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", dmn->pdmnState->addr.ToString());
return;
}
}
int nThreshold = mnInfo.nLastDsq + mnodeman.CountMasternodes() / 5;
LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", mnInfo.nLastDsq, nThreshold, mnodeman.nDsqCount);
int64_t nLastDsq = mnodeman.GetLastDsq(dmn->collateralOutpoint);
int nThreshold = nLastDsq + mnList.GetValidMNsCount() / 5;
LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", nLastDsq, nThreshold, mnodeman.nDsqCount);
//don't allow a few nodes to dominate the queuing process
if (mnInfo.nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) {
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", mnInfo.addr.ToString());
if (nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) {
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->pdmnState->addr.ToString());
return;
}
mnodeman.AllowMixing(dsq.masternodeOutpoint);
LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), mnInfo.addr.ToString());
LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
vecPrivateSendQueue.push_back(dsq);
dsq.Relay(connman);
}

View File

@ -50,77 +50,26 @@ bool CPrivateSendQueue::Sign()
{
if (!fMasternodeMode) return false;
std::string strError = "";
if (deterministicMNManager->IsDIP3Active()) {
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
sig.GetBuf(vchSig);
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) {
LogPrintf("CPrivateSendQueue::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) {
LogPrintf("CPrivateSendQueue::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = CTxIn(masternodeOutpoint).ToString() +
std::to_string(nDenom) +
std::to_string(nTime) +
std::to_string(fReady);
if (!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CPrivateSendQueue::Sign -- SignMessage() failed, %s\n", ToString());
return false;
}
if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CPrivateSendQueue::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
sig.GetBuf(vchSig);
return true;
}
bool CPrivateSendQueue::CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const
bool CPrivateSendQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const
{
std::string strError = "";
if (deterministicMNManager->IsDIP3Active()) {
uint256 hash = GetSignatureHash();
uint256 hash = GetSignatureHash();
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) {
// we don't care about queues with old signature format
LogPrintf("CPrivateSendQueue::CheckSignature -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = CTxIn(masternodeOutpoint).ToString() +
std::to_string(nDenom) +
std::to_string(nTime) +
std::to_string(fReady);
if (!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CPrivateSendQueue::CheckSignature -- Got bad Masternode queue signature: %s; error: %s\n", ToString(), strError);
return false;
}
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;
@ -145,73 +94,28 @@ bool CPrivateSendBroadcastTx::Sign()
{
if (!fMasternodeMode) return false;
std::string strError = "";
if (deterministicMNManager->IsDIP3Active()) {
uint256 hash = GetSignatureHash();
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
sig.GetBuf(vchSig);
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) {
LogPrintf("CPrivateSendBroadcastTx::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) {
LogPrintf("CPrivateSendBroadcastTx::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime);
if (!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CPrivateSendBroadcastTx::Sign -- SignMessage() failed\n");
return false;
}
if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CPrivateSendBroadcastTx::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
sig.GetBuf(vchSig);
return true;
}
bool CPrivateSendBroadcastTx::CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const
bool CPrivateSendBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const
{
std::string strError = "";
if (deterministicMNManager->IsDIP3Active()) {
uint256 hash = GetSignatureHash();
uint256 hash = GetSignatureHash();
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) {
// we don't care about dstxes with old signature format
LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime);
if (!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- Got bad dstx signature, error: %s\n", strError);
return false;
}
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;

View File

@ -225,7 +225,7 @@ public:
*/
bool Sign();
/// Check if we have a valid Masternode address
bool CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const;
bool CheckSignature(const CBLSPublicKey& blsPubKey) const;
bool Relay(CConnman& connman);
@ -306,7 +306,7 @@ public:
uint256 GetSignatureHash() const;
bool Sign();
bool CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const;
bool CheckSignature(const CBLSPublicKey& blsPubKey) const;
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
bool IsExpired(int nHeight);

View File

@ -83,10 +83,10 @@ int ClientModel::getNumConnections(unsigned int flags) const
QString ClientModel::getMasternodeCountString() const
{
// return tr("Total: %1 (PS compatible: %2 / Enabled: %3) (IPv4: %4, IPv6: %5, TOR: %6)").arg(QString::number((int)mnodeman.size()))
return tr("Total: %1 (PS compatible: %2 / Enabled: %3)")
.arg(QString::number((int)mnodeman.CountMasternodes(0)))
.arg(QString::number((int)mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION)))
.arg(QString::number((int)mnodeman.CountEnabled()));
auto mnList = deterministicMNManager->GetListAtChainTip();
return tr("Total: %1 (Enabled: %2)")
.arg(QString::number((int)mnList.GetAllMNsCount()))
.arg(QString::number((int)mnList.GetValidMNsCount()));
// .arg(QString::number((int)mnodeman.CountByIP(NET_IPV4)))
// .arg(QString::number((int)mnodeman.CountByIP(NET_IPV6)))
// .arg(QString::number((int)mnodeman.CountByIP(NET_TOR)));

View File

@ -261,7 +261,8 @@ UniValue gobject_submit(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Must wait for client to sync with masternode network. Try again in a minute or so.");
}
bool fMnFound = mnodeman.Has(activeMasternodeInfo.outpoint);
auto mnList = deterministicMNManager->GetListAtChainTip();
bool fMnFound = mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint);
DBG( std::cout << "gobject: submit activeMasternodeInfo.keyIDOperator = " << activeMasternodeInfo.legacyKeyIDOperator.ToString()
<< ", outpoint = " << activeMasternodeInfo.outpoint.ToStringShort()
@ -412,10 +413,9 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request)
UniValue statusObj(UniValue::VOBJ);
UniValue returnObj(UniValue::VOBJ);
CMasternode mn;
bool fMnFound = mnodeman.Get(activeMasternodeInfo.outpoint, mn);
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(activeMasternodeInfo.outpoint);
if (!fMnFound) {
if (!dmn) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Can't find masternode by collateral output"));
@ -425,19 +425,16 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request)
return returnObj;
}
CGovernanceVote vote(mn.outpoint, hash, eVoteSignal, eVoteOutcome);
CGovernanceVote vote(dmn->collateralOutpoint, hash, eVoteSignal, eVoteOutcome);
bool signSuccess = false;
if (deterministicMNManager->IsDIP3Active()) {
if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf for proposals when deterministic masternodes are active");
}
if (activeMasternodeInfo.blsKeyOperator) {
signSuccess = vote.Sign(*activeMasternodeInfo.blsKeyOperator);
}
} else {
signSuccess = vote.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator);
if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf for proposals");
}
if (activeMasternodeInfo.blsKeyOperator) {
signSuccess = vote.Sign(*activeMasternodeInfo.blsKeyOperator);
}
if (!signSuccess) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
@ -466,9 +463,9 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request)
return returnObj;
}
UniValue VoteWithMasternodeList(const std::vector<CMasternodeConfig::CMasternodeEntry>& entries,
const uint256& hash, vote_signal_enum_t eVoteSignal,
vote_outcome_enum_t eVoteOutcome)
UniValue VoteWithMasternodes(const std::map<uint256, CKey>& keys,
const uint256& hash, vote_signal_enum_t eVoteSignal,
vote_outcome_enum_t eVoteOutcome)
{
int govObjType;
{
@ -483,59 +480,31 @@ UniValue VoteWithMasternodeList(const std::vector<CMasternodeConfig::CMasternode
int nSuccessful = 0;
int nFailed = 0;
auto mnList = deterministicMNManager->GetListAtChainTip();
UniValue resultsObj(UniValue::VOBJ);
for (const auto& mne : entries) {
CPubKey pubKeyOperator;
CKey keyOperator;
for (const auto& p : keys) {
const auto& proTxHash = p.first;
const auto& key = p.second;
UniValue statusObj(UniValue::VOBJ);
if (!CMessageSigner::GetKeysFromSecret(mne.getPrivKey(), keyOperator, pubKeyOperator)) {
auto dmn = mnList.GetValidMN(proTxHash);
if (!dmn) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Masternode signing error, could not set key correctly"));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
statusObj.push_back(Pair("errorMessage", "Can't find masternode by proTxHash"));
resultsObj.push_back(Pair(proTxHash.ToString(), statusObj));
continue;
}
uint256 nTxHash;
nTxHash.SetHex(mne.getTxHash());
int nOutputIndex = 0;
if (!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) {
continue;
}
COutPoint outpoint(nTxHash, nOutputIndex);
CMasternode mn;
bool fMnFound = mnodeman.Get(outpoint, mn);
if (!fMnFound) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Can't find masternode by collateral output"));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
continue;
}
if (deterministicMNManager->IsDIP3Active()) {
if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && mn.keyIDVoting != pubKeyOperator.GetID()) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Can't vote on proposal when key does not match voting key"));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
continue;
}
}
CGovernanceVote vote(mn.outpoint, hash, eVoteSignal, eVoteOutcome);
if (!vote.Sign(keyOperator, pubKeyOperator.GetID())) {
CGovernanceVote vote(dmn->collateralOutpoint, hash, eVoteSignal, eVoteOutcome);
if (!vote.Sign(key, key.GetPubKey().GetID())) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Failure to sign."));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
resultsObj.push_back(Pair(proTxHash.ToString(), statusObj));
continue;
}
@ -549,7 +518,7 @@ UniValue VoteWithMasternodeList(const std::vector<CMasternodeConfig::CMasternode
statusObj.push_back(Pair("errorMessage", exception.GetMessage()));
}
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
resultsObj.push_back(Pair(proTxHash.ToString(), statusObj));
}
UniValue returnObj(UniValue::VOBJ);
@ -559,11 +528,12 @@ UniValue VoteWithMasternodeList(const std::vector<CMasternodeConfig::CMasternode
return returnObj;
}
#ifdef ENABLE_WALLET
void gobject_vote_many_help()
{
throw std::runtime_error(
"gobject vote-many <governance-hash> <vote> <vote-outcome>\n"
"Vote on a governance object by all masternodes (using masternode.conf setup)\n"
"Vote on a governance object by all masternodes for which the voting key is present in the local wallet\n"
"\nArguments:\n"
"1. governance-hash (string, required) hash of the governance object\n"
"2. vote (string, required) vote, possible values: [funding|valid|delete|endorsed]\n"
@ -592,66 +562,33 @@ UniValue gobject_vote_many(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'");
}
std::vector<CMasternodeConfig::CMasternodeEntry> entries = masternodeConfig.getEntries();
#ifdef ENABLE_WALLET
// This is a hack to maintain code-level backwards compatibility with masternode.conf and the deterministic masternodes.
// Deterministic masternode keys are managed inside the wallet instead of masternode.conf
// This allows voting on proposals when you have the MN voting key in your wallet
// We can remove this when we remove support for masternode.conf and only support wallet based masternode
// management
if (deterministicMNManager->IsDIP3Active()) {
if (!pwalletMain) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-many not supported when wallet is disabled.");
}
entries.clear();
auto mnList = deterministicMNManager->GetListAtChainTip();
mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
bool found = false;
for (const auto &mne : entries) {
uint256 nTxHash;
nTxHash.SetHex(mne.getTxHash());
int nOutputIndex = 0;
if(!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) {
continue;
}
if (nTxHash == dmn->collateralOutpoint.hash && (uint32_t)nOutputIndex == dmn->collateralOutpoint.n) {
found = true;
break;
}
}
if (!found) {
CKey ownerKey;
if (pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, ownerKey)) {
CBitcoinSecret secret(ownerKey);
CMasternodeConfig::CMasternodeEntry mne(dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToStringIPPort(false), secret.ToString(), dmn->collateralOutpoint.hash.ToString(), itostr(dmn->collateralOutpoint.n));
entries.push_back(mne);
}
}
});
}
#else
if (deterministicMNManager->IsDIP3Active()) {
if (!pwalletMain) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-many not supported when wallet is disabled.");
}
#endif
return VoteWithMasternodeList(entries, hash, eVoteSignal, eVoteOutcome);
std::map<uint256, CKey> votingKeys;
auto mnList = deterministicMNManager->GetListAtChainTip();
mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
CKey votingKey;
if (pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) {
votingKeys.emplace(dmn->proTxHash, votingKey);
}
});
return VoteWithMasternodes(votingKeys, hash, eVoteSignal, eVoteOutcome);
}
void gobject_vote_alias_help()
{
throw std::runtime_error(
"gobject vote-alias <governance-hash> <vote> <vote-outcome> <alias-name>\n"
"Vote on a governance object by masternode alias (using masternode.conf setup)\n"
"Vote on a governance object by masternode's voting key (if present in local wallet)\n"
"\nArguments:\n"
"1. governance-hash (string, required) hash of the governance object\n"
"2. vote (string, required) vote, possible values: [funding|valid|delete|endorsed]\n"
"3. vote-outcome (string, required) vote outcome, possible values: [yes|no|abstain]\n"
"4. alias-name (string, required) masternode alias or proTxHash after DIP3 activation"
"4. protx-hash (string, required) masternode's proTxHash"
);
}
@ -676,41 +613,27 @@ UniValue gobject_vote_alias(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'");
}
std::vector<CMasternodeConfig::CMasternodeEntry> entries;
if (deterministicMNManager->IsDIP3Active()) {
#ifdef ENABLE_WALLET
if (!pwalletMain) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-alias not supported when wallet is disabled");
}
uint256 proTxHash = ParseHashV(request.params[4], "alias-name");
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash);
if (!dmn) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid or unknown proTxHash");
}
CKey votingKey;
if (!pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Voting ekey %s not known by wallet", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString()));
}
CBitcoinSecret secret(votingKey);
CMasternodeConfig::CMasternodeEntry mne(dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToStringIPPort(false), secret.ToString(), dmn->collateralOutpoint.hash.ToString(), itostr(dmn->collateralOutpoint.n));
entries.push_back(mne);
#else
if (!pwalletMain) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-alias not supported when wallet is disabled");
#endif
} else {
std::string strAlias = request.params[4].get_str();
for (const auto& mne : masternodeConfig.getEntries()) {
if (strAlias == mne.getAlias())
entries.push_back(mne);
}
}
return VoteWithMasternodeList(entries, hash, eVoteSignal, eVoteOutcome);
uint256 proTxHash = ParseHashV(request.params[4], "protx-hash");
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash);
if (!dmn) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid or unknown proTxHash");
}
CKey votingKey;
if (!pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Voting key %s not known by wallet", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString()));
}
std::map<uint256, CKey> votingKeys;
votingKeys.emplace(proTxHash, votingKey);
return VoteWithMasternodes(votingKeys, hash, eVoteSignal, eVoteOutcome);
}
#endif
UniValue ListObjects(const std::string& strCachedSignal, const std::string& strType, int nStartTime)
{
@ -1063,10 +986,12 @@ UniValue gobject(const JSONRPCRequest& request)
return gobject_submit(request);
} else if (strCommand == "vote-conf") {
return gobject_vote_conf(request);
#ifdef ENABLE_WALLET
} else if (strCommand == "vote-many") {
return gobject_vote_many(request);
} else if (strCommand == "vote-alias") {
return gobject_vote_alias(request);
#endif
} else if (strCommand == "list") {
// USERS CAN QUERY THE SYSTEM FOR A LIST OF VARIOUS GOVERNANCE ITEMS
return gobject_list(request);
@ -1133,10 +1058,9 @@ UniValue voteraw(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
}
CMasternode mn;
bool fMnFound = mnodeman.Get(outpoint, mn);
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(outpoint);
if (!fMnFound) {
if (!dmn) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to find masternode in list : " + outpoint.ToStringShort());
}

View File

@ -99,13 +99,13 @@ UniValue getpoolinfo(const JSONRPCRequest& request)
// obj.push_back(Pair("entries", pprivateSendBase->GetEntriesCount()));
obj.push_back(Pair("status", privateSendClient.GetStatuses()));
std::vector<masternode_info_t> vecMnInfo;
if (privateSendClient.GetMixingMasternodesInfo(vecMnInfo)) {
std::vector<CDeterministicMNCPtr> vecDmns;
if (privateSendClient.GetMixingMasternodesInfo(vecDmns)) {
UniValue pools(UniValue::VARR);
for (const auto& mnInfo : vecMnInfo) {
for (const auto& dmn : vecDmns) {
UniValue pool(UniValue::VOBJ);
pool.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort()));
pool.push_back(Pair("addr", mnInfo.addr.ToString()));
pool.push_back(Pair("outpoint", dmn->collateralOutpoint.ToStringShort()));
pool.push_back(Pair("addr", dmn->pdmnState->addr.ToString()));
pools.push_back(pool);
}
obj.push_back(Pair("pools", pools));
@ -136,26 +136,21 @@ void masternode_list_help()
"2. \"filter\" (string, optional) Filter results. Partial match by outpoint by default in all modes,\n"
" additional matches in some modes are also available\n"
"\nAvailable modes:\n"
" activeseconds - Print number of seconds masternode recognized by the network as enabled\n"
" (since latest issued \"masternode start/start-many/start-alias\")\n"
" addr - Print ip address associated with a masternode (can be additionally filtered, partial match)\n"
" daemon - Print daemon version of a masternode (can be additionally filtered, exact match)\n"
" full - Print info in format 'status protocol payee lastseen activeseconds lastpaidtime lastpaidblock IP'\n"
" full - Print info in format 'status payee lastpaidtime lastpaidblock IP'\n"
" (can be additionally filtered, partial match)\n"
" info - Print info in format 'status protocol payee lastseen activeseconds sentinelversion sentinelstate IP'\n"
" info - Print info in format 'status payee IP'\n"
" (can be additionally filtered, partial match)\n"
" json - Print info in JSON format (can be additionally filtered, partial match)\n"
" keyIDOwner - Print the masternode owner key id\n"
" keyIDVoting - Print the masternode voting key id\n"
" lastpaidblock - Print the last block height a node was paid on the network\n"
" lastpaidtime - Print the last time a node was paid on the network\n"
" lastseen - Print timestamp of when a masternode was last seen on the network\n"
" payee - Print Dash address associated with a masternode (can be additionally filtered,\n"
" partial match)\n"
" protocol - Print protocol of a masternode (can be additionally filtered, exact match)\n"
" keyid - Print the masternode (not collateral) key id\n"
" rank - Print rank of a masternode based on current block\n"
" sentinel - Print sentinel version of a masternode (can be additionally filtered, exact match)\n"
" status - Print masternode status: PRE_ENABLED / ENABLED / EXPIRED / SENTINEL_PING_EXPIRED / NEW_START_REQUIRED /\n"
" UPDATE_REQUIRED / POSE_BAN / OUTPOINT_SPENT (can be additionally filtered, partial match)\n"
" pubKeyOperator - Print the masternode operator public key\n"
" status - Print masternode status: ENABLED / POSE_BAN / OUTPOINT_SPENT\n"
" (can be additionally filtered, partial match)\n"
);
}
@ -224,25 +219,15 @@ UniValue masternode_count(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 2)
masternode_count_help();
int nCount;
int total = mnodeman.CountMasternodes(0);
if (deterministicMNManager->IsDIP3Active()) {
nCount = mnodeman.CountEnabled();
} else {
masternode_info_t mnInfo;
mnodeman.GetNextMasternodeInQueueForPayment(true, nCount, mnInfo);
}
int ps = mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION);
int enabled = mnodeman.CountEnabled();
auto mnList = deterministicMNManager->GetListAtChainTip();
int total = mnList.GetAllMNsCount();
int enabled = mnList.GetValidMNsCount();
if (request.params.size() == 1) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("total", total));
obj.push_back(Pair("ps_compatible", ps));
obj.push_back(Pair("enabled", enabled));
obj.push_back(Pair("qualify", nCount));
return obj;
}
@ -252,47 +237,24 @@ UniValue masternode_count(const JSONRPCRequest& request)
if (strMode == "total")
return total;
if (strMode == "ps")
return ps;
if (strMode == "enabled")
return enabled;
if (strMode == "qualify")
return nCount;
if (strMode == "all")
return strprintf("Total: %d (PS Compatible: %d / Enabled: %d / Qualify: %d)",
total, ps, enabled, nCount);
return strprintf("Total: %d (Enabled: %d)",
total, enabled);
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown mode value");
}
UniValue GetNextMasternodeForPayment(int heightShift)
{
int nCount;
int nHeight;
masternode_info_t mnInfo;
CBlockIndex* pindex = NULL;
{
LOCK(cs_main);
pindex = chainActive.Tip();
}
nHeight = pindex->nHeight + heightShift;
mnodeman.UpdateLastPaid(pindex);
CScript payeeScript;
if (deterministicMNManager->IsDIP3Active()) {
auto payee = deterministicMNManager->GetListAtChainTip().GetMNPayee();
if (!payee || !mnodeman.GetMasternodeInfo(payee->proTxHash, mnInfo))
return "unknown";
payeeScript = payee->pdmnState->scriptPayout;
} else {
if (!mnodeman.GetNextMasternodeInQueueForPayment(nHeight, true, nCount, mnInfo))
return "unknown";
payeeScript = GetScriptForDestination(mnInfo.keyIDCollateralAddress);
}
auto mnList = deterministicMNManager->GetListAtChainTip();
auto payees = mnList.GetProjectedMNPayees(heightShift);
if (payees.empty())
return "unknown";
auto payee = payees[heightShift - 9];
CScript payeeScript = payee->pdmnState->scriptPayout;
CTxDestination payeeDest;
CBitcoinAddress payeeAddr;
@ -302,13 +264,11 @@ UniValue GetNextMasternodeForPayment(int heightShift)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("height", nHeight));
obj.push_back(Pair("IP:port", mnInfo.addr.ToString()));
obj.push_back(Pair("protocol", mnInfo.nProtocolVersion));
obj.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort()));
obj.push_back(Pair("height", mnList.GetHeight() + heightShift));
obj.push_back(Pair("IP:port", payee->pdmnState->addr.ToString()));
obj.push_back(Pair("proTxHash", payee->proTxHash.ToString()));
obj.push_back(Pair("outpoint", payee->collateralOutpoint.ToStringShort()));
obj.push_back(Pair("payee", payeeAddr.IsValid() ? payeeAddr.ToString() : "UNKNOWN"));
obj.push_back(Pair("lastseen", mnInfo.nTimeLastPing));
obj.push_back(Pair("activeseconds", mnInfo.nTimeLastPing - mnInfo.sigTime));
return obj;
}
@ -853,11 +813,14 @@ UniValue masternodelist(const JSONRPCRequest& request)
if (request.params.size() >= 1) strMode = request.params[0].get_str();
if (request.params.size() == 2) strFilter = request.params[1].get_str();
std::transform(strMode.begin(), strMode.end(), strMode.begin(), ::tolower);
if (request.fHelp || (
strMode != "activeseconds" && strMode != "addr" && strMode != "daemon" && strMode != "full" && strMode != "info" && strMode != "json" &&
strMode != "lastseen" && strMode != "lastpaidtime" && strMode != "lastpaidblock" &&
strMode != "protocol" && strMode != "payee" && strMode != "pubkey" &&
strMode != "rank" && strMode != "sentinel" && strMode != "status"))
strMode != "addr" && strMode != "full" && strMode != "info" && strMode != "json" &&
strMode != "keyidowner" && strMode != "keyidvoting" &&
strMode != "lastpaidtime" && strMode != "lastpaidblock" &&
strMode != "payee" && strMode != "pubkeyoperator" &&
strMode != "status"))
{
masternode_list_help();
}
@ -872,147 +835,108 @@ UniValue masternodelist(const JSONRPCRequest& request)
}
UniValue obj(UniValue::VOBJ);
if (strMode == "rank") {
CMasternodeMan::rank_pair_vec_t vMasternodeRanks;
mnodeman.GetMasternodeRanks(vMasternodeRanks);
for (const auto& rankpair : vMasternodeRanks) {
std::string strOutpoint = rankpair.second.outpoint.ToStringShort();
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, rankpair.first));
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmnToStatus = [&](const CDeterministicMNCPtr& dmn) {
if (mnList.IsMNValid(dmn)) {
return "ENABLED";
}
} else {
std::map<COutPoint, CMasternode> mapMasternodes = mnodeman.GetFullMasternodeMap();
for (const auto& mnpair : mapMasternodes) {
CMasternode mn = mnpair.second;
std::string strOutpoint = mnpair.first.ToStringShort();
CScript payeeScript;
if (deterministicMNManager->IsDIP3Active()) {
auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(mn.outpoint);
if (dmn) {
payeeScript = dmn->pdmnState->scriptPayout;
}
} else {
payeeScript = GetScriptForDestination(mn.keyIDCollateralAddress);
}
CTxDestination payeeDest;
std::string payeeStr = "UNKOWN";
if (ExtractDestination(payeeScript, payeeDest)) {
payeeStr = CBitcoinAddress(payeeDest).ToString();
}
if (strMode == "activeseconds") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, (int64_t)(mn.lastPing.sigTime - mn.sigTime)));
} else if (strMode == "addr") {
std::string strAddress = mn.addr.ToString();
if (strFilter !="" && strAddress.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, strAddress));
} else if (strMode == "daemon") {
std::string strDaemon = mn.lastPing.GetDaemonString();
if (strFilter !="" && strDaemon.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, strDaemon));
} else if (strMode == "sentinel") {
std::string strSentinel = mn.lastPing.GetSentinelString();
if (strFilter !="" && strSentinel.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, strSentinel));
} else if (strMode == "full") {
std::ostringstream streamFull;
streamFull << std::setw(18) <<
mn.GetStatus() << " " <<
mn.nProtocolVersion << " " <<
payeeStr << " " <<
(int64_t)mn.lastPing.sigTime << " " << std::setw(8) <<
(int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " << std::setw(10) <<
mn.GetLastPaidTime() << " " << std::setw(6) <<
mn.GetLastPaidBlock() << " " <<
mn.addr.ToString();
std::string strFull = streamFull.str();
if (strFilter !="" && strFull.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, strFull));
} else if (strMode == "info") {
std::ostringstream streamInfo;
streamInfo << std::setw(18) <<
mn.GetStatus() << " " <<
mn.nProtocolVersion << " " <<
payeeStr << " " <<
(int64_t)mn.lastPing.sigTime << " " << std::setw(8) <<
(int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " <<
mn.lastPing.GetSentinelString() << " " <<
(mn.lastPing.fSentinelIsCurrent ? "current" : "expired") << " " <<
mn.addr.ToString();
std::string strInfo = streamInfo.str();
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, strInfo));
} else if (strMode == "json") {
std::ostringstream streamInfo;
streamInfo << mn.addr.ToString() << " " <<
CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString() << " " <<
mn.GetStatus() << " " <<
mn.nProtocolVersion << " " <<
mn.lastPing.nDaemonVersion << " " <<
mn.lastPing.GetSentinelString() << " " <<
(mn.lastPing.fSentinelIsCurrent ? "current" : "expired") << " " <<
(int64_t)mn.lastPing.sigTime << " " <<
(int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " <<
mn.GetLastPaidTime() << " " <<
mn.GetLastPaidBlock();
std::string strInfo = streamInfo.str();
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
UniValue objMN(UniValue::VOBJ);
objMN.push_back(Pair("address", mn.addr.ToString()));
objMN.push_back(Pair("payee", CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString()));
objMN.push_back(Pair("status", mn.GetStatus()));
objMN.push_back(Pair("protocol", mn.nProtocolVersion));
objMN.push_back(Pair("daemonversion", mn.lastPing.GetDaemonString()));
objMN.push_back(Pair("sentinelversion", mn.lastPing.GetSentinelString()));
objMN.push_back(Pair("sentinelstate", (mn.lastPing.fSentinelIsCurrent ? "current" : "expired")));
objMN.push_back(Pair("lastseen", (int64_t)mn.lastPing.sigTime));
objMN.push_back(Pair("activeseconds", (int64_t)(mn.lastPing.sigTime - mn.sigTime)));
objMN.push_back(Pair("lastpaidtime", mn.GetLastPaidTime()));
objMN.push_back(Pair("lastpaidblock", mn.GetLastPaidBlock()));
obj.push_back(Pair(strOutpoint, objMN));
} else if (strMode == "lastpaidblock") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, mn.GetLastPaidBlock()));
} else if (strMode == "lastpaidtime") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, mn.GetLastPaidTime()));
} else if (strMode == "lastseen") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, (int64_t)mn.lastPing.sigTime));
} else if (strMode == "payee") {
if (strFilter !="" && payeeStr.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, payeeStr));
} else if (strMode == "protocol") {
if (strFilter !="" && strFilter != strprintf("%d", mn.nProtocolVersion) &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, mn.nProtocolVersion));
} else if (strMode == "keyIDOwner") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDOwner)));
} else if (strMode == "keyIDOperator") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, HexStr(mn.legacyKeyIDOperator)));
} else if (strMode == "keyIDVoting") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDVoting)));
} else if (strMode == "status") {
std::string strStatus = mn.GetStatus();
if (strFilter !="" && strStatus.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, strStatus));
}
if (mnList.IsMNPoSeBanned(dmn)) {
return "POSE_BANNED";
}
}
return "UNKNOWN";
};
auto dmnToLastPaidTime = [&](const CDeterministicMNCPtr& dmn) {
if (dmn->pdmnState->nLastPaidHeight == 0) {
return (int)0;
}
LOCK(cs_main);
const CBlockIndex* pindex = chainActive[dmn->pdmnState->nLastPaidHeight];
return (int)pindex->nTime;
};
mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
std::string strOutpoint = dmn->collateralOutpoint.ToStringShort();
CScript payeeScript = dmn->pdmnState->scriptPayout;
CTxDestination payeeDest;
std::string payeeStr = "UNKOWN";
if (ExtractDestination(payeeScript, payeeDest)) {
payeeStr = CBitcoinAddress(payeeDest).ToString();
}
if (strMode == "addr") {
std::string strAddress = dmn->pdmnState->addr.ToString(false);
if (strFilter !="" && strAddress.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, strAddress));
} else if (strMode == "full") {
std::ostringstream streamFull;
streamFull << std::setw(18) <<
dmnToStatus(dmn) << " " <<
payeeStr << " " << std::setw(10) <<
dmnToLastPaidTime(dmn) << " " << std::setw(6) <<
dmn->pdmnState->nLastPaidHeight << " " <<
dmn->pdmnState->addr.ToString();
std::string strFull = streamFull.str();
if (strFilter !="" && strFull.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, strFull));
} else if (strMode == "info") {
std::ostringstream streamInfo;
streamInfo << std::setw(18) <<
dmnToStatus(dmn) << " " <<
payeeStr << " " <<
dmn->pdmnState->addr.ToString();
std::string strInfo = streamInfo.str();
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, strInfo));
} else if (strMode == "json") {
std::ostringstream streamInfo;
streamInfo << dmn->pdmnState->addr.ToString() << " " <<
CBitcoinAddress(dmn->pdmnState->scriptPayout).ToString() << " " <<
dmnToStatus(dmn) << " " <<
dmnToLastPaidTime(dmn) << " " <<
dmn->pdmnState->nLastPaidHeight;
std::string strInfo = streamInfo.str();
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
UniValue objMN(UniValue::VOBJ);
objMN.push_back(Pair("address", dmn->pdmnState->addr.ToString()));
objMN.push_back(Pair("payee", CBitcoinAddress(dmn->pdmnState->scriptPayout).ToString()));
objMN.push_back(Pair("status", dmnToStatus(dmn)));
objMN.push_back(Pair("lastpaidtime", dmnToLastPaidTime(dmn)));
objMN.push_back(Pair("lastpaidblock", dmn->pdmnState->nLastPaidHeight));
obj.push_back(Pair(strOutpoint, objMN));
} else if (strMode == "lastpaidblock") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, dmn->pdmnState->nLastPaidHeight));
} else if (strMode == "lastpaidtime") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, dmnToLastPaidTime(dmn)));
} else if (strMode == "payee") {
if (strFilter !="" && payeeStr.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, payeeStr));
} else if (strMode == "keyidowner") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, HexStr(dmn->pdmnState->keyIDOwner)));
} else if (strMode == "pubkeyoperator") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, dmn->pdmnState->pubKeyOperator.ToString()));
} else if (strMode == "keyidvoting") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, HexStr(dmn->pdmnState->keyIDVoting)));
} else if (strMode == "status") {
std::string strStatus = dmnToStatus(dmn);
if (strFilter !="" && strStatus.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
obj.push_back(Pair(strOutpoint, strStatus));
}
});
return obj;
}

View File

@ -1828,35 +1828,7 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
ThresholdState state = VersionBitsState(pindexPrev, params, pos, versionbitscache);
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
if (vbinfo.check_mn_protocol && state == THRESHOLD_STARTED && fCheckMasternodesUpgraded) {
if (deterministicMNManager->IsDIP3Active()) {
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
auto payee = mnList.GetMNPayee();
if (!payee) {
continue;
}
} else {
std::vector<CTxOut> voutMasternodePayments;
masternode_info_t mnInfo;
if (!mnpayments.GetBlockTxOuts(pindexPrev->nHeight + 1, 0, voutMasternodePayments)) {
// no votes for this block
continue;
}
bool mnKnown = false;
for (const auto& txout : voutMasternodePayments) {
if (mnodeman.GetMasternodeInfo(txout.scriptPubKey, mnInfo)) {
mnKnown = true;
break;
}
}
if (!mnKnown) {
// unknown masternode
continue;
}
if (mnInfo.nProtocolVersion < DMN_PROTO_VERSION) {
// masternode is not upgraded yet
continue;
}
}
// TODO implement new logic for MN upgrade checks (e.g. with LLMQ based feature/version voting)
}
if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);

View File

@ -1121,10 +1121,11 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
}
AddToSpends(hash);
auto mnList = deterministicMNManager->GetListAtChainTip();
for(unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
if (IsMine(wtx.tx->vout[i]) && !IsSpent(hash, i)) {
setWalletUTXO.insert(COutPoint(hash, i));
if (deterministicMNManager->IsProTxWithCollateral(wtx.tx, i) || deterministicMNManager->HasMNCollateralAtChainTip(COutPoint(hash, i))) {
if (deterministicMNManager->IsProTxWithCollateral(wtx.tx, i) || mnList.HasMNByCollateral(COutPoint(hash, i))) {
LockCoin(COutPoint(hash, i));
}
}
@ -3989,11 +3990,13 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
// This avoids accidential spending of collaterals. They can still be unlocked manually if a spend is really intended.
void CWallet::AutoLockMasternodeCollaterals()
{
auto mnList = deterministicMNManager->GetListAtChainTip();
LOCK2(cs_main, cs_wallet);
for (const auto& pair : mapWallet) {
for (unsigned int i = 0; i < pair.second.tx->vout.size(); ++i) {
if (IsMine(pair.second.tx->vout[i]) && !IsSpent(pair.first, i)) {
if (deterministicMNManager->IsProTxWithCollateral(pair.second.tx, i) || deterministicMNManager->HasMNCollateralAtChainTip(COutPoint(pair.first, i))) {
if (deterministicMNManager->IsProTxWithCollateral(pair.second.tx, i) || mnList.HasMNByCollateral(COutPoint(pair.first, i))) {
LockCoin(COutPoint(pair.first, i));
}
}
@ -4643,11 +4646,13 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
void CWallet::ListProTxCoins(std::vector<COutPoint>& vOutpts)
{
auto mnList = deterministicMNManager->GetListAtChainTip();
AssertLockHeld(cs_wallet);
for (const auto &o : setWalletUTXO) {
if (mapWallet.count(o.hash)) {
const auto &p = mapWallet[o.hash];
if (deterministicMNManager->IsProTxWithCollateral(p.tx, o.n) || deterministicMNManager->HasMNCollateralAtChainTip(o)) {
if (deterministicMNManager->IsProTxWithCollateral(p.tx, o.n) || mnList.HasMNByCollateral(o)) {
vOutpts.emplace_back(o);
}
}