Skip to content

Commit

Permalink
index: Implement lookup methods on block filter index.
Browse files Browse the repository at this point in the history
Summary:
This is a partial backport of Core [[bitcoin/bitcoin#14121 | PR14121]] : bitcoin/bitcoin@b5e8200

Depends on D6338 and D6337

Test Plan:
  ninja all check-all

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D6339
  • Loading branch information
jimpo authored and deadalnix committed Jun 3, 2020
1 parent 12fb824 commit ec4a36d
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
160 changes: 160 additions & 0 deletions src/index/blockfilterindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <dbwrapper.h>
#include <index/blockfilterindex.h>
#include <primitives/blockhash.h>
#include <util/system.h>
Expand Down Expand Up @@ -153,6 +154,28 @@ bool BlockFilterIndex::CommitInternal(CDBBatch &batch) {
return BaseIndex::CommitInternal(batch);
}

bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos &pos,
BlockFilter &filter) const {
CAutoFile filein(m_filter_fileseq->Open(pos, true), SER_DISK,
CLIENT_VERSION);
if (filein.IsNull()) {
return false;
}

BlockHash block_hash;
std::vector<uint8_t> encoded_filter;
try {
filein >> block_hash >> encoded_filter;
filter =
BlockFilter(GetFilterType(), block_hash, std::move(encoded_filter));
} catch (const std::exception &e) {
return error("%s: Failed to deserialize block filter from disk: %s",
__func__, e.what());
}

return true;
}

size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos &pos,
const BlockFilter &filter) {
assert(filter.GetFilterType() == GetFilterType());
Expand Down Expand Up @@ -302,3 +325,140 @@ bool BlockFilterIndex::Rewind(const CBlockIndex *current_tip,

return BaseIndex::Rewind(current_tip, new_tip);
}

static bool LookupOne(const CDBWrapper &db, const CBlockIndex *block_index,
DBVal &result) {
// First check if the result is stored under the height index and the value
// there matches the block hash. This should be the case if the block is on
// the active chain.
std::pair<BlockHash, DBVal> read_out;
if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
return false;
}
if (read_out.first == block_index->GetBlockHash()) {
result = std::move(read_out.second);
return true;
}

// If value at the height index corresponds to an different block, the
// result will be stored in the hash index.
return db.Read(DBHashKey(block_index->GetBlockHash()), result);
}

static bool LookupRange(CDBWrapper &db, const std::string &index_name,
int start_height, const CBlockIndex *stop_index,
std::vector<DBVal> &results) {
if (start_height < 0) {
return error("%s: start height (%d) is negative", __func__,
start_height);
}
if (start_height > stop_index->nHeight) {
return error("%s: start height (%d) is greater than stop height (%d)",
__func__, start_height, stop_index->nHeight);
}

size_t results_size =
static_cast<size_t>(stop_index->nHeight - start_height + 1);
std::vector<std::pair<BlockHash, DBVal>> values(results_size);

DBHeightKey key(start_height);
std::unique_ptr<CDBIterator> db_it(db.NewIterator());
db_it->Seek(DBHeightKey(start_height));
for (int height = start_height; height <= stop_index->nHeight; ++height) {
if (!db_it->Valid() || !db_it->GetKey(key) || key.height != height) {
return false;
}

size_t i = static_cast<size_t>(height - start_height);
if (!db_it->GetValue(values[i])) {
return error("%s: unable to read value in %s at key (%c, %d)",
__func__, index_name, DB_BLOCK_HEIGHT, height);
}

db_it->Next();
}

results.resize(results_size);

// Iterate backwards through block indexes collecting results in order to
// access the block hash of each entry in case we need to look it up in the
// hash index.
for (const CBlockIndex *block_index = stop_index;
block_index && block_index->nHeight >= start_height;
block_index = block_index->pprev) {
BlockHash block_hash = block_index->GetBlockHash();

size_t i = static_cast<size_t>(block_index->nHeight - start_height);
if (block_hash == values[i].first) {
results[i] = std::move(values[i].second);
continue;
}

if (!db.Read(DBHashKey(block_hash), results[i])) {
return error("%s: unable to read value in %s at key (%c, %s)",
__func__, index_name, DB_BLOCK_HASH,
block_hash.ToString());
}
}

return true;
}

bool BlockFilterIndex::LookupFilter(const CBlockIndex *block_index,
BlockFilter &filter_out) const {
DBVal entry;
if (!LookupOne(*m_db, block_index, entry)) {
return false;
}

return ReadFilterFromDisk(entry.pos, filter_out);
}

bool BlockFilterIndex::LookupFilterHeader(const CBlockIndex *block_index,
uint256 &header_out) const {
DBVal entry;
if (!LookupOne(*m_db, block_index, entry)) {
return false;
}

header_out = entry.header;
return true;
}

bool BlockFilterIndex::LookupFilterRange(
int start_height, const CBlockIndex *stop_index,
std::vector<BlockFilter> &filters_out) const {
std::vector<DBVal> entries;
if (!LookupRange(*m_db, m_name, start_height, stop_index, entries)) {
return false;
}

filters_out.resize(entries.size());
auto filter_pos_it = filters_out.begin();
for (const auto &entry : entries) {
if (!ReadFilterFromDisk(entry.pos, *filter_pos_it)) {
return false;
}
++filter_pos_it;
}

return true;
}

bool BlockFilterIndex::LookupFilterHashRange(
int start_height, const CBlockIndex *stop_index,
std::vector<uint256> &hashes_out) const

{
std::vector<DBVal> entries;
if (!LookupRange(*m_db, m_name, start_height, stop_index, entries)) {
return false;
}

hashes_out.clear();
hashes_out.reserve(entries.size());
for (const auto &entry : entries) {
hashes_out.push_back(entry.hash);
}
return true;
}
17 changes: 17 additions & 0 deletions src/index/blockfilterindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class BlockFilterIndex final : public BaseIndex {
FlatFilePos m_next_filter_pos;
std::unique_ptr<FlatFileSeq> m_filter_fileseq;

bool ReadFilterFromDisk(const FlatFilePos &pos, BlockFilter &filter) const;
size_t WriteFilterToDisk(FlatFilePos &pos, const BlockFilter &filter);

protected:
Expand All @@ -49,6 +50,22 @@ class BlockFilterIndex final : public BaseIndex {
bool f_memory = false, bool f_wipe = false);

BlockFilterType GetFilterType() const { return m_filter_type; }

/** Get a single filter by block. */
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;

/** Get a range of filters between two heights on a chain. */
bool LookupFilterRange(int start_height, const CBlockIndex *stop_index,
std::vector<BlockFilter> &filters_out) const;

/** Get a range of filter hashes between two heights on a chain. */
bool LookupFilterHashRange(int start_height, const CBlockIndex *stop_index,
std::vector<uint256> &hashes_out) const;
};

#endif // BITCOIN_INDEX_BLOCKFILTERINDEX_H

0 comments on commit ec4a36d

Please sign in to comment.