diff --git a/src/c2pool/merged/merged_mining.cpp b/src/c2pool/merged/merged_mining.cpp index 3b9fd83d0..0774c8113 100644 --- a/src/c2pool/merged/merged_mining.cpp +++ b/src/c2pool/merged/merged_mining.cpp @@ -1272,6 +1272,11 @@ void MergedMiningManager::set_block_relay_fn(BlockRelayFn fn) // ─── Shared helpers ────────────────────────────────────────────────────────── +// [v36-audit C4] Output ordering here is NODE-LOCAL and NOT consensus-bearing: +// the assembled DOGE coinbase is submitted only to dogecoind, which accepts any +// valid ordering. The sharechain commits to merged work via the AuxPoW merkle +// proof, not by re-deriving these outputs across peers. Donation split + dust +// tiebreak below are deterministic purely for stable local block assembly. /*static*/ std::string MergedMiningManager::build_pplns_coinbase_hex( int height, const std::vector, uint64_t>>& payouts, diff --git a/src/impl/ltc/share_tracker.hpp b/src/impl/ltc/share_tracker.hpp index 4076bef28..f5140b225 100644 --- a/src/impl/ltc/share_tracker.hpp +++ b/src/impl/ltc/share_tracker.hpp @@ -2304,6 +2304,10 @@ class ShareTracker delta.total_weight = att * 65535; delta.total_donation_weight = att * static_cast(obj->m_donation); + // [v36-audit C2] INTENTIONAL DIVERGENCE: merged-chain weights are FLAT + // (att-weighted, no time-decay). Only the parent/LTC chain applies decay. + // Mirrors p2pool get_v36_merged_weights (flat + cap, data.py:2657) vs the + // parent decayed-cumulative skiplist. Verified intentional, not a bug. delta.weights[weight_key] = att * static_cast(65535 - obj->m_donation); return delta; } @@ -2512,6 +2516,12 @@ class ShareTracker // per_miner = miners_reward * w // accepted_total // rounding_remainder = miners_reward - sum(per_miner) // final_donation = donation_amount + rounding_remainder + // [v36-audit C4] NODE-LOCAL / NON-CONSENSUS. Despite the name, this derives + // THIS node's intended DOGE aux-coinbase payout split from PPLNS weights to + // build the block submitted to dogecoind. Sole caller = the MM payout_provider + // (c2pool_refactored.cpp); never invoked from share verification. Peers validate + // the merged commitment via the AuxPoW merkle proof, NOT by re-deriving these + // outputs, so output ordering is node-local (dogecoind accepts any valid order). std::map, uint64_t> get_merged_expected_payouts(const uint256& best_share_hash, const uint256& block_target,