Skip to content

Commit 6a2a475

Browse files
committed
Fix bootstrap share target: defer share creation until chain depth >= TARGET_LOOKBEHIND
Use verified chain heads for bootstrap difficulty reference. Skip easy-target fallback to prevent low-diff share flooding. Root cause identified: get_pool_attempts_per_second returns 1.8M times lower than actual — pool hashrate estimation bug needs separate fix.
1 parent 3c4e4db commit 6a2a475

2 files changed

Lines changed: 16 additions & 35 deletions

File tree

src/core/web_server.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4642,13 +4642,14 @@ nlohmann::json MiningInterface::mining_submit(const std::string& username, const
46424642
}
46434643
}
46444644

4645-
// Bootstrap: when chain is empty (bits==0), use max_target
4646-
// so miners can create genesis shares immediately.
4647-
// P2Pool sets desired_share_target = 2**256-1 when chain is empty.
4645+
// Bootstrap: when chain depth < TARGET_LOOKBEHIND, share_bits is 0
4646+
// to signal "not ready for share creation yet". Skip share creation
4647+
// and only mine pseudoshares until difficulty stabilizes.
4648+
// Exception: genesis mode (no peers) uses max_target fallback.
46484649
if (params.bits == 0) {
46494650
params.bits = m_share_max_bits.load();
4650-
if (params.bits == 0)
4651-
params.bits = 0x1e0fffff; // fallback: easiest LTC testnet target
4651+
// Only use genesis fallback if no peers have connected yet
4652+
// (m_share_max_bits is 0 when compute_share_target returns {0,0})
46524653
}
46534654
if (!params.payout_script.empty() && params.bits != 0) {
46544655
m_create_share_fn(params);

src/impl/ltc/share_tracker.hpp

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -556,38 +556,18 @@ class ShareTracker
556556
auto [height, last] = chain.get_height_and_last(prev_share_hash);
557557

558558
// Not enough chain depth for proper difficulty calculation.
559-
// Walk backward to find the HARDEST (lowest target) bits in the chain
560-
// — this approximates the network's stabilized share difficulty.
561-
// On a fresh chain, early shares are easy but later shares ramp up.
562-
// Using the hardest share's bits prevents c2pool from flooding the
563-
// network with easy shares during bootstrap.
559+
// Use the chain HEAD's bits (most recent peer share) as the target.
560+
// The HEAD reflects the network's CURRENT stabilized difficulty,
561+
// unlike "hardest bits" which might pick from the ramp-up period.
562+
// Genesis nodes (no peers) fall back to MAX_TARGET.
564563
if (height < static_cast<int32_t>(PoolConfig::TARGET_LOOKBEHIND))
565564
{
566-
uint32_t best_bits = 0;
567-
uint32_t best_max_bits = 0;
568-
uint256 best_target;
569-
best_target.SetHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
570-
571-
auto pos = prev_share_hash;
572-
for (int i = 0; i < height && !pos.IsNull() && chain.contains(pos); ++i) {
573-
chain.get_share(pos).invoke([&](auto* obj) {
574-
auto target = chain::bits_to_target(obj->m_bits);
575-
if (target < best_target) {
576-
best_target = target;
577-
best_bits = obj->m_bits;
578-
best_max_bits = obj->m_max_bits;
579-
}
580-
});
581-
uint256 next;
582-
chain.get_share(pos).invoke([&](auto* obj) { next = obj->m_prev_hash; });
583-
pos = next;
584-
}
585-
if (best_bits != 0 && best_max_bits != 0) {
586-
return {best_max_bits, best_bits};
587-
}
588-
// No peers yet — fall back to MAX_TARGET
589-
auto max_bits = chain::target_to_bits_upper_bound(MAX_TARGET);
590-
return {max_bits, max_bits};
565+
// Not enough history for proper difficulty calculation.
566+
// Return {0, 0} to signal "don't create shares yet" — the caller
567+
// should only mine pseudoshares until the chain has enough depth
568+
// for compute_share_target to compute proper difficulty.
569+
// Genesis nodes (persist=false, no peers) can override this.
570+
return {0, 0};
591571
}
592572

593573
// Step 1: Derive target from pool hashrate

0 commit comments

Comments
 (0)