diff --git a/include/bitcoin/database/impl/query/consensus/consensus_forks.ipp b/include/bitcoin/database/impl/query/consensus/consensus_forks.ipp index a17fd431e..77fd96a07 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_forks.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_forks.ipp @@ -125,7 +125,7 @@ header_states CLASS::get_validated_fork(size_t& fork_point, code ec{}; // Disable filter constraint if filtering is disabled. - ////const auto filter = filter_enabled(); + const auto filter = filter_enabled(); /////////////////////////////////////////////////////////////////////////// std::shared_lock interlock{ candidate_reorganization_mutex_ }; @@ -134,9 +134,11 @@ header_states CLASS::get_validated_fork(size_t& fork_point, auto height = add1(fork_point); auto link = to_candidate(height); - // Filter body always written before validated, so the check is redundant. - while (is_block_validated(ec, link, height, top_checkpoint) - /*&& (!filter || is_filtered_body(link))*/) + // Filter body always written before validated, but validated state is not + // written in the case of bypassed blocks, it's inferred. So for bypassed + // blocks the existence of the filter must be verified. + while (is_block_validated(ec, link, height, top_checkpoint) && + (!filter || ec != error::bypassed || is_filtered_body(link))) { out.emplace_back(link, ec); link = to_candidate(++height); diff --git a/test/query/consensus/consensus_forks.cpp b/test/query/consensus/consensus_forks.cpp index f0854c909..7a0ce33b0 100644 --- a/test/query/consensus/consensus_forks.cpp +++ b/test/query/consensus/consensus_forks.cpp @@ -22,4 +22,89 @@ BOOST_FIXTURE_TEST_SUITE(query_consensus_tests, test::directory_setup_fixture) +BOOST_AUTO_TEST_CASE(query_consensus__get_validated_fork__bypassed_filters_pending__stops_at_first_missing) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_REQUIRE(!store.create(test::events_handler)); + BOOST_REQUIRE(query.initialize(test::genesis)); + BOOST_REQUIRE(query.filter_enabled()); + BOOST_REQUIRE(query.set(test::block1, database::context{ 0, 1, 0 }, false, false)); + BOOST_REQUIRE(query.set(test::block2, database::context{ 0, 2, 0 }, false, false)); + + const auto link1 = query.to_header(test::block1_hash); + const auto link2 = query.to_header(test::block2_hash); + BOOST_REQUIRE(query.push_candidate(link1)); + BOOST_REQUIRE(query.push_candidate(link2)); + + size_t fork_point{}; + auto fork = query.get_validated_fork(fork_point, 2); + BOOST_REQUIRE_EQUAL(fork_point, 0u); + BOOST_REQUIRE(fork.empty()); + + BOOST_REQUIRE(query.set_filter_body(link1, test::block1)); + fork = query.get_validated_fork(fork_point, 2); + BOOST_REQUIRE_EQUAL(fork.size(), 1u); + BOOST_REQUIRE(fork.front().link == link1); + BOOST_REQUIRE(fork.front().ec == error::bypassed); + + BOOST_REQUIRE(query.set_filter_body(link2, test::block2)); + fork = query.get_validated_fork(fork_point, 2); + BOOST_REQUIRE_EQUAL(fork.size(), 2u); + BOOST_REQUIRE(fork.front().link == link1); + BOOST_REQUIRE(fork.back().link == link2); + BOOST_REQUIRE(fork.front().ec == error::bypassed); + BOOST_REQUIRE(fork.back().ec == error::bypassed); +} + +BOOST_AUTO_TEST_CASE(query_consensus__get_validated_fork__filters_disabled__bypass_unchanged) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + settings.filter_tx.buckets = 0; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_REQUIRE(!store.create(test::events_handler)); + BOOST_REQUIRE(query.initialize(test::genesis)); + BOOST_REQUIRE(!query.filter_enabled()); + BOOST_REQUIRE(query.set(test::block1, database::context{ 0, 1, 0 }, false, false)); + BOOST_REQUIRE(query.set(test::block2, database::context{ 0, 2, 0 }, false, false)); + + const auto link1 = query.to_header(test::block1_hash); + const auto link2 = query.to_header(test::block2_hash); + BOOST_REQUIRE(query.push_candidate(link1)); + BOOST_REQUIRE(query.push_candidate(link2)); + + size_t fork_point{}; + const auto fork = query.get_validated_fork(fork_point, 2); + BOOST_REQUIRE_EQUAL(fork_point, 0u); + BOOST_REQUIRE_EQUAL(fork.size(), 2u); + BOOST_REQUIRE(fork.front().link == link1); + BOOST_REQUIRE(fork.back().link == link2); + BOOST_REQUIRE(fork.front().ec == error::bypassed); + BOOST_REQUIRE(fork.back().ec == error::bypassed); +} + +BOOST_AUTO_TEST_CASE(query_consensus__get_validated_fork__milestone_filter_pending__empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_REQUIRE(!store.create(test::events_handler)); + BOOST_REQUIRE(query.initialize(test::genesis)); + BOOST_REQUIRE(query.filter_enabled()); + BOOST_REQUIRE(query.set(test::block1, database::context{ 0, 1, 0 }, true, false)); + + const auto link = query.to_header(test::block1_hash); + BOOST_REQUIRE(query.push_candidate(link)); + + size_t fork_point{}; + const auto fork = query.get_validated_fork(fork_point); + BOOST_REQUIRE_EQUAL(fork_point, 0u); + BOOST_REQUIRE(fork.empty()); +} + BOOST_AUTO_TEST_SUITE_END()