mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Merge 75135c673e into merged_master (Bitcoin PR bitcoin/bitcoin#27861)
This commit is contained in:
commit
a8a9ae2ae1
32 changed files with 407 additions and 205 deletions
|
|
@ -54,6 +54,7 @@
|
|||
#include <util/hasher.h>
|
||||
#include <util/moneystr.h>
|
||||
#include <util/rbf.h>
|
||||
#include <util/signalinterrupt.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/time.h>
|
||||
#include <util/trace.h>
|
||||
|
|
@ -1957,9 +1958,9 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AbortNode(BlockValidationState& state, const std::string& strMessage, const bilingual_str& userMessage)
|
||||
bool FatalError(Notifications& notifications, BlockValidationState& state, const std::string& strMessage, const bilingual_str& userMessage)
|
||||
{
|
||||
AbortNode(strMessage, userMessage);
|
||||
notifications.fatalError(strMessage, userMessage);
|
||||
return state.Error(strMessage);
|
||||
}
|
||||
|
||||
|
|
@ -2277,7 +2278,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
|||
// We don't write down blocks to disk if they may have been
|
||||
// corrupted, so this should be impossible unless we're having hardware
|
||||
// problems.
|
||||
return AbortNode(state, "Corrupt block found indicating potential hardware failure; shutting down");
|
||||
return FatalError(m_chainman.GetNotifications(), state, "Corrupt block found indicating potential hardware failure; shutting down");
|
||||
}
|
||||
return error("%s: Consensus::CheckBlock: %s", __func__, state.ToString());
|
||||
}
|
||||
|
|
@ -2736,7 +2737,7 @@ bool Chainstate::FlushStateToDisk(
|
|||
if (fDoFullFlush || fPeriodicWrite) {
|
||||
// Ensure we can write block index
|
||||
if (!CheckDiskSpace(m_blockman.m_opts.blocks_dir)) {
|
||||
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
|
||||
return FatalError(m_chainman.GetNotifications(), state, "Disk space is too low!", _("Disk space is too low!"));
|
||||
}
|
||||
{
|
||||
LOG_TIME_MILLIS_WITH_CATEGORY("write block and undo data to disk", BCLog::BENCH);
|
||||
|
|
@ -2756,7 +2757,7 @@ bool Chainstate::FlushStateToDisk(
|
|||
}
|
||||
}
|
||||
if (!m_blockman.WriteBlockIndexDB()) {
|
||||
return AbortNode(state, "Failed to write to block index database");
|
||||
return FatalError(m_chainman.GetNotifications(), state, "Failed to write to block index database");
|
||||
}
|
||||
|
||||
// This should be done inside WriteBatchSync, but CBlockIndex is const there
|
||||
|
|
@ -2814,11 +2815,11 @@ bool Chainstate::FlushStateToDisk(
|
|||
// an overestimation, as most will delete an existing entry or
|
||||
// overwrite one. Still, use a conservative safety factor of 2.
|
||||
if (!CheckDiskSpace(m_chainman.m_options.datadir, 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
|
||||
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
|
||||
return FatalError(m_chainman.GetNotifications(), state, "Disk space is too low!", _("Disk space is too low!"));
|
||||
}
|
||||
// Flush the chainstate (which may refer to block index entries).
|
||||
if (!CoinsTip().Flush())
|
||||
return AbortNode(state, "Failed to write to coin database");
|
||||
return FatalError(m_chainman.GetNotifications(), state, "Failed to write to coin database");
|
||||
m_last_flush = nNow;
|
||||
full_flush_completed = true;
|
||||
TRACE5(utxocache, flush,
|
||||
|
|
@ -2834,7 +2835,7 @@ bool Chainstate::FlushStateToDisk(
|
|||
GetMainSignals().ChainStateFlushed(m_chain.GetLocator());
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
return AbortNode(state, std::string("System error while flushing: ") + e.what());
|
||||
return FatalError(m_chainman.GetNotifications(), state, std::string("System error while flushing: ") + e.what());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3096,7 +3097,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
|
|||
if (!pblock) {
|
||||
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
|
||||
if (!m_blockman.ReadBlockFromDisk(*pblockNew, *pindexNew)) {
|
||||
return AbortNode(state, "Failed to read block");
|
||||
return FatalError(m_chainman.GetNotifications(), state, "Failed to read block");
|
||||
}
|
||||
pthisBlock = pblockNew;
|
||||
} else {
|
||||
|
|
@ -3294,7 +3295,7 @@ bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex*
|
|||
// If we're unable to disconnect a block during normal operation,
|
||||
// then that is a failure of our local system -- we should abort
|
||||
// rather than stay on a less work chain.
|
||||
AbortNode(state, "Failed to disconnect block; see debug.log for details");
|
||||
FatalError(m_chainman.GetNotifications(), state, "Failed to disconnect block; see debug.log for details");
|
||||
return false;
|
||||
}
|
||||
fBlocksDisconnected = true;
|
||||
|
|
@ -3521,11 +3522,11 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
|
|||
break;
|
||||
}
|
||||
|
||||
// We check shutdown only after giving ActivateBestChainStep a chance to run once so that we
|
||||
// never shutdown before connecting the genesis block during LoadChainTip(). Previously this
|
||||
// caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks
|
||||
// We check interrupt only after giving ActivateBestChainStep a chance to run once so that we
|
||||
// never interrupt before connecting the genesis block during LoadChainTip(). Previously this
|
||||
// caused an assert() failure during interrupt in such cases as the UTXO DB flushing checks
|
||||
// that the best block hash is non-null.
|
||||
if (ShutdownRequested()) break;
|
||||
if (m_chainman.m_interrupt) break;
|
||||
} while (pindexNewTip != pindexMostWork);
|
||||
CheckBlockIndex();
|
||||
|
||||
|
|
@ -3615,7 +3616,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
|
|||
|
||||
// Disconnect (descendants of) pindex, and mark them invalid.
|
||||
while (true) {
|
||||
if (ShutdownRequested()) break;
|
||||
if (m_chainman.m_interrupt) break;
|
||||
|
||||
// Make sure the queue of validation callbacks doesn't grow unboundedly.
|
||||
LimitValidationInterfaceQueue();
|
||||
|
|
@ -4442,7 +4443,7 @@ bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockV
|
|||
}
|
||||
ReceivedBlockTransactions(block, pindex, blockPos);
|
||||
} catch (const std::runtime_error& e) {
|
||||
return AbortNode(state, std::string("System error: ") + e.what());
|
||||
return FatalError(m_chainman.GetNotifications(), state, std::string("System error: ") + e.what());
|
||||
}
|
||||
|
||||
FlushStateToDisk(state, FlushStateMode::NONE);
|
||||
|
|
@ -4552,7 +4553,7 @@ void Chainstate::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_f
|
|||
{
|
||||
if (!m_mempool) return;
|
||||
::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function);
|
||||
m_mempool->SetLoadTried(!ShutdownRequested());
|
||||
m_mempool->SetLoadTried(!m_chainman.m_interrupt);
|
||||
}
|
||||
|
||||
bool Chainstate::LoadChainTip()
|
||||
|
|
@ -4685,7 +4686,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
|
|||
skipped_l3_checks = true;
|
||||
}
|
||||
}
|
||||
if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
|
||||
if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED;
|
||||
}
|
||||
if (pindexFailure) {
|
||||
LogPrintf("Verification error: coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
|
||||
|
|
@ -4718,7 +4719,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
|
|||
LogPrintf("Verification error: found unconnectable block at %d, hash=%s (%s)\n", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
|
||||
return VerifyDBResult::CORRUPTED_BLOCK_DB;
|
||||
}
|
||||
if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
|
||||
if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4886,7 +4887,7 @@ bool ChainstateManager::LoadBlockIndex()
|
|||
}
|
||||
|
||||
for (CBlockIndex* pindex : vSortedByHeight) {
|
||||
if (ShutdownRequested()) return false;
|
||||
if (m_interrupt) return false;
|
||||
if (pindex->IsAssumedValid() ||
|
||||
(pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
|
||||
(pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
|
||||
|
|
@ -4992,7 +4993,7 @@ void Chainstate::LoadExternalBlockFile(
|
|||
// such as a block fails to deserialize.
|
||||
uint64_t nRewind = blkdat.GetPos();
|
||||
while (!blkdat.eof()) {
|
||||
if (ShutdownRequested()) return;
|
||||
if (m_chainman.m_interrupt) return;
|
||||
|
||||
blkdat.SetPos(nRewind);
|
||||
nRewind++; // start one byte further next time, in case of failure
|
||||
|
|
@ -5133,7 +5134,7 @@ void Chainstate::LoadExternalBlockFile(
|
|||
}
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
AbortNode(std::string("System error: ") + e.what());
|
||||
m_chainman.GetNotifications().fatalError(std::string("System error: ") + e.what());
|
||||
}
|
||||
LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
|
||||
}
|
||||
|
|
@ -5585,7 +5586,7 @@ bool ChainstateManager::ActivateSnapshot(
|
|||
snapshot_chainstate.reset();
|
||||
bool removed = DeleteCoinsDBFromDisk(*snapshot_datadir, /*is_snapshot=*/true);
|
||||
if (!removed) {
|
||||
AbortNode(strprintf("Failed to remove snapshot chainstate dir (%s). "
|
||||
GetNotifications().fatalError(strprintf("Failed to remove snapshot chainstate dir (%s). "
|
||||
"Manually remove it before restarting.\n", fs::PathToString(*snapshot_datadir)));
|
||||
}
|
||||
}
|
||||
|
|
@ -5625,13 +5626,13 @@ struct StopHashingException : public std::exception
|
|||
{
|
||||
const char* what() const throw() override
|
||||
{
|
||||
return "ComputeUTXOStats interrupted by shutdown.";
|
||||
return "ComputeUTXOStats interrupted.";
|
||||
}
|
||||
};
|
||||
|
||||
static void SnapshotUTXOHashBreakpoint()
|
||||
static void SnapshotUTXOHashBreakpoint(const util::SignalInterrupt& interrupt)
|
||||
{
|
||||
if (ShutdownRequested()) throw StopHashingException();
|
||||
if (interrupt) throw StopHashingException();
|
||||
}
|
||||
|
||||
bool ChainstateManager::PopulateAndValidateSnapshot(
|
||||
|
|
@ -5708,7 +5709,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
// If our average Coin size is roughly 41 bytes, checking every 120,000 coins
|
||||
// means <5MB of memory imprecision.
|
||||
if (coins_processed % 120000 == 0) {
|
||||
if (ShutdownRequested()) {
|
||||
if (m_interrupt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -5765,7 +5766,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
|
||||
try {
|
||||
maybe_stats = ComputeUTXOStats(
|
||||
CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, SnapshotUTXOHashBreakpoint);
|
||||
CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, [&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); });
|
||||
} catch (StopHashingException const&) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -5850,8 +5851,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
// through IsUsable() checks, or
|
||||
//
|
||||
// (ii) giving each chainstate its own lock instead of using cs_main for everything.
|
||||
SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
|
||||
std::function<void(bilingual_str)> shutdown_fnc)
|
||||
SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation()
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (m_ibd_chainstate.get() == &this->ActiveChainstate() ||
|
||||
|
|
@ -5903,7 +5903,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
|
|||
user_error = strprintf(Untranslated("%s\n%s"), user_error, util::ErrorString(rename_result));
|
||||
}
|
||||
|
||||
shutdown_fnc(user_error);
|
||||
GetNotifications().fatalError(user_error.original, user_error);
|
||||
};
|
||||
|
||||
if (index_new.GetBlockHash() != snapshot_blockhash) {
|
||||
|
|
@ -5943,7 +5943,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
|
|||
CoinStatsHashType::HASH_SERIALIZED,
|
||||
&ibd_coins_db,
|
||||
m_blockman,
|
||||
SnapshotUTXOHashBreakpoint);
|
||||
[&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); });
|
||||
} catch (StopHashingException const&) {
|
||||
return SnapshotCompletionResult::STATS_FAILED;
|
||||
}
|
||||
|
|
@ -6052,9 +6052,10 @@ static ChainstateManager::Options&& Flatten(ChainstateManager::Options&& opts)
|
|||
return std::move(opts);
|
||||
}
|
||||
|
||||
ChainstateManager::ChainstateManager(Options options, node::BlockManager::Options blockman_options)
|
||||
: m_options{Flatten(std::move(options))},
|
||||
m_blockman{std::move(blockman_options)} {}
|
||||
ChainstateManager::ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options)
|
||||
: m_interrupt{interrupt},
|
||||
m_options{Flatten(std::move(options))},
|
||||
m_blockman{interrupt, std::move(blockman_options)} {}
|
||||
|
||||
ChainstateManager::~ChainstateManager()
|
||||
{
|
||||
|
|
@ -6199,13 +6200,13 @@ bool ChainstateManager::ValidatedSnapshotCleanup()
|
|||
|
||||
fs::path tmp_old{ibd_chainstate_path + "_todelete"};
|
||||
|
||||
auto rename_failed_abort = [](
|
||||
auto rename_failed_abort = [this](
|
||||
fs::path p_old,
|
||||
fs::path p_new,
|
||||
const fs::filesystem_error& err) {
|
||||
LogPrintf("%s: error renaming file (%s): %s\n",
|
||||
__func__, fs::PathToString(p_old), err.what());
|
||||
AbortNode(strprintf(
|
||||
GetNotifications().fatalError(strprintf(
|
||||
"Rename of '%s' -> '%s' failed. "
|
||||
"Cannot clean up the background chainstate leveldb directory.",
|
||||
fs::PathToString(p_old), fs::PathToString(p_new)));
|
||||
|
|
@ -6230,7 +6231,7 @@ bool ChainstateManager::ValidatedSnapshotCleanup()
|
|||
}
|
||||
|
||||
if (!DeleteCoinsDBFromDisk(tmp_old, /*is_snapshot=*/false)) {
|
||||
// No need to AbortNode because once the unneeded bg chainstate data is
|
||||
// No need to FatalError because once the unneeded bg chainstate data is
|
||||
// moved, it will not interfere with subsequent initialization.
|
||||
LogPrintf("Deletion of %s failed. Please remove it manually, as the " /* Continued */
|
||||
"directory is now unnecessary.\n",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue