dash/src/governance.h

318 lines
10 KiB
C
Raw Normal View History

// Copyright (c) 2014-2016 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef GOVERANCE_H
#define GOVERANCE_H
#include "main.h"
#include "sync.h"
#include "net.h"
#include "key.h"
#include "util.h"
#include "base58.h"
#include "masternode.h"
2016-04-14 00:41:40 +02:00
#include "governance-vote.h"
2016-05-25 18:56:58 +02:00
#include "masternodeman.h"
#include <boost/lexical_cast.hpp>
#include "init.h"
2016-04-16 19:19:17 +02:00
#include <stdio.h>
#include <string.h>
using namespace std;
extern CCriticalSection cs_budget;
class CGovernanceManager;
2016-04-16 19:19:17 +02:00
class CGovernanceObject;
class CGovernanceVote;
2016-04-14 20:53:46 +02:00
class CNode;
static const CAmount GOVERNANCE_FEE_TX = (0.1*COIN);
2016-04-10 02:43:15 +02:00
static const int64_t GOVERNANCE_FEE_CONFIRMATIONS = 6;
static const int64_t GOVERNANCE_UPDATE_MIN = 60*60;
2016-05-23 20:10:20 +02:00
extern std::vector<CGovernanceObject> vecImmatureGovernanceObjects;
extern std::map<uint256, int64_t> mapAskedForGovernanceObject;
2016-04-10 16:46:19 +02:00
extern CGovernanceManager governance;
2016-05-13 18:03:01 +02:00
// FOR SEEN MAP ARRAYS - GOVERNANCE OBJECTS AND VOTES
#define SEEN_OBJECT_IS_VALID 0
#define SEEN_OBJECT_ERROR_INVALID 1
#define SEEN_OBJECT_ERROR_IMMATURE 2
//Check the collateral transaction for the budget proposal/finalized budget
extern bool IsCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, std::string& strError, int& nConf, CAmount minFee);
//
// Governance Manager : Contains all proposals for the budget
//
class CGovernanceManager
{
private:
//hold txes until they mature enough to use
map<uint256, CTransaction> mapCollateral;
// Keep track of current block index
const CBlockIndex *pCurrentBlockIndex;
int64_t nTimeLastDiff;
public:
// critical section to protect the inner data structures
mutable CCriticalSection cs;
// keep track of the scanning errors I've seen
2016-05-13 18:03:01 +02:00
map<uint256, CGovernanceObject> mapObjects;
2016-04-14 00:41:40 +02:00
// todo - 12.1 - move to private for better encapsulation
std::map<uint256, int> mapSeenGovernanceObjects;
std::map<uint256, int> mapSeenVotes;
std::map<uint256, CGovernanceVote> mapOrphanVotes;
// todo: one of these should point to the other
// -- must be carefully managed while adding/removing/updating
std::map<uint256, CGovernanceVote> mapVotesByHash;
std::map<uint256, CGovernanceVote> mapVotesByType;
CGovernanceManager() {
2016-05-13 18:03:01 +02:00
mapObjects.clear();
}
void ClearSeen() {
mapSeenGovernanceObjects.clear();
mapSeenVotes.clear();
}
int CountProposalInventoryItems()
{
return mapSeenGovernanceObjects.size() + mapSeenVotes.size();
}
2016-05-13 18:03:01 +02:00
int sizeProposals() {return (int)mapObjects.size();}
2016-04-14 00:41:40 +02:00
// description: incremental sync with our peers
// note: incremental syncing seems excessive, well just have clients ask for specific objects and their votes
// note: 12.1 - remove
//void ResetSync();
//void MarkSynced();
void Sync(CNode* node, uint256 nProp);
void SyncParentObjectByVote(CNode* pfrom, const CGovernanceVote& vote);
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
void NewBlock();
2016-05-24 20:11:59 +02:00
CGovernanceObject *FindGovernanceObject(const std::string &strName);
CGovernanceObject *FindGovernanceObject(const uint256& nHash);
2016-04-26 06:08:36 +02:00
std::vector<CGovernanceObject*> GetAllProposals(int64_t nMoreThanTime);
2016-05-23 23:39:10 +02:00
int CountMatchingVotes(CGovernanceObject& govobj, int nVoteSignalIn, int nVoteOutcomeIn);
bool IsBudgetPaymentBlock(int nBlockHeight);
bool AddGovernanceObject (CGovernanceObject& govobj);
bool UpdateGovernanceObject(const CGovernanceVote& vote, CNode* pfrom, std::string& strError);
bool AddOrUpdateVote(const CGovernanceVote& vote, std::string& strError);
std::string GetRequiredPaymentsString(int nBlockHeight);
2016-04-14 22:01:15 +02:00
void CleanAndRemove(bool fSignatureCheck);
void CheckAndRemove();
void CheckOrphanVotes();
void Clear(){
LOCK(cs);
2016-05-23 23:39:10 +02:00
LogPrintf("Governance object manager was cleared\n");
2016-05-13 18:03:01 +02:00
mapObjects.clear();
mapSeenGovernanceObjects.clear();
mapSeenVotes.clear();
mapOrphanVotes.clear();
mapVotesByType.clear();
mapVotesByHash.clear();
}
std::string ToString() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(mapSeenGovernanceObjects);
READWRITE(mapSeenVotes);
READWRITE(mapOrphanVotes);
2016-05-13 18:03:01 +02:00
READWRITE(mapObjects);
READWRITE(mapVotesByHash);
READWRITE(mapVotesByType);
}
void UpdatedBlockTip(const CBlockIndex *pindex);
int64_t GetLastDiffTime() {return nTimeLastDiff;}
void UpdateLastDiffTime(int64_t nTimeIn) {nTimeLastDiff=nTimeIn;}
};
2016-04-14 03:52:26 +02:00
/**
2016-04-16 19:19:17 +02:00
* Generic Governance Object
2016-04-14 03:52:26 +02:00
*
*
*/
2016-04-16 19:19:17 +02:00
class CGovernanceObject
{
private:
// critical section to protect the inner data structures
mutable CCriticalSection cs;
CAmount nAlloted;
public:
uint256 nHashParent; //parent object, 0 is root
int nRevision; //object revision in the system
2016-04-16 19:19:17 +02:00
std::string strName; //org name, username, prop name, etc.
2016-04-26 06:08:36 +02:00
int64_t nTime; //time this object was created
uint256 nFeeTXHash; //fee-tx
std::string strData; // Data field - can be used for anything
2016-05-23 23:39:10 +02:00
// set by IsValid()
bool fCachedLocalValidity;
std::string strLocalValidityError;
// set via sentinel voting mechanisms
2016-05-13 18:03:01 +02:00
// caching -- one per voting mechanism -- see governance-vote.h for more information
bool fCachedFunding;
bool fCachedValid;
bool fCachedDelete;
bool fCachedEndorsed;
2016-04-17 02:29:41 +02:00
CGovernanceObject();
2016-04-26 06:08:36 +02:00
CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, std::string strNameIn, int64_t nTime, uint256 nFeeTXHashIn);
CGovernanceObject(const CGovernanceObject& other);
2016-05-23 23:39:10 +02:00
// Update local validity : store the values in memory
void UpdateLocalValidity(const CBlockIndex *pCurrentBlockIndex) {fCachedLocalValidity = IsValid(pCurrentBlockIndex, strLocalValidityError);};
2016-05-24 20:11:59 +02:00
void UpdateSentinelVariables(const CBlockIndex *pCurrentBlockIndex)
2016-05-24 00:52:10 +02:00
{
// CALCULATE MINIMUM SUPPORT LEVELS REQUIRED
2016-05-24 00:52:10 +02:00
2016-05-24 20:11:59 +02:00
int nMnCount = mnodeman.CountEnabled();
if(nMnCount == 0) return;
// CALCULATE THE MINUMUM VOTE COUNT REQUIRED FOR FULL SIGNAL
2016-05-24 20:11:59 +02:00
int nAbsYesVoteReq = nMnCount / 10;
int nAbsNoVoteReq = nAbsYesVoteReq; //same in absolute value
2016-05-24 00:52:10 +02:00
// SET SENTINEL FLAGS TO FALSE
2016-05-24 20:11:59 +02:00
fCachedFunding = false;
fCachedValid = true; //default to valid
2016-05-24 20:11:59 +02:00
fCachedDelete = false;
fCachedEndorsed = false;
// SET SENTINEL FLAGS TO TRUE IF MIMIMUM SUPPORT LEVELS ARE REACHED
// todo - 12.1
// if(GetAbsoluteYesCount(VOTE_SIGNAL_FUNDING) >= nAbsYesVoteReq) fCachedFunding = true;
// if(GetAbsoluteYesCount(VOTE_SIGNAL_VALID) >= nAbsYesVoteReq) fCachedValid = true;
// if(GetAbsoluteYesCount(VOTE_SIGNAL_DELETE) >= nAbsYesVoteReq) fCachedDelete = true;
// if(GetAbsoluteYesCount(VOTE_SIGNAL_ENDORSED) >= nAbsYesVoteReq) fCachedEndorsed = true;
// if(GetAbsoluteNoCount(VOTE_SIGNAL_FUNDING) >= nAbsNoVoteReq) fCachedFunding = false;
// if(GetAbsoluteNoCount(VOTE_SIGNAL_VALID) >= nAbsNoVoteReq) fCachedValid = false;
// if(GetAbsoluteNoCount(VOTE_SIGNAL_DELETE) >= nAbsNoVoteReq) fCachedDelete = false;
// if(GetAbsoluteNoCount(VOTE_SIGNAL_ENDORSED) >= nAbsNoVoteReq) fCachedEndorsed = false;
2016-05-24 00:52:10 +02:00
}
2016-04-26 06:08:36 +02:00
void swap(CGovernanceObject& first, CGovernanceObject& second) // nothrow
{
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.strName, second.strName);
swap(first.nHashParent, second.nHashParent);
swap(first.nRevision, second.nRevision);
swap(first.nTime, second.nTime);
swap(first.nFeeTXHash, second.nFeeTXHash);
swap(first.strData, second.strData);
2016-05-13 18:03:01 +02:00
// swap all cached valid flags
swap(first.fCachedFunding, second.fCachedFunding);
swap(first.fCachedValid, second.fCachedValid);
swap(first.fCachedDelete, second.fCachedDelete);
swap(first.fCachedEndorsed, second.fCachedEndorsed);
2016-04-26 06:08:36 +02:00
}
2016-04-17 02:29:41 +02:00
bool HasMinimumRequiredSupport();
bool IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral=true);
std::string GetName() {return strName; }
2016-04-26 06:08:36 +02:00
// get vote counts on each outcome
int GetAbsoluteYesCount(int nVoteSignalIn);
int GetAbsoluteNoCount(int nVoteSignalIn);
int GetYesCount(int nVoteSignalIn);
int GetNoCount(int nVoteSignalIn);
int GetAbstainCount(int nVoteSignalIn);
2016-04-17 02:29:41 +02:00
void CleanAndRemove(bool fSignatureCheck);
void Relay();
2016-05-24 00:52:10 +02:00
2016-04-17 02:29:41 +02:00
uint256 GetHash(){
2016-05-13 18:03:01 +02:00
// CREATE HASH OF ALL IMPORTANT PIECES OF DATA
2016-05-13 18:03:01 +02:00
2016-04-17 02:29:41 +02:00
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
2016-05-24 00:52:10 +02:00
ss << nHashParent;
ss << nRevision;
2016-04-17 02:29:41 +02:00
ss << strName;
2016-05-24 00:52:10 +02:00
ss << nTime;
2016-05-13 18:03:01 +02:00
ss << strData;
// fee_tx is left out on purpose
2016-04-17 02:29:41 +02:00
uint256 h1 = ss.GetHash();
return h1;
}
2016-04-15 11:10:38 +02:00
/**
* SetData - Example usage:
2016-04-16 19:19:17 +02:00
* --------------------------------------------------------
*
* Governance is data-agnostic, for rules about data see sentinel documentation
*
2016-04-15 11:10:38 +02:00
*/
2016-05-13 18:03:01 +02:00
bool SetData(std::string& strError, std::string strDataIn)
2016-04-16 19:19:17 +02:00
{
// SET DATA FIELD TO INPUT
2016-05-13 18:03:01 +02:00
if(strDataIn.size() > 512*4)
2016-04-16 19:19:17 +02:00
{
// (assumption) this is equal to pythons len(strData) > 512*4, I think
2016-04-16 19:19:17 +02:00
strError = "Too big.";
return false;
}
2016-05-13 18:03:01 +02:00
strData = strDataIn;
2016-04-16 19:19:17 +02:00
return true;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
2016-04-17 02:29:41 +02:00
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
{
// SERIALIZE DATA FOR SAVING/LOADING OR NETWORK FUNCTIONS
2016-04-26 06:08:36 +02:00
READWRITE(nHashParent);
READWRITE(nRevision);
READWRITE(LIMITED_STRING(strName, 64));
READWRITE(nTime);
READWRITE(nFeeTXHash);
READWRITE(strData);
}
};
#endif