Skip to content

Commit 2028001

Browse files
committed
Simplify is_internal_double_spend and is_forward_reference.
1 parent 9734372 commit 2028001

2 files changed

Lines changed: 35 additions & 37 deletions

File tree

include/bitcoin/system/chain/block.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class BC_API block
8989
hashes transaction_hashes(bool witness) const NOEXCEPT;
9090

9191
/// Computed properties.
92+
size_t outputs() const NOEXCEPT;
9293
size_t spends() const NOEXCEPT;
9394
size_t weight() const NOEXCEPT;
9495
uint64_t fees() const NOEXCEPT;

src/chain/block.cpp

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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
254269
size_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

651648
uint64_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

Comments
 (0)