Skip to content

dash(S8): arm --stratum dashd-RPC fallback via NodeRPC::getwork()#726

Merged
frstrtr merged 1 commit into
masterfrom
dash/s8-stratum-fallback-getwork
Jul 17, 2026
Merged

dash(S8): arm --stratum dashd-RPC fallback via NodeRPC::getwork()#726
frstrtr merged 1 commit into
masterfrom
dash/s8-stratum-fallback-getwork

Conversation

@frstrtr

@frstrtr frstrtr commented Jul 17, 2026

Copy link
Copy Markdown
Owner

What

Wires the run_node --stratum dashd-RPC fallback arm from a stub (empty DashWorkData set-gap default) to the EXISTING NodeRPC::getwork() seam — the same rich getblocktemplate -> DashWorkData path run_mine_block already uses.

Why

The S8 stratum standup shipped the run-path caller (main_dash --stratum -> DASHWorkSource -> StratumServer) with the dashd fallback arm stubbed. This closes that gap so the stratum path serves real dashd work when the embedded-GBT arm is not the source.

Safety

  • dashd-RPC fallback RETAINED (never removed) — operator standing rule.
  • UNARMED path (no dash.conf creds) keeps the empty set-gap default and logs [DASH-STRATUM-GBT] loudly — never a silent drop.
  • Lifetime-safe: rpc (unique_ptr, declared above work_source) outlives the lambda-owning work_source; destroyed BEFORE rpc at scope exit.
  • Embedded-P2P relay leg stays S8-gated. No shared-base / other-coin edit — per-coin isolation held.
  • Conforms vs oracle frstrtr/p2pool-dash (getwork seam unchanged; this is caller-side wiring only).

Verify

Local Linux x86_64 c2pool-dash link-verify in flight; will post CI + --run --stratum 127.0.0.1:13333 acceptor-standup result before undrafting. 1 file, +15/-4.

The run_node stratum standup shipped its dashd-RPC fallback arm as a stub
returning an empty DashWorkData (documented set-gap default). This wires it
to the EXISTING NodeRPC::getwork() seam -- the same rich getblocktemplate ->
DashWorkData path run_mine_block already uses -- so the stratum run-path can
serve real dashd work when the embedded-GBT arm is not the source.

- main_dash.cpp run_node: dashd_fallback lambda now calls rpc->getwork() when
  the RPC arm is ARMED; when UNARMED (no dash.conf creds) it keeps the empty
  set-gap default and logs [DASH-STRATUM-GBT] loudly -- never a silent drop.
- Lifetime-safe: rpc (unique_ptr, decl above work_source) outlives work_source,
  which owns this lambda; destroyed BEFORE rpc at scope exit.
- dashd-RPC fallback RETAINED (never removed). No shared-base / other-coin edit;
  per-coin isolation held. Embedded-P2P relay leg stays S8-gated.
@frstrtr
frstrtr marked this pull request as ready for review July 17, 2026 07:39
@frstrtr
frstrtr merged commit 3be9ba6 into master Jul 17, 2026
26 checks passed
@frstrtr
frstrtr deleted the dash/s8-stratum-fallback-getwork branch July 17, 2026 07:42
frstrtr added a commit that referenced this pull request Jul 17, 2026
…late path + X11 submit scoring (#733)

* core(stratum): runtime coin_symbol replaces hardcoded [LTC] template-wait tag

The coin-agnostic core hardcoded "[LTC]" in the send_notify_work
no-template warning, so a DASH binary logged LTC and sent the operator
diagnosing the wrong coin (#732 secondary defect). StratumConfig now
carries a runtime coin_symbol -- LTC sets it in main_ltc.cpp, BTC/DGB in
their work-source ctors (DASH follows in the 4c/4d commit) -- with a
neutral [Stratum] fallback when unset. No coin name remains hardcoded in
src/core.

* dash(stratum): 4c/4d -- serve real work + X11 submit scoring (#732)

Stage 4c (template serving): bridge the armed get_work() seam (#726,
embedded coin-state when seeded / retained dashd GBT fallback -- duality
preserved) into the template trio the coin-agnostic session consumes.
DashWorkData is cached under template_mutex_ keyed on work_generation_ +
a 30s staleness TTL (5s negative cache; tip-move bumps the generation).
get_current_work_template() emits exactly the fields send_notify_work()
reads with LTC/BTC byte conventions; merkle branches ride the existing
merkle_branches_raw/_hex SSOT; build_connection_coinbase() goes through
the verifier-shared compute_dash_payouts -> coinbase::build ->
split_coinb SSOTs (coinb1/coinb2 around the 8-byte nonce64 extranonce
slot), so the coinbase a miner hashes is byte-identical to the verifier
split by construction. Genesis case (fresh pool, empty sharechain): the
connecting miner's P2PKH script carries the full worker payout + the
GBT-mandated masternode/superblock outputs + donation tail; the PPLNS
multi-output path rides the new set_pplns_weights_fn seam through the
same SSOT arm. Ctor pins set_difficulty_multiplier to 1.0 (X11 =
standard diff-1 scale) -- the scrypt 65536 default inflated the
advertised difficulty 65536x (the wire=32.768 in the field report).

Stage 4d (submit scoring): mining_submit() reassembles the coinbase,
folds the frozen branches, serializes the 80-byte header via the
block_producer SSOT, runs the selftest-pinned X11, and classifies
tighten-first: WonBlock -> full block in the exact --mine-block
serialization -> submit_block_fn_ dual-path dispatcher (a won block
reaching no sink screams, never drops); ShareAccept -> new
set_mint_share_fn seam (accept-for-vardiff + loud log while unbound);
else low-difficulty reject. compute_share_difficulty() is the same
reconstruction ending in diff1/x11(header) so vardiff engages.

Test gate (the miss that let v0.2.2 ship): test_dash_stratum_work_source
(already in the build.yml allowlist + ctest registration) now carries
the 4c/4d KATs -- fixed-DashWorkData template trio with pinned
encodings, set-gap honesty, branch fold vs compute_merkle_root, coinbase
reassembly byte-identical to the SSOT build with pinned value splits,
X11 difficulty KAT, and deterministic mining_submit classification
(share accept / low-diff reject / won-block bytes / mint-seam routing).

Verified: 19/19 KATs green; c2pool-dash --selftest green; live smoke
(--run --stratum vs a stubbed GBT endpoint) serves mining.notify with a
real job on subscribe -- the #732 field failure mode is gone.

* main_ltc: route Windows RLIMIT_NOFILE notice to stdout (fix --help smoke)

On Windows raise_nofile_limit() always returns 0 (no RLIMIT_NOFILE). The
prior LOG_WARNING sent this benign startup notice to stderr; the CI --help
smoke pipes c2pool.exe through pwsh "2>&1 | Select-Object -First N", whose
early pipe-close promotes any native stderr write to a NativeCommandError
and exits 1. Emit the notice on stdout under _WIN32 (matching main_dash.cpp);
POSIX keeps LOG_WARNING for genuine getrlimit failures. SAFE-COSMETIC.

---------

Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
frstrtr added a commit that referenced this pull request Jul 19, 2026
…lty (unstub 4b/4c) (#753)

* dgb(stratum): wire external-daemon GBT prevhash+bits fallback for empty embedded chain

A freshly-stood-up c2pool-dgb :5025 node whose Scrypt-only HeaderChain has
not yet ingested a tip (tip_hash()==nullopt) could supply NEITHER a
previousblockhash NOR nBits: the header walk cannot reconstruct MultiShield-V4
(a 5-algo window == V37), and the embedded ingest that populates the tip lands
later. Result: an EMPTY mining.notify prevhash on the live testnet.

Add DGBWorkSource::set_gbt_tip_fn -- a std::function seam (mirrors
set_pplns_inputs_fn and dash #726 dashd_fallback) bound in main_dgb.cpp to a
lambda over NodeRPC::getblocktemplate. When the embedded chain has no tip,
get_current_work_template() AND get_current_gbt_prevhash() (the notify-prevhash
source) draw BOTH previousblockhash and the daemon-authoritative bits from ONE
GBT snapshot (consistent height). A real embedded tip always wins; the RPC
transport stays in main (stratum/ holds only the seam). Unbound / no digibyted
creds / RPC failure -> both fields stay a truthful ABSENCE, byte-identical to
the pre-wire path -- never a fabricated tip/bits. GBT previousblockhash is the
u256_be_display_hex big-endian convention the embedded path emits, so it flows
verbatim (width-guarded at the bind). TTL-cached (5s) so per-heartbeat template
+ prevhash polls do not each trigger a blocking getblocktemplate round-trip.

External-daemon GBT fallback RETAINED (never removed), per V36. Scrypt-only;
no shared-base / other-coin edit; per-coin isolation held.

Tests: 3 new DgbWorkSource.GbtTip* (populate / unbound-absent / nullopt-absent)
over the empty-chain fixture; full dgb_work_source_test 30/30 green.

* dgb(stratum): score shares via scrypt digest in compute_share_difficulty (unstub 4b/4c)

DGBWorkSource::compute_share_difficulty was a Stage-4b/4c stub returning 0.0.
The coin-agnostic StratumServer calls it BEFORE mining_submit and silently
rejects any share scoring below the vardiff floor (stratum_server.cpp: error 23
Low difficulty share, no server-side log), so every accepted-looking share was
dropped before the stage-4d classify+broadcaster ever ran -- the pool could
never advance its tip.

Implement it as a byte-for-byte mirror of mining_submit reconstruct:
coinb1||en1||en2||coinb2 -> sha256d txid -> ascend merkle branches -> 80-byte
header -> scrypt_1024_1_1_256, then bridge the coin-space u256 into core
uint256 via the u256_be_display_hex SSOT and return chain::target_to_difficulty
(diff-1 0x1d00ffff) -- unit-identical to the required_difficulty / pool_difficulty
the gate compares. Malformed reconstruct (header != 80B) keeps the documented
0.0 not-scored sentinel. KAT: valid header scores a finite positive difficulty;
malformed input still returns 0.0. 31/31 dgb_work_source_test green.

---------

Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant