Skip to content

Commit a6b8d42

Browse files
committed
Refactor to_spend_sets for complete integrity handling.
1 parent c3fe6a2 commit a6b8d42

File tree

3 files changed

+160
-105
lines changed

3 files changed

+160
-105
lines changed

include/bitcoin/database/impl/query/confirm.ipp

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -408,29 +408,29 @@ code CLASS::unspent_duplicates(const header_link& link,
408408

409409
// protected
410410
TEMPLATE
411-
spend_set CLASS::to_spend_set(const tx_link& link) const NOEXCEPT
411+
bool CLASS::get_spend_set(spend_set& set, const tx_link& link) const NOEXCEPT
412412
{
413413
table::transaction::get_version_puts tx{};
414414
if (!store_.tx.get(link, tx))
415-
return {};
415+
return false;
416416

417417
table::puts::get_spends puts{};
418418
puts.spend_fks.resize(tx.ins_count);
419419
if (!store_.puts.get(tx.puts_fk, puts))
420-
return {};
420+
return false;
421421

422-
spend_set set{ link, tx.version, {} };
422+
set.tx = link;
423+
set.version = tx.version;
424+
set.spends.clear();
423425
set.spends.reserve(tx.ins_count);
424426
table::spend::get_prevout_sequence get{};
425-
426-
// This reduced a no-bypass 840k sync/confirmable/confirm run by 8.3%.
427427
const auto ptr = store_.spend.get_memory();
428428

429-
// This is not concurrent because to_spend_sets is (by tx).
429+
// This is not concurrent because get_spend_sets is (by tx).
430430
for (const auto& spend_fk: puts.spend_fks)
431431
{
432432
if (!store_.spend.get(ptr, spend_fk, get))
433-
return {};
433+
return false;
434434

435435
// Translate result set to public struct.
436436
#if defined(HAVE_CLANG)
@@ -443,44 +443,56 @@ spend_set CLASS::to_spend_set(const tx_link& link) const NOEXCEPT
443443
#endif
444444
}
445445

446-
return set;
446+
return true;
447447
}
448448

449449
// protected
450450
TEMPLATE
451-
spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
451+
bool CLASS::get_spend_sets(spend_sets& sets,
452+
const header_link& link) const NOEXCEPT
452453
{
453454
// This is the only search [txs.find].
454455
// Coinbase tx does not spend so is not retrieved.
455456
const auto txs = to_spending_transactions(link);
456-
457-
// Empty here is normal.
458457
if (txs.empty())
459-
return {};
458+
{
459+
sets.clear();
460+
return true;
461+
}
460462

461-
spend_sets sets{ txs.size() };
462-
const auto to_set = [this](const auto& tx) NOEXCEPT
463+
std::atomic<bool> fault{};
464+
const auto to_set = [this, &fault](const auto& tx) NOEXCEPT
463465
{
464-
// Empty here implies integrity fault.
465-
return to_spend_set(tx);
466+
spend_set set{};
467+
if (!get_spend_set(set, tx)) fault.store(true);
468+
return set;
466469
};
467470

468471
// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
472+
sets.resize(txs.size());
469473
std_transform(bc::par_unseq, txs.begin(), txs.end(), sets.begin(), to_set);
474+
return populate_prevout1(sets, link);
475+
}
470476

471-
// TODO: move to new method populate_prevout_tx_and_coinbase.
472-
// TODO: provide alternate implementations using prevout table and not.
473-
// TODO: with consolidated points this becomes is_cb(to_tx(get_spend_key)).
474-
// TODO: populate alternate within to_spend_set, which adds only tx table.
475-
const auto count = [](size_t total, const auto& set) NOEXCEPT
476-
{
477-
return system::ceilinged_add(total, set.spends.size());
478-
};
479-
const auto spends = std::accumulate(sets.begin(), sets.end(), zero, count);
477+
// private/static
478+
TEMPLATE
479+
size_t CLASS::sets_size(const spend_sets& sets) NOEXCEPT
480+
{
481+
return std::accumulate(sets.begin(), sets.end(), zero,
482+
[](size_t total, const auto& set) NOEXCEPT
483+
{
484+
return system::ceilinged_add(total, set.spends.size());
485+
});
486+
}
480487

488+
TEMPLATE
489+
bool CLASS::populate_prevout1(spend_sets& sets,
490+
const header_link& link) const NOEXCEPT
491+
{
481492
table::prevout::record_get prevouts{};
482-
prevouts.values.resize(spends);
483-
store_.prevout.at(link, prevouts);
493+
prevouts.values.resize(sets_size(sets));
494+
if (!store_.prevout.at(link, prevouts))
495+
return false;
484496

485497
size_t index{};
486498
for (auto& set: sets)
@@ -490,7 +502,13 @@ spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
490502
spend.prevout_tx_fk = prevouts.output_tx_fk(index++);
491503
}
492504

493-
return sets;
505+
return true;
506+
}
507+
508+
TEMPLATE
509+
bool CLASS::populate_prevout2(spend_sets&, const header_link&) const NOEXCEPT
510+
{
511+
return true;
494512
}
495513

496514
// split(3) 219 secs for 400k-410k; split(2) 255 and split(0) 456 (not shown).
@@ -501,15 +519,16 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
501519
if (!get_context(ctx, link))
502520
return error::integrity;
503521

504-
// This is rarely invoked (bip30).
505522
code ec{};
506523
if ((ec = unspent_duplicates(link, ctx)))
507524
return ec;
508525

509-
// Empty here could imply integrity fault.
510-
const auto sets = to_spend_sets(link);
526+
spend_sets sets{};
527+
if (!get_spend_sets(sets, link))
528+
return error::integrity;
529+
511530
if (sets.empty())
512-
return ec;
531+
return error::success;
513532

514533
std::atomic<error::error_t> fault{ error::success };
515534

@@ -590,15 +609,17 @@ TEMPLATE
590609
bool CLASS::set_strong(const header_link& link, const tx_links& txs,
591610
bool positive) NOEXCEPT
592611
{
593-
// Preallocate all strong_tx records for the block and reuse memory ptr.
594612
using namespace system;
595613
using link_t = table::strong_tx::link;
614+
using element_t = table::strong_tx::record;
615+
616+
// Preallocate all strong_tx records for the block and reuse memory ptr.
596617
const auto records = possible_narrow_cast<link_t::integer>(txs.size());
597618
auto record = store_.strong_tx.allocate(records);
598619
const auto ptr = store_.strong_tx.get_memory();
599620

600-
for (const tx_link& tx: txs)
601-
if (!store_.strong_tx.put(ptr, record++, tx, table::strong_tx::record
621+
for (const auto tx: txs)
622+
if (!store_.strong_tx.put(ptr, record++, link_t{ tx }, element_t
602623
{
603624
{},
604625
link,

include/bitcoin/database/query.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,8 +576,10 @@ class query
576576
const context& ctx) const NOEXCEPT;
577577

578578
// Critical path
579-
spend_set to_spend_set(const tx_link& link) const NOEXCEPT;
580-
spend_sets to_spend_sets(const header_link& link) const NOEXCEPT;
579+
bool populate_prevout1(spend_sets& sets, const header_link& link) const NOEXCEPT;
580+
bool populate_prevout2(spend_sets& sets, const header_link& link) const NOEXCEPT;
581+
bool get_spend_set(spend_set& set, const tx_link& link) const NOEXCEPT;
582+
bool get_spend_sets(spend_sets& set, const header_link& link) const NOEXCEPT;
581583
bool is_spent_prevout(const point_link& link, index index,
582584
const tx_link& self=tx_link::terminal) const NOEXCEPT;
583585
error::error_t spent_prevout(const point_link& link, index index,
@@ -629,6 +631,7 @@ class query
629631
struct maybe_strong { header_link block{}; tx_link tx{}; bool strong{}; };
630632
using maybe_strongs = std_vector<maybe_strong>;
631633

634+
static size_t sets_size(const spend_sets& sets) NOEXCEPT;
632635
static inline tx_links strong_only(const maybe_strongs& pairs) NOEXCEPT;
633636
static inline bool contains(const maybe_strongs& pairs,
634637
const header_link& block) NOEXCEPT;

0 commit comments

Comments
 (0)