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
15 changes: 8 additions & 7 deletions include/bitcoin/database/impl/query/address/address_history.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ code CLASS::get_unconfirmed_history(const stopper& cancel, histories& out,
const hash_digest& key, size_t limit, bool turbo) const NOEXCEPT
{
tx_links txs{};
if (const auto ec = get_address_txs(cancel, txs, key, limit))
if (const auto ec = get_address_txs(cancel, txs, key, limit, turbo))
return ec;

// There is no cursor for unconfirmed, since it's height-based.
Expand All @@ -62,7 +62,7 @@ code CLASS::get_confirmed_history(const stopper& cancel, height_link& cursor,
bool turbo) const NOEXCEPT
{
tx_links txs{};
if (const auto ec = get_address_txs(cancel, txs, key, limit))
if (const auto ec = get_address_txs(cancel, txs, key, limit, turbo))
return ec;

// Cursor is still advanced in the case of (integrity) failure.
Expand Down Expand Up @@ -90,7 +90,7 @@ code CLASS::get_history(const stopper& cancel, height_link& cursor,
bool turbo) const NOEXCEPT
{
tx_links txs{};
if (const auto ec = get_address_txs(cancel, txs, key, limit))
if (const auto ec = get_address_txs(cancel, txs, key, limit, turbo))
return ec;

// Cursor is still advanced in the case of (integrity) failure.
Expand Down Expand Up @@ -250,14 +250,15 @@ histories CLASS::get_spenders_history(const hash_digest& key,

TEMPLATE
code CLASS::get_address_txs(const stopper& cancel, tx_links& out,
const hash_digest& key, size_t limit) const NOEXCEPT
const hash_digest& key, size_t limit, bool turbo) const NOEXCEPT
{
output_links links{};
tx_links parents{};
outs_link cursor{};
if (const auto ec = to_address_outputs(cancel, cursor, links, key, limit))
if (const auto ec = to_address_outputs(cancel, cursor, links, parents, key, limit))
return ec;

return to_touched_txs(cancel, out, links);
return to_touched_txs(cancel, out, links, parents, turbo);
}

// private/static
Expand All @@ -266,7 +267,7 @@ template <typename Functor>
code CLASS::parallel_history_transform(const stopper& cancel, bool turbo,
histories& out, const tx_links& txs, Functor&& functor) NOEXCEPT
{
const auto policy = poolstl::execution::par_if(turbo);
const auto policy = poolstl::execution::par_if(turbo, parallel_floor);
stopper fail{};

out.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ template <typename Functor>
code CLASS::parallel_outpoint_transform(const stopper& cancel, bool turbo,
outpoints& out, const output_links& links, Functor&& functor) NOEXCEPT
{
const auto policy = poolstl::execution::par_if(turbo);
const auto policy = poolstl::execution::par_if(turbo, parallel_floor);
stopper fail{};

out.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ template <typename Functor>
code CLASS::parallel_unspent_transform(const stopper& cancel, bool turbo,
unspent_outputs& out, const output_links& outs, Functor&& functor) NOEXCEPT
{
const auto policy = poolstl::execution::par_if(turbo);
const auto policy = poolstl::execution::par_if(turbo, parallel_floor);
stopper fail{};

out.clear();
Expand Down
89 changes: 74 additions & 15 deletions include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -80,30 +80,69 @@ TEMPLATE
code CLASS::to_touched_txs(const stopper& cancel, tx_links& out,
const output_links& outputs) const NOEXCEPT
{
// Reserve one for each output tx and one for spending input tx (estimate).
out.clear();
out.reserve(two * outputs.size());

// Orders are reversed due to expected tx_links reversal, for faster sort.
for (const auto& output: std::views::reverse(outputs))
tx_links parents{};
parents.reserve(outputs.size());
for (const auto& output: outputs)
{
if (cancel)
return error::query_canceled;

if (const auto tx = to_output_tx(output); tx.is_terminal())
return error::integrity;
else
out.push_back(tx);

for (const auto& input: std::views::reverse(to_spenders(output)))
{
if (const auto tx = to_input_tx(input); tx.is_terminal())
return error::integrity;
else
out.push_back(tx);
}
parents.push_back(tx);
}

return to_touched_txs(cancel, out, outputs, parents, false);
}

TEMPLATE
code CLASS::to_touched_txs(const stopper& cancel, tx_links& out,
const output_links& outputs, const tx_links& parents,
bool turbo) const NOEXCEPT
{
BC_ASSERT(outputs.size() == parents.size());
const auto policy = poolstl::execution::par_if(turbo, parallel_floor);
stopper fail{};

// Each output resolves to its parent tx followed by its spending txs.
std::vector<tx_links> touched(outputs.size());
std::transform(policy, outputs.cbegin(), outputs.cend(), parents.cbegin(),
touched.begin(), [this, &cancel, &fail](const output_link& output,
const tx_link& parent) NOEXCEPT
{
tx_links txs{};
if (cancel || fail)
return txs;

txs.push_back(parent);
for (const auto& input: std::views::reverse(to_spenders(parent, output)))
{
const auto tx = to_input_tx(input);
if (tx.is_terminal())
{
fail = true;
return txs;
}

txs.push_back(tx);
}

return txs;
});

if (fail)
return error::integrity;

if (cancel)
return error::query_canceled;

// Orders are reversed due to expected tx_links reversal, for faster sort.
out.clear();
out.reserve(two * outputs.size());
for (const auto& txs: std::views::reverse(touched))
out.insert(out.end(), txs.begin(), txs.end());

return error::success;
}

Expand All @@ -126,8 +165,18 @@ code CLASS::to_address_outputs(const stopper& cancel, output_links& out,
TEMPLATE
code CLASS::to_address_outputs(const stopper& cancel, outs_link& cursor,
output_links& out, const hash_digest& key, size_t limit) const NOEXCEPT
{
tx_links parents{};
return to_address_outputs(cancel, cursor, out, parents, key, limit);
}

TEMPLATE
code CLASS::to_address_outputs(const stopper& cancel, outs_link& cursor,
output_links& out, tx_links& parents, const hash_digest& key,
size_t limit) const NOEXCEPT
{
out.clear();
parents.clear();

// Limit bounds candidates, verified following iterator disposal.
// The iterator guards the aggregate, so puts is read unguarded.
Expand Down Expand Up @@ -179,7 +228,10 @@ code CLASS::to_address_outputs(const stopper& cancel, outs_link& cursor,
return error::integrity;

if (output.match)
{
out.push_back(candidate);
parents.push_back(output.parent_fk);
}
}

return deferred;
Expand Down Expand Up @@ -238,6 +290,13 @@ ins_links CLASS::to_spenders(const tx_link& output_tx,
return to_spenders(get_tx_key(output_tx), output_index);
}

TEMPLATE
ins_links CLASS::to_spenders(const tx_link& output_tx,
const output_link& link) const NOEXCEPT
{
return to_spenders(output_tx, to_output_index(output_tx, link));
}

TEMPLATE
ins_links CLASS::to_spenders(const hash_digest& point_hash,
uint32_t output_index) const NOEXCEPT
Expand Down
13 changes: 12 additions & 1 deletion include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ class query
uint32_t output_index) const NOEXCEPT;
ins_links to_spenders(const tx_link& output_tx,
uint32_t output_index) const NOEXCEPT;
ins_links to_spenders(const tx_link& output_tx,
const output_link& link) const NOEXCEPT;

/// tx to puts (forward navigation)
ins_links to_points(const tx_link& link) const NOEXCEPT;
Expand Down Expand Up @@ -416,6 +418,9 @@ class query
const output_links& outputs) const NOEXCEPT;
code to_touched_txs(const stopper& cancel, tx_links& out,
const output_links& outputs) const NOEXCEPT;
code to_touched_txs(const stopper& cancel, tx_links& out,
const output_links& outputs, const tx_links& parents,
bool turbo) const NOEXCEPT;

code to_address_outputs(output_links& out,
const hash_digest& key) const NOEXCEPT;
Expand All @@ -425,6 +430,9 @@ class query
code to_address_outputs(const stopper& cancel, outs_link& cursor,
output_links& out, const hash_digest& key,
size_t limit) const NOEXCEPT;
code to_address_outputs(const stopper& cancel, outs_link& cursor,
output_links& out, tx_links& parents, const hash_digest& key,
size_t limit) const NOEXCEPT;

/// Archive reads.
/// -----------------------------------------------------------------------
Expand Down Expand Up @@ -1338,12 +1346,15 @@ class query
history get_tx_unconfirmed_history(hash_digest&& key,
const tx_link& link) const NOEXCEPT;
code get_address_txs(const stopper& cancel, tx_links& out,
const hash_digest& key, size_t limit) const NOEXCEPT;
const hash_digest& key, size_t limit, bool turbo) const NOEXCEPT;

private:
// This value should never be read, but may be useful in debugging.
static constexpr uint32_t unspecified_timestamp = max_uint32;

// Minimum elements per parallel task for single-read transforms.
static constexpr size_t parallel_floor = 32;

// Fewest pool records hashed by one task of the compact short id scan.
static constexpr size_t short_id_minimum_records = system::power2(10u);

Expand Down
4 changes: 3 additions & 1 deletion include/bitcoin/database/tables/archives/output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ struct output
{
using namespace system;

// Skip parent fk and value, and read the script size.
// Read parent fk, skip value, and read the script size.
parent_fk = unsafe_from_little_endian<tx::integer>(start);
const auto* position = std::next(start, tx::size);
unsafe_from_variable(position);
const auto scrypt_size = unsafe_from_variable(position);
Expand All @@ -143,6 +144,7 @@ struct output
}

const system::hash_digest& key;
tx::integer parent_fk{};
bool match{};
};

Expand Down
Loading
Loading