@@ -338,31 +338,31 @@ error::error_t CLASS::spent_prevout(const point_link& link, index index,
338338
339339// protected
340340TEMPLATE
341- error::error_t CLASS::unspendable_prevout (const point_link& link,
342- uint32_t sequence, uint32_t version, const context& ctx) const NOEXCEPT
341+ error::error_t CLASS::unspendable_prevout (uint32_t sequence, bool coinbase,
342+ const tx_link& prevout_tx, uint32_t version,
343+ const context& ctx) const NOEXCEPT
343344{
344- // TODO: If unconfirmed_spend is encountered, perform a search (free).
345- // It's not possible for a confirmed spend to be the wrong tx instance.
346- // This eliminates the hash lookup and to_strong(hash) iteration.
347-
348345 // TODO: don't need to return tx link here, just the block (for strong/context).
349346 // MOOT: get_point_key(link) is redundant with spent_prevout().
350347 // to_strong has the only searches [tx.iterate, strong.find].
351- const auto strong_prevout = to_strong (get_point_key (link));
348+ // //const auto strong_prevout = to_strong(get_point_key(link));
349+ // //
350+ // //// prevout is strong if present.
351+ // //if (strong_prevout.block.is_terminal())
352+ // // return strong_prevout.tx.is_terminal() ?
353+ // // error::missing_previous_output : error::unconfirmed_spend;
352354
353- // prevout is strong if present .
354- if (strong_prevout. block . is_terminal ())
355- return strong_prevout. tx . is_terminal () ?
356- error::missing_previous_output : error::unconfirmed_spend ;
355+ // TODO: If unconfirmed_spend is encountered, perform a search (free) .
356+ // It's not possible for a confirmed spend to be the wrong tx instance.
357+ // This eliminates the hash lookup and to_strong(hash) iteration.
358+ const auto block = to_block (prevout_tx) ;
357359
358360 context out{};
359- if (!get_context (out, strong_prevout. block ))
361+ if (!get_context (out, block))
360362 return error::integrity;
361363
362- // All txs with same hash must be coinbase or not, so this query is redundant.
363- // TODO: Just use the cached value for the prevout, obtained in validation.
364- if (is_coinbase (strong_prevout.tx ) &&
365- !transaction::is_coinbase_mature (out.height , ctx.height ))
364+ // All txs with same hash must be coinbase or not.
365+ if (coinbase && !transaction::is_coinbase_mature (out.height , ctx.height ))
366366 return error::coinbase_maturity;
367367
368368 if (ctx.is_enabled (system::chain::flags::bip68_rule) &&
@@ -387,15 +387,10 @@ code CLASS::unspent_duplicates(const header_link& link,
387387 // [txs.find, {tx.iterate}, strong_tx.it]
388388 auto coinbases = to_strong_txs (get_tx_key (to_coinbase (link)));
389389
390- // Found only this block's coinbase instance, no duplicates .
391- if (is_one (coinbases.size ()))
390+ // Current block is not set strong .
391+ if (is_zero (coinbases.size ()))
392392 return error::success;
393393
394- // Remove self (will be not found if current block is not set_strong).
395- const auto self = std::find (coinbases.begin (), coinbases.end (), link);
396- if (self == coinbases.end () || coinbases.erase (self) == coinbases.end ())
397- return error::integrity;
398-
399394 // [point.first, is_spent_prevout()]
400395 const auto spent = [this ](const auto & tx) NOEXCEPT
401396 {
@@ -502,16 +497,34 @@ spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
502497 if (txs.empty ())
503498 return {};
504499
505- spend_sets out { txs.size () };
500+ spend_sets sets { txs.size () };
506501 const auto to_set = [this ](const auto & tx) NOEXCEPT
507502 {
508503 return to_spend_set (tx);
509504 };
510505
511506 // C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
512- std_transform (bc::par_unseq, txs.begin (), txs.end (), out.begin (), to_set);
507+ std_transform (bc::par_unseq, txs.begin (), txs.end (), sets.begin (), to_set);
508+
509+ const auto count = [](size_t total, const auto & set) NOEXCEPT
510+ {
511+ return system::ceilinged_add (total, set.spends .size ());
512+ };
513+ const auto spends = std::accumulate (sets.begin (), sets.end (), zero, count);
514+
515+ table::prevout::record_get prevouts{};
516+ prevouts.values .resize (spends);
517+ store_.prevout .at (link, prevouts);
513518
514- return out;
519+ size_t index{};
520+ for (auto & set: sets)
521+ for (auto & spend: set.spends )
522+ {
523+ spend.coinbase = prevouts.coinbase (index);
524+ spend.prevout_tx_fk = prevouts.output_tx_fk (index++);
525+ }
526+
527+ return sets;
515528}
516529
517530// split(3) 219 secs for 400k-410k; split(2) 255 and split(0) 456 (not shown).
@@ -526,8 +539,7 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
526539 code ec{};
527540 if ((ec = unspent_duplicates (link, ctx)))
528541 return ec;
529-
530- // This is eliminated by caching, since each non-internal spend is cached.
542+
531543 const auto sets = to_spend_sets (link);
532544 if (sets.empty ())
533545 return ec;
@@ -536,27 +548,39 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
536548
537549 const auto is_unspendable = [this , &ctx, &fault](const auto & set) NOEXCEPT
538550 {
551+ // TODO: prevout table optimized, evaluate.
539552 error::error_t ec{};
540553 for (const auto & spend: set.spends )
541- if ((ec = unspendable_prevout (spend.point_fk , spend.sequence ,
542- set.version , ctx)))
554+ {
555+ if (spend.prevout_tx_fk == table::prevout::tx::terminal)
556+ continue ;
557+
558+ if ((ec = unspendable_prevout (spend.sequence , spend.coinbase ,
559+ spend.prevout_tx_fk , set.version , ctx)))
543560 {
544561 fault.store (ec);
545562 return true ;
546563 }
564+ }
547565
548566 return false ;
549567 };
550568
551569 const auto is_spent = [this , &fault](const auto & set) NOEXCEPT
552570 {
571+ // TODO: point table optimize via consolidation with spend table.
553572 error::error_t ec{};
554- for (const auto & spend: set.spends )
573+ for (const spend_set::spend& spend: set.spends )
574+ {
575+ if (spend.prevout_tx_fk == table::prevout::tx::terminal)
576+ continue ;
577+
555578 if ((ec = spent_prevout (spend.point_fk , spend.point_index , set.tx )))
556579 {
557580 fault.store (ec);
558581 return true ;
559582 }
583+ }
560584
561585 return false ;
562586 };
@@ -708,7 +732,7 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT
708732}
709733
710734TEMPLATE
711- bool CLASS::set_prevouts (size_t height , const block& block) NOEXCEPT
735+ bool CLASS::set_prevouts (const header_link& link , const block& block) NOEXCEPT
712736{
713737 // Empty or coinbase only implies no spends.
714738 if (block.transactions () <= one)
@@ -719,7 +743,7 @@ bool CLASS::set_prevouts(size_t height, const block& block) NOEXCEPT
719743
720744 // Clean single allocation failure (e.g. disk full).
721745 const table::prevout::record_put_ref prevouts{ {}, block };
722- return store_.prevout .put (height , prevouts);
746+ return store_.prevout .put (link , prevouts);
723747 // ========================================================================
724748}
725749
0 commit comments