mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-12 19:20:42 +02:00
Merge 18223 via blockfilter_v0
This commit is contained in:
commit
9468bae9ef
@ -10,6 +10,7 @@
|
||||
#include <hash.h>
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/script.h>
|
||||
#include <streams.h>
|
||||
#include <undo.h>
|
||||
@ -20,6 +21,7 @@ using util::Join;
|
||||
|
||||
static const std::map<BlockFilterType, std::string> g_filter_types = {
|
||||
{BlockFilterType::BASIC, "basic"},
|
||||
{BlockFilterType::V0, "v0"},
|
||||
};
|
||||
|
||||
uint64_t GCSFilter::HashToRange(const Element& element) const
|
||||
@ -182,8 +184,10 @@ const std::string& ListBlockFilterTypes()
|
||||
return type_list;
|
||||
}
|
||||
|
||||
static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
|
||||
const CBlockUndo& block_undo)
|
||||
static GCSFilter::ElementSet BuildFilterElements(const CBlock& block,
|
||||
const CBlockUndo& block_undo,
|
||||
bool only_segwit = false,
|
||||
int witness_version = 0)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
|
||||
@ -191,6 +195,13 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
|
||||
for (const CTxOut& txout : tx->vout) {
|
||||
const CScript& script = txout.scriptPubKey;
|
||||
if (script.empty() || script[0] == OP_RETURN) continue;
|
||||
if (only_segwit) {
|
||||
int witnessversion;
|
||||
std::vector<unsigned char> witnessprogram;
|
||||
if (!script.IsWitnessProgram(witnessversion, witnessprogram)) continue;
|
||||
if (witnessversion != witness_version) continue;
|
||||
if (!(witnessversion == 0 && (witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE || witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE))) continue; // specific v0 checks
|
||||
}
|
||||
elements.emplace(script.begin(), script.end());
|
||||
}
|
||||
}
|
||||
@ -199,6 +210,13 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
|
||||
for (const Coin& prevout : tx_undo.vprevout) {
|
||||
const CScript& script = prevout.out.scriptPubKey;
|
||||
if (script.empty()) continue;
|
||||
if (only_segwit) {
|
||||
int witnessversion;
|
||||
std::vector<unsigned char> witnessprogram;
|
||||
if (!script.IsWitnessProgram(witnessversion, witnessprogram)) continue;
|
||||
if (witnessversion != witness_version) continue;
|
||||
if (!(witnessversion == 0 && (witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE || witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE))) continue; // specific v0 checks
|
||||
}
|
||||
elements.emplace(script.begin(), script.end());
|
||||
}
|
||||
}
|
||||
@ -224,13 +242,24 @@ 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, BuildFilterElements(block, block_undo));
|
||||
break;
|
||||
case BlockFilterType::V0:
|
||||
m_filter = GCSFilter(params, BuildFilterElements(block, block_undo, true));
|
||||
break;
|
||||
case BlockFilterType::INVALID:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlockFilter::BuildParams(GCSFilter::Params& params) const
|
||||
{
|
||||
switch (m_filter_type) {
|
||||
case BlockFilterType::BASIC:
|
||||
case BlockFilterType::V0:
|
||||
params.m_siphash_k0 = m_block_hash.GetUint64(0);
|
||||
params.m_siphash_k1 = m_block_hash.GetUint64(1);
|
||||
params.m_P = BASIC_FILTER_P;
|
||||
|
@ -92,6 +92,8 @@ constexpr uint32_t BASIC_FILTER_M = 784931;
|
||||
enum class BlockFilterType : uint8_t
|
||||
{
|
||||
BASIC = 0,
|
||||
// Filter 1 is reserved as an option to include all filters.
|
||||
V0 = 2,
|
||||
INVALID = 255,
|
||||
};
|
||||
|
||||
|
@ -534,7 +534,7 @@ void SetupServerArgs(ArgsManager& argsman)
|
||||
argsman.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-blockfilterindex=<type>",
|
||||
strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
|
||||
" If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
|
||||
" If <type> is not supplied or if <type> = 1, certain indexes are enabled (currently just basic).",
|
||||
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
|
||||
argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||
@ -976,7 +976,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
||||
// parse and validate enabled filter types
|
||||
std::string blockfilterindex_value = args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
|
||||
if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
|
||||
g_enabled_filter_types = AllBlockFilterTypes();
|
||||
g_enabled_filter_types = {BlockFilterType::BASIC};
|
||||
} else if (blockfilterindex_value != "0") {
|
||||
const std::vector<std::string> names = args.GetArgs("-blockfilterindex");
|
||||
for (const auto& name : names) {
|
||||
|
@ -3249,7 +3249,7 @@ static RPCHelpMan getblockfilter()
|
||||
"\nRetrieve a BIP 157 content filter for a particular block.\n",
|
||||
{
|
||||
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
|
||||
{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
|
||||
{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter, values: " + ListBlockFilterTypes()},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <test/data/blockfilters.json.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <addresstype.h>
|
||||
#include <blockfilter.h>
|
||||
#include <core_io.h>
|
||||
#include <primitives/block.h>
|
||||
@ -127,6 +128,74 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
|
||||
BOOST_CHECK(default_ctor_block_filter_1.GetEncodedFilter() == default_ctor_block_filter_2.GetEncodedFilter());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(blockfilter_v0_test)
|
||||
{
|
||||
CScript included_scripts[4], excluded_scripts[8];
|
||||
|
||||
included_scripts[0] = GetScriptForDestination(WitnessV0KeyHash()); // p2wpkh
|
||||
included_scripts[1] = GetScriptForDestination(WitnessV0KeyHash()); // p2wpkh
|
||||
included_scripts[2] = GetScriptForDestination(WitnessV0ScriptHash()); // p2wsh
|
||||
included_scripts[3] = GetScriptForDestination(WitnessV0ScriptHash()); // p2wsh
|
||||
|
||||
excluded_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG; // p2pk
|
||||
excluded_scripts[1] << OP_0 << OP_HASH160 << std::vector<unsigned char>(1, 20) << OP_EQUALVERIFY << OP_CHECKSIG; // p2pkh
|
||||
excluded_scripts[2] << OP_1 << std::vector<unsigned char>(2, 33) << OP_1 << OP_CHECKMULTISIG; // multisig
|
||||
excluded_scripts[3] << OP_0 << std::vector<unsigned char>(3, 32); // push data
|
||||
excluded_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL; // random script
|
||||
excluded_scripts[5] << OP_RETURN << std::vector<unsigned char>(4, 40); // opreturn
|
||||
excluded_scripts[6] << OP_RETURN << OP_4 << OP_ADD << OP_8 << OP_EQUAL; // none standard opreturn
|
||||
|
||||
CMutableTransaction tx_1;
|
||||
tx_1.vout.emplace_back(100, included_scripts[0]);
|
||||
tx_1.vout.emplace_back(100, included_scripts[2]);
|
||||
tx_1.vout.emplace_back(200, excluded_scripts[0]);
|
||||
tx_1.vout.emplace_back(300, excluded_scripts[1]);
|
||||
tx_1.vout.emplace_back(400, excluded_scripts[2]);
|
||||
|
||||
CMutableTransaction tx_2;
|
||||
tx_2.vout.emplace_back(100, included_scripts[3]);
|
||||
tx_2.vout.emplace_back(100, excluded_scripts[3]);
|
||||
tx_2.vout.emplace_back(0, excluded_scripts[4]);
|
||||
tx_2.vout.emplace_back(400, excluded_scripts[7]); // Script is empty
|
||||
|
||||
CBlock block;
|
||||
block.vtx.push_back(MakeTransactionRef(tx_1));
|
||||
block.vtx.push_back(MakeTransactionRef(tx_2));
|
||||
|
||||
CBlockUndo block_undo;
|
||||
block_undo.vtxundo.emplace_back();
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[1]), 1000, true);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, excluded_scripts[5]), 10000, false);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[6]), 100000, false);
|
||||
|
||||
BlockFilter block_filter(BlockFilterType::V0, block, block_undo);
|
||||
const GCSFilter& filter = block_filter.GetFilter();
|
||||
|
||||
for (const CScript& script : included_scripts) {
|
||||
BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
|
||||
}
|
||||
for (const CScript& script : excluded_scripts) {
|
||||
BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
|
||||
}
|
||||
|
||||
// Test serialization/unserialization.
|
||||
BlockFilter block_filter2;
|
||||
|
||||
DataStream stream;
|
||||
stream << block_filter;
|
||||
stream >> block_filter2;
|
||||
|
||||
BOOST_CHECK_EQUAL(block_filter.GetFilterType(), block_filter2.GetFilterType());
|
||||
BOOST_CHECK_EQUAL(block_filter.GetBlockHash(), block_filter2.GetBlockHash());
|
||||
BOOST_CHECK(block_filter.GetEncodedFilter() == block_filter2.GetEncodedFilter());
|
||||
|
||||
BlockFilter default_ctor_block_filter_1;
|
||||
BlockFilter default_ctor_block_filter_2;
|
||||
BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetFilterType(), default_ctor_block_filter_2.GetFilterType());
|
||||
BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetBlockHash(), default_ctor_block_filter_2.GetBlockHash());
|
||||
BOOST_CHECK(default_ctor_block_filter_1.GetEncodedFilter() == default_ctor_block_filter_2.GetEncodedFilter());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(blockfilters_json_test)
|
||||
{
|
||||
UniValue json;
|
||||
@ -179,12 +248,17 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test)
|
||||
BOOST_AUTO_TEST_CASE(blockfilter_type_names)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(BlockFilterTypeName(BlockFilterType::BASIC), "basic");
|
||||
BOOST_CHECK_EQUAL(BlockFilterTypeName(BlockFilterType::V0), "v0");
|
||||
BOOST_CHECK_EQUAL(BlockFilterTypeName(static_cast<BlockFilterType>(255)), "");
|
||||
|
||||
BlockFilterType filter_type;
|
||||
BOOST_CHECK(BlockFilterTypeByName("basic", filter_type));
|
||||
BOOST_CHECK_EQUAL(filter_type, BlockFilterType::BASIC);
|
||||
|
||||
BlockFilterType filter_type_v0;
|
||||
BOOST_CHECK(BlockFilterTypeByName("v0", filter_type_v0));
|
||||
BOOST_CHECK_EQUAL(filter_type_v0, BlockFilterType::V0);
|
||||
|
||||
BOOST_CHECK(!BlockFilterTypeByName("unknown", filter_type));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user