If I understand this correctly, GetSkipHeight’s complexity should come from its bit-width, not distance, so maybe we can just estimate it via triangular numbers:
This isn’t as tight as the previous one, but is very simple and seems to pass.
The patch would be something like:
0diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
1index d7d18cf76e..fd7b409c88 100644
2--- a/src/test/skiplist_tests.cpp
3+++ b/src/test/skiplist_tests.cpp
4@@ -6,7 +6,7 @@
5 #include <test/util/random.h>
6 #include <test/util/setup_common.h>
7
8-#include <cmath>
9+#include <bit>
10 #include <vector>
11
12 #include <boost/test/unit_test.hpp>
13@@ -268,6 +268,8 @@ BOOST_AUTO_TEST_CASE(skip_height_analysis)
14
15 // Build a chain
16 constexpr int chain_size{1'000'000};
17+ constexpr int chain_bits{std::bit_width<unsigned>(chain_size - 1)}; // Bit width of the maximum height.
18+ constexpr int iteration_bound{chain_bits * (chain_bits + 1) / 2}; // Conservative O(log^2(N)) bound.
19 std::vector<CBlockIndex> block_index(chain_size);
20 for (auto i{0}; i < chain_size; ++i) {
21 block_index[i].pprev = i == 0 ? nullptr : &block_index[i - 1];
22@@ -313,12 +315,7 @@ BOOST_AUTO_TEST_CASE(skip_height_analysis)
23 ++iteration_count;
24 }
25
26- // Asserts on the number of iterations:
27- // Absolute value maximum (derived empirically)
28- BOOST_CHECK_LE(iteration_count, 130);
29- // Dynamic bound, function of distance. Formula derived empirically.
30- const auto bound_log_distance{std::ceil(8.3 * std::log(delta) / std::log(2) - 35)};
31- BOOST_CHECK_LE(double(iteration_count), bound_log_distance);
32+ BOOST_CHECK_LE(iteration_count, iteration_bound);
33
34 // Also check that `GetAncestor` gives the same result
35 auto p_ancestor{start_p.GetAncestor(target_height)};