Skip to content

Commit 713c7f9

Browse files
authored
Merge pull request #704 from evoskuil/master
Make weak block association (to_block) protected.
2 parents 342c81f + 8322f85 commit 713c7f9

File tree

8 files changed

+78
-44
lines changed

8 files changed

+78
-44
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,14 @@ inline hash_digest CLASS::get_point_hash(const point_link& link) const NOEXCEPT
156156
TEMPLATE
157157
bool CLASS::get_tx_height(size_t& out, const tx_link& link) const NOEXCEPT
158158
{
159-
// to_block is strong but not necessarily confirmed.
160-
const auto fk = to_block(link);
159+
const auto fk = to_strong(link);
161160
return is_confirmed_block(fk) && get_height(out, fk);
162161
}
163162

164163
TEMPLATE
165164
bool CLASS::get_tx_position(size_t& out, const tx_link& link) const NOEXCEPT
166165
{
167-
// to_block is strong but not necessarily confirmed.
168-
const auto fk = to_block(link);
166+
const auto fk = to_strong(link);
169167
if (!is_confirmed_block(fk))
170168
return false;
171169

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

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ bool CLASS::set(const transaction& tx) NOEXCEPT
6565
}
6666

6767
TEMPLATE
68-
bool CLASS::set(const block& block, bool strong) NOEXCEPT
68+
bool CLASS::set(const block& block, bool strong, bool bypass) NOEXCEPT
6969
{
7070
// This sets only the txs of a block with header/context already archived.
71-
return !set_code(block, strong);
71+
return !set_code(block, strong, bypass);
7272
}
7373

7474
// set transaction
@@ -84,11 +84,12 @@ code CLASS::set_code(const transaction& tx) NOEXCEPT
8484
if (tx_fk.is_terminal())
8585
return error::tx_tx_allocate;
8686

87-
return set_code(tx_fk, tx);
87+
return set_code(tx_fk, tx, false);
8888
}
8989

9090
TEMPLATE
91-
code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
91+
code CLASS::set_code(const tx_link& tx_fk, const transaction& tx,
92+
bool bypass) NOEXCEPT
9293
{
9394
// This is the only multitable write query (except initialize/genesis).
9495

@@ -106,9 +107,6 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
106107
// ========================================================================
107108
const auto scope = store_.get_transactor();
108109

109-
// If dirty we must guard against duplicates.
110-
const auto dirty = store_.is_dirty();
111-
112110
// Allocate contiguously and store inputs.
113111
input_link in_fk{};
114112
if (!store_.input.put_link(in_fk,
@@ -167,9 +165,13 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
167165
if (!store_.point.expand(ins_fk + inputs))
168166
return error::tx_point_allocate;
169167

168+
// If dirty we must guard against duplicates.
169+
// Dirty doesn't hold up in the case of an invalidated block, as that
170+
// may result in a duplicated tx. So dirty should be false in the case
171+
// of a non-bypass (valid) block.
170172
// Must be set after tx.set and before tx.commit, since searchable and
171173
// produces association to tx.link, and is also an integral part of tx.
172-
if (dirty)
174+
if (store_.is_dirty() || !bypass)
173175
{
174176
// Collect duplicates to store in duplicate table.
175177
std::vector<chain::point> twins{};
@@ -336,7 +338,7 @@ code CLASS::set_code(header_link& out_fk, const block& block,
336338
const context& ctx, bool milestone, bool strong) NOEXCEPT
337339
{
338340
const auto ec = set_code(out_fk, block.header(), ctx, milestone);
339-
return ec ? ec : set_code(block, out_fk, strong);
341+
return ec ? ec : set_code(block, out_fk, strong, strong || milestone);
340342
}
341343

342344
// set txs from block
@@ -346,26 +348,26 @@ code CLASS::set_code(header_link& out_fk, const block& block,
346348
// releases all memory for parts of itself, due to the custom allocator.
347349

348350
TEMPLATE
349-
code CLASS::set_code(const block& block, bool strong) NOEXCEPT
351+
code CLASS::set_code(const block& block, bool strong, bool bypass) NOEXCEPT
350352
{
351353
header_link unused{};
352-
return set_code(unused, block, strong);
354+
return set_code(unused, block, strong, bypass);
353355
}
354356

355357
TEMPLATE
356-
code CLASS::set_code(header_link& out_fk, const block& block,
357-
bool strong) NOEXCEPT
358+
code CLASS::set_code(header_link& out_fk, const block& block, bool strong,
359+
bool bypass) NOEXCEPT
358360
{
359361
out_fk = to_header(block.get_hash());
360362
if (out_fk.is_terminal())
361363
return error::txs_header;
362364

363-
return set_code(block, out_fk, strong);
365+
return set_code(block, out_fk, strong, bypass);
364366
}
365367

366368
TEMPLATE
367369
code CLASS::set_code(const block& block, const header_link& key,
368-
bool strong) NOEXCEPT
370+
bool strong, bool bypass) NOEXCEPT
369371
{
370372
using namespace system;
371373
if (key.is_terminal())
@@ -383,7 +385,7 @@ code CLASS::set_code(const block& block, const header_link& key,
383385
code ec{};
384386
auto fk = tx_fks;
385387
for (const auto& tx: *block.transactions_ptr())
386-
if ((ec = set_code(fk++, *tx)))
388+
if ((ec = set_code(fk++, *tx, bypass)))
387389
return ec;
388390

389391
using bytes = linkage<schema::size>::integer;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ TEMPLATE
6868
bool CLASS::is_confirmed_tx(const tx_link& link) const NOEXCEPT
6969
{
7070
// The tx is strong *and* its block is confirmed (by height).
71-
const auto fk = to_block(link);
71+
const auto fk = to_strong(link);
7272
return !fk.is_terminal() && is_confirmed_block(fk);
7373
}
7474

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,7 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT
472472
TEMPLATE
473473
bool CLASS::get_doubles(tx_links& out, const point& point) const NOEXCEPT
474474
{
475-
// Body size check avoids a header hit when no duplicates (common).
476-
if (is_zero(store_.duplicate.body_size()) ||
477-
!store_.duplicate.exists(point))
475+
if (!store_.duplicate.exists(point))
478476
return true;
479477

480478
auto success = false;
@@ -510,8 +508,10 @@ bool CLASS::set_prevouts(const header_link& link, const block& block) NOEXCEPT
510508
if (block.transactions() <= one)
511509
return true;
512510

511+
// Body size check avoids a header hit when no duplicates (common).
513512
tx_links doubles{};
514-
if (!get_doubles(doubles, block))
513+
if (!is_zero(store_.duplicate.body_size()) &&
514+
!get_doubles(doubles, block))
515515
return false;
516516

517517
const auto prevout = to_prevout(link);

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,18 +165,47 @@ output_link CLASS::to_prevout(const point_link& link) const NOEXCEPT
165165
// block/tx to block (reverse navigation)
166166
// ----------------------------------------------------------------------------
167167

168+
TEMPLATE
169+
tx_link CLASS::to_strong_tx(const tx_link& link) const NOEXCEPT
170+
{
171+
return to_strong_tx(get_tx_key(link));
172+
}
173+
174+
TEMPLATE
175+
tx_link CLASS::to_strong_tx(const hash_digest& tx_hash) const NOEXCEPT
176+
{
177+
// Get all tx links for tx_hash.
178+
tx_links txs{};
179+
for (auto it = store_.tx.it(tx_hash); it; ++it)
180+
txs.push_back(*it);
181+
182+
// Find the first strong tx of the set and return its link.
183+
for (const auto& tx : txs)
184+
if (!to_block(tx).is_terminal())
185+
return tx;
186+
187+
return {};
188+
}
189+
190+
// protected (weak association)
168191
// Required for confirmation processing.
169192
TEMPLATE
170-
header_link CLASS::to_block(const tx_link& key) const NOEXCEPT
193+
header_link CLASS::to_block(const tx_link& link) const NOEXCEPT
171194
{
172195
table::strong_tx::record strong{};
173-
if (!store_.strong_tx.find(key, strong) || !strong.positive())
196+
if (!store_.strong_tx.find(link, strong) || !strong.positive())
174197
return {};
175198

176199
// Terminal implies not in strong block (reorganized).
177200
return strong.header_fk();
178201
}
179202

203+
TEMPLATE
204+
header_link CLASS::to_strong(const tx_link& link) const NOEXCEPT
205+
{
206+
return to_strong(get_tx_key(link));
207+
}
208+
180209
// Required for confirmation processing.
181210
TEMPLATE
182211
header_link CLASS::to_strong(const hash_digest& tx_hash) const NOEXCEPT
@@ -188,14 +217,12 @@ header_link CLASS::to_strong(const hash_digest& tx_hash) const NOEXCEPT
188217

189218
// Find the first strong tx of the set and return its block.
190219
for (const auto& tx: txs)
191-
{
192-
const auto block = to_block(tx);
193-
if (!block.is_terminal())
220+
if (const auto block = to_block(tx); !block.is_terminal())
194221
return block;
195-
}
196222

197223
return {};
198224
}
225+
199226
TEMPLATE
200227
header_link CLASS::to_parent(const header_link& link) const NOEXCEPT
201228
{

include/bitcoin/database/query.hpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,9 @@ class query
263263
output_link to_prevout(const point_link& link) const NOEXCEPT;
264264

265265
/// block/tx to block (reverse navigation)
266-
header_link to_block(const tx_link& key) const NOEXCEPT;
266+
tx_link to_strong_tx(const tx_link& link) const NOEXCEPT;
267+
tx_link to_strong_tx(const hash_digest& tx_hash) const NOEXCEPT;
268+
header_link to_strong(const tx_link& link) const NOEXCEPT;
267269
header_link to_strong(const hash_digest& tx_hash) const NOEXCEPT;
268270
header_link to_parent(const header_link& link) const NOEXCEPT;
269271

@@ -410,7 +412,7 @@ class query
410412
bool set(const block& block, const context& ctx,
411413
bool milestone, bool strong) NOEXCEPT;
412414
bool set(const transaction& tx) NOEXCEPT;
413-
bool set(const block& block, bool strong) NOEXCEPT;
415+
bool set(const block& block, bool strong, bool bypass) NOEXCEPT;
414416

415417
/// Set transaction.
416418
code set_code(const transaction& tx) NOEXCEPT;
@@ -436,9 +438,11 @@ class query
436438
const chain_context& ctx, bool milestone, bool strong) NOEXCEPT;
437439

438440
/// Set block.txs (headers-first).
439-
code set_code(const block& block, bool strong) NOEXCEPT;
440-
code set_code(header_link& out_fk, const block& block, bool strong) NOEXCEPT;
441-
code set_code(const block& block, const header_link& key, bool strong) NOEXCEPT;
441+
code set_code(const block& block, bool strong, bool bypass) NOEXCEPT;
442+
code set_code(header_link& out_fk, const block& block, bool strong,
443+
bool bypass) NOEXCEPT;
444+
code set_code(const block& block, const header_link& key, bool strong,
445+
bool bypass) NOEXCEPT;
442446

443447
/// Context.
444448
/// -----------------------------------------------------------------------
@@ -602,6 +606,7 @@ class query
602606

603607
/// Translate.
604608
/// -----------------------------------------------------------------------
609+
header_link to_block(const tx_link& link) const NOEXCEPT;
605610
uint32_t to_input_index(const tx_link& parent_fk,
606611
const point_link& point_fk) const NOEXCEPT;
607612
uint32_t to_output_index(const tx_link& parent_fk,
@@ -702,11 +707,13 @@ class query
702707
code get_confirmed_unspent_outputs_turbo(std::atomic_bool& cancel,
703708
outpoints& out, const hash_digest& key) const NOEXCEPT;
704709
code get_minimum_unspent_outputs_turbo(std::atomic_bool& cancel,
705-
outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT;
710+
outpoints& out, const hash_digest& key,
711+
uint64_t minimum) const NOEXCEPT;
706712

707713
/// tx_fk must be allocated.
708714
/// -----------------------------------------------------------------------
709-
code set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT;
715+
code set_code(const tx_link& tx_fk, const transaction& tx,
716+
bool bypass) NOEXCEPT;
710717

711718
private:
712719
// Chain objects.

test/query/archive_write.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__set_block_txs__get_block__expected)
705705
BOOST_REQUIRE(!query.is_block(test::genesis.hash()));
706706
BOOST_REQUIRE(query.set(test::genesis.header(), test::context, milestone));
707707
BOOST_REQUIRE(!query.is_associated(0));
708-
BOOST_REQUIRE(query.set(test::genesis, false));
708+
BOOST_REQUIRE(query.set(test::genesis, false, false));
709709
BOOST_REQUIRE(query.is_block(test::genesis.hash()));
710710
BOOST_REQUIRE(query.is_associated(0));
711711

test/query/initialize.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,17 +415,17 @@ BOOST_AUTO_TEST_CASE(query_initialize__get_unassociated_above__gapped_candidate_
415415
BOOST_REQUIRE_EQUAL(unassociated3.size(), 0u);
416416

417417
// There are two unassociated blocks above block 1 (new fork point).
418-
BOOST_REQUIRE(query.set(test::block1, false));
418+
BOOST_REQUIRE(query.set(test::block1, false, false));
419419
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block1.hash()), false));
420420
BOOST_REQUIRE_EQUAL(query.get_all_unassociated().size(), 2u);
421421

422422
// There is one unassociated block above block 2 (new fork point).
423-
BOOST_REQUIRE(query.set(test::block2, false));
423+
BOOST_REQUIRE(query.set(test::block2, false, false));
424424
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block2.hash()), false));
425425
BOOST_REQUIRE_EQUAL(query.get_all_unassociated().size(), 1u);
426426

427427
// There are no unassociated blocks above block 3 (new fork point).
428-
BOOST_REQUIRE(query.set(test::block3, false));
428+
BOOST_REQUIRE(query.set(test::block3, false, false));
429429
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block3.hash()), false));
430430
BOOST_REQUIRE_EQUAL(query.get_all_unassociated().size(), 0u);
431431
}
@@ -482,15 +482,15 @@ BOOST_AUTO_TEST_CASE(query_initialize__get_unassociated_count_above__gapped_cand
482482
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(3, 1), 0u);
483483

484484
// There is one unassociated block at block 2.
485-
BOOST_REQUIRE(query.set(test::block3, false)); // associated
485+
BOOST_REQUIRE(query.set(test::block3, false, false)); // associated
486486
BOOST_REQUIRE_EQUAL(query.get_unassociated_count(), 1u);
487487
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(0), 1u);
488488
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(1), 1u);
489489
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(2), 0u);
490490
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(3), 0u);
491491

492492
// There are no unassociated blocks.
493-
BOOST_REQUIRE(query.set(test::block2, false)); // associated
493+
BOOST_REQUIRE(query.set(test::block2, false, false)); // associated
494494
BOOST_REQUIRE_EQUAL(query.get_unassociated_count(), 0u);
495495
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(0), 0u);
496496
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(1), 0u);

0 commit comments

Comments
 (0)