Skip to content

Commit c811160

Browse files
authored
Merge pull request #724 from evoskuil/master
Fee queries optimizations, style, comments.
2 parents d2c2573 + d1ec9fa commit c811160

3 files changed

Lines changed: 28 additions & 163 deletions

File tree

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

Lines changed: 7 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ bool CLASS::get_height(size_t& out, const hash_digest& key) const NOEXCEPT
279279
TEMPLATE
280280
bool CLASS::get_height(size_t& out, const header_link& link) const NOEXCEPT
281281
{
282-
// Use get_height(..., key) in place of get(to_header(key)).
283282
const auto height = get_height(link);
284283
if (height >= height_link::terminal)
285284
return false;
@@ -347,86 +346,20 @@ bool CLASS::get_tx_spend(uint64_t& out, const tx_link& link) const NOEXCEPT
347346
TEMPLATE
348347
bool CLASS::get_tx_fee(uint64_t& out, const tx_link& link) const NOEXCEPT
349348
{
350-
#if defined(SLOW_FEES)
351-
const auto tx = get_transaction(link, false);
352-
if (!tx)
353-
return false;
354-
355-
// Prevent coinbase populate failure.
356-
if (tx->is_coinbase())
357-
{
358-
out = zero;
359-
return true;
360-
}
361-
362-
if (!populate_without_metadata(*tx))
363-
return false;
364-
365-
out = tx->fee();
366-
return true;
367-
#elif defined(FAST_FEES)
368-
table::transaction::get_coinbase tx{};
369-
if (!store_.tx.get(link, tx))
370-
return false;
371-
372-
// Prevent coinbase overspend failure.
373-
if (tx.coinbase)
374-
{
375-
out = zero;
376-
return true;
377-
}
378-
379-
uint64_t value{}, spend{};
380-
if (!get_tx_value(value, link) || !get_tx_spend(spend, link) ||
381-
spend > value)
382-
return false;
383-
384-
out = value - spend;
385-
return true;
386-
#else // FASTER_FEES
387-
table::transaction::get_puts tx{};
388-
if (!store_.tx.get(link, tx))
349+
uint64_t value{};
350+
if (!get_tx_value(value, link))
389351
return false;
390352

391-
// Shortcircuit coinbase prevout read.
392-
if (tx.coinbase)
393-
{
394-
out = zero;
353+
// Zero input implies either zero output or coinbase (both zero).
354+
if (is_zero(value))
395355
return true;
396-
}
397-
398-
uint64_t value{};
399-
auto point_fk = tx.points_fk;
400-
for (size_t index{}; index < tx.ins_count; ++index)
401-
{
402-
table::point::get_composed point{};
403-
if (!store_.point.get(point_fk++, point))
404-
return false;
405-
406-
uint64_t one_value{};
407-
if (!get_value(one_value, to_output(point.key))) return false;
408-
value = system::ceilinged_add(value, one_value);
409-
}
410-
411-
table::outs::record outs{};
412-
outs.out_fks.resize(tx.outs_count);
413-
if (!store_.outs.get(tx.outs_fk, outs))
414-
return false;
415356

416357
uint64_t spend{};
417-
for (const auto& output_fk: outs.out_fks)
418-
{
419-
uint64_t one_spend{};
420-
if (!get_value(one_spend, output_fk)) return false;
421-
spend = system::ceilinged_add(spend, one_spend);
422-
}
423-
424-
if (spend > value)
358+
if (!get_tx_spend(spend, link) || spend > value)
425359
return false;
426360

427361
out = value - spend;
428362
return true;
429-
#endif // SLOW_FEES
430363
}
431364

432365
TEMPLATE
@@ -490,49 +423,16 @@ bool CLASS::get_block_spend(uint64_t& out,
490423
}
491424

492425
TEMPLATE
493-
bool CLASS::get_block_fee(uint64_t& out, const header_link& link) const NOEXCEPT
426+
bool CLASS::get_block_fee(uint64_t& out,
427+
const header_link& link) const NOEXCEPT
494428
{
495-
#if defined(SLOW_FEES)
496-
const auto block = get_block(link, false);
497-
if (!block || !populate_without_metadata(*block))
498-
return false;
499-
500-
out = block->fees();
501-
return true;
502-
#elif defined(FAST_FEES)
503429
uint64_t value{}, spend{};
504430
if (!get_block_value(value, link) || !get_block_spend(spend, link) ||
505431
spend > value)
506432
return false;
507433

508434
out = value - spend;
509435
return true;
510-
#else // FASTER_FEES
511-
table::txs::get_txs txs{};
512-
if (!store_.txs.at(to_txs(link), txs) || (txs.tx_fks.size() < one))
513-
return false;
514-
515-
std::atomic_bool fail{};
516-
const auto begin = std::next(txs.tx_fks.begin());
517-
constexpr auto parallel = poolstl::execution::par;
518-
constexpr auto relaxed = std::memory_order_relaxed;
519-
520-
out = std::transform_reduce(parallel, begin, txs.tx_fks.end(), 0_u64,
521-
[](uint64_t left, uint64_t right) NOEXCEPT
522-
{
523-
return system::ceilinged_add(left, right);
524-
},
525-
[&](const auto& tx_fk) NOEXCEPT
526-
{
527-
uint64_t fee{};
528-
if (!fail.load(relaxed) && !get_tx_fee(fee, tx_fk))
529-
fail.store(true, relaxed);
530-
531-
return fee;
532-
});
533-
534-
return !fail.load(relaxed);
535-
#endif // SLOW_FEES
536436
}
537437

538438
} // namespace database

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

Lines changed: 20 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,16 @@
2222
#include <atomic>
2323
#include <algorithm>
2424
#include <iterator>
25-
#include <memory>
2625
#include <numeric>
2726
#include <utility>
2827
#include <bitcoin/database/define.hpp>
2928

30-
// virtual_size
31-
// ----------------------------------------------------------------------------
32-
3329
namespace libbitcoin {
3430
namespace database {
3531

32+
// virtual_size
33+
// ----------------------------------------------------------------------------
34+
3635
TEMPLATE
3736
bool CLASS::get_tx_virtual_size(size_t& out,
3837
const tx_link& link) const NOEXCEPT
@@ -63,70 +62,36 @@ bool CLASS::get_block_virtual_size(size_t& out,
6362
TEMPLATE
6463
bool CLASS::get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT
6564
{
66-
#if defined(SLOW_FEES)
65+
// This is somehow ~15-20% less efficient.
66+
////return get_tx_virtual_size(out.bytes, link) && get_tx_fee(out.fee, link);
6767
const auto tx = get_transaction(link, false);
6868
if (!tx || tx->is_coinbase() || !populate_without_metadata(*tx))
6969
return false;
7070

7171
out.bytes = tx->virtual_size();
7272
out.fee = tx->fee();
7373
return true;
74-
#else
75-
table::transaction::get_coinbase tx{};
76-
if (!store_.tx.get(link, tx) || tx.coinbase)
77-
return false;
78-
79-
return get_tx_virtual_size(out.bytes, link) && get_tx_fee(out.fee, link);
80-
#endif // SLOW_FEES
8174
}
82-
75+
8376
TEMPLATE
8477
bool CLASS::get_block_fees(fee_rates& out,
8578
const header_link& link) const NOEXCEPT
8679
{
87-
#if defined(SLOW_FEES)
88-
out.clear();
89-
const auto block = get_block(link, false);
90-
if (!block)
91-
return false;
92-
93-
block->populate();
94-
if (!populate_without_metadata(*block))
95-
return false;
96-
97-
const auto& txs = *block->transactions_ptr();
98-
if (txs.empty())
99-
return false;
100-
101-
out.reserve(txs.size());
102-
for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx)
103-
out.emplace_back((*tx)->virtual_size(), (*tx)->fee());
104-
105-
return true;
106-
#else // FAST_FEES|FASTER_FEES
10780
out.clear();
10881
table::txs::get_txs txs{};
10982
if (!store_.txs.at(to_txs(link), txs) || (txs.tx_fks.size() < one))
11083
return false;
11184

112-
std::atomic_bool fail{};
11385
out.resize(sub1(txs.tx_fks.size()));
114-
const auto begin = std::next(txs.tx_fks.begin());
115-
constexpr auto parallel = poolstl::execution::par;
116-
constexpr auto relaxed = std::memory_order_relaxed;
86+
const auto end = txs.tx_fks.end();
87+
auto rate = out.begin();
11788

118-
std::transform(parallel, begin, txs.tx_fks.end(), out.begin(),
119-
[&](const auto& tx_fk) NOEXCEPT
120-
{
121-
fee_rate rate{};
122-
if (!fail.load(relaxed) && !get_tx_fees(rate, tx_fk))
123-
fail.store(true, relaxed);
124-
125-
return rate;
126-
});
89+
// Skip coinbase.
90+
for (auto tx = std::next(txs.tx_fks.begin()); tx != end; ++tx)
91+
if (!get_tx_fees(*rate++, *tx))
92+
return false;
12793

128-
return !fail.load(relaxed);
129-
#endif // SLOW_FEES
94+
return true;
13095
}
13196

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

140-
if (system::is_add_overflow(start, sub1(count)))
141-
return false;
142-
143-
const auto last = start + sub1(count);
144-
if (last > get_top_confirmed())
105+
if (system::is_add_overflow(start, sub1(count)) ||
106+
(start + sub1(count) > get_top_confirmed()))
145107
return false;
146108

147109
out.resize(count);
110+
std::atomic_bool fail{};
148111
std::vector<size_t> offsets(count);
149112
std::iota(offsets.begin(), offsets.end(), zero);
150-
151-
std::atomic_bool fail{};
113+
constexpr auto parallel = poolstl::execution::par;
152114
constexpr auto relaxed = std::memory_order_relaxed;
153-
std::for_each(poolstl::execution::par, offsets.begin(), offsets.end(),
115+
116+
// Parallel execution saves ~50%.
117+
std::for_each(parallel, offsets.begin(), offsets.end(),
154118
[&](const size_t& offset) NOEXCEPT
155119
{
156120
if (fail.load(relaxed))

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ typename CLASS::transaction::cptr CLASS::get_transaction(const tx_link& link,
186186
tx.locktime
187187
);
188188

189+
// TODO: store caches sizes so these could be forwarded.
189190
// Witness hash is not retained by the store.
190191
ptr->set_nominal_hash(std::move(tx.key));
191192
return ptr;

0 commit comments

Comments
 (0)