Skip to content

Commit c5894cd

Browse files
authored
Merge pull request #288 from frstrtr/ltc-doge/ratchet-mint-accept-coupling
ltc: couple AutoRatchet mint gate to the work-weighted accept gate (fix #97 crossing wedge)
2 parents 148d9fe + 9a80a0a commit c5894cd

1 file changed

Lines changed: 27 additions & 11 deletions

File tree

src/impl/ltc/auto_ratchet.hpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -140,25 +140,41 @@ class AutoRatchet
140140
// (jtoomim rule). Prevents activation before the entire PPLNS
141141
// window has transitioned — p2pool check() rejects V36 shares
142142
// when the oldest 10% has < 60% signaling.
143+
// WORK-WEIGHTED tail guard (mint<->accept coupling). The
144+
// consensus accept gate (share_check step 2 / p2pool check()
145+
// data.py:1399) keys the 60% switch rule off
146+
// get_desired_version_counts, which in canonical p2pool
147+
// (data.py:2651) weights each share by
148+
// target_to_average_attempts(target) -- i.e. WORK, not a flat
149+
// head-count. AutoRatchet must evaluate the SAME work-weighted
150+
// 60% rule over the SAME [9/10*CL, CL] window before it
151+
// activates; otherwise a 95%-by-COUNT activation can outrun the
152+
// 60%-by-WORK accept gate under heterogeneous hashrate, the node
153+
// mints a V36 boundary share that every peer rejects, and the
154+
// crossing wedges. The weighted tally makes activation strictly
155+
// imply the accept gate, so a minted boundary share can never be
156+
// rejected.
143157
uint32_t tail_start = (chain_length * 9) / 10;
144158
uint32_t tail_size = chain_length / 10;
145159
auto tail_ancestor = tracker.chain.get_nth_parent_key(best_share_hash, tail_start);
146-
auto tail_counts = tracker.get_desired_version_counts(tail_ancestor, tail_size);
147-
148-
int64_t tail_target = 0, tail_total = 0;
149-
for (auto& [ver, cnt] : tail_counts) {
150-
tail_total += cnt;
151-
if (ver >= target_version_)
152-
tail_target += cnt;
160+
auto tail_weights = tracker.get_desired_version_weights(tail_ancestor, tail_size);
161+
162+
// mapped_type is the work-weight accumulator (uint288); default 0.
163+
decltype(tail_weights)::mapped_type tail_target{}, tail_total{};
164+
for (auto& [ver, w] : tail_weights) {
165+
tail_total = tail_total + w;
166+
if (static_cast<int64_t>(ver) >= target_version_)
167+
tail_target = tail_target + w;
153168
}
154-
int tail_pct = (tail_total > 0) ? static_cast<int>(tail_target * 100 / tail_total) : 0;
169+
// Canonical: counts.get(VERSION,0) < sum(counts)*60//100
170+
bool tail_ok = !(tail_target * uint32_t(100) < tail_total * uint32_t(SWITCH_THRESHOLD));
155171

156-
if (tail_pct < SWITCH_THRESHOLD) {
172+
if (!tail_ok) {
157173
static int tail_log = 0;
158174
if (tail_log++ % 20 == 0)
159175
LOG_INFO << "[AutoRatchet] VOTING: full window " << vote_pct
160-
<< "% >= " << ACTIVATION_THRESHOLD << "% but oldest 10% only "
161-
<< tail_pct << "% (need " << SWITCH_THRESHOLD << "%) — waiting";
176+
<< "% >= " << ACTIVATION_THRESHOLD << "% but oldest 10% work-weighted V"
177+
<< target_version_ << " desire < " << SWITCH_THRESHOLD << "%) — waiting";
162178
// Don't transition yet
163179
}
164180
else

0 commit comments

Comments
 (0)