diff --git a/src/Makefile.am b/src/Makefile.am index ad40b357329d0..77531237fc869 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -152,6 +152,7 @@ BITCOIN_CORE_H = \ serialize.h \ spork.h \ sporkdb.h \ + sporkid.h \ stakeinput.h \ streams.h \ support/cleanse.h \ diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 58ed547e112c5..c57da3da49f66 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -198,7 +198,7 @@ bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) * AFTER MIGRATION TO V12 IS DONE */ - if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return true; + if (sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return true; // for migration purposes ping our node on old masternodes network too std::string retErrorMessage; std::vector vchMasterNodeSignature; @@ -300,7 +300,7 @@ bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCol * AFTER MIGRATION TO V12 IS DONE */ - if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return true; + if (sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return true; // for migration purposes inject our node in old masternodes' list too std::string retErrorMessage; std::vector vchMasterNodeSignature; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b336fbfb4692d..318b8bb2a1a9f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -240,8 +240,8 @@ class CMainParams : public CChainParams nPoolMaxTransactions = 3; nBudgetCycleBlocks = 43200; //!< Amount of blocks in a months period of time (using 1 minutes per) = (60*24*30) - strSporkKey = "040F129DE6546FE405995329A887329BED4321325B1A73B0A257423C05C1FCFE9E40EF0678AEF59036A22C42E61DFD29DF7EFB09F56CC73CADF64E05741880E3E7"; - strSporkKeyOld = "0499A7AF4806FC6DE640D23BC5936C29B77ADF2174B4F45492727F897AE63CF8D27B2F05040606E0D14B547916379FA10716E344E745F880EDC037307186AA25B7"; + strSporkPubKey = "040F129DE6546FE405995329A887329BED4321325B1A73B0A257423C05C1FCFE9E40EF0678AEF59036A22C42E61DFD29DF7EFB09F56CC73CADF64E05741880E3E7"; + strSporkPubKeyOld = "0499A7AF4806FC6DE640D23BC5936C29B77ADF2174B4F45492727F897AE63CF8D27B2F05040606E0D14B547916379FA10716E344E745F880EDC037307186AA25B7"; strObfuscationPoolDummyAddress = "D87q2gC9j6nNrnzCsg4aY6bHMLsT9nUhEw"; nStartMasternodePayments = 1403728576; //Wed, 25 Jun 2014 20:36:16 GMT @@ -355,8 +355,8 @@ class CTestNetParams : public CMainParams nPoolMaxTransactions = 2; nBudgetCycleBlocks = 144; //!< Ten cycles per day on testnet - strSporkKey = "04E88BB455E2A04E65FCC41D88CD367E9CCE1F5A409BE94D8C2B4B35D223DED9C8E2F4E061349BA3A38839282508066B6DC4DB72DD432AC4067991E6BF20176127"; - strSporkKeyOld = "04A8B319388C0F8588D238B9941DC26B26D3F9465266B368A051C5C100F79306A557780101FE2192FE170D7E6DEFDCBEE4C8D533396389C0DAFFDBC842B002243C"; + strSporkPubKey = "04E88BB455E2A04E65FCC41D88CD367E9CCE1F5A409BE94D8C2B4B35D223DED9C8E2F4E061349BA3A38839282508066B6DC4DB72DD432AC4067991E6BF20176127"; + strSporkPubKeyOld = "04A8B319388C0F8588D238B9941DC26B26D3F9465266B368A051C5C100F79306A557780101FE2192FE170D7E6DEFDCBEE4C8D533396389C0DAFFDBC842B002243C"; strObfuscationPoolDummyAddress = "y57cqfGRkekRyDRNeJiLtYVEbvhXrNbmox"; nStartMasternodePayments = 1420837558; //Fri, 09 Jan 2015 21:05:58 GMT nBudget_Fee_Confirmations = 3; // Number of confirmations for the finalization fee. We have to make this very short @@ -437,7 +437,7 @@ class CRegTestParams : public CTestNetParams private key hex: bd4960dcbd9e7f2223f24e7164ecb6f1fe96fc3a416f5d3a830ba5720c84b8ca Address: yCvUVd72w7xpimf981m114FSFbmAmne7j9 */ - strSporkKey = "043969b1b0e6f327de37f297a015d37e2235eaaeeb3933deecd8162c075cee0207b13537618bde640879606001a8136091c62ec272dd0133424a178704e6e75bb7"; + strSporkPubKey = "043969b1b0e6f327de37f297a015d37e2235eaaeeb3933deecd8162c075cee0207b13537618bde640879606001a8136091c62ec272dd0133424a178704e6e75bb7"; } const Checkpoints::CCheckpointData& Checkpoints() const { diff --git a/src/chainparams.h b/src/chainparams.h index f107c923cc7ab..94f99e7c0cd2a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -104,8 +104,8 @@ class CChainParams int64_t GetProposalEstablishmentTime() const { return nProposalEstablishmentTime; } /** Spork key and Masternode Handling **/ - std::string SporkKey() const { return strSporkKey; } - std::string SporkKeyOld() const { return strSporkKeyOld; } + std::string SporkPubKey() const { return strSporkPubKey; } + std::string SporkPubKeyOld() const { return strSporkPubKeyOld; } int64_t NewSporkStart() const { return nEnforceNewSporkKey; } int64_t RejectOldSporkKey() const { return nRejectOldSporkKey; } std::string ObfuscationPoolDummyAddress() const { return strObfuscationPoolDummyAddress; } @@ -193,8 +193,8 @@ class CChainParams bool fHeadersFirstSyncingActive; int nPoolMaxTransactions; int nBudgetCycleBlocks; - std::string strSporkKey; - std::string strSporkKeyOld; + std::string strSporkPubKey; + std::string strSporkPubKeyOld; int64_t nEnforceNewSporkKey; int64_t nRejectOldSporkKey; std::string strObfuscationPoolDummyAddress; diff --git a/src/init.cpp b/src/init.cpp index 90830083301ff..1fd3963ba0a82 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1442,7 +1442,7 @@ bool AppInit2() // PIVX: load previous sessions sporks if we have them. uiInterface.InitMessage(_("Loading sporks...")); - LoadSporksFromDB(); + sporkManager.LoadSporksFromDB(); uiInterface.InitMessage(_("Loading block index...")); std::string strBlockIndexError = ""; diff --git a/src/main.cpp b/src/main.cpp index bc682af7154cd..8cc685240bf52 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1338,7 +1338,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa *pfMissingInputs = false; //Temporarily disable zerocoin for maintenance - if (GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE) && tx.ContainsZerocoins()) + if (sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE) && tx.ContainsZerocoins()) return state.DoS(10, error("AcceptToMemoryPool : Zerocoin transactions are temporarily disabled for maintenance"), REJECT_INVALID, "bad-tx"); int chainHeight = chainActive.Height(); @@ -2044,7 +2044,7 @@ CAmount GetSeeSaw(const CAmount& blockValue, int nMasternodeCount, int nHeight) { //if a mn count is inserted into the function we are looking for a specific result for a masternode count if (nMasternodeCount < 1){ - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) + if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) nMasternodeCount = mnodeman.stable_size(); else nMasternodeCount = mnodeman.size(); @@ -3241,7 +3241,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock() : too many sigops"), REJECT_INVALID, "bad-blk-sigops"); //Temporarily disable zerocoin transactions for maintenance - if (block.nTime > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE) && !IsInitialBlockDownload() && tx.ContainsZerocoins()) { + if (block.nTime > sporkManager.GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE) && !IsInitialBlockDownload() && tx.ContainsZerocoins()) { return state.DoS(100, error("ConnectBlock() : zerocoin transactions are currently in maintenance mode")); } @@ -3756,19 +3756,50 @@ bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* return true; } -bool DisconnectBlocksAndReprocess(int blocks) +bool DisconnectBlocks(int nBlocks) { LOCK(cs_main); CValidationState state; - LogPrintf("DisconnectBlocksAndReprocess: Got command to replay %d blocks\n", blocks); - for (int i = 0; i <= blocks; i++) + LogPrintf("%s: Got command to replay %d blocks\n", __func__, nBlocks); + for (int i = 0; i <= nBlocks; i++) DisconnectTip(state); return true; } +void ReprocessBlocks(int nBlocks) +{ + std::map::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 * Params().TargetSpacing() * 2)) { + BlockMap::iterator mi = mapBlockIndex.find((*it).first); + if (mi != mapBlockIndex.end() && (*mi).second) { + LOCK(cs_main); + + CBlockIndex* pindex = (*mi).second; + LogPrintf("%s - %s\n", __func__, (*it).first.ToString()); + + CValidationState state; + ReconsiderBlock(state, pindex); + } + } + ++it; + } + + CValidationState state; + { + LOCK(cs_main); + DisconnectBlocks(nBlocks); + } + + if (state.IsValid()) { + ActivateBestChain(state); + } +} + /* DisconnectBlockAndInputs @@ -4404,7 +4435,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo } // ----------- swiftTX transaction scanning ----------- - if (IsSporkActive(SPORK_3_SWIFTTX_BLOCK_FILTERING)) { + if (sporkManager.IsSporkActive(SPORK_3_SWIFTTX_BLOCK_FILTERING)) { for (const CTransaction& tx : block.vtx) { if (!tx.IsCoinBase()) { //only reject blocks when it's based on complete consensus @@ -7048,7 +7079,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR budget.ProcessMessage(pfrom, strCommand, vRecv); masternodePayments.ProcessMessageMasternodePayments(pfrom, strCommand, vRecv); ProcessMessageSwiftTX(pfrom, strCommand, vRecv); - ProcessSpork(pfrom, strCommand, vRecv); + sporkManager.ProcessSpork(pfrom, strCommand, vRecv); masternodeSync.ProcessMessage(pfrom, strCommand, vRecv); } @@ -7063,11 +7094,11 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR int ActiveProtocol() { // SPORK_14 is used for 70917 (v3.4+) - if (IsSporkActive(SPORK_14_NEW_PROTOCOL_ENFORCEMENT)) + if (sporkManager.IsSporkActive(SPORK_14_NEW_PROTOCOL_ENFORCEMENT)) return MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT; // SPORK_15 was used for 70916 (v3.3+), commented out now. - //if (IsSporkActive(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2)) + //if (sporkManager.IsSporkActive(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2)) // return MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT; return MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT; diff --git a/src/main.h b/src/main.h index 25a63ee803947..96cee4234fb78 100644 --- a/src/main.h +++ b/src/main.h @@ -461,7 +461,8 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); bool DisconnectBlock(CBlock& block, CValidationState& state, 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 nBlocks); +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, bool fAlreadyChecked = false); diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 393bf746f9326..d510f0c48b481 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -205,7 +205,7 @@ bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMin } 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 nMinted <= nExpectedValue; } @@ -234,7 +234,7 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) const CTransaction& txNew = (nBlockHeight > Params().LAST_POW_BLOCK() ? block.vtx[1] : block.vtx[0]); //check if it's a budget block - if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) { + if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) { if (budget.IsBudgetPaymentBlock(nBlockHeight)) { transactionStatus = budget.IsTransactionValid(txNew, nBlockHeight); if (transactionStatus == TrxValidationStatus::Valid) { @@ -243,7 +243,7 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) if (transactionStatus == TrxValidationStatus::InValid) { LogPrint("masternode","Invalid budget payment detected %s\n", txNew.ToString().c_str()); - if (IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) + if (sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) return false; LogPrint("masternode","Budget enforcement is disabled, accepting block\n"); @@ -261,7 +261,7 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) return true; LogPrint("masternode","Invalid mn payment detected %s\n", txNew.ToString().c_str()); - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) + if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) return false; LogPrint("masternode","Masternode payment enforcement is disabled, accepting block\n"); @@ -274,7 +274,7 @@ void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStak CBlockIndex* pindexPrev = chainActive.Tip(); if (!pindexPrev) return; - if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight + 1)) { + if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight + 1)) { budget.FillBlockPayee(txNew, nFees, fProofOfStake); } else { masternodePayments.FillBlockPayee(txNew, nFees, fProofOfStake, fZPIVStake); @@ -283,7 +283,7 @@ void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStak std::string GetRequiredPaymentsString(int nBlockHeight) { - 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 masternodePayments.GetRequiredPaymentsString(nBlockHeight); @@ -359,7 +359,7 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe int CMasternodePayments::GetMinMasternodePaymentsProto() { - if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) + if (sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return ActiveProtocol(); // Allow only updated peers else return MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT; // Also allow old peers as long as they are allowed to run @@ -547,7 +547,7 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) CAmount nReward = GetBlockValue(nBlockHeight); - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { // Get a stable number of masternodes by ignoring newly activated (< 8000 sec old) masternodes nMasternode_Drift_Count = mnodeman.stable_size() + Params().MasternodeCountDrift(); } diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index d23f1bd46be23..a765b5e325f2e 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -308,7 +308,7 @@ void CMasternodeSync::Process() // timeout if (lastMasternodeList == 0 && (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) { - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n"); RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED; RequestedMasternodeAttempt = 0; @@ -339,7 +339,7 @@ void CMasternodeSync::Process() // timeout if (lastMasternodeWinner == 0 && (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) { - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n"); RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED; RequestedMasternodeAttempt = 0; diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 04f6ad3a8bc0c..856245adb918f 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -358,7 +358,7 @@ int CMasternodeMan::stable_size () if (mn.protocolVersion < nMinProtocol) { continue; // Skip obsolete versions } - if (IsSporkActive (SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + if (sporkManager.IsSporkActive (SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { nMasternode_Age = GetAdjustedTime() - mn.sigTime; if ((nMasternode_Age) < nMasternode_Min_Age) { continue; // Skip masternodes younger than (default) 8000 sec (MUST be > MASTERNODE_REMOVAL_SECONDS) @@ -607,7 +607,7 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in continue; // Skip obsolete versions } - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { nMasternode_Age = GetAdjustedTime() - mn.sigTime; if ((nMasternode_Age) < nMasternode_Min_Age) { if (fDebug) LogPrint("masternode","Skipping just activated Masternode. Age: %ld\n", nMasternode_Age); @@ -856,7 +856,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // Light version for OLD MASSTERNODES - fake pings, no self-activation else if (strCommand == "dsee") { //ObfuScation Election Entry - if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return; + if (sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return; CTxIn vin; CService addr; @@ -1061,7 +1061,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData else if (strCommand == "dseep") { //ObfuScation Election Entry Ping - if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return; + if (sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return; CTxIn vin; std::vector vchSig; diff --git a/src/miner.cpp b/src/miner.cpp index 540bafece6d40..63562578c872e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -213,7 +213,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, if (tx.IsCoinBase() || tx.IsCoinStake() || !IsFinalTx(tx, nHeight)){ continue; } - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE) && tx.ContainsZerocoins()){ + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE) && tx.ContainsZerocoins()){ continue; } diff --git a/src/qt/pivx/privacywidget.cpp b/src/qt/pivx/privacywidget.cpp index 451fb29f0e529..88a0e34d163df 100644 --- a/src/qt/pivx/privacywidget.cpp +++ b/src/qt/pivx/privacywidget.cpp @@ -234,7 +234,7 @@ void PrivacyWidget::onSendClicked(){ if (!walletModel || !walletModel->getOptionsModel()) return; - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { warn(tr("Zerocoin"), tr("zPIV is currently undergoing maintenance")); return; } diff --git a/src/qt/pivx/send.cpp b/src/qt/pivx/send.cpp index 5e94edd3de2af..64a859d9abde2 100644 --- a/src/qt/pivx/send.cpp +++ b/src/qt/pivx/send.cpp @@ -380,7 +380,7 @@ bool SendWidget::sendZpiv(QList recipients){ if (!walletModel || !walletModel->getOptionsModel()) return false; - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { emit message(tr("Spend Zerocoin"), tr("zPIV is currently undergoing maintenance."), CClientUIInterface::MSG_ERROR); return false; } diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp index 47b6ccdd8ea45..a4acfe0174b47 100644 --- a/src/qt/privacydialog.cpp +++ b/src/qt/privacydialog.cpp @@ -164,7 +164,7 @@ void PrivacyDialog::on_pushButtonMintzPIV_clicked() if (!walletModel || !walletModel->getOptionsModel()) return; - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { QMessageBox::information(this, tr("Mint Zerocoin"), tr("zPIV is currently undergoing maintenance."), QMessageBox::Ok, QMessageBox::Ok); @@ -276,7 +276,7 @@ void PrivacyDialog::on_pushButtonSpendzPIV_clicked() if (!walletModel || !walletModel->getOptionsModel() || !pwalletMain) return; - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { QMessageBox::information(this, tr("Mint Zerocoin"), tr("zPIV is currently undergoing maintenance."), QMessageBox::Ok, QMessageBox::Ok); return; @@ -808,7 +808,7 @@ void PrivacyDialog::updateSPORK16Status() // Update/enable labels, buttons and tooltips depending on the current SPORK_16 status //bool fButtonsEnabled = ui->pushButtonMintzPIV->isEnabled(); bool fButtonsEnabled = false; - bool fMaintenanceMode = GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE); + bool fMaintenanceMode = sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE); if (fMaintenanceMode && fButtonsEnabled) { // Mint zPIV //ui->pushButtonMintzPIV->setEnabled(false); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 612d1344beff7..6a7670497947a 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -358,8 +358,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact CReserveKey* keyChange = transaction.getPossibleKeyChange(); - if (recipients[0].useSwiftTX && total > GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { - emit message(tr("Send Coins"), tr("SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 PIV.").arg(GetSporkValue(SPORK_5_MAX_VALUE)), + if (recipients[0].useSwiftTX && total > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { + emit message(tr("Send Coins"), tr("SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 PIV.").arg(sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } @@ -367,8 +367,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason, coinControl, recipients[0].inputType, recipients[0].useSwiftTX); transaction.setTransactionFee(nFeeRequired); - if (recipients[0].useSwiftTX && newTx->GetValueOut() > GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { - emit message(tr("Send Coins"), tr("SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 PIV.").arg(GetSporkValue(SPORK_5_MAX_VALUE)), + if (recipients[0].useSwiftTX && newTx->GetValueOut() > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { + emit message(tr("Send Coins"), tr("SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 PIV.").arg(sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 22e8c5d05f66a..c0846e73a6b6f 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -27,6 +27,8 @@ #include +extern std::vector sporkDefs; + /** * @note Do not add or change anything in the information returned by this @@ -291,22 +293,21 @@ UniValue spork(const UniValue& params, bool fHelp) { if (params.size() == 1 && params[0].get_str() == "show") { 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))); + for (const auto& sporkDef : sporkDefs) { + ret.push_back(Pair(sporkDef.name, sporkManager.GetSporkValue(sporkDef.sporkId))); } 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))); + for (const auto& sporkDef : sporkDefs) { + ret.push_back(Pair(sporkDef.name, sporkManager.IsSporkActive(sporkDef.sporkId))); } return ret; } else if (params.size() == 2) { - int nSporkID = sporkManager.GetSporkIDByName(params[0].get_str()); - if (nSporkID == -1) { - return "Invalid spork name"; + // advanced mode, update spork values + SporkId nSporkID = sporkManager.GetSporkIDByName(params[0].get_str()); + if (nSporkID == SPORK_INVALID) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid spork name"); } // SPORK VALUE diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 300fd8eed9317..d1cad1f73d609 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -934,7 +934,7 @@ UniValue createrawzerocoinstake(const UniValue& params, bool fHelp) assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance."); std::string serial_hash = params[0].get_str(); diff --git a/src/serialize.h b/src/serialize.h index f492fccccd26e..47d50f17c05a1 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -20,6 +20,7 @@ #include #include "libzerocoin/Denominations.h" #include "libzerocoin/SpendType.h" +#include "sporkid.h" class CScript; @@ -290,6 +291,23 @@ inline void Unserialize(Stream& s, libzerocoin::SpendType & a, int, int = 0) a = static_cast(f); } +// Serialization for SporkId +inline unsigned int GetSerializeSize(SporkId sporkID, int, int = 0) { return sizeof(SporkId); } +template +inline void Serialize(Stream& s, SporkId sporkID, int, int = 0) +{ + int32_t f = static_cast(sporkID); + WRITEDATA(s, f); +} + +template +inline void Unserialize(Stream& s, SporkId& sporkID, int, int = 0) +{ + int32_t f=0; + READDATA(s, f); + sporkID = (SporkId) f; +} + /** * Compact Size diff --git a/src/spork.cpp b/src/spork.cpp index e1a11337b08cb..1dc67cd52f0ef 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -3,38 +3,53 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "spork.h" -#include "base58.h" -#include "key.h" #include "main.h" #include "masternode-budget.h" #include "net.h" -#include "protocol.h" -#include "sync.h" +#include "spork.h" #include "sporkdb.h" -#include "util.h" -class CSporkMessage; -class CSporkManager; +#define MAKE_SPORK_DEF(name, defaultValue) CSporkDef(name, defaultValue, #name) -CSporkManager sporkManager; +std::vector sporkDefs = { + MAKE_SPORK_DEF(SPORK_2_SWIFTTX, 0), // ON + MAKE_SPORK_DEF(SPORK_3_SWIFTTX_BLOCK_FILTERING, 0), // ON + MAKE_SPORK_DEF(SPORK_5_MAX_VALUE, 1000), // 1000 PIV + MAKE_SPORK_DEF(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT, 4070908800ULL), // OFF + MAKE_SPORK_DEF(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT, 4070908800ULL), // OFF + MAKE_SPORK_DEF(SPORK_10_MASTERNODE_PAY_UPDATED_NODES, 0), // OFF + MAKE_SPORK_DEF(SPORK_13_ENABLE_SUPERBLOCKS, 4070908800ULL), // OFF + MAKE_SPORK_DEF(SPORK_14_NEW_PROTOCOL_ENFORCEMENT, 4070908800ULL), // OFF + MAKE_SPORK_DEF(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2, 4070908800ULL), // OFF + MAKE_SPORK_DEF(SPORK_16_ZEROCOIN_MAINTENANCE_MODE, 4070908800ULL), // OFF +}; +CSporkManager sporkManager; std::map mapSporks; -std::map mapSporksActive; -// PIVX: on startup load spork values from previous session if they exist in the sporkDB -void LoadSporksFromDB() +CSporkManager::CSporkManager() { - for (int i = SPORK_START; i <= SPORK_END; ++i) { - // Since not all spork IDs are in use, we have to exclude undefined IDs - std::string strSpork = sporkManager.GetSporkNameByID(i); - if (strSpork == "Unknown") continue; + for (auto& sporkDef : sporkDefs) { + sporkDefsById.emplace(sporkDef.sporkId, &sporkDef); + sporkDefsByName.emplace(sporkDef.name, &sporkDef); + } +} +void CSporkManager::Clear() +{ + strMasterPrivKey = ""; + mapSporksActive.clear(); +} + +// PIVX: on startup load spork values from previous session if they exist in the sporkDB +void CSporkManager::LoadSporksFromDB() +{ + for (const auto& sporkDef : sporkDefs) { // attempt to read spork from sporkDB CSporkMessage spork; - if (!pSporkDB->ReadSpork(i, spork)) { - LogPrintf("%s : no previous value for %s found in database\n", __func__, strSpork); + if (!pSporkDB->ReadSpork(sporkDef.sporkId, spork)) { + LogPrintf("%s : no previous value for %s found in database\n", __func__, sporkDef.name); continue; } @@ -54,50 +69,69 @@ void LoadSporksFromDB() } } -void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) +void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { - if (fLiteMode) return; //disable all obfuscation/masternode related functionality + if (fLiteMode || chainActive.Tip() == nullptr) return; // disable all obfuscation/masternode related functionality if (strCommand == "spork") { - //LogPrintf("ProcessSpork::spork\n"); - CDataStream vMsg(vRecv); + CSporkMessage spork; vRecv >> spork; - if (chainActive.Tip() == NULL) return; - // Ignore spork messages about unknown/deleted sporks std::string strSpork = sporkManager.GetSporkNameByID(spork.nSporkID); if (strSpork == "Unknown") return; + // Do not accept sporks signed way too far into the future + if (spork.nTimeSigned > GetAdjustedTime() + 2 * 60 * 60) { + LOCK(cs_main); + LogPrintf("%s : ERROR: too far into the future\n", __func__); + Misbehaving(pfrom->GetId(), 100); + return; + } + uint256 hash = spork.GetHash(); - if (mapSporksActive.count(spork.nSporkID)) { - if (mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned) { - if (fDebug) LogPrintf("%s : seen %s block %d \n", __func__, hash.ToString(), chainActive.Tip()->nHeight); - return; + { + LOCK(cs); + if (mapSporksActive.count(spork.nSporkID)) { + // spork is active + if (mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned) { + // spork in memory has been signed more recently + if (fDebug) LogPrintf("%s : seen %s block %d \n", __func__, hash.ToString(), chainActive.Tip()->nHeight); + return; + } else { + // update active spork + if (fDebug) LogPrintf("%s : got updated spork %s block %d \n", __func__, hash.ToString(), chainActive.Tip()->nHeight); + } } else { - if (fDebug) LogPrintf("%s : got updated spork %s block %d \n", __func__, hash.ToString(), chainActive.Tip()->nHeight); + // spork is not active + if (fDebug) LogPrintf("%s : got new spork %s block %d \n", __func__, hash.ToString(), chainActive.Tip()->nHeight); } } LogPrintf("%s : new %s ID %d Time %d bestHeight %d\n", __func__, hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Tip()->nHeight); bool fRequireNew = spork.nTimeSigned >= Params().NewSporkStart(); - if (!sporkManager.CheckSignature(spork, fRequireNew)) { + if (!spork.CheckSignature(fRequireNew)) { + LOCK(cs_main); LogPrintf("%s : Invalid Signature\n", __func__); Misbehaving(pfrom->GetId(), 100); return; } - mapSporks[hash] = spork; - mapSporksActive[spork.nSporkID] = spork; - sporkManager.Relay(spork); + { + LOCK(cs); + mapSporks[hash] = spork; + mapSporksActive[spork.nSporkID] = spork; + } + spork.Relay(); // PIVX: add to spork database. pSporkDB->WriteSpork(spork.nSporkID, spork); } if (strCommand == "getsporks") { - std::map::iterator it = mapSporksActive.begin(); + LOCK(cs); + std::map::iterator it = mapSporksActive.begin(); while (it != mapSporksActive.end()) { pfrom->PushMessage("spork", it->second); @@ -106,191 +140,139 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) } } - -// grab the value of the spork on the network, or the default -int64_t GetSporkValue(int nSporkID) +bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue) { - int64_t r = -1; - if (mapSporksActive.count(nSporkID)) { - r = mapSporksActive[nSporkID].nValue; - } else { - if (nSporkID == SPORK_2_SWIFTTX) r = SPORK_2_SWIFTTX_DEFAULT; - if (nSporkID == SPORK_3_SWIFTTX_BLOCK_FILTERING) r = SPORK_3_SWIFTTX_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_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT; - if (nSporkID == SPORK_14_NEW_PROTOCOL_ENFORCEMENT) r = SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT; - if (nSporkID == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) r = SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT; - if (nSporkID == SPORK_16_ZEROCOIN_MAINTENANCE_MODE) r = SPORK_16_ZEROCOIN_MAINTENANCE_MODE_DEFAULT; - - if (r == -1) LogPrintf("%s : Unknown Spork %d\n", __func__, nSporkID); + CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetTime()); + + if(spork.Sign(strMasterPrivKey)){ + spork.Relay(); + LOCK(cs); + mapSporks[spork.GetHash()] = spork; + mapSporksActive[nSporkID] = spork; + return true; } - return r; + return false; } // grab the spork value, and see if it's off -bool IsSporkActive(int nSporkID) +bool CSporkManager::IsSporkActive(SporkId nSporkID) { - int64_t r = GetSporkValue(nSporkID); - if (r == -1) return false; - return r < GetTime(); + return GetSporkValue(nSporkID) < GetAdjustedTime(); } - -void ReprocessBlocks(int nBlocks) +// grab the value of the spork on the network, or the default +int64_t CSporkManager::GetSporkValue(SporkId nSporkID) { - std::map::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); - } + LOCK(cs); + + if (mapSporksActive.count(nSporkID)) { + return mapSporksActive[nSporkID].nValue; + + } else { + auto it = sporkDefsById.find(nSporkID); + if (it != sporkDefsById.end()) { + return it->second->defaultValue; + } else { + LogPrintf("%s : Unknown Spork %d\n", __func__, nSporkID); } - ++it; } - CValidationState state; - { - LOCK(cs_main); - DisconnectBlocksAndReprocess(nBlocks); - } + return -1; +} - if (state.IsValid()) { - ActivateBestChain(state); +SporkId CSporkManager::GetSporkIDByName(std::string strName) +{ + auto it = sporkDefsByName.find(strName); + if (it == sporkDefsByName.end()) { + LogPrintf("%s : Unknown Spork name '%s'\n", __func__, strName); + return SPORK_INVALID; } + return it->second->sporkId; } -bool CSporkManager::CheckSignature(CSporkMessage& spork, bool fRequireNew) +std::string CSporkManager::GetSporkNameByID(SporkId nSporkID) { - //note: need to investigate why this is failing - std::string strMessage = std::to_string(spork.nSporkID) + std::to_string(spork.nValue) + std::to_string(spork.nTimeSigned); - CPubKey pubkeynew(ParseHex(Params().SporkKey())); - std::string errorMessage = ""; + auto it = sporkDefsById.find(nSporkID); + if (it == sporkDefsById.end()) { + LogPrint("%s : Unknown Spork ID %d\n", __func__, nSporkID); + return "Unknown"; + } + return it->second->name; +} - bool fValidWithNewKey = obfuScationSigner.VerifyMessage(pubkeynew, spork.vchSig,strMessage, errorMessage); +bool CSporkManager::SetPrivKey(std::string strPrivKey) +{ + CSporkMessage spork; - if (fRequireNew && !fValidWithNewKey) - return false; + spork.Sign(strPrivKey); - // See if window is open that allows for old spork key to sign messages - if (!fValidWithNewKey && GetAdjustedTime() < Params().RejectOldSporkKey()) { - CPubKey pubkeyold(ParseHex(Params().SporkKeyOld())); - return obfuScationSigner.VerifyMessage(pubkeyold, spork.vchSig, strMessage, errorMessage); + const bool fRequireNew = GetTime() >= Params().NewSporkStart(); + if (spork.CheckSignature(fRequireNew)) { + LOCK(cs); + // Test signing successful, proceed + LogPrintf("%s : Successfully initialized as spork signer\n", __func__); + strMasterPrivKey = strPrivKey; + return true; } - return fValidWithNewKey; + return false; +} + +std::string CSporkManager::ToString() const +{ + LOCK(cs); + return strprintf("Sporks: %llu", mapSporksActive.size()); } -bool CSporkManager::Sign(CSporkMessage& spork) +bool CSporkMessage::Sign(std::string strSignKey) { - std::string strMessage = std::to_string(spork.nSporkID) + std::to_string(spork.nValue) + std::to_string(spork.nTimeSigned); + std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned); - CKey key2; - CPubKey pubkey2; + CKey key; + CPubKey pubkey; std::string errorMessage = ""; - if (!obfuScationSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2)) { - LogPrintf("CMasternodePayments::Sign - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage); - return false; + if (!obfuScationSigner.SetKey(strSignKey, errorMessage, key, pubkey)) { + return error("%s : SetKey error: '%s'\n", __func__, errorMessage); } - if (!obfuScationSigner.SignMessage(strMessage, errorMessage, spork.vchSig, key2)) { - LogPrintf("CMasternodePayments::Sign - Sign message failed"); - return false; + if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, key)) { + return error("%s : Sign message failed", __func__); } - if (!obfuScationSigner.VerifyMessage(pubkey2, spork.vchSig, strMessage, errorMessage)) { - LogPrintf("CMasternodePayments::Sign - Verify message failed"); - return false; + if (!obfuScationSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)) { + return error("%s : Verify message failed", __func__); } return true; } -bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue) -{ - CSporkMessage msg; - msg.nSporkID = nSporkID; - msg.nValue = nValue; - msg.nTimeSigned = GetTime(); - - if (Sign(msg)) { - Relay(msg); - mapSporks[msg.GetHash()] = msg; - mapSporksActive[nSporkID] = msg; - return true; - } - - return false; -} - -void CSporkManager::Relay(CSporkMessage& msg) +bool CSporkMessage::CheckSignature(bool fRequireNew) { - CInv inv(MSG_SPORK, msg.GetHash()); - RelayInv(inv); -} - -bool CSporkManager::SetPrivKey(std::string strPrivKey) -{ - CSporkMessage msg; - - // Test signing successful, proceed - strMasterPrivKey = strPrivKey; + //note: need to investigate why this is failing + std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned); + CPubKey pubkeynew(ParseHex(Params().SporkPubKey())); + std::string errorMessage = ""; - Sign(msg); + bool fValidWithNewKey = obfuScationSigner.VerifyMessage(pubkeynew, vchSig, strMessage, errorMessage); - bool fRequireNew = GetTime() >= Params().NewSporkStart(); - if (CheckSignature(msg, fRequireNew)) { - LogPrintf("CSporkManager::SetPrivKey - Successfully initialized as spork signer\n"); - return true; - } else { + if (fRequireNew && !fValidWithNewKey) return false; - } -} -int CSporkManager::GetSporkIDByName(std::string strName) -{ - if (strName == "SPORK_2_SWIFTTX") return SPORK_2_SWIFTTX; - if (strName == "SPORK_3_SWIFTTX_BLOCK_FILTERING") return SPORK_3_SWIFTTX_BLOCK_FILTERING; - if (strName == "SPORK_5_MAX_VALUE") return SPORK_5_MAX_VALUE; - if (strName == "SPORK_7_MASTERNODE_SCANNING") return SPORK_7_MASTERNODE_SCANNING; - if (strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT; - if (strName == "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT") return SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT; - if (strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES; - if (strName == "SPORK_13_ENABLE_SUPERBLOCKS") return SPORK_13_ENABLE_SUPERBLOCKS; - if (strName == "SPORK_14_NEW_PROTOCOL_ENFORCEMENT") return SPORK_14_NEW_PROTOCOL_ENFORCEMENT; - if (strName == "SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2") return SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2; - if (strName == "SPORK_16_ZEROCOIN_MAINTENANCE_MODE") return SPORK_16_ZEROCOIN_MAINTENANCE_MODE; + // See if window is open that allows for old spork key to sign messages + if (!fValidWithNewKey && GetAdjustedTime() < Params().RejectOldSporkKey()) { + CPubKey pubkeyold(ParseHex(Params().SporkPubKeyOld())); + return obfuScationSigner.VerifyMessage(pubkeyold, vchSig, strMessage, errorMessage); + } - return -1; + return fValidWithNewKey; } -std::string CSporkManager::GetSporkNameByID(int id) +void CSporkMessage::Relay() { - if (id == SPORK_2_SWIFTTX) return "SPORK_2_SWIFTTX"; - if (id == SPORK_3_SWIFTTX_BLOCK_FILTERING) return "SPORK_3_SWIFTTX_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_13_ENABLE_SUPERBLOCKS) return "SPORK_13_ENABLE_SUPERBLOCKS"; - if (id == SPORK_14_NEW_PROTOCOL_ENFORCEMENT) return "SPORK_14_NEW_PROTOCOL_ENFORCEMENT"; - if (id == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) return "SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2"; - if (id == SPORK_16_ZEROCOIN_MAINTENANCE_MODE) return "SPORK_16_ZEROCOIN_MAINTENANCE_MODE"; - - return "Unknown"; + CInv inv(MSG_SPORK, GetHash()); + RelayInv(inv); } + diff --git a/src/spork.h b/src/spork.h index e7c068ebcc4d0..7ecc4108183d7 100644 --- a/src/spork.h +++ b/src/spork.h @@ -7,83 +7,46 @@ #define SPORK_H #include "base58.h" +#include "hash.h" #include "key.h" #include "main.h" #include "net.h" +#include "sporkid.h" #include "sync.h" #include "util.h" #include "obfuscation.h" #include "protocol.h" - -/* - Don't ever reuse these IDs for other sporks - - This would result in old clients getting confused about which spork is for what - - Sporks 11,12, and 16 to be removed with 1st zerocoin release -*/ -#define SPORK_START 10001 -#define SPORK_END 10015 - -#define SPORK_2_SWIFTTX 10001 -#define SPORK_3_SWIFTTX_BLOCK_FILTERING 10002 -#define SPORK_5_MAX_VALUE 10004 -#define SPORK_7_MASTERNODE_SCANNING 10006 -#define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT 10007 -#define SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT 10008 -#define SPORK_10_MASTERNODE_PAY_UPDATED_NODES 10009 -//#define SPORK_11_LOCK_INVALID_UTXO 10010 -//#define SPORK_12_RECONSIDER_BLOCKS 10011 -#define SPORK_13_ENABLE_SUPERBLOCKS 10012 -#define SPORK_14_NEW_PROTOCOL_ENFORCEMENT 10013 -#define SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2 10014 -#define SPORK_16_ZEROCOIN_MAINTENANCE_MODE 10015 - -#define SPORK_2_SWIFTTX_DEFAULT 978307200 //2001-1-1 -#define SPORK_3_SWIFTTX_BLOCK_FILTERING_DEFAULT 1424217600 //2015-2-18 -#define SPORK_5_MAX_VALUE_DEFAULT 1000 //1000 PIV -#define SPORK_7_MASTERNODE_SCANNING_DEFAULT 978307200 //2001-1-1 -#define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT 4070908800 //OFF -#define SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT 4070908800 //OFF -#define SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT 4070908800 //OFF -//#define SPORK_11_LOCK_INVALID_UTXO_DEFAULT 4070908800 //OFF - NOTE: this is block height not time! -#define SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT 4070908800 //OFF -#define SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT 4070908800 //OFF -#define SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT 4070908800 //OFF -#define SPORK_16_ZEROCOIN_MAINTENANCE_MODE_DEFAULT 4070908800 //OFF - class CSporkMessage; class CSporkManager; +extern std::vector sporkDefs; extern std::map mapSporks; -extern std::map mapSporksActive; extern CSporkManager sporkManager; -void LoadSporksFromDB(); -void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); -int64_t GetSporkValue(int nSporkID); -bool IsSporkActive(int nSporkID); -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 vchSig; - int nSporkID; + +public: + SporkId nSporkID; int64_t nValue; int64_t nTimeSigned; - uint256 GetHash() - { - uint256 n = HashQuark(BEGIN(nSporkID), END(nTimeSigned)); - return n; - } + CSporkMessage(SporkId nSporkID, int64_t nValue, int64_t nTimeSigned) : nSporkID(nSporkID), nValue(nValue), nTimeSigned(nTimeSigned) {} + CSporkMessage() : nSporkID((SporkId)0), nValue(0), nTimeSigned(0) {} + + uint256 GetHash() { return HashQuark(BEGIN(nSporkID), END(nTimeSigned)); } + bool Sign(std::string strSignKey); + bool CheckSignature(bool fRequireNew = false); + void Relay(); ADD_SERIALIZE_METHODS; @@ -101,21 +64,38 @@ class CSporkMessage class CSporkManager { private: - std::vector vchSig; + mutable CCriticalSection cs; std::string strMasterPrivKey; + std::map sporkDefsById; + std::map sporkDefsByName; + std::map mapSporksActive; public: - CSporkManager() + CSporkManager(); + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(mapSporksActive); + // we don't serialize private key to prevent its leakage } - std::string GetSporkNameByID(int id); - int GetSporkIDByName(std::string strName); - bool UpdateSpork(int nSporkID, int64_t nValue); + void Clear(); + void LoadSporksFromDB(); + + void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); + int64_t GetSporkValue(SporkId nSporkID); + void ExecuteSpork(SporkId nSporkID, int nValue); + bool UpdateSpork(SporkId nSporkID, int64_t nValue); + + bool IsSporkActive(SporkId nSporkID); + std::string GetSporkNameByID(SporkId id); + SporkId GetSporkIDByName(std::string strName); + bool SetPrivKey(std::string strPrivKey); - bool CheckSignature(CSporkMessage& spork, bool fRequireNew = false); - bool Sign(CSporkMessage& spork); - void Relay(CSporkMessage& msg); + std::string ToString() const; }; #endif diff --git a/src/sporkdb.cpp b/src/sporkdb.cpp index 79be1dc7a78ad..c957cca8aceae 100644 --- a/src/sporkdb.cpp +++ b/src/sporkdb.cpp @@ -7,19 +7,19 @@ CSporkDB::CSporkDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "sporks", nCacheSize, fMemory, fWipe) {} -bool CSporkDB::WriteSpork(const int nSporkId, const CSporkMessage& spork) +bool CSporkDB::WriteSpork(const SporkId nSporkId, const CSporkMessage& spork) { LogPrintf("Wrote spork %s to database\n", sporkManager.GetSporkNameByID(nSporkId)); return Write(nSporkId, spork); } -bool CSporkDB::ReadSpork(const int nSporkId, CSporkMessage& spork) +bool CSporkDB::ReadSpork(const SporkId nSporkId, CSporkMessage& spork) { return Read(nSporkId, spork); } -bool CSporkDB::SporkExists(const int nSporkId) +bool CSporkDB::SporkExists(const SporkId nSporkId) { return Exists(nSporkId); } diff --git a/src/sporkdb.h b/src/sporkdb.h index 47a6a5af2a6b5..98f18ba5f70e4 100644 --- a/src/sporkdb.h +++ b/src/sporkdb.h @@ -19,9 +19,9 @@ class CSporkDB : public CLevelDBWrapper void operator=(const CSporkDB&); public: - bool WriteSpork(const int nSporkId, const CSporkMessage& spork); - bool ReadSpork(const int nSporkId, CSporkMessage& spork); - bool SporkExists(const int nSporkId); + bool WriteSpork(const SporkId nSporkId, const CSporkMessage& spork); + bool ReadSpork(const SporkId nSporkId, CSporkMessage& spork); + bool SporkExists(const SporkId nSporkId); }; diff --git a/src/sporkid.h b/src/sporkid.h new file mode 100644 index 0000000000000..7d681725926c2 --- /dev/null +++ b/src/sporkid.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2016-2019 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SPORKID_H +#define SPORKID_H + +/* + Don't ever reuse these IDs for other sporks + - This would result in old clients getting confused about which spork is for what +*/ + +enum SporkId : int32_t { + SPORK_2_SWIFTTX = 10001, + SPORK_3_SWIFTTX_BLOCK_FILTERING = 10002, + SPORK_5_MAX_VALUE = 10004, + SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT = 10007, + SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT = 10008, + SPORK_10_MASTERNODE_PAY_UPDATED_NODES = 10009, + SPORK_13_ENABLE_SUPERBLOCKS = 10012, + SPORK_14_NEW_PROTOCOL_ENFORCEMENT = 10013, + SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2 = 10014, + SPORK_16_ZEROCOIN_MAINTENANCE_MODE = 10015, + + SPORK_INVALID = -1 +}; + +// Default values +struct CSporkDef +{ + CSporkDef(): sporkId(SPORK_INVALID), defaultValue(0) {} + CSporkDef(SporkId id, int64_t val, std::string n): sporkId(id), defaultValue(val), name(n) {} + SporkId sporkId; + int64_t defaultValue; + std::string name; +}; + +#endif diff --git a/src/swifttx.cpp b/src/swifttx.cpp index 1d7f4ca306a27..225942d63779e 100644 --- a/src/swifttx.cpp +++ b/src/swifttx.cpp @@ -37,7 +37,7 @@ int nCompleteTXLocks; void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { if (fLiteMode) return; //disable all obfuscation/masternode related functionality - if (!IsSporkActive(SPORK_2_SWIFTTX)) return; + if (!sporkManager.IsSporkActive(SPORK_2_SWIFTTX)) return; if (!masternodeSync.IsBlockchainSynced()) return; if (strCommand == "ix") { @@ -197,7 +197,7 @@ bool IsIXTXValid(const CTransaction& txCollateral) } } - if (nValueOut > GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { + if (nValueOut > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { LogPrint("swiftx", "IsIXTXValid - Transaction value too high - %s\n", txCollateral.ToString().c_str()); return false; } @@ -461,7 +461,7 @@ void CleanTransactionLocksList() int GetTransactionLockSignatures(uint256 txHash) { if(fLargeWorkForkFound || fLargeWorkInvalidChainFound) return -2; - if (!IsSporkActive(SPORK_2_SWIFTTX)) return -1; + if (!sporkManager.IsSporkActive(SPORK_2_SWIFTTX)) return -1; std::map::iterator it = mapTxLocks.find(txHash); if(it != mapTxLocks.end()) return it->second.CountSignatures(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a616e6f846c34..79c957c774e44 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2782,7 +2782,7 @@ UniValue mintzerocoin(const UniValue& params, bool fHelp) } int64_t nTime = GetTimeMillis(); - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance."); EnsureWalletIsUnlocked(true); @@ -2886,7 +2886,7 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance."); EnsureWalletIsUnlocked(); @@ -2950,7 +2950,7 @@ UniValue spendzerocoinmints(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) + if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance."); std::string address_str = ""; @@ -3739,7 +3739,7 @@ UniValue spendrawzerocoin(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - if (GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) + if (sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance."); CBigNum serial; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index aa5349ce40d65..49d26c3b19c44 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1845,7 +1845,7 @@ bool CWallet::SelectStakeCoins(std::list >& listInp /* Disable zPIV Staking //zPIV - if ((GetBoolArg("-zpivstake", true) || fPrecompute) && chainActive.Height() > Params().Zerocoin_Block_V2_Start() && !IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + if ((GetBoolArg("-zpivstake", true) || fPrecompute) && chainActive.Height() > Params().Zerocoin_Block_V2_Start() && !sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { //Only update zPIV set once per update interval bool fUpdate = false; static int64_t nTimeLastUpdate = 0; @@ -3312,7 +3312,7 @@ void CWallet::CreateAutoMintTransaction(const CAmount& nMintAmount, CCoinControl void CWallet::AutoZeromint() { // Don't bother Autominting if Zerocoin Protocol isn't active - if (GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) return; + if (sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) return; // Wait until blockchain + masternodes are fully synced and wallet is unlocked. if (IsInitialBlockDownload() || IsLocked()){ @@ -3727,7 +3727,7 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee, bool int CMerkleTx::GetTransactionLockSignatures() const { if (fLargeWorkForkFound || fLargeWorkInvalidChainFound) return -2; - if (!IsSporkActive(SPORK_2_SWIFTTX)) return -3; + if (!sporkManager.IsSporkActive(SPORK_2_SWIFTTX)) return -3; if (!fEnableSwiftTX) return -1; //compile consessus vote diff --git a/test/functional/rpc_spork.py b/test/functional/rpc_spork.py index 671cb18efea97..11b56ceb2d63a 100755 --- a/test/functional/rpc_spork.py +++ b/test/functional/rpc_spork.py @@ -78,6 +78,13 @@ def run_test(self): assert(sporks["SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT"] == new_value) active = self.nodes[0].spork("active") assert (active["SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT"]) + self.log.info("Stopping nodes...") + self.stop_nodes() + self.log.info("Restarting node 1...") + self.start_node(1, []) + sporks = self.nodes[1].spork("show") + self.printDict(sporks) + assert (sporks["SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT"] == new_value)