Merge #922: Refactor/fix spork
42bdf42 Refactor/fix spork: - move ProcessSpork, GetSporkValue, IsSporkActive, ExecuteSpork and mapSporksActive to CSporkManager - move Sign, CheckSignature, Relay to CSporkMessage - move ReprocessBlocks out of sporks to main.cpp / rename DisconnectBlocksAndReprocess to DisconnectBlocks - rename SporkKey to SporkPubKey - bugfix: only set strMasterPrivKey if spork signature produced by that key was verified successfully - few log format changes, cleaned up includes
This commit is contained in:
parent
7551d2da26
commit
d514ee7f9a
@ -148,7 +148,7 @@ public:
|
||||
fTestnetToBeDeprecatedFieldRPC = false;
|
||||
|
||||
nPoolMaxTransactions = 3;
|
||||
strSporkKey = "04549ac134f694c0243f503e8c8a9a986f5de6610049c40b07816809b0d1d06a21b07be27b9bb555931773f62ba6cf35a25fd52f694d4e1106ccd237a7bb899fdd";
|
||||
strSporkPubKey = "04549ac134f694c0243f503e8c8a9a986f5de6610049c40b07816809b0d1d06a21b07be27b9bb555931773f62ba6cf35a25fd52f694d4e1106ccd237a7bb899fdd";
|
||||
strMasternodePaymentsPubKey = "04549ac134f694c0243f503e8c8a9a986f5de6610049c40b07816809b0d1d06a21b07be27b9bb555931773f62ba6cf35a25fd52f694d4e1106ccd237a7bb899fdd";
|
||||
|
||||
checkpointData = (CCheckpointData) {
|
||||
@ -257,7 +257,7 @@ public:
|
||||
fTestnetToBeDeprecatedFieldRPC = true;
|
||||
|
||||
nPoolMaxTransactions = 2;
|
||||
strSporkKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
|
||||
strSporkPubKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
|
||||
strMasternodePaymentsPubKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
|
||||
checkpointData = (CCheckpointData) {
|
||||
boost::assign::map_list_of
|
||||
|
@ -78,7 +78,7 @@ public:
|
||||
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
|
||||
const CCheckpointData& Checkpoints() const { return checkpointData; }
|
||||
int PoolMaxTransactions() const { return nPoolMaxTransactions; }
|
||||
std::string SporkKey() const { return strSporkKey; }
|
||||
std::string SporkPubKey() const { return strSporkPubKey; }
|
||||
std::string MasternodePaymentPubKey() const { return strMasternodePaymentsPubKey; }
|
||||
protected:
|
||||
CChainParams() {}
|
||||
@ -102,7 +102,7 @@ protected:
|
||||
bool fTestnetToBeDeprecatedFieldRPC;
|
||||
CCheckpointData checkpointData;
|
||||
int nPoolMaxTransactions;
|
||||
std::string strSporkKey;
|
||||
std::string strSporkPubKey;
|
||||
std::string strMasternodePaymentsPubKey;
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ int nCompleteTXLocks;
|
||||
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
{
|
||||
if(fLiteMode) return; //disable all darksend/masternode related functionality
|
||||
if(!IsSporkActive(SPORK_2_INSTANTX)) return;
|
||||
if(!sporkManager.IsSporkActive(SPORK_2_INSTANTX)) return;
|
||||
if(!masternodeSync.IsBlockchainSynced()) return;
|
||||
|
||||
if (strCommand == NetMsgType::IX)
|
||||
@ -192,8 +192,8 @@ bool IsIXTXValid(const CTransaction& txCollateral){
|
||||
}
|
||||
}
|
||||
|
||||
if(nValueOut > GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
|
||||
LogPrint("instantsend", "IsIXTXValid - Transaction value too high - %s\n", txCollateral.ToString());
|
||||
if(nValueOut > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
|
||||
LogPrint("instantsend", "IsIXTXValid -- Transaction value too high: nValueOut=%d, txCollateral=%s", nValueOut, txCollateral.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -508,7 +508,7 @@ bool IsLockedIXTransaction(uint256 txHash) {
|
||||
int GetTransactionLockSignatures(uint256 txHash)
|
||||
{
|
||||
if(fLargeWorkForkFound || fLargeWorkInvalidChainFound) return -2;
|
||||
if(!IsSporkActive(SPORK_2_INSTANTX)) return -3;
|
||||
if(!sporkManager.IsSporkActive(SPORK_2_INSTANTX)) return -3;
|
||||
if(!fEnableInstantSend) return -1;
|
||||
|
||||
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(txHash);
|
||||
|
39
src/main.cpp
39
src/main.cpp
@ -2896,20 +2896,51 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisconnectBlocksAndReprocess(int blocks)
|
||||
bool DisconnectBlocks(int blocks)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
||||
CValidationState state;
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
LogPrintf("DisconnectBlocksAndReprocess: Got command to replay %d blocks\n", blocks);
|
||||
LogPrintf("DisconnectBlocks -- Got command to replay %d blocks\n", blocks);
|
||||
for(int i = 0; i <= blocks; i++)
|
||||
DisconnectTip(state, chainparams.GetConsensus());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReprocessBlocks(int nBlocks)
|
||||
{
|
||||
std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin();
|
||||
while(it != mapRejectedBlocks.end()){
|
||||
//use a window twice as large as is usual for the nBlocks we want to reset
|
||||
if((*it).second > GetTime() - (nBlocks*60*5)) {
|
||||
BlockMap::iterator mi = mapBlockIndex.find((*it).first);
|
||||
if (mi != mapBlockIndex.end() && (*mi).second) {
|
||||
LOCK(cs_main);
|
||||
|
||||
CBlockIndex* pindex = (*mi).second;
|
||||
LogPrintf("ReprocessBlocks -- %s\n", (*it).first.ToString());
|
||||
|
||||
CValidationState state;
|
||||
ReconsiderBlock(state, pindex);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
DisconnectBlocks(nBlocks);
|
||||
}
|
||||
|
||||
if (state.IsValid()) {
|
||||
ActivateBestChain(state, Params());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tip of the chain with the most work in it, that isn't
|
||||
* known to be invalid (it's however far from certain to be valid).
|
||||
@ -3443,7 +3474,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
||||
|
||||
// ----------- instantX transaction scanning -----------
|
||||
|
||||
if(IsSporkActive(SPORK_3_INSTANTX_BLOCK_FILTERING)){
|
||||
if(sporkManager.IsSporkActive(SPORK_3_INSTANTX_BLOCK_FILTERING)){
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
||||
if (!tx.IsCoinBase()){
|
||||
//only reject blocks when it's based on complete consensus
|
||||
@ -5917,7 +5948,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
mnodeman.ProcessMessage(pfrom, strCommand, vRecv);
|
||||
mnpayments.ProcessMessage(pfrom, strCommand, vRecv);
|
||||
ProcessMessageInstantX(pfrom, strCommand, vRecv);
|
||||
ProcessSpork(pfrom, strCommand, vRecv);
|
||||
sporkManager.ProcessSpork(pfrom, strCommand, vRecv);
|
||||
masternodeSync.ProcessMessage(pfrom, strCommand, vRecv);
|
||||
governance.ProcessMessage(pfrom, strCommand, vRecv);
|
||||
}
|
||||
|
@ -455,7 +455,8 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus
|
||||
bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
|
||||
|
||||
/** Reprocess a number of blocks to try and get on the correct chain again **/
|
||||
bool DisconnectBlocksAndReprocess(int blocks);
|
||||
bool DisconnectBlocks(int blocks);
|
||||
void ReprocessBlocks(int nBlocks);
|
||||
|
||||
/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
|
||||
|
@ -52,10 +52,10 @@ bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue){
|
||||
} else { // we're synced and have data so check the budget schedule
|
||||
|
||||
//are these blocks even enabled
|
||||
if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
|
||||
if(!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
|
||||
return block.vtx[0].GetValueOut() <= nExpectedValue;
|
||||
}
|
||||
|
||||
|
||||
// 12.1
|
||||
// if(nHeight >= Params().GetConsensus().nBudgetPaymentsStartBlock &&
|
||||
// budget.IsBudgetPaymentBlock(nHeight)){
|
||||
@ -77,14 +77,14 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
|
||||
}
|
||||
|
||||
//check if it's a budget block
|
||||
// 12.1
|
||||
// if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
|
||||
// 12.1
|
||||
// if(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
|
||||
// if(budget.IsBudgetPaymentBlock(nBlockHeight)){
|
||||
// if(budget.IsTransactionValid(txNew, nBlockHeight)){
|
||||
// return true;
|
||||
// } else {
|
||||
// LogPrintf("Invalid budget payment detected %s\n", txNew.ToString());
|
||||
// if(IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
|
||||
// LogPrintf("Invalid budget payment detected %s", txNew.ToString());
|
||||
// if(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
|
||||
// return false;
|
||||
// } else {
|
||||
// LogPrintf("Budget enforcement is disabled, accepting block\n");
|
||||
@ -99,8 +99,8 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
LogPrintf("Invalid mn payment detected %s\n", txNew.ToString());
|
||||
if(IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)){
|
||||
LogPrintf("Invalid mn payment detected %s", txNew.ToString());
|
||||
if(sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)){
|
||||
return false;
|
||||
} else {
|
||||
LogPrintf("Masternode payment enforcement is disabled, accepting block\n");
|
||||
@ -118,7 +118,7 @@ void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees)
|
||||
if(!chainActive.Tip()) return;
|
||||
|
||||
// 12.1
|
||||
// if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(chainActive.Tip()->nHeight+1)){
|
||||
// if(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(chainActive.Tip()->nHeight+1)){
|
||||
// budget.FillBlockPayee(txNew, nFees);
|
||||
// } else {
|
||||
// mnpayments.FillBlockPayee(txNew, nFees);
|
||||
@ -130,7 +130,7 @@ std::string GetRequiredPaymentsString(int nBlockHeight)
|
||||
{
|
||||
// 12.1 -- added triggered payments
|
||||
|
||||
// if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)){
|
||||
// if(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)){
|
||||
// return budget.GetRequiredPaymentsString(nBlockHeight);
|
||||
// } else {
|
||||
// return mnpayments.GetRequiredPaymentsString(nBlockHeight);
|
||||
@ -181,7 +181,7 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, CAmount nFe
|
||||
}
|
||||
|
||||
int CMasternodePayments::GetMinMasternodePaymentsProto() {
|
||||
return IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)
|
||||
return sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)
|
||||
? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
|
||||
: MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
|
||||
}
|
||||
|
@ -293,8 +293,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||
CWalletTx *newTx = transaction.getTransaction();
|
||||
CReserveKey *keyChange = transaction.getPossibleKeyChange();
|
||||
|
||||
if(recipients[0].useInstantX && total > GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
|
||||
Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(GetSporkValue(SPORK_5_MAX_VALUE)),
|
||||
if(recipients[0].useInstantX && total > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
|
||||
Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)),
|
||||
CClientUIInterface::MSG_ERROR);
|
||||
return TransactionCreationFailed;
|
||||
}
|
||||
@ -304,8 +304,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||
if (fSubtractFeeFromAmount && fCreated)
|
||||
transaction.reassignAmounts(nChangePosRet);
|
||||
|
||||
if(recipients[0].useInstantX && newTx->GetValueOut() > GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
|
||||
Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(GetSporkValue(SPORK_5_MAX_VALUE)),
|
||||
if(recipients[0].useInstantX && newTx->GetValueOut() > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
|
||||
Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)),
|
||||
CClientUIInterface::MSG_ERROR);
|
||||
return TransactionCreationFailed;
|
||||
}
|
||||
|
@ -610,7 +610,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||
}
|
||||
|
||||
result.push_back(Pair("masternode_payments", (int64_t)(pindexPrev->nHeight+1) > Params().GetConsensus().nMasternodePaymentsStartBlock));
|
||||
result.push_back(Pair("enforce_masternode_payments", IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)));
|
||||
result.push_back(Pair("enforce_masternode_payments", sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -236,14 +236,14 @@ UniValue spork(const UniValue& params, bool fHelp)
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
for(int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++){
|
||||
if(sporkManager.GetSporkNameByID(nSporkID) != "Unknown")
|
||||
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), GetSporkValue(nSporkID)));
|
||||
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), sporkManager.GetSporkValue(nSporkID)));
|
||||
}
|
||||
return ret;
|
||||
} else if(params.size() == 1 && params[0].get_str() == "active"){
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
for(int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++){
|
||||
if(sporkManager.GetSporkNameByID(nSporkID) != "Unknown")
|
||||
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), IsSporkActive(nSporkID)));
|
||||
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), sporkManager.IsSporkActive(nSporkID)));
|
||||
}
|
||||
return ret;
|
||||
} else if (params.size() == 2){
|
||||
@ -257,7 +257,7 @@ UniValue spork(const UniValue& params, bool fHelp)
|
||||
|
||||
//broadcast new spork
|
||||
if(sporkManager.UpdateSpork(nSporkID, nValue)){
|
||||
ExecuteSpork(nSporkID, nValue);
|
||||
sporkManager.ExecuteSpork(nSporkID, nValue);
|
||||
return "success";
|
||||
} else {
|
||||
return "failure";
|
||||
|
317
src/spork.cpp
317
src/spork.cpp
@ -2,22 +2,11 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
#include "key.h"
|
||||
#include "util.h"
|
||||
#include "base58.h"
|
||||
#include "darksend.h"
|
||||
#include "protocol.h"
|
||||
#include "spork.h"
|
||||
#include "main.h"
|
||||
#include "governance.h"
|
||||
#include "consensus/validation.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "spork.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
class CSporkMessage;
|
||||
class CSporkManager;
|
||||
@ -25,16 +14,14 @@ class CSporkManager;
|
||||
CSporkManager sporkManager;
|
||||
|
||||
std::map<uint256, CSporkMessage> mapSporks;
|
||||
std::map<int, CSporkMessage> mapSporksActive;
|
||||
|
||||
|
||||
void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
{
|
||||
if(fLiteMode) return; //disable all darksend/masternode related functionality
|
||||
if(fLiteMode) return; // disable all Dash specific functionality
|
||||
|
||||
if (strCommand == NetMsgType::SPORK)
|
||||
{
|
||||
//LogPrintf("ProcessSpork::spork\n");
|
||||
// LogPrintf("CSporkManager::ProcessSpork\n");
|
||||
CDataStream vMsg(vRecv);
|
||||
CSporkMessage spork;
|
||||
vRecv >> spork;
|
||||
@ -45,24 +32,24 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
uint256 hash = spork.GetHash();
|
||||
if(mapSporksActive.count(spork.nSporkID)) {
|
||||
if(mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned){
|
||||
if(fDebug) LogPrintf("spork - seen %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
|
||||
if(fDebug) LogPrintf("CSporkManager::ProcessSpork -- seen %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
|
||||
return;
|
||||
} else {
|
||||
if(fDebug) LogPrintf("spork - got updated spork %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
|
||||
if(fDebug) LogPrintf("CSporkManager::ProcessSpork -- got updated spork %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
|
||||
}
|
||||
}
|
||||
|
||||
LogPrintf("spork - new %s ID %d Time %d bestHeight %d\n", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Tip()->nHeight);
|
||||
LogPrintf("spork -- new %s ID %d Time %d bestHeight %d\n", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Tip()->nHeight);
|
||||
|
||||
if(!sporkManager.CheckSignature(spork)){
|
||||
LogPrintf("spork - invalid signature\n");
|
||||
if(!spork.CheckSignature()){
|
||||
LogPrintf("CSporkManager::ProcessSpork -- invalid signature\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
mapSporks[hash] = spork;
|
||||
mapSporksActive[spork.nSporkID] = spork;
|
||||
sporkManager.Relay(spork);
|
||||
spork.Relay();
|
||||
|
||||
//does a task if needed
|
||||
ExecuteSpork(spork.nSporkID, spork.nValue);
|
||||
@ -79,58 +66,7 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
|
||||
}
|
||||
|
||||
// grab the spork, otherwise say it's off
|
||||
bool IsSporkActive(int nSporkID)
|
||||
{
|
||||
int64_t r = -1;
|
||||
|
||||
if(mapSporksActive.count(nSporkID)){
|
||||
r = mapSporksActive[nSporkID].nValue;
|
||||
} else {
|
||||
if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
|
||||
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
|
||||
if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
|
||||
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
|
||||
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
|
||||
if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
|
||||
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
|
||||
if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;
|
||||
|
||||
if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
|
||||
}
|
||||
if(r == -1) r = 4070908800; //return 2099-1-1 by default
|
||||
|
||||
return r < GetTime();
|
||||
}
|
||||
|
||||
// grab the value of the spork on the network, or the default
|
||||
int64_t GetSporkValue(int nSporkID)
|
||||
{
|
||||
int64_t r = -1;
|
||||
|
||||
if(mapSporksActive.count(nSporkID)){
|
||||
r = mapSporksActive[nSporkID].nValue;
|
||||
} else {
|
||||
if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
|
||||
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
|
||||
if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
|
||||
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
|
||||
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
|
||||
if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
|
||||
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
|
||||
if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;
|
||||
|
||||
if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void ExecuteSpork(int nSporkID, int nValue)
|
||||
void CSporkManager::ExecuteSpork(int nSporkID, int nValue)
|
||||
{
|
||||
// if(nSporkID == SPORK_11_RESET_BUDGET && nValue == 1){
|
||||
// budget.Clear();
|
||||
@ -138,124 +74,76 @@ void ExecuteSpork(int nSporkID, int nValue)
|
||||
|
||||
//correct fork via spork technology
|
||||
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS && nValue > 0) {
|
||||
LogPrintf("Spork::ExecuteSpork -- Reconsider Last %d Blocks\n", nValue);
|
||||
LogPrintf("CSporkManager::ExecuteSpork -- Reconsider Last %d Blocks\n", nValue);
|
||||
|
||||
ReprocessBlocks(nValue);
|
||||
}
|
||||
}
|
||||
|
||||
void ReprocessBlocks(int nBlocks)
|
||||
{
|
||||
std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin();
|
||||
while(it != mapRejectedBlocks.end()){
|
||||
//use a window twice as large as is usual for the nBlocks we want to reset
|
||||
if((*it).second > GetTime() - (nBlocks*60*5)) {
|
||||
BlockMap::iterator mi = mapBlockIndex.find((*it).first);
|
||||
if (mi != mapBlockIndex.end() && (*mi).second) {
|
||||
LOCK(cs_main);
|
||||
|
||||
CBlockIndex* pindex = (*mi).second;
|
||||
LogPrintf("ReprocessBlocks - %s\n", (*it).first.ToString());
|
||||
|
||||
CValidationState state;
|
||||
ReconsiderBlock(state, pindex);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
DisconnectBlocksAndReprocess(nBlocks);
|
||||
}
|
||||
|
||||
if (state.IsValid()) {
|
||||
ActivateBestChain(state, Params());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CSporkManager::CheckSignature(CSporkMessage& spork)
|
||||
{
|
||||
//note: need to investigate why this is failing
|
||||
std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);
|
||||
CPubKey pubkey(ParseHex(Params().SporkKey()));
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pubkey, spork.vchSig, strMessage, errorMessage)){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSporkManager::Sign(CSporkMessage& spork)
|
||||
{
|
||||
std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);
|
||||
|
||||
CKey key2;
|
||||
CPubKey pubkey2;
|
||||
std::string errorMessage = "";
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
LogPrintf("CMasternodePayments::Sign - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, spork.vchSig, key2)) {
|
||||
LogPrintf("CMasternodePayments::Sign - Sign message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey2, spork.vchSig, strMessage, errorMessage)) {
|
||||
LogPrintf("CMasternodePayments::Sign - Verify message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue)
|
||||
{
|
||||
|
||||
CSporkMessage msg;
|
||||
msg.nSporkID = nSporkID;
|
||||
msg.nValue = nValue;
|
||||
msg.nTimeSigned = GetTime();
|
||||
CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetTime());
|
||||
|
||||
if(Sign(msg)){
|
||||
Relay(msg);
|
||||
mapSporks[msg.GetHash()] = msg;
|
||||
mapSporksActive[nSporkID] = msg;
|
||||
if(spork.Sign(strMasterPrivKey)){
|
||||
spork.Relay();
|
||||
mapSporks[spork.GetHash()] = spork;
|
||||
mapSporksActive[nSporkID] = spork;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSporkManager::Relay(CSporkMessage& msg)
|
||||
// grab the spork, otherwise say it's off
|
||||
bool CSporkManager::IsSporkActive(int nSporkID)
|
||||
{
|
||||
CInv inv(MSG_SPORK, msg.GetHash());
|
||||
RelayInv(inv);
|
||||
int64_t r = -1;
|
||||
|
||||
if(mapSporksActive.count(nSporkID)){
|
||||
r = mapSporksActive[nSporkID].nValue;
|
||||
} else {
|
||||
if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
|
||||
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
|
||||
if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
|
||||
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
|
||||
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
|
||||
if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
|
||||
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
|
||||
if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;
|
||||
|
||||
if(r == -1) LogPrintf("CSporkManager::IsSporkActive -- Unknown Spork %d\n", nSporkID);
|
||||
}
|
||||
if(r == -1) r = 4070908800; //return 2099-1-1 by default
|
||||
|
||||
return r < GetTime();
|
||||
}
|
||||
|
||||
bool CSporkManager::SetPrivKey(std::string strPrivKey)
|
||||
// grab the value of the spork on the network, or the default
|
||||
int64_t CSporkManager::GetSporkValue(int nSporkID)
|
||||
{
|
||||
CSporkMessage msg;
|
||||
int64_t r = -1;
|
||||
|
||||
// Test signing successful, proceed
|
||||
strMasterPrivKey = strPrivKey;
|
||||
|
||||
Sign(msg);
|
||||
|
||||
if(CheckSignature(msg)){
|
||||
LogPrintf("CSporkManager::SetPrivKey - Successfully initialized as spork signer\n");
|
||||
return true;
|
||||
if(mapSporksActive.count(nSporkID)){
|
||||
r = mapSporksActive[nSporkID].nValue;
|
||||
} else {
|
||||
return false;
|
||||
if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
|
||||
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
|
||||
if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
|
||||
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
|
||||
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
|
||||
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
|
||||
if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
|
||||
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
|
||||
if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;
|
||||
|
||||
if(r == -1) LogPrintf("CSporkManager::GetSporkValue -- Unknown Spork %d\n", nSporkID);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int CSporkManager::GetSporkIDByName(std::string strName)
|
||||
@ -274,18 +162,81 @@ int CSporkManager::GetSporkIDByName(std::string strName)
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string CSporkManager::GetSporkNameByID(int id)
|
||||
std::string CSporkManager::GetSporkNameByID(int nSporkID)
|
||||
{
|
||||
if(id == SPORK_2_INSTANTX) return "SPORK_2_INSTANTX";
|
||||
if(id == SPORK_3_INSTANTX_BLOCK_FILTERING) return "SPORK_3_INSTANTX_BLOCK_FILTERING";
|
||||
if(id == SPORK_5_MAX_VALUE) return "SPORK_5_MAX_VALUE";
|
||||
if(id == SPORK_7_MASTERNODE_SCANNING) return "SPORK_7_MASTERNODE_SCANNING";
|
||||
if(id == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT";
|
||||
if(id == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) return "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT";
|
||||
if(id == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES";
|
||||
if(id == SPORK_11_RESET_BUDGET) return "SPORK_11_RESET_BUDGET";
|
||||
if(id == SPORK_12_RECONSIDER_BLOCKS) return "SPORK_12_RECONSIDER_BLOCKS";
|
||||
if(id == SPORK_13_ENABLE_SUPERBLOCKS) return "SPORK_13_ENABLE_SUPERBLOCKS";
|
||||
if(nSporkID == SPORK_2_INSTANTX) return "SPORK_2_INSTANTX";
|
||||
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) return "SPORK_3_INSTANTX_BLOCK_FILTERING";
|
||||
if(nSporkID == SPORK_5_MAX_VALUE) return "SPORK_5_MAX_VALUE";
|
||||
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) return "SPORK_7_MASTERNODE_SCANNING";
|
||||
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT";
|
||||
if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) return "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT";
|
||||
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES";
|
||||
if(nSporkID == SPORK_11_RESET_BUDGET) return "SPORK_11_RESET_BUDGET";
|
||||
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) return "SPORK_12_RECONSIDER_BLOCKS";
|
||||
if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) return "SPORK_13_ENABLE_SUPERBLOCKS";
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool CSporkManager::SetPrivKey(std::string strPrivKey)
|
||||
{
|
||||
CSporkMessage spork;
|
||||
|
||||
spork.Sign(strMasterPrivKey);
|
||||
|
||||
if(spork.CheckSignature()){
|
||||
// Test signing successful, proceed
|
||||
LogPrintf("CSporkManager::SetPrivKey -- Successfully initialized as spork signer\n");
|
||||
strMasterPrivKey = strPrivKey;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSporkMessage::Sign(std::string strSignKey)
|
||||
{
|
||||
std::string strMessage = boost::lexical_cast<std::string>(nSporkID) + boost::lexical_cast<std::string>(nValue) + boost::lexical_cast<std::string>(nTimeSigned);
|
||||
|
||||
CKey key;
|
||||
CPubKey pubkey;
|
||||
std::string errorMessage = "";
|
||||
|
||||
if(!darkSendSigner.SetKey(strSignKey, errorMessage, key, pubkey)) {
|
||||
LogPrintf("CSporkMessage::Sign -- ERROR: '%s'\n", errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, key)) {
|
||||
LogPrintf("CSporkMessage::Sign -- SignMessage() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)) {
|
||||
LogPrintf("CSporkMessage::Sign -- VerifyMessage() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSporkMessage::CheckSignature()
|
||||
{
|
||||
//note: need to investigate why this is failing
|
||||
std::string strMessage = boost::lexical_cast<std::string>(nSporkID) + boost::lexical_cast<std::string>(nValue) + boost::lexical_cast<std::string>(nTimeSigned);
|
||||
CPubKey pubkey(ParseHex(Params().SporkPubKey()));
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)){
|
||||
LogPrintf("CSporkMessage::CheckSignature -- VerifyMessage() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSporkMessage::Relay()
|
||||
{
|
||||
CInv inv(MSG_SPORK, GetHash());
|
||||
RelayInv(inv);
|
||||
}
|
||||
|
55
src/spork.h
55
src/spork.h
@ -1,19 +1,14 @@
|
||||
|
||||
// Copyright (c) 2009-2012 The Dash Core developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef SPORK_H
|
||||
#define SPORK_H
|
||||
|
||||
#include "base58.h"
|
||||
#include "hash.h"
|
||||
#include "protocol.h"
|
||||
#include "util.h"
|
||||
#include "net.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
/*
|
||||
Don't ever reuse these IDs for other sporks
|
||||
- This would result in old clients getting confused about which spork is for what
|
||||
@ -42,37 +37,35 @@ using namespace boost;
|
||||
#define SPORK_11_RESET_BUDGET_DEFAULT 0
|
||||
#define SPORK_12_RECONSIDER_BLOCKS_DEFAULT 0
|
||||
#define SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT 4070908800 //OFF
|
||||
|
||||
|
||||
class CSporkMessage;
|
||||
class CSporkManager;
|
||||
|
||||
extern std::map<uint256, CSporkMessage> mapSporks;
|
||||
extern std::map<int, CSporkMessage> mapSporksActive;
|
||||
extern CSporkManager sporkManager;
|
||||
|
||||
void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
int64_t GetSporkValue(int nSporkID);
|
||||
bool IsSporkActive(int nSporkID);
|
||||
void ExecuteSpork(int nSporkID, int nValue);
|
||||
void ReprocessBlocks(int nBlocks);
|
||||
|
||||
//
|
||||
// Spork Class
|
||||
// Keeps track of all of the network spork settings
|
||||
// Spork classes
|
||||
// Keep track of all of the network spork settings
|
||||
//
|
||||
|
||||
class CSporkMessage
|
||||
{
|
||||
public:
|
||||
private:
|
||||
std::vector<unsigned char> vchSig;
|
||||
|
||||
public:
|
||||
int nSporkID;
|
||||
int64_t nValue;
|
||||
int64_t nTimeSigned;
|
||||
|
||||
uint256 GetHash(){
|
||||
uint256 n = HashX11(BEGIN(nSporkID), END(nTimeSigned));
|
||||
return n;
|
||||
}
|
||||
CSporkMessage(int nSporkID, int64_t nValue, int64_t nTimeSigned) : nSporkID(nSporkID), nValue(nValue), nTimeSigned(nTimeSigned) {}
|
||||
CSporkMessage() : nSporkID(0), nValue(0), nTimeSigned(0) {}
|
||||
|
||||
uint256 GetHash() { return HashX11(BEGIN(nSporkID), END(nTimeSigned)); }
|
||||
bool Sign(std::string strSignKey);
|
||||
bool CheckSignature();
|
||||
void Relay();
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
@ -91,20 +84,22 @@ class CSporkManager
|
||||
private:
|
||||
std::vector<unsigned char> vchSig;
|
||||
std::string strMasterPrivKey;
|
||||
std::map<int, CSporkMessage> mapSporksActive;
|
||||
|
||||
public:
|
||||
|
||||
CSporkManager() {
|
||||
}
|
||||
CSporkManager() {}
|
||||
|
||||
std::string GetSporkNameByID(int id);
|
||||
int GetSporkIDByName(std::string strName);
|
||||
void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
void ExecuteSpork(int nSporkID, int nValue);
|
||||
bool UpdateSpork(int nSporkID, int64_t nValue);
|
||||
bool SetPrivKey(std::string strPrivKey);
|
||||
bool CheckSignature(CSporkMessage& spork);
|
||||
bool Sign(CSporkMessage& spork);
|
||||
void Relay(CSporkMessage& msg);
|
||||
|
||||
bool IsSporkActive(int nSporkID);
|
||||
int64_t GetSporkValue(int nSporkID);
|
||||
int GetSporkIDByName(std::string strName);
|
||||
std::string GetSporkNameByID(int nSporkID);
|
||||
|
||||
bool SetPrivKey(std::string strPrivKey);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user