2019-01-29 15:53:14 +01:00
|
|
|
// Copyright (c) 2014-2019 The Dash Core developers
|
2016-02-02 16:28:56 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
#include "spork.h"
|
|
|
|
|
|
|
|
#include "base58.h"
|
2017-04-12 09:04:06 +02:00
|
|
|
#include "chainparams.h"
|
2017-08-09 02:19:06 +02:00
|
|
|
#include "validation.h"
|
2017-04-12 09:04:06 +02:00
|
|
|
#include "messagesigner.h"
|
2017-08-09 02:19:06 +02:00
|
|
|
#include "net_processing.h"
|
2016-11-25 20:01:56 +01:00
|
|
|
#include "netmessagemaker.h"
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-07-12 11:02:20 +02:00
|
|
|
#include <string>
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-10-11 16:34:52 +02:00
|
|
|
const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-Version-2";
|
2018-09-26 16:15:02 +02:00
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
#define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name}
|
|
|
|
std::vector<CSporkDef> sporkDefs = {
|
2019-07-09 16:50:08 +02:00
|
|
|
MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 4070908800ULL), // OFF
|
2019-05-29 20:18:31 +02:00
|
|
|
MAKE_SPORK_DEF(SPORK_6_NEW_SIGS, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL), // OFF
|
|
|
|
MAKE_SPORK_DEF(SPORK_20_INSTANTSEND_LLMQ_BASED, 4070908800ULL), // OFF
|
2018-04-18 13:50:26 +02:00
|
|
|
};
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
CSporkManager sporkManager;
|
|
|
|
|
|
|
|
CSporkManager::CSporkManager()
|
|
|
|
{
|
|
|
|
for (auto& sporkDef : sporkDefs) {
|
|
|
|
sporkDefsById.emplace(sporkDef.sporkId, &sporkDef);
|
|
|
|
sporkDefsByName.emplace(sporkDef.name, &sporkDef);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CSporkManager::SporkValueIsActive(SporkId nSporkID, int64_t &nActiveValueRet) const
|
2018-09-30 19:01:33 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
if (!mapSporksActive.count(nSporkID)) return false;
|
|
|
|
|
|
|
|
// calc how many values we have and how many signers vote for every value
|
Collection of minor performance optimizations (#2855)
* Merge #13176: Improve CRollingBloomFilter performance: replace modulus with FastMod
9aac9f90d5e56752cc6cbfac48063ad29a01143c replace modulus with FastMod (Martin Ankerl)
Pull request description:
Not sure if this is optimization is necessary, but anyway I have some spare time so here it is. This replaces the slow modulo operation with a much faster 64bit multiplication & shift. This works when the hash is uniformly distributed between 0 and 2^32-1. This speeds up the benchmark by a factor of about 1.3:
```
RollingBloom, 5, 1500000, 3.73733, 4.97569e-07, 4.99002e-07, 4.98372e-07 # before
RollingBloom, 5, 1500000, 2.86842, 3.81630e-07, 3.83730e-07, 3.82473e-07 # FastMod
```
Be aware that this changes the internal data of the filter, so this should probably
not be used for CBloomFilter because of interoperability problems.
Tree-SHA512: 04104f3fb09f56c9d14458a6aad919aeb0a5af944e8ee6a31f00e93c753e22004648c1cd65bf36752b6addec528d19fb665c27b955ce1666a85a928e17afa47a
* Use unordered_map in CSporkManager
In one of my profiling sessions with many InstantSend transactions
happening, calls into CSporkManager added up to about 1% of total CPU time.
This is easily avoidable by using unordered maps.
* Use std::unordered_map instead of std::map in limitedmap
* Use unordered_set for CNode::setAskFor
* Add serialization support for unordered maps and sets
* Use unordered_map for mapArgs and mapMultiArgs
* Let limitedmap prune in batches and use unordered_multimap
Due to the batched pruning, there is no need to maintain an ordered map
of values anymore. Only when nPruneAfterSize, there is a need to create
a temporary ordered vector of values to figure out what can be removed.
* Instead of using a multimap for mapAskFor, use a vector which we sort on demand
CNode::AskFor will now push entries into an initially unordered vector
instead of an ordered multimap. Only when we later want to use vecAskFor in
SendMessages, we sort the vector.
The vector will actually be mostly sorted in most cases as insertion order
usually mimics the desired ordering. Only the last few entries might need
some shuffling around. Doing the sort on-demand should be less wasteful
then trying to maintain correct order all the time.
* Fix compilation of tests
* Fix limitedmap tests
* Rename limitedmap to unordered_limitedmap to ensure backports conflict
This ensures that future backports that depends on limitedmap's ordering
conflict so that we are made aware of needed action.
* Fix compilation error on Travis
2019-04-11 14:42:14 +02:00
|
|
|
std::unordered_map<int64_t, int> mapValueCounts;
|
2018-09-30 19:01:33 +02:00
|
|
|
for (const auto& pair: mapSporksActive.at(nSporkID)) {
|
|
|
|
mapValueCounts[pair.second.nValue]++;
|
|
|
|
if (mapValueCounts.at(pair.second.nValue) >= nMinSporkKeys) {
|
|
|
|
// nMinSporkKeys is always more than the half of the max spork keys number,
|
|
|
|
// so there is only one such value and we can stop here
|
|
|
|
nActiveValueRet = pair.second.nValue;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-13 22:21:21 +02:00
|
|
|
void CSporkManager::Clear()
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
mapSporksActive.clear();
|
|
|
|
mapSporksByHash.clear();
|
2018-09-26 16:15:58 +02:00
|
|
|
// sporkPubKeyID and sporkPrivKey should be set in init.cpp,
|
|
|
|
// we should not alter them here.
|
2018-08-13 22:21:21 +02:00
|
|
|
}
|
|
|
|
|
2018-09-26 16:15:02 +02:00
|
|
|
void CSporkManager::CheckAndRemove()
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
2018-09-30 19:01:33 +02:00
|
|
|
bool fSporkAddressIsSet = !setSporkPubKeyIDs.empty();
|
2018-09-26 16:15:02 +02:00
|
|
|
assert(fSporkAddressIsSet);
|
|
|
|
|
|
|
|
auto itActive = mapSporksActive.begin();
|
|
|
|
while (itActive != mapSporksActive.end()) {
|
2018-09-30 19:01:33 +02:00
|
|
|
auto itSignerPair = itActive->second.begin();
|
|
|
|
while (itSignerPair != itActive->second.end()) {
|
|
|
|
if (setSporkPubKeyIDs.find(itSignerPair->first) == setSporkPubKeyIDs.end()) {
|
|
|
|
mapSporksByHash.erase(itSignerPair->second.GetHash());
|
2018-09-26 16:15:02 +02:00
|
|
|
continue;
|
|
|
|
}
|
2018-09-30 19:01:33 +02:00
|
|
|
if (!itSignerPair->second.CheckSignature(itSignerPair->first, false)) {
|
|
|
|
if (!itSignerPair->second.CheckSignature(itSignerPair->first, true)) {
|
|
|
|
mapSporksByHash.erase(itSignerPair->second.GetHash());
|
|
|
|
itActive->second.erase(itSignerPair++);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++itSignerPair;
|
|
|
|
}
|
|
|
|
if (itActive->second.empty()) {
|
|
|
|
mapSporksActive.erase(itActive++);
|
|
|
|
continue;
|
2018-09-26 16:15:02 +02:00
|
|
|
}
|
|
|
|
++itActive;
|
|
|
|
}
|
2018-09-30 19:01:33 +02:00
|
|
|
|
2018-09-26 16:15:02 +02:00
|
|
|
auto itByHash = mapSporksByHash.begin();
|
|
|
|
while (itByHash != mapSporksByHash.end()) {
|
2018-09-30 19:01:33 +02:00
|
|
|
bool found = false;
|
|
|
|
for (const auto& signer: setSporkPubKeyIDs) {
|
|
|
|
if (itByHash->second.CheckSignature(signer, false) ||
|
|
|
|
itByHash->second.CheckSignature(signer, true)) {
|
|
|
|
found = true;
|
|
|
|
break;
|
2018-09-26 16:15:02 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-30 19:01:33 +02:00
|
|
|
if (!found) {
|
|
|
|
mapSporksByHash.erase(itByHash++);
|
|
|
|
continue;
|
|
|
|
}
|
2018-09-26 16:15:02 +02:00
|
|
|
++itByHash;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-06 14:31:37 +01:00
|
|
|
void CSporkManager::ProcessSpork(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2016-07-30 13:04:27 +02:00
|
|
|
if(fLiteMode) return; // disable all Dash specific functionality
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2016-08-29 21:16:02 +02:00
|
|
|
if (strCommand == NetMsgType::SPORK) {
|
|
|
|
|
2015-02-09 21:54:51 +01:00
|
|
|
CSporkMessage spork;
|
|
|
|
vRecv >> spork;
|
|
|
|
|
|
|
|
uint256 hash = spork.GetHash();
|
2016-09-15 08:50:16 +02:00
|
|
|
|
|
|
|
std::string strLogMsg;
|
|
|
|
{
|
|
|
|
LOCK(cs_main);
|
2018-10-26 18:42:11 +02:00
|
|
|
connman.RemoveAskFor(hash);
|
2016-09-15 08:50:16 +02:00
|
|
|
if(!chainActive.Tip()) return;
|
2017-05-07 09:59:42 +02:00
|
|
|
strLogMsg = strprintf("SPORK -- hash: %s id: %d value: %10d bestHeight: %d peer=%d", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Height(), pfrom->GetId());
|
2016-09-15 08:50:16 +02:00
|
|
|
}
|
2018-09-30 19:01:33 +02:00
|
|
|
|
2018-12-22 11:33:49 +01:00
|
|
|
if (spork.nTimeSigned > GetAdjustedTime() + 2 * 60 * 60) {
|
|
|
|
LOCK(cs_main);
|
|
|
|
LogPrintf("CSporkManager::ProcessSpork -- ERROR: too far into the future\n");
|
|
|
|
Misbehaving(pfrom->GetId(), 100);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
CKeyID keyIDSigner;
|
|
|
|
bool fSpork6IsActive = IsSporkActive(SPORK_6_NEW_SIGS);
|
2019-04-30 14:48:21 +02:00
|
|
|
if (!spork.GetSignerKeyID(keyIDSigner, fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
|
2018-09-30 19:01:33 +02:00
|
|
|
// Note: unlike for other messages we have to check for new format even with SPORK_6_NEW_SIGS
|
|
|
|
// inactive because SPORK_6_NEW_SIGS default is OFF and it is not the first spork to sync
|
|
|
|
// (and even if it would, spork order can't be guaranteed anyway).
|
2019-04-30 14:48:21 +02:00
|
|
|
if (!spork.GetSignerKeyID(keyIDSigner, !fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
|
2018-09-30 19:01:33 +02:00
|
|
|
LOCK(cs_main);
|
|
|
|
LogPrintf("CSporkManager::ProcessSpork -- ERROR: invalid signature\n");
|
|
|
|
Misbehaving(pfrom->GetId(), 100);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-11 00:34:28 +02:00
|
|
|
{
|
|
|
|
LOCK(cs); // make sure to not lock this together with cs_main
|
|
|
|
if (mapSporksActive.count(spork.nSporkID)) {
|
2018-09-30 19:01:33 +02:00
|
|
|
if (mapSporksActive[spork.nSporkID].count(keyIDSigner)) {
|
|
|
|
if (mapSporksActive[spork.nSporkID][keyIDSigner].nTimeSigned >= spork.nTimeSigned) {
|
2019-05-22 23:51:39 +02:00
|
|
|
LogPrint(BCLog::SPORK, "%s seen\n", strLogMsg);
|
2018-09-30 19:01:33 +02:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
LogPrintf("%s updated\n", strLogMsg);
|
|
|
|
}
|
2018-08-11 00:34:28 +02:00
|
|
|
} else {
|
2018-09-30 19:01:33 +02:00
|
|
|
LogPrintf("%s new signer\n", strLogMsg);
|
2018-08-11 00:34:28 +02:00
|
|
|
}
|
2015-02-09 21:54:51 +01:00
|
|
|
} else {
|
2018-08-11 00:34:28 +02:00
|
|
|
LogPrintf("%s new\n", strLogMsg);
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-11 00:34:28 +02:00
|
|
|
{
|
|
|
|
LOCK(cs); // make sure to not lock this together with cs_main
|
2018-08-13 22:21:21 +02:00
|
|
|
mapSporksByHash[hash] = spork;
|
2018-09-30 19:01:33 +02:00
|
|
|
mapSporksActive[spork.nSporkID][keyIDSigner] = spork;
|
2018-08-11 00:34:28 +02:00
|
|
|
}
|
2017-09-07 17:58:38 +02:00
|
|
|
spork.Relay(connman);
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2016-08-29 21:16:02 +02:00
|
|
|
} else if (strCommand == NetMsgType::GETSPORKS) {
|
2018-08-11 00:34:28 +02:00
|
|
|
LOCK(cs); // make sure to not lock this together with cs_main
|
2018-07-12 11:07:51 +02:00
|
|
|
for (const auto& pair : mapSporksActive) {
|
2018-09-30 19:01:33 +02:00
|
|
|
for (const auto& signerSporkPair: pair.second) {
|
|
|
|
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SPORK, signerSporkPair.second));
|
|
|
|
}
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman& connman)
|
2016-07-30 13:04:27 +02:00
|
|
|
{
|
2017-08-29 01:51:44 +02:00
|
|
|
CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetAdjustedTime());
|
2016-07-30 13:04:27 +02:00
|
|
|
|
2019-08-28 13:51:59 +02:00
|
|
|
LOCK(cs);
|
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
bool fSpork6IsActive = IsSporkActive(SPORK_6_NEW_SIGS);
|
2019-08-28 13:51:59 +02:00
|
|
|
if (!spork.Sign(sporkPrivKey, fSpork6IsActive)) {
|
|
|
|
LogPrintf("CSporkManager::%s -- ERROR: signing failed for spork %d\n", __func__, nSporkID);
|
|
|
|
return false;
|
2016-07-30 13:04:27 +02:00
|
|
|
}
|
|
|
|
|
2019-08-28 13:51:59 +02:00
|
|
|
CKeyID keyIDSigner;
|
|
|
|
if (!spork.GetSignerKeyID(keyIDSigner, fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
|
|
|
|
LogPrintf("CSporkManager::UpdateSpork: failed to find keyid for private key\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
LogPrintf("CSporkManager::%s -- signed %d %s\n", __func__, nSporkID, spork.GetHash().ToString());
|
|
|
|
|
|
|
|
mapSporksByHash[spork.GetHash()] = spork;
|
|
|
|
mapSporksActive[nSporkID][keyIDSigner] = spork;
|
|
|
|
|
|
|
|
spork.Relay(connman);
|
|
|
|
return true;
|
2016-07-30 13:04:27 +02:00
|
|
|
}
|
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
bool CSporkManager::IsSporkActive(SporkId nSporkID)
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2019-05-29 20:18:31 +02:00
|
|
|
int64_t nSporkValue = GetSporkValue(nSporkID);
|
|
|
|
return nSporkValue < GetAdjustedTime();
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
int64_t CSporkManager::GetSporkValue(SporkId nSporkID)
|
2015-02-11 15:47:21 +01:00
|
|
|
{
|
2018-08-11 00:34:28 +02:00
|
|
|
LOCK(cs);
|
2018-09-30 19:01:33 +02:00
|
|
|
|
|
|
|
int64_t nSporkValue = -1;
|
|
|
|
if (SporkValueIsActive(nSporkID, nSporkValue)) {
|
|
|
|
return nSporkValue;
|
|
|
|
}
|
2016-08-29 21:16:02 +02:00
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
auto it = sporkDefsById.find(nSporkID);
|
|
|
|
if (it != sporkDefsById.end()) {
|
|
|
|
return it->second->defaultValue;
|
2015-02-11 15:47:21 +01:00
|
|
|
}
|
|
|
|
|
2019-05-22 23:51:39 +02:00
|
|
|
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
|
2018-04-18 13:50:26 +02:00
|
|
|
return -1;
|
2015-02-11 15:47:21 +01:00
|
|
|
}
|
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
SporkId CSporkManager::GetSporkIDByName(const std::string& strName)
|
2015-02-12 05:05:09 +01:00
|
|
|
{
|
2019-05-29 20:18:31 +02:00
|
|
|
auto it = sporkDefsByName.find(strName);
|
|
|
|
if (it == sporkDefsByName.end()) {
|
|
|
|
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
|
|
|
|
return SPORK_INVALID;
|
|
|
|
}
|
|
|
|
return it->second->sporkId;
|
2015-08-03 01:08:37 +02:00
|
|
|
}
|
2015-08-02 23:59:28 +02:00
|
|
|
|
2019-05-29 20:18:31 +02:00
|
|
|
std::string CSporkManager::GetSporkNameByID(SporkId nSporkID)
|
2016-07-30 13:04:27 +02:00
|
|
|
{
|
2019-05-29 20:18:31 +02:00
|
|
|
auto it = sporkDefsById.find(nSporkID);
|
|
|
|
if (it == sporkDefsById.end()) {
|
|
|
|
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
|
|
|
|
return "Unknown";
|
2016-08-29 21:16:02 +02:00
|
|
|
}
|
2019-05-29 20:18:31 +02:00
|
|
|
return it->second->name;
|
2015-02-12 05:05:09 +01:00
|
|
|
}
|
|
|
|
|
2018-08-13 22:21:21 +02:00
|
|
|
bool CSporkManager::GetSporkByHash(const uint256& hash, CSporkMessage &sporkRet)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
const auto it = mapSporksByHash.find(hash);
|
|
|
|
|
|
|
|
if (it == mapSporksByHash.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
sporkRet = it->second;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
bool CSporkManager::SetSporkAddress(const std::string& strAddress) {
|
2018-08-11 00:34:28 +02:00
|
|
|
LOCK(cs);
|
2018-03-02 14:15:04 +01:00
|
|
|
CBitcoinAddress address(strAddress);
|
2018-09-30 19:01:33 +02:00
|
|
|
CKeyID keyid;
|
|
|
|
if (!address.IsValid() || !address.GetKeyID(keyid)) {
|
2018-03-02 14:15:04 +01:00
|
|
|
LogPrintf("CSporkManager::SetSporkAddress -- Failed to parse spork address\n");
|
|
|
|
return false;
|
|
|
|
}
|
2018-09-30 19:01:33 +02:00
|
|
|
setSporkPubKeyIDs.insert(keyid);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CSporkManager::SetMinSporkKeys(int minSporkKeys)
|
|
|
|
{
|
|
|
|
int maxKeysNumber = setSporkPubKeyIDs.size();
|
|
|
|
if ((minSporkKeys <= maxKeysNumber / 2) || (minSporkKeys > maxKeysNumber)) {
|
|
|
|
LogPrintf("CSporkManager::SetMinSporkKeys -- Invalid min spork signers number: %d\n", minSporkKeys);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nMinSporkKeys = minSporkKeys;
|
2018-03-02 14:15:04 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-12 13:49:00 +01:00
|
|
|
bool CSporkManager::SetPrivKey(const std::string& strPrivKey)
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2018-03-02 14:15:04 +01:00
|
|
|
CKey key;
|
|
|
|
CPubKey pubKey;
|
|
|
|
if(!CMessageSigner::GetKeysFromSecret(strPrivKey, key, pubKey)) {
|
|
|
|
LogPrintf("CSporkManager::SetPrivKey -- Failed to parse private key\n");
|
|
|
|
return false;
|
|
|
|
}
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
if (setSporkPubKeyIDs.find(pubKey.GetID()) == setSporkPubKeyIDs.end()) {
|
|
|
|
LogPrintf("CSporkManager::SetPrivKey -- New private key does not belong to spork addresses\n");
|
2018-03-02 14:15:04 +01:00
|
|
|
return false;
|
|
|
|
}
|
2016-07-30 13:04:27 +02:00
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
CSporkMessage spork;
|
2019-08-28 13:51:59 +02:00
|
|
|
if (!spork.Sign(key, IsSporkActive(SPORK_6_NEW_SIGS))) {
|
2018-03-02 14:15:04 +01:00
|
|
|
LogPrintf("CSporkManager::SetPrivKey -- Test signing failed\n");
|
2015-02-09 21:54:51 +01:00
|
|
|
return false;
|
|
|
|
}
|
2019-08-28 13:51:59 +02:00
|
|
|
|
|
|
|
// Test signing successful, proceed
|
|
|
|
LOCK(cs);
|
|
|
|
LogPrintf("CSporkManager::SetPrivKey -- Successfully initialized as spork signer\n");
|
|
|
|
sporkPrivKey = key;
|
|
|
|
return true;
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
2018-08-13 22:21:21 +02:00
|
|
|
std::string CSporkManager::ToString() const
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
return strprintf("Sporks: %llu", mapSporksActive.size());
|
|
|
|
}
|
|
|
|
|
2018-02-16 15:54:53 +01:00
|
|
|
uint256 CSporkMessage::GetHash() const
|
|
|
|
{
|
|
|
|
return SerializeHash(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint256 CSporkMessage::GetSignatureHash() const
|
|
|
|
{
|
2018-09-30 19:01:33 +02:00
|
|
|
CHashWriter s(SER_GETHASH, 0);
|
|
|
|
s << nSporkID;
|
|
|
|
s << nValue;
|
|
|
|
s << nTimeSigned;
|
|
|
|
return s.GetHash();
|
2018-02-16 15:54:53 +01:00
|
|
|
}
|
|
|
|
|
2018-08-22 16:46:27 +02:00
|
|
|
bool CSporkMessage::Sign(const CKey& key, bool fSporkSixActive)
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2018-06-19 01:40:55 +02:00
|
|
|
if (!key.IsValid()) {
|
|
|
|
LogPrintf("CSporkMessage::Sign -- signing key is not valid\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
CKeyID pubKeyId = key.GetPubKey().GetID();
|
2016-08-19 13:50:04 +02:00
|
|
|
std::string strError = "";
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-08-22 16:46:27 +02:00
|
|
|
if (fSporkSixActive) {
|
2018-02-16 15:54:53 +01:00
|
|
|
uint256 hash = GetSignatureHash();
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-02-16 15:54:53 +01:00
|
|
|
if(!CHashSigner::SignHash(hash, key, vchSig)) {
|
|
|
|
LogPrintf("CSporkMessage::Sign -- SignHash() failed\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
|
2018-02-16 15:54:53 +01:00
|
|
|
LogPrintf("CSporkMessage::Sign -- VerifyHash() failed, error: %s\n", strError);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
2018-07-12 11:02:20 +02:00
|
|
|
std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
|
2018-02-16 15:54:53 +01:00
|
|
|
|
|
|
|
if(!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
|
|
|
|
LogPrintf("CSporkMessage::Sign -- SignMessage() failed\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
if(!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)) {
|
2018-02-16 15:54:53 +01:00
|
|
|
LogPrintf("CSporkMessage::Sign -- VerifyMessage() failed, error: %s\n", strError);
|
|
|
|
return false;
|
|
|
|
}
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-22 16:46:27 +02:00
|
|
|
bool CSporkMessage::CheckSignature(const CKeyID& pubKeyId, bool fSporkSixActive) const
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2016-08-19 13:50:04 +02:00
|
|
|
std::string strError = "";
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-08-22 16:46:27 +02:00
|
|
|
if (fSporkSixActive) {
|
2018-02-16 15:54:53 +01:00
|
|
|
uint256 hash = GetSignatureHash();
|
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
|
2018-02-16 15:54:53 +01:00
|
|
|
// Note: unlike for many other messages when SPORK_6_NEW_SIGS is ON sporks with sigs in old format
|
|
|
|
// and newer timestamps should not be accepted, so if we failed here - that's it
|
|
|
|
LogPrintf("CSporkMessage::CheckSignature -- VerifyHash() failed, error: %s\n", strError);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
2018-07-12 11:02:20 +02:00
|
|
|
std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
|
2018-02-16 15:54:53 +01:00
|
|
|
|
2018-03-02 14:15:04 +01:00
|
|
|
if (!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)){
|
2018-05-13 22:57:32 +02:00
|
|
|
// Note: unlike for other messages we have to check for new format even with SPORK_6_NEW_SIGS
|
|
|
|
// inactive because SPORK_6_NEW_SIGS default is OFF and it is not the first spork to sync
|
|
|
|
// (and even if it would, spork order can't be guaranteed anyway).
|
|
|
|
uint256 hash = GetSignatureHash();
|
|
|
|
if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
|
|
|
|
LogPrintf("CSporkMessage::CheckSignature -- VerifyHash() failed, error: %s\n", strError);
|
|
|
|
return false;
|
|
|
|
}
|
2018-02-16 15:54:53 +01:00
|
|
|
}
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
2016-07-30 13:04:27 +02:00
|
|
|
return true;
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
bool CSporkMessage::GetSignerKeyID(CKeyID &retKeyidSporkSigner, bool fSporkSixActive)
|
|
|
|
{
|
|
|
|
CPubKey pubkeyFromSig;
|
|
|
|
if (fSporkSixActive) {
|
|
|
|
if (!pubkeyFromSig.RecoverCompact(GetSignatureHash(), vchSig)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
|
|
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
|
|
ss << strMessageMagic;
|
|
|
|
ss << strMessage;
|
|
|
|
if (!pubkeyFromSig.RecoverCompact(ss.GetHash(), vchSig)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
retKeyidSporkSigner = pubkeyFromSig.GetID();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-07 17:58:38 +02:00
|
|
|
void CSporkMessage::Relay(CConnman& connman)
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2016-07-30 13:04:27 +02:00
|
|
|
CInv inv(MSG_SPORK, GetHash());
|
2017-09-07 17:58:38 +02:00
|
|
|
connman.RelayInv(inv);
|
2015-04-03 00:51:08 +02:00
|
|
|
}
|