Skip to content

Commit

Permalink
builds the index, does not serve to peers yet
Browse files Browse the repository at this point in the history
  • Loading branch information
josibake committed Jan 27, 2024
1 parent cbb8d3a commit 0004e6c
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 10 deletions.
55 changes: 54 additions & 1 deletion src/blockfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
#include <undo.h>
#include <util/golombrice.h>
#include <util/string.h>
#include <wallet/silentpayments.h>
#include <logging.h>

static const std::map<BlockFilterType, std::string> g_filter_types = {
{BlockFilterType::BASIC, "basic"},
{BlockFilterType::SILENT_PAYMENTS, "silent-payments"},
};

uint64_t GCSFilter::HashToRange(const Element& element) const
Expand Down Expand Up @@ -204,6 +207,35 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
return elements;
}

static InputsFilter SilentPaymentFilterElements(const CBlock& block,
const CBlockUndo& block_undo)
{
if (block_undo.vtxundo.empty()) return InputsFilter();
if (block.vtx.size() == 1) return InputsFilter();
InputsFilter elements;
assert(block.vtx.size() - 1 == block_undo.vtxundo.size());
for (uint32_t i = 0; i < block.vtx.size(); ++i) {
const CTransactionRef& tx = block.vtx.at(i);
if (tx->IsCoinBase()) continue;
// -1 as blockundo does not have coinbase tx
CTxUndo undoTX{block_undo.vtxundo.at(i - 1)};
std::map<COutPoint, Coin> coins;
for (uint32_t j = 0; j < tx->vin.size(); j++) {
coins[tx->vin.at(j).prevout] = undoTX.vprevout.at(j);
}
auto tweak_data = wallet::GetSilentPaymentTweakDataFromTxInputs(tx->vin, coins);
if (!tweak_data.has_value()) continue;

CKey inputs_hash;
inputs_hash.Set(tweak_data->first.begin(), tweak_data->first.end(), true);
CPubKey input_pubkeys_sum{tweak_data->second};
CPubKey final{inputs_hash.UnhashedECDH(input_pubkeys_sum)};
elements.addElement(final.data());
}

return elements;
}

BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
std::vector<unsigned char> filter, bool skip_decode_check)
: m_filter_type(filter_type), m_block_hash(block_hash)
Expand All @@ -213,6 +245,16 @@ BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
throw std::invalid_argument("unknown filter_type");
}
m_filter = GCSFilter(params, std::move(filter), skip_decode_check);
switch (m_filter_type) {
case BlockFilterType::BASIC:
m_filter = GCSFilter(params, std::move(filter), skip_decode_check);
break;
case BlockFilterType::SILENT_PAYMENTS:
m_filter = InputsFilter(std::move(filter));
break;
case BlockFilterType::INVALID:
throw std::invalid_argument("unknown filter_type");
}
}

BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
Expand All @@ -222,7 +264,16 @@ BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const
if (!BuildParams(params)) {
throw std::invalid_argument("unknown filter_type");
}
m_filter = GCSFilter(params, BasicFilterElements(block, block_undo));
switch (m_filter_type) {
case BlockFilterType::BASIC:
m_filter = GCSFilter(params, BasicFilterElements(block, block_undo));
break;
case BlockFilterType::SILENT_PAYMENTS:
m_filter = SilentPaymentFilterElements(block, block_undo);
break;
case BlockFilterType::INVALID:
throw std::invalid_argument("unknown filter_type");
}
}

bool BlockFilter::BuildParams(GCSFilter::Params& params) const
Expand All @@ -234,6 +285,8 @@ bool BlockFilter::BuildParams(GCSFilter::Params& params) const
params.m_P = BASIC_FILTER_P;
params.m_M = BASIC_FILTER_M;
return true;
case BlockFilterType::SILENT_PAYMENTS:
return true;
case BlockFilterType::INVALID:
return false;
}
Expand Down
60 changes: 56 additions & 4 deletions src/blockfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#ifndef BITCOIN_BLOCKFILTER_H
#define BITCOIN_BLOCKFILTER_H

#include "serialize.h"
#include <cstddef>
#include <cstdint>
#include <ios>
#include <set>
#include <string>
#include <unordered_set>
#include <utility>
#include <variant>
#include <vector>

#include <attributes.h>
Expand Down Expand Up @@ -86,12 +88,62 @@ class GCSFilter
bool MatchAny(const ElementSet& elements) const;
};

class InputsFilter {
public:
InputsFilter() = default;
InputsFilter(std::vector<unsigned char> filter)
: m_encoded(filter)
{}
// Element structure
struct Element {
char data[33];

Element(const unsigned char* d) {
std::memcpy(data, d, 33);
}
Element();
};

// Adds an element to the filter
void addElement(const Element& element) {
elements.push_back(element);
encode();
}

// Returns the encoded data
const std::vector<unsigned char>& GetEncoded() const LIFETIMEBOUND { return m_encoded; }

private:
std::vector<Element> elements; // Stores the elements
std::vector<unsigned char> m_encoded; // Encoded block of bytes

// Encodes the elements into m_encoded
void encode() {
m_encoded.clear();
for (const auto& element : elements) {
m_encoded.insert(m_encoded.end(), element.data, element.data + 33);
}
}
// decode into elements from a encoded InputsFilter
void decode() {
elements.clear();
const size_t elementSize = 33;
for (size_t i = 0; i < m_encoded.size(); i += elementSize) {
Element element;
std::memcpy(element.data, &m_encoded[i], elementSize);
elements.push_back(element);
}
}
};

using Filter = std::variant<GCSFilter, InputsFilter>;
constexpr uint8_t BASIC_FILTER_P = 19;
constexpr uint32_t BASIC_FILTER_M = 784931;

enum class BlockFilterType : uint8_t
{
BASIC = 0,
SILENT_PAYMENTS = 1,
INVALID = 255,
};

Expand All @@ -116,7 +168,7 @@ class BlockFilter
private:
BlockFilterType m_filter_type = BlockFilterType::INVALID;
uint256 m_block_hash;
GCSFilter m_filter;
Filter m_filter;

bool BuildParams(GCSFilter::Params& params) const;

Expand All @@ -133,11 +185,11 @@ class BlockFilter

BlockFilterType GetFilterType() const { return m_filter_type; }
const uint256& GetBlockHash() const LIFETIMEBOUND { return m_block_hash; }
const GCSFilter& GetFilter() const LIFETIMEBOUND { return m_filter; }
const Filter& GetFilter() const LIFETIMEBOUND { return m_filter; }

const std::vector<unsigned char>& GetEncodedFilter() const LIFETIMEBOUND
{
return m_filter.GetEncoded();
return std::visit([](const auto& f) -> const std::vector<unsigned char>& { return f.GetEncoded(); }, m_filter);
}

//! Compute the filter hash.
Expand All @@ -150,7 +202,7 @@ class BlockFilter
void Serialize(Stream& s) const {
s << static_cast<uint8_t>(m_filter_type)
<< m_block_hash
<< m_filter.GetEncoded();
<< std::visit([](const auto& f) { return f.GetEncoded(); }, m_filter);
}

template <typename Stream>
Expand Down
2 changes: 1 addition & 1 deletion src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ class ChainImpl : public Chain
BlockFilter filter;
const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};
if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;
return filter.GetFilter().MatchAny(filter_set);
return std::get<GCSFilter>(filter.GetFilter()).MatchAny(filter_set);
}
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2442,7 +2442,7 @@ static RPCHelpMan scanblocks()
if (index->LookupFilterRange(start_block, end_range, filters)) {
for (const BlockFilter& filter : filters) {
// compare the elements-set with each filter
if (filter.GetFilter().MatchAny(needle_set)) {
if (std::get<GCSFilter>(filter.GetFilter()).MatchAny(needle_set)) {
if (filter_false_positives) {
// Double check the filter matches by scanning the block
const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
Expand Down
4 changes: 2 additions & 2 deletions src/test/blockfilter_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[3]), 100000, false);

BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
const GCSFilter& filter = block_filter.GetFilter();
const GCSFilter& filter = std::get<GCSFilter>(block_filter.GetFilter());

for (const CScript& script : included_scripts) {
BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
Expand Down Expand Up @@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test)
BOOST_CHECK(ParseHashStr(test[pos++].get_str(), filter_header_basic));

BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo);
BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic);
BOOST_CHECK(computed_filter_basic.GetEncodedFilter() == filter_basic);

uint256 computed_header_basic = computed_filter_basic.ComputeHeader(prev_filter_header_basic);
BOOST_CHECK(computed_header_basic == filter_header_basic);
Expand Down
2 changes: 1 addition & 1 deletion src/test/fuzz/blockfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ FUZZ_TARGET(blockfilter)
(void)BlockFilterTypeName(block_filter_type);
}
{
const GCSFilter gcs_filter = block_filter->GetFilter();
const GCSFilter gcs_filter = std::get<GCSFilter>(block_filter->GetFilter());
(void)gcs_filter.GetN();
(void)gcs_filter.GetParams();
(void)gcs_filter.GetEncoded();
Expand Down

0 comments on commit 0004e6c

Please sign in to comment.