From 6c5a5f14e367f36b3b7330fde53150b4e242aaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Tue, 10 Jun 2025 16:14:22 +0200 Subject: [PATCH 1/2] Show reindex progress in ImportBlocks --- src/node/blockstorage.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 3c01ff2e8d62c..cd8ef26b98683 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -1220,26 +1220,27 @@ void ImportBlocks(ChainstateManager& chainman, std::span import_ // -reindex if (!chainman.m_blockman.m_blockfiles_indexed) { - int nFile = 0; + int total_files{0}; + while (fs::exists(chainman.m_blockman.GetBlockPosFilename(FlatFilePos(total_files, 0)))) { + total_files++; + } + // Map of disk positions for blocks with unknown parent (only used for reindex); // parent hash -> child disk position, multiple children can have the same parent. std::multimap blocks_with_unknown_parent; - while (true) { + + for (int nFile = 0; nFile < total_files; ++nFile) { FlatFilePos pos(nFile, 0); - if (!fs::exists(chainman.m_blockman.GetBlockPosFilename(pos))) { - break; // No block files left to reindex - } AutoFile file{chainman.m_blockman.OpenBlockFile(pos, /*fReadOnly=*/true)}; if (file.IsNull()) { break; // This error is logged in OpenBlockFile } - LogInfo("Reindexing block file blk%05u.dat...", (unsigned int)nFile); + LogInfo("Reindexing block file %05u/%d...", (unsigned int)nFile, total_files); chainman.LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent); if (chainman.m_interrupt) { LogInfo("Interrupt requested. Exit reindexing."); return; } - nFile++; } WITH_LOCK(::cs_main, chainman.m_blockman.m_block_tree_db->WriteReindexing(false)); chainman.m_blockman.m_blockfiles_indexed = true; From feb458e6bf455a35b653cd60cf00d7d1f394a054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Tue, 10 Jun 2025 18:35:49 +0200 Subject: [PATCH 2/2] Lazy init hashes in CTransaction --- src/primitives/transaction.cpp | 57 ++++++++++++++++++++++++++++------ src/primitives/transaction.h | 24 +++++++++----- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index e80ab60fcd87c..40e521b967448 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -78,22 +78,61 @@ bool CTransaction::ComputeHasWitness() const }); } -Txid CTransaction::ComputeHash() const +CTransaction::CTransaction(const CMutableTransaction& tx) + : vin(tx.vin), vout(tx.vout), version{tx.version}, nLockTime{tx.nLockTime}, + m_has_witness{ComputeHasWitness()} {} + +CTransaction::CTransaction(CMutableTransaction&& tx) + : vin(std::move(tx.vin)), vout(std::move(tx.vout)), version{tx.version}, + nLockTime{tx.nLockTime}, m_has_witness{ComputeHasWitness()} {} + +CTransaction::CTransaction(const CTransaction& tx) + : vin(tx.vin), vout(tx.vout), version(tx.version), nLockTime(tx.nLockTime), + m_has_witness(tx.m_has_witness) { - return Txid::FromUint256((HashWriter{} << TX_NO_WITNESS(*this)).GetHash()); + if (tx.m_hash) { + assert(tx.m_witness_hash); + m_hash = new Txid(*tx.m_hash); + m_witness_hash = new Wtxid(*tx.m_witness_hash); + std::call_once(m_initialized, [] {}); + } } -Wtxid CTransaction::ComputeWitnessHash() const +CTransaction::CTransaction(CTransaction&& tx) noexcept + : vin(std::move(tx.vin)), vout(std::move(tx.vout)), + version(tx.version), nLockTime(tx.nLockTime), + m_has_witness(tx.m_has_witness), + m_hash(tx.m_hash), m_witness_hash(tx.m_witness_hash) { - if (!HasWitness()) { - return Wtxid::FromUint256(hash.ToUint256()); - } + tx.m_hash = nullptr; + tx.m_witness_hash = nullptr; + if (m_hash) std::call_once(m_initialized, [] {}); +} + +CTransaction::~CTransaction() +{ + delete m_hash; + delete m_witness_hash; +} + +const Txid& CTransaction::GetHash() const +{ + std::call_once(m_initialized, [this] { + assert(!m_hash && !m_witness_hash); + auto h{(HashWriter{} << TX_NO_WITNESS(*this)).GetHash()}; + m_hash = new Txid(Txid::FromUint256(h)); - return Wtxid::FromUint256((HashWriter{} << TX_WITH_WITNESS(*this)).GetHash()); + if (HasWitness()) h = (HashWriter{} << TX_WITH_WITNESS(*this)).GetHash(); + m_witness_hash = new Wtxid(Wtxid::FromUint256(h)); + }); + return *m_hash; } -CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), version{tx.version}, nLockTime{tx.nLockTime}, m_has_witness{ComputeHasWitness()}, hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} -CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), version{tx.version}, nLockTime{tx.nLockTime}, m_has_witness{ComputeHasWitness()}, hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} +const Wtxid& CTransaction::GetWitnessHash() const +{ + (void)GetHash(); + return *m_witness_hash; +} CAmount CTransaction::GetValueOut() const { diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 295bce61b93c7..0bfacc4bcd1e5 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -311,11 +312,10 @@ class CTransaction private: /** Memory only. */ const bool m_has_witness; - const Txid hash; - const Wtxid m_witness_hash; - Txid ComputeHash() const; - Wtxid ComputeWitnessHash() const; + mutable Txid* m_hash{nullptr}; + mutable Wtxid* m_witness_hash{nullptr}; + mutable std::once_flag m_initialized{}; bool ComputeHasWitness() const; @@ -324,6 +324,10 @@ class CTransaction explicit CTransaction(const CMutableTransaction& tx); explicit CTransaction(CMutableTransaction&& tx); + CTransaction(const CTransaction& tx); + CTransaction(CTransaction&& tx) noexcept; + ~CTransaction(); + template inline void Serialize(Stream& s) const { SerializeTransaction(*this, s, s.template GetParams()); @@ -340,8 +344,8 @@ class CTransaction return vin.empty() && vout.empty(); } - const Txid& GetHash() const LIFETIMEBOUND { return hash; } - const Wtxid& GetWitnessHash() const LIFETIMEBOUND { return m_witness_hash; }; + const Txid& GetHash() const LIFETIMEBOUND; + const Wtxid& GetWitnessHash() const LIFETIMEBOUND; // Return sum of txouts. CAmount GetValueOut() const; @@ -355,17 +359,21 @@ class CTransaction bool IsCoinBase() const { - return (vin.size() == 1 && vin[0].prevout.IsNull()); + return vin.size() == 1 && vin[0].prevout.IsNull(); } friend bool operator==(const CTransaction& a, const CTransaction& b) { + // Quick checks first to avoid hash computation + if (a.nLockTime != b.nLockTime || a.version != b.version || a.vin.size() != b.vin.size() || a.vout.size() != b.vout.size()) { + return false; + } return a.GetWitnessHash() == b.GetWitnessHash(); } friend bool operator!=(const CTransaction& a, const CTransaction& b) { - return !operator==(a, b); + return !(a == b); } std::string ToString() const;