|
14 | 14 | #include <impl/dgb/config_pool.hpp> |
15 | 15 | #include <impl/dgb/config_coin.hpp> |
16 | 16 | #include <impl/dgb/share.hpp> |
| 17 | +#include <impl/dgb/share_tracker.hpp> // DensePPLNSWindow — V36 decayed-PPLNS SSOT |
17 | 18 |
|
18 | 19 | // Sharechain-identity: the isolation primitives (PREFIX / IDENTIFIER) are the |
19 | 20 | // per-coin namespacing boundary — they MUST stay byte-exact to the DGB oracle. |
@@ -88,3 +89,50 @@ TEST(DGB_share_test, LoadShareSymbolLinks) |
88 | 89 | auto fn = static_cast<dgb::ShareType (*)(chain::RawShare&, NetService)>(&dgb::load_share); |
89 | 90 | EXPECT_NE(fn, nullptr); |
90 | 91 | } |
| 92 | + |
| 93 | +// ── V36 decayed-PPLNS bit-exact KAT ─────────────────────────────────────── |
| 94 | +// Pins DensePPLNSWindow's decay constants + weight recurrence to the V36 MASTER |
| 95 | +// (frstrtr/p2pool-merged-v36 data.py get_decayed_cumulative_weights) — NOT the |
| 96 | +// legacy flat-weight oracle (that path is pre-v36 compat, replaced in the |
| 97 | +// transition). 3-bucket: decayed-PPLNS = BUCKET 2 v36-native shared structure |
| 98 | +// (DGB == ltc == merged-v36 ref). Ground truth re-derived independently with |
| 99 | +// bigint integer math mirroring the exact fixed-point ops (DECAY_PRECISION=40, |
| 100 | +// LN2_MICRO=693147, half_life=max(chain_len/4,1), iterative mul128_shift). This |
| 101 | +// guard fails loudly if any decay constant or the weight math drifts. |
| 102 | +TEST(DGB_share_test, DecayedPPLNSWeightsKAT) |
| 103 | +{ |
| 104 | + using W = dgb::DensePPLNSWindow; |
| 105 | + |
| 106 | + // chain_len = 8 -> half_life = max(8/4,1) = 2. Pin the per-step factor and |
| 107 | + // the full depth-0..7 decay table against the independent bigint oracle. |
| 108 | + W::init_decay_table(8); |
| 109 | + EXPECT_EQ(W::s_decay_per, 718450034647ull); |
| 110 | + ASSERT_EQ(W::s_decay_table.size(), 8u); |
| 111 | + EXPECT_EQ(W::s_decay_table[0], 1099511627776ull); // == DECAY_SCALE = 2^40 |
| 112 | + EXPECT_EQ(W::s_decay_table[1], 718450034647ull); |
| 113 | + EXPECT_EQ(W::s_decay_table[2], 469454291564ull); |
| 114 | + EXPECT_EQ(W::s_decay_table[3], 306753874646ull); |
| 115 | + EXPECT_EQ(W::s_decay_table[4], 200441110671ull); |
| 116 | + EXPECT_EQ(W::s_decay_table[5], 130973533401ull); |
| 117 | + EXPECT_EQ(W::s_decay_table[6], 85581577522ull); |
| 118 | + EXPECT_EQ(W::s_decay_table[7], 55921270664ull); |
| 119 | + |
| 120 | + // Hand-built window (depth 0 = newest). att kept small so every product |
| 121 | + // stays < 2^64 and the expected weights are exact uint64 literals. |
| 122 | + std::vector<unsigned char> A{0xAA}, B{0xBB}, C{0xCC}; |
| 123 | + dgb::DensePPLNSWindow win; |
| 124 | + win.m_entries.push_back({uint288(1000000ull), 0u, A}); // depth 0 |
| 125 | + win.m_entries.push_back({uint288(1000000ull), 6553u, B}); // depth 1 |
| 126 | + win.m_entries.push_back({uint288(2000000ull), 0u, A}); // depth 2 |
| 127 | + win.m_entries.push_back({uint288(500000ull), 65535u, C}); // depth 3 (full donation) |
| 128 | + |
| 129 | + auto w = win.compute_v36_weights(); |
| 130 | + |
| 131 | + // Per-script address weight: A = depth0 + depth2, B = depth1, C = 0 (full |
| 132 | + // donation consumed the weight). Totals from the same re-derivation. |
| 133 | + EXPECT_EQ(w.weights.at(A), 121497433620ull); |
| 134 | + EXPECT_EQ(w.weights.at(B), 38540372332ull); |
| 135 | + EXPECT_EQ(w.weights.at(C), 0ull); |
| 136 | + EXPECT_EQ(w.total_weight, 173461511355ull); |
| 137 | + EXPECT_EQ(w.total_donation_weight, 13423705403ull); |
| 138 | +} |
0 commit comments