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:
parent
0480626410
commit
451f7f0710
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user