Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions include/bitcoin/database/impl/query/archive_read.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,14 @@ inline hash_digest CLASS::get_point_hash(const point_link& link) const NOEXCEPT
TEMPLATE
bool CLASS::get_tx_height(size_t& out, const tx_link& link) const NOEXCEPT
{
// to_block is strong but not necessarily confirmed.
const auto fk = to_block(link);
const auto fk = to_strong(link);
return is_confirmed_block(fk) && get_height(out, fk);
}

TEMPLATE
bool CLASS::get_tx_position(size_t& out, const tx_link& link) const NOEXCEPT
{
// to_block is strong but not necessarily confirmed.
const auto fk = to_block(link);
const auto fk = to_strong(link);
if (!is_confirmed_block(fk))
return false;

Expand Down
34 changes: 18 additions & 16 deletions include/bitcoin/database/impl/query/archive_write.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ bool CLASS::set(const transaction& tx) NOEXCEPT
}

TEMPLATE
bool CLASS::set(const block& block, bool strong) NOEXCEPT
bool CLASS::set(const block& block, bool strong, bool bypass) NOEXCEPT
{
// This sets only the txs of a block with header/context already archived.
return !set_code(block, strong);
return !set_code(block, strong, bypass);
}

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

return set_code(tx_fk, tx);
return set_code(tx_fk, tx, false);
}

TEMPLATE
code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
code CLASS::set_code(const tx_link& tx_fk, const transaction& tx,
bool bypass) NOEXCEPT
{
// This is the only multitable write query (except initialize/genesis).

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

// If dirty we must guard against duplicates.
const auto dirty = store_.is_dirty();

// Allocate contiguously and store inputs.
input_link in_fk{};
if (!store_.input.put_link(in_fk,
Expand Down Expand Up @@ -167,9 +165,13 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
if (!store_.point.expand(ins_fk + inputs))
return error::tx_point_allocate;

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

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

TEMPLATE
code CLASS::set_code(const block& block, bool strong) NOEXCEPT
code CLASS::set_code(const block& block, bool strong, bool bypass) NOEXCEPT
{
header_link unused{};
return set_code(unused, block, strong);
return set_code(unused, block, strong, bypass);
}

TEMPLATE
code CLASS::set_code(header_link& out_fk, const block& block,
bool strong) NOEXCEPT
code CLASS::set_code(header_link& out_fk, const block& block, bool strong,
bool bypass) NOEXCEPT
{
out_fk = to_header(block.get_hash());
if (out_fk.is_terminal())
return error::txs_header;

return set_code(block, out_fk, strong);
return set_code(block, out_fk, strong, bypass);
}

TEMPLATE
code CLASS::set_code(const block& block, const header_link& key,
bool strong) NOEXCEPT
bool strong, bool bypass) NOEXCEPT
{
using namespace system;
if (key.is_terminal())
Expand All @@ -383,7 +385,7 @@ code CLASS::set_code(const block& block, const header_link& key,
code ec{};
auto fk = tx_fks;
for (const auto& tx: *block.transactions_ptr())
if ((ec = set_code(fk++, *tx)))
if ((ec = set_code(fk++, *tx, bypass)))
return ec;

using bytes = linkage<schema::size>::integer;
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/database/impl/query/confirm.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ TEMPLATE
bool CLASS::is_confirmed_tx(const tx_link& link) const NOEXCEPT
{
// The tx is strong *and* its block is confirmed (by height).
const auto fk = to_block(link);
const auto fk = to_strong(link);
return !fk.is_terminal() && is_confirmed_block(fk);
}

Expand Down
8 changes: 4 additions & 4 deletions include/bitcoin/database/impl/query/consensus.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,7 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT
TEMPLATE
bool CLASS::get_doubles(tx_links& out, const point& point) const NOEXCEPT
{
// Body size check avoids a header hit when no duplicates (common).
if (is_zero(store_.duplicate.body_size()) ||
!store_.duplicate.exists(point))
if (!store_.duplicate.exists(point))
return true;

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

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

const auto prevout = to_prevout(link);
Expand Down
39 changes: 33 additions & 6 deletions include/bitcoin/database/impl/query/translate.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,47 @@ output_link CLASS::to_prevout(const point_link& link) const NOEXCEPT
// block/tx to block (reverse navigation)
// ----------------------------------------------------------------------------

TEMPLATE
tx_link CLASS::to_strong_tx(const tx_link& link) const NOEXCEPT
{
return to_strong_tx(get_tx_key(link));
}

TEMPLATE
tx_link CLASS::to_strong_tx(const hash_digest& tx_hash) const NOEXCEPT
{
// Get all tx links for tx_hash.
tx_links txs{};
for (auto it = store_.tx.it(tx_hash); it; ++it)
txs.push_back(*it);

// Find the first strong tx of the set and return its link.
for (const auto& tx : txs)
if (!to_block(tx).is_terminal())
return tx;

return {};
}

// protected (weak association)
// Required for confirmation processing.
TEMPLATE
header_link CLASS::to_block(const tx_link& key) const NOEXCEPT
header_link CLASS::to_block(const tx_link& link) const NOEXCEPT
{
table::strong_tx::record strong{};
if (!store_.strong_tx.find(key, strong) || !strong.positive())
if (!store_.strong_tx.find(link, strong) || !strong.positive())
return {};

// Terminal implies not in strong block (reorganized).
return strong.header_fk();
}

TEMPLATE
header_link CLASS::to_strong(const tx_link& link) const NOEXCEPT
{
return to_strong(get_tx_key(link));
}

// Required for confirmation processing.
TEMPLATE
header_link CLASS::to_strong(const hash_digest& tx_hash) const NOEXCEPT
Expand All @@ -188,14 +217,12 @@ header_link CLASS::to_strong(const hash_digest& tx_hash) const NOEXCEPT

// Find the first strong tx of the set and return its block.
for (const auto& tx: txs)
{
const auto block = to_block(tx);
if (!block.is_terminal())
if (const auto block = to_block(tx); !block.is_terminal())
return block;
}

return {};
}

TEMPLATE
header_link CLASS::to_parent(const header_link& link) const NOEXCEPT
{
Expand Down
21 changes: 14 additions & 7 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ class query
output_link to_prevout(const point_link& link) const NOEXCEPT;

/// block/tx to block (reverse navigation)
header_link to_block(const tx_link& key) const NOEXCEPT;
tx_link to_strong_tx(const tx_link& link) const NOEXCEPT;
tx_link to_strong_tx(const hash_digest& tx_hash) const NOEXCEPT;
header_link to_strong(const tx_link& link) const NOEXCEPT;
header_link to_strong(const hash_digest& tx_hash) const NOEXCEPT;
header_link to_parent(const header_link& link) const NOEXCEPT;

Expand Down Expand Up @@ -410,7 +412,7 @@ class query
bool set(const block& block, const context& ctx,
bool milestone, bool strong) NOEXCEPT;
bool set(const transaction& tx) NOEXCEPT;
bool set(const block& block, bool strong) NOEXCEPT;
bool set(const block& block, bool strong, bool bypass) NOEXCEPT;

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

/// Set block.txs (headers-first).
code set_code(const block& block, bool strong) NOEXCEPT;
code set_code(header_link& out_fk, const block& block, bool strong) NOEXCEPT;
code set_code(const block& block, const header_link& key, bool strong) NOEXCEPT;
code set_code(const block& block, bool strong, bool bypass) NOEXCEPT;
code set_code(header_link& out_fk, const block& block, bool strong,
bool bypass) NOEXCEPT;
code set_code(const block& block, const header_link& key, bool strong,
bool bypass) NOEXCEPT;

/// Context.
/// -----------------------------------------------------------------------
Expand Down Expand Up @@ -602,6 +606,7 @@ class query

/// Translate.
/// -----------------------------------------------------------------------
header_link to_block(const tx_link& link) const NOEXCEPT;
uint32_t to_input_index(const tx_link& parent_fk,
const point_link& point_fk) const NOEXCEPT;
uint32_t to_output_index(const tx_link& parent_fk,
Expand Down Expand Up @@ -702,11 +707,13 @@ class query
code get_confirmed_unspent_outputs_turbo(std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
code get_minimum_unspent_outputs_turbo(std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT;
outpoints& out, const hash_digest& key,
uint64_t minimum) const NOEXCEPT;

/// tx_fk must be allocated.
/// -----------------------------------------------------------------------
code set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT;
code set_code(const tx_link& tx_fk, const transaction& tx,
bool bypass) NOEXCEPT;

private:
// Chain objects.
Expand Down
2 changes: 1 addition & 1 deletion test/query/archive_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__set_block_txs__get_block__expected)
BOOST_REQUIRE(!query.is_block(test::genesis.hash()));
BOOST_REQUIRE(query.set(test::genesis.header(), test::context, milestone));
BOOST_REQUIRE(!query.is_associated(0));
BOOST_REQUIRE(query.set(test::genesis, false));
BOOST_REQUIRE(query.set(test::genesis, false, false));
BOOST_REQUIRE(query.is_block(test::genesis.hash()));
BOOST_REQUIRE(query.is_associated(0));

Expand Down
10 changes: 5 additions & 5 deletions test/query/initialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,17 +415,17 @@ BOOST_AUTO_TEST_CASE(query_initialize__get_unassociated_above__gapped_candidate_
BOOST_REQUIRE_EQUAL(unassociated3.size(), 0u);

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

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

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

// There is one unassociated block at block 2.
BOOST_REQUIRE(query.set(test::block3, false)); // associated
BOOST_REQUIRE(query.set(test::block3, false, false)); // associated
BOOST_REQUIRE_EQUAL(query.get_unassociated_count(), 1u);
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(0), 1u);
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(1), 1u);
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(2), 0u);
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(3), 0u);

// There are no unassociated blocks.
BOOST_REQUIRE(query.set(test::block2, false)); // associated
BOOST_REQUIRE(query.set(test::block2, false, false)); // associated
BOOST_REQUIRE_EQUAL(query.get_unassociated_count(), 0u);
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(0), 0u);
BOOST_REQUIRE_EQUAL(query.get_unassociated_count_above(1), 0u);
Expand Down
Loading