Refactor sporks to get rid of repeated if/else blocks (#2946)

* Use enum to define spork IDs

* Introduce CSporkDef and remove if/else blocks in GetSporkIDByName/GetSporkNameByID

* Deduplicate code in IsSporkActive

* Fix spork RPC to use new spork defs

This also removes the need for SPORK_START/SPORK_END

* Move sporkManager global variable below sporkDefs

This ensures correct order of initialization.
This commit is contained in:
Alexander Block 2019-05-29 20:18:31 +02:00 committed by UdjinM6
parent a149ca7471
commit fc73b4d6e6
3 changed files with 90 additions and 99 deletions

View File

@ -253,16 +253,14 @@ UniValue spork(const JSONRPCRequest& request)
std:: string strCommand = request.params[0].get_str(); std:: string strCommand = request.params[0].get_str();
if (strCommand == "show") { if (strCommand == "show") {
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
for(int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++){ for (const auto& sporkDef : sporkDefs) {
if(sporkManager.GetSporkNameByID(nSporkID) != "Unknown") ret.push_back(Pair(sporkDef.name, sporkManager.GetSporkValue(sporkDef.sporkId)));
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), sporkManager.GetSporkValue(nSporkID)));
} }
return ret; return ret;
} else if(strCommand == "active"){ } else if(strCommand == "active"){
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
for(int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++){ for (const auto& sporkDef : sporkDefs) {
if(sporkManager.GetSporkNameByID(nSporkID) != "Unknown") ret.push_back(Pair(sporkDef.name, sporkManager.IsSporkActive(sporkDef.sporkId)));
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), sporkManager.IsSporkActive(nSporkID)));
} }
return ret; return ret;
} }
@ -291,8 +289,8 @@ UniValue spork(const JSONRPCRequest& request)
+ HelpExampleRpc("spork", "\"show\"")); + HelpExampleRpc("spork", "\"show\""));
} else { } else {
// advanced mode, update spork values // advanced mode, update spork values
int nSporkID = sporkManager.GetSporkIDByName(request.params[0].get_str()); SporkId nSporkID = sporkManager.GetSporkIDByName(request.params[0].get_str());
if(nSporkID == -1) if(nSporkID == SPORK_INVALID)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid spork name"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid spork name");
if (!g_connman) if (!g_connman)

View File

@ -13,25 +13,34 @@
#include <string> #include <string>
CSporkManager sporkManager;
const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-Version-2"; const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-Version-2";
std::map<int, int64_t> mapSporkDefaults = { #define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name}
{SPORK_2_INSTANTSEND_ENABLED, 0}, // ON std::vector<CSporkDef> sporkDefs = {
{SPORK_3_INSTANTSEND_BLOCK_FILTERING, 0}, // ON MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 0), // ON
{SPORK_5_INSTANTSEND_MAX_VALUE, 1000}, // 1000 Dash MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 0), // ON
{SPORK_6_NEW_SIGS, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_5_INSTANTSEND_MAX_VALUE, 1000), // 1000 Dash
{SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_6_NEW_SIGS, 4070908800ULL), // OFF
{SPORK_12_RECONSIDER_BLOCKS, 0}, // 0 BLOCKS MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF
{SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_12_RECONSIDER_BLOCKS, 0), // 0 BLOCKS
{SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL), // OFF
{SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL), // OFF
{SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL), // OFF
{SPORK_20_INSTANTSEND_LLMQ_BASED, 4070908800ULL}, // OFF MAKE_SPORK_DEF(SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL), // OFF
MAKE_SPORK_DEF(SPORK_20_INSTANTSEND_LLMQ_BASED, 4070908800ULL), // OFF
}; };
bool CSporkManager::SporkValueIsActive(int nSporkID, int64_t &nActiveValueRet) const CSporkManager sporkManager;
CSporkManager::CSporkManager()
{
for (auto& sporkDef : sporkDefs) {
sporkDefsById.emplace(sporkDef.sporkId, &sporkDef);
sporkDefsByName.emplace(sporkDef.name, &sporkDef);
}
}
bool CSporkManager::SporkValueIsActive(SporkId nSporkID, int64_t &nActiveValueRet) const
{ {
LOCK(cs); LOCK(cs);
@ -192,7 +201,7 @@ void CSporkManager::ProcessSpork(CNode* pfrom, const std::string& strCommand, CD
} }
void CSporkManager::ExecuteSpork(int nSporkID, int nValue) void CSporkManager::ExecuteSpork(SporkId nSporkID, int nValue)
{ {
//correct fork via spork technology //correct fork via spork technology
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS && nValue > 0) { if(nSporkID == SPORK_12_RECONSIDER_BLOCKS && nValue > 0) {
@ -221,7 +230,7 @@ void CSporkManager::ExecuteSpork(int nSporkID, int nValue)
} }
} }
bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue, CConnman& connman) bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman& connman)
{ {
CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetAdjustedTime()); CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetAdjustedTime());
@ -244,24 +253,13 @@ bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue, CConnman& connman)
return false; return false;
} }
bool CSporkManager::IsSporkActive(int nSporkID) bool CSporkManager::IsSporkActive(SporkId nSporkID)
{ {
LOCK(cs); int64_t nSporkValue = GetSporkValue(nSporkID);
int64_t nSporkValue = -1; return nSporkValue < GetAdjustedTime();
if (SporkValueIsActive(nSporkID, nSporkValue)) {
return nSporkValue < GetAdjustedTime();
}
if (mapSporkDefaults.count(nSporkID)) {
return mapSporkDefaults[nSporkID] < GetAdjustedTime();
}
LogPrint(BCLog::SPORK, "CSporkManager::IsSporkActive -- Unknown Spork ID %d\n", nSporkID);
return false;
} }
int64_t CSporkManager::GetSporkValue(int nSporkID) int64_t CSporkManager::GetSporkValue(SporkId nSporkID)
{ {
LOCK(cs); LOCK(cs);
@ -270,50 +268,33 @@ int64_t CSporkManager::GetSporkValue(int nSporkID)
return nSporkValue; return nSporkValue;
} }
if (mapSporkDefaults.count(nSporkID)) { auto it = sporkDefsById.find(nSporkID);
return mapSporkDefaults[nSporkID]; if (it != sporkDefsById.end()) {
return it->second->defaultValue;
} }
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID); LogPrint(BCLog::SPORK, "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
return -1; return -1;
} }
int CSporkManager::GetSporkIDByName(const std::string& strName) SporkId CSporkManager::GetSporkIDByName(const std::string& strName)
{ {
if (strName == "SPORK_2_INSTANTSEND_ENABLED") return SPORK_2_INSTANTSEND_ENABLED; auto it = sporkDefsByName.find(strName);
if (strName == "SPORK_3_INSTANTSEND_BLOCK_FILTERING") return SPORK_3_INSTANTSEND_BLOCK_FILTERING; if (it == sporkDefsByName.end()) {
if (strName == "SPORK_5_INSTANTSEND_MAX_VALUE") return SPORK_5_INSTANTSEND_MAX_VALUE; LogPrint(BCLog::SPORK, "CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
if (strName == "SPORK_6_NEW_SIGS") return SPORK_6_NEW_SIGS; return SPORK_INVALID;
if (strName == "SPORK_9_SUPERBLOCKS_ENABLED") return SPORK_9_SUPERBLOCKS_ENABLED; }
if (strName == "SPORK_12_RECONSIDER_BLOCKS") return SPORK_12_RECONSIDER_BLOCKS; return it->second->sporkId;
if (strName == "SPORK_15_DETERMINISTIC_MNS_ENABLED") return SPORK_15_DETERMINISTIC_MNS_ENABLED;
if (strName == "SPORK_16_INSTANTSEND_AUTOLOCKS") return SPORK_16_INSTANTSEND_AUTOLOCKS;
if (strName == "SPORK_17_QUORUM_DKG_ENABLED") return SPORK_17_QUORUM_DKG_ENABLED;
if (strName == "SPORK_19_CHAINLOCKS_ENABLED") return SPORK_19_CHAINLOCKS_ENABLED;
if (strName == "SPORK_20_INSTANTSEND_LLMQ_BASED") return SPORK_20_INSTANTSEND_LLMQ_BASED;
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
return -1;
} }
std::string CSporkManager::GetSporkNameByID(int nSporkID) std::string CSporkManager::GetSporkNameByID(SporkId nSporkID)
{ {
switch (nSporkID) { auto it = sporkDefsById.find(nSporkID);
case SPORK_2_INSTANTSEND_ENABLED: return "SPORK_2_INSTANTSEND_ENABLED"; if (it == sporkDefsById.end()) {
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: return "SPORK_3_INSTANTSEND_BLOCK_FILTERING"; LogPrint(BCLog::SPORK, "CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
case SPORK_5_INSTANTSEND_MAX_VALUE: return "SPORK_5_INSTANTSEND_MAX_VALUE"; return "Unknown";
case SPORK_6_NEW_SIGS: return "SPORK_6_NEW_SIGS";
case SPORK_9_SUPERBLOCKS_ENABLED: return "SPORK_9_SUPERBLOCKS_ENABLED";
case SPORK_12_RECONSIDER_BLOCKS: return "SPORK_12_RECONSIDER_BLOCKS";
case SPORK_15_DETERMINISTIC_MNS_ENABLED: return "SPORK_15_DETERMINISTIC_MNS_ENABLED";
case SPORK_16_INSTANTSEND_AUTOLOCKS: return "SPORK_16_INSTANTSEND_AUTOLOCKS";
case SPORK_17_QUORUM_DKG_ENABLED: return "SPORK_17_QUORUM_DKG_ENABLED";
case SPORK_19_CHAINLOCKS_ENABLED: return "SPORK_19_CHAINLOCKS_ENABLED";
case SPORK_20_INSTANTSEND_LLMQ_BASED: return "SPORK_20_INSTANTSEND_LLMQ_BASED";
default:
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
return "Unknown";
} }
return it->second->name;
} }
bool CSporkManager::GetSporkByHash(const uint256& hash, CSporkMessage &sporkRet) bool CSporkManager::GetSporkByHash(const uint256& hash, CSporkMessage &sporkRet)

View File

@ -20,22 +20,31 @@ class CSporkManager;
Don't ever reuse these IDs for other sporks Don't ever reuse these IDs for other sporks
- This would result in old clients getting confused about which spork is for what - This would result in old clients getting confused about which spork is for what
*/ */
static const int SPORK_2_INSTANTSEND_ENABLED = 10001; enum SporkId : int32_t {
static const int SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002; SPORK_2_INSTANTSEND_ENABLED = 10001,
static const int SPORK_5_INSTANTSEND_MAX_VALUE = 10004; SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002,
static const int SPORK_6_NEW_SIGS = 10005; SPORK_5_INSTANTSEND_MAX_VALUE = 10004,
static const int SPORK_9_SUPERBLOCKS_ENABLED = 10008; SPORK_6_NEW_SIGS = 10005,
static const int SPORK_12_RECONSIDER_BLOCKS = 10011; SPORK_9_SUPERBLOCKS_ENABLED = 10008,
static const int SPORK_15_DETERMINISTIC_MNS_ENABLED = 10014; SPORK_12_RECONSIDER_BLOCKS = 10011,
static const int SPORK_16_INSTANTSEND_AUTOLOCKS = 10015; SPORK_15_DETERMINISTIC_MNS_ENABLED = 10014,
static const int SPORK_17_QUORUM_DKG_ENABLED = 10016; SPORK_16_INSTANTSEND_AUTOLOCKS = 10015,
static const int SPORK_19_CHAINLOCKS_ENABLED = 10018; SPORK_17_QUORUM_DKG_ENABLED = 10016,
static const int SPORK_20_INSTANTSEND_LLMQ_BASED = 10019; SPORK_19_CHAINLOCKS_ENABLED = 10018,
SPORK_20_INSTANTSEND_LLMQ_BASED = 10019,
static const int SPORK_START = SPORK_2_INSTANTSEND_ENABLED; SPORK_INVALID = -1,
static const int SPORK_END = SPORK_20_INSTANTSEND_LLMQ_BASED; };
template<> struct is_serializable_enum<SporkId> : std::true_type {};
extern std::map<int, int64_t> mapSporkDefaults; struct CSporkDef
{
SporkId sporkId{SPORK_INVALID};
int64_t defaultValue{0};
std::string name;
};
extern std::vector<CSporkDef> sporkDefs;
extern CSporkManager sporkManager; extern CSporkManager sporkManager;
/** /**
@ -62,18 +71,18 @@ private:
std::vector<unsigned char> vchSig; std::vector<unsigned char> vchSig;
public: public:
int nSporkID; SporkId nSporkID;
int64_t nValue; int64_t nValue;
int64_t nTimeSigned; int64_t nTimeSigned;
CSporkMessage(int nSporkID, int64_t nValue, int64_t nTimeSigned) : CSporkMessage(SporkId nSporkID, int64_t nValue, int64_t nTimeSigned) :
nSporkID(nSporkID), nSporkID(nSporkID),
nValue(nValue), nValue(nValue),
nTimeSigned(nTimeSigned) nTimeSigned(nTimeSigned)
{} {}
CSporkMessage() : CSporkMessage() :
nSporkID(0), nSporkID((SporkId)0),
nValue(0), nValue(0),
nTimeSigned(0) nTimeSigned(0)
{} {}
@ -137,9 +146,12 @@ class CSporkManager
private: private:
static const std::string SERIALIZATION_VERSION_STRING; static const std::string SERIALIZATION_VERSION_STRING;
std::unordered_map<SporkId, CSporkDef*> sporkDefsById;
std::unordered_map<std::string, CSporkDef*> sporkDefsByName;
mutable CCriticalSection cs; mutable CCriticalSection cs;
std::unordered_map<uint256, CSporkMessage> mapSporksByHash; std::unordered_map<uint256, CSporkMessage> mapSporksByHash;
std::unordered_map<int, std::map<CKeyID, CSporkMessage> > mapSporksActive; std::unordered_map<SporkId, std::map<CKeyID, CSporkMessage> > mapSporksActive;
std::set<CKeyID> setSporkPubKeyIDs; std::set<CKeyID> setSporkPubKeyIDs;
int nMinSporkKeys; int nMinSporkKeys;
@ -149,11 +161,11 @@ private:
* SporkValueIsActive is used to get the value agreed upon by the majority * SporkValueIsActive is used to get the value agreed upon by the majority
* of signed spork messages for a given Spork ID. * of signed spork messages for a given Spork ID.
*/ */
bool SporkValueIsActive(int nSporkID, int64_t& nActiveValueRet) const; bool SporkValueIsActive(SporkId nSporkID, int64_t& nActiveValueRet) const;
public: public:
CSporkManager() {} CSporkManager();
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@ -209,13 +221,13 @@ public:
* *
* Currently only used with Spork 12. * Currently only used with Spork 12.
*/ */
void ExecuteSpork(int nSporkID, int nValue); void ExecuteSpork(SporkId nSporkID, int nValue);
/** /**
* UpdateSpork is used by the spork RPC command to set a new spork value, sign * UpdateSpork is used by the spork RPC command to set a new spork value, sign
* and broadcast the spork message. * and broadcast the spork message.
*/ */
bool UpdateSpork(int nSporkID, int64_t nValue, CConnman& connman); bool UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman& connman);
/** /**
* IsSporkActive returns a bool for time-based sporks, and should be used * IsSporkActive returns a bool for time-based sporks, and should be used
@ -226,23 +238,23 @@ public:
* instead, and therefore this method doesn't make sense and should not be * instead, and therefore this method doesn't make sense and should not be
* used. * used.
*/ */
bool IsSporkActive(int nSporkID); bool IsSporkActive(SporkId nSporkID);
/** /**
* GetSporkValue returns the spork value given a Spork ID. If no active spork * GetSporkValue returns the spork value given a Spork ID. If no active spork
* message has yet been received by the node, it returns the default value. * message has yet been received by the node, it returns the default value.
*/ */
int64_t GetSporkValue(int nSporkID); int64_t GetSporkValue(SporkId nSporkID);
/** /**
* GetSporkIDByName returns the internal Spork ID given the spork name. * GetSporkIDByName returns the internal Spork ID given the spork name.
*/ */
int GetSporkIDByName(const std::string& strName); SporkId GetSporkIDByName(const std::string& strName);
/** /**
* GetSporkNameByID returns the spork name as a string, given a Spork ID. * GetSporkNameByID returns the spork name as a string, given a Spork ID.
*/ */
std::string GetSporkNameByID(int nSporkID); std::string GetSporkNameByID(SporkId nSporkID);
/** /**
* GetSporkByHash returns a spork message given a hash of the spork message. * GetSporkByHash returns a spork message given a hash of the spork message.