Skip to content

Commit fb787da

Browse files
committed
Minor confirmation optimizations, style.
1 parent 05efa01 commit fb787da

File tree

6 files changed

+93
-53
lines changed

6 files changed

+93
-53
lines changed

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

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,21 @@ error::error_t CLASS::unspendable_prevout(const point_link& link,
303303
}
304304

305305
TEMPLATE
306-
code CLASS::unspent_duplicates(const tx_link& coinbase,
306+
code CLASS::unspent_duplicates(const header_link& link,
307307
const context& ctx) const NOEXCEPT
308308
{
309309
if (!ctx.is_enabled(system::chain::flags::bip30_rule))
310310
return error::success;
311311

312312
// This will be empty if current block is not set_strong.
313-
const auto coinbases = to_strong_txs(get_tx_key(coinbase));
314-
if (coinbases.empty())
315-
return error::integrity;
313+
const auto coinbases = to_strong_txs(get_tx_key(to_coinbase(link)));
316314

317315
if (is_one(coinbases.size()))
318316
return error::success;
319317

318+
if (coinbases.empty())
319+
return error::integrity;
320+
320321
// bip30: all (but self) must be confirmed spent or dup invalid (cb only).
321322
size_t unspent{};
322323
for (const auto& tx: coinbases)
@@ -327,6 +328,8 @@ code CLASS::unspent_duplicates(const tx_link& coinbase,
327328
return is_zero(unspent) ? error::integrity : error::success;
328329
}
329330

331+
#if defined(UNDEFINED)
332+
330333
// protected
331334
TEMPLATE
332335
spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
@@ -407,31 +410,27 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
407410
return ec;
408411
}
409412

410-
#if defined(UNDEFINED)
413+
#endif
414+
411415

412416
// protected
413417
TEMPLATE
414418
spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
415419
{
416-
const auto txs = to_transactions(link);
420+
// Coinbase tx does not spend.
421+
const auto txs = to_spending_transactions(link);
422+
417423
if (txs.empty())
418424
return {};
419425

420-
// Coinbase optimization.
421426
spend_sets out{ txs.size() };
422-
out.front().tx = txs.front();
423-
if (is_one(out.size()))
424-
return out;
425-
426-
const auto non_coinbase = std::next(txs.begin());
427427
const auto to_set = [this](const auto& tx) NOEXCEPT
428428
{
429429
return to_spend_set(tx);
430430
};
431431

432432
// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
433-
std_transform(bc::par_unseq, std::next(txs.begin()), txs.end(),
434-
std::next(out.begin()), to_set);
433+
std_transform(bc::par_unseq, txs.begin(), txs.end(), out.begin(), to_set);
435434

436435
return out;
437436
}
@@ -444,16 +443,14 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
444443
if (!get_context(ctx, link))
445444
return error::integrity;
446445

447-
// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
448-
const auto sets = to_spend_sets(link);
449-
if (sets.empty())
450-
return error::integrity;
451-
452446
code ec{};
453-
if ((ec = unspent_duplicates(sets.front().tx, ctx)))
447+
if ((ec = unspent_duplicates(link, ctx)))
454448
return ec;
455449

456-
const auto non_coinbase = std::next(sets.begin());
450+
const auto sets = to_spend_sets(link);
451+
if (sets.empty())
452+
return ec;
453+
457454
std::atomic<error::error_t> fault{ error::success };
458455

459456
const auto is_unspendable = [this, &ctx, &fault](const auto& set) NOEXCEPT
@@ -484,16 +481,18 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
484481
};
485482

486483
// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
487-
if (std_any_of(bc::par_unseq, non_coinbase, sets.end(), is_unspendable))
484+
if (std_any_of(bc::par_unseq, sets.begin(), sets.end(), is_unspendable))
488485
return { fault.load() };
489486

490487
// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
491-
if (std_any_of(bc::par_unseq, non_coinbase, sets.end(), is_spent))
488+
if (std_any_of(bc::par_unseq, sets.begin(), sets.end(), is_spent))
492489
return { fault.load() };
493-
490+
494491
return ec;
495492
}
496493

494+
#if defined(UNDEFINED)
495+
497496
// split(1) 446 secs for 400k-410k
498497
TEMPLATE
499498
code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
@@ -620,7 +619,7 @@ TEMPLATE
620619
bool CLASS::initialize(const block& genesis) NOEXCEPT
621620
{
622621
BC_ASSERT(!is_initialized());
623-
BC_ASSERT(genesis.transactions_ptr()->size() == one);
622+
BC_ASSERT(is_one(genesis.transactions_ptr()->size()));
624623

625624
// ========================================================================
626625
const auto scope = store_.get_transactor();

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,13 +479,12 @@ spend_set CLASS::to_spend_set(const tx_link& link) const NOEXCEPT
479479

480480
spend_set set{ link, tx.version, {} };
481481
set.spends.reserve(tx.ins_count);
482-
483-
// This is not concurrent because to_spend_sets is (by tx).
484482
table::spend::get_prevout_sequence get{};
485483

486484
// This reduced a no-bypass 840k sync/confirmable/confirm run by 8.3%.
487485
const auto ptr = store_.spend.get_memory();
488486

487+
// This is not concurrent because to_spend_sets is (by tx).
489488
for (const auto& spend_fk: puts.spend_fks)
490489
{
491490
if (!store_.spend.get(ptr, spend_fk, get))
@@ -516,6 +515,16 @@ tx_links CLASS::to_transactions(const header_link& link) const NOEXCEPT
516515
return std::move(txs.tx_fks);
517516
}
518517

518+
TEMPLATE
519+
tx_links CLASS::to_spending_transactions(const header_link& link) const NOEXCEPT
520+
{
521+
table::txs::get_spending_txs txs{};
522+
if (!store_.txs.find(link, txs))
523+
return {};
524+
525+
return std::move(txs.tx_fks);
526+
}
527+
519528
TEMPLATE
520529
tx_link CLASS::to_coinbase(const header_link& link) const NOEXCEPT
521530
{

include/bitcoin/database/query.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ class query
288288
/// block to txs/puts (forward navigation)
289289
tx_link to_coinbase(const header_link& link) const NOEXCEPT;
290290
tx_links to_transactions(const header_link& link) const NOEXCEPT;
291+
tx_links to_spending_transactions(const header_link& link) const NOEXCEPT;
291292
output_links to_block_outputs(const header_link& link) const NOEXCEPT;
292293
spend_links to_block_spends(const header_link& link) const NOEXCEPT;
293294

@@ -497,8 +498,8 @@ class query
497498
bool set_strong(const header_link& link) NOEXCEPT;
498499
bool set_unstrong(const header_link& link) NOEXCEPT;
499500
code block_confirmable(const header_link& link) const NOEXCEPT;
500-
code tx_confirmable(const tx_link& link, const context& ctx) const NOEXCEPT;
501-
code unspent_duplicates(const tx_link& coinbase,
501+
////code tx_confirmable(const tx_link& link, const context& ctx) const NOEXCEPT;
502+
code unspent_duplicates(const header_link& coinbase,
502503
const context& ctx) const NOEXCEPT;
503504

504505
/// Height indexation.

include/bitcoin/database/tables/archives/txs.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define LIBBITCOIN_DATABASE_TABLES_ARCHIVES_TXS_HPP
2121

2222
#include <algorithm>
23+
#include <iterator>
2324
#include <bitcoin/system.hpp>
2425
#include <bitcoin/database/define.hpp>
2526
#include <bitcoin/database/memory/memory.hpp>
@@ -169,6 +170,28 @@ struct txs
169170
keys tx_fks{};
170171
};
171172

173+
struct get_spending_txs
174+
: public schema::txs
175+
{
176+
inline bool from_data(reader& source) NOEXCEPT
177+
{
178+
const auto count = source.read_little_endian<tx::integer, schema::count_>();
179+
if (count <= one)
180+
return source;
181+
182+
tx_fks.resize(sub1(count));
183+
source.skip_bytes(bytes::size + tx::size);
184+
std::for_each(tx_fks.begin(), tx_fks.end(), [&](auto& fk) NOEXCEPT
185+
{
186+
fk = source.read_little_endian<tx::integer, tx::size>();
187+
});
188+
189+
return source;
190+
}
191+
192+
keys tx_fks{};
193+
};
194+
172195
struct get_tx_quantity
173196
: public schema::txs
174197
{

test/query/confirm.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -484,12 +484,13 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__null_points__success)
484484
BOOST_REQUIRE(query.set(test::block2, context{ bip68 }, false, false));
485485
BOOST_REQUIRE(query.set(test::block3, context{ bip68 }, false, false));
486486

487+
// ALL COINBASE TXS
487488
// block1/2/3 at links 1/2/3 confirming at heights 1/2/3.
488489
// blocks have only coinbase txs, all txs should be set strong before calling
489490
// confirmable, but these are bip30 default configuration.
490-
BOOST_REQUIRE(!query.block_confirmable(1));
491-
BOOST_REQUIRE(!query.block_confirmable(2));
492-
BOOST_REQUIRE(!query.block_confirmable(3));
491+
BOOST_REQUIRE_EQUAL(query.block_confirmable(1), error::success);
492+
BOOST_REQUIRE_EQUAL(query.block_confirmable(2), error::success);
493+
BOOST_REQUIRE_EQUAL(query.block_confirmable(3), error::success);
493494
}
494495

495496
BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__missing_prevouts__integrity)
@@ -502,9 +503,10 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__missing_prevouts__integri
502503
BOOST_REQUIRE(query.initialize(test::genesis));
503504
BOOST_REQUIRE(query.set(test::block1a, context{ bip68, 1, 0 }, false, false));
504505

506+
// ONLY COINBASE TXS
505507
// block1a is missing all three input prevouts.
506508
BOOST_REQUIRE(query.set_strong(1));
507-
BOOST_REQUIRE(!query.block_confirmable(1));
509+
BOOST_REQUIRE_EQUAL(query.block_confirmable(1), error::success);
508510
}
509511

510512
BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_gensis__coinbase_maturity)
@@ -520,8 +522,9 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_gensis__coinbase_ma
520522
BOOST_REQUIRE(query.set(test::block_spend_genesis, context{ 0, 101, 0 }, false, false));
521523
BOOST_REQUIRE(query.set_strong(1));
522524

525+
// COINBASE TX
523526
// 1 + 100 = 101 (maturity, except genesis)
524-
BOOST_REQUIRE(!query.block_confirmable(1));
527+
BOOST_REQUIRE_EQUAL(query.block_confirmable(1), error::success);
525528
}
526529

527530
BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__immature_prevouts__coinbase_maturity)
@@ -536,12 +539,13 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__immature_prevouts__coinba
536539
// block1b has only a coinbase tx.
537540
BOOST_REQUIRE(query.set(test::block1b, context{ bip68, 1, 0 }, false, false));
538541
BOOST_REQUIRE(query.set_strong(1));
539-
BOOST_REQUIRE(!query.block_confirmable(1));
542+
BOOST_REQUIRE_EQUAL(query.block_confirmable(1), error::success);
540543

544+
// COINBASE TX
541545
// block2b prematurely spends block1b's coinbase outputs.
542546
BOOST_REQUIRE(query.set(test::block2b, context{ 0, 100, 0 }, false, false));
543547
BOOST_REQUIRE(query.set_strong(2));
544-
BOOST_REQUIRE(!query.block_confirmable(2));
548+
BOOST_REQUIRE_EQUAL(query.block_confirmable(2), error::success);
545549
}
546550

547551
BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__mature_prevouts__success)
@@ -556,12 +560,13 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__mature_prevouts__success)
556560
// block1b has only a coinbase tx.
557561
BOOST_REQUIRE(query.set(test::block1b, context{ bip68, 1, 0 }, false, false));
558562
BOOST_REQUIRE(query.set_strong(1));
559-
BOOST_REQUIRE(!query.block_confirmable(1));
563+
BOOST_REQUIRE_EQUAL(query.block_confirmable(1), error::success);
560564

565+
// COINBASE TX
561566
// block2b spends block1b's coinbase outputs.
562567
BOOST_REQUIRE(query.set(test::block2b, context{ 0, 101, 0 }, false, false));
563568
BOOST_REQUIRE(query.set_strong(2));
564-
BOOST_REQUIRE(!query.block_confirmable(2));
569+
BOOST_REQUIRE_EQUAL(query.block_confirmable(2), error::success);
565570
}
566571

567572
BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_non_coinbase__success)
@@ -581,8 +586,9 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_non_coinbase__succe
581586
BOOST_REQUIRE(query.set(test::block_spend_1a, context{ 0, 2, 0 }, false, false));
582587
BOOST_REQUIRE(query.set_strong(2));
583588

589+
// COINBASE TX
584590
// Maturity applies only to coinbase prevouts.
585-
BOOST_REQUIRE(!query.block_confirmable(2));
591+
BOOST_REQUIRE_EQUAL(query.block_confirmable(2), error::success);
586592
}
587593

588594
// These pas but test vectors need to be updated to create clear test conditions.
@@ -608,7 +614,7 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_non_coinbase__succe
608614
//// BOOST_REQUIRE(query.set_strong(2));
609615
////
610616
//// // Not confirmable because lack of maturity.
611-
//// BOOST_REQUIRE(!query.block_confirmable(2));
617+
//// BOOST_REQUIRE_EQUAL(!query.block_confirmable(2), error::success);
612618
////}
613619
////
614620
////BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_coinbase_and_internal_mature__success)
@@ -635,7 +641,7 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_non_coinbase__succe
635641
//// // It spends only its first own output (coinbase) and that can never be mature.
636642
//// // But spend target is not stored as coinbase because it's not a null point.
637643
//// BOOST_REQUIRE(query.set_strong(2));
638-
//// BOOST_REQUIRE(!query.block_confirmable(2));
644+
//// BOOST_REQUIRE_EQUAL(!query.block_confirmable(2), error::success);
639645
////}
640646
////
641647
////BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__confirmed_double_spend__confirmed_double_spend)
@@ -660,7 +666,7 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_non_coinbase__succe
660666
//// BOOST_REQUIRE(query.set_strong(3));
661667
////
662668
//// // Not confirmable because of intervening block2a implies double spend.
663-
//// BOOST_REQUIRE(!query.block_confirmable(3));
669+
//// BOOST_REQUIRE_EQUAL(!query.block_confirmable(3), error::success);
664670
////}
665671
////
666672
////BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__unconfirmed_double_spend__success)
@@ -684,7 +690,7 @@ BOOST_AUTO_TEST_CASE(query_confirm__block_confirmable__spend_non_coinbase__succe
684690
//// BOOST_REQUIRE(query.set_strong(2));
685691
////
686692
//// // Confirmable because of intervening tx5 is unconfirmed double spend.
687-
//// BOOST_REQUIRE(!query.block_confirmable(2));
693+
//// BOOST_REQUIRE_EQUAL(!query.block_confirmable(2));
688694
////}
689695

690696
BOOST_AUTO_TEST_CASE(query_confirm__set_strong__unassociated__false)

test/query/translate.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,13 @@ BOOST_AUTO_TEST_CASE(query_translate__to_spend_tx__to_spend__expected)
324324
BOOST_REQUIRE_EQUAL(spends.spends[2].point_index, (*test::block1a.transactions_ptr()->front()->inputs_ptr())[2]->point().index());
325325
BOOST_REQUIRE_EQUAL(spends.version, test::block1a.transactions_ptr()->front()->version());
326326

327+
// COINBASE TXS!
327328
// TODO: All blocks have one transaction.
328-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 1u);
329-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 1u);
330-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(2).size(), 1u);
331-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(3).size(), 1u);
332-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(4).size(), 1u);
329+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 0u);
330+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 0u);
331+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(2).size(), 0u);
332+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(3).size(), 0u);
333+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(4).size(), 0u);
333334

334335
// Past end.
335336
BOOST_REQUIRE_EQUAL(query.to_spend_tx(7), tx_link::terminal);
@@ -430,7 +431,7 @@ BOOST_AUTO_TEST_CASE(query_translate__to_spend_sets__populated__expected)
430431

431432
// coinbase only (null and first).
432433
BOOST_REQUIRE(query.initialize(test::genesis));
433-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 1u);
434+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 0u);
434435
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 0u);
435436
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(2).size(), 0u);
436437

@@ -444,8 +445,8 @@ BOOST_AUTO_TEST_CASE(query_translate__to_spend_sets__populated__expected)
444445

445446
// coinbase only (null and first).
446447
BOOST_REQUIRE(query.set(test::block1b, context{ 0, 1, 0 }, false, false));
447-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 1u);
448-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 1u);
448+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 0u);
449+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 0u);
449450
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(2).size(), 0u);
450451

451452
BOOST_REQUIRE_EQUAL(store.point_body(), system::base16_chunk(""));
@@ -460,10 +461,11 @@ BOOST_AUTO_TEST_CASE(query_translate__to_spend_sets__populated__expected)
460461
"01000000""b1""0179"
461462
"01000000""b1""0179"));
462463

464+
// COINBASE TX
463465
// 2 inputs (block1b and tx2b).
464466
BOOST_REQUIRE(query.set(test::block_spend_internal_2b, context{ 0, 101, 0 }, false, false));
465-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 1u);
466-
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 1u);
467+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(0).size(), 0u);
468+
BOOST_REQUIRE_EQUAL(query.to_spend_sets_(1).size(), 0u);
467469

468470
// Two points because non-null, but only one is non-first (also coinbase criteria).
469471
// block_spend_internal_2b first tx (tx2b) is first but with non-null input.

0 commit comments

Comments
 (0)