Skip to content

Commit

Permalink
Replace watchdogs with ping (#1491)
Browse files Browse the repository at this point in the history
* Add hassentinelping to governanceinfo

* sentinelping rpc call

* additional fields in mnp

* sentinel ping implementation

* change sentinel state to byte in mnp

* use adjusted time in sentinel ping

* update nTimeLastWatchdogVote if sentinel ping is actual

* remove unused fields

* bump protocol to 70207

* Fix small issues

 - fix the error message text in CActivbeMasternodeUpdateSentinelPing;
 - add empty string before public: in CActiveMasternode class declaration;
 - rename field sentinelPing in CMasternodePing to sentinelIsActual and change $
 - decrease sentinelVersion field size to uint16_t;

* revert proto bump for MIN_... consts

* revert changes in getgovernanceinfo

* Update mn vote time for remote masternodes

 - call UpdateWatchdogVoteTime in CMasternodeMan::ProcessMessage
 - deserialize masternodeping from the previous version archive without exception
 - add ability to set time in UpdateWatchdogVoteTime
 - set nTimeLastWatchdogVote to masternode ping sigTime if sentinel is actual
 - bump CMasternodeMan::SERIALIZATION_VERSION_STRING

* remove mn state checks and add correct rpc param convertion

* fix var names

* Helper class for version in string and integer form

* String version in sentinel ping

Version format is "x.x.x"

* test for bacward compatibility in serialization

* Change VersionInfo class to convert functions
  • Loading branch information
gladcow authored and UdjinM6 committed Jul 4, 2017
1 parent f65017c commit a439e98
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/activemasternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ bool CActiveMasternode::SendMasternodePing()
}

CMasternodePing mnp(vin);
mnp.nSentinelVersion = nSentinelVersion;
mnp.fSentinelIsCurrent =
(abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_WATCHDOG_MAX_SECONDS);
if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
LogPrintf("CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
return false;
Expand All @@ -127,6 +130,14 @@ bool CActiveMasternode::SendMasternodePing()
return true;
}

bool CActiveMasternode::UpdateSentinelPing(int version)
{
nSentinelVersion = version;
nSentinelPingTime = GetAdjustedTime();

return true;
}

void CActiveMasternode::ManageStateInitial()
{
LogPrint("masternode", "CActiveMasternode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
Expand Down
7 changes: 7 additions & 0 deletions src/activemasternode.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class CActiveMasternode
/// Ping Masternode
bool SendMasternodePing();

// sentinel ping data
int64_t nSentinelPingTime;
uint32_t nSentinelVersion;

public:
// Keys for the active Masternode
CPubKey pubKeyMasternode;
Expand All @@ -52,6 +56,7 @@ class CActiveMasternode
int nState; // should be one of ACTIVE_MASTERNODE_XXXX
std::string strNotCapableReason;


CActiveMasternode()
: eType(MASTERNODE_UNKNOWN),
fPingerEnabled(false),
Expand All @@ -69,6 +74,8 @@ class CActiveMasternode
std::string GetStatus() const;
std::string GetTypeString() const;

bool UpdateSentinelPing(int version);

private:
void ManageStateInitial();
void ManageStateRemote();
Expand Down
10 changes: 7 additions & 3 deletions src/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,9 @@ void CMasternodeBroadcast::Relay()
RelayInv(inv);
}

CMasternodePing::CMasternodePing(CTxIn& vinNew)
CMasternodePing::CMasternodePing(CTxIn& vinNew) :
fSentinelIsCurrent(false),
nSentinelVersion(0)
{
LOCK(cs_main);
if (!chainActive.Tip() || chainActive.Height() < 12) return;
Expand All @@ -751,6 +753,7 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
std::string strError;
std::string strMasterNodeSignMessage;

// TODO: add sentinel data
sigTime = GetAdjustedTime();
std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);

Expand All @@ -769,6 +772,7 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)

bool CMasternodePing::CheckSignature(CPubKey& pubKeyMasternode, int &nDos)
{
// TODO: add sentinel data
std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
std::string strError = "";
nDos = 0;
Expand Down Expand Up @@ -909,10 +913,10 @@ void CMasternode::RemoveGovernanceObject(uint256 nGovernanceObjectHash)
mapGovernanceObjectsVotedOn.erase(it);
}

void CMasternode::UpdateWatchdogVoteTime()
void CMasternode::UpdateWatchdogVoteTime(uint64_t nVoteTime)
{
LOCK(cs);
nTimeLastWatchdogVote = GetTime();
nTimeLastWatchdogVote = (nVoteTime == 0) ? GetTime() : nVoteTime;
}

/**
Expand Down
15 changes: 13 additions & 2 deletions src/masternode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ static const int MASTERNODE_WATCHDOG_MAX_SECONDS = 120 * 60;
static const int MASTERNODE_NEW_START_REQUIRED_SECONDS = 180 * 60;

static const int MASTERNODE_POSE_BAN_MAX_SCORE = 5;

//
// The Masternode Ping Class : Contains a different serialize method for sending pings from masternodes throughout the network
//
Expand All @@ -34,13 +35,17 @@ class CMasternodePing
uint256 blockHash;
int64_t sigTime; //mnb message times
std::vector<unsigned char> vchSig;
bool fSentinelIsCurrent; // true if last sentinel ping was actual
uint32_t nSentinelVersion; // MSB is always 0, other 3 bits corresponds to x.x.x version scheme
//removed stop

CMasternodePing() :
vin(),
blockHash(),
sigTime(0),
vchSig()
vchSig(),
fSentinelIsCurrent(false),
nSentinelVersion(0)
{}

CMasternodePing(CTxIn& vinNew);
Expand All @@ -53,6 +58,10 @@ class CMasternodePing
READWRITE(blockHash);
READWRITE(sigTime);
READWRITE(vchSig);
if(ser_action.ForRead() && (s.size() == 0))
return;
READWRITE(fSentinelIsCurrent);
READWRITE(nSentinelVersion);
}

void swap(CMasternodePing& first, CMasternodePing& second) // nothrow
Expand All @@ -66,6 +75,8 @@ class CMasternodePing
swap(first.blockHash, second.blockHash);
swap(first.sigTime, second.sigTime);
swap(first.vchSig, second.vchSig);
swap(first.fSentinelIsCurrent, second.fSentinelIsCurrent);
swap(first.nSentinelVersion, second.nSentinelVersion);
}

uint256 GetHash() const
Expand Down Expand Up @@ -318,7 +329,7 @@ class CMasternode

void RemoveGovernanceObject(uint256 nGovernanceObjectHash);

void UpdateWatchdogVoteTime();
void UpdateWatchdogVoteTime(uint64_t nVoteTime = 0);

CMasternode& operator=(CMasternode from)
{
Expand Down
13 changes: 12 additions & 1 deletion src/masternodeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/** Masternode manager */
CMasternodeMan mnodeman;

const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-4";
const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-5";

struct CompareLastPaidBlock
{
Expand Down Expand Up @@ -849,6 +849,12 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
// see if we have this Masternode
CMasternode* pmn = mnodeman.Find(mnp.vin);

// if masternode uses sentinel ping instead of watchdog
// we shoud update nTimeLastWatchdogVote here if sentinel
// ping flag is actual
if(pmn && mnp.fSentinelIsCurrent)
pmn->UpdateWatchdogVoteTime(mnp.sigTime);

// too late, new MNANNOUNCE is required
if(pmn && pmn->IsNewStartRequired()) return;

Expand Down Expand Up @@ -1642,6 +1648,11 @@ void CMasternodeMan::SetMasternodeLastPing(const CTxIn& vin, const CMasternodePi
return;
}
pMN->lastPing = mnp;
// if masternode uses sentinel ping instead of watchdog
// we shoud update nTimeLastWatchdogVote here if sentinel
// ping flag is actual
if(mnp.fSentinelIsCurrent)
pMN->UpdateWatchdogVoteTime(mnp.sigTime);
mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp));

CMasternodeBroadcast mnb(*pMN);
Expand Down
1 change: 1 addition & 0 deletions src/rpc/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -972,3 +972,4 @@ UniValue getsuperblockbudget(const UniValue& params, bool fHelp)

return strBudget;
}

20 changes: 20 additions & 0 deletions src/rpc/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,3 +795,23 @@ UniValue masternodebroadcast(const UniValue& params, bool fHelp)

return NullUniValue;
}

UniValue sentinelping(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1) {
throw std::runtime_error(
"sentinelping version\n"
"\nSentinel ping.\n"
"\nArguments:\n"
"1. version (string, required) Sentinel version in the form \"x.x.x\"\n"
"\nResult:\n"
"state (boolean) Ping result\n"
"\nExamples:\n"
+ HelpExampleCli("sentinelping", "1.0.2")
+ HelpExampleRpc("sentinelping", "1.0.2")
);
}

activeMasternode.UpdateSentinelPing(StringVersionToInt(params[0].get_str()));
return true;
}
1 change: 1 addition & 0 deletions src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ static const CRPCCommand vRPCCommands[] =
{ "dash", "mnsync", &mnsync, true },
{ "dash", "spork", &spork, true },
{ "dash", "getpoolinfo", &getpoolinfo, true },
{ "dash", "sentinelping", &sentinelping, true },
#ifdef ENABLE_WALLET
{ "dash", "privatesend", &privatesend, false },

Expand Down
1 change: 1 addition & 0 deletions src/rpc/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ extern UniValue getchaintips(const UniValue& params, bool fHelp);
extern UniValue invalidateblock(const UniValue& params, bool fHelp);
extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
extern UniValue getspentinfo(const UniValue& params, bool fHelp);
extern UniValue sentinelping(const UniValue& params, bool fHelp);

bool StartRPC();
void InterruptRPC();
Expand Down
7 changes: 7 additions & 0 deletions src/test/rpc_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,4 +307,11 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128");
}

BOOST_AUTO_TEST_CASE(rpc_sentinel_ping)
{
BOOST_CHECK_NO_THROW(CallRPC("sentinelping 1.0.2"));
BOOST_CHECK_THROW(CallRPC("sentinelping"), runtime_error);
BOOST_CHECK_THROW(CallRPC("sentinelping 2"), bad_cast);
}

BOOST_AUTO_TEST_SUITE_END()
49 changes: 49 additions & 0 deletions src/test/serialize_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,53 @@ BOOST_AUTO_TEST_CASE(insert_delete)
BOOST_CHECK_EQUAL(ss.size(), 0);
}

// Change struct size and check if it can be deserialized
// from old version archive and vice versa
struct old_version
{
int field1;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(field1);
}
};\
struct new_version
{
int field1;
int field2;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(field1);
if(ser_action.ForRead() && (s.size() == 0))
{
field2 = 0;
return;
}
READWRITE(field2);
}
};

BOOST_AUTO_TEST_CASE(check_backward_compatibility)
{
CDataStream ss(SER_DISK, 0);
old_version old_src({5});
ss << old_src;
new_version new_dest({6, 7});
BOOST_REQUIRE_NO_THROW(ss >> new_dest);
BOOST_REQUIRE(old_src.field1 == new_dest.field1);
BOOST_REQUIRE(ss.size() == 0);

new_version new_src({6, 7});
ss << new_src;
old_version old_dest({5});
BOOST_REQUIRE_NO_THROW(ss >> old_dest);
BOOST_REQUIRE(new_src.field1 == old_dest.field1);
}

BOOST_AUTO_TEST_SUITE_END()
15 changes: 15 additions & 0 deletions src/test/util_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,4 +489,19 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
}

BOOST_AUTO_TEST_CASE(version_info_helper)
{
BOOST_CHECK(StringVersionToInt("1.1.1") == 0x010101);
BOOST_CHECK(IntVersionToString(0x010101) == "1.1.1");

BOOST_CHECK_THROW(StringVersionToInt("1.1.hgdghfgf"), bad_cast);
BOOST_CHECK_THROW(StringVersionToInt("1.1"), bad_cast);
BOOST_CHECK_THROW(StringVersionToInt("1.1.1f"), bad_cast);
BOOST_CHECK_THROW(StringVersionToInt("1.1.1000"), bad_cast);
BOOST_CHECK_THROW(StringVersionToInt("10"), bad_cast);
BOOST_CHECK_THROW(StringVersionToInt("1.1.1.1"), bad_cast);
BOOST_CHECK_THROW(IntVersionToString(0x01010101), bad_cast);
BOOST_CHECK_THROW(IntVersionToString(0), bad_cast);
}

BOOST_AUTO_TEST_SUITE_END()
38 changes: 38 additions & 0 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
Expand Down Expand Up @@ -952,3 +954,39 @@ int GetNumCores()
#endif
}


uint32_t StringVersionToInt(const std::string& strVersion)
{
std::vector<std::string> tokens;
boost::split(tokens, strVersion, boost::is_any_of("."));
if(tokens.size() != 3)
throw std::bad_cast();
uint32_t nVersion = 0;
for(unsigned idx = 0; idx < 3; idx++)
{
if(tokens[idx].length() == 0)
throw std::bad_cast();
uint32_t value = boost::lexical_cast<uint32_t>(tokens[idx]);
if(value > 255)
throw std::bad_cast();
nVersion <<= 8;
nVersion |= value;
}
return nVersion;
}

std::string IntVersionToString(uint32_t nVersion)
{
if((nVersion >> 24) > 0) // MSB is always 0
throw std::bad_cast();
if(nVersion == 0)
throw std::bad_cast();
std::array<std::string, 3> tokens;
for(unsigned idx = 0; idx < 3; idx++)
{
unsigned shift = (2 - idx) * 8;
uint32_t byteValue = (nVersion >> shift) & 0xff;
tokens[idx] = boost::lexical_cast<std::string>(byteValue);
}
return boost::join(tokens, ".");
}
19 changes: 19 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,23 @@ template <typename Callable> void TraceThread(const char* name, Callable func)
}
}


/**
* @brief Converts version strings to 4-byte unsigned integer
* @param strVersion version in "x.x.x" format (decimal digits only)
* @return 4-byte unsigned integer, most significant byte is always 0
* Throws std::bad_cast if format doesn\t match.
*/
uint32_t StringVersionToInt(const std::string& strVersion);


/**
* @brief Converts version as 4-byte unsigned integer to string
* @param nVersion 4-byte unsigned integer, most significant byte is always 0
* @return version string in "x.x.x" format (last 3 bytes as version parts)
* Throws std::bad_cast if format doesn\t match.
*/
std::string IntVersionToString(uint32_t nVersion);


#endif // BITCOIN_UTIL_H
2 changes: 1 addition & 1 deletion src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* network protocol versioning
*/

static const int PROTOCOL_VERSION = 70206;
static const int PROTOCOL_VERSION = 70207;

//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
Expand Down

0 comments on commit a439e98

Please sign in to comment.