|
| 1 | +// dgb think() Phase-6 desired-shares TIMESTAMP CUTOFF conformance KAT. |
| 2 | +// |
| 3 | +// FENCED, additive (no production code touched this slice). Pins |
| 4 | +// src/impl/dgb/think_p6_desired_cutoff.hpp against the p2pool data.py think() |
| 5 | +// Phase-6 tail oracle for the two pure decisions: |
| 6 | +// timestamp_cutoff = min(now, best_ts) - 3600 if best valid |
| 7 | +// = now - 24*60*60 otherwise |
| 8 | +// keep(req) = req.max_timestamp >= timestamp_cutoff (inclusive) |
| 9 | +// |
| 10 | +// Expectations are HAND-DERIVED from the oracle formula, NOT read back from the |
| 11 | +// code under test — a conformance KAT that asks its subject for the answer |
| 12 | +// passes vacuously. Pure arithmetic: links only core (no chain standup). MUST |
| 13 | +// appear in BOTH this dir's CMakeLists.txt AND the build.yml --target allowlist, |
| 14 | +// or it becomes a #143 NOT_BUILT sentinel (compiled-out, silently "passing"). |
| 15 | + |
| 16 | +#include <impl/dgb/think_p6_desired_cutoff.hpp> |
| 17 | + |
| 18 | +#include <gtest/gtest.h> |
| 19 | + |
| 20 | +#include <cstdint> |
| 21 | + |
| 22 | +namespace { |
| 23 | + |
| 24 | +// A fixed "now" well above the 24h/1h offsets so no uint32 underflow occurs in |
| 25 | +// the hand-derived arithmetic below. (1700000000 ~= 2023-11-14 UTC.) |
| 26 | +constexpr uint32_t NOW = 1700000000u; |
| 27 | + |
| 28 | +// ---- timestamp_cutoff: no valid best -> 24h fallback window |
| 29 | +TEST(ThinkP6DesiredCutoff, NoBestUses24hFallback) |
| 30 | +{ |
| 31 | + // best_ts is ignored on the no-best branch. |
| 32 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(false, 0, NOW), |
| 33 | + NOW - 86400u); |
| 34 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(false, NOW + 50000u, NOW), |
| 35 | + NOW - 86400u); |
| 36 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(false, 12345u, NOW), |
| 37 | + NOW - 86400u); |
| 38 | +} |
| 39 | + |
| 40 | +// ---- timestamp_cutoff: valid best, best_ts BEHIND now -> best_ts - 3600 |
| 41 | +TEST(ThinkP6DesiredCutoff, BestBehindNowUsesBestMinus3600) |
| 42 | +{ |
| 43 | + const uint32_t best_ts = NOW - 7200u; // 2h behind local clock |
| 44 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(true, best_ts, NOW), |
| 45 | + best_ts - 3600u); // min(now,best)=best |
| 46 | +} |
| 47 | + |
| 48 | +// ---- timestamp_cutoff: valid best, best_ts AHEAD of now -> now - 3600 |
| 49 | +// min() clamps a best share whose timestamp leads local clock so the cutoff |
| 50 | +// can never be pushed into the future. |
| 51 | +TEST(ThinkP6DesiredCutoff, BestAheadOfNowClampsToNowMinus3600) |
| 52 | +{ |
| 53 | + const uint32_t best_ts = NOW + 10000u; // best leads local clock |
| 54 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(true, best_ts, NOW), |
| 55 | + NOW - 3600u); // min(now,best)=now |
| 56 | +} |
| 57 | + |
| 58 | +// ---- timestamp_cutoff: valid best, best_ts == now -> now - 3600 (boundary) |
| 59 | +TEST(ThinkP6DesiredCutoff, BestEqualsNowBoundary) |
| 60 | +{ |
| 61 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(true, NOW, NOW), NOW - 3600u); |
| 62 | +} |
| 63 | + |
| 64 | +// ---- keep predicate: inclusive lower bound at the cutoff |
| 65 | +TEST(ThinkP6DesiredCutoff, KeepPredicateInclusive) |
| 66 | +{ |
| 67 | + const uint32_t cutoff = NOW - 3600u; |
| 68 | + EXPECT_FALSE(dgb::think_p6_passes_cutoff(cutoff - 1u, cutoff)); // stale -> drop |
| 69 | + EXPECT_TRUE (dgb::think_p6_passes_cutoff(cutoff, cutoff)); // == cutoff -> keep |
| 70 | + EXPECT_TRUE (dgb::think_p6_passes_cutoff(cutoff + 1u, cutoff)); // fresh -> keep |
| 71 | + EXPECT_TRUE (dgb::think_p6_passes_cutoff(NOW, cutoff)); |
| 72 | + EXPECT_FALSE(dgb::think_p6_passes_cutoff(0u, cutoff)); |
| 73 | +} |
| 74 | + |
| 75 | +// ---- Non-circular delegation proof --------------------------------------- |
| 76 | +// When share_tracker.hpp think() Phase 6 is rewired to CALL the SSOT functions |
| 77 | +// above, this anchors against drift. It does NOT stand up a ShareTracker; |
| 78 | +// instead it re-implements the EXACT pre-delegation inline expressions verbatim |
| 79 | +// (copied from the share_tracker.hpp think() body as it stood before this slice) |
| 80 | +// and asserts byte-identity to the SSOT across a dense input grid. Independent |
| 81 | +// code path => non-circular. |
| 82 | + |
| 83 | +// Verbatim copy of the pre-delegation inline cutoff computation. |
| 84 | +// Original (best valid): std::min(static_cast<uint32_t>(now), best_ts) - 3600 |
| 85 | +// (no best) : now - 24*60*60 |
| 86 | +inline uint32_t inline_cutoff_verbatim(bool best_valid, uint32_t best_ts, |
| 87 | + uint32_t now) |
| 88 | +{ |
| 89 | + uint32_t timestamp_cutoff; |
| 90 | + if (best_valid) |
| 91 | + timestamp_cutoff = std::min(static_cast<uint32_t>(now), best_ts) - 3600; |
| 92 | + else |
| 93 | + timestamp_cutoff = static_cast<uint32_t>(now) - 24 * 60 * 60; |
| 94 | + return timestamp_cutoff; |
| 95 | +} |
| 96 | + |
| 97 | +// Verbatim copy of the pre-delegation inline keep test. |
| 98 | +// Original: if (d.max_timestamp >= timestamp_cutoff) keep; |
| 99 | +inline bool inline_keep_verbatim(uint32_t max_timestamp, uint32_t cutoff) |
| 100 | +{ |
| 101 | + return max_timestamp >= cutoff; |
| 102 | +} |
| 103 | + |
| 104 | +TEST(ThinkP6DesiredCutoff, DelegationMatchesPreDelegationInlineCutoff) |
| 105 | +{ |
| 106 | + for (uint32_t now : {1700000000u, 1234567890u, 90000u}) { |
| 107 | + // no-best branch |
| 108 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(false, 0u, now), |
| 109 | + inline_cutoff_verbatim(false, 0u, now)) |
| 110 | + << "no-best cutoff drift @ now=" << now; |
| 111 | + // best-valid branch across a window straddling `now` |
| 112 | + for (uint32_t off = 0; off <= 20000u; off += 250u) { |
| 113 | + const uint32_t behind = now - off; |
| 114 | + const uint32_t ahead = now + off; |
| 115 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(true, behind, now), |
| 116 | + inline_cutoff_verbatim(true, behind, now)) |
| 117 | + << "best-behind cutoff drift @ now=" << now << " off=" << off; |
| 118 | + EXPECT_EQ(dgb::think_p6_timestamp_cutoff(true, ahead, now), |
| 119 | + inline_cutoff_verbatim(true, ahead, now)) |
| 120 | + << "best-ahead cutoff drift @ now=" << now << " off=" << off; |
| 121 | + } |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +TEST(ThinkP6DesiredCutoff, DelegationMatchesPreDelegationInlineKeep) |
| 126 | +{ |
| 127 | + const uint32_t cutoff = 1700000000u - 3600u; |
| 128 | + for (int32_t delta = -5000; delta <= 5000; delta += 25) { |
| 129 | + const uint32_t ts = static_cast<uint32_t>(static_cast<int64_t>(cutoff) + delta); |
| 130 | + EXPECT_EQ(dgb::think_p6_passes_cutoff(ts, cutoff), |
| 131 | + inline_keep_verbatim(ts, cutoff)) |
| 132 | + << "keep drift @ delta=" << delta; |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +} // namespace |
0 commit comments