@@ -136,3 +136,53 @@ TEST(DGB_share_test, DecayedPPLNSWeightsKAT)
136136 EXPECT_EQ (w.total_weight , 173461511355ull );
137137 EXPECT_EQ (w.total_donation_weight , 13423705403ull );
138138}
139+
140+ // ── get_desired_version_weights: attempts-weighted, NOT a flat count ─────────
141+ // The check()-phase version-switch gate (share_check step 2) tallies each
142+ // share's desired_version vote weighted by target_to_average_attempts(target)
143+ // (= ShareIndex::work), per canonical p2pool get_desired_version_counts
144+ // (data.py:2651) — NOT one-share-one-vote. Bucket-2 v36-native shared structure
145+ // (must stay byte-identical with p2pool-merged-v36 across all coins). Guard: a
146+ // SINGLE high-difficulty share out-votes TWO low-difficulty shares — exactly the
147+ // property a flat tally (2 vs 1) inverts. test-only, no prod change.
148+ TEST (DGB_share_test, DesiredVersionWeightsByAttempts)
149+ {
150+ dgb::ShareTracker tracker;
151+
152+ auto mk = [&](const char * hh, const char * ph, uint64_t dv, uint32_t bits) {
153+ auto * s = new dgb::MergedMiningShare ();
154+ s->m_hash .SetHex (hh);
155+ if (ph) s->m_prev_hash .SetHex (ph); else s->m_prev_hash .SetNull ();
156+ s->m_desired_version = dv;
157+ s->m_bits = bits;
158+ s->m_max_bits = bits;
159+ dgb::ShareType st; st = s;
160+ tracker.add (st);
161+ };
162+
163+ // chain: h0 <- h1 (dv=36, easy target => low work) <- h2 (dv=35, hard target
164+ // => high work). flat count would read dv36=2, dv35=1; attempts read dv35 >>.
165+ const char * h0 = " 00000000000000000000000000000000000000000000000000000000000000a0" ;
166+ const char * h1 = " 00000000000000000000000000000000000000000000000000000000000000a1" ;
167+ const char * h2 = " 00000000000000000000000000000000000000000000000000000000000000a2" ;
168+ mk (h0, nullptr , 36 , 0x1e0fffff );
169+ mk (h1, h0, 36 , 0x1e0fffff );
170+ mk (h2, h1, 35 , 0x1d00ffff );
171+
172+ uint256 tip; tip.SetHex (h2);
173+ auto w = tracker.get_desired_version_weights (tip, 100 );
174+
175+ ASSERT_EQ (w.count (35u ), 1u );
176+ ASSERT_EQ (w.count (36u ), 1u );
177+
178+ // Weight per desired_version == sum of ShareIndex::work over its shares,
179+ // tied directly to the SSOT work fn (no magic literals).
180+ const uint288 easy_work = chain::target_to_average_attempts (chain::bits_to_target (0x1e0fffff ));
181+ const uint288 hard_work = chain::target_to_average_attempts (chain::bits_to_target (0x1d00ffff ));
182+ EXPECT_EQ (w.at (36u ), easy_work + easy_work); // two equal dv=36 shares
183+ EXPECT_EQ (w.at (35u ), hard_work); // one dv=35 share
184+
185+ // Attempts-weighting: the lone high-difficulty dv=35 share outweighs the two
186+ // low-difficulty dv=36 shares — the exact property a flat count inverts.
187+ EXPECT_GT (w.at (35u ), w.at (36u ));
188+ }
0 commit comments