@@ -408,29 +408,29 @@ code CLASS::unspent_duplicates(const header_link& link,
408408
409409// protected
410410TEMPLATE
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
450450TEMPLATE
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
590609bool 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,
0 commit comments