Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/bitcoin/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ enum error_t : uint8_t
tx_connected,
tx_disconnected,
block_valid,
block_prevalid,
block_confirmable,
block_unconfirmable,
unassociated,
Expand Down
45 changes: 43 additions & 2 deletions include/bitcoin/database/impl/query/consensus/consensus_forks.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,45 @@
namespace libbitcoin {
namespace database {

// get_prevalids
// ----------------------------------------------------------------------------
// startup query (reorg safety not required)

TEMPLATE
header_links CLASS::get_prevalids(size_t fork_point) const NOEXCEPT
{
header_links out{};
auto height = fork_point;

while (true)
{
const auto link = to_candidate(++height);
if (link.is_terminal())
break;

switch (get_block_state(link).value())
{
case error::block_prevalid:
{
out.push_back(link);
break;
}

case error::unassociated:
case error::block_unconfirmable:
return out;

////case error::bypassed:
////case error::unvalidated:
////case error::block_valid:
////case error::block_confirmable:
default:;
}
}

return out;
}

// get_confirmed
// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -133,8 +172,10 @@ header_states CLASS::get_validated_fork(size_t& fork_point,
fork_point = get_fork_();
auto height = add1(fork_point);
auto link = to_candidate(height);
while (is_block_validated(ec, link, height, top_checkpoint) &&
(!filter || is_filtered_body(link)))

// 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))*/)
{
out.emplace_back(link, ec);
link = to_candidate(++height);
Expand Down
12 changes: 12 additions & 0 deletions include/bitcoin/database/impl/query/consensus/consensus_states.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ bool CLASS::is_validateable(size_t height) const NOEXCEPT
return
(ec == database::error::unvalidated) ||
(ec == database::error::block_valid) ||
(ec == database::error::block_prevalid) ||
(ec == database::error::unknown_state) ||
(ec == database::error::block_confirmable);
}
Expand All @@ -58,6 +59,10 @@ inline code CLASS::to_block_code(
case block_state::valid:
return error::block_valid;

// Transitional: Satisfies validation rules if signatures verify.
case block_state::prevalid:
return error::block_prevalid;

// Final: Satisfies confirmation rules (prevouts confirmable).
case block_state::confirmable:
return error::block_confirmable;
Expand Down Expand Up @@ -134,6 +139,7 @@ code CLASS::get_header_state(const header_link& link) const NOEXCEPT
// unassociated
// unvalidated
// block_valid
// block_prevalid
// block_confirmable
// block_unconfirmable
TEMPLATE
Expand Down Expand Up @@ -227,6 +233,12 @@ bool CLASS::set_block_valid(const header_link& link) NOEXCEPT
return set_block_state(link, block_state::valid);
}

TEMPLATE
bool CLASS::set_block_prevalid(const header_link& link) NOEXCEPT
{
return set_block_state(link, block_state::prevalid);
}

TEMPLATE
bool CLASS::set_block_confirmable(const header_link& link) NOEXCEPT
{
Expand Down
2 changes: 2 additions & 0 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ class query

/// Setters.
bool set_block_valid(const header_link& link) NOEXCEPT;
bool set_block_prevalid(const header_link& link) NOEXCEPT;
bool set_block_unconfirmable(const header_link& link) NOEXCEPT;
bool set_block_confirmable(const header_link& link) NOEXCEPT;
bool set_block_unknown(const header_link& link) NOEXCEPT;
Expand Down Expand Up @@ -665,6 +666,7 @@ class query
header_links get_confirmed_headers(size_t first,
size_t limit) const NOEXCEPT;

header_links get_prevalids(size_t fork_point) const NOEXCEPT;
height_link get_confirmed_height(const header_link& link) const NOEXCEPT;
header_links get_confirmed_fork(const header_link& fork) const NOEXCEPT;
header_links get_candidate_fork(size_t& fork_point) const NOEXCEPT;
Expand Down
5 changes: 4 additions & 1 deletion include/bitcoin/database/types/block_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ enum block_state : uint8_t
/// transitional
valid = 1,

/// transitional
prevalid = 2,

/// final
unconfirmable = 2,
unconfirmable = 3,

/// transitional (debug)
block_unknown = 42
Expand Down
1 change: 1 addition & 0 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
{ tx_connected, "transaction connected" },
{ tx_disconnected, "transaction disconnected" },
{ block_valid, "block valid" },
{ block_prevalid, "block prevalid" },
{ block_confirmable, "block confirmable" },
{ block_unconfirmable, "block unconfirmable" },
{ unassociated, "unassociated" },
Expand Down
9 changes: 9 additions & 0 deletions test/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__block_valid__true_expected_message)
BOOST_REQUIRE_EQUAL(ec.message(), "block valid");
}

BOOST_AUTO_TEST_CASE(error_t__code__block_prevalid__true_expected_message)
{
constexpr auto value = error::block_prevalid;
const auto ec = code(value);
BOOST_REQUIRE(ec);
BOOST_REQUIRE(ec == value);
BOOST_REQUIRE_EQUAL(ec.message(), "block prevalid");
}

BOOST_AUTO_TEST_CASE(error_t__code__block_confirmable__true_expected_message)
{
constexpr auto value = error::block_confirmable;
Expand Down
164 changes: 164 additions & 0 deletions test/query/confirmed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,170 @@

BOOST_FIXTURE_TEST_SUITE(query_confirmed_tests, test::directory_setup_fixture)

static void push_chain(test::query_accessor& query)
{
BOOST_REQUIRE(query.initialize(test::genesis));
BOOST_REQUIRE(query.set(test::block1, context{ 0, 1, 0 }, false, false));
BOOST_REQUIRE(query.set(test::block2, context{ 0, 2, 0 }, false, false));
BOOST_REQUIRE(query.push_candidate(1));
BOOST_REQUIRE(query.push_candidate(2));
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__empty_chain__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.get_prevalids(0).empty());
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__no_prevalids__empty)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

BOOST_REQUIRE(query.get_prevalids(0).empty());
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__single_prevalid__one_link)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

const auto link1 = query.to_candidate(1);
BOOST_REQUIRE(query.set_block_prevalid(link1));

const auto out = query.get_prevalids(0);
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE(out.front() == link1);
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__two_prevalids__both_links)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

const auto link1 = query.to_candidate(1);
const auto link2 = query.to_candidate(2);
BOOST_REQUIRE(query.set_block_prevalid(link1));
BOOST_REQUIRE(query.set_block_prevalid(link2));

const auto out = query.get_prevalids(0);
BOOST_REQUIRE_EQUAL(out.size(), 2u);
BOOST_REQUIRE(out.front() == link1);
BOOST_REQUIRE(out.back() == link2);
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__valid_below_prevalid__collects_prevalid)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

const auto link1 = query.to_candidate(1);
const auto link2 = query.to_candidate(2);

BOOST_REQUIRE(query.set_block_valid(link1));
BOOST_REQUIRE(query.set_block_prevalid(link2));

const auto out = query.get_prevalids(0);
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE(out.front() == link2);
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__confirmable_below_prevalid__collects_prevalid)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

const auto link1 = query.to_candidate(1);
const auto link2 = query.to_candidate(2);

BOOST_REQUIRE(query.set_block_confirmable(link1));
BOOST_REQUIRE(query.set_block_prevalid(link2));

const auto out = query.get_prevalids(0);
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE(out.front() == link2);
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__fork_above_prevalid__excludes_below)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

const auto link1 = query.to_candidate(1);
const auto link2 = query.to_candidate(2);
BOOST_REQUIRE(query.set_block_prevalid(link1));
BOOST_REQUIRE(query.set_block_prevalid(link2));

const auto out = query.get_prevalids(1);
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE(out.front() == link2);
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__unconfirmable_stops__excludes_above)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
push_chain(query);

const auto link1 = query.to_candidate(1);
const auto link2 = query.to_candidate(2);

BOOST_REQUIRE(query.set_block_unconfirmable(link1));
BOOST_REQUIRE(query.set_block_prevalid(link2));
BOOST_REQUIRE(query.get_prevalids(0).empty());
}

BOOST_AUTO_TEST_CASE(query_prevalids__get_prevalids__unassociated_stops__excludes_above)
{
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.set(test::block1.header(), context{ 0, 1, 0 }, false));
BOOST_REQUIRE(query.set(test::block2, context{ 0, 2, 0 }, false, false));
BOOST_REQUIRE(query.push_candidate(1));
BOOST_REQUIRE(query.push_candidate(2));

const auto link2 = query.to_candidate(2);
BOOST_REQUIRE(query.set_block_prevalid(query.to_candidate(2)));
BOOST_REQUIRE(query.get_prevalids(0).empty());
}

BOOST_AUTO_TEST_CASE(query_confirmed__is_candidate_block__push_pop_candidate__expected)
{
settings settings{};
Expand Down
15 changes: 15 additions & 0 deletions test/query/properties_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,21 @@ BOOST_AUTO_TEST_CASE(query_properties_block__get_block_state__valid__block_valid
BOOST_REQUIRE_EQUAL(query.get_block_state(1), error::block_valid);
}

BOOST_AUTO_TEST_CASE(query_properties_block__get_block_state__prevalid__block_prevalid)
{
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.set(test::block1, context{}, false, false));

BOOST_REQUIRE(query.set_block_prevalid(1));
BOOST_REQUIRE_EQUAL(query.get_header_state(1), error::block_prevalid);
BOOST_REQUIRE_EQUAL(query.get_block_state(1), error::block_prevalid);
}

BOOST_AUTO_TEST_CASE(query_properties_block__get_block_state__unconfirmable__block_unconfirmable)
{
settings settings{};
Expand Down
Loading