Skip to content

Commit 28043d5

Browse files
committed
Implement prevout table optionality.
1 parent 65a4512 commit 28043d5

File tree

2 files changed

+66
-41
lines changed

2 files changed

+66
-41
lines changed

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

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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
478494
TEMPLATE
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

508520
TEMPLATE
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
662685
TEMPLATE
663686
bool 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;

include/bitcoin/database/query.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,8 @@ class query
577577
const context& ctx) const NOEXCEPT;
578578

579579
// Critical path
580-
bool populate_prevout1(spend_sets& sets, const header_link& link) const NOEXCEPT;
581-
bool populate_prevout2(spend_sets& sets, const header_link& link) const NOEXCEPT;
580+
bool populate_prevouts(spend_sets& sets) const NOEXCEPT;
581+
bool populate_prevouts(spend_sets& sets, const header_link& link) const NOEXCEPT;
582582
bool get_spend_set(spend_set& set, const tx_link& link) const NOEXCEPT;
583583
bool get_spend_sets(spend_sets& set, const header_link& link) const NOEXCEPT;
584584
bool is_spent_prevout(const point_link& link, index index,
@@ -632,7 +632,6 @@ class query
632632
struct maybe_strong { header_link block{}; tx_link tx{}; bool strong{}; };
633633
using maybe_strongs = std_vector<maybe_strong>;
634634

635-
static size_t sets_size(const spend_sets& sets) NOEXCEPT;
636635
static inline tx_links strong_only(const maybe_strongs& pairs) NOEXCEPT;
637636
static inline bool contains(const maybe_strongs& pairs,
638637
const header_link& block) NOEXCEPT;

0 commit comments

Comments
 (0)