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

View File

@ -13,25 +13,34 @@
#include <string>
CSporkManager sporkManager;
const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-Version-2";
std::map<int, int64_t> mapSporkDefaults = {
{SPORK_2_INSTANTSEND_ENABLED, 0}, // ON
{SPORK_3_INSTANTSEND_BLOCK_FILTERING, 0}, // ON
{SPORK_5_INSTANTSEND_MAX_VALUE, 1000}, // 1000 Dash
{SPORK_6_NEW_SIGS, 4070908800ULL}, // OFF
{SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL}, // OFF
{SPORK_12_RECONSIDER_BLOCKS, 0}, // 0 BLOCKS
{SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL}, // OFF
{SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL}, // OFF
{SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL}, // OFF
{SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL}, // OFF
{SPORK_20_INSTANTSEND_LLMQ_BASED, 4070908800ULL}, // OFF
#define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name}
std::vector<CSporkDef> sporkDefs = {
MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 0), // ON
MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 0), // ON
MAKE_SPORK_DEF(SPORK_5_INSTANTSEND_MAX_VALUE, 1000), // 1000 Dash
MAKE_SPORK_DEF(SPORK_6_NEW_SIGS, 4070908800ULL), // OFF
MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF
MAKE_SPORK_DEF(SPORK_12_RECONSIDER_BLOCKS, 0), // 0 BLOCKS
MAKE_SPORK_DEF(SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL), // OFF
MAKE_SPORK_DEF(SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL), // OFF
MAKE_SPORK_DEF(SPORK_17_QUORUM_DKG_ENABLED, 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);
@ -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
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());
@ -244,24 +253,13 @@ bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue, CConnman& connman)
return false;
}
bool CSporkManager::IsSporkActive(int nSporkID)
bool CSporkManager::IsSporkActive(SporkId nSporkID)
{
LOCK(cs);
int64_t nSporkValue = -1;
if (SporkValueIsActive(nSporkID, nSporkValue)) {
int64_t nSporkValue = GetSporkValue(nSporkID);
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);
@ -270,50 +268,33 @@ int64_t CSporkManager::GetSporkValue(int nSporkID)
return nSporkValue;
}
if (mapSporkDefaults.count(nSporkID)) {
return mapSporkDefaults[nSporkID];
auto it = sporkDefsById.find(nSporkID);
if (it != sporkDefsById.end()) {
return it->second->defaultValue;
}
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
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;
if (strName == "SPORK_3_INSTANTSEND_BLOCK_FILTERING") return SPORK_3_INSTANTSEND_BLOCK_FILTERING;
if (strName == "SPORK_5_INSTANTSEND_MAX_VALUE") return SPORK_5_INSTANTSEND_MAX_VALUE;
if (strName == "SPORK_6_NEW_SIGS") return SPORK_6_NEW_SIGS;
if (strName == "SPORK_9_SUPERBLOCKS_ENABLED") return SPORK_9_SUPERBLOCKS_ENABLED;
if (strName == "SPORK_12_RECONSIDER_BLOCKS") return SPORK_12_RECONSIDER_BLOCKS;
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;
auto it = sporkDefsByName.find(strName);
if (it == sporkDefsByName.end()) {
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
return -1;
return SPORK_INVALID;
}
return it->second->sporkId;
}
std::string CSporkManager::GetSporkNameByID(int nSporkID)
std::string CSporkManager::GetSporkNameByID(SporkId nSporkID)
{
switch (nSporkID) {
case SPORK_2_INSTANTSEND_ENABLED: return "SPORK_2_INSTANTSEND_ENABLED";
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: return "SPORK_3_INSTANTSEND_BLOCK_FILTERING";
case SPORK_5_INSTANTSEND_MAX_VALUE: return "SPORK_5_INSTANTSEND_MAX_VALUE";
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:
auto it = sporkDefsById.find(nSporkID);
if (it == sporkDefsById.end()) {
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)

View File

@ -20,22 +20,31 @@ class CSporkManager;
Don't ever reuse these IDs for other sporks
- This would result in old clients getting confused about which spork is for what
*/
static const int SPORK_2_INSTANTSEND_ENABLED = 10001;
static const int SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002;
static const int SPORK_5_INSTANTSEND_MAX_VALUE = 10004;
static const int SPORK_6_NEW_SIGS = 10005;
static const int SPORK_9_SUPERBLOCKS_ENABLED = 10008;
static const int SPORK_12_RECONSIDER_BLOCKS = 10011;
static const int SPORK_15_DETERMINISTIC_MNS_ENABLED = 10014;
static const int SPORK_16_INSTANTSEND_AUTOLOCKS = 10015;
static const int SPORK_17_QUORUM_DKG_ENABLED = 10016;
static const int SPORK_19_CHAINLOCKS_ENABLED = 10018;
static const int SPORK_20_INSTANTSEND_LLMQ_BASED = 10019;
enum SporkId : int32_t {
SPORK_2_INSTANTSEND_ENABLED = 10001,
SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002,
SPORK_5_INSTANTSEND_MAX_VALUE = 10004,
SPORK_6_NEW_SIGS = 10005,
SPORK_9_SUPERBLOCKS_ENABLED = 10008,
SPORK_12_RECONSIDER_BLOCKS = 10011,
SPORK_15_DETERMINISTIC_MNS_ENABLED = 10014,
SPORK_16_INSTANTSEND_AUTOLOCKS = 10015,
SPORK_17_QUORUM_DKG_ENABLED = 10016,
SPORK_19_CHAINLOCKS_ENABLED = 10018,
SPORK_20_INSTANTSEND_LLMQ_BASED = 10019,
static const int SPORK_START = SPORK_2_INSTANTSEND_ENABLED;
static const int SPORK_END = SPORK_20_INSTANTSEND_LLMQ_BASED;
SPORK_INVALID = -1,
};
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;
/**
@ -62,18 +71,18 @@ private:
std::vector<unsigned char> vchSig;
public:
int nSporkID;
SporkId nSporkID;
int64_t nValue;
int64_t nTimeSigned;
CSporkMessage(int nSporkID, int64_t nValue, int64_t nTimeSigned) :
CSporkMessage(SporkId nSporkID, int64_t nValue, int64_t nTimeSigned) :
nSporkID(nSporkID),
nValue(nValue),
nTimeSigned(nTimeSigned)
{}
CSporkMessage() :
nSporkID(0),
nSporkID((SporkId)0),
nValue(0),
nTimeSigned(0)
{}
@ -137,9 +146,12 @@ class CSporkManager
private:
static const std::string SERIALIZATION_VERSION_STRING;
std::unordered_map<SporkId, CSporkDef*> sporkDefsById;
std::unordered_map<std::string, CSporkDef*> sporkDefsByName;
mutable CCriticalSection cs;
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;
int nMinSporkKeys;
@ -149,11 +161,11 @@ private:
* SporkValueIsActive is used to get the value agreed upon by the majority
* 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:
CSporkManager() {}
CSporkManager();
ADD_SERIALIZE_METHODS;
@ -209,13 +221,13 @@ public:
*
* 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
* 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
@ -226,23 +238,23 @@ public:
* instead, and therefore this method doesn't make sense and should not be
* used.
*/
bool IsSporkActive(int nSporkID);
bool IsSporkActive(SporkId nSporkID);
/**
* 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.
*/
int64_t GetSporkValue(int nSporkID);
int64_t GetSporkValue(SporkId nSporkID);
/**
* 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.
*/
std::string GetSporkNameByID(int nSporkID);
std::string GetSporkNameByID(SporkId nSporkID);
/**
* GetSporkByHash returns a spork message given a hash of the spork message.