Line data Source code
1 : // Copyright (c) 2014-2015 The Dash developers
2 : // Copyright (c) 2015-2022 The PIVX Core developers
3 : // Distributed under the MIT/X11 software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #ifndef PIVX_BUDGET_BUDGETMANAGER_H
7 : #define PIVX_BUDGET_BUDGETMANAGER_H
8 :
9 : #include "budget/budgetproposal.h"
10 : #include "budget/finalizedbudget.h"
11 : #include "validationinterface.h"
12 :
13 : class CValidationState;
14 :
15 : #define ORPHAN_VOTES_CACHE_LIMIT 10000
16 :
17 : //
18 : // Budget Manager : Contains all proposals for the budget
19 : //
20 : class CBudgetManager : public CValidationInterface
21 : {
22 : protected:
23 : // map budget hash --> CollTx hash.
24 : // hold unconfirmed finalized-budgets collateral txes until they mature enough to use
25 : std::map<uint256, uint256> mapUnconfirmedFeeTx; // guarded by cs_budgets
26 :
27 : // map CollTx hash --> budget hash
28 : // keep track of collaterals for valid budgets/proposals (for reorgs)
29 : std::map<uint256, uint256> mapFeeTxToProposal; // guarded by cs_proposals
30 : std::map<uint256, uint256> mapFeeTxToBudget; // guarded by cs_budgets
31 :
32 : std::map<uint256, CBudgetProposal> mapProposals; // guarded by cs_proposals
33 : std::map<uint256, CFinalizedBudget> mapFinalizedBudgets; // guarded by cs_budgets
34 :
35 : std::map<uint256, CBudgetVote> mapSeenProposalVotes; // guarded by cs_votes
36 : typedef std::pair<std::vector<CBudgetVote>, int64_t> PropVotesAndLastVoteReceivedTime;
37 : std::map<uint256, PropVotesAndLastVoteReceivedTime> mapOrphanProposalVotes; // guarded by cs_votes
38 : std::map<uint256, CFinalizedBudgetVote> mapSeenFinalizedBudgetVotes; // guarded by cs_finalizedvotes
39 : typedef std::pair<std::vector<CFinalizedBudgetVote>, int64_t> BudVotesAndLastVoteReceivedTime;
40 : std::map<uint256, BudVotesAndLastVoteReceivedTime> mapOrphanFinalizedBudgetVotes; // guarded by cs_finalizedvotes
41 :
42 : // Memory Only. Updated in NewBlock (blocks arrive in order)
43 : std::atomic<int> nBestHeight;
44 :
45 : struct HighestFinBudget {
46 : const CFinalizedBudget* m_budget_fin{nullptr};
47 : int m_vote_count{0};
48 : };
49 :
50 : // Returns a const pointer to the budget with highest vote count
51 : HighestFinBudget GetBudgetWithHighestVoteCount(int chainHeight) const;
52 : int GetHighestVoteCount(int chainHeight) const;
53 : // Get the payee and amount for the budget with the highest vote count
54 : bool GetPayeeAndAmount(int chainHeight, CScript& payeeRet, CAmount& nAmountRet) const;
55 : // Marks synced all votes in proposals and finalized budgets
56 : void SetSynced(bool synced);
57 :
58 : public:
59 : // critical sections to protect the inner data structures (must be locked in this order)
60 : mutable RecursiveMutex cs_budgets;
61 : mutable RecursiveMutex cs_proposals;
62 : mutable RecursiveMutex cs_finalizedvotes;
63 : mutable RecursiveMutex cs_votes;
64 :
65 : // budget finalization
66 : std::string strBudgetMode;
67 :
68 486 : CBudgetManager() {}
69 :
70 : void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
71 :
72 11984 : bool HaveProposal(const uint256& propHash) const { LOCK(cs_proposals); return mapProposals.count(propHash); }
73 1114 : bool HaveSeenProposalVote(const uint256& voteHash) const { LOCK(cs_votes); return mapSeenProposalVotes.count(voteHash); }
74 776 : bool HaveFinalizedBudget(const uint256& budgetHash) const { LOCK(cs_budgets); return mapFinalizedBudgets.count(budgetHash); }
75 1038 : bool HaveSeenFinalizedBudgetVote(const uint256& voteHash) const { LOCK(cs_finalizedvotes); return mapSeenFinalizedBudgetVotes.count(voteHash); }
76 :
77 : // Clears and reloads seen votes in the maps, and clears orphan votes
78 : void ReloadMapSeen();
79 :
80 : void AddSeenProposalVote(const CBudgetVote& vote);
81 : void AddSeenFinalizedBudgetVote(const CFinalizedBudgetVote& vote);
82 :
83 : void RemoveStaleVotesOnProposal(CBudgetProposal* prop);
84 : void RemoveStaleVotesOnFinalBudget(CFinalizedBudget* fbud);
85 :
86 : // Use const operator std::map::at(), thus existence must be checked before calling.
87 : CDataStream GetProposalVoteSerialized(const uint256& voteHash) const;
88 : CDataStream GetProposalSerialized(const uint256& propHash) const;
89 : CDataStream GetFinalizedBudgetVoteSerialized(const uint256& voteHash) const;
90 : CDataStream GetFinalizedBudgetSerialized(const uint256& budgetHash) const;
91 :
92 : bool AddAndRelayProposalVote(const CBudgetVote& vote, std::string& strError);
93 :
94 : // sets strProposal of a CFinalizedBudget reference
95 : void SetBudgetProposalsStr(CFinalizedBudget& finalizedBudget) const;
96 :
97 : // checks finalized budget proposals (existence, payee, amount) for the finalized budget
98 : // in the map, with given nHash. Returns error string if any, or "OK" otherwise
99 : std::string GetFinalizedBudgetStatus(const uint256& nHash) const;
100 :
101 894 : void ResetSync() { SetSynced(false); }
102 1111 : void MarkSynced() { SetSynced(true); }
103 : // Respond to full budget sync requests and internally triggered partial budget items relay
104 : void Sync(CNode* node, bool fPartial);
105 : // Respond to single budget item requests (proposals / budget finalization)
106 : void SyncSingleItem(CNode* pfrom, const uint256& nProp);
107 41745 : void SetBestHeight(int height) { nBestHeight.store(height, std::memory_order_release); };
108 16448 : int GetBestHeight() const { return nBestHeight.load(std::memory_order_acquire); }
109 :
110 : bool ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, int& banScore);
111 : /// Process the message and returns the ban score (0 if no banning is needed)
112 : int ProcessMessageInner(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
113 :
114 : int ProcessBudgetVoteSync(const uint256& nProp, CNode* pfrom);
115 : int ProcessProposal(CBudgetProposal& proposal);
116 : int ProcessFinalizedBudget(CFinalizedBudget& finalbudget, CNode* pfrom);
117 :
118 : bool ProcessProposalVote(CBudgetVote& proposal, CNode* pfrom, CValidationState& state);
119 : bool ProcessFinalizedBudgetVote(CFinalizedBudgetVote& vote, CNode* pfrom, CValidationState& state);
120 :
121 : // functions returning a pointer in the map. Need cs_proposals/cs_budgets locked from the caller
122 : CBudgetProposal* FindProposal(const uint256& nHash);
123 : CFinalizedBudget* FindFinalizedBudget(const uint256& nHash);
124 : // const functions, copying the budget object to a reference and returning true if found
125 : bool GetProposal(const uint256& nHash, CBudgetProposal& bp) const;
126 : bool GetFinalizedBudget(const uint256& nHash, CFinalizedBudget& fb) const;
127 : // finds the proposal with the given name, with highest net yes count.
128 : const CBudgetProposal* FindProposalByName(const std::string& strProposalName) const;
129 :
130 : // Returns true if there is at least one proposal stored.
131 : bool HasAnyProposal() const { return WITH_LOCK(cs_proposals, return !mapProposals.empty()); }
132 :
133 : static CAmount GetTotalBudget(int nHeight);
134 : std::vector<CBudgetProposal> GetBudget();
135 : // Get all the budget proposals sorted by votes (highest to lowest)
136 : std::vector<CBudgetProposal*> GetAllProposalsOrdered();
137 : std::vector<CFinalizedBudget*> GetFinalizedBudgets();
138 : bool GetExpectedPayeeAmount(int chainHeight, CAmount& nAmountRet) const;
139 : bool IsBudgetPaymentBlock(int nBlockHeight) const;
140 : bool IsBudgetPaymentBlock(int nBlockHeight, int& nCountThreshold) const;
141 : bool AddProposal(CBudgetProposal& budgetProposal);
142 : bool AddFinalizedBudget(CFinalizedBudget& finalizedBudget, CNode* pfrom = nullptr);
143 : void ForceAddFinalizedBudget(const uint256& nHash, const uint256& feeTxId, const CFinalizedBudget& finalizedBudget);
144 : uint256 SubmitFinalBudget();
145 :
146 : bool UpdateProposal(const CBudgetVote& vote, CNode* pfrom, std::string& strError);
147 : bool UpdateFinalizedBudget(const CFinalizedBudgetVote& vote, CNode* pfrom, std::string& strError);
148 : TrxValidationStatus IsTransactionValid(const CTransaction& txNew, const uint256& nBlockHash, int nBlockHeight) const;
149 : std::string GetRequiredPaymentsString(int nBlockHeight);
150 : bool FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const int nHeight, bool fProofOfStake) const;
151 :
152 : // Only initialized masternodes: sign and submit votes on valid finalized budgets
153 : void VoteOnFinalizedBudgets();
154 :
155 0 : int CountProposals() { LOCK(cs_proposals); return mapProposals.size(); }
156 :
157 : void CheckOrphanVotes();
158 5 : void Clear()
159 : {
160 5 : {
161 5 : LOCK(cs_proposals);
162 5 : mapProposals.clear();
163 5 : mapFeeTxToProposal.clear();
164 : }
165 5 : {
166 5 : LOCK(cs_budgets);
167 5 : mapFinalizedBudgets.clear();
168 5 : mapFeeTxToBudget.clear();
169 5 : mapUnconfirmedFeeTx.clear();
170 : }
171 5 : {
172 5 : LOCK(cs_votes);
173 5 : mapSeenProposalVotes.clear();
174 5 : mapOrphanProposalVotes.clear();
175 : }
176 5 : {
177 5 : LOCK(cs_finalizedvotes);
178 5 : mapSeenFinalizedBudgetVotes.clear();
179 5 : mapOrphanFinalizedBudgetVotes.clear();
180 : }
181 5 : LogPrintf("Budget object cleared\n");
182 5 : }
183 : void CheckAndRemove();
184 : std::string ToString() const;
185 :
186 : // Remove proposal/budget by FeeTx (called when a block is disconnected)
187 : void RemoveByFeeTxId(const uint256& feeTxId);
188 :
189 920 : SERIALIZE_METHODS(CBudgetManager, obj)
190 : {
191 : {
192 460 : LOCK(obj.cs_proposals);
193 920 : READWRITE(obj.mapProposals, obj.mapFeeTxToProposal);
194 : }
195 : {
196 460 : LOCK(obj.cs_votes);
197 920 : READWRITE(obj.mapSeenProposalVotes, obj.mapOrphanProposalVotes);
198 : }
199 : {
200 460 : LOCK(obj.cs_budgets);
201 920 : READWRITE(obj.mapFinalizedBudgets, obj.mapFeeTxToBudget, obj.mapUnconfirmedFeeTx);
202 : }
203 : {
204 460 : LOCK(obj.cs_finalizedvotes);
205 920 : READWRITE(obj.mapSeenFinalizedBudgetVotes, obj.mapOrphanFinalizedBudgetVotes);
206 : }
207 460 : }
208 : };
209 :
210 : extern CBudgetManager g_budgetman;
211 :
212 : #endif // PIVX_BUDGET_BUDGETMANAGER_H
|