diff --git a/src/Mempool.cpp b/src/Mempool.cpp index 18404562..82d5ef5a 100644 --- a/src/Mempool.cpp +++ b/src/Mempool.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include void Mempool::clear() { @@ -33,32 +34,42 @@ void Mempool::clear() { hashXTxs.rehash(0); } -auto Mempool::calcCompactFeeHistogram(double binSize) const -> FeeHistogramVec +auto Mempool::calcCompactFeeHistogram(unsigned binSizeBytes) const -> FeeHistogramVec { - // this algorithm is taken from: - // https://github.com/Electron-Cash/electrumx/blob/fbd00416d804c286eb7de856e9399efb07a2ceaf/electrumx/server/mempool.py#L139 + // This algorithm is taken from: + // https://github.com/spesmilo/electrumx/blob/bbd985a95db63cada13254bb766f174e9ab674d0/electrumx/server/mempool.py#L154 FeeHistogramVec ret; std::map> histogram; // sorted map, descending order by key for (const auto & [txid, tx] : txs) { + if (tx->fee < bitcoin::Amount::zero()) continue; // skip negative fees (coinbase txn, etc) const auto feeRate = unsigned(tx->fee / bitcoin::Amount::satoshi()) // sats / std::max(tx->sizeBytes, 1u); // per byte histogram[feeRate] += tx->sizeBytes; // accumulate size by feeRate } - // now, compact the bins + // Now, compact the bins ret.reserve(8); unsigned cumSize = 0; - double r = 0.; + double binSize = static_cast(binSizeBytes); + std::optional prevFeeRate; for (const auto & [feeRate, size] : histogram) { + // If there is a big lump of txns at this specific size, + // add the previous item now (if not added already) + if (double(size) > 2.0 * binSize && prevFeeRate && cumSize > 0) { + ret.emplace_back(*prevFeeRate, cumSize); + cumSize = 0; + binSize *= 1.1; + } + // Now work on perhaps adding this item cumSize += size; - if (cumSize + r > binSize) { - ret.push_back(FeeHistogramItem{feeRate, cumSize}); - r += double(cumSize) - binSize; + if (cumSize > binSize) { + ret.emplace_back(feeRate, cumSize); cumSize = 0; binSize *= 1.1; } + prevFeeRate = feeRate; } ret.shrink_to_fit(); // save memory return ret; diff --git a/src/Mempool.h b/src/Mempool.h index 60905738..20c50ee6 100644 --- a/src/Mempool.h +++ b/src/Mempool.h @@ -209,12 +209,13 @@ struct Mempool struct FeeHistogramItem { unsigned feeRate = 0; // in sats/B, quotient truncated to uint. unsigned cumulativeSize = 0; // bin size, cumulative bytes + FeeHistogramItem(unsigned fr, unsigned cs) : feeRate{fr}, cumulativeSize{cs} {} }; using FeeHistogramVec = std::vector; /// This function is potentially going to take a couple of ms at worst on very large mempools. Even a 1.5k tx /// mempool takes under 1 ms on average hardware, so it's very fast. Storage calls this in refreshMempoolHistogram /// from a periodic background task kicked off in Controller. - FeeHistogramVec calcCompactFeeHistogram(double binSize = 1e5 /* binSize in bytes */) const; + FeeHistogramVec calcCompactFeeHistogram(unsigned binSize = 30'000 /* binSize in bytes */) const; // -- Dump (for JSONesque debug support) diff --git a/src/Servers.h b/src/Servers.h index 50e616b6..74c228b7 100644 --- a/src/Servers.h +++ b/src/Servers.h @@ -334,7 +334,7 @@ protected slots: [[nodiscard]] static QVariantMap unspentItemToVariantMap(const Storage::UnspentItem &); }; -/// Implements the ElectrumX/ElectronX JSON-RPC protocol, version 1.4.4. +/// Implements the Electrum Cash JSON-RPC protocol: https://electrum-cash-protocol.readthedocs.io/en/latest/index.html /// See also ServerSSL (subclass) which is identical but serves to SSL clients. (This class serves to TCP clients). class Server : public ServerBase {