void WaitForShutdown(boost::thread_group* threadGroup) { bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. while (!fShutdown) { MilliSleep(200); fShutdown = ShutdownRequested(); } if (threadGroup) { Interrupt(*threadGroup); threadGroup->join_all(); } }
void DetectShutdownThread(boost::thread_group* threadGroup) { bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. while (!fShutdown) { MilliSleep(200); fShutdown = ShutdownRequested(); } if (threadGroup) { threadGroup->interrupt_all(); threadGroup->join_all(); } }
static void WaitForShutdown() { while (!ShutdownRequested()) { MilliSleep(200); } Interrupt(); }
void WaitForShutdown(boost::thread_group* threadGroup) { bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. while (!fShutdown) { MilliSleep(200); fShutdown = ShutdownRequested(); }; LogPrintf("PerfectCoin shutdown.\n\n"); if (threadGroup) { threadGroup->interrupt_all(); threadGroup->join_all(); }; }
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript) { static const int nInnerLoopCount = 0x10000; int nHeightEnd = 0; int nHeight = 0; unsigned int profile = 0x3; { // Don't keep cs_main locked LOCK(cs_main); nHeight = chainActive.Height(); nHeightEnd = nHeight+nGenerate; } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd && !ShutdownRequested()) { std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } if (pblock->GetBlockTime() >= Params().GetConsensus().nNeoScryptFork) profile = 0x0; while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetPoWHash(profile), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; --nMaxTries; } if (nMaxTries == 0) { break; } if (pblock->nNonce == nInnerLoopCount) { continue; } std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock); if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); //mark script as important because it was used at least for one coinbase output if the script came from the wallet if (keepScript) { coinbaseScript->KeepScript(); } } return blockHashes; }
void WaitForShutdown(boost::thread_group* threadGroup) { bool fShutdown = ShutdownRequested(); if (!fDaemon && GetBoolArg("-cli", false)) { threadGroup->create_thread(boost::bind(&TraceThread<void (*)()>, "cli", &ThreadCli)); }; // Tell the main threads to shutdown. while (!fShutdown) { MilliSleep(200); fShutdown = ShutdownRequested(); }; LogPrintf("vTorrent shutdown.\n\n"); if (threadGroup) { threadGroup->interrupt_all(); threadGroup->join_all(); }; }
void CMasternode::Check(bool forceCheck) { if(ShutdownRequested()) return; if(!forceCheck && (GetTime() - lastTimeChecked < MASTERNODE_CHECK_SECONDS)) return; lastTimeChecked = GetTime(); //once spent, stop doing the checks if(activeState == MASTERNODE_VIN_SPENT) return; if(lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS){ activeState = MASTERNODE_PRE_ENABLED; return; } if(!IsPingedWithin(MASTERNODE_REMOVAL_SECONDS)){ activeState = MASTERNODE_REMOVE; return; } if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)){ activeState = MASTERNODE_EXPIRED; return; } if(!unitTest){ CValidationState state; CMutableTransaction tx = CMutableTransaction(); CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey); tx.vin.push_back(vin); tx.vout.push_back(vout); { TRY_LOCK(cs_main, lockMain); if(!lockMain) return; if(!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL)){ activeState = MASTERNODE_VIN_SPENT; return; } } } activeState = MASTERNODE_ENABLED; // OK }
void CAlphanode::Check() { if(ShutdownRequested()) return; //TODO: Random segfault with this line removed TRY_LOCK(cs_main, lockRecv); if(!lockRecv) return; //once spent, stop doing the checks if(activeState == ALPHANODE_VIN_SPENT) return; if(!UpdatedWithin(ALPHANODE_REMOVAL_SECONDS)){ activeState = ALPHANODE_REMOVE; return; } if(!UpdatedWithin(ALPHANODE_EXPIRATION_SECONDS)){ activeState = ALPHANODE_EXPIRED; return; } if(!unitTest){ CValidationState state; CTransaction tx = CTransaction(); CTxOut vout = CTxOut(Params().DarkSendPoolMax(), darkSendPool.collateralPubKey); tx.vin.push_back(vin); tx.vout.push_back(vout); if(!AcceptableInputs(mempool, tx, false, NULL)){ activeState = ALPHANODE_VIN_SPENT; return; } } activeState = ALPHANODE_ENABLED; // OK }
void CMasternode::Check(bool fForce) { LOCK(cs); if(ShutdownRequested()) return; if(!fForce && (GetTime() - nTimeLastChecked < MASTERNODE_CHECK_SECONDS)) return; nTimeLastChecked = GetTime(); LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state\n", vin.prevout.ToStringShort(), GetStateString()); //once spent, stop doing the checks if(IsOutpointSpent()) return; int nHeight = 0; if(!fUnitTest) { TRY_LOCK(cs_main, lockMain); if(!lockMain) return; CCoins coins; if(!pcoinsTip->GetCoins(vin.prevout.hash, coins) || (unsigned int)vin.prevout.n>=coins.vout.size() || coins.vout[vin.prevout.n].IsNull()) { nActiveState = MASTERNODE_OUTPOINT_SPENT; LogPrint("masternode", "CMasternode::Check -- Failed to find Masternode UTXO, masternode=%s\n", vin.prevout.ToStringShort()); return; } nHeight = chainActive.Height(); } if(IsPoSeBanned()) { if(nHeight < nPoSeBanHeight) return; // too early? // Otherwise give it a chance to proceed further to do all the usual checks and to change its state. // Masternode still will be on the edge and can be banned back easily if it keeps ignoring mnverify // or connect attempts. Will require few mnverify messages to strengthen its position in mn list. LogPrintf("CMasternode::Check -- Masternode %s is unbanned and back in list now\n", vin.prevout.ToStringShort()); DecreasePoSeBanScore(); } else if(nPoSeBanScore >= MASTERNODE_POSE_BAN_MAX_SCORE) { nActiveState = MASTERNODE_POSE_BAN; // ban for the whole payment cycle nPoSeBanHeight = nHeight + mnodeman.size(); LogPrintf("CMasternode::Check -- Masternode %s is banned till block %d now\n", vin.prevout.ToStringShort(), nPoSeBanHeight); return; } int nActiveStatePrev = nActiveState; bool fOurMasternode = fMasterNode && activeMasternode.pubKeyMasternode == pubKeyMasternode; // masternode doesn't meet payment protocol requirements ... bool fRequireUpdate = nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto() || // or it's our own node and we just updated it to the new protocol but we are still waiting for activation ... (fOurMasternode && nProtocolVersion < PROTOCOL_VERSION); if(fRequireUpdate) { nActiveState = MASTERNODE_UPDATE_REQUIRED; if(nActiveStatePrev != nActiveState) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); } return; } // keep old masternodes on start, give them a chance to receive updates... bool fWaitForPing = !masternodeSync.IsMasternodeListSynced() && !IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS); if(fWaitForPing && !fOurMasternode) { // ...but if it was already expired before the initial check - return right away if(IsExpired() || IsWatchdogExpired() || IsNewStartRequired()) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state, waiting for ping\n", vin.prevout.ToStringShort(), GetStateString()); return; } } // don't expire if we are still in "waiting for ping" mode unless it's our own masternode if(!fWaitForPing || fOurMasternode) { if(!IsPingedWithin(MASTERNODE_NEW_START_REQUIRED_SECONDS)) { nActiveState = MASTERNODE_NEW_START_REQUIRED; if(nActiveStatePrev != nActiveState) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); } return; } bool fWatchdogActive = masternodeSync.IsSynced() && mnodeman.IsWatchdogActive(); bool fWatchdogExpired = (fWatchdogActive && ((GetTime() - nTimeLastWatchdogVote) > MASTERNODE_WATCHDOG_MAX_SECONDS)); LogPrint("masternode", "CMasternode::Check -- outpoint=%s, nTimeLastWatchdogVote=%d, GetTime()=%d, fWatchdogExpired=%d\n", vin.prevout.ToStringShort(), nTimeLastWatchdogVote, GetTime(), fWatchdogExpired); if(fWatchdogExpired) { nActiveState = MASTERNODE_WATCHDOG_EXPIRED; if(nActiveStatePrev != nActiveState) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); } return; } if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)) { nActiveState = MASTERNODE_EXPIRED; if(nActiveStatePrev != nActiveState) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); } return; } } if(lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS) { nActiveState = MASTERNODE_PRE_ENABLED; if(nActiveStatePrev != nActiveState) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); } return; } nActiveState = MASTERNODE_ENABLED; // OK if(nActiveStatePrev != nActiveState) { LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); } }
void ThreadSendAlert(CConnman& connman) { if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert")) return; // Wait one minute so we get well connected. If we only need to print // but not to broadcast - do this right away. if (mapArgs.count("-sendalert")) MilliSleep(60*1000); // // Alerts are relayed around the network until nRelayUntil, flood // filling to every node. // After the relay time is past, new nodes are told about alerts // when they connect to peers, until either nExpiration or // the alert is cancelled by a newer alert. // Nodes never save alerts to disk, they are in-memory-only. // CAlert alert; alert.nRelayUntil = GetAdjustedTime() + 15 * 60; alert.nExpiration = GetAdjustedTime() + 30 * 60 * 60; alert.nID = 1; // keep track of alert IDs somewhere alert.nCancel = 0; // cancels previous messages up to this ID number // These versions are protocol versions alert.nMinVer = 70000; alert.nMaxVer = 70103; // // 1000 for Misc warnings like out of disk space and clock is wrong // 2000 for longer invalid proof-of-work chain // Higher numbers mean higher priority alert.nPriority = 5000; alert.strComment = ""; alert.strStatusBar = "URGENT: Upgrade required: see https://www.terracoin.io"; // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done: // alert.setSubVer.insert(std::string("/Terracoin Core:0.12.0.58/")); // Sign if(!alert.Sign()) { LogPrintf("ThreadSendAlert() : could not sign alert\n"); return; } // Test CDataStream sBuffer(SER_NETWORK, CLIENT_VERSION); sBuffer << alert; CAlert alert2; sBuffer >> alert2; if (!alert2.CheckSignature(Params().AlertKey())) { printf("ThreadSendAlert() : CheckSignature failed\n"); return; } assert(alert2.vchMsg == alert.vchMsg); assert(alert2.vchSig == alert.vchSig); alert.SetNull(); printf("\nThreadSendAlert:\n"); printf("hash=%s\n", alert2.GetHash().ToString().c_str()); printf("%s", alert2.ToString().c_str()); printf("vchMsg=%s\n", HexStr(alert2.vchMsg).c_str()); printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str()); // Confirm if (!mapArgs.count("-sendalert")) return; while (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && !ShutdownRequested()) MilliSleep(500); if (ShutdownRequested()) return; // Send printf("ThreadSendAlert() : Sending alert\n"); int nSent = 0; { connman.ForEachNode([&alert2, &connman, &nSent](CNode* pnode) { if (alert2.RelayTo(pnode, connman)) { printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str()); nSent++; } }); } printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent); }
void ThreadSendAlert() { if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert")) return; MilliSleep(60*1000); // Wait a minute so we get connected // // Alerts are relayed around the network until nRelayUntil, flood // filling to every node. // After the relay time is past, new nodes are told about alerts // when they connect to peers, until either nExpiration or // the alert is cancelled by a newer alert. // Nodes never save alerts to disk, they are in-memory-only. // CAlert alert; alert.nRelayUntil = GetTime() + 15 * 60; alert.nExpiration = GetTime() + 365 * 60 * 60; alert.nID = 1000; // use https://github.com/zcash/zcash/wiki/specification#assigned-numbers to keep track of alert IDs alert.nCancel = 0; // cancels previous messages up to this ID number // These versions are protocol versions // 170002 : 1.0.0 alert.nMinVer = 170002; alert.nMaxVer = 170002; // // main.cpp: // 1000 for Misc warnings like out of disk space and clock is wrong // 2000 for longer invalid proof-of-work chain // Higher numbers mean higher priority // 4000 or higher will put the RPC into safe mode alert.nPriority = 5000; alert.strComment = ""; alert.strStatusBar = "URGENT: Upgrade required: see https://z.cash"; alert.strRPCError = "URGENT: Upgrade required: see https://z.cash"; // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done: // alert.setSubVer.insert(std::string("/MagicBean:0.7.2/")); // Sign const CChainParams& chainparams = Params(); std::string networkID = chainparams.NetworkIDString(); bool fIsTestNet = networkID.compare("test") == 0; std::vector<unsigned char> vchTmp(ParseHex(fIsTestNet ? pszTestNetPrivKey : pszPrivKey)); CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end()); CDataStream sMsg(SER_NETWORK, CLIENT_VERSION); sMsg << *(CUnsignedAlert*)&alert; alert.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end()); CKey key; if (!key.SetPrivKey(vchPrivKey, false)) { printf("ThreadSendAlert() : key.SetPrivKey failed\n"); return; } if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig)) { printf("ThreadSendAlert() : key.Sign failed\n"); return; } // Test CDataStream sBuffer(SER_NETWORK, CLIENT_VERSION); sBuffer << alert; CAlert alert2; sBuffer >> alert2; if (!alert2.CheckSignature(chainparams.AlertKey())) { printf("ThreadSendAlert() : CheckSignature failed\n"); return; } assert(alert2.vchMsg == alert.vchMsg); assert(alert2.vchSig == alert.vchSig); alert.SetNull(); printf("\nThreadSendAlert:\n"); printf("hash=%s\n", alert2.GetHash().ToString().c_str()); printf("%s\n", alert2.ToString().c_str()); printf("vchMsg=%s\n", HexStr(alert2.vchMsg).c_str()); printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str()); // Confirm if (!mapArgs.count("-sendalert")) return; while (vNodes.size() < 1 && !ShutdownRequested()) MilliSleep(500); if (ShutdownRequested()) return; // Send printf("ThreadSendAlert() : Sending alert\n"); int nSent = 0; { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { if (alert2.RelayTo(pnode)) { printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str()); nSent++; } } } printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent); }
void CMasternode::Check(bool fForce) { AssertLockHeld(cs_main); LOCK(cs); if (ShutdownRequested()) return; if (!fForce && (GetTime() - nTimeLastChecked < MASTERNODE_CHECK_SECONDS)) return; nTimeLastChecked = GetTime(); LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state\n", outpoint.ToStringShort(), GetStateString()); //once spent, stop doing the checks if (IsOutpointSpent()) return; int nHeight = 0; if (!fUnitTest) { Coin coin; if (!GetUTXOCoin(outpoint, coin)) { nActiveState = MASTERNODE_OUTPOINT_SPENT; LogPrint(MCLog::MN, "CMasternode::Check -- Failed to find Masternode UTXO, masternode=%s\n", outpoint.ToStringShort()); return; } nHeight = chainActive.Height(); } if (IsPoSeBanned()) { if (nHeight < nPoSeBanHeight) return; // too early? // Otherwise give it a chance to proceed further to do all the usual checks and to change its state. // Masternode still will be on the edge and can be banned back easily if it keeps ignoring mnverify // or connect attempts. Will require few mnverify messages to strengthen its position in mn list. LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is unbanned and back in list now\n", outpoint.ToStringShort()); DecreasePoSeBanScore(); } else if (nPoSeBanScore >= MASTERNODE_POSE_BAN_MAX_SCORE) { nActiveState = MASTERNODE_POSE_BAN; // ban for the whole payment cycle nPoSeBanHeight = nHeight + mnodeman.size(); LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is banned till block %d now\n", outpoint.ToStringShort(), nPoSeBanHeight); return; } int nActiveStatePrev = nActiveState; bool fOurMasternode = fMasternodeMode && activeMasternode.pubKeyMasternode == pubKeyMasternode; // masternode doesn't meet payment protocol requirements ... bool fRequireUpdate = nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto() || // or it's our own node and we just updated it to the new protocol but we are still waiting for activation ... (fOurMasternode && nProtocolVersion < PROTOCOL_VERSION); if (fRequireUpdate) { nActiveState = MASTERNODE_UPDATE_REQUIRED; if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } // keep old masternodes on start, give them a chance to receive updates... bool fWaitForPing = !masternodeSync.IsMasternodeListSynced() && !IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS); if (fWaitForPing && !fOurMasternode) { // ...but if it was already expired before the initial check - return right away if (IsExpired() || IsSentinelPingExpired() || IsNewStartRequired()) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state, waiting for ping\n", outpoint.ToStringShort(), GetStateString()); return; } } // don't expire if we are still in "waiting for ping" mode unless it's our own masternode if (!fWaitForPing || fOurMasternode) { if (!IsPingedWithin(MASTERNODE_NEW_START_REQUIRED_SECONDS)) { nActiveState = MASTERNODE_NEW_START_REQUIRED; if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } if (!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)) { nActiveState = MASTERNODE_EXPIRED; if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } // part 1: expire based on machinecoind ping bool fSentinelPingActive = masternodeSync.IsSynced() && mnodeman.IsSentinelPingActive(); bool fSentinelPingExpired = fSentinelPingActive && !IsPingedWithin(MASTERNODE_SENTINEL_PING_MAX_SECONDS); LogPrint(MCLog::MN, "CMasternode::Check -- outpoint=%s, GetAdjustedTime()=%d, fSentinelPingExpired=%d\n", outpoint.ToStringShort(), GetAdjustedTime(), fSentinelPingExpired); if (fSentinelPingExpired) { nActiveState = MASTERNODE_SENTINEL_PING_EXPIRED; if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } } // We require MNs to be in PRE_ENABLED until they either start to expire or receive a ping and go into ENABLED state // Works on mainnet/testnet only and not the case on regtest. if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { if (lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS) { nActiveState = MASTERNODE_PRE_ENABLED; if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } } if (!fWaitForPing || fOurMasternode) { // part 2: expire based on sentinel info bool fSentinelPingActive = masternodeSync.IsSynced() && mnodeman.IsSentinelPingActive(); bool fSentinelPingExpired = fSentinelPingActive && !lastPing.fSentinelIsCurrent; LogPrint(MCLog::MN, "CMasternode::Check -- outpoint=%s, GetAdjustedTime()=%d, fSentinelPingExpired=%d\n", outpoint.ToStringShort(), GetAdjustedTime(), fSentinelPingExpired); if (fSentinelPingExpired) { nActiveState = MASTERNODE_SENTINEL_PING_EXPIRED; if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } } nActiveState = MASTERNODE_ENABLED; // OK if (nActiveStatePrev != nActiveState) { LogPrint(MCLog::MN, "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } }
void CActiveLegacyMasternodeManager::DoMaintenance(CConnman& connman) { if (ShutdownRequested()) return; ManageState(connman); }
bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator) { // The prior implementation of txindex was always in sync with block index // and presence was indicated with a boolean DB flag. If the flag is set, // this means the txindex from a previous version is valid and in sync with // the chain tip. The first step of the migration is to unset the flag and // write the chain hash to a separate key, DB_TXINDEX_BLOCK. After that, the // index entries are copied over in batches to the new database. Finally, // DB_TXINDEX_BLOCK is erased from the old database and the block hash is // written to the new database. // // Unsetting the boolean flag ensures that if the node is downgraded to a // previous version, it will not see a corrupted, partially migrated index // -- it will see that the txindex is disabled. When the node is upgraded // again, the migration will pick up where it left off and sync to the block // with hash DB_TXINDEX_BLOCK. bool f_legacy_flag = false; block_tree_db.ReadFlag("txindex", f_legacy_flag); if (f_legacy_flag) { if (!block_tree_db.Write(DB_TXINDEX_BLOCK, best_locator)) { return error("%s: cannot write block indicator", __func__); } if (!block_tree_db.WriteFlag("txindex", false)) { return error("%s: cannot write block index db flag", __func__); } } CBlockLocator locator; if (!block_tree_db.Read(DB_TXINDEX_BLOCK, locator)) { return true; } int64_t count = 0; LogPrintf("Upgrading txindex database... [0%%]\n"); uiInterface.ShowProgress(_("Upgrading txindex database"), 0, true); int report_done = 0; const size_t batch_size = 1 << 24; // 16 MiB CDBBatch batch_newdb(*this); CDBBatch batch_olddb(block_tree_db); std::pair<unsigned char, uint256> key; std::pair<unsigned char, uint256> begin_key{DB_TXINDEX, uint256()}; std::pair<unsigned char, uint256> prev_key = begin_key; bool interrupted = false; std::unique_ptr<CDBIterator> cursor(block_tree_db.NewIterator()); for (cursor->Seek(begin_key); cursor->Valid(); cursor->Next()) { boost::this_thread::interruption_point(); if (ShutdownRequested()) { interrupted = true; break; } if (!cursor->GetKey(key)) { return error("%s: cannot get key from valid cursor", __func__); } if (key.first != DB_TXINDEX) { break; } // Log progress every 10%. if (++count % 256 == 0) { // Since txids are uniformly random and traversed in increasing order, the high 16 bits // of the hash can be used to estimate the current progress. const uint256& txid = key.second; uint32_t high_nibble = (static_cast<uint32_t>(*(txid.begin() + 0)) << 8) + (static_cast<uint32_t>(*(txid.begin() + 1)) << 0); int percentage_done = (int)(high_nibble * 100.0 / 65536.0 + 0.5); uiInterface.ShowProgress(_("Upgrading txindex database"), percentage_done, true); if (report_done < percentage_done/10) { LogPrintf("Upgrading txindex database... [%d%%]\n", percentage_done); report_done = percentage_done/10; } } CDiskTxPos value; if (!cursor->GetValue(value)) { return error("%s: cannot parse txindex record", __func__); } batch_newdb.Write(key, value); batch_olddb.Erase(key); if (batch_newdb.SizeEstimate() > batch_size || batch_olddb.SizeEstimate() > batch_size) { // NOTE: it's OK to delete the key pointed at by the current DB cursor while iterating // because LevelDB iterators are guaranteed to provide a consistent view of the // underlying data, like a lightweight snapshot. WriteTxIndexMigrationBatches(*this, block_tree_db, batch_newdb, batch_olddb, prev_key, key); prev_key = key; } } // If these final DB batches complete the migration, write the best block // hash marker to the new database and delete from the old one. This signals // that the former is fully caught up to that point in the blockchain and // that all txindex entries have been removed from the latter. if (!interrupted) { batch_olddb.Erase(DB_TXINDEX_BLOCK); batch_newdb.Write(DB_BEST_BLOCK, locator); } WriteTxIndexMigrationBatches(*this, block_tree_db, batch_newdb, batch_olddb, begin_key, key); if (interrupted) { LogPrintf("[CANCELLED].\n"); return false; } uiInterface.ShowProgress("", 100, false); LogPrintf("[DONE].\n"); return true; }