Skip to content

Commit

Permalink
Merge pull request #433 from evoskuil/master
Browse files Browse the repository at this point in the history
Move hash parsing optimizations to system, delete block memory if fails.
  • Loading branch information
evoskuil authored Aug 22, 2024
2 parents e2de742 + 3dea38f commit 7df60c6
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 73 deletions.
4 changes: 0 additions & 4 deletions include/bitcoin/network/messages/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ struct BCT_API block
static const uint32_t version_minimum;
static const uint32_t version_maximum;

/// Populate header and tx hashes onto the block.
static void set_hashes(const system::chain::block& block,
const system::data_chunk& data) NOEXCEPT;

static cptr deserialize(arena& arena, uint32_t version,
const system::data_chunk& data, bool witness=true) NOEXCEPT;
static cptr deserialize(uint32_t version, const system::data_chunk& data,
Expand Down
3 changes: 0 additions & 3 deletions include/bitcoin/network/messages/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ struct BCT_API transaction
static const uint32_t version_minimum;
static const uint32_t version_maximum;

static system::hash_digest desegregated_hash(size_t witnessed,
size_t unwitnessed, const uint8_t* data) NOEXCEPT;

static cptr deserialize(uint32_t version, const system::data_chunk& data,
bool witness=true) NOEXCEPT;
static transaction deserialize(uint32_t version, system::reader& source,
Expand Down
56 changes: 13 additions & 43 deletions src/messages/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,48 +44,9 @@ const identifier block::id = identifier::block;
const uint32_t block::version_minimum = level::minimum_protocol;
const uint32_t block::version_maximum = level::maximum_protocol;

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

// Cache header hash.
block.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: *block.transactions_ptr())
{
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
typename block::cptr block::deserialize(uint32_t version,
const system::data_chunk& data, bool witness) NOEXCEPT
const data_chunk& data, bool witness) NOEXCEPT
{
static default_memory memory{};
return deserialize(*memory.get_arena(), version, data, witness);
Expand All @@ -105,10 +66,20 @@ typename block::cptr block::deserialize(arena& arena, uint32_t version,
byte_reader reader{ source, &arena };
auto& allocator = reader.get_allocator();
const auto block = allocator.new_object<chain::block>(reader, witness);
if (is_null(block) || !reader)

// Destruct block if created but failed to deserialize.
if (!reader && !is_null(block))
byte_allocator::deleter<chain::block>(&arena);

// Release memory if block construction or deserialization failed.
if (!reader || is_null(block))
{
arena.release(memory);
return nullptr;
}

set_hashes(*block, data);
// Cache hashes as extracted from serialized block.
block->set_hashes(data);

// Set size of block allocation owned by memory (zero if non-detachable).
block->set_allocation(arena.detach());
Expand All @@ -121,7 +92,6 @@ typename block::cptr block::deserialize(arena& arena, uint32_t version,
byte_allocator::deleter<chain::block>(&arena);

// Deallocate detached memory (nop if not detachable).
// Follows destructor just in case a destructor traverses memory.
arena.release(memory);
}));
}
Expand Down
25 changes: 2 additions & 23 deletions src/messages/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,6 @@ const identifier transaction::id = identifier::transaction;
const uint32_t transaction::version_minimum = level::minimum_protocol;
const uint32_t transaction::version_maximum = level::maximum_protocol;

// Optimized non-witness hash derivation using witness-serialized tx.
hash_digest transaction::desegregated_hash(size_t witnessed,
size_t unwitnessed, const uint8_t* data) NOEXCEPT
{
BC_ASSERT_MSG(!is_null(data), "nullptr");

using namespace system;
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;
}

// static
typename transaction::cptr transaction::deserialize(uint32_t version,
const data_chunk& data, bool witness) NOEXCEPT
Expand All @@ -75,8 +54,8 @@ typename transaction::cptr transaction::deserialize(uint32_t version,
const auto true_size = tx.serialized_size(true);
const auto false_size = tx.serialized_size(false);
tx.set_witness_hash(bitcoin_hash(true_size, data.data()));
tx.set_nominal_hash(desegregated_hash(true_size, false_size,
data.data()));
tx.set_nominal_hash(chain::transaction::desegregated_hash(
true_size, false_size, data.data()));
}
else
{
Expand Down

0 comments on commit 7df60c6

Please sign in to comment.