Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

spork.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2019 The Dash Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <spork.h>
6 
7 #include <base58.h>
8 #include <chainparams.h>
9 #include <validation.h>
10 #include <messagesigner.h>
11 #include <net_processing.h>
12 #include <netmessagemaker.h>
13 
14 #include <string>
15 
16 const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-Version-2";
17 
18 #define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name}
19 std::vector<CSporkDef> sporkDefs = {
20  MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 4070908800ULL), // OFF
22  MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF
23  MAKE_SPORK_DEF(SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL), // OFF
24  MAKE_SPORK_DEF(SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL), // OFF
25  MAKE_SPORK_DEF(SPORK_21_QUORUM_ALL_CONNECTED, 4070908800ULL), // OFF
26  MAKE_SPORK_DEF(SPORK_22_PS_MORE_PARTICIPANTS, 4070908800ULL), // OFF
27 };
28 
30 
32 {
33  for (auto& sporkDef : sporkDefs) {
34  sporkDefsById.emplace(sporkDef.sporkId, &sporkDef);
35  sporkDefsByName.emplace(sporkDef.name, &sporkDef);
36  }
37 }
38 
39 bool CSporkManager::SporkValueIsActive(SporkId nSporkID, int64_t &nActiveValueRet) const
40 {
41  LOCK(cs);
42 
43  if (!mapSporksActive.count(nSporkID)) return false;
44 
45  // calc how many values we have and how many signers vote for every value
46  std::unordered_map<int64_t, int> mapValueCounts;
47  for (const auto& pair: mapSporksActive.at(nSporkID)) {
48  mapValueCounts[pair.second.nValue]++;
49  if (mapValueCounts.at(pair.second.nValue) >= nMinSporkKeys) {
50  // nMinSporkKeys is always more than the half of the max spork keys number,
51  // so there is only one such value and we can stop here
52  nActiveValueRet = pair.second.nValue;
53  return true;
54  }
55  }
56 
57  return false;
58 }
59 
61 {
62  LOCK(cs);
63  mapSporksActive.clear();
64  mapSporksByHash.clear();
65  // sporkPubKeyID and sporkPrivKey should be set in init.cpp,
66  // we should not alter them here.
67 }
68 
70 {
71  LOCK(cs);
72  bool fSporkAddressIsSet = !setSporkPubKeyIDs.empty();
73  assert(fSporkAddressIsSet);
74 
75  auto itActive = mapSporksActive.begin();
76  while (itActive != mapSporksActive.end()) {
77  auto itSignerPair = itActive->second.begin();
78  while (itSignerPair != itActive->second.end()) {
79  if (setSporkPubKeyIDs.find(itSignerPair->first) == setSporkPubKeyIDs.end()) {
80  mapSporksByHash.erase(itSignerPair->second.GetHash());
81  continue;
82  }
83  if (!itSignerPair->second.CheckSignature(itSignerPair->first)) {
84  mapSporksByHash.erase(itSignerPair->second.GetHash());
85  itActive->second.erase(itSignerPair++);
86  continue;
87  }
88  ++itSignerPair;
89  }
90  if (itActive->second.empty()) {
91  mapSporksActive.erase(itActive++);
92  continue;
93  }
94  ++itActive;
95  }
96 
97  auto itByHash = mapSporksByHash.begin();
98  while (itByHash != mapSporksByHash.end()) {
99  bool found = false;
100  for (const auto& signer: setSporkPubKeyIDs) {
101  if (itByHash->second.CheckSignature(signer)) {
102  found = true;
103  break;
104  }
105  }
106  if (!found) {
107  mapSporksByHash.erase(itByHash++);
108  continue;
109  }
110  ++itByHash;
111  }
112 }
113 
114 void CSporkManager::ProcessSpork(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
115 {
116 
117  if (strCommand == NetMsgType::SPORK) {
118 
120  vRecv >> spork;
121 
122  uint256 hash = spork.GetHash();
123 
124  std::string strLogMsg;
125  {
126  LOCK(cs_main);
127  EraseObjectRequest(pfrom->GetId(), CInv(MSG_SPORK, hash));
128  if(!chainActive.Tip()) return;
129  strLogMsg = strprintf("SPORK -- hash: %s id: %d value: %10d bestHeight: %d peer=%d", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Height(), pfrom->GetId());
130  }
131 
132  if (spork.nTimeSigned > GetAdjustedTime() + 2 * 60 * 60) {
133  LOCK(cs_main);
134  LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: too far into the future\n");
135  Misbehaving(pfrom->GetId(), 100);
136  return;
137  }
138 
139  CKeyID keyIDSigner;
140 
141  if (!spork.GetSignerKeyID(keyIDSigner) || !setSporkPubKeyIDs.count(keyIDSigner)) {
142  LOCK(cs_main);
143  LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: invalid signature\n");
144  Misbehaving(pfrom->GetId(), 100);
145  return;
146  }
147 
148  {
149  LOCK(cs); // make sure to not lock this together with cs_main
150  if (mapSporksActive.count(spork.nSporkID)) {
151  if (mapSporksActive[spork.nSporkID].count(keyIDSigner)) {
152  if (mapSporksActive[spork.nSporkID][keyIDSigner].nTimeSigned >= spork.nTimeSigned) {
153  LogPrint(BCLog::SPORK, "%s seen\n", strLogMsg);
154  return;
155  } else {
156  LogPrintf("%s updated\n", strLogMsg);
157  }
158  } else {
159  LogPrintf("%s new signer\n", strLogMsg);
160  }
161  } else {
162  LogPrintf("%s new\n", strLogMsg);
163  }
164  }
165 
166 
167  {
168  LOCK(cs); // make sure to not lock this together with cs_main
169  mapSporksByHash[hash] = spork;
170  mapSporksActive[spork.nSporkID][keyIDSigner] = spork;
171  }
172  spork.Relay(connman);
173 
174  } else if (strCommand == NetMsgType::GETSPORKS) {
175  LOCK(cs); // make sure to not lock this together with cs_main
176  for (const auto& pair : mapSporksActive) {
177  for (const auto& signerSporkPair: pair.second) {
178  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SPORK, signerSporkPair.second));
179  }
180  }
181  }
182 
183 }
184 
185 bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman& connman)
186 {
187  CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetAdjustedTime());
188 
189  LOCK(cs);
190 
191  if (!spork.Sign(sporkPrivKey)) {
192  LogPrintf("CSporkManager::%s -- ERROR: signing failed for spork %d\n", __func__, nSporkID);
193  return false;
194  }
195 
196  CKeyID keyIDSigner;
197  if (!spork.GetSignerKeyID(keyIDSigner) || !setSporkPubKeyIDs.count(keyIDSigner)) {
198  LogPrintf("CSporkManager::UpdateSpork: failed to find keyid for private key\n");
199  return false;
200  }
201 
202  LogPrintf("CSporkManager::%s -- signed %d %s\n", __func__, nSporkID, spork.GetHash().ToString());
203 
204  mapSporksByHash[spork.GetHash()] = spork;
205  mapSporksActive[nSporkID][keyIDSigner] = spork;
206 
207  spork.Relay(connman);
208  return true;
209 }
210 
212 {
213  int64_t nSporkValue = GetSporkValue(nSporkID);
214  return nSporkValue < GetAdjustedTime();
215 }
216 
218 {
219  LOCK(cs);
220 
221  int64_t nSporkValue = -1;
222  if (SporkValueIsActive(nSporkID, nSporkValue)) {
223  return nSporkValue;
224  }
225 
226  auto it = sporkDefsById.find(nSporkID);
227  if (it != sporkDefsById.end()) {
228  return it->second->defaultValue;
229  }
230 
231  LogPrint(BCLog::SPORK, "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
232  return -1;
233 }
234 
235 SporkId CSporkManager::GetSporkIDByName(const std::string& strName)
236 {
237  auto it = sporkDefsByName.find(strName);
238  if (it == sporkDefsByName.end()) {
239  LogPrint(BCLog::SPORK, "CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
240  return SPORK_INVALID;
241  }
242  return it->second->sporkId;
243 }
244 
246 {
247  auto it = sporkDefsById.find(nSporkID);
248  if (it == sporkDefsById.end()) {
249  LogPrint(BCLog::SPORK, "CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
250  return "Unknown";
251  }
252  return it->second->name;
253 }
254 
256 {
257  LOCK(cs);
258 
259  const auto it = mapSporksByHash.find(hash);
260 
261  if (it == mapSporksByHash.end())
262  return false;
263 
264  sporkRet = it->second;
265 
266  return true;
267 }
268 
269 bool CSporkManager::SetSporkAddress(const std::string& strAddress) {
270  LOCK(cs);
271  CTxDestination dest = DecodeDestination(strAddress);
272  const CKeyID *keyID = boost::get<CKeyID>(&dest);
273  if (!keyID) {
274  LogPrintf("CSporkManager::SetSporkAddress -- Failed to parse spork address\n");
275  return false;
276  }
277  setSporkPubKeyIDs.insert(*keyID);
278  return true;
279 }
280 
281 bool CSporkManager::SetMinSporkKeys(int minSporkKeys)
282 {
283  int maxKeysNumber = setSporkPubKeyIDs.size();
284  if ((minSporkKeys <= maxKeysNumber / 2) || (minSporkKeys > maxKeysNumber)) {
285  LogPrintf("CSporkManager::SetMinSporkKeys -- Invalid min spork signers number: %d\n", minSporkKeys);
286  return false;
287  }
288  nMinSporkKeys = minSporkKeys;
289  return true;
290 }
291 
292 bool CSporkManager::SetPrivKey(const std::string& strPrivKey)
293 {
294  CKey key;
295  CPubKey pubKey;
296  if(!CMessageSigner::GetKeysFromSecret(strPrivKey, key, pubKey)) {
297  LogPrintf("CSporkManager::SetPrivKey -- Failed to parse private key\n");
298  return false;
299  }
300 
301  if (setSporkPubKeyIDs.find(pubKey.GetID()) == setSporkPubKeyIDs.end()) {
302  LogPrintf("CSporkManager::SetPrivKey -- New private key does not belong to spork addresses\n");
303  return false;
304  }
305 
307  if (!spork.Sign(key)) {
308  LogPrintf("CSporkManager::SetPrivKey -- Test signing failed\n");
309  return false;
310  }
311 
312  // Test signing successful, proceed
313  LOCK(cs);
314  LogPrintf("CSporkManager::SetPrivKey -- Successfully initialized as spork signer\n");
315  sporkPrivKey = key;
316  return true;
317 }
318 
319 std::string CSporkManager::ToString() const
320 {
321  LOCK(cs);
322  return strprintf("Sporks: %llu", mapSporksActive.size());
323 }
324 
326 {
327  return SerializeHash(*this);
328 }
329 
331 {
332  CHashWriter s(SER_GETHASH, 0);
333  s << nSporkID;
334  s << nValue;
335  s << nTimeSigned;
336  return s.GetHash();
337 }
338 
339 bool CSporkMessage::Sign(const CKey& key)
340 {
341  if (!key.IsValid()) {
342  LogPrintf("CSporkMessage::Sign -- signing key is not valid\n");
343  return false;
344  }
345 
346  CKeyID pubKeyId = key.GetPubKey().GetID();
347  std::string strError = "";
348 
349  // Harden Spork6 so that it is active on testnet and no other networks
350  if (Params().NetworkIDString() == CBaseChainParams::TESTNET) {
351  uint256 hash = GetSignatureHash();
352 
353  if(!CHashSigner::SignHash(hash, key, vchSig)) {
354  LogPrintf("CSporkMessage::Sign -- SignHash() failed\n");
355  return false;
356  }
357 
358  if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
359  LogPrintf("CSporkMessage::Sign -- VerifyHash() failed, error: %s\n", strError);
360  return false;
361  }
362  } else {
363  std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
364 
365  if(!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
366  LogPrintf("CSporkMessage::Sign -- SignMessage() failed\n");
367  return false;
368  }
369 
370  if(!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)) {
371  LogPrintf("CSporkMessage::Sign -- VerifyMessage() failed, error: %s\n", strError);
372  return false;
373  }
374  }
375 
376  return true;
377 }
378 
379 bool CSporkMessage::CheckSignature(const CKeyID& pubKeyId) const
380 {
381  std::string strError = "";
382 
383  // Harden Spork6 so that it is active on testnet and no other networks
384  if (Params().NetworkIDString() == CBaseChainParams::TESTNET) {
385  uint256 hash = GetSignatureHash();
386 
387  if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
388  LogPrint(BCLog::SPORK, "CSporkMessage::CheckSignature -- VerifyHash() failed, error: %s\n", strError);
389  return false;
390  }
391  } else {
392  std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
393 
394  if (!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)){
395  LogPrint(BCLog::SPORK, "CSporkMessage::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
396  return false;
397  }
398  }
399 
400  return true;
401 }
402 
403 bool CSporkMessage::GetSignerKeyID(CKeyID &retKeyidSporkSigner)
404 {
405  CPubKey pubkeyFromSig;
406  // Harden Spork6 so that it is active on testnet and no other networks
407  if (Params().NetworkIDString() == CBaseChainParams::TESTNET) {
408  if (!pubkeyFromSig.RecoverCompact(GetSignatureHash(), vchSig)) {
409  return false;
410  }
411  } else {
412  std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
413  CHashWriter ss(SER_GETHASH, 0);
414  ss << strMessageMagic;
415  ss << strMessage;
416  if (!pubkeyFromSig.RecoverCompact(ss.GetHash(), vchSig)) {
417  return false;
418  }
419  }
420 
421  retKeyidSporkSigner = pubkeyFromSig.GetID();
422  return true;
423 }
424 
426 {
427  CInv inv(MSG_SPORK, GetHash());
428  connman.RelayInv(inv);
429 }
static bool VerifyHash(const uint256 &hash, const CPubKey &pubkey, const std::vector< unsigned char > &vchSig, std::string &strErrorRet)
Verify the hash signature, returns true if succcessful.
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:80
int GetSendVersion() const
Definition: net.cpp:887
bool UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman &connman)
UpdateSpork is used by the spork RPC command to set a new spork value, sign and broadcast the spork m...
Definition: spork.cpp:185
bool Sign(const CKey &key)
Sign will sign the spork message with the given key.
Definition: spork.cpp:339
#define strprintf
Definition: tinyformat.h:1066
CCriticalSection cs
Definition: spork.h:159
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:179
inv message data
Definition: protocol.h:429
static bool SignHash(const uint256 &hash, const CKey &key, std::vector< unsigned char > &vchSigRet)
Sign the hash, returns true if successful.
int Height() const
Return the maximal height in the chain.
Definition: chain.h:484
SporkId GetSporkIDByName(const std::string &strName)
GetSporkIDByName returns the internal Spork ID given the spork name.
Definition: spork.cpp:235
CCriticalSection cs_main
Definition: validation.cpp:213
CTxDestination DecodeDestination(const std::string &str)
Definition: base58.cpp:336
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3733
int64_t nTimeSigned
Definition: spork.h:83
void ProcessSpork(CNode *pfrom, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
ProcessSpork is used to handle the &#39;getsporks&#39; and &#39;spork&#39; p2p messages.
Definition: spork.cpp:114
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
uint256 GetSignatureHash() const
GetSignatureHash returns the hash of the serialized spork message without the signature included...
Definition: spork.cpp:330
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:149
const std::string strMessageMagic
Definition: validation.cpp:257
Sporks are network parameters used primarily to prevent forking and turn on/off certain features...
Definition: spork.h:75
static bool VerifyMessage(const CPubKey &pubkey, const std::vector< unsigned char > &vchSig, const std::string &strMessage, std::string &strErrorRet)
Verify the message signature, returns true if succcessful.
CKey sporkPrivKey
Definition: spork.h:165
std::string ToString() const
ToString returns the string representation of the SporkManager.
Definition: spork.cpp:319
bool SetSporkAddress(const std::string &strAddress)
SetSporkAddress is used to set a public key ID which will be used to verify spork signatures...
Definition: spork.cpp:269
static bool SignMessage(const std::string &strMessage, std::vector< unsigned char > &vchSigRet, const CKey &key)
Sign the message, returns true if successful.
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object&#39;s serialization.
Definition: hash.h:254
void Misbehaving(NodeId pnode, int howmuch, const std::string &message)
Increase a node&#39;s misbehavior score.
SporkId nSporkID
Definition: spork.h:81
std::unordered_map< SporkId, std::map< CKeyID, CSporkMessage > > mapSporksActive
Definition: spork.h:161
UniValue spork(const JSONRPCRequest &request)
Definition: misc.cpp:165
#define LogPrintf(...)
Definition: util.h:203
void CheckAndRemove()
CheckAndRemove is defined to fulfill an interface as part of the on-disk cache used to cache sporks b...
Definition: spork.cpp:69
#define MAKE_SPORK_DEF(name, defaultValue)
Definition: spork.cpp:18
#define LOCK(cs)
Definition: sync.h:178
bool RecoverCompact(const uint256 &hash, const std::vector< unsigned char > &vchSig)
Recover a public key from a compact signature.
Definition: pubkey.cpp:186
An encapsulated public key.
Definition: pubkey.h:30
std::set< CKeyID > setSporkPubKeyIDs
Definition: spork.h:163
const char * GETSPORKS
Definition: protocol.cpp:46
CSporkManager is a higher-level class which manages the node&#39;s spork messages, rules for which sporks...
Definition: spork.h:151
int64_t GetSporkValue(SporkId nSporkID)
GetSporkValue returns the spork value given a Spork ID.
Definition: spork.cpp:217
bool GetSporkByHash(const uint256 &hash, CSporkMessage &sporkRet)
GetSporkByHash returns a spork message given a hash of the spork message.
Definition: spork.cpp:255
std::string GetSporkNameByID(SporkId nSporkID)
GetSporkNameByID returns the spork name as a string, given a Spork ID.
Definition: spork.cpp:245
Definition: net.h:136
static const std::string SERIALIZATION_VERSION_STRING
Definition: spork.h:154
std::string ToString() const
Definition: uint256.cpp:62
SporkId
Definition: spork.h:23
NodeId GetId() const
Definition: net.h:973
CSporkManager sporkManager
Definition: spork.cpp:29
#define LogPrint(category,...)
Definition: util.h:214
uint256 GetHash() const
GetHash returns the double-sha256 hash of the serialized spork message.
Definition: spork.cpp:325
uint256 GetHash()
Definition: hash.h:203
256-bit opaque blob.
Definition: uint256.h:123
static bool GetKeysFromSecret(const std::string &strSecret, CKey &keyRet, CPubKey &pubkeyRet)
Set the private/public key values, returns true if successful.
std::unordered_map< uint256, CSporkMessage > mapSporksByHash
Definition: spork.h:160
std::vector< unsigned char > vchSig
Definition: spork.h:78
bool GetSignerKeyID(CKeyID &retKeyidSporkSigner)
GetSignerKeyID is used to recover the spork address of the key used to sign this spork message...
Definition: spork.cpp:403
const CChainParams & Params()
Return the currently selected parameters.
void Relay(CConnman &connman)
Relay is used to send this spork message to other peers.
Definition: spork.cpp:425
int64_t nValue
Definition: spork.h:82
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
bool CheckSignature(const CKeyID &pubKeyId) const
CheckSignature will ensure the spork signature matches the provided public key hash.
Definition: spork.cpp:379
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:20
std::unordered_map< std::string, CSporkDef * > sporkDefsByName
Definition: spork.h:157
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:453
int nMinSporkKeys
Definition: spork.h:164
void RelayInv(CInv &inv, const int minProtoVersion=MIN_PEER_PROTO_VERSION, bool fAllowMasternodeConnections=false)
Definition: net.cpp:3482
static const std::string TESTNET
void EraseObjectRequest(CNodeState *nodestate, const CInv &inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:184
std::vector< CSporkDef > sporkDefs
Definition: spork.cpp:19
void Clear()
Clear is used to clear all in-memory active spork messages.
Definition: spork.cpp:60
bool SporkValueIsActive(SporkId nSporkID, int64_t &nActiveValueRet) const
SporkValueIsActive is used to get the value agreed upon by the majority of signed spork messages for ...
Definition: spork.cpp:39
An encapsulated private key.
Definition: key.h:27
bool IsSporkActive(SporkId nSporkID)
IsSporkActive returns a bool for time-based sporks, and should be used to determine whether the spork...
Definition: spork.cpp:211
Information about a peer.
Definition: net.h:800
CSporkManager()
Definition: spork.cpp:31
CChain & chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:217
const char * SPORK
Definition: protocol.cpp:45
bool SetMinSporkKeys(int minSporkKeys)
SetMinSporkKeys is used to set the required spork signer threshold, for a spork to be considered acti...
Definition: spork.cpp:281
bool SetPrivKey(const std::string &strPrivKey)
SetPrivKey is used to set a spork key to enable setting / signing of spork values.
Definition: spork.cpp:292
std::unordered_map< SporkId, CSporkDef * > sporkDefsById
Definition: spork.h:156
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:93
Released under the MIT license