diff --git a/include/bitcoin/system/chain/checkpoint.hpp b/include/bitcoin/system/chain/checkpoint.hpp index 5543442979..1befd7373c 100644 --- a/include/bitcoin/system/chain/checkpoint.hpp +++ b/include/bitcoin/system/chain/checkpoint.hpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -39,6 +38,7 @@ class BC_API checkpoint DEFAULT_COPY_MOVE_DESTRUCT(checkpoint); + static bool is_at(const list& checkpoints, size_t height) NOEXCEPT; static bool is_under(const list& checkpoints, size_t height) NOEXCEPT; static bool is_conflict(const list& checkpoints, const hash_digest& hash, size_t height) NOEXCEPT; diff --git a/src/chain/checkpoint.cpp b/src/chain/checkpoint.cpp index 93f6169b47..e9958dc0a3 100644 --- a/src/chain/checkpoint.cpp +++ b/src/chain/checkpoint.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -32,9 +31,18 @@ namespace libbitcoin { namespace system { namespace chain { +bool checkpoint::is_at(const list& checkpoints, size_t height) NOEXCEPT +{ + return std::any_of(checkpoints.begin(), checkpoints.end(), + [&](const auto& item) NOEXCEPT + { + return height == item.height(); + }); +} + bool checkpoint::is_under(const list& checkpoints, size_t height) NOEXCEPT { - // False if empty, optimial if checkpoints sorted by increasing height. + // False if empty, optimal if checkpoints sorted by increasing height. return std::any_of(checkpoints.rbegin(), checkpoints.rend(), [&](const auto& item) NOEXCEPT { @@ -45,13 +53,14 @@ bool checkpoint::is_under(const list& checkpoints, size_t height) NOEXCEPT bool checkpoint::is_conflict(const list& checkpoints, const hash_digest& hash, size_t height) NOEXCEPT { + // Conflict if height matches and hash does not. const auto it = std::find_if(checkpoints.begin(), checkpoints.end(), [&](const auto& item) NOEXCEPT { return height == item.height(); }); - return it != checkpoints.end() && it->hash() == hash; + return it != checkpoints.end() && it->hash() != hash; } // Constructors. diff --git a/test/chain/checkpoint.cpp b/test/chain/checkpoint.cpp index 53aacc3e27..9a44779c82 100644 --- a/test/chain/checkpoint.cpp +++ b/test/chain/checkpoint.cpp @@ -166,6 +166,79 @@ BOOST_AUTO_TEST_CASE(checkpoint__equality__different__expected) BOOST_REQUIRE(!(instance1 == instance2)); } +BOOST_AUTO_TEST_CASE(checkpoint__is_at__empty__false) +{ + const checkpoints points{}; + BOOST_REQUIRE(!checkpoint::is_at(points, 0)); + BOOST_REQUIRE(!checkpoint::is_at(points, 42)); +} + +BOOST_AUTO_TEST_CASE(checkpoint__is_at__non_empty__expected) +{ + const checkpoints points + { + { "0000000000000000000000000000000000000000000000000000000000000000", 17 }, + { "0102030405060708090a0102030405060708090a0102030405060708090a0b0c", 42 }, + { "1111111111111111111111111111111111111111111111111111111111111111", 1000 } + }; + + BOOST_REQUIRE(!checkpoint::is_at(points, 0)); + BOOST_REQUIRE(!checkpoint::is_at(points, 1)); + BOOST_REQUIRE(checkpoint::is_at(points, 17)); + BOOST_REQUIRE(checkpoint::is_at(points, 42)); + BOOST_REQUIRE(checkpoint::is_at(points, 1000)); + BOOST_REQUIRE(!checkpoint::is_at(points, 1001)); +} + +BOOST_AUTO_TEST_CASE(checkpoint__is_under__empty__false) +{ + const checkpoints points{}; + BOOST_REQUIRE(!checkpoint::is_under(points, 0)); + BOOST_REQUIRE(!checkpoint::is_under(points, 42)); +} + +BOOST_AUTO_TEST_CASE(checkpoint__is_under__non_empty__expected) +{ + const checkpoints points + { + { "0000000000000000000000000000000000000000000000000000000000000000", 17 }, + { "0102030405060708090a0102030405060708090a0102030405060708090a0b0c", 42 }, + { "1111111111111111111111111111111111111111111111111111111111111111", 1000 } + }; + + BOOST_REQUIRE(checkpoint::is_under(points, 0)); + BOOST_REQUIRE(checkpoint::is_under(points, 1)); + BOOST_REQUIRE(checkpoint::is_under(points, 17)); + BOOST_REQUIRE(checkpoint::is_under(points, 42)); + BOOST_REQUIRE(checkpoint::is_under(points, 1000)); + BOOST_REQUIRE(!checkpoint::is_under(points, 1001)); +} + +BOOST_AUTO_TEST_CASE(checkpoint__is_conflict__empty__false) +{ + const checkpoints points{}; + const checkpoint point("0102030405060708090a0102030405060708090a0102030405060708090a0b0c", 42); + BOOST_REQUIRE(!checkpoint::is_conflict(points, point.hash(), 0)); + BOOST_REQUIRE(!checkpoint::is_conflict(points, point.hash(), point.height())); +} + +BOOST_AUTO_TEST_CASE(checkpoint__is_conflict__non_empty__expected) +{ + const checkpoints points + { + { "0000000000000000000000000000000000000000000000000000000000000000", 17 }, + { "0102030405060708090a0102030405060708090a0102030405060708090a0b0c", 42 }, + { "1111111111111111111111111111111111111111111111111111111111111111", 1000 } + }; + const auto hash = base16_hash("0102030405060708090a0102030405060708090a0102030405060708090a0b0c"); + + BOOST_REQUIRE(!checkpoint::is_conflict(points, hash, 0)); + BOOST_REQUIRE(checkpoint::is_conflict(points, hash, 17)); + BOOST_REQUIRE(!checkpoint::is_conflict(points, hash, 42)); + BOOST_REQUIRE(checkpoint::is_conflict(points, hash, 1000)); + BOOST_REQUIRE(!checkpoint::is_conflict(points, hash, 1001)); +} + // json // ----------------------------------------------------------------------------