dash/src/spork.cpp

447 lines
15 KiB
C++
Raw Normal View History

// Copyright (c) 2014-2019 The Dash Core developers
// 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
#include "spork.h"
#include "base58.h"
#include "chainparams.h"
#include "validation.h"
#include "messagesigner.h"
#include "net_processing.h"
#include "netmessagemaker.h"
2015-02-09 21:54:51 +01:00
#include <string>
2015-02-09 21:54:51 +01:00
const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-Version-2";
2018-09-26 16:15:02 +02:00
#define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name}
std::vector<CSporkDef> sporkDefs = {
Remove legacy InstantSend code (#3020) * Remove ppszTypeName from protocol.cpp and reimplement GetCommand This removes the need to carefully maintain ppszTypeName, which required correct order and also did not allow to permanently remove old message types. To get the command name for an INV type, GetCommandInternal uses a switch which needs to be maintained from now on. The way this is implemented also resembles the way it is implemented in Bitcoin today, but it's not identical. The original PR that introduced the switch case in Bitcoin was part of the Segwit changes and thus never got backported. I decided to implement it in a slightly different way that avoids throwing exceptions when an unknown INV type is encountered. IsKnownType will now also leverage GetCommandInternal() to figure out if the INV type is known locally. This has the side effect of old/legacy message types to return false from now on. We will depend on this side effect in later commits when we remove legacy InstantSend code. * Stop handling/relaying legacy IX messages When we receive an IX message, we simply treat it as a regular TX and relay it as such. We'll however still request IX messages when they are announced to us. We can't simply revert to requesting TX messages in this case as it might result in the other peer not answering due to the TX not being in mapRelay yet. We should at some point in the future completely drop handling of IX messages instead. * Remove IsNewInstantSendEnabled() and only use IsInstantSendEnabled() * Remove legacy InstantSend from GUI * Remove InstantSend from Bitcoin/Dash URIs * Remove legacy InstantSend from RPC commands * Remove legacy InstantSend from wallet * Remove legacy instantsend.h include * Remove legacy InstantSend from validation code * Completely remove remaining legacy InstantSend code * Remove now unused spork * Fix InstantSend related test failures * Remove now obsolete auto IS tests * Make spork2 and spork3 disabled by default This should have no influence on mainnet as these sporks are actually set there. This will however affect regtest, which shouldn't have LLMQ based InstantSend enabled by default. * Remove instantsend tests from dip3-deterministicmns.py These were only testing legacy InstantSend * Fix .QCheckBox#checkUsePrivateSend styling a bit * s/TXLEGACYLOCKREQUEST/LEGACYTXLOCKREQUEST/ * Revert "verified via InstantSend" back to "verified via LLMQ based InstantSend" * Use cmd == nullptr instead of !cmd * Remove last parameter from AvailableCoins call This was for fUseInstantSend which is not present anymore since rebase
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
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
};
2015-02-09 21:54:51 +01: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
{
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;
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;
}
void CSporkManager::Clear()
{
LOCK(cs);
mapSporksActive.clear();
mapSporksByHash.clear();
// sporkPubKeyID and sporkPrivKey should be set in init.cpp,
// we should not alter them here.
}
2018-09-26 16:15:02 +02:00
void CSporkManager::CheckAndRemove()
{
LOCK(cs);
bool fSporkAddressIsSet = !setSporkPubKeyIDs.empty();
2018-09-26 16:15:02 +02:00
assert(fSporkAddressIsSet);
auto itActive = mapSporksActive.begin();
while (itActive != mapSporksActive.end()) {
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;
}
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-26 16:15:02 +02:00
auto itByHash = mapSporksByHash.begin();
while (itByHash != mapSporksByHash.end()) {
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
}
}
if (!found) {
mapSporksByHash.erase(itByHash++);
continue;
}
2018-09-26 16:15:02 +02:00
++itByHash;
}
}
void CSporkManager::ProcessSpork(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
2015-02-09 21:54:51 +01:00
{
if(fLiteMode) return; // disable all Dash specific functionality
2015-02-09 21:54:51 +01:00
if (strCommand == NetMsgType::SPORK) {
2015-02-09 21:54:51 +01:00
CSporkMessage spork;
vRecv >> spork;
uint256 hash = spork.GetHash();
std::string strLogMsg;
{
LOCK(cs_main);
connman.RemoveAskFor(hash);
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->GetId());
}
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;
}
CKeyID keyIDSigner;
bool fSpork6IsActive = IsSporkActive(SPORK_6_NEW_SIGS);
if (!spork.GetSignerKeyID(keyIDSigner, fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
// 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).
if (!spork.GetSignerKeyID(keyIDSigner, !fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
LOCK(cs_main);
LogPrintf("CSporkManager::ProcessSpork -- ERROR: invalid signature\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
}
{
LOCK(cs); // make sure to not lock this together with cs_main
if (mapSporksActive.count(spork.nSporkID)) {
if (mapSporksActive[spork.nSporkID].count(keyIDSigner)) {
if (mapSporksActive[spork.nSporkID][keyIDSigner].nTimeSigned >= spork.nTimeSigned) {
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
LogPrint(BCLog::SPORK, "%s seen\n", strLogMsg);
return;
} else {
LogPrintf("%s updated\n", strLogMsg);
}
} else {
LogPrintf("%s new signer\n", strLogMsg);
}
2015-02-09 21:54:51 +01:00
} else {
LogPrintf("%s new\n", strLogMsg);
2015-02-09 21:54:51 +01:00
}
}
{
LOCK(cs); // make sure to not lock this together with cs_main
mapSporksByHash[hash] = spork;
mapSporksActive[spork.nSporkID][keyIDSigner] = spork;
}
spork.Relay(connman);
2015-02-09 21:54:51 +01:00
} else if (strCommand == NetMsgType::GETSPORKS) {
LOCK(cs); // make sure to not lock this together with cs_main
for (const auto& pair : mapSporksActive) {
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
}
}
}
bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman& connman)
{
CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetAdjustedTime());
LOCK(cs);
bool fSpork6IsActive = IsSporkActive(SPORK_6_NEW_SIGS);
if (!spork.Sign(sporkPrivKey, fSpork6IsActive)) {
LogPrintf("CSporkManager::%s -- ERROR: signing failed for spork %d\n", __func__, nSporkID);
return false;
}
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;
}
bool CSporkManager::IsSporkActive(SporkId nSporkID)
2015-02-09 21:54:51 +01:00
{
int64_t nSporkValue = GetSporkValue(nSporkID);
return nSporkValue < GetAdjustedTime();
2015-02-09 21:54:51 +01:00
}
int64_t CSporkManager::GetSporkValue(SporkId nSporkID)
2015-02-11 15:47:21 +01:00
{
LOCK(cs);
int64_t nSporkValue = -1;
if (SporkValueIsActive(nSporkID, nSporkValue)) {
return nSporkValue;
}
auto it = sporkDefsById.find(nSporkID);
if (it != sporkDefsById.end()) {
return it->second->defaultValue;
2015-02-11 15:47:21 +01:00
}
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
return -1;
2015-02-11 15:47:21 +01:00
}
SporkId CSporkManager::GetSporkIDByName(const std::string& strName)
2015-02-12 05:05:09 +01: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
std::string CSporkManager::GetSporkNameByID(SporkId nSporkID)
{
auto it = sporkDefsById.find(nSporkID);
if (it == sporkDefsById.end()) {
LogPrint(BCLog::SPORK, "CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
return "Unknown";
}
return it->second->name;
2015-02-12 05:05:09 +01: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;
}
bool CSporkManager::SetSporkAddress(const std::string& strAddress) {
LOCK(cs);
CBitcoinAddress address(strAddress);
CKeyID keyid;
if (!address.IsValid() || !address.GetKeyID(keyid)) {
LogPrintf("CSporkManager::SetSporkAddress -- Failed to parse spork address\n");
return false;
}
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;
return true;
}
bool CSporkManager::SetPrivKey(const std::string& strPrivKey)
2015-02-09 21:54:51 +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
if (setSporkPubKeyIDs.find(pubKey.GetID()) == setSporkPubKeyIDs.end()) {
LogPrintf("CSporkManager::SetPrivKey -- New private key does not belong to spork addresses\n");
return false;
}
CSporkMessage spork;
if (!spork.Sign(key, IsSporkActive(SPORK_6_NEW_SIGS))) {
LogPrintf("CSporkManager::SetPrivKey -- Test signing failed\n");
2015-02-09 21:54:51 +01:00
return false;
}
// 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
}
std::string CSporkManager::ToString() const
{
LOCK(cs);
return strprintf("Sporks: %llu", mapSporksActive.size());
}
uint256 CSporkMessage::GetHash() const
{
return SerializeHash(*this);
}
uint256 CSporkMessage::GetSignatureHash() const
{
CHashWriter s(SER_GETHASH, 0);
s << nSporkID;
s << nValue;
s << nTimeSigned;
return s.GetHash();
}
bool CSporkMessage::Sign(const CKey& key, bool fSporkSixActive)
2015-02-09 21:54:51 +01:00
{
if (!key.IsValid()) {
LogPrintf("CSporkMessage::Sign -- signing key is not valid\n");
return false;
}
CKeyID pubKeyId = key.GetPubKey().GetID();
std::string strError = "";
2015-02-09 21:54:51 +01:00
if (fSporkSixActive) {
uint256 hash = GetSignatureHash();
2015-02-09 21:54:51 +01:00
if(!CHashSigner::SignHash(hash, key, vchSig)) {
LogPrintf("CSporkMessage::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
LogPrintf("CSporkMessage::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
if(!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
LogPrintf("CSporkMessage::Sign -- SignMessage() failed\n");
return false;
}
if(!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)) {
LogPrintf("CSporkMessage::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
2015-02-09 21:54:51 +01:00
}
return true;
}
bool CSporkMessage::CheckSignature(const CKeyID& pubKeyId, bool fSporkSixActive) const
2015-02-09 21:54:51 +01:00
{
std::string strError = "";
2015-02-09 21:54:51 +01:00
if (fSporkSixActive) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) {
// 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 {
std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
if (!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)){
// 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;
}
}
2015-02-09 21:54:51 +01:00
}
return true;
2015-02-09 21:54:51 +01: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;
}
void CSporkMessage::Relay(CConnman& connman)
2015-02-09 21:54:51 +01:00
{
CInv inv(MSG_SPORK, GetHash());
connman.RelayInv(inv);
2015-04-03 00:51:08 +02:00
}