LCOV - code coverage report
Current view: top level - src - spork.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 111 152 73.0 %
Date: 2025-02-23 09:33:43 Functions: 15 20 75.0 %

          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             : 

Generated by: LCOV version 1.14