dash(mint 3/3): run-loop share minting — ShareAccept -> tracker insert + broadcast + PPLNS weights#750
Merged
Merged
Conversation
…>build_share adapter scaffold (WIP, KAT+build next)
…dapter + 5 KATs Implements make_producer_mint_fn / build_mint_share: maps a stratum-found solution (DASHWorkSource::MintShareInputs) plus the per-job context frozen at job assembly (FrozenMintJob) into a fully-built, self-verified DashShare and returns its X11 share hash. parse_min_header_80 (BlockHeaderType slice) + pubkey_hash_from_p2pkh (inverse of pubkey_hash_to_script2), both fail-closed. Integrity gate: rebuilt share m_hash must reproduce the solved header pow_hash or the mint is declined (null). Header-only, impl/dash only, nothing in src/core; KAT-gated, not wired into --run (that is slice 3/3). dashd RPC fallback untouched. Compiled into the existing allowlisted test target so the build.yml allowlist is unchanged. 5/5 KATs green; direct-build parity pinned.
… frozen-job registry, ban-safety mint gate mint_runloop.hpp: the wiring layer between the producer machinery (slices 1-2) and the live --run pool. - build_producer_job: job-time producer pass — prospective share_info off the live chain, oracle-window cumulative weights (grandparent start, data.py:181), ref_hash, and the FULL share gentx serialized with the nonce64 slot zeroed. The stratum coinbase IS this gentx (split around the slot), so the solved bytes are byte-identical to what the mint-time rebuild reproduces — byte-parity by construction, ONE gentx serializer (producer::build_gentx), no parallel-implementation parity to drift. - FrozenJobRegistry: bounded ref_hash -> FrozenMintJob store; ref_hash commits to the entire prospective share_info, so a miss is a fail-closed decline, never a guess. - mint_from_inputs: slice-2 build_mint_share (X11 identity gate) PLUS the explicit pow<=committed-target guard — a stratum share-bits race can never mint a share that fails its own m_bits target on peers (the PeerMisbehavingError BAN line). - elect_best_share: verified-work-first election (think() best when on the verified chain; else heaviest verified head by ACCUMULATED work via the tracker view; ZERO with peers-but-no-verified-chain; raw-head genesis bootstrap). Pure function so the policy is KAT-able. - pplns_weights_for: oracle-window tracker walk for the non-producer coinbase seam (uniform-shift u64 normalization; ref ZERO by contract — a solve on the fallback path can never mint). - MintFeePolicy/resolve_mint_identity/donation_percent_to_u16: README flag port (LTC sharechain-lane semantics) — --give-author -> share donation field (oracle dev-fee channel; donation output stays ALWAYS emitted); --fee/--node-owner-address -> consensus-safe probabilistic identity substitution; --redistribute fee/donate for non-P2PKH credentials (donate = donation=65535, the pubkey-hash-keyed DASH form of 100%-to- donation); pplns/boost redistribution engine not yet ported (declines, the pre-existing fail-closed behavior). work_source: ProducerJobFn seam (build_connection_coinbase serves the producer gentx verbatim when bound, publishes the committed share bits via set_share_target; byte-unchanged fallback otherwise); MintShareInputs now carries ref_hash (recovered from the coinb1 tail), last_txout_nonce (LE u64 of en1||en2) and the job's frozen tx_data. share_producer_bind: FrozenMintJob.payout_script_override — the mint-time rebuild uses the identity the job was BUILT with (fee substitution would otherwise fail the X11 identity gate on every substituted solve). Fenced to src/impl/dash/; dashd-RPC fallback untouched.
…oadcast leg, LevelDB persistence, version-handshake send Ports of the btc::NodeImpl prod reference reconciled to the DASH pool-node (the tracker's think() was already fully implemented; this is the NODE-side driver + the send legs that were missing): - run_think(): compute-thread think() under the exclusive tracker lock (bootstrap full-verify on an empty verified chain), publishes m_best_share_hash + the lock-free snapshot, flushes verified marks to LevelDB, IO-phase drains deferred share batches, fires on_best_share_changed (stratum work refresh) and re-broadcasts the new head. Serialized by m_think_running; budget-exhaustion continuation re-posts. bad_peer_addresses are LOGGED (no ban list on the DASH node yet) and the desired-share download leg is loudly logged as a later slice — both honest gaps, not silent drops. - best_share_hash()/advertised_best_share(): election via the mint_runloop elect_best_share policy; advertised variant is inline (vtable-safe for the link-deferred KAT targets) and feeds send_version. - broadcast_share()/send_shares(): the missing FORWARD leg — walk up to 5 un-broadcast ancestors, remember_tx the txs the peer lacks (from m_known_txs), send via the message_shares wire codec (round-trip pinned byte-identical by KAT), forget_tx after. try_to_lock throughout (IO thread never blocks on the compute thread). - connected()/send_version(): the node now OPENS the handshake on every connection (p2pool sends version from both sides; a silent side gets dropped by the remote handshake timeout) and advertises its best share so peers pull our chain. send_ping is now a real keep-alive. - init_storage()/load_persisted_shares()/flush_verified_to_leveldb()/ shutdown_persistence(): SharechainStorage construction under the per-net name, verified-hash + removal persistence hooks, height-ordered reload with known_verified pre-population and window pruning (btc parity: 8-byte version prefix + packed contents). - add_verified_shares(): now persists each new batch atomically and triggers run_think() (p2pool: set_best_share after every batch). - add_local_share(): the mint insertion — non-blocking exclusive lock (busy => decline, fail-closed), tracker add + inline attempt_verify + persist, then broadcast + rescore. - register_template_txs(): current template txs -> m_known_txs (bounded by one template) so share relay can serve remember_tx for a minted share's new_transaction_hashes. Fenced to src/impl/dash/.
… broadcast + PPLNS weights + fee flags main_dash run_node now actually MINTS onto the sharechain: - tracker coin-params set at startup (X11 pow_func — reception verify was running with an empty default) + init_storage(net_subdir) (LevelDB sharechain persistence + reload under the per-net dir). - set_best_share_hash_fn -> the node's verified-work-first election, so new jobs build on the live tip. - set_producer_job_fn: tracker-guarded (try-lock, degrade-on-busy) producer job build with a per-(prev, payout, template) 30 s cache (stable job bytes across the 1 s notify cadence — keeps the session payload cache effective and the frozen-job registry within its window), fee-policy identity resolution (one roll per job build, the p2pool per-get_work fee roll), and template-tx registration for relay. - set_mint_share_fn: registry lookup by the coinbase's OP_RETURN commitment -> deterministic producer rebuild (X11 identity + pow<=target ban-safety gates) -> add_local_share (tracker insert + persist + broadcast + rescore). Every decline is loud; nothing mints on a miss. - set_pplns_weights_fn: oracle-window tracker walk for the non-producer coinbase path (pays the live PPLNS window even when the producer seam degrades). - on_best_share_changed -> stratum work-generation bump; initial run_think + 15 s keep-fresh tick; shutdown_persistence on exit. - README fee flags (LTC-path port): --give-author/--dev-donation (default 0.1% -> donation field 66; the donation output is ALWAYS emitted by the gentx, 0% keeps the dust-marker semantic), -f/--fee + --node-owner-address (consensus-safe probabilistic node-owner identity substitution), --redistribute pplns|fee|boost|donate (broken-credential policy; weighted pplns/boost engine is a later port and declines fail-closed). The minted shares are the LEGACY v16 DashShare lineage the live p2pool-dash network speaks (min-proto 1700); the v36 crossing stays a separate later step. dashd-RPC fallback untouched.
…11 solves 11 KATs into the existing allowlisted test_dash_share_hash_link target (no build.yml change): - ShareAcceptMintsVerifiedShareIntoTracker: producer job -> coinb1/coinb2 split -> miner coinbase reassembly -> REAL X11 nonce search -> mint; the share hash IS the solved header PoW, the frozen-job registry keys on the ref recovered from the coinb1 tail, the share passes the in-tree verifier (build_share mandatory self-verify), inserts into the tracker and appears in the get_shares chain walk. - MintedShareWireRoundTripByteIdentical: message_shares payload codec round-trip byte-identical + the reloaded share re-verifies to the SAME X11 hash through share_init_verify (the exact peer-side check). - BestShareElectionPicksHeaviestVerifiedHead: heaviest ACCUMULATED-work verified head wins across forks; think-best on the verified chain is authoritative; peers-but-no-verified-chain refuses (ZERO). - PplnsWeightsMatchOracleWindow: oracle grandparent-start window pin — the tip's own miner excluded, earlier miners' equal weights + total hand-verified; ref ZERO on the fallback path. - DeclinesSolveBelowCommittedTarget: the ban-safety gate — a structurally-consistent solve above the committed share target is DECLINED (isolated to the pow<=target discriminator via mainnet params). - FrozenJobRegistryFailClosedAndBounded: unknown-ref decline + FIFO cap. - DonationPercentToU16Mapping / ResolveMintIdentityFeeAndRedistribute / CombinedFeeSplitOwnerSubstitutionWithZeroDevFee / DonationFieldDecaysPplnsWeight: the fee-flag port pins — --give-author u16 mapping (0.1->66, 0.5->328), fee-roll substitution + redistribute fee/donate/pplns outcomes, the combined --fee 1 --give-author 0 split (owner identity + donation field 0 + donation output PRESENT in the solved coinbase bytes), and the oracle weight decay att*(65535-donation) with the donation weight att*donation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Slice 3/3 of the DASH sharechain-MINT campaign: the run-loop wiring that makes
c2pool-dash --runactually MINT legacy v16 shares onto the p2pool-dash sharechain — ShareAccept -> producer rebuild -> tracker insert -> peer broadcast, with best-share election and the PPLNS window bound into the coinbase. Enables PPLNS payouts and is the prerequisite for joining the live p2pool-dash network.Re-verified gap delta (vs the earlier assessment)
share_producer_bind.hpp(+ its 5 KATs) sat unmerged ondash/s8-share-producer-mint-bindwith no PR. The two commits are included here (cherry-picked, unchanged) — this PR stacks on them.ShareTracker::think()(P1 verify walk / P2 budgeted verify / scoring) is fully implemented on master. What was missing was the NODE-side driver:run_think(),m_best_share_hashpublication, the pending-adds drain, and any caller. All added.versionmessage (noconnected()override /send_version) — a p2pool-dash peer drops the link on handshake timeout, so reception alone could not hold a session;send_pingwas also a stub;tracker.m_coin_params(X11 pow_func) — reception verify would run with an empty pow function and reject every share.What was built
Byte-parity architecture (the ban-safety keystone): when the producer seam is bound, the stratum coinbase served to miners IS the producer share gentx (
producer::build_gentx), split verbatim around the zeroed nonce64 slot. The mint-time rebuild (build_mint_share, slice 2) re-runs the identical deterministic producer walks (all anchored backward from the frozenprev_share_hash), so the rebuilt share reproduces the solved header bytes exactly — ONE gentx serializer, byte-parity by construction rather than by parallel-implementation parity. Fail-closed gates stack: frozen-job registry miss (ref_hash recovered from the coinb1 tail), the slice-2 X11 identity gate, and a new explicitpow <= committed m_bits targetguard so a stratum share-bits race can never mint a share peers would ban over.src/impl/dash/mint_runloop.hpp— build_producer_job, FrozenJobRegistry, mint_from_inputs (ban-safety gate), elect_best_share (verified-accumulated-work-first; KAT-able pure function), pplns_weights_for (ORACLE window: grandparent start, data.py:181), fee policy (below).src/impl/dash/node.{hpp,cpp}— run_think + election + snapshot publication; broadcast_share/send_shares (message_shares codec + remember_tx/forget_tx tx forwarding); connected()/send_version (+ real ping); SharechainStorage construction + reload + verified-mark/removal persistence + batch share persist; add_local_share; register_template_txs.src/impl/dash/stratum/work_source.{hpp,cpp}— ProducerJobFn seam (byte-unchanged fallback path when unbound); MintShareInputs extended with ref_hash / last_txout_nonce / tx_data.src/c2pool/main_dash.cpp— full --run wiring: coin-params + storage init, best-share fn, producer-job fn (per-job cache to keep notify bytes stable + the registry within its window), mint fn, PPLNS weights fn, work-refresh on best change, initial + 15 s think tick, shutdown flush.Fee flags (README design, LTC sharechain-lane port):
--give-author(default 0.1%) -> the share'sdonationu16 (oracle dev-fee channel; PPLNS weights decay byatt*(65535-donation); the donation output is ALWAYS emitted by the gentx —--give-author 0keeps the dust-marker output present).-f/--fee+--node-owner-address-> the consensus-safe probabilistic identity substitution (~fee% of minted shares carry the owner's pubkey_hash; identical coinbases on every peer).--redistribute fee|donatefor non-P2PKH miner credentials (donate =donation=65535, the pubkey-hash-keyed DASH form of 100%-to-donation); the LTC weightedpplns|boostredistribution engine is NOT yet ported — those decline fail-closed (the pre-existing behavior), reported as a follow-up. The pre-v36 donation script staysdash::DONATION_SCRIPT(what the live v16 network verifies); the v36 COMBINED-script migration surface (compute_dash_payoutsversion gate) is untouched — when the crossing slice lands,producer::build_gentxneeds the same share-version gate (flagged, not silently wrong: this slice mints v16 only by construction).STOPPED on (honest gaps, loudly logged — not half-wired)
desiredset is logged, not requested. Reception can serve peers (handle_get_share), but filling OUR gaps beyond what peers push rides a later slice — required for a cold-start sync against the live network.m_ban_list/m_rejected_share_hashes): bad-share peers are logged, not banned.KATs (11 new, in the existing allowlisted
test_dash_share_hash_linktarget; 40/40 green)Full pipeline with REAL X11 nonce searches: ShareAccept mints a share that passes the in-tree verifier and whose hash IS the solved header PoW; message_shares codec round-trip byte-identical + peer-side re-verify to the same hash; tracker insert + get_shares walk; heaviest-verified-head election (+ refusal with peers-but-no-verified-chain); PPLNS oracle-window pin (grandparent start, tip's miner excluded, hand-computed weights); ban-safety decline of an above-target solve (isolated to the target gate via mainnet params); registry fail-closed + FIFO bound; donation u16 mapping; fee-roll/redistribute identity resolution; the combined
--fee 1 --give-author 0split (owner identity + donation 0 + donation output PRESENT); oracle weight decayatt*(65535-donation).Verification
c2pool-dash --selftestOK; 20 s--run --testnetsmoke: listener + stratum up, think tick live, clean shutdown with persistence flush.src/impl/dash/+main_dash.cpp+ dash test files; no core/other-coin source edits; dashd-RPC fallback untouched.Byte-parity confidence vs the oracle
The producer core (slice 1) is hand-traced from frstrtr/p2pool-dash with oracle-pinned KATs; slice 3 adds no second serializer — the mint reuses the producer end-to-end and self-verifies through the in-tree verifier plus the X11 identity + target gates, so a diverging share CANNOT reach the tracker or the wire (it declines instead). What KATs cannot prove is live-oracle ACCEPTANCE semantics (e.g. tx-forwarding expectations of a real peer, timestamp/donation edge tolerances) — the next step is a controlled soak against a p2pool-dash testnet peer (available on request) BEFORE pointing at mainnet: connect, mint on the live tip, and confirm the oracle keeps the session + tracks our share.
Remaining gap to a live p2pool-dash JOIN