Skip to content

Commit 451f7f0

Browse files
authored
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
1 parent 0480626 commit 451f7f0

File tree

7 files changed

+132
-30
lines changed

7 files changed

+132
-30
lines changed

dash-docs/protocol-documentation.md

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

src/masternode-payments.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ bool CMasternodePaymentVote::Sign()
401401
std::string strError;
402402
std::string strMessage = masternodeOutpoint.ToStringShort() +
403403
boost::lexical_cast<std::string>(nBlockHeight) +
404-
ScriptToAsmStr(payee);
404+
(sporkManager.IsSporkActive(SPORK_6_NEW_SIGS) ? HexStr(payee) : ScriptToAsmStr(payee));
405405

406406
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternode.keyMasternode)) {
407407
LogPrintf("CMasternodePaymentVote::Sign -- SignMessage() failed\n");
@@ -838,10 +838,34 @@ bool CMasternodePaymentVote::CheckSignature(const CPubKey& pubKeyMasternode, int
838838

839839
std::string strMessage = masternodeOutpoint.ToStringShort() +
840840
boost::lexical_cast<std::string>(nBlockHeight) +
841-
ScriptToAsmStr(payee);
841+
(sporkManager.IsSporkActive(SPORK_6_NEW_SIGS) ? HexStr(payee) : ScriptToAsmStr(payee));
842842

843843
std::string strError = "";
844844
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
845+
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
846+
// Try old format even though we activated signing via new one already.
847+
// Could be an old vote signed earlier or a vote signed by a non-upgraded MN.
848+
std::string strErrorOld = "";
849+
strMessage = masternodeOutpoint.ToStringShort() +
850+
boost::lexical_cast<std::string>(nBlockHeight) +
851+
ScriptToAsmStr(payee);
852+
853+
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strErrorOld)) {
854+
// Neither format worked, definitely an invalid signature.
855+
// Only ban for future block vote when we are already synced.
856+
// Otherwise it could be the case when MN which signed this vote is using another key now
857+
// and we have no idea about the old one.
858+
if(masternodeSync.IsMasternodeListSynced() && nBlockHeight > nValidationHeight) {
859+
nDos = 20;
860+
}
861+
return error("CMasternodePaymentVote::CheckSignature -- Got bad Masternode payment signature, masternode=%s, error: %s",
862+
masternodeOutpoint.ToStringShort(), strErrorOld);
863+
}
864+
// Was indeed a valid signature in old format
865+
LogPrintf("Masternode %s send payment vote in old format, new format \n", masternodeOutpoint.ToStringShort());
866+
return true;
867+
}
868+
// Spork is off but message signature is invalid.
845869
// Only ban for future block vote when we are already synced.
846870
// Otherwise it could be the case when MN which signed this vote is using another key now
847871
// and we have no idea about the old one.

src/masternode.cpp

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "activemasternode.h"
66
#include "base58.h"
7+
#include "clientversion.h"
78
#include "init.h"
89
#include "netbase.h"
910
#include "masternode.h"
@@ -635,6 +636,23 @@ void CMasternodeBroadcast::Relay(CConnman& connman) const
635636
connman.RelayInv(inv);
636637
}
637638

639+
uint256 CMasternodePing::GetHash() const
640+
{
641+
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
642+
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
643+
ss << masternodeOutpoint;
644+
ss << blockHash;
645+
ss << sigTime;
646+
ss << fSentinelIsCurrent;
647+
ss << nSentinelVersion;
648+
ss << nDaemonVersion;
649+
} else {
650+
ss << masternodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format
651+
ss << sigTime;
652+
}
653+
return ss.GetHash();
654+
}
655+
638656
CMasternodePing::CMasternodePing(const COutPoint& outpoint)
639657
{
640658
LOCK(cs_main);
@@ -643,42 +661,69 @@ CMasternodePing::CMasternodePing(const COutPoint& outpoint)
643661
masternodeOutpoint = outpoint;
644662
blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash();
645663
sigTime = GetAdjustedTime();
664+
nDaemonVersion = CLIENT_VERSION;
646665
}
647666

648667
bool CMasternodePing::Sign(const CKey& keyMasternode, const CPubKey& pubKeyMasternode)
649668
{
650669
std::string strError;
651-
std::string strMasterNodeSignMessage;
652670

653-
// TODO: add sentinel data
654671
sigTime = GetAdjustedTime();
655-
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
656672

657-
if(!CMessageSigner::SignMessage(strMessage, vchSig, keyMasternode)) {
658-
LogPrintf("CMasternodePing::Sign -- SignMessage() failed\n");
659-
return false;
660-
}
673+
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
674+
uint256 hash = GetHash();
661675

662-
if(!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
663-
LogPrintf("CMasternodePing::Sign -- VerifyMessage() failed, error: %s\n", strError);
664-
return false;
676+
if (!CHashSigner::SignHash(hash, keyMasternode, vchSig)) {
677+
LogPrintf("CMasternodePing::Sign -- SignHash() failed\n");
678+
return false;
679+
}
680+
681+
if (!CHashSigner::VerifyHash(hash, pubKeyMasternode, vchSig, strError)) {
682+
LogPrintf("CMasternodePing::Sign -- VerifyHash() failed, error: %s\n", strError);
683+
return false;
684+
}
685+
} else {
686+
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() +
687+
boost::lexical_cast<std::string>(sigTime);
688+
689+
if (!CMessageSigner::SignMessage(strMessage, vchSig, keyMasternode)) {
690+
LogPrintf("CMasternodePing::Sign -- SignMessage() failed\n");
691+
return false;
692+
}
693+
694+
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
695+
LogPrintf("CMasternodePing::Sign -- VerifyMessage() failed, error: %s\n", strError);
696+
return false;
697+
}
665698
}
666699

667700
return true;
668701
}
669702

670703
bool CMasternodePing::CheckSignature(const CPubKey& pubKeyMasternode, int &nDos)
671704
{
672-
// TODO: add sentinel data
673-
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
674705
std::string strError = "";
675706
nDos = 0;
676707

677-
if(!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
678-
LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError);
679-
nDos = 33;
680-
return false;
708+
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
709+
uint256 hash = GetHash();
710+
711+
if (!CHashSigner::VerifyHash(hash, pubKeyMasternode, vchSig, strError)) {
712+
LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError);
713+
nDos = 33;
714+
return false;
715+
}
716+
} else {
717+
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() +
718+
boost::lexical_cast<std::string>(sigTime);
719+
720+
if (!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
721+
LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError);
722+
nDos = 33;
723+
return false;
724+
}
681725
}
726+
682727
return true;
683728
}
684729

src/masternode.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ static const int MASTERNODE_POSE_BAN_MAX_SCORE = 5;
2626
// The Masternode Ping Class : Contains a different serialize method for sending pings from masternodes throughout the network
2727
//
2828

29-
// sentinel version before sentinel ping implementation
29+
// sentinel version before implementation of nSentinelVersion in CMasternodePing
3030
#define DEFAULT_SENTINEL_VERSION 0x010001
31+
// daemon version before implementation of nDaemonVersion in CMasternodePing
32+
#define DEFAULT_DAEMON_VERSION 120200
3133

3234
class CMasternodePing
3335
{
@@ -39,6 +41,7 @@ class CMasternodePing
3941
bool fSentinelIsCurrent = false; // true if last sentinel ping was actual
4042
// MSB is always 0, other 3 bits corresponds to x.x.x version scheme
4143
uint32_t nSentinelVersion{DEFAULT_SENTINEL_VERSION};
44+
uint32_t nDaemonVersion{DEFAULT_DAEMON_VERSION};
4245

4346
CMasternodePing() = default;
4447

@@ -66,23 +69,24 @@ class CMasternodePing
6669
READWRITE(blockHash);
6770
READWRITE(sigTime);
6871
READWRITE(vchSig);
69-
if(ser_action.ForRead() && (s.size() == 0))
70-
{
72+
if(ser_action.ForRead() && s.size() == 0) {
7173
fSentinelIsCurrent = false;
7274
nSentinelVersion = DEFAULT_SENTINEL_VERSION;
75+
nDaemonVersion = DEFAULT_DAEMON_VERSION;
7376
return;
7477
}
7578
READWRITE(fSentinelIsCurrent);
7679
READWRITE(nSentinelVersion);
80+
if(ser_action.ForRead() && s.size() == 0) {
81+
nDaemonVersion = DEFAULT_DAEMON_VERSION;
82+
return;
83+
}
84+
if (nVersion > 70208) {
85+
READWRITE(nDaemonVersion);
86+
}
7787
}
7888

79-
uint256 GetHash() const
80-
{
81-
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
82-
ss << masternodeOutpoint << uint8_t{} << 0xffffffff;
83-
ss << sigTime;
84-
return ss.GetHash();
85-
}
89+
uint256 GetHash() const;
8690

8791
bool IsExpired() const { return GetAdjustedTime() - sigTime > MASTERNODE_NEW_START_REQUIRED_SECONDS; }
8892

src/privatesend.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,18 @@ bool CDarksendQueue::Sign()
4040
{
4141
if(!fMasternodeMode) return false;
4242

43-
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(nTime) + boost::lexical_cast<std::string>(fReady);
43+
std::string strMessage;
44+
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
45+
strMessage = masternodeOutpoint.ToStringShort() +
46+
boost::lexical_cast<std::string>(nDenom) +
47+
boost::lexical_cast<std::string>(nTime) +
48+
boost::lexical_cast<std::string>(fReady);
49+
} else {
50+
strMessage = CTxIn(masternodeOutpoint).ToString() +
51+
boost::lexical_cast<std::string>(nDenom) +
52+
boost::lexical_cast<std::string>(nTime) +
53+
boost::lexical_cast<std::string>(fReady);
54+
}
4455

4556
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternode.keyMasternode)) {
4657
LogPrintf("CDarksendQueue::Sign -- SignMessage() failed, %s\n", ToString());
@@ -52,8 +63,19 @@ bool CDarksendQueue::Sign()
5263

5364
bool CDarksendQueue::CheckSignature(const CPubKey& pubKeyMasternode)
5465
{
55-
std::string strMessage = CTxIn(masternodeOutpoint).ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(nTime) + boost::lexical_cast<std::string>(fReady);
5666
std::string strError = "";
67+
std::string strMessage;
68+
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
69+
strMessage = masternodeOutpoint.ToStringShort() +
70+
boost::lexical_cast<std::string>(nDenom) +
71+
boost::lexical_cast<std::string>(nTime) +
72+
boost::lexical_cast<std::string>(fReady);
73+
} else {
74+
strMessage = CTxIn(masternodeOutpoint).ToString() +
75+
boost::lexical_cast<std::string>(nDenom) +
76+
boost::lexical_cast<std::string>(nTime) +
77+
boost::lexical_cast<std::string>(fReady);
78+
}
5779

5880
if(!CMessageSigner::VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
5981
LogPrintf("CDarksendQueue::CheckSignature -- Got bad Masternode queue signature: %s; error: %s\n", ToString(), strError);

src/spork.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ bool CSporkManager::IsSporkActive(int nSporkID)
129129
case SPORK_2_INSTANTSEND_ENABLED: r = SPORK_2_INSTANTSEND_ENABLED_DEFAULT; break;
130130
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: r = SPORK_3_INSTANTSEND_BLOCK_FILTERING_DEFAULT; break;
131131
case SPORK_5_INSTANTSEND_MAX_VALUE: r = SPORK_5_INSTANTSEND_MAX_VALUE_DEFAULT; break;
132+
case SPORK_6_NEW_SIGS: r = SPORK_6_NEW_SIGS_DEFAULT; break;
132133
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT; break;
133134
case SPORK_9_SUPERBLOCKS_ENABLED: r = SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT; break;
134135
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)
154155
case SPORK_2_INSTANTSEND_ENABLED: return SPORK_2_INSTANTSEND_ENABLED_DEFAULT;
155156
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: return SPORK_3_INSTANTSEND_BLOCK_FILTERING_DEFAULT;
156157
case SPORK_5_INSTANTSEND_MAX_VALUE: return SPORK_5_INSTANTSEND_MAX_VALUE_DEFAULT;
158+
case SPORK_6_NEW_SIGS: return SPORK_6_NEW_SIGS_DEFAULT;
157159
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
158160
case SPORK_9_SUPERBLOCKS_ENABLED: return SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT;
159161
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)
171173
if (strName == "SPORK_2_INSTANTSEND_ENABLED") return SPORK_2_INSTANTSEND_ENABLED;
172174
if (strName == "SPORK_3_INSTANTSEND_BLOCK_FILTERING") return SPORK_3_INSTANTSEND_BLOCK_FILTERING;
173175
if (strName == "SPORK_5_INSTANTSEND_MAX_VALUE") return SPORK_5_INSTANTSEND_MAX_VALUE;
176+
if (strName == "SPORK_6_NEW_SIGS") return SPORK_6_NEW_SIGS;
174177
if (strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT;
175178
if (strName == "SPORK_9_SUPERBLOCKS_ENABLED") return SPORK_9_SUPERBLOCKS_ENABLED;
176179
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)
187190
case SPORK_2_INSTANTSEND_ENABLED: return "SPORK_2_INSTANTSEND_ENABLED";
188191
case SPORK_3_INSTANTSEND_BLOCK_FILTERING: return "SPORK_3_INSTANTSEND_BLOCK_FILTERING";
189192
case SPORK_5_INSTANTSEND_MAX_VALUE: return "SPORK_5_INSTANTSEND_MAX_VALUE";
193+
case SPORK_6_NEW_SIGS: return "SPORK_6_NEW_SIGS";
190194
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT";
191195
case SPORK_9_SUPERBLOCKS_ENABLED: return "SPORK_9_SUPERBLOCKS_ENABLED";
192196
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES";

src/spork.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static const int SPORK_END = 10013;
2222
static const int SPORK_2_INSTANTSEND_ENABLED = 10001;
2323
static const int SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002;
2424
static const int SPORK_5_INSTANTSEND_MAX_VALUE = 10004;
25+
static const int SPORK_6_NEW_SIGS = 10005;
2526
static const int SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT = 10007;
2627
static const int SPORK_9_SUPERBLOCKS_ENABLED = 10008;
2728
static const int SPORK_10_MASTERNODE_PAY_UPDATED_NODES = 10009;
@@ -31,6 +32,7 @@ static const int SPORK_14_REQUIRE_SENTINEL_FLAG = 10013;
3132
static const int64_t SPORK_2_INSTANTSEND_ENABLED_DEFAULT = 0; // ON
3233
static const int64_t SPORK_3_INSTANTSEND_BLOCK_FILTERING_DEFAULT = 0; // ON
3334
static const int64_t SPORK_5_INSTANTSEND_MAX_VALUE_DEFAULT = 1000; // 1000 DASH
35+
static const int64_t SPORK_6_NEW_SIGS_DEFAULT = 4070908800ULL;// OFF
3436
static const int64_t SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT = 4070908800ULL;// OFF
3537
static const int64_t SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT = 4070908800ULL;// OFF
3638
static const int64_t SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT = 4070908800ULL;// OFF

0 commit comments

Comments
 (0)