Skip to content

Commit c7d77d7

Browse files
committed
dash(s8): get_work() job-target assembly — pseudoshare modulation + SANE clip + job targets
Author dash::stratum::{modulate_desired_pseudoshare_target, clip_to_sane, assemble_work_job_targets} (work_job_targets.hpp) — the S8 follow-on the #545 desired_share_target modulation accessor explicitly deferred. Together they are the full get_work() target arithmetic from the DASH oracle frstrtr/p2pool-dash @9a0a609 work.py:368-426, as pure, header-only, socket-free accessors: Pseudoshare modulation (work.py:368-374) None-path caps the vardiff target to ~1 share/sec via average_attempts_to_target(lhr*1). SANE clip (work.py:380-393) math.clip into PARENT.SANE_TARGET_RANGE. Job targets (work.py:411-426 ba dict) min_share_target = min(share bits, SANE_TARGET_RANGE[1]); share_target = the clipped pseudoshare target. SANE_TARGET_RANGE added to dash::PoolConfig SSOT (config_pool.hpp, sane_target_min/max) from oracle networks/dash.py:33 + dash_testnet.py:27. Bucket-2 (v36_standardization_goal): the modulation+clip algorithm is the protocol-universal shape that folds to a v37 unified work-source, authored as a reusable accessor. Inputs (SANE_TARGET_RANGE) stay per-coin config SSOT — tuning bounds, not isolation primitives. SAFE-ADDITIVE, dash-only: new header + new KAT (test_dash_work_job_targets) wired into the dash allowlist; no shared/core/other-coin source touched. test_dash_work_job_targets: 9/9 green on Linux x86_64, every expected value derived independently from the oracle integer formulas (true byte-parity pin).
1 parent 0a18184 commit c7d77d7

5 files changed

Lines changed: 264 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ jobs:
8282
test_threading test_weights \
8383
test_header_chain test_mempool test_template_builder \
8484
test_doge_chain test_compact_blocks test_dash_x11_kat \
85-
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 \
85+
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 \
8686
test_multiaddress_pplns test_pplns_stress \
8787
test_hash_link test_decay_pplns \
8888
test_pplns_consensus \
@@ -226,7 +226,7 @@ jobs:
226226
test_threading test_weights \
227227
test_header_chain test_mempool test_template_builder \
228228
test_doge_chain test_compact_blocks test_dash_x11_kat \
229-
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 \
229+
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 \
230230
test_hash_link test_decay_pplns \
231231
test_pplns_consensus \
232232
test_v36_script_sorting test_v36_cross_impl_refhash \

src/impl/dash/config_pool.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,27 @@ struct PoolConfig
9191
}();
9292
return is_testnet ? TESTNET_MAX : MAINNET_MAX;
9393
}
94+
95+
// SANE_TARGET_RANGE = (min_target/hardest, max_target/easiest) — the parent-coin
96+
// sane vardiff bounds the stratum get_work() pseudoshare target is clipped into
97+
// (p2pool work.py:380-393, math.clip). SOURCE: oracle networks/dash.py:33 +
98+
// dash_testnet.py:27.
99+
// mainnet min = (0xFFFF*2**208)//10000 max = 0xFFFF*2**208
100+
// testnet min = 2**256//2**32//1000000 - 1 max = 2**256//2**20 - 1
101+
// sane_target_max() mainnet == max_target() (both = _DIFF1_TARGET); kept as its
102+
// own accessor so the clip reads the oracle SANE pair, not the share-diff floor.
103+
static uint256 sane_target_min()
104+
{
105+
static const uint256 MAINNET_MIN = [] {
106+
uint256 t; t.SetHex("0000000000068db22d0e5604189374bc6a7ef9db22d0e5604189374bc6a7ef9d"); return t;
107+
}();
108+
static const uint256 TESTNET_MIN = [] {
109+
uint256 t; t.SetHex("00000000000010c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26f9"); return t;
110+
}();
111+
return is_testnet ? TESTNET_MIN : MAINNET_MIN;
112+
}
113+
114+
static uint256 sane_target_max() { return max_target(); }
94115
};
95116

96117
} // namespace dash
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#pragma once
2+
3+
// dash::stratum::* — get_work() JOB-TARGET assembly (S8 get_work() wiring).
4+
//
5+
// This is the S8 follow-on the per-miner modulation accessor (work_target.hpp,
6+
// PR #545) explicitly deferred: where work_target.hpp authors the
7+
// desired_SHARE_target modulation (work.py:308-326), this header authors the
8+
// rest of the get_work() target arithmetic — the desired_PSEUDOSHARE_target
9+
// (vardiff) modulation, the SANE_TARGET_RANGE clip, and the two job-target
10+
// fields the stratum work blob carries. Together they are everything the
11+
// (future) DASHWorkSource::get_work() needs to turn frozen template +
12+
// share-tracker state into a jobs nbits, with no node and no socket.
13+
//
14+
// ORACLE: frstrtr/p2pool-dash @9a0a609 p2pool/work.py:368-426.
15+
//
16+
// Pseudoshare modulation (work.py:368-374) — when the stratum client supplies
17+
// no desired_pseudoshare_target, start from 2**256-1 and cap to ~one share
18+
// response per second: average_attempts_to_target(local_hash_rate * 1).
19+
//
20+
// SANE clip (work.py:380-393) — math.clip(target, PARENT.SANE_TARGET_RANGE):
21+
// bound the vardiff target into (min_target/hardest, max_target/easiest).
22+
//
23+
// Job targets (work.py:411-426, the `ba` dict) —
24+
// min_share_target = min(share_info[bits].target, SANE_TARGET_RANGE[1])
25+
// (the P2Pool share-difficulty floor)
26+
// share_target = the clipped pseudoshare/vardiff target.
27+
//
28+
// CLASSIFICATION (operator v36_standardization_goal 2026-06-17, Bucket-2):
29+
// Same as work_target.hpp — the pseudoshare modulation + clip ALGORITHM is the
30+
// protocol-universal shape that folds to a v37 unified work-source, so it is a
31+
// pure reusable accessor. The INPUTS it reads — SANE_TARGET_RANGE — stay
32+
// per-coin config SSOT (dash::PoolConfig::sane_target_min/max, config_pool.hpp);
33+
// tuning bounds, not isolation primitives, so no cross-coin entanglement.
34+
//
35+
// PURITY: header-only, socket-free, node-free — every function is a pure
36+
// transform of its arguments. This is what lets test_dash_work_job_targets pin
37+
// oracle-exact arithmetic with no VM200/201 node and no live sharechain.
38+
39+
#include "work_target.hpp" // dash::stratum::average_attempts_to_target
40+
#include <core/uint256.hpp> // uint256
41+
42+
namespace dash::stratum {
43+
44+
// math.clip(x, (lo, hi)) — oracle p2pool util/math.py: return lo if x < lo,
45+
// hi if x > hi, else x. SANE_TARGET_RANGE = (min_target/hardest, max_target/
46+
// easiest), so lo <= hi as targets. Clamps the vardiff target into range.
47+
inline uint256 clip_to_sane(uint256 target,
48+
const uint256& sane_min,
49+
const uint256& sane_max)
50+
{
51+
if (target < sane_min) return sane_min;
52+
if (target > sane_max) return sane_max;
53+
return target;
54+
}
55+
56+
// Pseudoshare (vardiff) target modulation — work.py:368-374. The None-path:
57+
// start from 2**256-1, cap to one share-response/sec by tightening to
58+
// average_attempts_to_target(local_hash_rate * 1). local_hash_rate <= 0 leaves
59+
// it unconstrained (no measured rate yet). The merged-work aux max
60+
// (work.py:376-377) is omitted: this is the dash-fenced single-chain path; aux
61+
// targets fold in at the merged-mining seam, not here.
62+
inline uint256 modulate_desired_pseudoshare_target(double local_hash_rate)
63+
{
64+
uint256 target;
65+
target.SetHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
66+
if (local_hash_rate > 0.0) {
67+
uint256 cap = average_attempts_to_target(local_hash_rate * 1.0);
68+
if (cap < target) target = cap;
69+
}
70+
return target;
71+
}
72+
73+
// Frozen per-job target inputs, assembled by the (future) DASHWorkSource from
74+
// the modulated desired_share_target (work_target.hpp), the generated share_info
75+
// bits target, and per-miner vardiff state at job time.
76+
struct WorkJobTargetInputs {
77+
uint256 share_info_bits_target; ///< share_info[bits].target from generate_transaction
78+
uint256 sane_target_min; ///< PoolConfig::sane_target_min() (SANE_TARGET_RANGE[0])
79+
uint256 sane_target_max; ///< PoolConfig::sane_target_max() (SANE_TARGET_RANGE[1])
80+
bool have_desired_pseudoshare = false;///< client supplied desired_pseudoshare_target?
81+
uint256 desired_pseudoshare_target; ///< client-supplied target (when have_... = true)
82+
double local_hash_rate = 0.0; ///< for the None-path *1 cap
83+
};
84+
85+
// The two job-target fields of the stratum work blob (work.py:411-426 `ba`).
86+
struct WorkJobTargets {
87+
uint256 min_share_target; ///< min(share_info bits target, SANE_TARGET_RANGE[1]) — share floor
88+
uint256 share_target; ///< clipped pseudoshare/vardiff target
89+
};
90+
91+
// get_work() job-target assembly. Faithful to work.py:368-426: the share_target
92+
// is the (modulated-or-supplied) pseudoshare target clipped into SANE range; the
93+
// min_share_target is the generated share bits target floored at the easiest sane
94+
// target. Pure transform of `in` — no node/template/daemon state touched.
95+
inline WorkJobTargets assemble_work_job_targets(const WorkJobTargetInputs& in)
96+
{
97+
uint256 target = in.have_desired_pseudoshare
98+
? in.desired_pseudoshare_target
99+
: modulate_desired_pseudoshare_target(in.local_hash_rate);
100+
target = clip_to_sane(target, in.sane_target_min, in.sane_target_max);
101+
102+
uint256 floor = (in.share_info_bits_target < in.sane_target_max)
103+
? in.share_info_bits_target
104+
: in.sane_target_max;
105+
106+
return WorkJobTargets{ floor, target };
107+
}
108+
109+
} // namespace dash::stratum

test/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,18 @@ if (BUILD_TESTING AND GTest_FOUND)
277277
target_link_libraries(test_dash_work_target PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39): core stratum/web_server TUs
278278
gtest_add_tests(test_dash_work_target "" AUTO)
279279

280+
# Header-only (stratum/work_job_targets.hpp over work_target.hpp + config_pool);
281+
# pure, socket-free. get_work() job-target assembly KAT.
282+
add_executable(test_dash_work_job_targets test_dash_work_job_targets.cpp)
283+
target_link_libraries(test_dash_work_job_targets PRIVATE
284+
GTest::gtest_main GTest::gtest
285+
dash_x11 core
286+
nlohmann_json::nlohmann_json
287+
${Boost_LIBRARIES}
288+
)
289+
target_link_libraries(test_dash_work_job_targets PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39): core stratum/web_server TUs
290+
gtest_add_tests(test_dash_work_job_targets "" AUTO)
291+
280292
# share_init_verify gentx hash_link byte-parity vs oracle (coinbase_payload
281293
# VarStr prefix). Header-only over the dash_x11 + core link set; mirrors the
282294
# test_dash_conformance link set.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// DASH S8 get_work() JOB-TARGET assembly KAT.
2+
//
3+
// Pins dash::stratum::{modulate_desired_pseudoshare_target, clip_to_sane,
4+
// assemble_work_job_targets} to oracle-EXACT arithmetic from
5+
// frstrtr/p2pool-dash @9a0a609 work.py:368-426 (the get_work() pseudoshare
6+
// modulation + SANE clip + the two job-target fields of the stratum work blob).
7+
// Every expected value below was computed independently from the oracle integer
8+
// formulas (see the derive comment on each vector), NOT from the SUT — a true
9+
// byte-parity pin, not a tautology.
10+
//
11+
// Pure / socket-free / node-free: no VM200/201 dashd, no live sharechain.
12+
//
13+
// SANE_TARGET_RANGE inputs read from dash::PoolConfig SSOT (config_pool.hpp).
14+
15+
#include <gtest/gtest.h>
16+
17+
#include <impl/dash/stratum/work_job_targets.hpp>
18+
#include <impl/dash/config_pool.hpp>
19+
20+
using namespace dash::stratum;
21+
22+
namespace {
23+
constexpr const char* MAX_HEX =
24+
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
25+
// Oracle SANE_TARGET_RANGE, mainnet (networks/dash.py:33):
26+
// min = (0xFFFF*2**208)//10000 ; max = 0xFFFF*2**208
27+
constexpr const char* SMIN_HEX =
28+
"0000000000068db22d0e5604189374bc6a7ef9db22d0e5604189374bc6a7ef9d";
29+
constexpr const char* SMAX_HEX =
30+
"00000000ffff0000000000000000000000000000000000000000000000000000";
31+
32+
uint256 U(const char* h) { uint256 t; t.SetHex(h); return t; }
33+
} // namespace
34+
35+
// modulate_desired_pseudoshare_target: no measured rate -> unconstrained MAX
36+
// (work.py:369 target = 2**256-1, local_hash_rate path skipped).
37+
TEST(DashWorkJobTargets, PseudoshareNoRate)
38+
{
39+
EXPECT_EQ(modulate_desired_pseudoshare_target(0.0).GetHex(), MAX_HEX);
40+
}
41+
42+
// modulate_desired_pseudoshare_target(lhr) == average_attempts_to_target(lhr*1)
43+
// == 2**256 // int(lhr) - 1 (work.py:372-373). Derive (python3):
44+
// "%064x" % (2**256//10000000000 - 1)
45+
TEST(DashWorkJobTargets, PseudoshareExact)
46+
{
47+
EXPECT_EQ(modulate_desired_pseudoshare_target(1e10).GetHex(),
48+
"000000006df37f675ef6eadf5ab9a2072d44268d97df837e6748956e5c6c2116");
49+
}
50+
51+
// clip_to_sane = math.clip(x, (lo, hi)) (work.py:393).
52+
TEST(DashWorkJobTargets, ClipBelowMinReturnsMin)
53+
{
54+
EXPECT_EQ(clip_to_sane(U("01"), U(SMIN_HEX), U(SMAX_HEX)).GetHex(), SMIN_HEX);
55+
}
56+
TEST(DashWorkJobTargets, ClipAboveMaxReturnsMax)
57+
{
58+
EXPECT_EQ(clip_to_sane(U(MAX_HEX), U(SMIN_HEX), U(SMAX_HEX)).GetHex(), SMAX_HEX);
59+
}
60+
TEST(DashWorkJobTargets, ClipInRangeUnchanged)
61+
{
62+
// MID = SMIN*2, derived in-range (python3): smin=(0xFFFF*2**208)//10000
63+
const char* MID =
64+
"00000000000d1b645a1cac083126e978d4fdf3b645a1cac083126e978d4fdf3a";
65+
EXPECT_EQ(clip_to_sane(U(MID), U(SMIN_HEX), U(SMAX_HEX)).GetHex(), MID);
66+
}
67+
68+
// dash::PoolConfig SANE_TARGET_RANGE SSOT == oracle networks/dash.py:33 +
69+
// dash_testnet.py:27.
70+
TEST(DashWorkJobTargets, PoolConfigSaneMatchesOracleMainnet)
71+
{
72+
dash::PoolConfig::is_testnet = false;
73+
EXPECT_EQ(dash::PoolConfig::sane_target_min().GetHex(), SMIN_HEX);
74+
EXPECT_EQ(dash::PoolConfig::sane_target_max().GetHex(), SMAX_HEX);
75+
}
76+
TEST(DashWorkJobTargets, PoolConfigSaneMatchesOracleTestnet)
77+
{
78+
dash::PoolConfig::is_testnet = true;
79+
EXPECT_EQ(dash::PoolConfig::sane_target_min().GetHex(),
80+
"00000000000010c6f7a0b5ed8d36b4c7f34938583621fafc8b0079a2834d26f9");
81+
EXPECT_EQ(dash::PoolConfig::sane_target_max().GetHex(),
82+
"00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
83+
dash::PoolConfig::is_testnet = false; // restore SSOT default
84+
}
85+
86+
// assemble: None-path, modulated pseudoshare in SANE range -> share_target is the
87+
// modulated value unchanged; min_share_target = share bits (below sane_max).
88+
// SHAREBITS = SMIN*3 (in-range, < sane_max). lhr=1e10 -> PseudoshareExact value.
89+
TEST(DashWorkJobTargets, AssembleNonePathInRange)
90+
{
91+
WorkJobTargetInputs in;
92+
in.share_info_bits_target =
93+
U("000000000013a916872b020c49ba5e353f7ced916872b020c49ba5e353f7ced7");
94+
in.sane_target_min = U(SMIN_HEX);
95+
in.sane_target_max = U(SMAX_HEX);
96+
in.have_desired_pseudoshare = false;
97+
in.local_hash_rate = 1e10;
98+
99+
WorkJobTargets out = assemble_work_job_targets(in);
100+
EXPECT_EQ(out.share_target.GetHex(),
101+
"000000006df37f675ef6eadf5ab9a2072d44268d97df837e6748956e5c6c2116");
102+
EXPECT_EQ(out.min_share_target.GetHex(),
103+
"000000000013a916872b020c49ba5e353f7ced916872b020c49ba5e353f7ced7");
104+
}
105+
106+
// assemble: client-SUPPLIED pseudoshare target above sane_max -> clipped to
107+
// sane_max; share bits also above sane_max -> min_share_target floored to sane_max.
108+
TEST(DashWorkJobTargets, AssembleSuppliedClippedAndFloored)
109+
{
110+
WorkJobTargetInputs in;
111+
in.share_info_bits_target = U(MAX_HEX); // above sane_max -> floored
112+
in.sane_target_min = U(SMIN_HEX);
113+
in.sane_target_max = U(SMAX_HEX);
114+
in.have_desired_pseudoshare = true;
115+
in.desired_pseudoshare_target = U(MAX_HEX); // above sane_max -> clipped
116+
117+
WorkJobTargets out = assemble_work_job_targets(in);
118+
EXPECT_EQ(out.share_target.GetHex(), SMAX_HEX);
119+
EXPECT_EQ(out.min_share_target.GetHex(), SMAX_HEX);
120+
}

0 commit comments

Comments
 (0)