aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@protonmail.com>2020-05-21 18:09:24 +0200
committerWladimir J. van der Laan <laanwj@protonmail.com>2020-05-21 19:34:29 +0200
commit4479eb04d92806633aa3ad3e413f6a7166863638 (patch)
tree6cf61d79794ae455322a3340e8c95379f13bb2c2 /src
parentfed1a9043fdf802c7cf7eab1c8aab25ca1c90e8d (diff)
parent0187d4c118ab4c0f5c2d4fb180c2a8dea8ac53cf (diff)
downloadbitcoin-4479eb04d92806633aa3ad3e413f6a7166863638.tar.xz
Merge #18960: indexes: Add compact block filter headers cache
0187d4c118ab4c0f5c2d4fb180c2a8dea8ac53cf [indexes] Add compact block filter headers cache (John Newbery) Pull request description: Cache block filter headers at heights of multiples of 1000 in memory. Block filter headers at height 1000x are checkpointed, and will be the most frequently requested. Cache them in memory to avoid costly disk reads. ACKs for top commit: jkczyz: ACK 0187d4c118ab4c0f5c2d4fb180c2a8dea8ac53cf theStack: ACK 0187d4c118ab4c0f5c2d4fb180c2a8dea8ac53cf :tada: fjahr: re-utACK 0187d4c118ab4c0f5c2d4fb180c2a8dea8ac53cf laanwj: code review ACK 0187d4c118ab4c0f5c2d4fb180c2a8dea8ac53cf ariard: Code Review ACK 0187d4c. Tree-SHA512: 2075ae36901ebcdc4a217eae5203ebc8582181a0831fb7a53a119f031c46bca960a610a38a3d0636a9a405f713efcf4200c85f10c8559fd80139036d89473c56
Diffstat (limited to 'src')
-rw-r--r--src/index/blockfilterindex.cpp27
-rw-r--r--src/index/blockfilterindex.h13
-rw-r--r--src/net_processing.cpp6
3 files changed, 40 insertions, 6 deletions
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index f2c3d66ebd..65a5f03a8e 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -31,6 +31,12 @@ constexpr char DB_FILTER_POS = 'P';
constexpr unsigned int MAX_FLTR_FILE_SIZE = 0x1000000; // 16 MiB
/** The pre-allocation chunk size for fltr?????.dat files */
constexpr unsigned int FLTR_FILE_CHUNK_SIZE = 0x100000; // 1 MiB
+/** Maximum size of the cfheaders cache
+ * We have a limit to prevent a bug in filling this cache
+ * potentially turning into an OOM. At 2000 entries, this cache
+ * is big enough for a 2,000,000 length block chain, which
+ * we should be enough until ~2047. */
+constexpr size_t CF_HEADERS_CACHE_MAX_SZ{2000};
namespace {
@@ -377,13 +383,32 @@ bool BlockFilterIndex::LookupFilter(const CBlockIndex* block_index, BlockFilter&
return ReadFilterFromDisk(entry.pos, filter_out);
}
-bool BlockFilterIndex::LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) const
+bool BlockFilterIndex::LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out)
{
+ LOCK(m_cs_headers_cache);
+
+ bool is_checkpoint{block_index->nHeight % CFCHECKPT_INTERVAL == 0};
+
+ if (is_checkpoint) {
+ // Try to find the block in the headers cache if this is a checkpoint height.
+ auto header = m_headers_cache.find(block_index->GetBlockHash());
+ if (header != m_headers_cache.end()) {
+ header_out = header->second;
+ return true;
+ }
+ }
+
DBVal entry;
if (!LookupOne(*m_db, block_index, entry)) {
return false;
}
+ if (is_checkpoint &&
+ m_headers_cache.size() < CF_HEADERS_CACHE_MAX_SZ) {
+ // Add to the headers cache if this is a checkpoint height.
+ m_headers_cache.emplace(block_index->GetBlockHash(), entry.header);
+ }
+
header_out = entry.header;
return true;
}
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index 436d52515f..7ca43540c7 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -10,6 +10,14 @@
#include <flatfile.h>
#include <index/base.h>
+/** Interval between compact filter checkpoints. See BIP 157. */
+static constexpr int CFCHECKPT_INTERVAL = 1000;
+
+struct FilterHeaderHasher
+{
+ size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
+};
+
/**
* BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of
* blocks by height. An index is constructed for each supported filter type with its own database
@@ -30,6 +38,9 @@ private:
bool ReadFilterFromDisk(const FlatFilePos& pos, BlockFilter& filter) const;
size_t WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& filter);
+ Mutex m_cs_headers_cache;
+ std::unordered_map<uint256, uint256, FilterHeaderHasher> m_headers_cache GUARDED_BY(m_cs_headers_cache);
+
protected:
bool Init() override;
@@ -54,7 +65,7 @@ public:
bool LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const;
/** Get a single filter header by block. */
- bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) const;
+ bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out);
/** Get a range of filters between two heights on a chain. */
bool LookupFilterRange(int start_height, const CBlockIndex* stop_index,
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 018541a597..9d9e31d3ed 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -129,8 +129,6 @@ static constexpr unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
/** Maximum feefilter broadcast delay after significant change. */
static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
-/** Interval between compact filter checkpoints. See BIP 157. */
-static constexpr int CFCHECKPT_INTERVAL = 1000;
struct COrphanTx {
// When modifying, adapt the copy of this definition in tests/DoS_tests.
@@ -1994,7 +1992,7 @@ static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_pa
BlockFilterType filter_type,
const uint256& stop_hash,
const CBlockIndex*& stop_index,
- const BlockFilterIndex*& filter_index)
+ BlockFilterIndex*& filter_index)
{
const bool supported_filter_type =
(filter_type == BlockFilterType::BASIC &&
@@ -2049,7 +2047,7 @@ static void ProcessGetCFCheckPt(CNode* pfrom, CDataStream& vRecv, const CChainPa
const BlockFilterType filter_type = static_cast<BlockFilterType>(filter_type_ser);
const CBlockIndex* stop_index;
- const BlockFilterIndex* filter_index;
+ BlockFilterIndex* filter_index;
if (!PrepareBlockFilterRequest(pfrom, chain_params, filter_type, stop_hash,
stop_index, filter_index)) {
return;