@@ -235,7 +235,7 @@ hashes block::transaction_hashes(bool witness) const NOEXCEPT
235235{
236236 const auto count = txs_->size ();
237237 const auto size = is_odd (count) && count > one ? add1 (count) : count;
238- hashes out ( size) ;
238+ hashes out{ size } ;
239239
240240 // Extra allocation for odd count optimizes for merkle root.
241241 // Vector capacity is never reduced when resizing to smaller size.
@@ -250,6 +250,21 @@ hashes block::transaction_hashes(bool witness) const NOEXCEPT
250250 return out;
251251}
252252
253+ // computed
254+ size_t block::outputs () const NOEXCEPT
255+ {
256+ if (txs_->empty ())
257+ return zero;
258+
259+ // Overflow returns max_size_t.
260+ const auto outs = [](size_t total, const auto & tx) NOEXCEPT
261+ {
262+ return ceilinged_add (total, tx->outputs ());
263+ };
264+
265+ return std::accumulate (std::next (txs_->begin ()), txs_->end (), zero, outs);
266+ }
267+
253268// computed
254269size_t block::spends () const NOEXCEPT
255270{
@@ -262,6 +277,7 @@ size_t block::spends() const NOEXCEPT
262277 return ceilinged_add (total, tx->inputs ());
263278 };
264279
280+ // inputs() is add1(spends()) if the block is valid (one coinbase input).
265281 return std::accumulate (std::next (txs_->begin ()), txs_->end (), zero, ins);
266282}
267283
@@ -382,22 +398,17 @@ bool block::is_forward_reference() const NOEXCEPT
382398 if (txs_->empty ())
383399 return false ;
384400
385- const auto sum_txs = sub1 (txs_->size ());
386- unordered_set_of_hash_cref hashes{ sum_txs };
387- const auto spent = [&hashes](const input::cptr& input) NOEXCEPT
401+ unordered_set_of_hash_cref hashes{ sub1 (txs_->size ()) };
402+ for (auto tx = txs_->rbegin (); tx != std::prev (txs_->rend ()); ++tx)
388403 {
389- return hashes.find (std::ref (input->point ().hash ())) != hashes.end ();
390- };
404+ for (const auto & in: *(*tx)->inputs_ptr ())
405+ if (hashes.contains (in->point ().hash ()))
406+ return true ;
391407
392- const auto spend = [&spent, &hashes](const auto & tx) NOEXCEPT
393- {
394- const auto & ins = tx->inputs_ptr ();
395- const auto forward = std::any_of (ins->begin (), ins->end (), spent);
396- hashes.emplace (tx->get_hash (false ));
397- return forward;
398- };
408+ hashes.emplace ((*tx)->get_hash (false ));
409+ }
399410
400- return std::any_of (txs_-> rbegin (), std::prev (txs_-> rend ()), spend) ;
411+ return false ;
401412}
402413
403414// This also precludes the block merkle calculation DoS exploit by preventing
@@ -408,27 +419,13 @@ bool block::is_internal_double_spend() const NOEXCEPT
408419 if (txs_->empty ())
409420 return false ;
410421
411- // Overflow returns max_size_t.
412- const auto sum_ins = [](size_t total, const auto & tx) NOEXCEPT
413- {
414- return ceilinged_add (total, tx->inputs ());
415- };
416-
417- const auto tx1 = std::next (txs_->begin ());
418- const auto spends_count = std::accumulate (tx1, txs_->end (), zero, sum_ins);
419- unordered_set_of_point_cref points{ spends_count };
420- const auto spent = [&points](const input::cptr& in) NOEXCEPT
421- {
422- return !points.emplace (in->point ()).second ;
423- };
424-
425- const auto double_spent = [&spent](const auto & tx) NOEXCEPT
426- {
427- const auto & ins = tx->inputs_ptr ();
428- return std::any_of (ins->begin (), ins->end (), spent);
429- };
422+ unordered_set_of_point_cref points{ spends () };
423+ for (auto tx = std::next (txs_->begin ()); tx != txs_->end (); ++tx)
424+ for (const auto & in: *(*tx)->inputs_ptr ())
425+ if (!points.emplace (in->point ()).second )
426+ return true ;
430427
431- return std::any_of (tx1, txs_-> end (), double_spent) ;
428+ return false ;
432429}
433430
434431// private
@@ -477,7 +474,7 @@ bool block::is_hash_limit_exceeded() const NOEXCEPT
477474 return false ;
478475
479476 // A set is used to collapse duplicates.
480- unordered_set_of_hash_cref hashes{};
477+ unordered_set_of_hash_cref hashes{ txs_-> size () };
481478
482479 // Just the coinbase tx hash, skip its null input hashes.
483480 hashes.emplace (txs_->front ()->get_hash (false ));
@@ -645,7 +642,7 @@ uint64_t block::fees() const NOEXCEPT
645642 return ceilinged_add (total, tx->fee ());
646643 };
647644
648- return std::accumulate (txs_->begin (), txs_->end (), uint64_t {0 }, value);
645+ return std::accumulate (txs_->begin (), txs_->end (), uint64_t {}, value);
649646}
650647
651648uint64_t block::claim () const NOEXCEPT
@@ -709,7 +706,7 @@ bool block::populate(const chain::context& ctx) const NOEXCEPT
709706
710707 const auto start = std::next (txs_->begin ());
711708 const auto bip68 = ctx.is_enabled (chain::flags::bip68_rule);
712- unordered_map_of_cref_point_to_output_cptr_cref points{};
709+ unordered_map_of_cref_point_to_output_cptr_cref points{ outputs () };
713710 uint32_t index{};
714711
715712 // Populate outputs hash table.
0 commit comments