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
114 changes: 7 additions & 107 deletions include/bitcoin/database/impl/query/archive_read.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ bool CLASS::get_height(size_t& out, const hash_digest& key) const NOEXCEPT
TEMPLATE
bool CLASS::get_height(size_t& out, const header_link& link) const NOEXCEPT
{
// Use get_height(..., key) in place of get(to_header(key)).
const auto height = get_height(link);
if (height >= height_link::terminal)
return false;
Expand Down Expand Up @@ -347,86 +346,20 @@ bool CLASS::get_tx_spend(uint64_t& out, const tx_link& link) const NOEXCEPT
TEMPLATE
bool CLASS::get_tx_fee(uint64_t& out, const tx_link& link) const NOEXCEPT
{
#if defined(SLOW_FEES)
const auto tx = get_transaction(link, false);
if (!tx)
return false;

// Prevent coinbase populate failure.
if (tx->is_coinbase())
{
out = zero;
return true;
}

if (!populate_without_metadata(*tx))
return false;

out = tx->fee();
return true;
#elif defined(FAST_FEES)
table::transaction::get_coinbase tx{};
if (!store_.tx.get(link, tx))
return false;

// Prevent coinbase overspend failure.
if (tx.coinbase)
{
out = zero;
return true;
}

uint64_t value{}, spend{};
if (!get_tx_value(value, link) || !get_tx_spend(spend, link) ||
spend > value)
return false;

out = value - spend;
return true;
#else // FASTER_FEES
table::transaction::get_puts tx{};
if (!store_.tx.get(link, tx))
uint64_t value{};
if (!get_tx_value(value, link))
return false;

// Shortcircuit coinbase prevout read.
if (tx.coinbase)
{
out = zero;
// Zero input implies either zero output or coinbase (both zero).
if (is_zero(value))
return true;
}

uint64_t value{};
auto point_fk = tx.points_fk;
for (size_t index{}; index < tx.ins_count; ++index)
{
table::point::get_composed point{};
if (!store_.point.get(point_fk++, point))
return false;

uint64_t one_value{};
if (!get_value(one_value, to_output(point.key))) return false;
value = system::ceilinged_add(value, one_value);
}

table::outs::record outs{};
outs.out_fks.resize(tx.outs_count);
if (!store_.outs.get(tx.outs_fk, outs))
return false;

uint64_t spend{};
for (const auto& output_fk: outs.out_fks)
{
uint64_t one_spend{};
if (!get_value(one_spend, output_fk)) return false;
spend = system::ceilinged_add(spend, one_spend);
}

if (spend > value)
if (!get_tx_spend(spend, link) || spend > value)
return false;

out = value - spend;
return true;
#endif // SLOW_FEES
}

TEMPLATE
Expand Down Expand Up @@ -490,49 +423,16 @@ bool CLASS::get_block_spend(uint64_t& out,
}

TEMPLATE
bool CLASS::get_block_fee(uint64_t& out, const header_link& link) const NOEXCEPT
bool CLASS::get_block_fee(uint64_t& out,
const header_link& link) const NOEXCEPT
{
#if defined(SLOW_FEES)
const auto block = get_block(link, false);
if (!block || !populate_without_metadata(*block))
return false;

out = block->fees();
return true;
#elif defined(FAST_FEES)
uint64_t value{}, spend{};
if (!get_block_value(value, link) || !get_block_spend(spend, link) ||
spend > value)
return false;

out = value - spend;
return true;
#else // FASTER_FEES
table::txs::get_txs txs{};
if (!store_.txs.at(to_txs(link), txs) || (txs.tx_fks.size() < one))
return false;

std::atomic_bool fail{};
const auto begin = std::next(txs.tx_fks.begin());
constexpr auto parallel = poolstl::execution::par;
constexpr auto relaxed = std::memory_order_relaxed;

out = std::transform_reduce(parallel, begin, txs.tx_fks.end(), 0_u64,
[](uint64_t left, uint64_t right) NOEXCEPT
{
return system::ceilinged_add(left, right);
},
[&](const auto& tx_fk) NOEXCEPT
{
uint64_t fee{};
if (!fail.load(relaxed) && !get_tx_fee(fee, tx_fk))
fail.store(true, relaxed);

return fee;
});

return !fail.load(relaxed);
#endif // SLOW_FEES
}

} // namespace database
Expand Down
76 changes: 20 additions & 56 deletions include/bitcoin/database/impl/query/fees.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,16 @@
#include <atomic>
#include <algorithm>
#include <iterator>
#include <memory>
#include <numeric>
#include <utility>
#include <bitcoin/database/define.hpp>

// virtual_size
// ----------------------------------------------------------------------------

namespace libbitcoin {
namespace database {

// virtual_size
// ----------------------------------------------------------------------------

TEMPLATE
bool CLASS::get_tx_virtual_size(size_t& out,
const tx_link& link) const NOEXCEPT
Expand Down Expand Up @@ -63,70 +62,36 @@ bool CLASS::get_block_virtual_size(size_t& out,
TEMPLATE
bool CLASS::get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT
{
#if defined(SLOW_FEES)
// This is somehow ~15-20% less efficient.
////return get_tx_virtual_size(out.bytes, link) && get_tx_fee(out.fee, link);
const auto tx = get_transaction(link, false);
if (!tx || tx->is_coinbase() || !populate_without_metadata(*tx))
return false;

out.bytes = tx->virtual_size();
out.fee = tx->fee();
return true;
#else
table::transaction::get_coinbase tx{};
if (!store_.tx.get(link, tx) || tx.coinbase)
return false;

return get_tx_virtual_size(out.bytes, link) && get_tx_fee(out.fee, link);
#endif // SLOW_FEES
}

TEMPLATE
bool CLASS::get_block_fees(fee_rates& out,
const header_link& link) const NOEXCEPT
{
#if defined(SLOW_FEES)
out.clear();
const auto block = get_block(link, false);
if (!block)
return false;

block->populate();
if (!populate_without_metadata(*block))
return false;

const auto& txs = *block->transactions_ptr();
if (txs.empty())
return false;

out.reserve(txs.size());
for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx)
out.emplace_back((*tx)->virtual_size(), (*tx)->fee());

return true;
#else // FAST_FEES|FASTER_FEES
out.clear();
table::txs::get_txs txs{};
if (!store_.txs.at(to_txs(link), txs) || (txs.tx_fks.size() < one))
return false;

std::atomic_bool fail{};
out.resize(sub1(txs.tx_fks.size()));
const auto begin = std::next(txs.tx_fks.begin());
constexpr auto parallel = poolstl::execution::par;
constexpr auto relaxed = std::memory_order_relaxed;
const auto end = txs.tx_fks.end();
auto rate = out.begin();

std::transform(parallel, begin, txs.tx_fks.end(), out.begin(),
[&](const auto& tx_fk) NOEXCEPT
{
fee_rate rate{};
if (!fail.load(relaxed) && !get_tx_fees(rate, tx_fk))
fail.store(true, relaxed);

return rate;
});
// Skip coinbase.
for (auto tx = std::next(txs.tx_fks.begin()); tx != end; ++tx)
if (!get_tx_fees(*rate++, *tx))
return false;

return !fail.load(relaxed);
#endif // SLOW_FEES
return true;
}

TEMPLATE
Expand All @@ -137,20 +102,19 @@ bool CLASS::get_branch_fees(std::atomic_bool& cancel, fee_rate_sets& out,
if (is_zero(count))
return true;

if (system::is_add_overflow(start, sub1(count)))
return false;

const auto last = start + sub1(count);
if (last > get_top_confirmed())
if (system::is_add_overflow(start, sub1(count)) ||
(start + sub1(count) > get_top_confirmed()))
return false;

out.resize(count);
std::atomic_bool fail{};
std::vector<size_t> offsets(count);
std::iota(offsets.begin(), offsets.end(), zero);

std::atomic_bool fail{};
constexpr auto parallel = poolstl::execution::par;
constexpr auto relaxed = std::memory_order_relaxed;
std::for_each(poolstl::execution::par, offsets.begin(), offsets.end(),

// Parallel execution saves ~50%.
std::for_each(parallel, offsets.begin(), offsets.end(),
[&](const size_t& offset) NOEXCEPT
{
if (fail.load(relaxed))
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/database/impl/query/objects.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ typename CLASS::transaction::cptr CLASS::get_transaction(const tx_link& link,
tx.locktime
);

// TODO: store caches sizes so these could be forwarded.
// Witness hash is not retained by the store.
ptr->set_nominal_hash(std::move(tx.key));
return ptr;
Expand Down
Loading