diff --git a/include/bitcoin/database/impl/query/archive_read.ipp b/include/bitcoin/database/impl/query/archive_read.ipp index a87cebf9..080f21a8 100644 --- a/include/bitcoin/database/impl/query/archive_read.ipp +++ b/include/bitcoin/database/impl/query/archive_read.ipp @@ -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; @@ -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 @@ -490,16 +423,9 @@ 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) @@ -507,32 +433,6 @@ bool CLASS::get_block_fee(uint64_t& out, const header_link& link) const NOEXCEPT 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 diff --git a/include/bitcoin/database/impl/query/fees.ipp b/include/bitcoin/database/impl/query/fees.ipp index 449c8539..b906646c 100644 --- a/include/bitcoin/database/impl/query/fees.ipp +++ b/include/bitcoin/database/impl/query/fees.ipp @@ -22,17 +22,16 @@ #include #include #include -#include #include #include #include -// virtual_size -// ---------------------------------------------------------------------------- - namespace libbitcoin { namespace database { +// virtual_size +// ---------------------------------------------------------------------------- + TEMPLATE bool CLASS::get_tx_virtual_size(size_t& out, const tx_link& link) const NOEXCEPT @@ -63,7 +62,8 @@ 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; @@ -71,62 +71,27 @@ bool CLASS::get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT 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 @@ -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 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)) diff --git a/include/bitcoin/database/impl/query/objects.ipp b/include/bitcoin/database/impl/query/objects.ipp index 047620b5..a97e640d 100644 --- a/include/bitcoin/database/impl/query/objects.ipp +++ b/include/bitcoin/database/impl/query/objects.ipp @@ -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;