Fix issues with mnp, mnw and dsq signatures via new spork (SPORK_6_NEW_SIGS) (#1936)

* Use new spork SPORK_6_NEW_SIGS to fix masternode payment vote signature format

* Use SPORK_6_NEW_SIGS to also fix masternode ping signature format

* Use SPORK_6_NEW_SIGS to also fix privatesend queue signature format

* adjust spork6 description in docs

* mnp hashing/signing changed - hash everything and use SignHash/VerifyHash directly instead of constructing a string to sign (both activate via SPORK_6_NEW_SIGS)

* fix

* cleanup
This commit is contained in:
UdjinM6 2018-02-15 17:44:22 +03:00 committed by GitHub
parent 0480626410
commit 451f7f0710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 132 additions and 30 deletions

View File

@ -254,6 +254,7 @@ Spork
| 10001 | 2 | INSTANTSEND_ENABLED | Turns on and off InstantSend network wide
| 10002 | 3 | INSTANTSEND_BLOCK_FILTERING | Turns on and off InstantSend block filtering
| 10004 | 5 | INSTANTSEND_MAX_VALUE | Controls the max value for an InstantSend transaction (currently 2000 dash)
| 10005 | 6 | NEW_SIGS | Turns on and off new signature format for some messages (mnp, mnw, dsq)
| 10007 | 8 | MASTERNODE_PAYMENT_ENFORCEMENT | Requires masternodes to be paid by miners when blocks are processed
| 10008 | 9 | SUPERBLOCKS_ENABLED | Superblocks are enabled (the 10% comes to fund the dash treasury)
| 10009 | 10 | MASTERNODE_PAY_UPDATED_NODES | Only current protocol version masternode's will be paid (not older nodes)

View File

@ -401,7 +401,7 @@ bool CMasternodePaymentVote::Sign()
std::string strError;
std::string strMessage = masternodeOutpoint.ToStringShort() +
boost::lexical_cast<std::string>(nBlockHeight) +
ScriptToAsmStr(payee);
(sporkManager.IsSporkActive(SPORK_6_NEW_SIGS) ? HexStr(payee) : ScriptToAsmStr(payee));
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternode.keyMasternode)) {
LogPrintf("CMasternodePaymentVote::Sign -- SignMessage() failed\n");
@ -838,10 +838,34 @@ bool CMasternodePaymentVote::CheckSignature(const CPubKey& pubKeyMasternode, int
std::string strMessage = masternodeOutpoint.ToStringShort() +
boost::lexical_cast<std::string>(nBlockHeight) +
ScriptToAsmStr(payee);
(sporkManager.IsSporkActive(SPORK_6_NEW_SIGS) ? HexStr(payee) : ScriptToAsmStr(payee));
std::string strError = "";
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
// Try old format even though we activated signing via new one already.
// Could be an old vote signed earlier or a vote signed by a non-upgraded MN.
std::string strErrorOld = "";
strMessage = masternodeOutpoint.ToStringShort() +
boost::lexical_cast<std::string>(nBlockHeight) +
ScriptToAsmStr(payee);
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strErrorOld)) {
// Neither format worked, definitely an invalid signature.
// Only ban for future block vote when we are already synced.
// Otherwise it could be the case when MN which signed this vote is using another key now
// and we have no idea about the old one.
if(masternodeSync.IsMasternodeListSynced() && nBlockHeight > nValidationHeight) {
nDos = 20;
}
return error("CMasternodePaymentVote::CheckSignature -- Got bad Masternode payment signature, masternode=%s, error: %s",
masternodeOutpoint.ToStringShort(), strErrorOld);
}
// Was indeed a valid signature in old format
LogPrintf("Masternode %s send payment vote in old format, new format \n", masternodeOutpoint.ToStringShort());
return true;
}
// Spork is off but message signature is invalid.
// Only ban for future block vote when we are already synced.
// Otherwise it could be the case when MN which signed this vote is using another key now
// and we have no idea about the old one.

View File

@ -4,6 +4,7 @@
#include "activemasternode.h"
#include "base58.h"
#include "clientversion.h"
#include "init.h"
#include "netbase.h"
#include "masternode.h"
@ -635,6 +636,23 @@ void CMasternodeBroadcast::Relay(CConnman& connman) const
connman.RelayInv(inv);
}
uint256 CMasternodePing::GetHash() const
{
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
ss << masternodeOutpoint;
ss << blockHash;
ss << sigTime;
ss << fSentinelIsCurrent;
ss << nSentinelVersion;
ss << nDaemonVersion;
} else {
ss << masternodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format
ss << sigTime;
}
return ss.GetHash();
}
CMasternodePing::CMasternodePing(const COutPoint& outpoint)
{
LOCK(cs_main);
@ -643,25 +661,40 @@ CMasternodePing::CMasternodePing(const COutPoint& outpoint)
masternodeOutpoint = outpoint;
blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash();
sigTime = GetAdjustedTime();
nDaemonVersion = CLIENT_VERSION;
}
bool CMasternodePing::Sign(const CKey& keyMasternode, const CPubKey& pubKeyMasternode)
{
std::string strError;
std::string strMasterNodeSignMessage;
// TODO: add sentinel data
sigTime = GetAdjustedTime();
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
if(!CMessageSigner::SignMessage(strMessage, vchSig, keyMasternode)) {
LogPrintf("CMasternodePing::Sign -- SignMessage() failed\n");
return false;
}
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetHash();
if(!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
LogPrintf("CMasternodePing::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
if (!CHashSigner::SignHash(hash, keyMasternode, vchSig)) {
LogPrintf("CMasternodePing::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, pubKeyMasternode, vchSig, strError)) {
LogPrintf("CMasternodePing::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() +
boost::lexical_cast<std::string>(sigTime);
if (!CMessageSigner::SignMessage(strMessage, vchSig, keyMasternode)) {
LogPrintf("CMasternodePing::Sign -- SignMessage() failed\n");
return false;
}
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
LogPrintf("CMasternodePing::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
}
return true;
@ -669,16 +702,28 @@ bool CMasternodePing::Sign(const CKey& keyMasternode, const CPubKey& pubKeyMaste
bool CMasternodePing::CheckSignature(const CPubKey& pubKeyMasternode, int &nDos)
{
// TODO: add sentinel data
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
std::string strError = "";
nDos = 0;
if(!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError);
nDos = 33;
return false;
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetHash();
if (!CHashSigner::VerifyHash(hash, pubKeyMasternode, vchSig, strError)) {
LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError);
nDos = 33;
return false;
}
} else {
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() +
boost::lexical_cast<std::string>(sigTime);
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError);
nDos = 33;
return false;
}
}
return true;
}

View File

@ -26,8 +26,10 @@ 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
//
// sentinel version before sentinel ping implementation
// sentinel version before implementation of nSentinelVersion in CMasternodePing
#define DEFAULT_SENTINEL_VERSION 0x010001
// daemon version before implementation of nDaemonVersion in CMasternodePing
#define DEFAULT_DAEMON_VERSION 120200
class CMasternodePing
{
@ -39,6 +41,7 @@ public:
bool fSentinelIsCurrent = false; // true if last sentinel ping was actual
// MSB is always 0, other 3 bits corresponds to x.x.x version scheme
uint32_t nSentinelVersion{DEFAULT_SENTINEL_VERSION};
uint32_t nDaemonVersion{DEFAULT_DAEMON_VERSION};
CMasternodePing() = default;
@ -66,23 +69,24 @@ public:
READWRITE(blockHash);
READWRITE(sigTime);
READWRITE(vchSig);
if(ser_action.ForRead() && (s.size() == 0))
{
if(ser_action.ForRead() && s.size() == 0) {
fSentinelIsCurrent = false;
nSentinelVersion = DEFAULT_SENTINEL_VERSION;
nDaemonVersion = DEFAULT_DAEMON_VERSION;
return;
}
READWRITE(fSentinelIsCurrent);
READWRITE(nSentinelVersion);
if(ser_action.ForRead() && s.size() == 0) {
nDaemonVersion = DEFAULT_DAEMON_VERSION;
return;
}
if (nVersion > 70208) {
READWRITE(nDaemonVersion);
}
}
uint256 GetHash() const
{
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << masternodeOutpoint << uint8_t{} << 0xffffffff;
ss << sigTime;
return ss.GetHash();
}
uint256 GetHash() const;
bool IsExpired() const { return GetAdjustedTime() - sigTime > MASTERNODE_NEW_START_REQUIRED_SECONDS; }

View File

@ -40,7 +40,18 @@ bool CDarksendQueue::Sign()
{
if(!fMasternodeMode) return false;
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(nTime) + boost::lexical_cast<std::string>(fReady);
std::string strMessage;
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
strMessage = masternodeOutpoint.ToStringShort() +
boost::lexical_cast<std::string>(nDenom) +
boost::lexical_cast<std::string>(nTime) +
boost::lexical_cast<std::string>(fReady);
} else {
strMessage = CTxIn(masternodeOutpoint).ToString() +
boost::lexical_cast<std::string>(nDenom) +
boost::lexical_cast<std::string>(nTime) +
boost::lexical_cast<std::string>(fReady);
}
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternode.keyMasternode)) {
LogPrintf("CDarksendQueue::Sign -- SignMessage() failed, %s\n", ToString());
@ -52,8 +63,19 @@ bool CDarksendQueue::Sign()
bool CDarksendQueue::CheckSignature(const CPubKey& pubKeyMasternode)
{
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(nTime) + boost::lexical_cast<std::string>(fReady);
std::string strError = "";
std::string strMessage;
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
strMessage = masternodeOutpoint.ToStringShort() +
boost::lexical_cast<std::string>(nDenom) +
boost::lexical_cast<std::string>(nTime) +
boost::lexical_cast<std::string>(fReady);
} else {
strMessage = CTxIn(masternodeOutpoint).ToString() +
boost::lexical_cast<std::string>(nDenom) +
boost::lexical_cast<std::string>(nTime) +
boost::lexical_cast<std::string>(fReady);
}
if(!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
LogPrintf("CDarksendQueue::CheckSignature -- Got bad Masternode queue signature: %s; error: %s\n", ToString(), strError);

View File

@ -129,6 +129,7 @@ bool CSporkManager::IsSporkActive(int nSporkID)
case SPORK_2_INSTANTSEND_ENABLED: r = SPORK_2_INSTANTSEND_ENABLED_DEFAULT; break;
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: r = SPORK_3_INSTANTSEND_BLOCK_FILTERING_DEFAULT; break;
case SPORK_5_INSTANTSEND_MAX_VALUE: r = SPORK_5_INSTANTSEND_MAX_VALUE_DEFAULT; break;
case SPORK_6_NEW_SIGS: r = SPORK_6_NEW_SIGS_DEFAULT; break;
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT; break;
case SPORK_9_SUPERBLOCKS_ENABLED: r = SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT; break;
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT; break;
@ -154,6 +155,7 @@ int64_t CSporkManager::GetSporkValue(int nSporkID)
case SPORK_2_INSTANTSEND_ENABLED: return SPORK_2_INSTANTSEND_ENABLED_DEFAULT;
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: return SPORK_3_INSTANTSEND_BLOCK_FILTERING_DEFAULT;
case SPORK_5_INSTANTSEND_MAX_VALUE: return SPORK_5_INSTANTSEND_MAX_VALUE_DEFAULT;
case SPORK_6_NEW_SIGS: return SPORK_6_NEW_SIGS_DEFAULT;
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
case SPORK_9_SUPERBLOCKS_ENABLED: return SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT;
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: return SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
@ -171,6 +173,7 @@ int 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_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT;
if (strName == "SPORK_9_SUPERBLOCKS_ENABLED") return SPORK_9_SUPERBLOCKS_ENABLED;
if (strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES;
@ -187,6 +190,7 @@ std::string CSporkManager::GetSporkNameByID(int 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_8_MASTERNODE_PAYMENT_ENFORCEMENT: return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT";
case SPORK_9_SUPERBLOCKS_ENABLED: return "SPORK_9_SUPERBLOCKS_ENABLED";
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES";

View File

@ -22,6 +22,7 @@ static const int SPORK_END = 10013;
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_8_MASTERNODE_PAYMENT_ENFORCEMENT = 10007;
static const int SPORK_9_SUPERBLOCKS_ENABLED = 10008;
static const int SPORK_10_MASTERNODE_PAY_UPDATED_NODES = 10009;
@ -31,6 +32,7 @@ static const int SPORK_14_REQUIRE_SENTINEL_FLAG = 10013;
static const int64_t SPORK_2_INSTANTSEND_ENABLED_DEFAULT = 0; // ON
static const int64_t SPORK_3_INSTANTSEND_BLOCK_FILTERING_DEFAULT = 0; // ON
static const int64_t SPORK_5_INSTANTSEND_MAX_VALUE_DEFAULT = 1000; // 1000 DASH
static const int64_t SPORK_6_NEW_SIGS_DEFAULT = 4070908800ULL;// OFF
static const int64_t SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT = 4070908800ULL;// OFF
static const int64_t SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT = 4070908800ULL;// OFF
static const int64_t SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT = 4070908800ULL;// OFF