@@ -284,34 +284,34 @@ error::error_t CLASS::spent_prevout(const point_link& link, index index,
284284
285285 // Iterate points by point hash (of output tx) because may be conflicts.
286286 // Search key must be passed as an l-value as it is held by reference.
287- const auto point_sk = get_point_key (link);
288- auto point = store_.point .it (point_sk);
289- if (!point)
290- return error::integrity;
287+ // //const auto point_sk = get_point_key(link);
288+ // //auto point = store_.point.it(point_sk);
289+ // //if (!point)
290+ // // return error::integrity;
291+
292+ // //do
293+ // //{
294+ // Iterate all spends of the point to find double spends.
295+ // Search key must be passed as an l-value as it is held by reference.
296+ const auto spend_sk = table::spend::compose (link /* point.self()*/ , index);
297+ auto it = store_.spend .it (spend_sk);
298+ if (!it)
299+ return error::success;
291300
301+ table::spend::get_parent spend{};
292302 do
293303 {
294- // Iterate all spends of the point to find double spends.
295- // Search key must be passed as an l-value as it is held by reference.
296- const auto spend_sk = table::spend::compose (point.self (), index);
297- auto it = store_.spend .it (spend_sk);
298- if (!it)
299- return error::success;
304+ if (!store_.spend .get (it, spend))
305+ return error::integrity;
300306
301- table::spend::get_parent spend{};
302- do
303- {
304- if (!store_.spend .get (it, spend))
305- return error::integrity;
306-
307- // is_strong_tx (search) only called in the case of duplicate.
308- // Other parent tx of spend is strong (confirmed spent prevout).
309- if ((spend.parent_fk != self) && is_strong_tx (spend.parent_fk ))
310- return error::confirmed_double_spend;
311- }
312- while (it.advance ());
307+ // is_strong_tx (search) only called in the case of duplicate.
308+ // Other parent tx of spend is strong (confirmed spent prevout).
309+ if ((spend.parent_fk != self) && is_strong_tx (spend.parent_fk ))
310+ return error::confirmed_double_spend;
313311 }
314- while (point.advance ());
312+ while (it.advance ());
313+ // //}
314+ // //while (point.advance());
315315 return error::success;
316316}
317317
@@ -391,9 +391,23 @@ code CLASS::unspent_duplicates(const header_link& link,
391391 // [txs.find, {tx.iterate}, strong_tx.it]
392392 auto coinbases = to_strong_txs (get_tx_key (to_coinbase (link)));
393393
394- // Current block is not set strong.
395- if (is_zero (coinbases.size ()))
396- return error::success;
394+ if (prevout_enabled ())
395+ {
396+ // Current block is not set strong.
397+ if (is_zero (coinbases.size ()))
398+ return error::success;
399+ }
400+ else
401+ {
402+ // Found only this block's coinbase instance, no duplicates.
403+ if (is_one (coinbases.size ()))
404+ return error::success;
405+
406+ // Remove self (will be not found if current block is not set_strong).
407+ const auto self = std::find (coinbases.begin (), coinbases.end (), link);
408+ if (self == coinbases.end () || coinbases.erase (self) == coinbases.end ())
409+ return error::integrity;
410+ }
397411
398412 // [point.first, is_spent_prevout()]
399413 const auto spent = [this ](const auto & tx) NOEXCEPT
@@ -468,29 +482,27 @@ bool CLASS::get_spend_sets(spend_sets& sets,
468482 return set;
469483 };
470484
471- // C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
472485 sets.resize (txs.size ());
486+
487+ // C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
473488 std_transform (bc::par_unseq, txs.begin (), txs.end (), sets.begin (), to_set);
474- return populate_prevout1 (sets, link);
489+
490+ return prevout_enabled () ? populate_prevouts (sets, link) :
491+ populate_prevouts (sets);
475492}
476493
477- // private/static
478494TEMPLATE
479- size_t CLASS::sets_size (const spend_sets& sets) NOEXCEPT
495+ bool CLASS::populate_prevouts (spend_sets& sets,
496+ const header_link& link) const NOEXCEPT
480497{
481- return std::accumulate (sets.begin (), sets.end (), zero,
498+ const auto sets_size = std::accumulate (sets.begin (), sets.end (), zero,
482499 [](size_t total, const auto & set) NOEXCEPT
483500 {
484501 return system::ceilinged_add (total, set.spends .size ());
485502 });
486- }
487503
488- TEMPLATE
489- bool CLASS::populate_prevout1 (spend_sets& sets,
490- const header_link& link) const NOEXCEPT
491- {
492504 table::prevout::record_get prevouts{};
493- prevouts.values .resize (sets_size (sets) );
505+ prevouts.values .resize (sets_size);
494506 if (!store_.prevout .at (link, prevouts))
495507 return false ;
496508
@@ -506,8 +518,19 @@ bool CLASS::populate_prevout1(spend_sets& sets,
506518}
507519
508520TEMPLATE
509- bool CLASS::populate_prevout2 (spend_sets&, const header_link& ) const NOEXCEPT
521+ bool CLASS::populate_prevouts (spend_sets& sets ) const NOEXCEPT
510522{
523+ // This technique does not benefit from skipping internal spends, and
524+ // therefore also requires set_strong before query, and self removal.
525+ for (auto & set: sets)
526+ for (auto & spend: set.spends )
527+ {
528+ spend.prevout_tx_fk = to_tx (get_point_key (spend.point_fk ));
529+ spend.coinbase = is_coinbase (spend.prevout_tx_fk );
530+ if (spend.prevout_tx_fk == table::prevout::tx::terminal)
531+ return false ;
532+ }
533+
511534 return true ;
512535}
513536
@@ -662,6 +685,9 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT
662685TEMPLATE
663686bool CLASS::set_prevouts (const header_link& link, const block& block) NOEXCEPT
664687{
688+ if (!prevout_enabled ())
689+ return true ;
690+
665691 // Empty or coinbase only implies no spends.
666692 if (block.transactions () <= one)
667693 return true ;
0 commit comments