Skip to content

Commit 527d342

Browse files
authored
Merge pull request #586 from frstrtr/dash/s8-poolnode-share-tracker-leaf
DASH S8 pool-node leaf 4 — share_tracker (DensePPLNS window + verify entry)
2 parents ace024b + 5bde808 commit 527d342

20 files changed

Lines changed: 3843 additions & 105 deletions

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
test_threading test_weights \
8989
test_header_chain test_mempool test_template_builder \
9090
test_doge_chain test_compact_blocks test_dash_x11_kat \
91-
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_cb_payee test_dash_poolnode_messages test_dash_peer \
91+
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_cb_payee test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node \
9292
test_multiaddress_pplns test_pplns_stress \
9393
test_hash_link test_decay_pplns \
9494
test_pplns_consensus \
@@ -238,7 +238,7 @@ jobs:
238238
test_threading test_weights \
239239
test_header_chain test_mempool test_template_builder \
240240
test_doge_chain test_compact_blocks test_dash_x11_kat \
241-
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_cb_payee test_dash_poolnode_messages test_dash_peer \
241+
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_cb_payee test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node \
242242
test_hash_link test_decay_pplns \
243243
test_pplns_consensus \
244244
test_v36_script_sorting test_v36_cross_impl_refhash \

src/impl/dash/coinbase_builder.hpp

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
#include <core/pack.hpp>
4949
#include <core/uint256.hpp>
50+
#include <core/version_gate.hpp> // SSOT: core::version_gate::is_v36_active (DASH 16->36)
5051
#include <core/hash.hpp>
5152
#include <core/coin_params.hpp>
5253
#include <core/log.hpp>
@@ -107,31 +108,64 @@ inline std::vector<MinerPayout> compute_dash_payouts(
107108
// 2. worker_payout = subsidy - Σpayment_amounts
108109
uint64_t worker_payout = (subsidy > total_payments) ? (subsidy - total_payments) : 0;
109110

110-
// 3. amounts[script] = worker_payout * 49 * weight / (50 * total_weight)
111-
// (skipped for genesis where total_weight==0; populated for
112-
// non-genesis shares via walk_cumulative_weights).
111+
// 3-4. PPLNS split. Two consensus arms, gated on the minted share version
112+
// (core::version_gate SSOT; DASH transition 16 -> 36):
113+
//
114+
// pre-v36 (bucket-3 per-coin compat, UNCHANGED p2pool-dash shape):
115+
// amounts[script] = worker_payout * 49 * weight / (50 * total_weight)
116+
// amounts[this_script] += worker_payout / 50 (2% block-finder)
117+
//
118+
// v36 (bucket-2 standardize-toward-merged-v36; mirrors DGB
119+
// share_tracker::get_expected_payouts):
120+
// amounts[script] = worker_payout * weight / total_weight (FULL weight)
121+
// NO block-finder fee.
122+
// total_weight is the GRAND total (includes donation_weight), so the
123+
// donation absorbs its decayed-weight share via the step-5 remainder.
124+
const bool v36 =
125+
core::version_gate::is_v36_active(params.current_share_version);
113126
std::map<Script, uint64_t> amounts;
114127
if (total_weight > 0) {
115-
// uint128-ish: worker_payout < 2^50, 49 < 2^6, weight < ~2^80 for a few
116-
// shares; use explicit 128-bit to avoid silent overflow.
117-
__uint128_t den = static_cast<__uint128_t>(total_weight) * 50;
128+
// weights/total_weight fit uint64 at the DASH layer; __uint128_t covers
129+
// the products (worker_payout < 2^50, 49 < 2^6, weight < 2^64).
130+
__uint128_t den = v36
131+
? static_cast<__uint128_t>(total_weight)
132+
: static_cast<__uint128_t>(total_weight) * 50;
118133
for (const auto& [script, w] : weights) {
119134
__uint128_t num = static_cast<__uint128_t>(w)
120-
* static_cast<__uint128_t>(worker_payout)
121-
* 49;
135+
* static_cast<__uint128_t>(worker_payout);
136+
if (!v36) num *= 49;
122137
amounts[script] = static_cast<uint64_t>(num / den);
123138
}
124139
}
125140

126-
// 4. amounts[this_script] += worker_payout // 50 (2 % block-finder).
141+
// 4. (pre-v36 only) 2% block-finder fee to the share creator.
127142
auto this_script = dash::pubkey_hash_to_script2(miner_pubkey_hash);
128-
amounts[this_script] = amounts[this_script] + (worker_payout / 50);
143+
if (!v36)
144+
amounts[this_script] = amounts[this_script] + (worker_payout / 50);
129145

130146
// 5. amounts[DONATION] += worker_payout - Σamounts (remainder incl. rounding).
131147
uint64_t current_sum = 0;
132148
for (const auto& [s, a] : amounts) current_sum += a;
133149
uint64_t donation_remainder = (worker_payout > current_sum)
134150
? (worker_payout - current_sum) : 0;
151+
152+
// v36 consensus (a60f7f7f): the donation output MUST carry >= 1 satoshi.
153+
// If the remainder rounds to 0, deduct 1 sat from the largest miner
154+
// (deterministic tiebreak: (amount, script)); the sum invariant holds.
155+
if (v36 && donation_remainder < 1 && worker_payout > 0 && !amounts.empty()) {
156+
auto largest = std::max_element(amounts.begin(), amounts.end(),
157+
[&](const auto& a, const auto& b) {
158+
if (a.first == donation_script) return true; // never pick donation
159+
if (b.first == donation_script) return false;
160+
if (a.second != b.second) return a.second < b.second;
161+
return a.first < b.first;
162+
});
163+
if (largest != amounts.end() && largest->first != donation_script
164+
&& largest->second >= 1) {
165+
largest->second -= 1;
166+
donation_remainder += 1;
167+
}
168+
}
135169
amounts[donation_script] = amounts[donation_script] + donation_remainder;
136170

137171
// Sanity: Σ(amounts) == worker_payout (matches p2pool-dash assertion).

src/impl/dash/config_pool.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace dash
2727

2828
// DASH sharechain p2pool constants. Source of truth: p2pool-dash oracle
2929
// networks/dash.py (mainnet) + networks/dash_testnet.py (testnet).
30-
struct PoolConfig
30+
struct SharechainConfig
3131
{
3232
// ---- mainnet (networks/dash.py) ----
3333
static constexpr uint16_t P2P_PORT = 8999;

0 commit comments

Comments
 (0)