Line data Source code
1 : // Copyright (c) 2014-2016 The Dash developers
2 : // Copyright (c) 2016-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 : #include "spork.h"
7 :
8 : #include "netmessagemaker.h"
9 : #include "sporkdb.h"
10 : #include "validation.h"
11 :
12 : #include <iostream>
13 :
14 : #define MAKE_SPORK_DEF(name, defaultValue) CSporkDef(name, defaultValue, #name)
15 :
16 : std::vector<CSporkDef> sporkDefs = {
17 : MAKE_SPORK_DEF(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT, 4070908800ULL), // OFF
18 : MAKE_SPORK_DEF(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT, 4070908800ULL), // OFF
19 : MAKE_SPORK_DEF(SPORK_13_ENABLE_SUPERBLOCKS, 4070908800ULL), // OFF
20 : MAKE_SPORK_DEF(SPORK_14_NEW_PROTOCOL_ENFORCEMENT, 4070908800ULL), // OFF
21 : MAKE_SPORK_DEF(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2, 4070908800ULL), // OFF
22 : MAKE_SPORK_DEF(SPORK_19_COLDSTAKING_MAINTENANCE, 4070908800ULL), // OFF
23 : MAKE_SPORK_DEF(SPORK_20_SAPLING_MAINTENANCE, 4070908800ULL), // OFF
24 : MAKE_SPORK_DEF(SPORK_21_LEGACY_MNS_MAX_HEIGHT, 4070908800ULL), // OFF
25 : MAKE_SPORK_DEF(SPORK_22_LLMQ_DKG_MAINTENANCE, 4070908800ULL), // OFF
26 : MAKE_SPORK_DEF(SPORK_23_CHAINLOCKS_ENFORCEMENT, 4070908800ULL), // OFF
27 : };
28 :
29 : CSporkManager sporkManager;
30 : std::map<uint256, CSporkMessage> mapSporks;
31 :
32 479 : CSporkManager::CSporkManager()
33 : {
34 5269 : for (auto& sporkDef : sporkDefs) {
35 4790 : sporkDefsById.emplace(sporkDef.sporkId, &sporkDef);
36 4790 : sporkDefsByName.emplace(sporkDef.name, &sporkDef);
37 : }
38 479 : }
39 :
40 0 : void CSporkManager::Clear()
41 : {
42 0 : strMasterPrivKey = "";
43 0 : mapSporksActive.clear();
44 0 : }
45 :
46 : // PIVX: on startup load spork values from previous session if they exist in the sporkDB
47 357 : void CSporkManager::LoadSporksFromDB()
48 : {
49 3927 : for (const auto& sporkDef : sporkDefs) {
50 : // attempt to read spork from sporkDB
51 3576 : CSporkMessage spork;
52 3570 : if (!pSporkDB->ReadSpork(sporkDef.sporkId, spork)) {
53 3564 : LogPrintf("%s : no previous value for %s found in database\n", __func__, sporkDef.name);
54 3564 : continue;
55 : }
56 :
57 : // TODO: Temporary workaround for v5.0 clients to ensure up-to-date protocol version spork
58 6 : if (spork.nSporkID == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) {
59 0 : LogPrintf("%s : Spork 15 signed at %d\n", __func__, spork.nTimeSigned);
60 : // 1578338986 is the timestamp that spork 15 was last signed at for mainnet for the previous
61 : // protocol bump. If the timestamp in the DB is equal or lower than this, we know that
62 : // the value is stale and should ignore it to prevent un-necessary disconnections in the
63 : // version handshake process. This value is also suitable for testnet as the timestamp
64 : // for this spork on that network was signed shortly after this.
65 0 : if (spork.nTimeSigned <= 1578338986 ) {
66 0 : LogPrintf("%s : Stale spork 15 detected, clearing...\n", __func__);
67 0 : CSporkManager::Clear();
68 0 : return;
69 : }
70 : }
71 :
72 : // add spork to memory
73 6 : AddOrUpdateSporkMessage(spork);
74 :
75 6 : std::time_t result = spork.nValue;
76 : // If SPORK Value is greater than 1,000,000 assume it's actually a Date and then convert to a more readable format
77 12 : std::string sporkName = sporkManager.GetSporkNameByID(spork.nSporkID);
78 6 : if (spork.nValue > 1000000) {
79 3 : char* res = std::ctime(&result);
80 3 : LogPrintf("%s : loaded spork %s with value %d : %s\n", __func__, sporkName.c_str(), spork.nValue,
81 3 : ((res) ? res : "no time") );
82 : } else {
83 3 : LogPrintf("%s : loaded spork %s with value %d\n", __func__,
84 : sporkName, spork.nValue);
85 : }
86 : }
87 : }
88 :
89 55734 : bool CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, int& dosScore)
90 : {
91 55734 : if (strCommand == NetMsgType::SPORK) {
92 0 : dosScore = ProcessSporkMsg(vRecv);
93 0 : return dosScore == 0;
94 : }
95 55734 : if (strCommand == NetMsgType::GETSPORKS) {
96 0 : ProcessGetSporks(pfrom, strCommand, vRecv);
97 : }
98 : return true;
99 : }
100 :
101 0 : int CSporkManager::ProcessSporkMsg(CDataStream& vRecv)
102 : {
103 0 : CSporkMessage spork;
104 0 : vRecv >> spork;
105 0 : return ProcessSporkMsg(spork);
106 : }
107 :
108 2167 : int CSporkManager::ProcessSporkMsg(CSporkMessage& spork)
109 : {
110 : // Ignore spork messages about unknown/deleted sporks
111 4334 : std::string strSpork = sporkManager.GetSporkNameByID(spork.nSporkID);
112 2167 : if (strSpork == "Unknown") return 0;
113 :
114 : // Do not accept sporks signed way too far into the future
115 805 : if (spork.nTimeSigned > GetAdjustedTime() + 2 * 60 * 60) {
116 0 : LogPrint(BCLog::SPORKS, "%s : ERROR: too far into the future\n", __func__);
117 0 : return 100;
118 : }
119 :
120 : // reject old signature version
121 805 : if (spork.nMessVersion != MessageVersion::MESS_VER_HASH) {
122 0 : LogPrint(BCLog::SPORKS, "%s : nMessVersion=%d not accepted anymore\n", __func__, spork.nMessVersion);
123 0 : return 0;
124 : }
125 :
126 2972 : std::string sporkName = sporkManager.GetSporkNameByID(spork.nSporkID);
127 1610 : std::string strStatus;
128 805 : {
129 805 : LOCK(cs);
130 805 : if (mapSporksActive.count(spork.nSporkID)) {
131 : // spork is active
132 638 : if (mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned) {
133 : // spork in memory has been signed more recently
134 617 : LogPrint(BCLog::SPORKS, "%s : spork %d (%s) in memory is more recent: %d >= %d\n", __func__,
135 : spork.nSporkID, sporkName,
136 : mapSporksActive[spork.nSporkID].nTimeSigned, spork.nTimeSigned);
137 1234 : return 0;
138 : } else {
139 : // update active spork
140 21 : strStatus = "updated";
141 : }
142 : } else {
143 : // spork is not active
144 188 : strStatus = "new";
145 : }
146 : }
147 :
148 188 : const bool fRequireNew = spork.nTimeSigned >= Params().GetConsensus().nTime_EnforceNewSporkKey;
149 188 : bool fValidSig = spork.CheckSignature(spork.GetPublicKey().GetID());
150 188 : if (!fValidSig && !fRequireNew) {
151 : // See if window is open that allows for old spork key to sign messages
152 0 : if (GetAdjustedTime() < Params().GetConsensus().nTime_RejectOldSporkKey) {
153 0 : CPubKey pubkeyold = spork.GetPublicKeyOld();
154 0 : fValidSig = spork.CheckSignature(pubkeyold.GetID());
155 : }
156 : }
157 :
158 188 : if (!fValidSig) {
159 0 : LogPrint(BCLog::SPORKS, "%s : Invalid Signature\n", __func__);
160 0 : return 100;
161 : }
162 :
163 : // Log valid spork value change
164 188 : LogPrintf("%s : got %s spork %d (%s) with value %d (signed at %d)\n", __func__,
165 188 : strStatus, spork.nSporkID, sporkName, spork.nValue, spork.nTimeSigned);
166 :
167 188 : AddOrUpdateSporkMessage(spork, true);
168 188 : spork.Relay();
169 :
170 : // All good.
171 : return 0;
172 : }
173 :
174 1415 : void CSporkManager::ProcessGetSporks(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
175 : {
176 1415 : LOCK(cs);
177 :
178 1415 : std::map<SporkId, CSporkMessage>::iterator it = mapSporksActive.begin();
179 :
180 2191 : while (it != mapSporksActive.end()) {
181 776 : g_connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SPORK, it->second));
182 2191 : it++;
183 : }
184 :
185 : // end message
186 1415 : if (Params().IsRegTestNet()) {
187 : // For now, only use it on regtest.
188 2830 : CSporkMessage msg(SPORK_INVALID, 0, 0);
189 1415 : g_connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SPORK, msg));
190 : }
191 1415 : }
192 :
193 41 : bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue)
194 : {
195 82 : CSporkMessage spork(nSporkID, nValue, GetTime());
196 :
197 123 : if (spork.Sign(strMasterPrivKey)) {
198 41 : spork.Relay();
199 41 : AddOrUpdateSporkMessage(spork, true);
200 : return true;
201 : }
202 :
203 : return false;
204 : }
205 :
206 251 : void CSporkManager::AddOrUpdateSporkMessage(const CSporkMessage& spork, bool flush)
207 : {
208 251 : {
209 251 : LOCK(cs);
210 251 : mapSporks[spork.GetHash()] = spork;
211 251 : mapSporksActive[spork.nSporkID] = spork;
212 : }
213 251 : if (flush) {
214 : // add to spork database.
215 229 : pSporkDB->WriteSpork(spork.nSporkID, spork);
216 : }
217 251 : }
218 :
219 : // grab the spork value, and see if it's off
220 727321 : bool CSporkManager::IsSporkActive(SporkId nSporkID)
221 : {
222 727321 : return GetSporkValue(nSporkID) < GetAdjustedTime();
223 : }
224 :
225 : // grab the value of the spork on the network, or the default
226 1014008 : int64_t CSporkManager::GetSporkValue(SporkId nSporkID)
227 : {
228 2028014 : LOCK(cs);
229 :
230 1014008 : if (mapSporksActive.count(nSporkID)) {
231 135117 : return mapSporksActive[nSporkID].nValue;
232 :
233 : } else {
234 878891 : auto it = sporkDefsById.find(nSporkID);
235 878891 : if (it != sporkDefsById.end()) {
236 878891 : return it->second->defaultValue;
237 : } else {
238 0 : LogPrintf("%s : Unknown Spork %d\n", __func__, nSporkID);
239 : }
240 : }
241 :
242 0 : return -1;
243 : }
244 :
245 41 : SporkId CSporkManager::GetSporkIDByName(std::string strName)
246 : {
247 41 : auto it = sporkDefsByName.find(strName);
248 41 : if (it == sporkDefsByName.end()) {
249 0 : LogPrintf("%s : Unknown Spork name '%s'\n", __func__, strName);
250 0 : return SPORK_INVALID;
251 : }
252 41 : return it->second->sporkId;
253 : }
254 :
255 3207 : std::string CSporkManager::GetSporkNameByID(SporkId nSporkID)
256 : {
257 3207 : auto it = sporkDefsById.find(nSporkID);
258 3207 : if (it == sporkDefsById.end()) {
259 1362 : LogPrint(BCLog::SPORKS, "%s : Unknown Spork ID %d\n", __func__, nSporkID);
260 1362 : return "Unknown";
261 : }
262 1845 : return it->second->name;
263 : }
264 :
265 85 : bool CSporkManager::SetPrivKey(std::string strPrivKey)
266 : {
267 170 : CSporkMessage spork;
268 :
269 170 : spork.Sign(strPrivKey);
270 :
271 85 : bool fValidSig = spork.CheckSignature(spork.GetPublicKey().GetID());
272 85 : if (!fValidSig) {
273 : // See if window is open that allows for old spork key to sign messages
274 0 : if (GetAdjustedTime() < Params().GetConsensus().nTime_RejectOldSporkKey) {
275 0 : CPubKey pubkeyold = spork.GetPublicKeyOld();
276 0 : fValidSig = spork.CheckSignature(pubkeyold.GetID());
277 : }
278 : }
279 85 : if (fValidSig) {
280 170 : LOCK(cs);
281 : // Test signing successful, proceed
282 85 : LogPrintf("%s : Successfully initialized as spork signer\n", __func__);
283 85 : strMasterPrivKey = strPrivKey;
284 85 : return true;
285 : }
286 :
287 : return false;
288 : }
289 :
290 0 : std::string CSporkManager::ToString() const
291 : {
292 0 : LOCK(cs);
293 0 : return strprintf("Sporks: %llu", mapSporksActive.size());
294 : }
295 :
296 399 : uint256 CSporkMessage::GetSignatureHash() const
297 : {
298 399 : CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
299 399 : ss << nMessVersion;
300 399 : ss << nSporkID;
301 399 : ss << nValue;
302 399 : ss << nTimeSigned;
303 399 : return ss.GetHash();
304 : }
305 :
306 0 : std::string CSporkMessage::GetStrMessage() const
307 : {
308 0 : return std::to_string(nSporkID) +
309 0 : std::to_string(nValue) +
310 0 : std::to_string(nTimeSigned);
311 : }
312 :
313 273 : const CPubKey CSporkMessage::GetPublicKey() const
314 : {
315 273 : return CPubKey(ParseHex(Params().GetConsensus().strSporkPubKey));
316 : }
317 :
318 0 : const CPubKey CSporkMessage::GetPublicKeyOld() const
319 : {
320 0 : return CPubKey(ParseHex(Params().GetConsensus().strSporkPubKeyOld));
321 : }
322 :
323 229 : void CSporkMessage::Relay()
324 : {
325 229 : CInv inv(MSG_SPORK, GetHash());
326 229 : g_connman->RelayInv(inv);
327 229 : }
328 :
|