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
|
|
|
|
2015-02-26 15:02:39 +01:00
|
|
|
CSporkManager sporkManager;
|
|
|
|
|
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
|
|
|
|
2018-04-18 13:50:26 +02:00
|
|
|
std::map<int, int64_t> mapSporkDefaults = {
|
|
|
|
{SPORK_2_INSTANTSEND_ENABLED, 0}, // ON
|
|
|
|
{SPORK_3_INSTANTSEND_BLOCK_FILTERING, 0}, // ON
|
|
|
|
{SPORK_5_INSTANTSEND_MAX_VALUE, 1000}, // 1000 Dash
|
|
|
|
{SPORK_6_NEW_SIGS, 4070908800ULL}, // OFF
|
|
|
|
{SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL}, // OFF
|
|
|
|
{SPORK_12_RECONSIDER_BLOCKS, 0}, // 0 BLOCKS
|
2019-02-14 19:24:06 +01:00
|
|
|
{SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL}, // OFF
|
2018-09-26 16:17:47 +02:00
|
|
|
{SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL}, // OFF
|
2018-11-26 16:53:20 +01:00
|
|
|
{SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL}, // OFF
|
2019-01-30 19:53:03 +01:00
|
|
|
{SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL}, // OFF
|
2019-03-04 08:04:18 +01:00
|
|
|
{SPORK_20_INSTANTSEND_LLMQ_BASED, 4070908800ULL}, // OFF
|
2018-04-18 13:50:26 +02:00
|
|
|
};
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
bool CSporkManager::SporkValueIsActive(int nSporkID, int64_t &nActiveValueRet) const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
strLogMsg = strprintf("SPORK -- hash: %s id: %d value: %10d bestHeight: %d peer=%d", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Height(), pfrom->id);
|
|
|
|
}
|
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) {
|
|
|
|
LogPrint("spork", "%s seen\n", strLogMsg);
|
|
|
|
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
|
|
|
|
2015-02-12 05:05:09 +01:00
|
|
|
//does a task if needed
|
2018-09-30 19:01:33 +02:00
|
|
|
int64_t nActiveValue = 0;
|
|
|
|
if (SporkValueIsActive(spork.nSporkID, nActiveValue)) {
|
|
|
|
ExecuteSpork(spork.nSporkID, nActiveValue);
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-07-30 13:04:27 +02:00
|
|
|
void CSporkManager::ExecuteSpork(int nSporkID, int nValue)
|
|
|
|
{
|
|
|
|
//correct fork via spork technology
|
|
|
|
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS && nValue > 0) {
|
2017-02-04 01:42:04 +01:00
|
|
|
// allow to reprocess 24h of blocks max, which should be enough to resolve any issues
|
|
|
|
int64_t nMaxBlocks = 576;
|
|
|
|
// this potentially can be a heavy operation, so only allow this to be executed once per 10 minutes
|
|
|
|
int64_t nTimeout = 10 * 60;
|
|
|
|
|
|
|
|
static int64_t nTimeExecuted = 0; // i.e. it was never executed before
|
|
|
|
|
|
|
|
if(GetTime() - nTimeExecuted < nTimeout) {
|
|
|
|
LogPrint("spork", "CSporkManager::ExecuteSpork -- ERROR: Trying to reconsider blocks, too soon - %d/%d\n", GetTime() - nTimeExecuted, nTimeout);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nValue > nMaxBlocks) {
|
|
|
|
LogPrintf("CSporkManager::ExecuteSpork -- ERROR: Trying to reconsider too many blocks %d/%d\n", nValue, nMaxBlocks);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-30 13:04:27 +02:00
|
|
|
LogPrintf("CSporkManager::ExecuteSpork -- Reconsider Last %d Blocks\n", nValue);
|
|
|
|
|
|
|
|
ReprocessBlocks(nValue);
|
2017-02-04 01:42:04 +01:00
|
|
|
nTimeExecuted = GetTime();
|
2016-07-30 13:04:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-07 17:58:38 +02:00
|
|
|
bool CSporkManager::UpdateSpork(int 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
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
bool fSpork6IsActive = IsSporkActive(SPORK_6_NEW_SIGS);
|
|
|
|
if(spork.Sign(sporkPrivKey, fSpork6IsActive)) {
|
|
|
|
CKeyID keyIDSigner;
|
|
|
|
if (!spork.GetSignerKeyID(keyIDSigner, fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
|
|
|
|
LogPrintf("CSporkManager::UpdateSpork: failed to find keyid for private key\n");
|
|
|
|
return false;
|
|
|
|
}
|
2019-03-18 14:50:55 +01:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
mapSporksByHash[spork.GetHash()] = spork;
|
|
|
|
mapSporksActive[nSporkID][keyIDSigner] = spork;
|
|
|
|
}
|
2017-09-07 17:58:38 +02:00
|
|
|
spork.Relay(connman);
|
2016-07-30 13:04:27 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CSporkManager::IsSporkActive(int nSporkID)
|
2015-02-09 21:54:51 +01:00
|
|
|
{
|
2018-08-11 00:34:28 +02:00
|
|
|
LOCK(cs);
|
2018-09-30 19:01:33 +02:00
|
|
|
int64_t nSporkValue = -1;
|
2015-02-09 21:54:51 +01:00
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
if (SporkValueIsActive(nSporkID, nSporkValue)) {
|
|
|
|
return nSporkValue < GetAdjustedTime();
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
2018-09-30 19:01:33 +02:00
|
|
|
if (mapSporkDefaults.count(nSporkID)) {
|
|
|
|
return mapSporkDefaults[nSporkID] < GetAdjustedTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
LogPrint("spork", "CSporkManager::IsSporkActive -- Unknown Spork ID %d\n", nSporkID);
|
|
|
|
return false;
|
2015-02-09 21:54:51 +01:00
|
|
|
}
|
|
|
|
|
2016-07-30 13:04:27 +02:00
|
|
|
int64_t CSporkManager::GetSporkValue(int 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
|
|
|
|
2018-04-18 13:50:26 +02:00
|
|
|
if (mapSporkDefaults.count(nSporkID)) {
|
|
|
|
return mapSporkDefaults[nSporkID];
|
2015-02-11 15:47:21 +01:00
|
|
|
}
|
|
|
|
|
2018-04-18 13:50:26 +02:00
|
|
|
LogPrint("spork", "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
|
|
|
|
return -1;
|
2015-02-11 15:47:21 +01:00
|
|
|
}
|
|
|
|
|
2018-02-12 13:49:00 +01:00
|
|
|
int CSporkManager::GetSporkIDByName(const std::string& strName)
|
2015-02-12 05:05:09 +01:00
|
|
|
{
|
2016-09-01 16:55:25 +02:00
|
|
|
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;
|
2018-02-15 15:44:22 +01:00
|
|
|
if (strName == "SPORK_6_NEW_SIGS") return SPORK_6_NEW_SIGS;
|
2016-08-29 21:16:02 +02:00
|
|
|
if (strName == "SPORK_9_SUPERBLOCKS_ENABLED") return SPORK_9_SUPERBLOCKS_ENABLED;
|
|
|
|
if (strName == "SPORK_12_RECONSIDER_BLOCKS") return SPORK_12_RECONSIDER_BLOCKS;
|
2019-02-14 19:24:06 +01:00
|
|
|
if (strName == "SPORK_15_DETERMINISTIC_MNS_ENABLED") return SPORK_15_DETERMINISTIC_MNS_ENABLED;
|
2018-09-26 16:17:47 +02:00
|
|
|
if (strName == "SPORK_16_INSTANTSEND_AUTOLOCKS") return SPORK_16_INSTANTSEND_AUTOLOCKS;
|
2018-11-26 16:53:20 +01:00
|
|
|
if (strName == "SPORK_17_QUORUM_DKG_ENABLED") return SPORK_17_QUORUM_DKG_ENABLED;
|
2019-01-23 17:40:37 +01:00
|
|
|
if (strName == "SPORK_19_CHAINLOCKS_ENABLED") return SPORK_19_CHAINLOCKS_ENABLED;
|
2019-03-04 08:04:18 +01:00
|
|
|
if (strName == "SPORK_20_INSTANTSEND_LLMQ_BASED") return SPORK_20_INSTANTSEND_LLMQ_BASED;
|
2016-08-29 21:16:02 +02:00
|
|
|
|
2016-09-15 08:50:16 +02:00
|
|
|
LogPrint("spork", "CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
|
2016-07-30 13:04:27 +02:00
|
|
|
return -1;
|
2015-08-03 01:08:37 +02:00
|
|
|
}
|
2015-08-02 23:59:28 +02:00
|
|
|
|
2016-07-30 13:04:27 +02:00
|
|
|
std::string CSporkManager::GetSporkNameByID(int nSporkID)
|
|
|
|
{
|
2016-08-29 21:16:02 +02:00
|
|
|
switch (nSporkID) {
|
2016-09-01 16:55:25 +02:00
|
|
|
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";
|
2018-02-15 15:44:22 +01:00
|
|
|
case SPORK_6_NEW_SIGS: return "SPORK_6_NEW_SIGS";
|
2016-08-29 21:16:02 +02:00
|
|
|
case SPORK_9_SUPERBLOCKS_ENABLED: return "SPORK_9_SUPERBLOCKS_ENABLED";
|
2016-09-01 16:55:25 +02:00
|
|
|
case SPORK_12_RECONSIDER_BLOCKS: return "SPORK_12_RECONSIDER_BLOCKS";
|
2019-02-14 19:24:06 +01:00
|
|
|
case SPORK_15_DETERMINISTIC_MNS_ENABLED: return "SPORK_15_DETERMINISTIC_MNS_ENABLED";
|
2018-09-26 16:17:47 +02:00
|
|
|
case SPORK_16_INSTANTSEND_AUTOLOCKS: return "SPORK_16_INSTANTSEND_AUTOLOCKS";
|
2018-11-26 16:53:20 +01:00
|
|
|
case SPORK_17_QUORUM_DKG_ENABLED: return "SPORK_17_QUORUM_DKG_ENABLED";
|
2019-01-23 17:40:37 +01:00
|
|
|
case SPORK_19_CHAINLOCKS_ENABLED: return "SPORK_19_CHAINLOCKS_ENABLED";
|
2019-03-04 08:04:18 +01:00
|
|
|
case SPORK_20_INSTANTSEND_LLMQ_BASED: return "SPORK_20_INSTANTSEND_LLMQ_BASED";
|
2016-08-29 21:16:02 +02:00
|
|
|
default:
|
2016-09-15 08:50:16 +02:00
|
|
|
LogPrint("spork", "CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
|
2016-08-29 21:16:02 +02:00
|
|
|
return "Unknown";
|
|
|
|
}
|
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;
|
2018-08-22 16:46:27 +02:00
|
|
|
if (spork.Sign(key, IsSporkActive(SPORK_6_NEW_SIGS))) {
|
2018-08-11 00:34:28 +02:00
|
|
|
LOCK(cs);
|
2016-07-30 13:04:27 +02:00
|
|
|
// Test signing successful, proceed
|
|
|
|
LogPrintf("CSporkManager::SetPrivKey -- Successfully initialized as spork signer\n");
|
2018-03-02 14:15:04 +01:00
|
|
|
|
|
|
|
sporkPrivKey = key;
|
2016-07-30 13:04:27 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|