Skip to content

Commit

Permalink
Merge pull request #1529 from evoskuil/master
Browse files Browse the repository at this point in the history
Move hash parsing optimizations from network.
  • Loading branch information
evoskuil authored Aug 22, 2024
2 parents 72058b0 + 42ff428 commit 5ff7c3e
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/bitcoin/system/chain/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class BC_API block
/// Reference used to avoid copy, sets cache if not set (not thread safe).
const hash_digest& get_hash() const NOEXCEPT;

/// Optimized hash derivations using wire serialization of same block.
void set_hashes(const data_chunk& data) NOEXCEPT;

/// Set/get memory allocation.
void set_allocation(size_t allocation) const NOEXCEPT;
size_t get_allocation() const NOEXCEPT;
Expand Down
5 changes: 5 additions & 0 deletions include/bitcoin/system/chain/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ class BC_API transaction
typedef std::shared_ptr<const transaction> cptr;
typedef input_cptrs::const_iterator input_iterator;

/// Not genesis and at least 100 blocks deep.
static bool is_coinbase_mature(size_t coinbase_height,
size_t height) NOEXCEPT;

/// Optimized non-witness hash derivation using witness-serialized tx.
static hash_digest desegregated_hash(size_t witnessed,
size_t unwitnessed, const uint8_t* data) NOEXCEPT;

/// Constructors.
/// -----------------------------------------------------------------------

Expand Down
38 changes: 38 additions & 0 deletions src/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,44 @@ const hash_digest& block::get_hash() const NOEXCEPT
return header_->get_hash();
}

void block::set_hashes(const data_chunk& data) NOEXCEPT
{
constexpr auto header_size = chain::header::serialized_size();

// Cache header hash.
header_->set_hash(bitcoin_hash(header_size, data.data()));

// Skip transaction count, guarded by preceding successful block construct.
auto start = std::next(data.data(), header_size);
std::advance(start, size_variable(*start));

// Cache transaction hashes.
auto coinbase = true;
for (const auto& tx: *txs_)
{
const auto witness_size = tx->serialized_size(true);

// If !witness then wire txs cannot have been segregated.
if (tx->is_segregated())
{
const auto nominal_size = tx->serialized_size(false);

tx->set_nominal_hash(transaction::desegregated_hash(
witness_size, nominal_size, start));

if (!coinbase)
tx->set_witness_hash(bitcoin_hash(witness_size, start));
}
else
{
tx->set_nominal_hash(bitcoin_hash(witness_size, start));
}

coinbase = false;
std::advance(start, witness_size);
}
}

// static/private
block::sizes block::serialized_size(
const chain::transaction_cptrs& txs) NOEXCEPT
Expand Down
21 changes: 21 additions & 0 deletions src/chain/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,27 @@ hash_digest transaction::hash(bool witness) const NOEXCEPT
return digest;
}

// static
hash_digest transaction::desegregated_hash(size_t witnessed,
size_t unwitnessed, const uint8_t* data) NOEXCEPT
{
if (is_null(data))
return null_hash;

constexpr auto preamble = sizeof(uint32_t) + two * sizeof(uint8_t);
const auto puts = floored_subtract(unwitnessed, two * sizeof(uint32_t));
const auto locktime = floored_subtract(witnessed, sizeof(uint32_t));

hash_digest digest{};
stream::out::fast stream{ digest };
hash::sha256x2::fast sink{ stream };
sink.write_bytes(data, sizeof(uint32_t));
sink.write_bytes(std::next(data, preamble), puts);
sink.write_bytes(std::next(data, locktime), sizeof(uint32_t));
sink.flush();
return digest;
}

// Methods.
// ----------------------------------------------------------------------------

Expand Down

0 comments on commit 5ff7c3e

Please sign in to comment.