Line data Source code
1 : // Copyright (c) 2021-2022 The PIVX Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include "tiertwo/init.h"
6 :
7 : #include "budget/budgetdb.h"
8 : #include "evo/evodb.h"
9 : #include "evo/evonotificationinterface.h"
10 : #include "flatdb.h"
11 : #include "guiinterface.h"
12 : #include "guiinterfaceutil.h"
13 : #include "masternodeman.h"
14 : #include "masternode-payments.h"
15 : #include "masternodeconfig.h"
16 : #include "llmq/quorums_init.h"
17 : #include "scheduler.h"
18 : #include "tiertwo/masternode_meta_manager.h"
19 : #include "tiertwo/netfulfilledman.h"
20 : #include "validation.h"
21 : #include "wallet/wallet.h"
22 :
23 : #include <boost/thread.hpp>
24 :
25 : static std::unique_ptr<EvoNotificationInterface> pEvoNotificationInterface{nullptr};
26 :
27 1 : std::string GetTierTwoHelpString(bool showDebug)
28 : {
29 1 : std::string strUsage = HelpMessageGroup("Masternode options:");
30 3 : strUsage += HelpMessageOpt("-masternode=<n>", strprintf("Enable the client to act as a masternode (0-1, default: %u)", DEFAULT_MASTERNODE));
31 3 : strUsage += HelpMessageOpt("-mnconf=<file>", strprintf("Specify masternode configuration file (default: %s)", PIVX_MASTERNODE_CONF_FILENAME));
32 3 : strUsage += HelpMessageOpt("-mnconflock=<n>", strprintf("Lock masternodes from masternode configuration file (default: %u)", DEFAULT_MNCONFLOCK));
33 4 : strUsage += HelpMessageOpt("-masternodeprivkey=<n>", "Set the masternode private key");
34 4 : strUsage += HelpMessageOpt("-masternodeaddr=<n>", strprintf("Set external address:port to get to this masternode (example: %s). Only for Legacy Masternodes", "128.127.106.235:51472"));
35 4 : strUsage += HelpMessageOpt("-budgetvotemode=<mode>", "Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto)");
36 4 : strUsage += HelpMessageOpt("-mnoperatorprivatekey=<bech32>", "Set the masternode operator private key. Only valid with -masternode=1. When set, the masternode acts as a deterministic masternode.");
37 1 : if (showDebug) {
38 0 : strUsage += HelpMessageOpt("-pushversion", strprintf("Modifies the mnauth serialization if the version is lower than %d."
39 0 : "testnet/regtest only; ", MNAUTH_NODE_VER_VERSION));
40 0 : strUsage += HelpMessageOpt("-disabledkg", "Disable the DKG sessions process threads for the entire lifecycle. testnet/regtest only.");
41 : }
42 1 : return strUsage;
43 : }
44 :
45 357 : void InitTierTwoInterfaces()
46 : {
47 357 : pEvoNotificationInterface = std::make_unique<EvoNotificationInterface>();
48 357 : RegisterValidationInterface(pEvoNotificationInterface.get());
49 357 : }
50 :
51 378 : void ResetTierTwoInterfaces()
52 : {
53 378 : if (pEvoNotificationInterface) {
54 357 : UnregisterValidationInterface(pEvoNotificationInterface.get());
55 357 : pEvoNotificationInterface.reset();
56 : }
57 :
58 378 : if (activeMasternodeManager) {
59 41 : UnregisterValidationInterface(activeMasternodeManager);
60 41 : delete activeMasternodeManager;
61 41 : activeMasternodeManager = nullptr;
62 : }
63 378 : }
64 :
65 357 : void InitTierTwoPreChainLoad(bool fReindex)
66 : {
67 357 : int64_t nEvoDbCache = 1024 * 1024 * 64; // Max cache is 64MB
68 357 : deterministicMNManager.reset();
69 357 : evoDb.reset();
70 357 : evoDb.reset(new CEvoDB(nEvoDbCache, false, fReindex));
71 357 : deterministicMNManager.reset(new CDeterministicMNManager(*evoDb));
72 357 : }
73 :
74 357 : void InitTierTwoPostCoinsCacheLoad(CScheduler* scheduler)
75 : {
76 : // Initialize LLMQ system
77 357 : llmq::InitLLMQSystem(*evoDb, scheduler, false);
78 357 : }
79 :
80 355 : void InitTierTwoChainTip()
81 : {
82 : // force UpdatedBlockTip to initialize nCachedBlockHeight for DS, MN payments and budgets
83 : // but don't call it directly to prevent triggering of other listeners like zmq etc.
84 355 : pEvoNotificationInterface->InitializeCurrentBlockTip();
85 355 : }
86 :
87 : // Sets the last CACHED_BLOCK_HASHES hashes into masternode manager cache
88 355 : static void LoadBlockHashesCache(CMasternodeMan& man)
89 : {
90 355 : LOCK(cs_main);
91 355 : const CBlockIndex* pindex = chainActive.Tip();
92 : unsigned int inserted = 0;
93 24715 : while (pindex && inserted < CACHED_BLOCK_HASHES) {
94 24360 : man.CacheBlockHash(pindex);
95 24360 : pindex = pindex->pprev;
96 24360 : ++inserted;
97 : }
98 355 : }
99 :
100 355 : bool LoadTierTwo(int chain_active_height, bool load_cache_files)
101 : {
102 : // ################################# //
103 : // ## Legacy Masternodes Manager ### //
104 : // ################################# //
105 355 : uiInterface.InitMessage(_("Loading masternode cache..."));
106 :
107 355 : mnodeman.SetBestHeight(chain_active_height);
108 355 : LoadBlockHashesCache(mnodeman);
109 710 : CMasternodeDB mndb;
110 355 : CMasternodeDB::ReadResult readResult = mndb.Read(mnodeman);
111 355 : if (readResult == CMasternodeDB::FileError)
112 273 : LogPrintf("Missing masternode cache file - mncache.dat, will try to recreate\n");
113 82 : else if (readResult != CMasternodeDB::Ok) {
114 0 : LogPrintf("Error reading mncache.dat - cached data discarded\n");
115 : }
116 :
117 : // ##################### //
118 : // ## Budget Manager ### //
119 : // ##################### //
120 355 : uiInterface.InitMessage(_("Loading budget cache..."));
121 :
122 710 : CBudgetDB budgetdb;
123 355 : const bool fDryRun = (chain_active_height <= 0);
124 355 : if (!fDryRun) g_budgetman.SetBestHeight(chain_active_height);
125 355 : CBudgetDB::ReadResult readResult2 = budgetdb.Read(g_budgetman, fDryRun);
126 :
127 355 : if (readResult2 == CBudgetDB::FileError)
128 273 : LogPrintf("Missing budget cache - budget.dat, will try to recreate\n");
129 82 : else if (readResult2 != CBudgetDB::Ok) {
130 0 : LogPrintf("Error reading budget.dat - cached data discarded\n");
131 : }
132 :
133 : // flag our cached items so we send them to our peers
134 355 : g_budgetman.ResetSync();
135 355 : g_budgetman.ReloadMapSeen();
136 :
137 : // ######################################### //
138 : // ## Legacy Masternodes-Payments Manager ## //
139 : // ######################################### //
140 355 : uiInterface.InitMessage(_("Loading masternode payment cache..."));
141 :
142 355 : CMasternodePaymentDB mnpayments;
143 355 : CMasternodePaymentDB::ReadResult readResult3 = mnpayments.Read(masternodePayments);
144 355 : if (readResult3 == CMasternodePaymentDB::FileError)
145 273 : LogPrintf("Missing masternode payment cache - mnpayments.dat, will try to recreate\n");
146 82 : else if (readResult3 != CMasternodePaymentDB::Ok) {
147 0 : LogPrintf("Error reading mnpayments.dat - cached data discarded\n");
148 : }
149 :
150 : // ###################################### //
151 : // ## Legacy Parse 'masternodes.conf' ## //
152 : // ###################################### //
153 710 : std::string strErr;
154 355 : if (!masternodeConfig.read(strErr)) {
155 0 : return UIError(strprintf(_("Error reading masternode configuration file: %s"), strErr));
156 : }
157 :
158 : // ############################## //
159 : // ## Net MNs Metadata Manager ## //
160 : // ############################## //
161 355 : uiInterface.InitMessage(_("Loading masternode cache..."));
162 710 : CFlatDB<CMasternodeMetaMan> metadb(MN_META_CACHE_FILENAME, MN_META_CACHE_FILE_ID);
163 355 : if (load_cache_files) {
164 348 : if (!metadb.Load(g_mmetaman)) {
165 0 : return UIError(strprintf(_("Failed to load masternode metadata cache from: %s"), metadb.GetDbPath().string()));
166 : }
167 : } else {
168 14 : CMasternodeMetaMan mmetamanTmp;
169 7 : if (!metadb.Dump(mmetamanTmp)) {
170 0 : return UIError(strprintf(_("Failed to clear masternode metadata cache at: %s"), metadb.GetDbPath().string()));
171 : }
172 : }
173 :
174 : // ############################## //
175 : // ## Network Requests Manager ## //
176 : // ############################## //
177 355 : uiInterface.InitMessage(_("Loading network requests cache..."));
178 355 : CFlatDB<CNetFulfilledRequestManager> netRequestsDb(NET_REQUESTS_CACHE_FILENAME, NET_REQUESTS_CACHE_FILE_ID);
179 355 : if (load_cache_files) {
180 348 : if (!netRequestsDb.Load(g_netfulfilledman)) {
181 0 : LogPrintf("Failed to load network requests cache from %s\n", netRequestsDb.GetDbPath().string());
182 : }
183 : } else {
184 14 : CNetFulfilledRequestManager netfulfilledmanTmp(0);
185 7 : if (!netRequestsDb.Dump(netfulfilledmanTmp)) {
186 0 : LogPrintf("Failed to clear network requests cache at %s\n", netRequestsDb.GetDbPath().string());
187 : }
188 : }
189 :
190 355 : return true;
191 : }
192 :
193 355 : void RegisterTierTwoValidationInterface()
194 : {
195 355 : RegisterValidationInterface(&g_budgetman);
196 355 : RegisterValidationInterface(&masternodePayments);
197 355 : if (activeMasternodeManager) RegisterValidationInterface(activeMasternodeManager);
198 355 : }
199 :
200 378 : void DumpTierTwo()
201 : {
202 378 : DumpMasternodes();
203 378 : DumpBudgets(g_budgetman);
204 378 : DumpMasternodePayments();
205 378 : CFlatDB<CMasternodeMetaMan>(MN_META_CACHE_FILENAME, MN_META_CACHE_FILE_ID).Dump(g_mmetaman);
206 378 : CFlatDB<CNetFulfilledRequestManager>(NET_REQUESTS_CACHE_FILENAME, NET_REQUESTS_CACHE_FILE_ID).Dump(g_netfulfilledman);
207 378 : }
208 :
209 355 : void SetBudgetFinMode(const std::string& mode)
210 : {
211 355 : g_budgetman.strBudgetMode = mode;
212 355 : LogPrintf("Budget Mode %s\n", g_budgetman.strBudgetMode);
213 355 : }
214 :
215 355 : bool InitActiveMN()
216 : {
217 355 : fMasterNode = gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE);
218 355 : if ((fMasterNode || masternodeConfig.getCount() > -1) && fTxIndex == false) {
219 0 : return UIError(strprintf(_("Enabling Masternode support requires turning on transaction indexing."
220 : "Please add %s to your configuration and start with %s"), "txindex=1", "-reindex"));
221 : }
222 :
223 355 : if (fMasterNode) {
224 :
225 0 : if (gArgs.IsArgSet("-connect") && gArgs.GetArgs("-connect").size() > 0) {
226 0 : return UIError(_("Cannot be a masternode and only connect to specific nodes"));
227 : }
228 :
229 0 : if (gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS) < DEFAULT_MAX_PEER_CONNECTIONS) {
230 0 : return UIError(strprintf(_("Masternode must be able to handle at least %d connections, set %s=%d"),
231 : DEFAULT_MAX_PEER_CONNECTIONS, "-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS));
232 : }
233 :
234 0 : const std::string& mnoperatorkeyStr = gArgs.GetArg("-mnoperatorprivatekey", "");
235 0 : const bool fDeterministic = !mnoperatorkeyStr.empty();
236 0 : LogPrintf("IS %s MASTERNODE\n", (fDeterministic ? "DETERMINISTIC " : ""));
237 :
238 0 : if (fDeterministic) {
239 : // Check enforcement
240 0 : if (!deterministicMNManager->IsDIP3Enforced()) {
241 0 : const std::string strError = strprintf(
242 0 : _("Cannot start deterministic masternode before enforcement. Remove %s to start as legacy masternode"),
243 0 : "-mnoperatorprivatekey");
244 0 : LogPrintf("-- ERROR: %s\n", strError);
245 0 : return UIError(strError);
246 : }
247 : // Create and register activeMasternodeManager
248 0 : activeMasternodeManager = new CActiveDeterministicMasternodeManager();
249 0 : auto res = activeMasternodeManager->SetOperatorKey(mnoperatorkeyStr);
250 0 : if (!res) { return UIError(res.getError()); }
251 : // Init active masternode
252 0 : const CBlockIndex* pindexTip = WITH_LOCK(cs_main, return chainActive.Tip(););
253 0 : activeMasternodeManager->Init(pindexTip);
254 0 : if (activeMasternodeManager->GetState() == CActiveDeterministicMasternodeManager::MASTERNODE_ERROR) {
255 0 : return UIError(activeMasternodeManager->GetStatus()); // state logged internally
256 : }
257 : } else {
258 : // Check enforcement
259 0 : if (deterministicMNManager->LegacyMNObsolete()) {
260 0 : const std::string strError = strprintf(
261 0 : _("Legacy masternode system disabled. Use %s to start as deterministic masternode"),
262 0 : "-mnoperatorprivatekey");
263 0 : LogPrintf("-- ERROR: %s\n", strError);
264 0 : return UIError(strError);
265 : }
266 0 : auto res = initMasternode(gArgs.GetArg("-masternodeprivkey", ""), gArgs.GetArg("-masternodeaddr", ""),
267 0 : true);
268 0 : if (!res) { return UIError(res.getError()); }
269 : }
270 : }
271 :
272 : #ifdef ENABLE_WALLET
273 : // !TODO: remove after complete transition to DMN
274 : // use only the first wallet here. This section can be removed after transition to DMN
275 710 : if (gArgs.GetBoolArg("-mnconflock", DEFAULT_MNCONFLOCK) && !vpwallets.empty() && vpwallets[0]) {
276 686 : LOCK(vpwallets[0]->cs_wallet);
277 343 : LogPrintf("Locking Masternodes collateral utxo:\n");
278 343 : uint256 mnTxHash;
279 344 : for (const auto& mne : masternodeConfig.getEntries()) {
280 1 : mnTxHash.SetHex(mne.getTxHash());
281 1 : COutPoint outpoint = COutPoint(mnTxHash, (unsigned int) std::stoul(mne.getOutputIndex()));
282 1 : vpwallets[0]->LockCoin(outpoint);
283 1 : LogPrintf("Locked collateral, MN: %s, tx hash: %s, output index: %s\n",
284 1 : mne.getAlias(), mne.getTxHash(), mne.getOutputIndex());
285 : }
286 : }
287 :
288 : // automatic lock for DMN
289 355 : if (gArgs.GetBoolArg("-mnconflock", DEFAULT_MNCONFLOCK)) {
290 355 : LogPrintf("Locking masternode collaterals...\n");
291 355 : const auto& mnList = deterministicMNManager->GetListAtChainTip();
292 355 : mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
293 24 : for (CWallet* pwallet : vpwallets) {
294 24 : pwallet->LockOutpointIfMineWithMutex(nullptr, dmn->collateralOutpoint);
295 : }
296 12 : });
297 : }
298 : #endif
299 : // All good
300 : return true;
301 : }
302 :
303 355 : void StartTierTwoThreadsAndScheduleJobs(boost::thread_group& threadGroup, CScheduler& scheduler)
304 : {
305 355 : threadGroup.create_thread(std::bind(&ThreadCheckMasternodes));
306 355 : scheduler.scheduleEvery(std::bind(&CNetFulfilledRequestManager::DoMaintenance, std::ref(g_netfulfilledman)), 60 * 1000);
307 :
308 : // Start LLMQ system
309 355 : if (gArgs.GetBoolArg("-disabledkg", false)) {
310 8 : if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
311 0 : throw std::runtime_error("DKG system can be disabled only on testnet/regtest");
312 : } else {
313 8 : LogPrintf("DKG system disabled.\n");
314 : }
315 : } else {
316 347 : llmq::StartLLMQSystem();
317 : }
318 355 : }
319 :
320 378 : void StopTierTwoThreads()
321 : {
322 378 : llmq::StopLLMQSystem();
323 378 : }
324 :
325 378 : void DeleteTierTwo()
326 : {
327 378 : llmq::DestroyLLMQSystem();
328 378 : deterministicMNManager.reset();
329 378 : evoDb.reset();
330 378 : }
331 :
332 378 : void InterruptTierTwo()
333 : {
334 378 : llmq::InterruptLLMQSystem();
335 378 : }
|