Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1220,26 +1220,27 @@ void ImportBlocks(ChainstateManager& chainman, std::span<const fs::path> 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<uint256, FlatFilePos> 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;
Expand Down
57 changes: 48 additions & 9 deletions src/primitives/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
24 changes: 16 additions & 8 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <ios>
#include <limits>
#include <memory>
#include <mutex>
#include <numeric>
#include <string>
#include <tuple>
Expand Down Expand Up @@ -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;

Expand All @@ -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 <typename Stream>
inline void Serialize(Stream& s) const {
SerializeTransaction(*this, s, s.template GetParams<TransactionSerParams>());
Expand All @@ -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;
Expand All @@ -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();
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO out-of-band comment by @hodlinator:

Looking further up, computing the hashes entails serializing the transaction we've just deserialized.. Maybe could have an alternative ctor which takes in the raw memory.

}

friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
return !operator==(a, b);
return !(a == b);
}

std::string ToString() const;
Expand Down
Loading